浏览代码

xfs: update ag iterator to support wait on new inodes

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>
Brian Foster 8 年之前
父节点
当前提交
ae2c4ac2dd
共有 2 个文件被更改,包括 53 次插入8 次删除
  1. 45 8
      fs/xfs/xfs_icache.c
  2. 8 0
      fs/xfs/xfs_icache.h

+ 45 - 8
fs/xfs/xfs_icache.c

@@ -262,6 +262,22 @@ xfs_inode_clear_reclaim_tag(
 	xfs_perag_clear_reclaim_tag(pag);
 	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
  * 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
  * part of the structure. This is made more complex by the fact we store
@@ -626,9 +642,11 @@ out_error_or_again:
 
 
 STATIC int
 STATIC int
 xfs_inode_ag_walk_grab(
 xfs_inode_ag_walk_grab(
-	struct xfs_inode	*ip)
+	struct xfs_inode	*ip,
+	int			flags)
 {
 {
 	struct inode		*inode = VFS_I(ip);
 	struct inode		*inode = VFS_I(ip);
+	bool			newinos = !!(flags & XFS_AGITER_INEW_WAIT);
 
 
 	ASSERT(rcu_read_lock_held());
 	ASSERT(rcu_read_lock_held());
 
 
@@ -646,7 +664,8 @@ xfs_inode_ag_walk_grab(
 		goto out_unlock_noent;
 		goto out_unlock_noent;
 
 
 	/* avoid new or reclaimable inodes. Leave for reclaim code to flush */
 	/* 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;
 		goto out_unlock_noent;
 	spin_unlock(&ip->i_flags_lock);
 	spin_unlock(&ip->i_flags_lock);
 
 
@@ -674,7 +693,8 @@ xfs_inode_ag_walk(
 					   void *args),
 					   void *args),
 	int			flags,
 	int			flags,
 	void			*args,
 	void			*args,
-	int			tag)
+	int			tag,
+	int			iter_flags)
 {
 {
 	uint32_t		first_index;
 	uint32_t		first_index;
 	int			last_error = 0;
 	int			last_error = 0;
@@ -716,7 +736,7 @@ restart:
 		for (i = 0; i < nr_found; i++) {
 		for (i = 0; i < nr_found; i++) {
 			struct xfs_inode *ip = batch[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;
 				batch[i] = NULL;
 
 
 			/*
 			/*
@@ -744,6 +764,9 @@ restart:
 		for (i = 0; i < nr_found; i++) {
 		for (i = 0; i < nr_found; i++) {
 			if (!batch[i])
 			if (!batch[i])
 				continue;
 				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);
 			error = execute(batch[i], flags, args);
 			IRELE(batch[i]);
 			IRELE(batch[i]);
 			if (error == -EAGAIN) {
 			if (error == -EAGAIN) {
@@ -823,12 +846,13 @@ xfs_cowblocks_worker(
 }
 }
 
 
 int
 int
-xfs_inode_ag_iterator(
+xfs_inode_ag_iterator_flags(
 	struct xfs_mount	*mp,
 	struct xfs_mount	*mp,
 	int			(*execute)(struct xfs_inode *ip, int flags,
 	int			(*execute)(struct xfs_inode *ip, int flags,
 					   void *args),
 					   void *args),
 	int			flags,
 	int			flags,
-	void			*args)
+	void			*args,
+	int			iter_flags)
 {
 {
 	struct xfs_perag	*pag;
 	struct xfs_perag	*pag;
 	int			error = 0;
 	int			error = 0;
@@ -838,7 +862,8 @@ xfs_inode_ag_iterator(
 	ag = 0;
 	ag = 0;
 	while ((pag = xfs_perag_get(mp, ag))) {
 	while ((pag = xfs_perag_get(mp, ag))) {
 		ag = pag->pag_agno + 1;
 		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);
 		xfs_perag_put(pag);
 		if (error) {
 		if (error) {
 			last_error = error;
 			last_error = error;
@@ -849,6 +874,17 @@ xfs_inode_ag_iterator(
 	return last_error;
 	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
 int
 xfs_inode_ag_iterator_tag(
 xfs_inode_ag_iterator_tag(
 	struct xfs_mount	*mp,
 	struct xfs_mount	*mp,
@@ -866,7 +902,8 @@ xfs_inode_ag_iterator_tag(
 	ag = 0;
 	ag = 0;
 	while ((pag = xfs_perag_get_tag(mp, ag, tag))) {
 	while ((pag = xfs_perag_get_tag(mp, ag, tag))) {
 		ag = pag->pag_agno + 1;
 		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);
 		xfs_perag_put(pag);
 		if (error) {
 		if (error) {
 			last_error = error;
 			last_error = error;

+ 8 - 0
fs/xfs/xfs_icache.h

@@ -48,6 +48,11 @@ struct xfs_eofblocks {
 #define XFS_IGET_UNTRUSTED	0x2
 #define XFS_IGET_UNTRUSTED	0x2
 #define XFS_IGET_DONTCACHE	0x4
 #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,
 int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
 	     uint flags, uint lock_flags, xfs_inode_t **ipp);
 	     uint flags, uint lock_flags, xfs_inode_t **ipp);
 
 
@@ -79,6 +84,9 @@ void xfs_cowblocks_worker(struct work_struct *);
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
 int xfs_inode_ag_iterator(struct xfs_mount *mp,
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	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 xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	int (*execute)(struct xfs_inode *ip, int flags, void *args),
 	int flags, void *args, int tag);
 	int flags, void *args, int tag);