[PATCH 11/17] fsfreeze: add thaw_super_force

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



There are cases where we need the thaw operation to succeed not matter what:
the umount time thaw and emergency thaw. The former is particularly problematic
because after the umount the filesystem may not accessible anymore, which
means that any processes in the fsfreeze wait queue would be stuck in an
uninterruptible wait forever.

We add thaw_super_force() to the fsfreeze in-kernel API to be used in
situations like the ones mentioned above. For code reuse purposes
raw_thaw_super() is introduced too and all the thaw functions restructured
around it.

Cc: linux-fsdevel@xxxxxxxxxxxxxxx
Cc: Josef Bacik <jbacik@xxxxxxxxxxxx>
Cc: Eric Sandeen <sandeen@xxxxxxxxxx>
Cc: Christoph Hellwig <hch@xxxxxxxxxxxxx>
Cc: Dave Chinner <dchinner@xxxxxxxxxx>
Cc: Jan Kara <jack@xxxxxxx>
Cc: Luiz Capitulino <lcapitulino@xxxxxxxxxx>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@xxxxxxxxxxxxx>
---

diff -urNp linux-3.8-rc1-orig/fs/namespace.c linux-3.8-rc1/fs/namespace.c
--- linux-3.8-rc1-orig/fs/namespace.c	2012-12-25 16:26:40.328018000 +0900
+++ linux-3.8-rc1/fs/namespace.c	2012-12-25 16:27:19.792018000 +0900
@@ -1095,21 +1095,16 @@ static void thaw_mount(struct mount *mnt
 {
 	struct super_block *sb = mnt->mnt.mnt_sb;
 
+	/* thaw_super_force() has to be called with superblock lock taken. */
 	down_write(&sb->s_umount);
-	if (sb->s_writers.frozen == SB_UNFROZEN) {
-		up_write(&sb->s_umount);
-		return;
-	}
 	/*
-	 * The superblock may be in the process of being detached from the
-	 * namespace which means we have to make sure the thaw of the superblock
-	 * succeeds (once it has been detached the fsfreeze ioctls become
-	 * unusable). Thus, Force-thaw sb so that all tasks in fsfreeze wait
-	 * queue are woken up.
+	 * The superblock may be in the process of being detached from
+	 * the namespace which means we have to make sure the thaw of the
+	 * superblock succeeds (once it has been detached the fsfreeze
+	 * ioctls become unusable). Thus, force-thaw sb so that all tasks
+	 * in fsfreeze wait queue are woken up.
 	 */
-	sb->s_freeze_count = 1;
-	__thaw_super(sb, true);
-	deactivate_locked_super(sb);
+	thaw_super_force(sb); /* Drops superblock lock. */
 }
 
 void release_mounts(struct list_head *head)
diff -urNp linux-3.8-rc1-orig/fs/super.c linux-3.8-rc1/fs/super.c
--- linux-3.8-rc1-orig/fs/super.c	2012-12-25 16:26:40.332018000 +0900
+++ linux-3.8-rc1/fs/super.c	2012-12-25 16:27:19.792018000 +0900
@@ -1412,51 +1412,34 @@ out_deactivate:
 EXPORT_SYMBOL(freeze_super);
 
 /**
- * __thaw_super -- unlock filesystem
+ * raw_thaw_super - unlock filesystem
  * @sb: the super to thaw
  * @force: whether or not to force the thaw (read details below before using)
  *
  * Unlocks the filesystem and marks it writeable again.
  *
- * Returns -EINVAL if @sb is not frozen, the number of nested freezes remaining
- * after this thaw if it succeeded or the corresponding error code otherwise.
- * If the unfreeze fails, @sb is left in the frozen state.
- *
  * If the force flag is set the kernel will proceeed with the thaw even if the
  * call to the filesystem specific thaw function (->unfreeze_fs()) fails. This
  * feature should be used only in situations where there is no entity we can
  * return an error to so that it has a chance to clean things up and retry, i.e.
  * this is the last oportunity to wake the tasks in the fsfreeze wait queue up.
  *
- * This is the unlocked version of thaw_super, so it is the caller's job to
- * to protect the superblock by grabbing the s_umount semaphore in write mode
- * and release it again on return. See thaw_super() for an example.
+ * This is the raw version of thaw_super and comes without locking, so it is
+ * the caller's job to to protect the superblock by grabbing the s_umount
+ * semaphore in write mode and to release it again on return.
  */
-int __thaw_super(struct super_block *sb, bool force)
+static int raw_thaw_super(struct super_block *sb, bool force)
 {
 	int error = 0;
 
-	if (!sb->s_freeze_count) {
-		error = -EINVAL;
-		goto out;
-	}
-
-	if (--sb->s_freeze_count > 0) {
-		error = sb->s_freeze_count;
-		goto out;
-	}
-
 	if (sb->s_flags & MS_RDONLY)
 		goto out_thaw;
 
 	if (sb->s_op->unfreeze_fs && (error = sb->s_op->unfreeze_fs(sb))) {
 		printk(KERN_ERR "VFS: Filesystem thaw failed\n");
-		if (!force) {
-			sb->s_freeze_count++;
+		if (!force)
 			goto out;
-		}
 	}
-
 out_thaw:
 	sb->s_writers.frozen = SB_UNFROZEN;
 	smp_wmb();
@@ -1466,52 +1449,91 @@ out:
 }
 
 /**
- * thaw_super -- unlock filesystem
+ * thaw_super - unlock filesystem
  * @sb: the super to thaw
  *
  * Unlocks the filesystem and marks it writeable again after freeze_super().
+ *
+ * Returns -EINVAL if @sb is not frozen, 0 if it succeeded or the corresponding
+ * error code otherwise. If the unfreeze fails, @sb is left in the frozen state.
  */
 int thaw_super(struct super_block *sb)
 {
-	int res;
+	int error = 0;
+
 	down_write(&sb->s_umount);
-	res = __thaw_super(sb, false);
-	if (!res) /* Active reference released after last thaw. */
-		deactivate_locked_super(sb);
-	else
-		up_write(&sb->s_umount);
-	return res > 0 ? 0 : res;
+
+	if (!sb->s_freeze_count) {
+		error = -EINVAL;
+		goto out_unlock;
+	}
+
+	if (--sb->s_freeze_count > 0)
+		goto out_unlock;
+
+	error = raw_thaw_super(sb, false);
+
+	if (error) {
+		sb->s_freeze_count++;
+		goto out_unlock;
+	}
+
+	/* Active reference released after last thaw. */
+	deactivate_locked_super(sb);
+	return error;
+
+out_unlock:
+	up_write(&sb->s_umount);
+	return error;
 }
 EXPORT_SYMBOL(thaw_super);
 
+/**
+ * thaw_super_force - unlock filesystem by force
+ * @sb: the super to force unlock
+ *
+ * Thaws the filesystem by force and releases the active reference taken at
+ * freeze time. Returns -EINVAL if the filesystem was not frozen or 0
+ * otherwise.
+ *
+ * thaw_super_force is called with ->s_umount lock held and drops it.
+ */
+int thaw_super_force(struct super_block *sb)
+{
+	if (sb->s_writers.frozen == SB_UNFROZEN) {
+		/* Superblock was not frozen so release lock and bail out. */
+		up_write(&sb->s_umount);
+		return -EINVAL;
+	}
+	sb->s_freeze_count = 0;
+	raw_thaw_super(sb, true);
+	/* Active reference released after last thaw. */
+	deactivate_locked_super(sb);
+	return 0;
+}
+
 static void do_thaw_one(struct super_block *sb, void *unused)
 {
-	int res;
+	int error;
 
-	if (sb->s_writers.frozen == SB_UNFROZEN)
-		return;
+	/*
+	 * We got here from __iterate_supers with the superblock lock taken
+	 * so we can call thaw_super_force() safely.
+	 */
+	error = thaw_super_force(sb);
 
-	if (sb->s_bdev) {
+	if (error != -EINVAL && sb->s_bdev) {
 		char b[BDEVNAME_SIZE];
 		printk(KERN_WARNING "Emergency Thaw on %s.\n",
 		       bdevname(sb->s_bdev, b));
 	}
 
 	/*
-	 * We got here from __iterate_supers with the superblock lock taken
-	 * so we can call the lockless version of thaw_super() safely.
+	 * We have to re-acquire s_umount because iterate_supers_write() will
+	 * unlock it. It still holds passive reference so sb cannot be freed
+	 * under us.
 	 */
-	sb->s_freeze_count = 1; /* avoid multiple calls to __thaw_super */
-	res = __thaw_super(sb, false);
-	if (!res) {
-		deactivate_locked_super(sb);
-		/*
-		 * We have to re-acquire s_umount because
-		 * iterate_supers_write() will unlock it. It still holds
-		 * passive reference so sb cannot be freed under us.
-		 */
-		down_write(&sb->s_umount);
-	}
+	down_write(&sb->s_umount);
 }
 
 static void do_thaw_all(struct work_struct *work)
@@ -1522,7 +1544,7 @@ static void do_thaw_all(struct work_stru
 }
 
 /**
- * emergency_thaw_all -- forcibly thaw every frozen filesystem
+ * emergency_thaw_all - forcibly thaw every frozen filesystem
  *
  * Used for emergency unfreeze of all filesystems via SysRq
  */
diff -urNp linux-3.8-rc1-orig/include/linux/fs.h linux-3.8-rc1/include/linux/fs.h
--- linux-3.8-rc1-orig/include/linux/fs.h	2012-12-25 16:26:40.332018000 +0900
+++ linux-3.8-rc1/include/linux/fs.h	2012-12-25 16:27:19.792018000 +0900
@@ -1882,8 +1882,8 @@ extern int user_statfs(const char __user
 extern int fd_statfs(int, struct kstatfs *);
 extern int vfs_ustat(dev_t, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
-extern int __thaw_super(struct super_block *super, bool force);
 extern int thaw_super(struct super_block *super);
+extern int thaw_super_force(struct super_block *super);
 extern void emergency_thaw_all(void);
 extern bool our_mnt(struct vfsmount *mnt);
 


--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux