All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jeff Liu <jeff.liu@oracle.com>
To: "xfs@oss.sgi.com" <xfs@oss.sgi.com>
Subject: [PATCH v2 09/10] xfs: introduce per allocation group bulkstat
Date: Fri, 18 Apr 2014 08:58:53 +0800	[thread overview]
Message-ID: <535078CD.6050500@oracle.com> (raw)

From: Jie Liu <jeff.liu@oracle.com>

Introduce xfs_perag_bulkstat(), we can return stat information in bulk by
inode as per the given allocation group number and start inode number in
it via a new ioctl(2) in the future.  Similar to the per allocation group
inumbers, we could perform bulkstat in parallel with that.

Refactor xfs_bulkstat() with it.

Signed-off-by: Jie Liu <jeff.liu@oracle.com>
---
 fs/xfs/xfs_itable.c | 288 +++++++++++++++++++++++++++++-----------------------
 fs/xfs/xfs_itable.h |  20 ++++
 2 files changed, 180 insertions(+), 128 deletions(-)

diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 56e1d5f..58dc182 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -337,86 +337,44 @@ xfs_bulkstat_ag_ichunk(
 }
 
 /*
- * Return stat information in bulk (by-inode) for the filesystem.
+ * Return stat information in bulk (by-inode) in an allocation group until
+ * we run out of the AG or user buffers.
  */
