xfs: use actual inode count for sparse records in bulkstat/inumbers
authorBrian Foster <bfoster@redhat.com>
Thu, 28 May 2015 23:04:19 +0000 (09:04 +1000)
committerDave Chinner <david@fromorbit.com>
Thu, 28 May 2015 23:04:19 +0000 (09:04 +1000)
The bulkstat and inumbers mechanisms make the assumption that inode
records consist of a full 64 inode chunk in several places. For example,
this is used to track how many inodes have been processed overall as
well as to determine whether a record has allocated inodes that must be
handled.

This assumption is invalid for sparse inode records. While sparse inodes
will be marked as free in the ir_free mask, they are not accounted as
free in ir_freecount because they cannot be allocated. Therefore,
ir_freecount may be less than 64 inodes in an inode record for which all
physically allocated inodes are free (and in turn ir_freecount < 64 does
not signify that the record has allocated inodes).

The new in-core inobt record format includes the ir_count field. This
holds the number of true, physical inodes tracked by the record. The
in-core ir_count field is always valid as it is hardcoded to
XFS_INODES_PER_CHUNK when sparse inodes is not enabled. Use ir_count to
handle inode records correctly in bulkstat in a generic manner.

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_itable.c

index 8042989..f41b0c3 100644 (file)
@@ -252,7 +252,7 @@ xfs_bulkstat_grab_ichunk(
                }
 
                irec->ir_free |= xfs_inobt_maskn(0, idx);
-               *icount = XFS_INODES_PER_CHUNK - irec->ir_freecount;
+               *icount = irec->ir_count - irec->ir_freecount;
        }
 
        return 0;
@@ -415,6 +415,8 @@ xfs_bulkstat(
                                goto del_cursor;
                        if (icount) {
                                irbp->ir_startino = r.ir_startino;
+                               irbp->ir_holemask = r.ir_holemask;
+                               irbp->ir_count = r.ir_count;
                                irbp->ir_freecount = r.ir_freecount;
                                irbp->ir_free = r.ir_free;
                                irbp++;
@@ -447,13 +449,15 @@ xfs_bulkstat(
                         * If this chunk has any allocated inodes, save it.
                         * Also start read-ahead now for this chunk.
                         */
-                       if (r.ir_freecount < XFS_INODES_PER_CHUNK) {
+                       if (r.ir_freecount < r.ir_count) {
                                xfs_bulkstat_ichunk_ra(mp, agno, &r);
                                irbp->ir_startino = r.ir_startino;
+                               irbp->ir_holemask = r.ir_holemask;
+                               irbp->ir_count = r.ir_count;
                                irbp->ir_freecount = r.ir_freecount;
                                irbp->ir_free = r.ir_free;
                                irbp++;
-                               icount += XFS_INODES_PER_CHUNK - r.ir_freecount;
+                               icount += r.ir_count - r.ir_freecount;
                        }
                        error = xfs_btree_increment(cur, 0, &stat);
                        if (error || stat == 0) {
@@ -599,8 +603,7 @@ xfs_inumbers(
                agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1;
                buffer[bufidx].xi_startino =
                        XFS_AGINO_TO_INO(mp, agno, r.ir_startino);
-               buffer[bufidx].xi_alloccount =
-                       XFS_INODES_PER_CHUNK - r.ir_freecount;
+               buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount;
                buffer[bufidx].xi_allocmask = ~r.ir_free;
                if (++bufidx == bcount) {
                        long    written;