Skip to content

Commit 1af3331

Browse files
committed
super: add filesystem freezing helpers for suspend and hibernate
Allow the power subsystem to support filesystem freeze for suspend and hibernate. For some kernel subsystems it is paramount that they are guaranteed that they are the owner of the freeze to avoid any risk of deadlocks. This is the case for the power subsystem. Enable it to recognize whether it did actually freeze the filesystem. If userspace has 10 filesystems and suspend/hibernate manges to freeze 5 and then fails on the 6th for whatever odd reason (current or future) then power needs to undo the freeze of the first 5 filesystems. It can't just walk the list again because while it's unlikely that a new filesystem got added in the meantime it still cannot tell which filesystems the power subsystem actually managed to get a freeze reference count on that needs to be dropped during thaw. There's various ways out of this ugliness. For example, record the filesystems the power subsystem managed to freeze on a temporary list in the callbacks and then walk that list backwards during thaw to undo the freezing or make sure that the power subsystem just actually exclusively freezes things it can freeze and marking such filesystems as being owned by power for the duration of the suspend or resume cycle. I opted for the latter as that seemed the clean thing to do even if it means more code changes. If hibernation races with filesystem freezing (e.g. DM reconfiguration), then hibernation need not freeze a filesystem because it's already frozen but userspace may thaw the filesystem before hibernation actually happens. If the race happens the other way around, DM reconfiguration may unexpectedly fail with EBUSY. So allow FREEZE_EXCL to nest with other holders. An exclusive freezer cannot be undone by any of the other concurrent freezers. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Jan Kara <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 62a2175 commit 1af3331

File tree

8 files changed

+196
-40
lines changed

8 files changed

+196
-40
lines changed

fs/f2fs/gc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,12 +2271,12 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
22712271
if (err)
22722272
return err;
22732273

2274-
err = freeze_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2274+
err = freeze_super(sbi->sb, FREEZE_HOLDER_USERSPACE, NULL);
22752275
if (err)
22762276
return err;
22772277

22782278
if (f2fs_readonly(sbi->sb)) {
2279-
err = thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2279+
err = thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE, NULL);
22802280
if (err)
22812281
return err;
22822282
return -EROFS;
@@ -2333,6 +2333,6 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
23332333
out_err:
23342334
f2fs_up_write(&sbi->cp_global_sem);
23352335
f2fs_up_write(&sbi->gc_lock);
2336-
thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2336+
thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE, NULL);
23372337
return err;
23382338
}

fs/gfs2/super.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -674,15 +674,15 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
674674
return sdp->sd_log_error;
675675
}
676676

677-
static int gfs2_do_thaw(struct gfs2_sbd *sdp, enum freeze_holder who)
677+
static int gfs2_do_thaw(struct gfs2_sbd *sdp, enum freeze_holder who, const void *freeze_owner)
678678
{
679679
struct super_block *sb = sdp->sd_vfs;
680680
int error;
681681

682682
error = gfs2_freeze_lock_shared(sdp);
683683
if (error)
684684
goto fail;
685-
error = thaw_super(sb, who);
685+
error = thaw_super(sb, who, freeze_owner);
686686
if (!error)
687687
return 0;
688688

@@ -703,14 +703,14 @@ void gfs2_freeze_func(struct work_struct *work)
703703
if (test_bit(SDF_FROZEN, &sdp->sd_flags))
704704
goto freeze_failed;
705705

706-
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
706+
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
707707
if (error)
708708
goto freeze_failed;
709709

710710
gfs2_freeze_unlock(sdp);
711711
set_bit(SDF_FROZEN, &sdp->sd_flags);
712712

713-
error = gfs2_do_thaw(sdp, FREEZE_HOLDER_USERSPACE);
713+
error = gfs2_do_thaw(sdp, FREEZE_HOLDER_USERSPACE, NULL);
714714
if (error)
715715
goto out;
716716

@@ -729,10 +729,12 @@ void gfs2_freeze_func(struct work_struct *work)
729729
* gfs2_freeze_super - prevent further writes to the filesystem
730730
* @sb: the VFS structure for the filesystem
731731
* @who: freeze flags
732+
* @freeze_owner: owner of the freeze
732733
*
733734
*/
734735

735-
static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
736+
static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who,
737+
const void *freeze_owner)
736738
{
737739
struct gfs2_sbd *sdp = sb->s_fs_info;
738740
int error;
@@ -745,7 +747,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
745747
}
746748

747749
for (;;) {
748-
error = freeze_super(sb, who);
750+
error = freeze_super(sb, who, freeze_owner);
749751
if (error) {
750752
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
751753
error);
@@ -759,7 +761,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
759761
break;
760762
}
761763

762-
error = gfs2_do_thaw(sdp, who);
764+
error = gfs2_do_thaw(sdp, who, freeze_owner);
763765
if (error)
764766
goto out;
765767

@@ -798,10 +800,12 @@ static int gfs2_freeze_fs(struct super_block *sb)
798800
* gfs2_thaw_super - reallow writes to the filesystem
799801
* @sb: the VFS structure for the filesystem
800802
* @who: freeze flags
803+
* @freeze_owner: owner of the freeze
801804
*
802805
*/
803806

804-
static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
807+
static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who,
808+
const void *freeze_owner)
805809
{
806810
struct gfs2_sbd *sdp = sb->s_fs_info;
807811
int error;
@@ -816,7 +820,7 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
816820
atomic_inc(&sb->s_active);
817821
gfs2_freeze_unlock(sdp);
818822

819-
error = gfs2_do_thaw(sdp, who);
823+
error = gfs2_do_thaw(sdp, who, freeze_owner);
820824

821825
if (!error) {
822826
clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);

fs/gfs2/sys.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
174174

175175
switch (n) {
176176
case 0:
177-
error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE);
177+
error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL);
178178
break;
179179
case 1:
180-
error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE);
180+
error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL);
181181
break;
182182
default:
183183
return -EINVAL;

fs/ioctl.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ static int ioctl_fsfreeze(struct file *filp)
396396

397397
/* Freeze */
398398
if (sb->s_op->freeze_super)
399-
return sb->s_op->freeze_super(sb, FREEZE_HOLDER_USERSPACE);
400-
return freeze_super(sb, FREEZE_HOLDER_USERSPACE);
399+
return sb->s_op->freeze_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
400+
return freeze_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
401401
}
402402

403403
static int ioctl_fsthaw(struct file *filp)
@@ -409,8 +409,8 @@ static int ioctl_fsthaw(struct file *filp)
409409

410410
/* Thaw */
411411
if (sb->s_op->thaw_super)
412-
return sb->s_op->thaw_super(sb, FREEZE_HOLDER_USERSPACE);
413-
return thaw_super(sb, FREEZE_HOLDER_USERSPACE);
412+
return sb->s_op->thaw_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
413+
return thaw_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
414414
}
415415

416416
static int ioctl_file_dedupe_range(struct file *file,

0 commit comments

Comments
 (0)