orangefs: fix orangefs_superblock locking

* switch orangefs_remount() to taking ORANGEFS_SB(sb) instead of sb
* remove from the list _before_ orangefs_unmount() - request_mutex
in the latter will make sure that nothing observed in the loop in
ORANGEFS_DEV_REMOUNT_ALL handling will get freed until the end
of loop
* on removal, keep the forward pointer and zero the back one. That
way we can drop and regain the spinlock in the loop body (again,
ORANGEFS_DEV_REMOUNT_ALL one) and still be able to get to the
rest of the list.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Mike Marshall <hubcap@omnibond.com>

authored by Al Viro and committed by Mike Marshall 45996492 6d4c1a30

Changed files
+48 -59
fs
+24 -19
fs/orangefs/devorangefs-req.c
··· 572 572 struct dev_mask_info_s mask_info = { 0 }; 573 573 struct dev_mask2_info_s mask2_info = { 0, 0 }; 574 574 int upstream_kmod = 1; 575 - struct list_head *tmp = NULL; 576 - struct orangefs_sb_info_s *orangefs_sb = NULL; 575 + struct orangefs_sb_info_s *orangefs_sb; 577 576 578 577 /* mtmoore: add locking here */ 579 578 ··· 618 619 gossip_debug(GOSSIP_DEV_DEBUG, 619 620 "%s: priority remount in progress\n", 620 621 __func__); 621 - list_for_each(tmp, &orangefs_superblocks) { 622 - orangefs_sb = 623 - list_entry(tmp, 624 - struct orangefs_sb_info_s, 625 - list); 626 - if (orangefs_sb && (orangefs_sb->sb)) { 627 - gossip_debug(GOSSIP_DEV_DEBUG, 628 - "%s: Remounting SB %p\n", 629 - __func__, 630 - orangefs_sb); 622 + spin_lock(&orangefs_superblocks_lock); 623 + list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { 624 + /* 625 + * We have to drop the spinlock, so entries can be 626 + * removed. They can't be freed, though, so we just 627 + * keep the forward pointers and zero the back ones - 628 + * that way we can get to the rest of the list. 629 + */ 630 + if (!orangefs_sb->list.prev) 631 + continue; 632 + gossip_debug(GOSSIP_DEV_DEBUG, 633 + "%s: Remounting SB %p\n", 634 + __func__, 635 + orangefs_sb); 631 636 632 - ret = orangefs_remount(orangefs_sb->sb); 633 - if (ret) { 634 - gossip_debug(GOSSIP_DEV_DEBUG, 635 - "SB %p remount failed\n", 636 - orangefs_sb); 637 - break; 638 - } 637 + spin_unlock(&orangefs_superblocks_lock); 638 + ret = orangefs_remount(orangefs_sb); 639 + spin_lock(&orangefs_superblocks_lock); 640 + if (ret) { 641 + gossip_debug(GOSSIP_DEV_DEBUG, 642 + "SB %p remount failed\n", 643 + orangefs_sb); 644 + break; 639 645 } 640 646 } 647 + spin_unlock(&orangefs_superblocks_lock); 641 648 gossip_debug(GOSSIP_DEV_DEBUG, 642 649 "%s: priority remount complete\n", 643 650 __func__);
+1 -33
fs/orangefs/orangefs-kernel.h
··· 462 462 void *data); 463 463 464 464 void orangefs_kill_sb(struct super_block *sb); 465 - int orangefs_remount(struct super_block *sb); 465 + int orangefs_remount(struct orangefs_sb_info_s *); 466 466 467 467 int fsid_key_table_initialize(void); 468 468 void fsid_key_table_finalize(void); ··· 597 597 #define get_interruptible_flag(inode) \ 598 598 ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \ 599 599 ORANGEFS_OP_INTERRUPTIBLE : 0) 600 - 601 - #define add_orangefs_sb(sb) \ 602 - do { \ 603 - gossip_debug(GOSSIP_SUPER_DEBUG, \ 604 - "Adding SB %p to orangefs superblocks\n", \ 605 - ORANGEFS_SB(sb)); \ 606 - spin_lock(&orangefs_superblocks_lock); \ 607 - list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); \ 608 - spin_unlock(&orangefs_superblocks_lock); \ 609 - } while (0) 610 - 611 - #define remove_orangefs_sb(sb) \ 612 - do { \ 613 - struct list_head *tmp = NULL; \ 614 - struct list_head *tmp_safe = NULL; \ 615 - struct orangefs_sb_info_s *orangefs_sb = NULL; \ 616 - \ 617 - spin_lock(&orangefs_superblocks_lock); \ 618 - list_for_each_safe(tmp, tmp_safe, &orangefs_superblocks) { \ 619 - orangefs_sb = list_entry(tmp, \ 620 - struct orangefs_sb_info_s, \ 621 - list); \ 622 - if (orangefs_sb && (orangefs_sb->sb == sb)) { \ 623 - gossip_debug(GOSSIP_SUPER_DEBUG, \ 624 - "Removing SB %p from orangefs superblocks\n", \ 625 - orangefs_sb); \ 626 - list_del(&orangefs_sb->list); \ 627 - break; \ 628 - } \ 629 - } \ 630 - spin_unlock(&orangefs_superblocks_lock); \ 631 - } while (0) 632 600 633 601 #define fill_default_sys_attrs(sys_attr, type, mode) \ 634 602 do { \
+23 -7
fs/orangefs/super.c
··· 210 210 * the client regains all of the mount information from us. 211 211 * NOTE: this function assumes that the request_mutex is already acquired! 212 212 */ 213 - int orangefs_remount(struct super_block *sb) 213 + int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb) 214 214 { 215 215 struct orangefs_kernel_op_s *new_op; 216 216 int ret = -EINVAL; ··· 221 221 if (!new_op) 222 222 return -ENOMEM; 223 223 strncpy(new_op->upcall.req.fs_mount.orangefs_config_server, 224 - ORANGEFS_SB(sb)->devname, 224 + orangefs_sb->devname, 225 225 ORANGEFS_MAX_SERVER_ADDR_LEN); 226 226 227 227 gossip_debug(GOSSIP_SUPER_DEBUG, ··· 244 244 * short-lived mapping that the system interface uses 245 245 * to map this superblock to a particular mount entry 246 246 */ 247 - ORANGEFS_SB(sb)->id = new_op->downcall.resp.fs_mount.id; 248 - ORANGEFS_SB(sb)->mount_pending = 0; 247 + orangefs_sb->id = new_op->downcall.resp.fs_mount.id; 248 + orangefs_sb->mount_pending = 0; 249 249 } 250 250 251 251 op_release(new_op); ··· 485 485 * finally, add this sb to our list of known orangefs 486 486 * sb's 487 487 */ 488 - add_orangefs_sb(sb); 488 + gossip_debug(GOSSIP_SUPER_DEBUG, 489 + "Adding SB %p to orangefs superblocks\n", 490 + ORANGEFS_SB(sb)); 491 + spin_lock(&orangefs_superblocks_lock); 492 + list_add_tail(&ORANGEFS_SB(sb)->list, &orangefs_superblocks); 493 + spin_unlock(&orangefs_superblocks_lock); 489 494 op_release(new_op); 490 495 return dget(sb->s_root); 491 496 ··· 517 512 * issue the unmount to userspace to tell it to remove the 518 513 * dynamic mount info it has for this superblock 519 514 */ 520 - orangefs_unmount_sb(sb); 515 + orangefs_unmount_sb(sb); 521 516 522 517 /* remove the sb from our list of orangefs specific sb's */ 523 - remove_orangefs_sb(sb); 518 + 519 + spin_lock(&orangefs_superblocks_lock); 520 + __list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */ 521 + ORANGEFS_SB(sb)->list.prev = NULL; 522 + spin_unlock(&orangefs_superblocks_lock); 523 + 524 + /* 525 + * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us 526 + * gets completed before we free the dang thing. 527 + */ 528 + mutex_lock(&request_mutex); 529 + mutex_unlock(&request_mutex); 524 530 525 531 /* free the orangefs superblock private data */ 526 532 kfree(ORANGEFS_SB(sb));