Skip to content

Commit 24307aa

Browse files
committed
configfs: Fix race between configfs_readdir() and configfs_d_iput()
configfs_readdir() will use the existing inode numbers of inodes in the dcache, but it makes them up for attribute files that aren't currently instantiated. There is a race where a closing attribute file can be tearing down at the same time as configfs_readdir() is trying to get its inode number. We want to get the inode number of open attribute files, because they should match while instantiated. We can't lock down the transition where dentry->d_inode is set to NULL, so we just check for NULL there. We can, however, ensure that an inode we find isn't iput() in configfs_d_iput() until after we've accessed it. Signed-off-by: Joel Becker <jlbec@evilplan.org>
1 parent df7f996 commit 24307aa

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

fs/configfs/dir.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,14 @@ DEFINE_SPINLOCK(configfs_dirent_lock);
5353
static void configfs_d_iput(struct dentry * dentry,
5454
struct inode * inode)
5555
{
56-
struct configfs_dirent * sd = dentry->d_fsdata;
56+
struct configfs_dirent *sd = dentry->d_fsdata;
5757

5858
if (sd) {
5959
BUG_ON(sd->s_dentry != dentry);
60+
/* Coordinate with configfs_readdir */
61+
spin_lock(&configfs_dirent_lock);
6062
sd->s_dentry = NULL;
63+
spin_unlock(&configfs_dirent_lock);
6164
configfs_put(sd);
6265
}
6366
iput(inode);
@@ -1546,7 +1549,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
15461549
struct configfs_dirent * parent_sd = dentry->d_fsdata;
15471550
struct configfs_dirent *cursor = filp->private_data;
15481551
struct list_head *p, *q = &cursor->s_sibling;
1549-
ino_t ino;
1552+
ino_t ino = 0;
15501553
int i = filp->f_pos;
15511554

15521555
switch (i) {
@@ -1574,6 +1577,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
15741577
struct configfs_dirent *next;
15751578
const char * name;
15761579
int len;
1580+
struct inode *inode = NULL;
15771581

15781582
next = list_entry(p, struct configfs_dirent,
15791583
s_sibling);
@@ -1582,9 +1586,28 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
15821586

15831587
name = configfs_get_name(next);
15841588
len = strlen(name);
1585-
if (next->s_dentry)
1586-
ino = next->s_dentry->d_inode->i_ino;
1587-
else
1589+
1590+
/*
1591+
* We'll have a dentry and an inode for
1592+
* PINNED items and for open attribute
1593+
* files. We lock here to prevent a race
1594+
* with configfs_d_iput() clearing
1595+
* s_dentry before calling iput().
1596+
*
1597+
* Why do we go to the trouble? If
1598+
* someone has an attribute file open,
1599+
* the inode number should match until
1600+
* they close it. Beyond that, we don't
1601+
* care.
1602+
*/
1603+
spin_lock(&configfs_dirent_lock);
1604+
dentry = next->s_dentry;
1605+
if (dentry)
1606+
inode = dentry->d_inode;
1607+
if (inode)
1608+
ino = inode->i_ino;
1609+
spin_unlock(&configfs_dirent_lock);
1610+
if (!inode)
15881611
ino = iunique(configfs_sb, 2);
15891612

15901613
if (filldir(dirent, name, len, filp->f_pos, ino,

0 commit comments

Comments
 (0)