[PATCH 2/3] fs: Introduce { freeze, thaw }_active_super functions

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

 



Introduce functions freeze_active_super() and thaw_active_super(), which
are like freeze_super() and thaw_super() but don't keep an active super
block reference between freeze_super() and the following thaw_super().
This allows filesystem shutdown to occur while a filesystem is frozen.

In places in the filesystem code where a super block may or may not be
active anymore (i.e., places that may race with ->put_super()), function
activate_super() can be used for grabbing an active super block
reference.  In that case,

freeze_super(sb) turns into:

	if (activate_super(sb)) {
		ret = freeze_active_super(sb);
		deactivate_super(sb);
	}

and thaw_super(sb) turns into:

	if (activate_super(sb)) {
		ret = thaw_active_super(sb);
		deactivate_super(sb);
	}

For obvious reaons, the filesystem is responsible for making sure that
no such asynchronous code outlives put_super().

Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx>
---
 fs/super.c         | 70 ++++++++++++++++++++++++++++++++++++++++------
 include/linux/fs.h |  2 ++
 2 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/fs/super.c b/fs/super.c
index 051241cf408b..cba55ca89c09 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -39,6 +39,7 @@
 #include <uapi/linux/mount.h>
 #include "internal.h"
 
+static int thaw_active_super_locked(struct super_block *sb);
 static int thaw_super_locked(struct super_block *sb);
 
 static LIST_HEAD(super_blocks);
@@ -510,6 +511,8 @@ void generic_shutdown_super(struct super_block *sb)
 		if (sop->put_super)
 			sop->put_super(sb);
 
+		thaw_active_super_locked(sb);
+
 		if (!list_empty(&sb->s_inodes)) {
 			printk("VFS: Busy inodes after unmount of %s. "
 			   "Self-destruct in 5 seconds.  Have a nice day...\n",
@@ -1676,7 +1679,7 @@ static void sb_freeze_unlock(struct super_block *sb, int level)
 }
 
 /**
- * freeze_super - lock the filesystem and force it into a consistent state
+ * freeze_active_super - lock the filesystem and force it into a consistent state
  * @sb: the super to lock
  *
  * Syncs the super to make sure the filesystem is consistent and calls the fs's
@@ -1708,11 +1711,10 @@ static void sb_freeze_unlock(struct super_block *sb, int level)
  *
  * sb->s_writers.frozen is protected by sb->s_umount.
  */
-int freeze_super(struct super_block *sb)
+int freeze_active_super(struct super_block *sb)
 {
 	int ret;
 
-	atomic_inc(&sb->s_active);
 	down_write(&sb->s_umount);
 	if (sb->s_writers.frozen != SB_UNFROZEN) {
 		deactivate_locked_super(sb);
@@ -1776,16 +1778,38 @@ int freeze_super(struct super_block *sb)
 	up_write(&sb->s_umount);
 	return 0;
 }
+EXPORT_SYMBOL(freeze_active_super);
+
+/**
+ * freeze_super - lock the filesystem and force it into a consistent state
+ * @sb: the super to lock
+ *
+ * Like freeze_active_super(), but takes an active reference on @sb so
+ * that it cannot be shut down while frozen.
+ */
+int freeze_super(struct super_block *sb)
+{
+	atomic_inc(&sb->s_active);
+	return freeze_active_super(sb);
+}
 EXPORT_SYMBOL(freeze_super);
 
-static int thaw_super_locked(struct super_block *sb)
+/**
+ * thaw_active_super_locked -- unlock filesystem
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem and marks it writeable again after freeze_super().
+ *
+ * Like thaw_super(), but takes a locked super block, leaves it locked, and
+ * doesn't drop an active reference.  For use in ->put_super by filesystems
+ * that use freeze_active_super() and thaw_active_super().
+ */
+static int thaw_active_super_locked(struct super_block *sb)
 {
 	int error;
 
-	if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
-		up_write(&sb->s_umount);
+	if (sb->s_writers.frozen != SB_FREEZE_COMPLETE)
 		return -EINVAL;
-	}
 
 	if (sb_rdonly(sb)) {
 		sb->s_writers.frozen = SB_UNFROZEN;
@@ -1800,7 +1824,6 @@ static int thaw_super_locked(struct super_block *sb)
 			printk(KERN_ERR
 				"VFS:Filesystem thaw failed\n");
 			lockdep_sb_freeze_release(sb);
-			up_write(&sb->s_umount);
 			return error;
 		}
 	}
@@ -1809,6 +1832,18 @@ static int thaw_super_locked(struct super_block *sb)
 	sb_freeze_unlock(sb, SB_FREEZE_FS);
 out:
 	wake_up(&sb->s_writers.wait_unfrozen);
+	return 0;
+}
+
+static int thaw_super_locked(struct super_block *sb)
+{
+	int ret;
+
+	ret = thaw_active_super_locked(sb);
+	if (ret) {
+		up_write(&sb->s_umount);
+		return ret;
+	}
 	deactivate_locked_super(sb);
 	return 0;
 }
@@ -1825,3 +1860,22 @@ int thaw_super(struct super_block *sb)
 	return thaw_super_locked(sb);
 }
 EXPORT_SYMBOL(thaw_super);
+
+/**
+ * thaw_active_super -- unlock filesystem
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem and marks it writeable again after freeze_super().
+ *
+ * Like thaw_super(), but doesn't drop an active reference.
+ */
+int thaw_active_super(struct super_block *sb)
+{
+	int ret;
+
+	down_write(&sb->s_umount);
+	ret = thaw_active_super_locked(sb);
+	up_write(&sb->s_umount);
+	return ret;
+}
+EXPORT_SYMBOL(thaw_active_super);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 84c609123a25..fe869102cd85 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2612,6 +2612,8 @@ extern int user_statfs(const char __user *, struct kstatfs *);
 extern int fd_statfs(int, struct kstatfs *);
 extern int freeze_super(struct super_block *super);
 extern int thaw_super(struct super_block *super);
+extern int freeze_active_super(struct super_block *super);
+extern int thaw_active_super(struct super_block *super);
 extern __printf(2, 3)
 int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
 extern int super_setup_bdi(struct super_block *sb);
-- 
2.38.1




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

  Powered by Linux