-int					/* error status */
-xfs_bulkstat(
-	xfs_mount_t		*mp,	/* mount point for filesystem */
-	xfs_ino_t		*lastinop, /* last inode returned */
-	int			*ubcountp, /* size of buffer/count returned */
-	bulkstat_one_pf		formatter, /* func that'd fill a single buf */
-	size_t			statstruct_size, /* sizeof struct filling */
-	char			__user *ubuffer, /* buffer with inode stats */
-	int			*done)	/* 1 if there are more stats to get */
+int
+xfs_perag_bulkstat(
+	struct xfs_mount		*mp,
+	struct xfs_agbulkstat		*agbulkp,
+	struct xfs_inobt_rec_incore	*irbuf,
+	size_t				nirbuf,
+	bulkstat_one_pf			formatter,
+	size_t				statstruct_size)
 {
-	xfs_buf_t		*agbp;	/* agi header buffer */
-	xfs_agi_t		*agi;	/* agi header data */
-	xfs_agino_t		agino;	/* inode # in allocation group */
-	xfs_agnumber_t		agno;	/* allocation group number */
-	xfs_btree_cur_t		*cur;	/* btree cursor for ialloc btree */
-	int			end_of_ag; /* set if we've seen the ag end */
-	int			error;	/* error code */
-	int                     fmterror;/* bulkstat formatter result */
-	int			i;	/* loop index */
-	int			icount;	/* count of inodes good in irbuf */
-	size_t			irbsize; /* size of irec buffer in bytes */
-	xfs_ino_t		ino;	/* inode number (filesystem) */
-	xfs_inobt_rec_incore_t	*irbp;	/* current irec buffer pointer */
-	xfs_inobt_rec_incore_t	*irbuf;	/* start of irec buffer */
-	xfs_inobt_rec_incore_t	*irbufend; /* end of good irec buffer entries */
-	xfs_ino_t		lastino; /* last inode number returned */
-	int			nirbuf;	/* size of irbuf */
-	int			rval;	/* return value error code */
-	int			tmp;	/* result value from btree calls */
-	int			ubcount; /* size of user's buffer */
-	int			ubleft;	/* bytes left in user's buffer */
-	char			__user *ubufp;	/* pointer into user's buffer */
-	int			ubelem;	/* spaces used in user's buffer */
-
-	/*
-	 * Get the last inode value, see if there's nothing to do.
-	 */
-	ino = (xfs_ino_t)*lastinop;
-	lastino = ino;
-	agno = XFS_INO_TO_AGNO(mp, ino);
-	agino = XFS_INO_TO_AGINO(mp, ino);
-	if (agno >= mp->m_sb.sb_agcount ||
-	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {
-		*done = 1;
-		*ubcountp = 0;
-		return 0;
-	}
-	ubcount = *ubcountp; /* statstruct's */
-	ubleft = ubcount * statstruct_size; /* bytes */
-	*ubcountp = ubelem = 0;
-	*done = 0;
-	fmterror = 0;
-	ubufp = ubuffer;
-	irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
-	if (!irbuf)
-		return ENOMEM;
-
-	nirbuf = irbsize / sizeof(*irbuf);
+	xfs_agnumber_t			agno = agbulkp->ab_agno;
+	xfs_agino_t			agino = *(agbulkp->ab_aginop);
+	xfs_ino_t			lastino = XFS_AGINO_TO_INO(mp, agno,
+								   agino);
+	char				__user *ubuffer = agbulkp->ab_ubuffer;
+	int				ubcount = agbulkp->ab_icount;
+	int				ubelem = 0;/* # elements written */
+	struct xfs_btree_cur		*cur = NULL;
+	struct xfs_buf			*agbp = NULL;
+	int				ubleft_bytes;
+	int				error;
+
+	ubleft_bytes = ubcount * statstruct_size;
+	for (;;) {
+		struct xfs_inobt_rec_incore	*irbp = irbuf;
+		struct xfs_inobt_rec_incore	*irbufend = irbuf + nirbuf;
+		struct xfs_agi			*agi;
+		int				stat;
+		int				icount = 0;/* # inodes in irbuf */
+		bool				end_of_ag = false;
 
-	/*
-	 * Loop over the allocation groups, starting from the last
-	 * inode returned; 0 means start of the allocation group.
-	 */
-	rval = 0;
-	while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
-		cond_resched();
 		error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
 		if (error)
 			break;
 		agi = XFS_BUF_TO_AGI(agbp);
-		/*
-		 * Allocate and initialize a btree cursor for ialloc btree.
-		 */
 		cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
-		irbp = irbuf;
-		irbufend = irbuf + nirbuf;
-		end_of_ag = 0;
-		icount = 0;
 		if (agino > 0) {
 			/*
 			 * In the middle of an allocation group, we need to get
@@ -434,32 +392,34 @@ xfs_bulkstat(
 				irbp++;
 				agino += r.ir_startino + XFS_INODES_PER_CHUNK;
 			}
-			/* Increment to the next record */
-			error = xfs_btree_increment(cur, 0, &tmp);
+			error = xfs_btree_increment(cur, 0, &stat);
+			if (error)
+				break;
+			if (!stat)
+				end_of_ag = true;
 		} else {
 			/* Start of ag.  Lookup the first inode chunk */
-			error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp);
+			error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat);
+			if (error || !stat)
+				break;
 		}
-		if (error)
-			break;
 
 		/*
-		 * Loop through inode btree records in this ag,
-		 * until we run out of inodes or space in the buffer.
+		 * Loop over inode btree records in this AG until we run out of
+		 * inodes or space in the buffer.
 		 */
 		while (irbp < irbufend && icount < ubcount) {
 			struct xfs_inobt_rec_incore	r;
 
-			error = xfs_inobt_get_rec(cur, &r, &i);
-			if (error || i == 0) {
-				end_of_ag = 1;
+			error = xfs_inobt_get_rec(cur, &r, &stat);
+			if (error)
+				break;
+			if (!stat) {
+				end_of_ag = true;
 				break;
 			}
 
-			/*
-			 * If this chunk has any allocated inodes, save it.
-			 * Also start read-ahead now for this chunk.
-			 */
+			/* If this chunk has any allocated inodes, save it */
 			if (r.ir_freecount < XFS_INODES_PER_CHUNK) {
 				xfs_bulkstat_ichunk_ra(mp, agno, &r);
 				irbp->ir_startino = r.ir_startino;
@@ -468,77 +428,149 @@ xfs_bulkstat(
 				irbp++;
 				icount += XFS_INODES_PER_CHUNK - r.ir_freecount;
 			}
-			/*
-			 * Set agino to after this chunk and bump the cursor.
-			 */
+
+			/* Set agino to after this chunk and bump the cursor */
 			agino = r.ir_startino + XFS_INODES_PER_CHUNK;
-			error = xfs_btree_increment(cur, 0, &tmp);
+			error = xfs_btree_increment(cur, 0, &stat);
+			if (error)
+				break;
+			if (!stat) {
+				end_of_ag = true;
+				break;
+			}
+
 			cond_resched();
 		}
+
+		/* Break if previously there is any error has happened */
+		if (error)
+			break;
 		/*
-		 * Drop the btree buffers and the agi buffer.
-		 * We can't hold any of the locks these represent
-		 * when calling iget.
+		 * Drop the btree buffers and the agi buffer.  We can't hold
+		 * any of the locks these represent when calling iget.
 		 */
 		xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
+		cur = NULL;
 		xfs_buf_relse(agbp);
-		/*
-		 * Now format all the good inodes into the user's buffer.
-		 */
+		agbp = NULL;
+
 		irbufend = irbp;
 		for (irbp = irbuf;
-		     irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) {
-			struct xfs_bulkstat_agichunk ac;
+		     irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft_bytes);
+		     irbp++) {
+			struct xfs_bulkstat_agichunk	ac;
 
 			ac.ac_lastino = lastino;
 			ac.ac_ubuffer = ubuffer;
-			ac.ac_ubleft = ubleft;
+			ac.ac_ubleft = ubleft_bytes;
 			ac.ac_ubelem = ubelem;
 			error = xfs_bulkstat_ag_ichunk(mp, agno, irbp,
 					formatter, statstruct_size, &ac);
 			if (error)
-				rval = error;
-
+				break;
 			lastino = ac.ac_lastino;
-			ubleft = ac.ac_ubleft;
+			ubleft_bytes = ac.ac_ubleft;
 			ubelem = ac.ac_ubelem;
 
 			cond_resched();
 		}
-		/*
-		 * Set up for the next loop iteration.
-		 */
-		if (XFS_BULKSTAT_UBLEFT(ubleft)) {
-			if (end_of_ag) {
-				agno++;
-				agino = 0;
-			} else
-				agino = XFS_INO_TO_AGINO(mp, lastino);
-		} else
+
+		if (error || end_of_ag || !XFS_BULKSTAT_UBLEFT(ubleft_bytes))
 			break;
+
+		/* Set up for the next loop iteration */
+		agino = XFS_INO_TO_AGINO(mp, lastino);
 	}
+
+	if (!error) {
+		agbulkp->ab_ocount = ubelem;
+		*(agbulkp->ab_aginop) = XFS_INO_TO_AGINO(mp, lastino);
+	}
+
+	if (cur) {
+		xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR :
+						  XFS_BTREE_NOERROR);
+	}
+	if (agbp)
+		xfs_buf_relse(agbp);
+
+	return error;
+}
+
+/*
+ * Return stat information in bulk (by-inode) for the filesystem.
+ */
+int
+xfs_bulkstat(
+	struct xfs_mount	*mp,	/* mount point for filesystem */
+	xfs_ino_t		*lastinop, /* last inode returned */
+	int			*ubcountp, /* size of buffer/count returned */
+	bulkstat_one_pf		formatter, /* func that'd fill a single buf */
+	size_t			statstruct_size, /* sizeof struct filling */
+	char			__user *ubuffer, /* buffer with inode stats */
+	int			*done)	/* 1 if there are more stats to get */
+{
+	xfs_ino_t		lastino = *lastinop;/* last inode number */
+	xfs_agnumber_t		agno = XFS_INO_TO_AGNO(mp, lastino);
+	xfs_agino_t		agino = XFS_INO_TO_AGINO(mp, lastino);
+	int			ubleft = *ubcountp;/* size of user's buffer */
+	size_t			irbsize;/* size of irec buffer in bytes */
+	int			nirbuf;	/* size of irbuf */
+	int			error;	/* error code */
+	struct xfs_inobt_rec_incore *irbuf;/* start of irec buffer */
+
+	/* The given last inode number is beyond file system range, done */
+	if (agno >= mp->m_sb.sb_agcount ||
+	    lastino != XFS_AGINO_TO_INO(mp, agno, agino)) {
+		*ubcountp = 0;
+		*done = 1;
+		return 0;
+	}
+
+	irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4);
+	if (!irbuf)
+		return ENOMEM;
+	nirbuf = irbsize / sizeof(*irbuf);
+
+	*done = 0;
 	/*
-	 * Done, we're either out of filesystem or space to put the data.
-	 */
-	kmem_free(irbuf);
-	*ubcountp = ubelem;
-	/*
-	 * Found some inodes, return them now and return the error next time.
+	 * Loop over the allocation groups, starting from the last inode
+	 * returned; 0 means start of the allocation group.
 	 */
