xfs: support a union-based filter for eofblocks scans
authorBrian Foster <bfoster@redhat.com>
Thu, 24 Jul 2014 09:44:28 +0000 (19:44 +1000)
committerDave Chinner <david@fromorbit.com>
Thu, 24 Jul 2014 09:44:28 +0000 (19:44 +1000)
From: Brian Foster <bfoster@redhat.com>

The eofblocks scan inode filter uses intersection logic by default.
E.g., specifying both user and group quota ids filters out inodes that
are not covered by both the specified user and group quotas. This is
suitable for behavior exposed to userspace.

Scans that are initiated from within the kernel might require more broad
semantics, such as scanning all inodes under each quota associated with
an inode to alleviate low free space conditions in each.

Create the XFS_EOF_FLAGS_UNION flag to support a conditional union-based
filtering algorithm for eofblocks scans. This flag is intentionally left
out of the valid mask as it is not supported for scans initiated from
userspace.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
fs/xfs/xfs_fs.h
fs/xfs/xfs_icache.c

index d34703dbcb423b7fdbb52438b2525dd74417f1eb..ffdabc68785218504729a60cc81645f0cd59b11b 100644 (file)
@@ -375,6 +375,9 @@ struct xfs_fs_eofblocks {
 #define XFS_EOF_FLAGS_GID              (1 << 2) /* filter by gid */
 #define XFS_EOF_FLAGS_PRID             (1 << 3) /* filter by project id */
 #define XFS_EOF_FLAGS_MINFILESIZE      (1 << 4) /* filter by min file size */
+#define XFS_EOF_FLAGS_UNION            (1 << 5) /* union filter algorithm;
+                                                 * kernel only, not included in
+                                                 * valid mask */
 #define XFS_EOF_FLAGS_VALID    \
        (XFS_EOF_FLAGS_SYNC |   \
         XFS_EOF_FLAGS_UID |    \
index 6e522ff5a006b08835c30ef96da42d5ee8ffe6cd..43452081b705286fd815e5b4300360c13a6a35d1 100644 (file)
@@ -1203,6 +1203,30 @@ xfs_inode_match_id(
        return 1;
 }
 
+/*
+ * A union-based inode filtering algorithm. Process the inode if any of the
+ * criteria match. This is for global/internal scans only.
+ */
+STATIC int
+xfs_inode_match_id_union(
+       struct xfs_inode        *ip,
+       struct xfs_eofblocks    *eofb)
+{
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_UID) &&
+           uid_eq(VFS_I(ip)->i_uid, eofb->eof_uid))
+               return 1;
+
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_GID) &&
+           gid_eq(VFS_I(ip)->i_gid, eofb->eof_gid))
+               return 1;
+
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) &&
+           xfs_get_projid(ip) == eofb->eof_prid)
+               return 1;
+
+       return 0;
+}
+
 STATIC int
 xfs_inode_free_eofblocks(
        struct xfs_inode        *ip,
@@ -1212,6 +1236,7 @@ xfs_inode_free_eofblocks(
        int ret;
        struct xfs_eofblocks *eofb = args;
        bool need_iolock = true;
+       int match;
 
        ASSERT(!eofb || (eofb && eofb->eof_scan_owner != 0));
 
@@ -1231,7 +1256,11 @@ xfs_inode_free_eofblocks(
                return 0;
 
        if (eofb) {
-               if (!xfs_inode_match_id(ip, eofb))
+               if (eofb->eof_flags & XFS_EOF_FLAGS_UNION)
+                       match = xfs_inode_match_id_union(ip, eofb);
+               else
+                       match = xfs_inode_match_id(ip, eofb);
+               if (!match)
                        return 0;
 
                /* skip the inode if the file size is too small */