mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
gfs2: Fix freeze consistency check in log_write_header
Functions gfs2_freeze_super() and gfs2_thaw_super() are using the SDF_FROZEN flag to indicate when the filesystem is frozen, synchronized by sd_freeze_mutex. However, this doesn't prevent writes from happening between the point of calling thaw_super() and the point where the SDF_FROZEN flag is cleared, so the following assert can trigger in log_write_header(): gfs2_assert_withdraw(sdp, !test_bit(SDF_FROZEN, &sdp->sd_flags)); Fix that by checking for sb->s_writers.frozen != SB_FREEZE_COMPLETE in log_write_header() instead. To make sure that the filesystem-specific part of freezing happens before sb->s_writers.frozen is set to SB_FREEZE_COMPLETE, move that code from gfs2_freeze_locally() into gfs2_freeze_fs() and hook that up to the .freeze_fs operation. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
This commit is contained in:
parent
4e58543e7d
commit
e345b87b0b
@ -913,8 +913,9 @@ void gfs2_write_log_header(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd,
|
||||
static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
|
||||
{
|
||||
blk_opf_t op_flags = REQ_PREFLUSH | REQ_FUA | REQ_META | REQ_SYNC;
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
|
||||
gfs2_assert_withdraw(sdp, !test_bit(SDF_FROZEN, &sdp->sd_flags));
|
||||
gfs2_assert_withdraw(sdp, sb->s_writers.frozen != SB_FREEZE_COMPLETE);
|
||||
|
||||
if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) {
|
||||
gfs2_ordered_wait(sdp);
|
||||
|
@ -673,28 +673,6 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
|
||||
return sdp->sd_log_error;
|
||||
}
|
||||
|
||||
static int gfs2_freeze_locally(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
int error;
|
||||
|
||||
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
|
||||
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
|
||||
GFS2_LFC_FREEZE_GO_SYNC);
|
||||
if (gfs2_withdrawing_or_withdrawn(sdp)) {
|
||||
error = thaw_super(sb, FREEZE_HOLDER_USERSPACE);
|
||||
if (error)
|
||||
return error;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gfs2_do_thaw(struct gfs2_sbd *sdp)
|
||||
{
|
||||
struct super_block *sb = sdp->sd_vfs;
|
||||
@ -724,7 +702,7 @@ void gfs2_freeze_func(struct work_struct *work)
|
||||
if (test_bit(SDF_FROZEN, &sdp->sd_flags))
|
||||
goto freeze_failed;
|
||||
|
||||
error = gfs2_freeze_locally(sdp);
|
||||
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
|
||||
if (error)
|
||||
goto freeze_failed;
|
||||
|
||||
@ -765,7 +743,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
error = gfs2_freeze_locally(sdp);
|
||||
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
|
||||
if (error) {
|
||||
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
|
||||
error);
|
||||
@ -801,6 +779,19 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int gfs2_freeze_fs(struct super_block *sb)
|
||||
{
|
||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||
|
||||
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
|
||||
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
|
||||
GFS2_LFC_FREEZE_GO_SYNC);
|
||||
if (gfs2_withdrawing_or_withdrawn(sdp))
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gfs2_thaw_super - reallow writes to the filesystem
|
||||
* @sb: the VFS structure for the filesystem
|
||||
@ -1599,6 +1590,7 @@ const struct super_operations gfs2_super_ops = {
|
||||
.put_super = gfs2_put_super,
|
||||
.sync_fs = gfs2_sync_fs,
|
||||
.freeze_super = gfs2_freeze_super,
|
||||
.freeze_fs = gfs2_freeze_fs,
|
||||
.thaw_super = gfs2_thaw_super,
|
||||
.statfs = gfs2_statfs,
|
||||
.drop_inode = gfs2_drop_inode,
|
||||
|
Loading…
Reference in New Issue
Block a user