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) { |