| From ae2c4ac2dd39b23a87ddb14ceddc3f2872c6aef5 Mon Sep 17 00:00:00 2001 |
| From: Brian Foster <bfoster@redhat.com> |
| Date: Wed, 26 Apr 2017 08:30:39 -0700 |
| Subject: xfs: update ag iterator to support wait on new inodes |
| |
| From: Brian Foster <bfoster@redhat.com> |
| |
| 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 | 53 ++++++++++++++++++++++++++++++++++++++++++++-------- |
| fs/xfs/xfs_icache.h | 8 +++++++ |
| 2 files changed, 53 insertions(+), 8 deletions(-) |
| |
| --- a/fs/xfs/xfs_icache.c |
| +++ b/fs/xfs/xfs_icache.c |
| @@ -264,6 +264,22 @@ xfs_inode_clear_reclaim_tag( |
| xfs_perag_clear_reclaim_tag(pag); |
| } |
| |
| +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); |
| +} |
| + |
| /* |
| * When we recycle a reclaimable inode, we need to re-initialise the VFS inode |
| * part of the structure. This is made more complex by the fact we store |
| @@ -628,9 +644,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()); |
| |
| @@ -648,7 +666,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); |
| |
| @@ -676,7 +695,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; |
| @@ -718,7 +738,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; |
| |
| /* |
| @@ -746,6 +766,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) { |
| @@ -825,12 +848,13 @@ xfs_cowblocks_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; |
| @@ -840,7 +864,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; |
| @@ -852,6 +877,17 @@ xfs_inode_ag_iterator( |
| } |
| |
| 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, |
| int (*execute)(struct xfs_inode *ip, int flags, |
| @@ -868,7 +904,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; |
| --- a/fs/xfs/xfs_icache.h |
| +++ b/fs/xfs/xfs_icache.h |
| @@ -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); |
| |
| @@ -79,6 +84,9 @@ void xfs_cowblocks_worker(struct work_st |
| 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); |