diff options
| author | Nick Piggin <npiggin@suse.de> | 2009-05-28 03:01:15 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-06-11 21:36:10 -0400 |
| commit | 4195f73d1329e49727bcceb028e58cb38376c2b0 (patch) | |
| tree | b4c729c164d6907e4186f6dc51e319a604dee416 | |
| parent | 545b9fd3d737afc0bb5203b1e79194a471605acd (diff) | |
fs: block_dump missing dentry locking
I think the block_dump output in __mark_inode_dirty is missing dentry locking.
Surely the i_dentry list can change any time, so we may not even *get* a
dentry there. If we do get one by chance, then it would appear to be able to
go away or get renamed at any time...
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/fs-writeback.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index efcedb6d9cbc..40308e98c6a4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -64,6 +64,28 @@ static void writeback_release(struct backing_dev_info *bdi) | |||
| 64 | clear_bit(BDI_pdflush, &bdi->state); | 64 | clear_bit(BDI_pdflush, &bdi->state); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static noinline void block_dump___mark_inode_dirty(struct inode *inode) | ||
| 68 | { | ||
| 69 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { | ||
| 70 | struct dentry *dentry; | ||
| 71 | const char *name = "?"; | ||
| 72 | |||
| 73 | dentry = d_find_alias(inode); | ||
| 74 | if (dentry) { | ||
| 75 | spin_lock(&dentry->d_lock); | ||
| 76 | name = (const char *) dentry->d_name.name; | ||
| 77 | } | ||
| 78 | printk(KERN_DEBUG | ||
| 79 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 80 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 81 | name, inode->i_sb->s_id); | ||
| 82 | if (dentry) { | ||
| 83 | spin_unlock(&dentry->d_lock); | ||
| 84 | dput(dentry); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 67 | /** | 89 | /** |
| 68 | * __mark_inode_dirty - internal function | 90 | * __mark_inode_dirty - internal function |
| 69 | * @inode: inode to mark | 91 | * @inode: inode to mark |
| @@ -114,23 +136,8 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
| 114 | if ((inode->i_state & flags) == flags) | 136 | if ((inode->i_state & flags) == flags) |
| 115 | return; | 137 | return; |
| 116 | 138 | ||
| 117 | if (unlikely(block_dump)) { | 139 | if (unlikely(block_dump)) |
| 118 | struct dentry *dentry = NULL; | 140 | block_dump___mark_inode_dirty(inode); |
| 119 | const char *name = "?"; | ||
| 120 | |||
| 121 | if (!list_empty(&inode->i_dentry)) { | ||
| 122 | dentry = list_entry(inode->i_dentry.next, | ||
| 123 | struct dentry, d_alias); | ||
| 124 | if (dentry && dentry->d_name.name) | ||
| 125 | name = (const char *) dentry->d_name.name; | ||
| 126 | } | ||
| 127 | |||
| 128 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) | ||
| 129 | printk(KERN_DEBUG | ||
| 130 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 131 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 132 | name, inode->i_sb->s_id); | ||
| 133 | } | ||
| 134 | 141 | ||
| 135 | spin_lock(&inode_lock); | 142 | spin_lock(&inode_lock); |
| 136 | if ((inode->i_state & flags) != flags) { | 143 | if ((inode->i_state & flags) != flags) { |
