System perforamance 4.x vs. 5.x and 6.x

Brett Bump bbump at rsts.org
Thu Feb 21 11:20:06 UTC 2008


On Wed, 20 Feb 2008, Kostik Belousov wrote:

> I cannot reproduce it locally. With patch applied, it compiles both
> GENERIC and GENERIC with options QUOTA added just fine.
>
> Check for partially applied patch.
>

Thanks Kostik.  You can double check me on sizes, but it would appear that
all files in the patch were touched, and I double checked my sources with:
ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/6.2-RELEASE/src which are
identical (this is still a fresh install, I did not run cvsup).

-bash-2.05b$ grep RCS quotas-RELENG_6-20070623-1455.patch
RCS file: /usr/local/arch/ncvs/src/sys/kern/vfs_syscalls.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ffs/ffs_softdep.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ffs/ffs_vfsops.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/quota.h,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/ufs_inode.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/ufs_lookup.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/ufs_quota.c,v
RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v
-bash-2.05b$ cd /usr/src/sys
-bash-2.05b$ ls -l kern/vfs_syscalls.c ufs/ffs/ffs_softdep.c
ufs/ffs/ffs_vfsops.c ufs/ufs/quota.h ufs/ufs/ufs_inode.c
ufs/ufs/ufs_lookup.c ufs/ufs/ufs_quota.c ufs/ufs/ufs_vnops.c
-rw-r--r--  1 root  wheel  109156 Feb 19 14:32 kern/vfs_syscalls.c
-rw-r--r--  1 root  wheel  186964 Feb 19 14:33 ufs/ffs/ffs_softdep.c
-rw-r--r--  1 root  wheel   47272 Feb 19 14:33 ufs/ffs/ffs_vfsops.c
-rw-r--r--  1 root  wheel    7923 Feb 19 14:34 ufs/ufs/quota.h
-rw-r--r--  1 root  wheel    6364 Feb 19 14:34 ufs/ufs/ufs_inode.c
-rw-r--r--  1 root  wheel   36499 Feb 19 14:34 ufs/ufs/ufs_lookup.c
-rw-r--r--  1 root  wheel   31107 Feb 19 14:34 ufs/ufs/ufs_quota.c
-rw-r--r--  1 root  wheel   62960 Feb 19 14:34 ufs/ufs/ufs_vnops.c

The only patch barking a problem would appear to be ufs_quota.c:

--------------------------
|Index: ufs/ufs/ufs_quota.c
|===================================================================
|RCS file: /usr/local/arch/ncvs/src/sys/ufs/ufs/ufs_quota.c,v
|retrieving revision 1.74.2.6
|diff -u -r1.74.2.6 ufs_quota.c
|--- ufs/ufs/ufs_quota.c        1 Feb 2007 04:45:43 -0000       1.74.2.6
|+++ ufs/ufs/ufs_quota.c        25 Jun 2007 14:52:48 -0000
--------------------------
Patching file ufs_quota.c using Plan A...
Hunk #1 failed at 72.
Hunk #2 succeeded at 114 (offset -5 lines).
Hunk #3 succeeded at 122 (offset -5 lines).
Hunk #4 failed at 142.
Hunk #5 succeeded at 158 (offset -13 lines).
Hunk #6 succeeded at 175 (offset -5 lines).
Hunk #7 succeeded at 214 (offset -13 lines).
Hunk #8 succeeded at 236 (offset -5 lines).
Hunk #9 succeeded at 244 (offset -13 lines).
Hunk #10 succeeded at 271 (offset -5 lines).
Hunk #11 succeeded at 296 (offset -13 lines).
Hunk #12 succeeded at 317 with fuzz 1 (offset -4 lines).
Hunk #13 succeeded at 318 (offset -13 lines).
Hunk #14 succeeded at 376 (offset -4 lines).
Hunk #15 failed at 390.
Hunk #16 succeeded at 397 (offset -13 lines).
Hunk #17 succeeded at 425 (offset -4 lines).
Hunk #18 failed at 471.
Hunk #19 succeeded at 490 (offset -19 lines).
Hunk #20 succeeded at 567 (offset -4 lines).
Hunk #21 succeeded at 589 (offset -19 lines).
Hunk #22 succeeded at 631 (offset -4 lines).
Hunk #23 succeeded at 660 (offset -19 lines).
Hunk #24 succeeded at 791 (offset -4 lines).
Hunk #25 succeeded at 809 (offset -19 lines).
Hunk #26 succeeded at 864 (offset -4 lines).
Hunk #27 succeeded at 878 (offset -19 lines).
Hunk #28 succeeded at 920 (offset -4 lines).
Hunk #29 succeeded at 927 (offset -19 lines).
Hunk #30 succeeded at 974 (offset -4 lines).
Hunk #31 succeeded at 984 (offset -19 lines).
Hunk #32 succeeded at 1018 (offset -4 lines).
Hunk #33 succeeded at 1019 (offset -19 lines).
Hunk #34 failed at 1063.
Hunk #35 succeeded at 1197 (offset -9 lines).
Hunk #36 succeeded at 1209 (offset -19 lines).
Hunk #37 succeeded at 1261 (offset -9 lines).
Hunk #38 succeeded at 1281 (offset -19 lines).
Hunk #39 succeeded at 1323 (offset -9 lines).
Hunk #40 succeeded at 1365 (offset -19 lines).
Hunk #41 succeeded at 1410 (offset -9 lines).
Hunk #42 succeeded at 1412 (offset -19 lines).
5 out of 42 hunks failed--saving rejects to ufs_quota.c.rej
done

