Commit 45d28b097280a78893ce25a5d0db41e6a2717853
Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/gi…
…t/frederic/random-tracing * 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing: reiserfs: Safely acquire i_mutex from xattr_rmdir reiserfs: Safely acquire i_mutex from reiserfs_for_each_xattr reiserfs: Fix journal mutex <-> inode mutex lock inversion reiserfs: Fix unwanted recursive reiserfs lock in reiserfs_unlink() reiserfs: Relax lock before open xattr dir in reiserfs_xattr_set_handle() reiserfs: Relax reiserfs lock while freeing the journal reiserfs: Fix reiserfs lock <-> i_mutex dependency inversion on xattr reiserfs: Warn on lock relax if taken recursively reiserfs: Fix reiserfs lock <-> i_xattr_sem dependency inversion reiserfs: Fix remaining in-reclaim-fs <-> reclaim-fs-on locking inversion reiserfs: Fix reiserfs lock <-> inode mutex dependency inversion reiserfs: Fix reiserfs lock and journal lock inversion dependency reiserfs: Fix possible recursive lock
Showing 7 changed files Side-by-side Diff
fs/reiserfs/bitmap.c
... | ... | @@ -1277,7 +1277,10 @@ |
1277 | 1277 | struct reiserfs_bitmap_info *bitmap; |
1278 | 1278 | unsigned int bmap_nr = reiserfs_bmap_count(sb); |
1279 | 1279 | |
1280 | + /* Avoid lock recursion in fault case */ | |
1281 | + reiserfs_write_unlock(sb); | |
1280 | 1282 | bitmap = vmalloc(sizeof(*bitmap) * bmap_nr); |
1283 | + reiserfs_write_lock(sb); | |
1281 | 1284 | if (bitmap == NULL) |
1282 | 1285 | return -ENOMEM; |
1283 | 1286 |
fs/reiserfs/inode.c
... | ... | @@ -31,11 +31,12 @@ |
31 | 31 | JOURNAL_PER_BALANCE_CNT * 2 + |
32 | 32 | 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); |
33 | 33 | struct reiserfs_transaction_handle th; |
34 | + int depth; | |
34 | 35 | int err; |
35 | 36 | |
36 | 37 | truncate_inode_pages(&inode->i_data, 0); |
37 | 38 | |
38 | - reiserfs_write_lock(inode->i_sb); | |
39 | + depth = reiserfs_write_lock_once(inode->i_sb); | |
39 | 40 | |
40 | 41 | /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */ |
41 | 42 | if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */ |
... | ... | @@ -74,7 +75,7 @@ |
74 | 75 | out: |
75 | 76 | clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */ |
76 | 77 | inode->i_blocks = 0; |
77 | - reiserfs_write_unlock(inode->i_sb); | |
78 | + reiserfs_write_unlock_once(inode->i_sb, depth); | |
78 | 79 | } |
79 | 80 | |
80 | 81 | static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid, |
fs/reiserfs/journal.c
... | ... | @@ -2009,10 +2009,11 @@ |
2009 | 2009 | destroy_workqueue(commit_wq); |
2010 | 2010 | commit_wq = NULL; |
2011 | 2011 | } |
2012 | - reiserfs_write_lock(sb); | |
2013 | 2012 | |
2014 | 2013 | free_journal_ram(sb); |
2015 | 2014 | |
2015 | + reiserfs_write_lock(sb); | |
2016 | + | |
2016 | 2017 | return 0; |
2017 | 2018 | } |
2018 | 2019 | |
2019 | 2020 | |
2020 | 2021 | |
... | ... | @@ -2758,11 +2759,18 @@ |
2758 | 2759 | struct reiserfs_journal *journal; |
2759 | 2760 | struct reiserfs_journal_list *jl; |
2760 | 2761 | char b[BDEVNAME_SIZE]; |
2762 | + int ret; | |
2761 | 2763 | |
2764 | + /* | |
2765 | + * Unlock here to avoid various RECLAIM-FS-ON <-> IN-RECLAIM-FS | |
2766 | + * dependency inversion warnings. | |
2767 | + */ | |
2768 | + reiserfs_write_unlock(sb); | |
2762 | 2769 | journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal)); |
2763 | 2770 | if (!journal) { |
2764 | 2771 | reiserfs_warning(sb, "journal-1256", |
2765 | 2772 | "unable to get memory for journal structure"); |
2773 | + reiserfs_write_lock(sb); | |
2766 | 2774 | return 1; |
2767 | 2775 | } |
2768 | 2776 | memset(journal, 0, sizeof(struct reiserfs_journal)); |
2769 | 2777 | |
... | ... | @@ -2771,10 +2779,12 @@ |
2771 | 2779 | INIT_LIST_HEAD(&journal->j_working_list); |
2772 | 2780 | INIT_LIST_HEAD(&journal->j_journal_list); |
2773 | 2781 | journal->j_persistent_trans = 0; |
2774 | - if (reiserfs_allocate_list_bitmaps(sb, | |
2775 | - journal->j_list_bitmap, | |
2776 | - reiserfs_bmap_count(sb))) | |
2782 | + ret = reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap, | |
2783 | + reiserfs_bmap_count(sb)); | |
2784 | + reiserfs_write_lock(sb); | |
2785 | + if (ret) | |
2777 | 2786 | goto free_and_return; |
2787 | + | |
2778 | 2788 | allocate_bitmap_nodes(sb); |
2779 | 2789 | |
2780 | 2790 | /* reserved for journal area support */ |
fs/reiserfs/lock.c
... | ... | @@ -86,4 +86,13 @@ |
86 | 86 | reiserfs_panic(sb, "%s called without kernel lock held %d", |
87 | 87 | caller); |
88 | 88 | } |
89 | + | |
90 | +#ifdef CONFIG_REISERFS_CHECK | |
91 | +void reiserfs_lock_check_recursive(struct super_block *sb) | |
92 | +{ | |
93 | + struct reiserfs_sb_info *sb_i = REISERFS_SB(sb); | |
94 | + | |
95 | + WARN_ONCE((sb_i->lock_depth > 0), "Unwanted recursive reiserfs lock!\n"); | |
96 | +} | |
97 | +#endif |
fs/reiserfs/namei.c
... | ... | @@ -921,6 +921,7 @@ |
921 | 921 | struct reiserfs_transaction_handle th; |
922 | 922 | int jbegin_count; |
923 | 923 | unsigned long savelink; |
924 | + int depth; | |
924 | 925 | |
925 | 926 | inode = dentry->d_inode; |
926 | 927 | |
... | ... | @@ -932,7 +933,7 @@ |
932 | 933 | JOURNAL_PER_BALANCE_CNT * 2 + 2 + |
933 | 934 | 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); |
934 | 935 | |
935 | - reiserfs_write_lock(dir->i_sb); | |
936 | + depth = reiserfs_write_lock_once(dir->i_sb); | |
936 | 937 | retval = journal_begin(&th, dir->i_sb, jbegin_count); |
937 | 938 | if (retval) |
938 | 939 | goto out_unlink; |
... | ... | @@ -993,7 +994,7 @@ |
993 | 994 | |
994 | 995 | retval = journal_end(&th, dir->i_sb, jbegin_count); |
995 | 996 | reiserfs_check_path(&path); |
996 | - reiserfs_write_unlock(dir->i_sb); | |
997 | + reiserfs_write_unlock_once(dir->i_sb, depth); | |
997 | 998 | return retval; |
998 | 999 | |
999 | 1000 | end_unlink: |
... | ... | @@ -1003,7 +1004,7 @@ |
1003 | 1004 | if (err) |
1004 | 1005 | retval = err; |
1005 | 1006 | out_unlink: |
1006 | - reiserfs_write_unlock(dir->i_sb); | |
1007 | + reiserfs_write_unlock_once(dir->i_sb, depth); | |
1007 | 1008 | return retval; |
1008 | 1009 | } |
1009 | 1010 |
fs/reiserfs/xattr.c
... | ... | @@ -83,7 +83,8 @@ |
83 | 83 | BUG_ON(!mutex_is_locked(&dir->i_mutex)); |
84 | 84 | vfs_dq_init(dir); |
85 | 85 | |
86 | - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | |
86 | + reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex, | |
87 | + I_MUTEX_CHILD, dir->i_sb); | |
87 | 88 | error = dir->i_op->unlink(dir, dentry); |
88 | 89 | mutex_unlock(&dentry->d_inode->i_mutex); |
89 | 90 | |
... | ... | @@ -98,7 +99,8 @@ |
98 | 99 | BUG_ON(!mutex_is_locked(&dir->i_mutex)); |
99 | 100 | vfs_dq_init(dir); |
100 | 101 | |
101 | - mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | |
102 | + reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex, | |
103 | + I_MUTEX_CHILD, dir->i_sb); | |
102 | 104 | dentry_unhash(dentry); |
103 | 105 | error = dir->i_op->rmdir(dir, dentry); |
104 | 106 | if (!error) |
105 | 107 | |
106 | 108 | |
107 | 109 | |
... | ... | @@ -235,16 +237,22 @@ |
235 | 237 | if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1) |
236 | 238 | return 0; |
237 | 239 | |
240 | + reiserfs_write_unlock(inode->i_sb); | |
238 | 241 | dir = open_xa_dir(inode, XATTR_REPLACE); |
239 | 242 | if (IS_ERR(dir)) { |
240 | 243 | err = PTR_ERR(dir); |
244 | + reiserfs_write_lock(inode->i_sb); | |
241 | 245 | goto out; |
242 | 246 | } else if (!dir->d_inode) { |
243 | 247 | err = 0; |
248 | + reiserfs_write_lock(inode->i_sb); | |
244 | 249 | goto out_dir; |
245 | 250 | } |
246 | 251 | |
247 | 252 | mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR); |
253 | + | |
254 | + reiserfs_write_lock(inode->i_sb); | |
255 | + | |
248 | 256 | buf.xadir = dir; |
249 | 257 | err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos); |
250 | 258 | while ((err == 0 || err == -ENOSPC) && buf.count) { |
... | ... | @@ -283,8 +291,9 @@ |
283 | 291 | err = journal_begin(&th, inode->i_sb, blocks); |
284 | 292 | if (!err) { |
285 | 293 | int jerror; |
286 | - mutex_lock_nested(&dir->d_parent->d_inode->i_mutex, | |
287 | - I_MUTEX_XATTR); | |
294 | + reiserfs_mutex_lock_nested_safe( | |
295 | + &dir->d_parent->d_inode->i_mutex, | |
296 | + I_MUTEX_XATTR, inode->i_sb); | |
288 | 297 | err = action(dir, data); |
289 | 298 | jerror = journal_end(&th, inode->i_sb, blocks); |
290 | 299 | mutex_unlock(&dir->d_parent->d_inode->i_mutex); |
291 | 300 | |
292 | 301 | |
293 | 302 | |
... | ... | @@ -480,11 +489,16 @@ |
480 | 489 | if (!buffer) |
481 | 490 | return lookup_and_delete_xattr(inode, name); |
482 | 491 | |
492 | + reiserfs_write_unlock(inode->i_sb); | |
483 | 493 | dentry = xattr_lookup(inode, name, flags); |
484 | - if (IS_ERR(dentry)) | |
494 | + if (IS_ERR(dentry)) { | |
495 | + reiserfs_write_lock(inode->i_sb); | |
485 | 496 | return PTR_ERR(dentry); |
497 | + } | |
486 | 498 | |
487 | - down_write(&REISERFS_I(inode)->i_xattr_sem); | |
499 | + down_read(&REISERFS_I(inode)->i_xattr_sem); | |
500 | + | |
501 | + reiserfs_write_lock(inode->i_sb); | |
488 | 502 | |
489 | 503 | xahash = xattr_hash(buffer, buffer_size); |
490 | 504 | while (buffer_pos < buffer_size || buffer_pos == 0) { |
include/linux/reiserfs_fs.h
... | ... | @@ -62,6 +62,12 @@ |
62 | 62 | int reiserfs_write_lock_once(struct super_block *s); |
63 | 63 | void reiserfs_write_unlock_once(struct super_block *s, int lock_depth); |
64 | 64 | |
65 | +#ifdef CONFIG_REISERFS_CHECK | |
66 | +void reiserfs_lock_check_recursive(struct super_block *s); | |
67 | +#else | |
68 | +static inline void reiserfs_lock_check_recursive(struct super_block *s) { } | |
69 | +#endif | |
70 | + | |
65 | 71 | /* |
66 | 72 | * Several mutexes depend on the write lock. |
67 | 73 | * However sometimes we want to relax the write lock while we hold |
68 | 74 | |
... | ... | @@ -92,8 +98,28 @@ |
92 | 98 | static inline void reiserfs_mutex_lock_safe(struct mutex *m, |
93 | 99 | struct super_block *s) |
94 | 100 | { |
101 | + reiserfs_lock_check_recursive(s); | |
95 | 102 | reiserfs_write_unlock(s); |
96 | 103 | mutex_lock(m); |
104 | + reiserfs_write_lock(s); | |
105 | +} | |
106 | + | |
107 | +static inline void | |
108 | +reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass, | |
109 | + struct super_block *s) | |
110 | +{ | |
111 | + reiserfs_lock_check_recursive(s); | |
112 | + reiserfs_write_unlock(s); | |
113 | + mutex_lock_nested(m, subclass); | |
114 | + reiserfs_write_lock(s); | |
115 | +} | |
116 | + | |
117 | +static inline void | |
118 | +reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s) | |
119 | +{ | |
120 | + reiserfs_lock_check_recursive(s); | |
121 | + reiserfs_write_unlock(s); | |
122 | + down_read(sem); | |
97 | 123 | reiserfs_write_lock(s); |
98 | 124 | } |
99 | 125 |