summaryrefslogtreecommitdiff
path: root/fs/orangefs/devorangefs-req.c
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 /fs/orangefs/devorangefs-req.c
parent6d4c1a30b32a377083900f39c42bcacb633f99a1 (diff)
downloadlinux-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.c41
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__);