summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorMateusz Guzik <mguzik@redhat.com>2017-10-03 18:17:41 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2018-03-19 02:21:40 -0400
commit08fdc8a0138afaf324296a342f32ad26ec465e43 (patch)
treee645f0525576eec37e4eb892aa654f97df9b3b83 /fs
parentfa7c1d5080f6e7dc4428210b6eac60271f899908 (diff)
buffer.c: call thaw_super during emergency thaw
There are 2 distinct freezing mechanisms - one operates on block devices and another one directly on super blocks. Both end up with the same result, but thaw of only one of these does not thaw the other. In particular fsfreeze --freeze uses the ioctl variant going to the super block. Since prior to this patch emergency thaw was not doing a relevant thaw, filesystems frozen with this method remained unaffected. The patch is a hack which adds blind unfreezing. In order to keep the super block write-locked the whole time the code is shuffled around and the newly introduced __iterate_supers is employed. Signed-off-by: Mateusz Guzik <mguzik@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/buffer.c25
-rw-r--r--fs/super.c44
2 files changed, 43 insertions, 26 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index 170df856bdb9..37ea00b265d0 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -523,35 +523,12 @@ repeat:
return err;
}
-static void do_thaw_one(struct super_block *sb, void *unused)
+void emergency_thaw_bdev(struct super_block *sb)
{
while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
printk(KERN_WARNING "Emergency Thaw on %pg\n", sb->s_bdev);
}
-static void do_thaw_all(struct work_struct *work)
-{
- iterate_supers(do_thaw_one, NULL);
- kfree(work);
- printk(KERN_WARNING "Emergency Thaw complete\n");
-}
-
-/**
- * emergency_thaw_all -- forcibly thaw every frozen filesystem
- *
- * Used for emergency unfreeze of all filesystems via SysRq
- */
-void emergency_thaw_all(void)
-{
- struct work_struct *work;
-
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- if (work) {
- INIT_WORK(work, do_thaw_all);
- schedule_work(work);
- }
-}
-
/**
* sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers
* @mapping: the mapping which wants those buffers written
diff --git a/fs/super.c b/fs/super.c
index fd9c02f543eb..83c5c8a60f5f 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -36,6 +36,7 @@
#include <linux/user_namespace.h>
#include "internal.h"
+static int thaw_super_locked(struct super_block *sb);
static LIST_HEAD(super_blocks);
static DEFINE_SPINLOCK(sb_lock);
@@ -934,6 +935,40 @@ void emergency_remount(void)
}
}
+static void do_thaw_all_callback(struct super_block *sb)
+{
+ down_write(&sb->s_umount);
+ if (sb->s_root && sb->s_flags & MS_BORN) {
+ emergency_thaw_bdev(sb);
+ thaw_super_locked(sb);
+ } else {
+ up_write(&sb->s_umount);
+ }
+}
+
+static void do_thaw_all(struct work_struct *work)
+{
+ __iterate_supers(do_thaw_all_callback);
+ kfree(work);
+ printk(KERN_WARNING "Emergency Thaw complete\n");
+}
+
+/**
+ * emergency_thaw_all -- forcibly thaw every frozen filesystem
+ *
+ * Used for emergency unfreeze of all filesystems via SysRq
+ */
+void emergency_thaw_all(void)
+{
+ struct work_struct *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (work) {
+ INIT_WORK(work, do_thaw_all);
+ schedule_work(work);
+ }
+}
+
/*
* Unnamed block devices are dummy devices used by virtual
* filesystems which don't use real block-devices. -- jrs
@@ -1503,11 +1538,10 @@ EXPORT_SYMBOL(freeze_super);
*
* Unlocks the filesystem and marks it writeable again after freeze_super().
*/
-int thaw_super(struct super_block *sb)
+static int thaw_super_locked(struct super_block *sb)
{
int error;
- down_write(&sb->s_umount);
if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
up_write(&sb->s_umount);
return -EINVAL;
@@ -1538,4 +1572,10 @@ out:
deactivate_locked_super(sb);
return 0;
}
+
+int thaw_super(struct super_block *sb)
+{
+ down_write(&sb->s_umount);
+ return thaw_super_locked(sb);
+}
EXPORT_SYMBOL(thaw_super);