The contents of ufs_quota.c.rej contain:
-bash-2.05b$ cat ufs_quota.c.rej
***************
*** 72,83 ****
   */
  static char *quotatypes[] = INITQFNAMES;

- static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int);
- static int chkiqchg(struct inode *, int, struct ucred *, int);
  static int dqget(struct vnode *,
-               u_long, struct ufsmount *, int, struct dquot **);
  static int dqsync(struct vnode *, struct dquot *);
  static void dqflush(struct vnode *);

  #ifdef DIAGNOSTIC
  static void dqref(struct dquot *);
--- 72,85 ----
   */
  static char *quotatypes[] = INITQFNAMES;

+ static int chkdqchg(struct inode *, ufs2_daddr_t, struct ucred *, int,
int *);
+ static int chkiqchg(struct inode *, int, struct ucred *, int, int *);
  static int dqget(struct vnode *,
+       u_long, struct ufsmount *, int, struct dquot **);
  static int dqsync(struct vnode *, struct dquot *);
  static void dqflush(struct vnode *);
+ static int quotaoff1(struct thread *td, struct mount *mp, int type);
+ static int quotaoff_inchange(struct thread *td, struct mount *mp, int
type);

  #ifdef DIAGNOSTIC
  static void dqref(struct dquot *);
***************
*** 142,148 ****
        struct dquot *dq;
        ufs2_daddr_t ncurblocks;
        struct vnode *vp = ITOV(ip);
-       int i, error;

        /*
         * Disk quotas must be turned off for system files.  Currently
--- 142,148 ----
        struct dquot *dq;
        ufs2_daddr_t ncurblocks;
        struct vnode *vp = ITOV(ip);
+       int i, error, warn, do_check;

        /*
         * Disk quotas must be turned off for system files.  Currently
***************
*** 335,345 ****
   * Issue an error message if appropriate.
   */
  static int
- chkiqchg(ip, change, cred, type)
        struct inode *ip;
        int change;
        struct ucred *cred;
        int type;
  {
        struct dquot *dq = ip->i_dquot[type];
        ino_t ncurinodes = dq->dq_curinodes + change;
--- 390,401 ----
   * Issue an error message if appropriate.
   */
  static int
+ chkiqchg(ip, change, cred, type, warn)
        struct inode *ip;
        int change;
        struct ucred *cred;
        int type;
+       int *warn;
  {
        struct dquot *dq = ip->i_dquot[type];
        ino_t ncurinodes = dq->dq_curinodes + change;
***************
*** 411,425 ****
         */
        if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
                return;
        for (i = 0; i < MAXQUOTAS; i++) {
                if (ump->um_quotas[i] == NULLVP ||
                    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
                        continue;
                if (ip->i_dquot[i] == NODQUOT) {
                        vprint("chkdquot: missing dquot", ITOV(ip));
                        panic("chkdquot: missing dquot");
                }
        }
  }
  #endif

--- 471,489 ----
         */
        if ((int)ip->i_uid < 0 || (int)ip->i_gid < 0)
                return;
+
+       UFS_LOCK(ump);
        for (i = 0; i < MAXQUOTAS; i++) {
                if (ump->um_quotas[i] == NULLVP ||
                    (ump->um_qflags[i] & (QTF_OPENING|QTF_CLOSING)))
                        continue;
                if (ip->i_dquot[i] == NODQUOT) {
+                       UFS_UNLOCK(ump);
                        vprint("chkdquot: missing dquot", ITOV(ip));
                        panic("chkdquot: missing dquot");
                }
        }
+       UFS_UNLOCK(ump);
  }
  #endif
***************
*** 851,905 ****
        struct dquot **dqp;
  {
        struct thread *td = curthread;          /* XXX */
-       struct dquot *dq;
        struct dqhash *dqh;
        struct vnode *dqvp;
        struct iovec aiov;
        struct uio auio;
-       int error;

        /* XXX: Disallow negative id values to prevent the
        * creation of 100GB+ quota data files.
        */
        if ((int)id < 0)
                return (EINVAL);
        dqvp = ump->um_quotas[type];
        if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
                *dqp = NODQUOT;
                return (EINVAL);
        }
        /*
         * Check the cache first.
         */
        dqh = DQHASH(dqvp, id);
-       LIST_FOREACH(dq, dqh, dq_hash) {
-               if (dq->dq_id != id ||
-                   dq->dq_ump->um_quotas[dq->dq_type] != dqvp)
-                       continue;
                /*
-                * Cache hit with no references.  Take
-                * the structure off the free list.
                 */
-               if (dq->dq_cnt == 0)
-                       TAILQ_REMOVE(&dqfreelist, dq, dq_freelist);
-               DQREF(dq);
-               *dqp = dq;
-               return (0);
        }
        /*
-        * Not in cache, allocate a new one.
         */
        if (TAILQ_FIRST(&dqfreelist) == NODQUOT &&
            numdquot < MAXQUOTAS * desiredvnodes)
                desireddquot += DQUOTINC;
        if (numdquot < desireddquot) {
-               dq = (struct dquot *)malloc(sizeof *dq, M_DQUOT,
-                   M_WAITOK | M_ZERO);
                numdquot++;
        } else {
                if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) {
                        tablefull("dquot");
                        *dqp = NODQUOT;
                        return (EUSERS);
                }
                if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))
