Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

orangefs: free superblock when mount fails

Otherwise lockdep says:

[ 1337.483798] ================================================
[ 1337.483999] [ BUG: lock held when returning to user space! ]
[ 1337.484252] 4.11.0-rc6 #19 Not tainted
[ 1337.484423] ------------------------------------------------
[ 1337.484626] mount/14766 is leaving the kernel with locks still held!
[ 1337.484841] 1 lock held by mount/14766:
[ 1337.485017] #0: (&type->s_umount_key#33/1){+.+.+.}, at: [<ffffffff8124171f>] sget_userns+0x2af/0x520

Caught by xfstests generic/413 which tried to mount with the unsupported
mount option dax. Then xfstests generic/422 ran sync which deadlocks.

Signed-off-by: Martin Brandenburg <martin@omnibond.com>
Acked-by: Mike Marshall <hubcap@omnibond.com>
Cc: stable@vger.kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Martin Brandenburg and committed by
Linus Torvalds
1ec1688c c0eb027e

+24 -9
+7 -2
fs/orangefs/devorangefs-req.c
··· 208 208 continue; 209 209 /* 210 210 * Skip ops whose filesystem we don't know about unless 211 - * it is being mounted. 211 + * it is being mounted or unmounted. It is possible for 212 + * a filesystem we don't know about to be unmounted if 213 + * it fails to mount in the kernel after userspace has 214 + * been sent the mount request. 212 215 */ 213 216 /* XXX: is there a better way to detect this? */ 214 217 } else if (ret == -1 && 215 218 !(op->upcall.type == 216 219 ORANGEFS_VFS_OP_FS_MOUNT || 217 220 op->upcall.type == 218 - ORANGEFS_VFS_OP_GETATTR)) { 221 + ORANGEFS_VFS_OP_GETATTR || 222 + op->upcall.type == 223 + ORANGEFS_VFS_OP_FS_UMOUNT)) { 219 224 gossip_debug(GOSSIP_DEV_DEBUG, 220 225 "orangefs: skipping op tag %llu %s\n", 221 226 llu(op->tag), get_opname_string(op));
+1
fs/orangefs/orangefs-kernel.h
··· 249 249 char devname[ORANGEFS_MAX_SERVER_ADDR_LEN]; 250 250 struct super_block *sb; 251 251 int mount_pending; 252 + int no_list; 252 253 struct list_head list; 253 254 }; 254 255
+16 -7
fs/orangefs/super.c
··· 493 493 494 494 if (ret) { 495 495 d = ERR_PTR(ret); 496 - goto free_op; 496 + goto free_sb_and_op; 497 497 } 498 498 499 499 /* ··· 519 519 spin_unlock(&orangefs_superblocks_lock); 520 520 op_release(new_op); 521 521 522 + /* Must be removed from the list now. */ 523 + ORANGEFS_SB(sb)->no_list = 0; 524 + 522 525 if (orangefs_userspace_version >= 20906) { 523 526 new_op = op_alloc(ORANGEFS_VFS_OP_FEATURES); 524 527 if (!new_op) ··· 536 533 537 534 return dget(sb->s_root); 538 535 536 + free_sb_and_op: 537 + /* Will call orangefs_kill_sb with sb not in list. */ 538 + ORANGEFS_SB(sb)->no_list = 1; 539 + deactivate_locked_super(sb); 539 540 free_op: 540 541 gossip_err("orangefs_mount: mount request failed with %d\n", ret); 541 542 if (ret == -EINVAL) { ··· 565 558 */ 566 559 orangefs_unmount_sb(sb); 567 560 568 - /* remove the sb from our list of orangefs specific sb's */ 569 - 570 - spin_lock(&orangefs_superblocks_lock); 571 - __list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */ 572 - ORANGEFS_SB(sb)->list.prev = NULL; 573 - spin_unlock(&orangefs_superblocks_lock); 561 + if (!ORANGEFS_SB(sb)->no_list) { 562 + /* remove the sb from our list of orangefs specific sb's */ 563 + spin_lock(&orangefs_superblocks_lock); 564 + /* not list_del_init */ 565 + __list_del_entry(&ORANGEFS_SB(sb)->list); 566 + ORANGEFS_SB(sb)->list.prev = NULL; 567 + spin_unlock(&orangefs_superblocks_lock); 568 + } 574 569 575 570 /* 576 571 * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us