diff options
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r-- | fs/configfs/dir.c | 39 |
1 files changed, 32 insertions, 7 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 3313dd19f543..9a37a9b6de3a 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -53,11 +53,14 @@ DEFINE_SPINLOCK(configfs_dirent_lock); | |||
53 | static void configfs_d_iput(struct dentry * dentry, | 53 | static void configfs_d_iput(struct dentry * dentry, |
54 | struct inode * inode) | 54 | struct inode * inode) |
55 | { | 55 | { |
56 | struct configfs_dirent * sd = dentry->d_fsdata; | 56 | struct configfs_dirent *sd = dentry->d_fsdata; |
57 | 57 | ||
58 | if (sd) { | 58 | if (sd) { |
59 | BUG_ON(sd->s_dentry != dentry); | 59 | BUG_ON(sd->s_dentry != dentry); |
60 | /* Coordinate with configfs_readdir */ | ||
61 | spin_lock(&configfs_dirent_lock); | ||
60 | sd->s_dentry = NULL; | 62 | sd->s_dentry = NULL; |
63 | spin_unlock(&configfs_dirent_lock); | ||
61 | configfs_put(sd); | 64 | configfs_put(sd); |
62 | } | 65 | } |
63 | iput(inode); | 66 | iput(inode); |
@@ -689,7 +692,8 @@ static int create_default_group(struct config_group *parent_group, | |||
689 | sd = child->d_fsdata; | 692 | sd = child->d_fsdata; |
690 | sd->s_type |= CONFIGFS_USET_DEFAULT; | 693 | sd->s_type |= CONFIGFS_USET_DEFAULT; |
691 | } else { | 694 | } else { |
692 | d_delete(child); | 695 | BUG_ON(child->d_inode); |
696 | d_drop(child); | ||
693 | dput(child); | 697 | dput(child); |
694 | } | 698 | } |
695 | } | 699 | } |
@@ -1545,7 +1549,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir | |||
1545 | struct configfs_dirent * parent_sd = dentry->d_fsdata; | 1549 | struct configfs_dirent * parent_sd = dentry->d_fsdata; |
1546 | struct configfs_dirent *cursor = filp->private_data; | 1550 | struct configfs_dirent *cursor = filp->private_data; |
1547 | struct list_head *p, *q = &cursor->s_sibling; | 1551 | struct list_head *p, *q = &cursor->s_sibling; |
1548 | ino_t ino; | 1552 | ino_t ino = 0; |
1549 | int i = filp->f_pos; | 1553 | int i = filp->f_pos; |
1550 | 1554 | ||
1551 | switch (i) { | 1555 | switch (i) { |
@@ -1573,6 +1577,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir | |||
1573 | struct configfs_dirent *next; | 1577 | struct configfs_dirent *next; |
1574 | const char * name; | 1578 | const char * name; |
1575 | int len; | 1579 | int len; |
1580 | struct inode *inode = NULL; | ||
1576 | 1581 | ||
1577 | next = list_entry(p, struct configfs_dirent, | 1582 | next = list_entry(p, struct configfs_dirent, |
1578 | s_sibling); | 1583 | s_sibling); |
@@ -1581,9 +1586,28 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir | |||
1581 | 1586 | ||
1582 | name = configfs_get_name(next); | 1587 | name = configfs_get_name(next); |
1583 | len = strlen(name); | 1588 | len = strlen(name); |
1584 | if (next->s_dentry) | 1589 | |
1585 | ino = next->s_dentry->d_inode->i_ino; | 1590 | /* |
1586 | else | 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) | ||
1587 | ino = iunique(configfs_sb, 2); | 1611 | ino = iunique(configfs_sb, 2); |
1588 | 1612 | ||
1589 | if (filldir(dirent, name, len, filp->f_pos, ino, | 1613 | if (filldir(dirent, name, len, filp->f_pos, ino, |
@@ -1683,7 +1707,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) | |||
1683 | err = configfs_attach_group(sd->s_element, &group->cg_item, | 1707 | err = configfs_attach_group(sd->s_element, &group->cg_item, |
1684 | dentry); | 1708 | dentry); |
1685 | if (err) { | 1709 | if (err) { |
1686 | d_delete(dentry); | 1710 | BUG_ON(dentry->d_inode); |
1711 | d_drop(dentry); | ||
1687 | dput(dentry); | 1712 | dput(dentry); |
1688 | } else { | 1713 | } else { |
1689 | spin_lock(&configfs_dirent_lock); | 1714 | spin_lock(&configfs_dirent_lock); |