summary refs log tree commit diff
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-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__);