diff options
author | Fabian Frederick <fabf@skynet.be> | 2015-06-09 20:09:32 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-07-10 12:49:38 -0400 |
commit | 0da5a72210cbe177ab1043be058403ca49eb7a2b (patch) | |
tree | fef6e817f2efaf4c44ff3dfe96f3c3210a476532 | |
parent | 60c92e3205a6eb78c7970bf370cc9c550bd0c132 (diff) |
fs/ufs: restore s_lock mutex
commit cdd9eefdf905e92e7fc6cc393314efe68dc6ff66 upstream.
Commit 0244756edc4b98c ("ufs: sb mutex merge + mutex_destroy") generated
deadlocks in read/write mode on mkdir.
This patch partially reverts it keeping fixes by Andrew Morton and
mutex_destroy()
[AV: fixed a missing bit in ufs_remount()]
Signed-off-by: Fabian Frederick <fabf@skynet.be>
Reported-by: Ian Campbell <ian.campbell@citrix.com>
Suggested-by: Jan Kara <jack@suse.cz>
Cc: Ian Campbell <ian.campbell@citrix.com>
Cc: Evgeniy Dushistov <dushistov@mail.ru>
Cc: Alexey Khoroshilov <khoroshilov@ispras.ru>
Cc: Roger Pau Monne <roger.pau@citrix.com>
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | fs/ufs/balloc.c | 34 | ||||
-rw-r--r-- | fs/ufs/ialloc.c | 16 | ||||
-rw-r--r-- | fs/ufs/super.c | 10 | ||||
-rw-r--r-- | fs/ufs/ufs.h | 1 |
4 files changed, 36 insertions, 25 deletions
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 2c1036080d52..a7106eda5024 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c | |||
@@ -51,8 +51,8 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) | |||
51 | 51 | ||
52 | if (ufs_fragnum(fragment) + count > uspi->s_fpg) | 52 | if (ufs_fragnum(fragment) + count > uspi->s_fpg) |
53 | ufs_error (sb, "ufs_free_fragments", "internal error"); | 53 | ufs_error (sb, "ufs_free_fragments", "internal error"); |
54 | 54 | ||
55 | lock_ufs(sb); | 55 | mutex_lock(&UFS_SB(sb)->s_lock); |
56 | 56 | ||
57 | cgno = ufs_dtog(uspi, fragment); | 57 | cgno = ufs_dtog(uspi, fragment); |
58 | bit = ufs_dtogd(uspi, fragment); | 58 | bit = ufs_dtogd(uspi, fragment); |
@@ -115,13 +115,13 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) | |||
115 | if (sb->s_flags & MS_SYNCHRONOUS) | 115 | if (sb->s_flags & MS_SYNCHRONOUS) |
116 | ubh_sync_block(UCPI_UBH(ucpi)); | 116 | ubh_sync_block(UCPI_UBH(ucpi)); |
117 | ufs_mark_sb_dirty(sb); | 117 | ufs_mark_sb_dirty(sb); |
118 | 118 | ||
119 | unlock_ufs(sb); | 119 | mutex_unlock(&UFS_SB(sb)->s_lock); |
120 | UFSD("EXIT\n"); | 120 | UFSD("EXIT\n"); |
121 | return; | 121 | return; |
122 | 122 | ||
123 | failed: | 123 | failed: |
124 | unlock_ufs(sb); | 124 | mutex_unlock(&UFS_SB(sb)->s_lock); |
125 | UFSD("EXIT (FAILED)\n"); | 125 | UFSD("EXIT (FAILED)\n"); |
126 | return; | 126 | return; |
127 | } | 127 | } |
@@ -151,7 +151,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count) | |||
151 | goto failed; | 151 | goto failed; |
152 | } | 152 | } |
153 | 153 | ||
154 | lock_ufs(sb); | 154 | mutex_lock(&UFS_SB(sb)->s_lock); |
155 | 155 | ||
156 | do_more: | 156 | do_more: |
157 | overflow = 0; | 157 | overflow = 0; |
@@ -211,12 +211,12 @@ do_more: | |||
211 | } | 211 | } |
212 | 212 | ||
213 | ufs_mark_sb_dirty(sb); | 213 | ufs_mark_sb_dirty(sb); |
214 | unlock_ufs(sb); | 214 | mutex_unlock(&UFS_SB(sb)->s_lock); |
215 | UFSD("EXIT\n"); | 215 | UFSD("EXIT\n"); |
216 | return; | 216 | return; |
217 | 217 | ||
218 | failed_unlock: | 218 | failed_unlock: |
219 | unlock_ufs(sb); | 219 | mutex_unlock(&UFS_SB(sb)->s_lock); |
220 | failed: | 220 | failed: |
221 | UFSD("EXIT (FAILED)\n"); | 221 | UFSD("EXIT (FAILED)\n"); |
222 | return; | 222 | return; |
@@ -357,7 +357,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
357 | usb1 = ubh_get_usb_first(uspi); | 357 | usb1 = ubh_get_usb_first(uspi); |
358 | *err = -ENOSPC; | 358 | *err = -ENOSPC; |
359 | 359 | ||
360 | lock_ufs(sb); | 360 | mutex_lock(&UFS_SB(sb)->s_lock); |
361 | tmp = ufs_data_ptr_to_cpu(sb, p); | 361 | tmp = ufs_data_ptr_to_cpu(sb, p); |
362 | 362 | ||
363 | if (count + ufs_fragnum(fragment) > uspi->s_fpb) { | 363 | if (count + ufs_fragnum(fragment) > uspi->s_fpb) { |
@@ -378,19 +378,19 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
378 | "fragment %llu, tmp %llu\n", | 378 | "fragment %llu, tmp %llu\n", |
379 | (unsigned long long)fragment, | 379 | (unsigned long long)fragment, |
380 | (unsigned long long)tmp); | 380 | (unsigned long long)tmp); |
381 | unlock_ufs(sb); | 381 | mutex_unlock(&UFS_SB(sb)->s_lock); |
382 | return INVBLOCK; | 382 | return INVBLOCK; |
383 | } | 383 | } |
384 | if (fragment < UFS_I(inode)->i_lastfrag) { | 384 | if (fragment < UFS_I(inode)->i_lastfrag) { |
385 | UFSD("EXIT (ALREADY ALLOCATED)\n"); | 385 | UFSD("EXIT (ALREADY ALLOCATED)\n"); |
386 | unlock_ufs(sb); | 386 | mutex_unlock(&UFS_SB(sb)->s_lock); |
387 | return 0; | 387 | return 0; |
388 | } | 388 | } |
389 | } | 389 | } |
390 | else { | 390 | else { |
391 | if (tmp) { | 391 | if (tmp) { |
392 | UFSD("EXIT (ALREADY ALLOCATED)\n"); | 392 | UFSD("EXIT (ALREADY ALLOCATED)\n"); |
393 | unlock_ufs(sb); | 393 | mutex_unlock(&UFS_SB(sb)->s_lock); |
394 | return 0; | 394 | return 0; |
395 | } | 395 | } |
396 | } | 396 | } |
@@ -399,7 +399,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
399 | * There is not enough space for user on the device | 399 | * There is not enough space for user on the device |
400 | */ | 400 | */ |
401 | if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { | 401 | if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { |
402 | unlock_ufs(sb); | 402 | mutex_unlock(&UFS_SB(sb)->s_lock); |
403 | UFSD("EXIT (FAILED)\n"); | 403 | UFSD("EXIT (FAILED)\n"); |
404 | return 0; | 404 | return 0; |
405 | } | 405 | } |
@@ -424,7 +424,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
424 | ufs_clear_frags(inode, result + oldcount, | 424 | ufs_clear_frags(inode, result + oldcount, |
425 | newcount - oldcount, locked_page != NULL); | 425 | newcount - oldcount, locked_page != NULL); |
426 | } | 426 | } |
427 | unlock_ufs(sb); | 427 | mutex_unlock(&UFS_SB(sb)->s_lock); |
428 | UFSD("EXIT, result %llu\n", (unsigned long long)result); | 428 | UFSD("EXIT, result %llu\n", (unsigned long long)result); |
429 | return result; | 429 | return result; |
430 | } | 430 | } |
@@ -439,7 +439,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
439 | fragment + count); | 439 | fragment + count); |
440 | ufs_clear_frags(inode, result + oldcount, newcount - oldcount, | 440 | ufs_clear_frags(inode, result + oldcount, newcount - oldcount, |
441 | locked_page != NULL); | 441 | locked_page != NULL); |
442 | unlock_ufs(sb); | 442 | mutex_unlock(&UFS_SB(sb)->s_lock); |
443 | UFSD("EXIT, result %llu\n", (unsigned long long)result); | 443 | UFSD("EXIT, result %llu\n", (unsigned long long)result); |
444 | return result; | 444 | return result; |
445 | } | 445 | } |
@@ -477,7 +477,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
477 | *err = 0; | 477 | *err = 0; |
478 | UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, | 478 | UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, |
479 | fragment + count); | 479 | fragment + count); |
480 | unlock_ufs(sb); | 480 | mutex_unlock(&UFS_SB(sb)->s_lock); |
481 | if (newcount < request) | 481 | if (newcount < request) |
482 | ufs_free_fragments (inode, result + newcount, request - newcount); | 482 | ufs_free_fragments (inode, result + newcount, request - newcount); |
483 | ufs_free_fragments (inode, tmp, oldcount); | 483 | ufs_free_fragments (inode, tmp, oldcount); |
@@ -485,7 +485,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, | |||
485 | return result; | 485 | return result; |
486 | } | 486 | } |
487 | 487 | ||
488 | unlock_ufs(sb); | 488 | mutex_unlock(&UFS_SB(sb)->s_lock); |
489 | UFSD("EXIT (FAILED)\n"); | 489 | UFSD("EXIT (FAILED)\n"); |
490 | return 0; | 490 | return 0; |
491 | } | 491 | } |
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 7caa01652888..fd0203ce1f7f 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c | |||
@@ -69,11 +69,11 @@ void ufs_free_inode (struct inode * inode) | |||
69 | 69 | ||
70 | ino = inode->i_ino; | 70 | ino = inode->i_ino; |
71 | 71 | ||
72 | lock_ufs(sb); | 72 | mutex_lock(&UFS_SB(sb)->s_lock); |
73 | 73 | ||
74 | if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) { | 74 | if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) { |
75 | ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); | 75 | ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); |
76 | unlock_ufs(sb); | 76 | mutex_unlock(&UFS_SB(sb)->s_lock); |
77 | return; | 77 | return; |
78 | } | 78 | } |
79 | 79 | ||
@@ -81,7 +81,7 @@ void ufs_free_inode (struct inode * inode) | |||
81 | bit = ufs_inotocgoff (ino); | 81 | bit = ufs_inotocgoff (ino); |
82 | ucpi = ufs_load_cylinder (sb, cg); | 82 | ucpi = ufs_load_cylinder (sb, cg); |
83 | if (!ucpi) { | 83 | if (!ucpi) { |
84 | unlock_ufs(sb); | 84 | mutex_unlock(&UFS_SB(sb)->s_lock); |
85 | return; | 85 | return; |
86 | } | 86 | } |
87 | ucg = ubh_get_ucg(UCPI_UBH(ucpi)); | 87 | ucg = ubh_get_ucg(UCPI_UBH(ucpi)); |
@@ -115,7 +115,7 @@ void ufs_free_inode (struct inode * inode) | |||
115 | ubh_sync_block(UCPI_UBH(ucpi)); | 115 | ubh_sync_block(UCPI_UBH(ucpi)); |
116 | 116 | ||
117 | ufs_mark_sb_dirty(sb); | 117 | ufs_mark_sb_dirty(sb); |
118 | unlock_ufs(sb); | 118 | mutex_unlock(&UFS_SB(sb)->s_lock); |
119 | UFSD("EXIT\n"); | 119 | UFSD("EXIT\n"); |
120 | } | 120 | } |
121 | 121 | ||
@@ -193,7 +193,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode) | |||
193 | sbi = UFS_SB(sb); | 193 | sbi = UFS_SB(sb); |
194 | uspi = sbi->s_uspi; | 194 | uspi = sbi->s_uspi; |
195 | 195 | ||
196 | lock_ufs(sb); | 196 | mutex_lock(&sbi->s_lock); |
197 | 197 | ||
198 | /* | 198 | /* |
199 | * Try to place the inode in its parent directory | 199 | * Try to place the inode in its parent directory |
@@ -331,21 +331,21 @@ cg_found: | |||
331 | sync_dirty_buffer(bh); | 331 | sync_dirty_buffer(bh); |
332 | brelse(bh); | 332 | brelse(bh); |
333 | } | 333 | } |
334 | unlock_ufs(sb); | 334 | mutex_unlock(&sbi->s_lock); |
335 | 335 | ||
336 | UFSD("allocating inode %lu\n", inode->i_ino); | 336 | UFSD("allocating inode %lu\n", inode->i_ino); |
337 | UFSD("EXIT\n"); | 337 | UFSD("EXIT\n"); |
338 | return inode; | 338 | return inode; |
339 | 339 | ||
340 | fail_remove_inode: | 340 | fail_remove_inode: |
341 | unlock_ufs(sb); | 341 | mutex_unlock(&sbi->s_lock); |
342 | clear_nlink(inode); | 342 | clear_nlink(inode); |
343 | unlock_new_inode(inode); | 343 | unlock_new_inode(inode); |
344 | iput(inode); | 344 | iput(inode); |
345 | UFSD("EXIT (FAILED): err %d\n", err); | 345 | UFSD("EXIT (FAILED): err %d\n", err); |
346 | return ERR_PTR(err); | 346 | return ERR_PTR(err); |
347 | failed: | 347 | failed: |
348 | unlock_ufs(sb); | 348 | mutex_unlock(&sbi->s_lock); |
349 | make_bad_inode(inode); | 349 | make_bad_inode(inode); |
350 | iput (inode); | 350 | iput (inode); |
351 | UFSD("EXIT (FAILED): err %d\n", err); | 351 | UFSD("EXIT (FAILED): err %d\n", err); |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index b3bc3e7ae79d..afe9955654c8 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
@@ -694,6 +694,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait) | |||
694 | unsigned flags; | 694 | unsigned flags; |
695 | 695 | ||
696 | lock_ufs(sb); | 696 | lock_ufs(sb); |
697 | mutex_lock(&UFS_SB(sb)->s_lock); | ||
697 | 698 | ||
698 | UFSD("ENTER\n"); | 699 | UFSD("ENTER\n"); |
699 | 700 | ||
@@ -711,6 +712,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait) | |||
711 | ufs_put_cstotal(sb); | 712 | ufs_put_cstotal(sb); |
712 | 713 | ||
713 | UFSD("EXIT\n"); | 714 | UFSD("EXIT\n"); |
715 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
714 | unlock_ufs(sb); | 716 | unlock_ufs(sb); |
715 | 717 | ||
716 | return 0; | 718 | return 0; |
@@ -1277,6 +1279,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1277 | 1279 | ||
1278 | sync_filesystem(sb); | 1280 | sync_filesystem(sb); |
1279 | lock_ufs(sb); | 1281 | lock_ufs(sb); |
1282 | mutex_lock(&UFS_SB(sb)->s_lock); | ||
1280 | uspi = UFS_SB(sb)->s_uspi; | 1283 | uspi = UFS_SB(sb)->s_uspi; |
1281 | flags = UFS_SB(sb)->s_flags; | 1284 | flags = UFS_SB(sb)->s_flags; |
1282 | usb1 = ubh_get_usb_first(uspi); | 1285 | usb1 = ubh_get_usb_first(uspi); |
@@ -1290,6 +1293,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1290 | new_mount_opt = 0; | 1293 | new_mount_opt = 0; |
1291 | ufs_set_opt (new_mount_opt, ONERROR_LOCK); | 1294 | ufs_set_opt (new_mount_opt, ONERROR_LOCK); |
1292 | if (!ufs_parse_options (data, &new_mount_opt)) { | 1295 | if (!ufs_parse_options (data, &new_mount_opt)) { |
1296 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1293 | unlock_ufs(sb); | 1297 | unlock_ufs(sb); |
1294 | return -EINVAL; | 1298 | return -EINVAL; |
1295 | } | 1299 | } |
@@ -1297,12 +1301,14 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1297 | new_mount_opt |= ufstype; | 1301 | new_mount_opt |= ufstype; |
1298 | } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { | 1302 | } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { |
1299 | pr_err("ufstype can't be changed during remount\n"); | 1303 | pr_err("ufstype can't be changed during remount\n"); |
1304 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1300 | unlock_ufs(sb); | 1305 | unlock_ufs(sb); |
1301 | return -EINVAL; | 1306 | return -EINVAL; |
1302 | } | 1307 | } |
1303 | 1308 | ||
1304 | if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { | 1309 | if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
1305 | UFS_SB(sb)->s_mount_opt = new_mount_opt; | 1310 | UFS_SB(sb)->s_mount_opt = new_mount_opt; |
1311 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1306 | unlock_ufs(sb); | 1312 | unlock_ufs(sb); |
1307 | return 0; | 1313 | return 0; |
1308 | } | 1314 | } |
@@ -1326,6 +1332,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1326 | */ | 1332 | */ |
1327 | #ifndef CONFIG_UFS_FS_WRITE | 1333 | #ifndef CONFIG_UFS_FS_WRITE |
1328 | pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); | 1334 | pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); |
1335 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1329 | unlock_ufs(sb); | 1336 | unlock_ufs(sb); |
1330 | return -EINVAL; | 1337 | return -EINVAL; |
1331 | #else | 1338 | #else |
@@ -1335,11 +1342,13 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1335 | ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && | 1342 | ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && |
1336 | ufstype != UFS_MOUNT_UFSTYPE_UFS2) { | 1343 | ufstype != UFS_MOUNT_UFSTYPE_UFS2) { |
1337 | pr_err("this ufstype is read-only supported\n"); | 1344 | pr_err("this ufstype is read-only supported\n"); |
1345 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1338 | unlock_ufs(sb); | 1346 | unlock_ufs(sb); |
1339 | return -EINVAL; | 1347 | return -EINVAL; |
1340 | } | 1348 | } |
1341 | if (!ufs_read_cylinder_structures(sb)) { | 1349 | if (!ufs_read_cylinder_structures(sb)) { |
1342 | pr_err("failed during remounting\n"); | 1350 | pr_err("failed during remounting\n"); |
1351 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1343 | unlock_ufs(sb); | 1352 | unlock_ufs(sb); |
1344 | return -EPERM; | 1353 | return -EPERM; |
1345 | } | 1354 | } |
@@ -1347,6 +1356,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
1347 | #endif | 1356 | #endif |
1348 | } | 1357 | } |
1349 | UFS_SB(sb)->s_mount_opt = new_mount_opt; | 1358 | UFS_SB(sb)->s_mount_opt = new_mount_opt; |
1359 | mutex_unlock(&UFS_SB(sb)->s_lock); | ||
1350 | unlock_ufs(sb); | 1360 | unlock_ufs(sb); |
1351 | return 0; | 1361 | return 0; |
1352 | } | 1362 | } |
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 2a07396d5f9e..cf6368d42d4a 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h | |||
@@ -30,6 +30,7 @@ struct ufs_sb_info { | |||
30 | int work_queued; /* non-zero if the delayed work is queued */ | 30 | int work_queued; /* non-zero if the delayed work is queued */ |
31 | struct delayed_work sync_work; /* FS sync delayed work */ | 31 | struct delayed_work sync_work; /* FS sync delayed work */ |
32 | spinlock_t work_lock; /* protects sync_work and work_queued */ | 32 | spinlock_t work_lock; /* protects sync_work and work_queued */ |
33 | struct mutex s_lock; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct ufs_inode_info { | 36 | struct ufs_inode_info { |