-	if (ubelem)
-		rval = 0;
-	if (agno >= mp->m_sb.sb_agcount) {
+	do {
+		struct xfs_agbulkstat	agbulk;
+
+		agbulk.ab_agno = agno;
+		agbulk.ab_aginop = &agino;
+		agbulk.ab_ubuffer = ubuffer;
+		agbulk.ab_icount = ubleft;
+		agbulk.ab_ocount = 0;
+		error = xfs_perag_bulkstat(mp, &agbulk, irbuf, nirbuf,
+					   formatter, statstruct_size);
+		if (error)
+			break;
+
+		ubleft -= agbulk.ab_ocount;
+		ASSERT(ubleft >= 0);
+		if (!ubleft)
+			break;
+
 		/*
-		 * If we ran out of filesystem, mark lastino as off
-		 * the end of the filesystem, so the next call
-		 * will return immediately.
+		 * No more inodes in current allocation group, however the user
+		 * requires more.  Proceed to loop over the next one.
 		 */
-		*lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0);
+		agino = 0;
+	} while (++agno < mp->m_sb.sb_agcount);
+
+	kmem_free(irbuf);
+
+	if (!error) {
+		*ubcountp -= ubleft;
+		*lastinop = XFS_AGINO_TO_INO(mp, agno, agino);
 		*done = 1;
-	} else
-		*lastinop = (xfs_ino_t)lastino;
+	}
 
