aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-03-25 19:56:34 -0400
committerMike Marshall <hubcap@omnibond.com>2016-03-26 07:22:00 -0400
commit45996492e5c85aa0ac93a95d1b2d1ed56851c865 (patch)
tree3ee74b07ce43cdb0b637c3747fadbb1f2ba59eb6
parent6d4c1a30b32a377083900f39c42bcacb633f99a1 (diff)
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>
-rw-r--r--fs/orangefs/devorangefs-req.c41
-rw-r--r--fs/orangefs/orangefs-kernel.h34
-rw-r--r--fs/orangefs/super.c30
3 files changed, 47 insertions, 58 deletions
diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c
index 35418d0b77bf..db170beba797 100644
--- a/fs/orangefs/devorangefs-req.c
+++ b/fs/orangefs/devorangefs-req.c
@@ -572,8 +572,7 @@ static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
572 struct dev_mask_info_s mask_info = { 0 }; 572 struct dev_mask_info_s mask_info = { 0 };
573 struct dev_mask2_info_s mask2_info = { 0, 0 }; 573 struct dev_mask2_info_s mask2_info = { 0, 0 };
574 int upstream_kmod = 1; 574 int upstream_kmod = 1;
575 struct list_head *tmp = NULL; 575 struct orangefs_sb_info_s *orangefs_sb;
576 struct orangefs_sb_info_s *orangefs_sb = NULL;
577 576
578 /* mtmoore: add locking here */ 577 /* mtmoore: add locking here */
579 578
@@ -619,26 +618,32 @@ static long dispatch_ioctl_command(unsigned int command, unsigned long arg)
619 gossip_debug(GOSSIP_DEV_DEBUG, 618 gossip_debug(GOSSIP_DEV_DEBUG,
620 "%s: priority remount in progress\n", 619 "%s: priority remount in progress\n",
621 __func__); 620 __func__);
622 list_for_each(tmp, &orangefs_superblocks) { 621 spin_lock(&orangefs_superblocks_lock);
623 orangefs_sb = 622 list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) {
624 list_entry(tmp, 623 /*
625 struct orangefs_sb_info_s, 624 * We have to drop the spinlock, so entries can be
626 list); 625 * removed. They can't be freed, though, so we just
627 if (orangefs_sb && (orangefs_sb->sb)) { 626 * keep the forward pointers and zero the back ones -
627 * that way we can get to the rest of the list.
628 */
629 if (!orangefs_sb->list.prev)
630 continue;
631 gossip_debug(GOSSIP_DEV_DEBUG,
632 "%s: Remounting SB %p\n",
633 __func__,
634 orangefs_sb);
635
636 spin_unlock(&orangefs_superblocks_lock);
637 ret = orangefs_remount(orangefs_sb);
638 spin_lock(&orangefs_superblocks_lock);
639 if (ret) {
628 gossip_debug(GOSSIP_DEV_DEBUG, 640 gossip_debug(GOSSIP_DEV_DEBUG,
629 "%s: Remounting SB %p\n", 641 "SB %p remount failed\n",
630 __func__,
631 orangefs_sb); 642 orangefs_sb);
632 643 break;
633 ret = orangefs_remount(orangefs_sb->sb);
634 if (ret) {
635 gossip_debug(GOSSIP_DEV_DEBUG,
636 "SB %p remount failed\n",
637 orangefs_sb);
638 break;
639 }
640 } 644 }
641 } 645 }
646 spin_unlock(&orangefs_superblocks_lock);
642 gossip_debug(GOSSIP_DEV_DEBUG, 647 gossip_debug(GOSSIP_DEV_DEBUG,
643 "%s: priority remount complete\n", 648 "%s: priority remount complete\n",
644 __func__); 649 __func__);
diff --git a/fs/orangefs/orangefs-kernel.h b/fs/orangefs/orangefs-kernel.h
index db258d2ccc6a..a9925e296ceb 100644
--- a/fs/orangefs/orangefs-kernel.h
+++ b/fs/orangefs/orangefs-kernel.h
@@ -462,7 +462,7 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
462 void *data); 462 void *data);
463 463
464void orangefs_kill_sb(struct super_block *sb); 464void orangefs_kill_sb(struct super_block *sb);
465int orangefs_remount(struct super_block *sb); 465int orangefs_remount(struct orangefs_sb_info_s *);
466 466
467int fsid_key_table_initialize(void); 467int fsid_key_table_initialize(void);
468void fsid_key_table_finalize(void); 468void fsid_key_table_finalize(void);
@@ -598,38 +598,6 @@ int service_operation(struct orangefs_kernel_op_s *op,
598 ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \ 598 ((ORANGEFS_SB(inode->i_sb)->flags & ORANGEFS_OPT_INTR) ? \
599 ORANGEFS_OP_INTERRUPTIBLE : 0) 599 ORANGEFS_OP_INTERRUPTIBLE : 0)
600 600
601#define add_orangefs_sb(sb) \
602do { \
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) \
612do { \
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
633#define fill_default_sys_attrs(sys_attr, type, mode) \ 601#define fill_default_sys_attrs(sys_attr, type, mode) \
634do { \ 602do { \
635 sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \ 603 sys_attr.owner = from_kuid(current_user_ns(), current_fsuid()); \
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 5a89b8083966..b9da9a0281c9 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -210,7 +210,7 @@ static int orangefs_remount_fs(struct super_block *sb, int *flags, char *data)
210 * the client regains all of the mount information from us. 210 * the client regains all of the mount information from us.
211 * NOTE: this function assumes that the request_mutex is already acquired! 211 * NOTE: this function assumes that the request_mutex is already acquired!
212 */ 212 */
213int orangefs_remount(struct super_block *sb) 213int orangefs_remount(struct orangefs_sb_info_s *orangefs_sb)
214{ 214{
215 struct orangefs_kernel_op_s *new_op; 215 struct orangefs_kernel_op_s *new_op;
216 int ret = -EINVAL; 216 int ret = -EINVAL;
@@ -221,7 +221,7 @@ int orangefs_remount(struct super_block *sb)
221 if (!new_op) 221 if (!new_op)
222 return -ENOMEM; 222 return -ENOMEM;
223 strncpy(new_op->upcall.req.fs_mount.orangefs_config_server, 223 strncpy(new_op->upcall.req.fs_mount.orangefs_config_server,
224 ORANGEFS_SB(sb)->devname, 224 orangefs_sb->devname,
225 ORANGEFS_MAX_SERVER_ADDR_LEN); 225 ORANGEFS_MAX_SERVER_ADDR_LEN);
226 226
227 gossip_debug(GOSSIP_SUPER_DEBUG, 227 gossip_debug(GOSSIP_SUPER_DEBUG,
@@ -244,8 +244,8 @@ int orangefs_remount(struct super_block *sb)
244 * short-lived mapping that the system interface uses 244 * short-lived mapping that the system interface uses
245 * to map this superblock to a particular mount entry 245 * to map this superblock to a particular mount entry
246 */ 246 */
247 ORANGEFS_SB(sb)->id = new_op->downcall.resp.fs_mount.id; 247 orangefs_sb->id = new_op->downcall.resp.fs_mount.id;
248 ORANGEFS_SB(sb)->mount_pending = 0; 248 orangefs_sb->mount_pending = 0;
249 } 249 }
250 250
251 op_release(new_op); 251 op_release(new_op);
@@ -485,7 +485,12 @@ struct dentry *orangefs_mount(struct file_system_type *fst,
485 * finally, add this sb to our list of known orangefs 485 * finally, add this sb to our list of known orangefs
486 * sb's 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 op_release(new_op); 494 op_release(new_op);
490 return dget(sb->s_root); 495 return dget(sb->s_root);
491 496
@@ -512,10 +517,21 @@ void orangefs_kill_sb(struct super_block *sb)
512 * issue the unmount to userspace to tell it to remove the 517 * issue the unmount to userspace to tell it to remove the
513 * dynamic mount info it has for this superblock 518 * dynamic mount info it has for this superblock
514 */ 519 */
515 orangefs_unmount_sb(sb); 520 orangefs_unmount_sb(sb);
516 521
517 /* remove the sb from our list of orangefs specific sb's */ 522 /* remove the sb from our list of orangefs specific sb's */
518 remove_orangefs_sb(sb); 523
524 spin_lock(&orangefs_superblocks_lock);
525 __list_del_entry(&ORANGEFS_SB(sb)->list); /* not list_del_init */
526 ORANGEFS_SB(sb)->list.prev = NULL;
527 spin_unlock(&orangefs_superblocks_lock);
528
529 /*
530 * make sure that ORANGEFS_DEV_REMOUNT_ALL loop that might've seen us
531 * gets completed before we free the dang thing.
532 */
533 mutex_lock(&request_mutex);
534 mutex_unlock(&request_mutex);
519 535
520 /* free the orangefs superblock private data */ 536 /* free the orangefs superblock private data */
521 kfree(ORANGEFS_SB(sb)); 537 kfree(ORANGEFS_SB(sb));