aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabian Frederick <fabf@skynet.be>2015-06-09 20:09:32 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-10 12:49:38 -0400
commit0da5a72210cbe177ab1043be058403ca49eb7a2b (patch)
treefef6e817f2efaf4c44ff3dfe96f3c3210a476532
parent60c92e3205a6eb78c7970bf370cc9c550bd0c132 (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.c34
-rw-r--r--fs/ufs/ialloc.c16
-rw-r--r--fs/ufs/super.c10
-rw-r--r--fs/ufs/ufs.h1
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
123failed: 123failed:
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
156do_more: 156do_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
218failed_unlock: 218failed_unlock:
219 unlock_ufs(sb); 219 mutex_unlock(&UFS_SB(sb)->s_lock);
220failed: 220failed:
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
340fail_remove_inode: 340fail_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);
347failed: 347failed:
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
35struct ufs_inode_info { 36struct ufs_inode_info {