diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-03-25 19:56:34 -0400 |
---|---|---|
committer | Mike Marshall <hubcap@omnibond.com> | 2016-03-26 07:22:00 -0400 |
commit | 45996492e5c85aa0ac93a95d1b2d1ed56851c865 (patch) | |
tree | 3ee74b07ce43cdb0b637c3747fadbb1f2ba59eb6 | |
parent | 6d4c1a30b32a377083900f39c42bcacb633f99a1 (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.c | 41 | ||||
-rw-r--r-- | fs/orangefs/orangefs-kernel.h | 34 | ||||
-rw-r--r-- | fs/orangefs/super.c | 30 |
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 | ||
464 | void orangefs_kill_sb(struct super_block *sb); | 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 | int fsid_key_table_initialize(void); | 467 | int fsid_key_table_initialize(void); |
468 | void fsid_key_table_finalize(void); | 468 | void 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) \ | ||
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 | |||
633 | #define fill_default_sys_attrs(sys_attr, type, mode) \ | 601 | #define fill_default_sys_attrs(sys_attr, type, mode) \ |
634 | do { \ | 602 | do { \ |
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 | */ |
213 | int orangefs_remount(struct super_block *sb) | 213 | int 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)); |