Skip to content

Commit 59ba4fd

Browse files
author
Darrick J. Wong
committed
fs: wait for partially frozen filesystems
Jan Kara suggested that when one thread is in the middle of freezing a filesystem, another thread trying to freeze the same fs but with a different freeze_holder should wait until the freezer reaches either end state (UNFROZEN or COMPLETE) instead of returning EBUSY immediately. Neither caller can do anything sensible with this race other than retry but they cannot really distinguish EBUSY as in "some other holder of the same type has the sb already frozen" from "freezing raced with holder of a different type". Plumb in the extra code needed to wait for the fs freezer to reach an end state and try the freeze again. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz>
1 parent 880b957 commit 59ba4fd

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

fs/super.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,24 @@ static void sb_freeze_unlock(struct super_block *sb, int level)
16441644
percpu_up_write(sb->s_writers.rw_sem + level);
16451645
}
16461646

1647+
static int wait_for_partially_frozen(struct super_block *sb)
1648+
{
1649+
int ret = 0;
1650+
1651+
do {
1652+
unsigned short old = sb->s_writers.frozen;
1653+
1654+
up_write(&sb->s_umount);
1655+
ret = wait_var_event_killable(&sb->s_writers.frozen,
1656+
sb->s_writers.frozen != old);
1657+
down_write(&sb->s_umount);
1658+
} while (ret == 0 &&
1659+
sb->s_writers.frozen != SB_UNFROZEN &&
1660+
sb->s_writers.frozen != SB_FREEZE_COMPLETE);
1661+
1662+
return ret;
1663+
}
1664+
16471665
/**
16481666
* freeze_super - lock the filesystem and force it into a consistent state
16491667
* @sb: the super to lock
@@ -1695,6 +1713,7 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
16951713
atomic_inc(&sb->s_active);
16961714
down_write(&sb->s_umount);
16971715

1716+
retry:
16981717
if (sb->s_writers.frozen == SB_FREEZE_COMPLETE) {
16991718
if (sb->s_writers.freeze_holders & who) {
17001719
deactivate_locked_super(sb);
@@ -1713,8 +1732,13 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
17131732
}
17141733

17151734
if (sb->s_writers.frozen != SB_UNFROZEN) {
1716-
deactivate_locked_super(sb);
1717-
return -EBUSY;
1735+
ret = wait_for_partially_frozen(sb);
1736+
if (ret) {
1737+
deactivate_locked_super(sb);
1738+
return ret;
1739+
}
1740+
1741+
goto retry;
17181742
}
17191743

17201744
if (!(sb->s_flags & SB_BORN)) {
@@ -1726,6 +1750,7 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
17261750
/* Nothing to do really... */
17271751
sb->s_writers.freeze_holders |= who;
17281752
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
1753+
wake_up_var(&sb->s_writers.frozen);
17291754
up_write(&sb->s_umount);
17301755
return 0;
17311756
}
@@ -1745,6 +1770,7 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
17451770
if (ret) {
17461771
sb->s_writers.frozen = SB_UNFROZEN;
17471772
sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT);
1773+
wake_up_var(&sb->s_writers.frozen);
17481774
deactivate_locked_super(sb);
17491775
return ret;
17501776
}
@@ -1760,6 +1786,7 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
17601786
"VFS:Filesystem freeze failed\n");
17611787
sb->s_writers.frozen = SB_UNFROZEN;
17621788
sb_freeze_unlock(sb, SB_FREEZE_FS);
1789+
wake_up_var(&sb->s_writers.frozen);
17631790
deactivate_locked_super(sb);
17641791
return ret;
17651792
}
@@ -1770,6 +1797,7 @@ int freeze_super(struct super_block *sb, enum freeze_holder who)
17701797
*/
17711798
sb->s_writers.freeze_holders |= who;
17721799
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
1800+
wake_up_var(&sb->s_writers.frozen);
17731801
lockdep_sb_freeze_release(sb);
17741802
up_write(&sb->s_umount);
17751803
return 0;
@@ -1810,6 +1838,7 @@ static int thaw_super_locked(struct super_block *sb, enum freeze_holder who)
18101838
if (sb_rdonly(sb)) {
18111839
sb->s_writers.freeze_holders &= ~who;
18121840
sb->s_writers.frozen = SB_UNFROZEN;
1841+
wake_up_var(&sb->s_writers.frozen);
18131842
goto out;
18141843
}
18151844

@@ -1828,6 +1857,7 @@ static int thaw_super_locked(struct super_block *sb, enum freeze_holder who)
18281857

18291858
sb->s_writers.freeze_holders &= ~who;
18301859
sb->s_writers.frozen = SB_UNFROZEN;
1860+
wake_up_var(&sb->s_writers.frozen);
18311861
sb_freeze_unlock(sb, SB_FREEZE_FS);
18321862
out:
18331863
deactivate_locked_super(sb);

0 commit comments

Comments
 (0)