xfs: trigger all block gc scans when low on quota space
authorDarrick J. Wong <djwong@kernel.org>
Sat, 23 Jan 2021 00:48:34 +0000 (16:48 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 3 Feb 2021 17:18:49 +0000 (09:18 -0800)
The functions to run an eof/cowblocks scan to try to reduce quota usage
are kind of a mess -- the logic repeatedly initializes an eofb structure
and there are logic bugs in the code that result in the cowblocks scan
never actually happening.

Replace all three functions with a single function that fills out an
eofb and runs both eof and cowblocks scans.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/xfs_file.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h

index 48f6f89..b55f1eb 100644 (file)
@@ -672,7 +672,7 @@ xfs_file_buffered_aio_write(
        struct inode            *inode = mapping->host;
        struct xfs_inode        *ip = XFS_I(inode);
        ssize_t                 ret;
-       int                     enospc = 0;
+       bool                    cleared_space = false;
        int                     iolock;
 
        if (iocb->ki_flags & IOCB_NOWAIT)
@@ -704,19 +704,16 @@ write_retry:
         * also behaves as a filter to prevent too many eofblocks scans from
         * running at the same time.
         */
-       if (ret == -EDQUOT && !enospc) {
+       if (ret == -EDQUOT && !cleared_space) {
                xfs_iunlock(ip, iolock);
-               enospc = xfs_inode_free_quota_eofblocks(ip);
-               if (enospc)
-                       goto write_retry;
-               enospc = xfs_inode_free_quota_cowblocks(ip);
-               if (enospc)
+               cleared_space = xfs_inode_free_quota_blocks(ip);
+               if (cleared_space)
                        goto write_retry;
                iolock = 0;
-       } else if (ret == -ENOSPC && !enospc) {
+       } else if (ret == -ENOSPC && !cleared_space) {
                struct xfs_eofblocks eofb = {0};
 
-               enospc = 1;
+               cleared_space = true;
                xfs_flush_inodes(ip->i_mount);
 
                xfs_iunlock(ip, iolock);
index deb9930..c71eb15 100644 (file)
@@ -1397,33 +1397,31 @@ xfs_icache_free_eofblocks(
 }
 
 /*
- * Run eofblocks scans on the quotas applicable to the inode. For inodes with
- * multiple quotas, we don't know exactly which quota caused an allocation
+ * Run cow/eofblocks scans on the quotas applicable to the inode. For inodes
+ * with multiple quotas, we don't know exactly which quota caused an allocation
  * failure. We make a best effort by including each quota under low free space
  * conditions (less than 1% free space) in the scan.
  */
-static int
-__xfs_inode_free_quota_eofblocks(
-       struct xfs_inode        *ip,
-       int                     (*execute)(struct xfs_mount *mp,
-                                          struct xfs_eofblocks *eofb))
+bool
+xfs_inode_free_quota_blocks(
+       struct xfs_inode        *ip)
 {
-       int scan = 0;
-       struct xfs_eofblocks eofb = {0};
-       struct xfs_dquot *dq;
+       struct xfs_eofblocks    eofb = {0};
+       struct xfs_dquot        *dq;
+       bool                    do_work = false;
 
        /*
         * Run a sync scan to increase effectiveness and use the union filter to
         * cover all applicable quotas in a single scan.
         */
-       eofb.eof_flags = XFS_EOF_FLAGS_UNION|XFS_EOF_FLAGS_SYNC;
+       eofb.eof_flags = XFS_EOF_FLAGS_UNION | XFS_EOF_FLAGS_SYNC;
 
        if (XFS_IS_UQUOTA_ENFORCED(ip->i_mount)) {
                dq = xfs_inode_dquot(ip, XFS_DQTYPE_USER);
                if (dq && xfs_dquot_lowsp(dq)) {
                        eofb.eof_uid = VFS_I(ip)->i_uid;
                        eofb.eof_flags |= XFS_EOF_FLAGS_UID;
-                       scan = 1;
+                       do_work = true;
                }
        }
 
@@ -1432,21 +1430,16 @@ __xfs_inode_free_quota_eofblocks(
                if (dq && xfs_dquot_lowsp(dq)) {
                        eofb.eof_gid = VFS_I(ip)->i_gid;
                        eofb.eof_flags |= XFS_EOF_FLAGS_GID;
-                       scan = 1;
+                       do_work = true;
                }
        }
 
-       if (scan)
-               execute(ip->i_mount, &eofb);
-
-       return scan;
-}
+       if (!do_work)
+               return false;
 
-int
-xfs_inode_free_quota_eofblocks(
-       struct xfs_inode *ip)
-{
-       return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_eofblocks);
+       xfs_icache_free_eofblocks(ip->i_mount, &eofb);
+       xfs_icache_free_cowblocks(ip->i_mount, &eofb);
+       return true;
 }
 
 static inline unsigned long
@@ -1646,13 +1639,6 @@ xfs_icache_free_cowblocks(
                        XFS_ICI_COWBLOCKS_TAG);
 }
 
-int
-xfs_inode_free_quota_cowblocks(
-       struct xfs_inode *ip)
-{
-       return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_cowblocks);
-}
-
 void
 xfs_inode_set_cowblocks_tag(
        xfs_inode_t     *ip)
index 3a4c8b3..3f7ddbc 100644 (file)
@@ -54,17 +54,17 @@ long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
 
 void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
 
+bool xfs_inode_free_quota_blocks(struct xfs_inode *ip);
+
 void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
 void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
 int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
-int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip);
 void xfs_eofblocks_worker(struct work_struct *);
 void xfs_queue_eofblocks(struct xfs_mount *);
 
 void xfs_inode_set_cowblocks_tag(struct xfs_inode *ip);
 void xfs_inode_clear_cowblocks_tag(struct xfs_inode *ip);
 int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *);
-int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip);
 void xfs_cowblocks_worker(struct work_struct *);
 void xfs_queue_cowblocks(struct xfs_mount *);