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 /fs/orangefs/devorangefs-req.c | |
parent | 6d4c1a30b32a377083900f39c42bcacb633f99a1 (diff) | |
download | linux-next-45996492e5c85aa0ac93a95d1b2d1ed56851c865.tar.gz |
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>
Diffstat (limited to 'fs/orangefs/devorangefs-req.c')
-rw-r--r-- | fs/orangefs/devorangefs-req.c | 41 |
1 files changed, 23 insertions, 18 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) struct dev_mask_info_s mask_info = { 0 }; struct dev_mask2_info_s mask2_info = { 0, 0 }; int upstream_kmod = 1; - struct list_head *tmp = NULL; - struct orangefs_sb_info_s *orangefs_sb = NULL; + struct orangefs_sb_info_s *orangefs_sb; /* mtmoore: add locking here */ @@ -619,26 +618,32 @@ static long dispatch_ioctl_command(unsigned int command, unsigned long arg) gossip_debug(GOSSIP_DEV_DEBUG, "%s: priority remount in progress\n", __func__); - list_for_each(tmp, &orangefs_superblocks) { - orangefs_sb = - list_entry(tmp, - struct orangefs_sb_info_s, - list); - if (orangefs_sb && (orangefs_sb->sb)) { + spin_lock(&orangefs_superblocks_lock); + list_for_each_entry(orangefs_sb, &orangefs_superblocks, list) { + /* + * We have to drop the spinlock, so entries can be + * removed. They can't be freed, though, so we just + * keep the forward pointers and zero the back ones - + * that way we can get to the rest of the list. + */ + if (!orangefs_sb->list.prev) + continue; + gossip_debug(GOSSIP_DEV_DEBUG, + "%s: Remounting SB %p\n", + __func__, + orangefs_sb); + + spin_unlock(&orangefs_superblocks_lock); + ret = orangefs_remount(orangefs_sb); + spin_lock(&orangefs_superblocks_lock); + if (ret) { gossip_debug(GOSSIP_DEV_DEBUG, - "%s: Remounting SB %p\n", - __func__, + "SB %p remount failed\n", orangefs_sb); - - ret = orangefs_remount(orangefs_sb->sb); - if (ret) { - gossip_debug(GOSSIP_DEV_DEBUG, - "SB %p remount failed\n", - orangefs_sb); - break; - } + break; } } + spin_unlock(&orangefs_superblocks_lock); gossip_debug(GOSSIP_DEV_DEBUG, "%s: priority remount complete\n", __func__); |