xfs: update ag iterator to support wait on new inodes
authorBrian Foster <bfoster@redhat.com>
Wed, 26 Apr 2017 15:30:39 +0000 (08:30 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 7 Jun 2017 10:06:02 +0000 (12:06 +0200)
commit ae2c4ac2dd39b23a87ddb14ceddc3f2872c6aef5 upstream.

The AG inode iterator currently skips new inodes as such inodes are
inserted into the inode radix tree before they are fully
constructed. Certain contexts require the ability to wait on the
construction of new inodes, however. The fs-wide dquot release from
the quotaoff sequence is an example of this.

Update the AG inode iterator to support the ability to wait on
inodes flagged with XFS_INEW upon request. Create a new
xfs_inode_ag_iterator_flags() interface and support a set of
iteration flags to modify the iteration behavior. When the
XFS_AGITER_INEW_WAIT flag is set, include XFS_INEW flags in the
radix tree inode lookup and wait on them before the callback is
executed.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h

index 88d3933e4a3e599b21576d95b72bcb4e85492680..adbc1f59969a5f8562d7204d0056002775eac79b 100644 (file)
@@ -366,6 +366,22 @@ out_destroy:
        return error;
 }
 
+static void
+xfs_inew_wait(
+       struct xfs_inode        *ip)
+{
+       wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_INEW_BIT);
+       DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_INEW_BIT);
+
+       do {
+               prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+               if (!xfs_iflags_test(ip, XFS_INEW))
+                       break;
+               schedule();
+       } while (true);
+       finish_wait(wq, &wait.wait);
+}
+
 /*
  * Look up an inode by number in the given file system.
  * The inode is looked up in the cache held in each AG.
@@ -470,9 +486,11 @@ out_error_or_again:
 
 STATIC int
 xfs_inode_ag_walk_grab(
-       struct xfs_inode        *ip)
+       struct xfs_inode        *ip,
+       int                     flags)
 {
        struct inode            *inode = VFS_I(ip);
+       bool                    newinos = !!(flags & XFS_AGITER_INEW_WAIT);
 
        ASSERT(rcu_read_lock_held());
 
@@ -490,7 +508,8 @@ xfs_inode_ag_walk_grab(
                goto out_unlock_noent;
 
        /* avoid new or reclaimable inodes. Leave for reclaim code to flush */
-       if (__xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM))
+       if ((!newinos && __xfs_iflags_test(ip, XFS_INEW)) ||
+           __xfs_iflags_test(ip, XFS_IRECLAIMABLE | XFS_IRECLAIM))
                goto out_unlock_noent;
        spin_unlock(&ip->i_flags_lock);
 
@@ -518,7 +537,8 @@ xfs_inode_ag_walk(
                                           void *args),
        int                     flags,
        void                    *args,
-       int                     tag)
+       int                     tag,
+       int                     iter_flags)
 {
        uint32_t                first_index;
        int                     last_error = 0;
@@ -560,7 +580,7 @@ restart:
                for (i = 0; i < nr_found; i++) {
                        struct xfs_inode *ip = batch[i];
 
-                       if (done || xfs_inode_ag_walk_grab(ip))
+                       if (done || xfs_inode_ag_walk_grab(ip, iter_flags))
                                batch[i] = NULL;
 
                        /*
@@ -588,6 +608,9 @@ restart:
                for (i = 0; i < nr_found; i++) {
                        if (!batch[i])
                                continue;
+                       if ((iter_flags & XFS_AGITER_INEW_WAIT) &&
+                           xfs_iflags_test(batch[i], XFS_INEW))
+                               xfs_inew_wait(batch[i]);
                        error = execute(batch[i], flags, args);
                        IRELE(batch[i]);
                        if (error == -EAGAIN) {
@@ -640,12 +663,13 @@ xfs_eofblocks_worker(
 }
 
 int
-xfs_inode_ag_iterator(
+xfs_inode_ag_iterator_flags(
        struct xfs_mount        *mp,
        int                     (*execute)(struct xfs_inode *ip, int flags,
                                           void *args),
        int                     flags,
-       void                    *args)
+       void                    *args,
+       int                     iter_flags)
 {
        struct xfs_perag        *pag;
        int                     error = 0;
@@ -655,7 +679,8 @@ xfs_inode_ag_iterator(
        ag = 0;
        while ((pag = xfs_perag_get(mp, ag))) {
                ag = pag->pag_agno + 1;
-               error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1);
+               error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1,
+                                         iter_flags);
                xfs_perag_put(pag);
                if (error) {
                        last_error = error;
@@ -666,6 +691,17 @@ xfs_inode_ag_iterator(
        return last_error;
 }
 
+int
+xfs_inode_ag_iterator(
+       struct xfs_mount        *mp,
+       int                     (*execute)(struct xfs_inode *ip, int flags,
+                                          void *args),
+       int                     flags,
+       void                    *args)
+{
+       return xfs_inode_ag_iterator_flags(mp, execute, flags, args, 0);
+}
+
 int
 xfs_inode_ag_iterator_tag(
        struct xfs_mount        *mp,
@@ -683,7 +719,8 @@ xfs_inode_ag_iterator_tag(
        ag = 0;
        while ((pag = xfs_perag_get_tag(mp, ag, tag))) {
                ag = pag->pag_agno + 1;
-               error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag);
+               error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag,
+                                         0);
                xfs_perag_put(pag);
                if (error) {
                        last_error = error;
index 62f1f91c32cb345dda3c121b346ff4a5c4f17b43..147a79212e63c3265dfee32138469f4fd20c5506 100644 (file)
@@ -48,6 +48,11 @@ struct xfs_eofblocks {
 #define XFS_IGET_UNTRUSTED     0x2
 #define XFS_IGET_DONTCACHE     0x4
 
+/*
+ * flags for AG inode iterator
+ */
+#define XFS_AGITER_INEW_WAIT   0x1     /* wait on new inodes */
+
 int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
             uint flags, uint lock_flags, xfs_inode_t **ipp);
 
@@ -72,6 +77,9 @@ void xfs_eofblocks_worker(struct work_struct *);
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
        int (*execute)(struct xfs_inode *ip, int flags, void *args),
        int flags, void *args);
+int xfs_inode_ag_iterator_flags(struct xfs_mount *mp,
+       int (*execute)(struct xfs_inode *ip, int flags, void *args),
+       int flags, void *args, int iter_flags);
 int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
        int (*execute)(struct xfs_inode *ip, int flags, void *args),
        int flags, void *args, int tag);