]> git.baikalelectronics.ru Git - kernel.git/commitdiff
xfs: sync lazy sb accounting on quiesce of read-only mounts
authorBrian Foster <bfoster@redhat.com>
Thu, 16 Feb 2023 05:20:19 +0000 (10:50 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Feb 2023 11:50:38 +0000 (12:50 +0100)
commit 3c5d3da420bb9f37f4d98bdf398e336e5dbe9e61 upstream.

[ Modify xfs_log_unmount_write() to return zero when the log is in a read-only
state ]

xfs_log_sbcount() syncs the superblock specifically to accumulate
the in-core percpu superblock counters and commit them to disk. This
is required to maintain filesystem consistency across quiesce
(freeze, read-only mount/remount) or unmount when lazy superblock
accounting is enabled because individual transactions do not update
the superblock directly.

This mechanism works as expected for writable mounts, but
xfs_log_sbcount() skips the update for read-only mounts. Read-only
mounts otherwise still allow log recovery and write out an unmount
record during log quiesce. If a read-only mount performs log
recovery, it can modify the in-core superblock counters and write an
unmount record when the filesystem unmounts without ever syncing the
in-core counters. This leaves the filesystem with a clean log but in
an inconsistent state with regard to lazy sb counters.

Update xfs_log_sbcount() to use the same logic
xfs_log_unmount_write() uses to determine when to write an unmount
record. This ensures that lazy accounting is always synced before
the log is cleaned. Refactor this logic into a new helper to
distinguish between a writable filesystem and a writable log.
Specifically, the log is writable unless the filesystem is mounted
with the norecovery mount option, the underlying log device is
read-only, or the filesystem is shutdown. Drop the freeze state
check because the update is already allowed during the freezing
process and no context calls this function on an already frozen fs.
Also, retain the shutdown check in xfs_log_unmount_write() to catch
the case where the preceding log force might have triggered a
shutdown.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Gao Xiang <hsiangkao@redhat.com>
Reviewed-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandan.babu@oracle.com>
Acked-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_mount.c

index ebbf9b9c85049fa0e6aa207c89e5cd40d08d2d03..03a52b3919b82ae9bca181e4f1a20324e182648c 100644 (file)
@@ -369,6 +369,25 @@ xlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type)
        tic->t_res_num++;
 }
 
+bool
+xfs_log_writable(
+       struct xfs_mount        *mp)
+{
+       /*
+        * Never write to the log on norecovery mounts, if the block device is
+        * read-only, or if the filesystem is shutdown. Read-only mounts still
+        * allow internal writes for log recovery and unmount purposes, so don't
+        * restrict that case here.
+        */
+       if (mp->m_flags & XFS_MOUNT_NORECOVERY)
+               return false;
+       if (xfs_readonly_buftarg(mp->m_log->l_targ))
+               return false;
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return false;
+       return true;
+}
+
 /*
  * Replenish the byte reservation required by moving the grant write head.
  */
@@ -895,15 +914,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
 #endif
        int              error;
 
-       /*
-        * Don't write out unmount record on norecovery mounts or ro devices.
-        * Or, if we are doing a forced umount (typically because of IO errors).
-        */
-       if (mp->m_flags & XFS_MOUNT_NORECOVERY ||
-           xfs_readonly_buftarg(log->l_targ)) {
-               ASSERT(mp->m_flags & XFS_MOUNT_RDONLY);
+       if (!xfs_log_writable(mp))
                return 0;
-       }
 
        error = xfs_log_force(mp, XFS_LOG_SYNC);
        ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log)));
index 4ede2163beb2882d4b462aee00258fd80c348e0c..dc9229e7ddaaacbf1b4af4bc36a41e5708a421f6 100644 (file)
@@ -132,6 +132,7 @@ int   xfs_log_reserve(struct xfs_mount *mp,
 int      xfs_log_regrant(struct xfs_mount *mp, struct xlog_ticket *tic);
 void      xfs_log_unmount(struct xfs_mount *mp);
 int      xfs_log_force_umount(struct xfs_mount *mp, int logerror);
+bool   xfs_log_writable(struct xfs_mount *mp);
 
 struct xlog_ticket *xfs_log_ticket_get(struct xlog_ticket *ticket);
 void     xfs_log_ticket_put(struct xlog_ticket *ticket);
index bbcf48a625b2a4cb5d998ca304a4f1c6dba1f9b1..2860966af6c20a19cb3392d7dd59bea74376825f 100644 (file)
@@ -1218,8 +1218,7 @@ xfs_fs_writable(
 int
 xfs_log_sbcount(xfs_mount_t *mp)
 {
-       /* allow this to proceed during the freeze sequence... */
-       if (!xfs_fs_writable(mp, SB_FREEZE_COMPLETE))
+       if (!xfs_log_writable(mp))
                return 0;
 
        /*