Skip to content

Commit

Permalink
buffer.c: call thaw_super during emergency thaw
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mateusz Guzik authored and Al Viro committed Mar 19, 2018
1 parent fa7c1d5 commit 08fdc8a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 26 deletions.
25 changes: 1 addition & 24 deletions fs/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,35 +523,12 @@ static int osync_buffers_list(spinlock_t *lock, struct list_head *list)
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
Expand Down
44 changes: 42 additions & 2 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1538,4 +1572,10 @@ int thaw_super(struct super_block *sb)
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);
6 changes: 6 additions & 0 deletions include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,7 @@ extern int sync_blockdev(struct block_device *bdev);
extern void kill_bdev(struct block_device *);
extern struct super_block *freeze_bdev(struct block_device *);
extern void emergency_thaw_all(void);
extern void emergency_thaw_bdev(struct super_block *sb);
extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
extern int fsync_bdev(struct block_device *);

Expand All @@ -2453,6 +2454,11 @@ static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
return 0;
}

static inline int emergency_thaw_bdev(struct super_block *sb)
{
return 0;
}

static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void *arg)
{
}
Expand Down

0 comments on commit 08fdc8a

Please sign in to comment.