-	return rval;
+	return error;
 }
 
 /*
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index d3e004e..0488960 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -47,6 +47,26 @@ xfs_bulkstat_ag_ichunk(
 	struct xfs_bulkstat_agichunk	*acp);
 
 /*
+ * Structures returned stat information in bulk (by-inode) per AG.
+ */
+struct xfs_agbulkstat {
+	xfs_agnumber_t	ab_agno;	/* AG number */
+	xfs_agino_t	*ab_aginop;	/* last agino returned */
+	char		__user *ab_ubuffer; /* pointer into user's buffer */
+	__uint32_t	ab_icount;	/* count of entries in buffer */
+	__uint32_t	ab_ocount;	/* output counter */
+};
+
+int
+xfs_perag_bulkstat(
+	struct xfs_mount		*mp,
+	struct xfs_agbulkstat		*agbulkp,
+	struct xfs_inobt_rec_incore	*irbuf,
+	size_t				nirbuf,
+	bulkstat_one_pf			formatter,
+	size_t				statstruct_size);
+
+/*
  * Values for stat return value.
  */
 #define BULKSTAT_RV_NOTHING	0
-- 
1.8.3.2

_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs

                 reply	other threads:[~2014-04-18  0:59 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=535078CD.6050500@oracle.com \
    --to=jeff.liu@oracle.com \
    --cc=xfs@oss.sgi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.