--- 1063,1184 ----
        struct dquot **dqp;
  {
        struct thread *td = curthread;          /* XXX */
+       struct dquot *dq, *dq1;
        struct dqhash *dqh;
        struct vnode *dqvp;
        struct iovec aiov;
        struct uio auio;
+       int vfslocked, dqvplocked, error;
+
+ #ifdef DEBUG_VFS_LOCKS
+       if (vp != NULLVP)
+               ASSERT_VOP_ELOCKED(vp, "dqget");
+ #endif
+
+       if (vp != NULLVP && *dqp != NODQUOT) {
+               return (0);
+       }

        /* XXX: Disallow negative id values to prevent the
        * creation of 100GB+ quota data files.
        */
        if ((int)id < 0)
                return (EINVAL);
+
+       UFS_LOCK(ump);
        dqvp = ump->um_quotas[type];
        if (dqvp == NULLVP || (ump->um_qflags[type] & QTF_CLOSING)) {
                *dqp = NODQUOT;
+               UFS_UNLOCK(ump);
                return (EINVAL);
        }
+       vref(dqvp);
+       UFS_UNLOCK(ump);
+       error = 0;
+       dqvplocked = 0;
+
        /*
         * Check the cache first.
         */
        dqh = DQHASH(dqvp, id);
+       DQH_LOCK();
+       dq = dqhashfind(dqh, id, dqvp);
+       if (dq != NULL) {
+               DQH_UNLOCK();
+ hfound:               DQI_LOCK(dq);
+               DQI_WAIT(dq, PINOD+1, "dqget");
+               DQI_UNLOCK(dq);
+               if (dq->dq_ump == NULL) {
+                       dqrele(vp, dq);
+                       dq = NODQUOT;
+                       error = EIO;
+               }
+               *dqp = dq;
+               vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
+               if (dqvplocked)
+                       vput(dqvp);
+               else
+                       vrele(dqvp);
+               VFS_UNLOCK_GIANT(vfslocked);
+               return (error);
+       }
+
+       /*
+        * Quota vnode lock is before DQ_LOCK. Acquire dqvp lock there
+        * since new dq will appear on the hash chain DQ_LOCKed.
+        */
+       if (vp != dqvp) {
+               DQH_UNLOCK();
+               vn_lock(dqvp, LK_SHARED | LK_RETRY, td);
+               dqvplocked = 1;
+               DQH_LOCK();
                /*
+                * Recheck the cache after sleep for quota vnode lock.
                 */
+               dq = dqhashfind(dqh, id, dqvp);
+               if (dq != NULL) {
+                       DQH_UNLOCK();
+                       goto hfound;
+               }
        }
+
        /*
+        * Not in cache, allocate a new one or take it from the
+        * free list.
         */
        if (TAILQ_FIRST(&dqfreelist) == NODQUOT &&
            numdquot < MAXQUOTAS * desiredvnodes)
                desireddquot += DQUOTINC;
        if (numdquot < desireddquot) {
                numdquot++;
+               DQH_UNLOCK();
+               dq1 = (struct dquot *)malloc(sizeof *dq, M_DQUOT,
+                   M_WAITOK | M_ZERO);
+               mtx_init(&dq1->dq_lock, "dqlock", NULL, MTX_DEF);
+               DQH_LOCK();
+               /*
+                * Recheck the cache after sleep for memory.
+                */
+               dq = dqhashfind(dqh, id, dqvp);
+               if (dq != NULL) {
+                       numdquot--;
+                       DQH_UNLOCK();
+                       mtx_destroy(&dq1->dq_lock);
+                       free(dq1, M_DQUOT);
+                       goto hfound;
+               }
+               dq = dq1;
        } else {
                if ((dq = TAILQ_FIRST(&dqfreelist)) == NULL) {
+                       DQH_UNLOCK();
                        tablefull("dquot");
                        *dqp = NODQUOT;
+                       vfslocked = VFS_LOCK_GIANT(dqvp->v_mount);
+                       if (dqvplocked)
+                               vput(dqvp);
+                       else
+                               vrele(dqvp);
+                       VFS_UNLOCK_GIANT(vfslocked);
                        return (EUSERS);
                }
                if (dq->dq_cnt || (dq->dq_flags & DQ_MOD))

Brett


More information about the freebsd-performance mailing list