Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=cd57e594adc624dd9ee4c0ded3949da21ec24b2f
Commit:     cd57e594adc624dd9ee4c0ded3949da21ec24b2f
Parent:     d757762bf2f6aea954745c76b4d767067b85be9d
Author:     Lachlan McIlroy <[EMAIL PROTECTED]>
AuthorDate: Fri Nov 23 16:30:32 2007 +1100
Committer:  Lachlan McIlroy <[EMAIL PROTECTED]>
CommitDate: Mon Dec 10 13:44:11 2007 +1100

    [XFS] 971064 Various fixups for xfs_bulkstat().
    
    - sanity check for NULL user buffer in xfs_ioc_bulkstat[_compat]()
    - remove the special case for XFS_IOC_FSBULKSTAT with count == 1. This
      special case causes bulkstat to fail because the special case uses
      xfs_bulkstat_single() instead of xfs_bulkstat() and the two functions
      have different semantics.  xfs_bulkstat() will return the next inode
      after the one supplied while skipping internal inodes (ie quota inodes).
      xfs_bulkstate_single() will only lookup the inode supplied and return
      an error if it is an internal inode.
    - in xfs_bulkstat(), need to initialise 'lastino' to the inode supplied
      so in cases were we return without examining any inodes the scan wont
      restart back at zero.
    - sanity check for valid *ubcountp values. Cannot sanity check for valid
      ubuffer here because some users of xfs_bulkstat() don't supply a buffer.
    - checks against 'ubleft' (the space left in the user's buffer) should be
      against 'statstruct_size' which is the supplied minimum object size.
      The mixture of checks against statstruct_size and 0 was one of the
      reasons we were skipping inodes.
    - if the formatter function returns BULKSTAT_RV_NOTHING and an error and
      the error is not ENOENT or EINVAL then we need to abort the scan. ENOENT
      is for inodes that are no longer valid and we just skip them. EINVAL is
      returned if we try to lookup an internal inode so we skip them too. For
      a DMF scan if the inode and DMF attribute cannot fit into the space left
      in the user's buffer it would return ERANGE. We didn't handle this error
      and skipped the inode. We would continue to skip inodes until one fitted
      into the user's buffer or we completed the scan.
    - put back the recalculation of agino (that got removed with the last fix)
      at the end of the while loop. This is because the code at the start of
      the loop expects agino to be the last inode examined if it is non-zero.
    - if we found some inodes but then encountered an error, return success
      this time and the error next time. If the formatter aborted with ENOMEM
      we will now return this error but only if we couldn't read any inodes.
      Previously if we encountered ENOMEM without reading any inodes we
      returned a zero count and no error which falsely indicated the scan was
      complete.
    
    SGI-PV: 973431
    SGI-Modid: xfs-linux-melb:xfs-kern:30089a
    
    Signed-off-by: Lachlan McIlroy <[EMAIL PROTECTED]>
    Signed-off-by: David Chinner <[EMAIL PROTECTED]>
---
 fs/xfs/linux-2.6/xfs_ioctl.c   |   20 +++++++-----------
 fs/xfs/linux-2.6/xfs_ioctl32.c |    3 ++
 fs/xfs/xfs_itable.c            |   43 +++++++++++++++++++++++++++-------------
 3 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 2b34bad..98a5656 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -1047,24 +1047,20 @@ xfs_ioc_bulkstat(
        if ((count = bulkreq.icount) <= 0)
                return -XFS_ERROR(EINVAL);
 
+       if (bulkreq.ubuffer == NULL)
+               return -XFS_ERROR(EINVAL);
+
        if (cmd == XFS_IOC_FSINUMBERS)
                error = xfs_inumbers(mp, &inlast, &count,
                                        bulkreq.ubuffer, xfs_inumbers_fmt);
        else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
                error = xfs_bulkstat_single(mp, &inlast,
                                                bulkreq.ubuffer, &done);
-       else {  /* XFS_IOC_FSBULKSTAT */
-               if (count == 1 && inlast != 0) {
-                       inlast++;
-                       error = xfs_bulkstat_single(mp, &inlast,
-                                       bulkreq.ubuffer, &done);
-               } else {
-                       error = xfs_bulkstat(mp, &inlast, &count,
-                               (bulkstat_one_pf)xfs_bulkstat_one, NULL,
-                               sizeof(xfs_bstat_t), bulkreq.ubuffer,
-                               BULKSTAT_FG_QUICK, &done);
-               }
-       }
+       else    /* XFS_IOC_FSBULKSTAT */
+               error = xfs_bulkstat(mp, &inlast, &count,
+                       (bulkstat_one_pf)xfs_bulkstat_one, NULL,
+                       sizeof(xfs_bstat_t), bulkreq.ubuffer,
+                       BULKSTAT_FG_QUICK, &done);
 
        if (error)
                return -error;
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index 0046bdd..bf2a956 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -291,6 +291,9 @@ xfs_ioc_bulkstat_compat(
        if ((count = bulkreq.icount) <= 0)
                return -XFS_ERROR(EINVAL);
 
+       if (bulkreq.ubuffer == NULL)
+               return -XFS_ERROR(EINVAL);
+
        if (cmd == XFS_IOC_FSINUMBERS)
                error = xfs_inumbers(mp, &inlast, &count,
                                bulkreq.ubuffer, xfs_inumbers_fmt_compat);
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 9972992..9fc4c28 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -316,6 +316,8 @@ xfs_bulkstat_use_dinode(
        return 1;
 }
 
+#define XFS_BULKSTAT_UBLEFT(ubleft)    ((ubleft) >= statstruct_size)
+
 /*
  * Return stat information in bulk (by-inode) for the filesystem.
  */
@@ -353,7 +355,7 @@ xfs_bulkstat(
        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=0; /* last inode number returned */
+       xfs_ino_t               lastino; /* last inode number returned */
        int                     nbcluster; /* # of blocks in a cluster */
        int                     nicluster; /* # of inodes in a cluster */
        int                     nimask; /* mask for inode clusters */
@@ -373,6 +375,7 @@ xfs_bulkstat(
         * Get the last inode value, see if there's nothing to do.
         */
        ino = (xfs_ino_t)*lastinop;
+       lastino = ino;
        dip = NULL;
        agno = XFS_INO_TO_AGNO(mp, ino);
        agino = XFS_INO_TO_AGINO(mp, ino);
@@ -382,6 +385,9 @@ xfs_bulkstat(
                *ubcountp = 0;
                return 0;
        }
+       if (!ubcountp || *ubcountp <= 0) {
+               return EINVAL;
+       }
        ubcount = *ubcountp; /* statstruct's */
        ubleft = ubcount * statstruct_size; /* bytes */
        *ubcountp = ubelem = 0;
@@ -402,7 +408,8 @@ xfs_bulkstat(
         * inode returned; 0 means start of the allocation group.
         */
        rval = 0;
-       while (ubleft >= statstruct_size && agno < mp->m_sb.sb_agcount) {
+       while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) {
+               cond_resched();
                bp = NULL;
                down_read(&mp->m_peraglock);
                error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
@@ -499,6 +506,7 @@ xfs_bulkstat(
                                        break;
                                error = xfs_inobt_lookup_ge(cur, agino, 0, 0,
                                                            &tmp);
+                               cond_resched();
                        }
                        /*
                         * If ran off the end of the ag either with an error,
@@ -542,6 +550,7 @@ xfs_bulkstat(
                         */
                        agino = gino + XFS_INODES_PER_CHUNK;
                        error = xfs_inobt_increment(cur, 0, &tmp);
+                       cond_resched();
                }
                /*
                 * Drop the btree buffers and the agi buffer.
@@ -555,12 +564,12 @@ xfs_bulkstat(
                 */
                irbufend = irbp;
                for (irbp = irbuf;
-                    irbp < irbufend && ubleft >= statstruct_size; irbp++) {
+                    irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) {
                        /*
                         * Now process this chunk of inodes.
                         */
                        for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
-                            ubleft > 0 &&
+                            XFS_BULKSTAT_UBLEFT(ubleft) &&
                                irbp->ir_freecount < XFS_INODES_PER_CHUNK;
                             chunkidx++, clustidx++, agino++) {
                                ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
@@ -663,15 +672,13 @@ xfs_bulkstat(
                                                ubleft, private_data,
                                                bno, &ubused, dip, &fmterror);
                                if (fmterror == BULKSTAT_RV_NOTHING) {
-                                        if (error == EFAULT) {
-                                                ubleft = 0;
-                                                rval = error;
-                                                break;
-                                        }
-                                       else if (error == ENOMEM)
+                                       if (error && error != ENOENT &&
+                                               error != EINVAL) {
                                                ubleft = 0;
-                                       else
-                                               lastino = ino;
+                                               rval = error;
+                                               break;
+                                       }
+                                       lastino = ino;
                                        continue;
                                }
                                if (fmterror == BULKSTAT_RV_GIVEUP) {
@@ -686,6 +693,8 @@ xfs_bulkstat(
                                ubelem++;
                                lastino = ino;
                        }
+
+                       cond_resched();
                }
 
                if (bp)
@@ -694,11 +703,12 @@ xfs_bulkstat(
                /*
                 * Set up for the next loop iteration.
                 */
-               if (ubleft > 0) {
+               if (XFS_BULKSTAT_UBLEFT(ubleft)) {
                        if (end_of_ag) {
                                agno++;
                                agino = 0;
-                       }
+                       } else
+                               agino = XFS_INO_TO_AGINO(mp, lastino);
                } else
                        break;
        }
@@ -707,6 +717,11 @@ xfs_bulkstat(
         */
        kmem_free(irbuf, irbsize);
        *ubcountp = ubelem;
+       /*
+        * Found some inodes, return them now and return the error next time.
+        */
+       if (ubelem)
+               rval = 0;
        if (agno >= mp->m_sb.sb_agcount) {
                /*
                 * If we ran out of filesystem, mark lastino as off
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to