Submit #2470
closed[PATCH] kernel -- ffs: Move inode hash to per-mount structure.
0%
Description
FFS uses a hash table to map inode number to per-inode data. The
hash table was global, rather than per-mount, and was keyed off of
(inode number, per-mount device minor number). This patch converts
it to a per-mount table, sychronized by the per-mount token.
---
  sys/vfs/ufs/ffs_alloc.c   |  8 ++--
  sys/vfs/ufs/ffs_softdep.c |  7 ++--
  sys/vfs/ufs/ffs_vfsops.c  | 24 ++++--------
  sys/vfs/ufs/ufs_extern.h  | 14 +++-----
  sys/vfs/ufs/ufs_ihash.c   | 80 ++++++++++++++++------------------------------
  sys/vfs/ufs/ufs_inode.c   |  5 +-
  sys/vfs/ufs/ufs_vfsops.c  |  1 
  sys/vfs/ufs/ufsmount.h    | 11 +
  8 files changed, 64 insertions(+), 86 deletions(-)
diff --git a/sys/vfs/ufs/ffs_alloc.c b/sys/vfs/ufs/ffs_alloc.c
index afcde72..5a1f8f8 100644
--- a/sys/vfs/ufs/ffs_alloc.c
+++ b/sys/vfs/ufs/ffs_alloc.c@ -1354,6 +1354,7 @ fail:
  static ino_t
  ffs_nodealloccg(struct inode *ip, int cg, ufs_daddr_t ipref, int mode)
  {
+    struct ufsmount *ump;
      struct fs *fs;
      struct cg *cgp;
      struct buf *bp;@ -1362,7 +1363,10 @ ffs_nodealloccg(struct inode *ip, int cg, ufs_daddr_t ipref, int mode)
      int error, len, arraysize, i;
      int icheckmiss;
      ufs_daddr_t ibase;
+    struct vnode *vp;
+    vp = ITOV;
+    ump = VFSTOUFS;
      fs = ip->i_fs;
      if (fs->fs_cs(fs, cg).cs_nifree == 0)
          return (0);@ -1388,7 +1392,7 @ ffs_nodealloccg(struct inode *ip, int cg, ufs_daddr_t ipref, int mode)
      if (ipref) {
          ipref %= fs->fs_ipg;
          if (isclr(inosused, ipref)) {
-            if (ufs_ihashcheck(ip->i_dev, ibase + ipref)  0)
+            if (ufs_ihashcheck(ump, ip->i_dev, ibase + ipref)  0)
                  goto gotit;
          }
      }@ -1422,7 +1426,7 @ ffs_nodealloccg(struct inode *ip, int cg, ufs_daddr_t ipref, int mode)
                   * quick-check up above.
                   */
                  if ((map & (1 << i))  0) {
-                    if (ufs_ihashcheck(ip->i_dev, ibase + (ipref << 3) + i)  0) {
+                    if (ufs_ihashcheck(ump, ip->i_dev, ibase + (ipref << 3) + i) == 0) {
                          ipref = (ipref << 3) + i;
                          cgp->cg_irotor = (ipref + 1) % fs->fs_ipg;
                          goto gotit;
diff --git a/sys/vfs/ufs/ffs_softdep.c b/sys/vfs/ufs/ffs_softdep.c
index b6a8cbf..2e9788d 100644
--- a/sys/vfs/ufs/ffs_softdep.c
+++ b/sys/vfs/ufs/ffs_softdep.c@ -592,6 +592,7 @ done:
  static int
  process_worklist_item(struct mount *matchmnt, int flags)
  {
+    struct ufsmount *ump;
      struct worklist *wk;
      struct dirrem *dirrem;
      struct fs *matchfs;@ -612,8 +613,10 @ process_worklist_item(struct mount *matchmnt, int flags)
          if ((flags & LK_NOWAIT) == 0 || wk->wk_type != D_DIRREM)
              break;
          dirrem = WK_DIRREM(wk);
-        vp = ufs_ihashlookup(VFSTOUFS->um_dev,
-            dirrem->dm_oldinum);
+        ump = VFSTOUFS;
+        lwkt_gettoken(&ump->um_mountp->mnt_token);
+        vp = ufs_ihashlookup(ump, ump->um_dev, dirrem->dm_oldinum);
+        lwkt_reltoken(&ump->um_mountp->mnt_token);
          if (vp == NULL || !vn_islocked(vp))
              break;
      }
diff --git a/sys/vfs/ufs/ffs_vfsops.c b/sys/vfs/ufs/ffs_vfsops.c
index 92c008b..d62f5b3 100644
--- a/sys/vfs/ufs/ffs_vfsops.c
+++ b/sys/vfs/ufs/ffs_vfsops.c@ -84,7 +84,6 @ static struct vfsops ufs_vfsops = {
      .vfs_checkexp =        ufs_check_export,
      .vfs_vptofh =        ffs_vptofh,
      .vfs_init =            ffs_init,
-    .vfs_uninit =        ufs_uninit
  };
VFS_SET(ufs_vfsops, ufs, 0);
@ -768,6 +767,7 @ ffs_mountfs(struct vnode *devvp, struct mount *mp, struct malloc_type *mtype)
          mp->mnt_time = fs->fs_time;
      }+    ufs_ihashinit(ump);
      ump->um_savedmaxfilesize = fs->fs_maxfilesize;        /* XXX /
      maxfilesize = (uint64_t)0x40000000 * fs->fs_bsize - 1;    / XXX /
      / Enforce limit caused by vm object backing (32 bits vm_pindex_t). */@ -796,6 +796,7 @ out:
          brelse(bp);
      VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE);
      if (ump) {
+        ufs_ihashuninit(ump);
          kfree(ump->um_fs, M_UFSMNT);
          kfree(ump, M_UFSMNT);
          mp->mnt_data = (qaddr_t)0;@ -871,6 +872,7 @ ffs_unmount(struct mount *mp, int mntflags)
vrele(ump->um_devvp);+    ufs_ihashuninit(ump);
      kfree(fs->fs_csp, M_UFSMNT);
      kfree(fs, M_UFSMNT);
      kfree(ump, M_UFSMNT);@ -1085,8 +1087,8 @ ffs_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp)
ump = VFSTOUFS(mp);
      dev = ump->um_dev;
restart:
    if ((*vpp = ufs_ihashget(dev, ino)) != NULL) {
+    
+    if ((*vpp = ufs_ihashget(ump, dev, ino)) != NULL) {
          return (0);
      }@ -1100,7 +1102,8 @ restart:
       * XXX this may no longer be true since getnewvnode returns a
       * VX locked vnode now.
       */
-    ip = kmalloc(sizeof(struct inode), ump->um_malloctype, M_WAITOK);
+    ip = kmalloc(sizeof(struct inode), ump->um_malloctype,
+             M_WAITOK | M_ZERO);
/* Allocate a new vnode/inode. */
      error = getnewvnode(VT_UFS, mp, &vp, VLKTIMEOUT, LK_CANRECURSE);
@ -1109,7 +1112,6 @ restart:
          kfree(ip, ump->um_malloctype);
          return (error);
      }
-    bzero((caddr_t)ip, sizeof(struct inode));
      ip->i_vnode = vp;
      ip->i_fs = fs = ump->um_fs;
      ip->i_dev = dev;
@ -1123,16 +1125,10 @ restart:
  #endif/*
-     * Insert it into the inode hash table and check for a collision.
-     * If a collision occurs, throw away the vnode and try again.
+     * Insert it into the inode hash table.
       */
-    if (ufs_ihashins(ip) != 0) {
-        kprintf("debug: ufs ihashins collision, retrying inode %ld\n",
-            (long)ip->i_number);
-        vp->v_type = VBAD;
-        vx_put(vp);
-        kfree(ip, ump->um_malloctype);
-        goto restart;
+    if (ufs_ihashins(ump, ip) != 0) {
+        panic("duplicate inode in inohash");
      }
      vp->v_data = ip;diff --git a/sys/vfs/ufs/ufs_extern.h b/sys/vfs/ufs/ufs_extern.h
index d05c350..6f681b6 100644
--- a/sys/vfs/ufs/ufs_extern.h
++ b/sys/vfs/ufs/ufs_extern.h@ -78,16 +78,16 @ int     ufs_dirremove(struct vnode *, struct inode *, int, int);
  int     ufs_dirrewrite(struct inode *, struct inode *, ino_t, int, int);
  int     ufs_getlbns(struct vnode *, ufs_daddr_t, struct indir *, int *);
  struct vnode *
-     ufs_ihashget(cdev_t, ino_t);int     ufs_ihashcheck(cdev_t, ino_t);     ufs_ihashget(struct ufsmount *, cdev_t, ino_t);
-void     ufs_ihashinit(void);
-int     ufs_ihashins(struct inode *);
int     ufs_ihashcheck(struct ufsmount *, cdev_t, ino_t);
+void     ufs_ihashinit(struct ufsmount *);
+void     ufs_ihashuninit(struct ufsmount *);
+int     ufs_ihashins(struct ufsmount *, struct inode *);
  struct vnode *
     ufs_ihashlookup(cdev_t, ino_t);void     ufs_ihashrem(struct inode *);     ufs_ihashlookup(struct ufsmount *, cdev_t, ino_t);
void     ufs_ihashrem(struct ufsmount *, struct inode *);
  int     ufs_inactive(struct vop_inactive_args *);
  int     ufs_init(struct vfsconf *);
-int     ufs_uninit(struct vfsconf *);
  void     ufs_itimes(struct vnode *vp);
  int     ufs_lookup(struct vop_old_lookup_args *);
  int     ufs_reclaim(struct vop_reclaim_args *);
diff --git a/sys/vfs/ufs/ufs_ihash.c b/sys/vfs/ufs/ufs_ihash.c
index 277bcf2..426b2d4 100644
-- a/sys/vfs/ufs/ufs_ihash.c
++ b/sys/vfs/ufs/ufs_ihash.c@ -32,7 +32,6 @
   *
   *    @(#)ufs_ihash.c    8.7 (Berkeley) 5/17/95
   * $FreeBSD: src/sys/ufs/ufs/ufs_ihash.c,v 1.20 1999/08/28 00:52:29 peter Exp $
- * $DragonFly: src/sys/vfs/ufs/ufs_ihash.c,v 1.20 2006/10/14 16:26:40 dillon Exp $
   */
#include <sys/param.h>
@ -42,60 +41,52 @
  #include <sys/vnode.h>
  #include <sys/malloc.h>
  #include <sys/proc.h>
+#include <sys/mount.h>#include "quota.h" 
  #include "inode.h" 
  #include "ufs_extern.h" 
+#include "ufsmount.h"static MALLOC_DEFINE(M_UFSIHASH, "UFS ihash", "UFS Inode hash tables");
/*
 * Structures associated with inode cacheing.
- /
-static struct inode **ihashtbl;
-static u_long    ihash;        / size of hash table - 1 */
-static struct lwkt_token ufs_ihash_token;#define    INOHASH    (&ihashtbl[(minor(device) + (inum)) & ihash])>um_ihashtbl[inum & ump->um_ihash])
#define    INOHASH    \
    (&ump
/*
 * Initialize inode hash table.
   */
  void
-ufs_ihashinit(void)
+ufs_ihashinit(struct ufsmount *ump)
{
-    ihash = 16;
-    while (ihash < desiredvnodes)
-        ihash <<= 1;
-    ihashtbl = kmalloc(sizeof(void *) * ihash, M_UFSIHASH, M_WAITOK|M_ZERO);
-    --ihash;
-    lwkt_token_init(&ufs_ihash_token, "ufsihash");
+    ump->um_ihash = 16;
+    while (ump->um_ihash < desiredvnodes)
+        ump->um_ihash <<= 1;
+    ump->um_ihashtbl = kmalloc(sizeof(void *) * ump->um_ihash, M_UFSIHASH,
+                   M_WAITOK|M_ZERO);
+    --ump->um_ihash;
  }-int
-ufs_uninit(struct vfsconf *vfc)
+void
+ufs_ihashuninit(struct ufsmount *ump)
  {
-    lwkt_gettoken(&ufs_ihash_token);
-    if (ihashtbl)
-        kfree(ihashtbl, M_UFSIHASH);
-    lwkt_reltoken(&ufs_ihash_token);
+    if (ump->um_ihashtbl)
+        kfree(ump->um_ihashtbl, M_UFSIHASH);
  }
+
  /*
   * Use the device/inum pair to find the incore inode, and return a pointer
   * to it. If it is in core, return it, even if it is locked.
   */
  struct vnode *
-ufs_ihashlookup(cdev_t dev, ino_t inum)
+ufs_ihashlookup(struct ufsmount *ump, cdev_t dev, ino_t inum)
  {
-    struct inode *ip;
+    struct inode *ip = NULL;
-    lwkt_gettoken(&ufs_ihash_token);
-    for (ip = *INOHASH; ip; ip = ip->i_next) {
+    for (ip = *INOHASH; ip; ip = ip->i_next) {
          if (inum  ip->i_number && dev  ip->i_dev)
              break;
      }
-    lwkt_reltoken(&ufs_ihash_token);
      if (ip)
          return (ITOV);
      return (NULLVP);@ -105,20 +96,16 @ ufs_ihashlookup(cdev_t dev, ino_t inum)
   * Use the device/inum pair to find the incore inode, and return a pointer
   * to it. If it is in core, but locked, wait for it.
   *
- * Note that the serializing tokens do not prevent other processes from
- * playing with the data structure being protected while we are blocked.
- * They do protect us from preemptive interrupts which might try to
- * play with the protected data structure.
+ * This subroutine may block.
   */
  struct vnode *
-ufs_ihashget(cdev_t dev, ino_t inum)
+ufs_ihashget(struct ufsmount *ump, cdev_t dev, ino_t inum)
  {
      struct inode *ip;
      struct vnode *vp;
-    lwkt_gettoken(&ufs_ihash_token);
  loop:
-    for (ip = *INOHASH; ip; ip = ip->i_next) {
+    for (ip = *INOHASH; ip; ip = ip->i_next) {
          if (inum != ip->i_number || dev != ip->i_dev)
              continue;
          vp = ITOV;@ -128,7 +115,7 @ loop:
           * We must check to see if the inode has been ripped
           * out from under us after blocking.
           */
-        for (ip = *INOHASH; ip; ip = ip->i_next) {
+        for (ip = *INOHASH; ip; ip = ip->i_next) {
              if (inum  ip->i_number && dev  ip->i_dev)
                  break;
          }@ -136,10 +123,8 @ loop:
              vput(vp);
              goto loop;
          }
-        lwkt_reltoken(&ufs_ihash_token);
          return (vp);
      }
-    lwkt_reltoken(&ufs_ihash_token);
      return (NULL);
  }
@ -149,16 +134,14 @ loop:
   * reallocate of its inode number before we have had a chance to recycle it.
   */
  int
-ufs_ihashcheck(cdev_t dev, ino_t inum)
+ufs_ihashcheck(struct ufsmount *ump, cdev_t dev, ino_t inum)
  {
      struct inode *ip;
-    lwkt_gettoken(&ufs_ihash_token);
-    for (ip = *INOHASH; ip; ip = ip->i_next) {
+    for (ip = *INOHASH; ip; ip = ip->i_next) {
          if (inum  ip->i_number && dev  ip->i_dev)
              break;
      }
-    lwkt_reltoken(&ufs_ihash_token);
      return(ip ? 1 : 0);
  }
@ -166,17 +149,15 @ ufs_ihashcheck(cdev_t dev, ino_t inum)
   * Insert the inode into the hash table, and return it locked.
   */
  int
-ufs_ihashins(struct inode *ip)
+ufs_ihashins(struct ufsmount *ump, struct inode *ip)
  {
      struct inode **ipp;
      struct inode *iq;
KKASSERT((ip->i_flag & IN_HASHED) == 0);
-    lwkt_gettoken(&ufs_ihash_token);
-    ipp = INOHASH(ip->i_dev, ip->i_number);
+    ipp = INOHASH(ump, ip->i_number);
      while ((iq = *ipp) != NULL) {
          if (ip->i_dev  iq->i_dev && ip->i_number  iq->i_number) {
-            lwkt_reltoken(&ufs_ihash_token);
              return(EBUSY);
          }
          ipp = &iq->i_next;
@ -184,7 +165,6 @ ufs_ihashins(struct inode *ip)
      ip->i_next = NULL;
      *ipp = ip;
      ip->i_flag |= IN_HASHED;
-    lwkt_reltoken(&ufs_ihash_token);
      return(0);
  }@ -192,14 +172,13 @ ufs_ihashins(struct inode *ip)
   * Remove the inode from the hash table.
   */
  void
-ufs_ihashrem(struct inode *ip)
+ufs_ihashrem(struct ufsmount *ump, struct inode *ip)
  {
      struct inode **ipp;
      struct inode *iq;
-    lwkt_gettoken(&ufs_ihash_token);
      if (ip->i_flag & IN_HASHED) {
-        ipp = INOHASH;
+        ipp = INOHASH;
          while ((iq = *ipp) != NULL) {
              if (ip == iq)
                  break;@ -210,6 +189,5 @ ufs_ihashrem(struct inode *ip)
          ip->i_next = NULL;
          ip->i_flag &= ~IN_HASHED;
      }
-    lwkt_reltoken(&ufs_ihash_token);
  }
diff --git a/sys/vfs/ufs/ufs_inode.c b/sys/vfs/ufs/ufs_inode.c
index 9b51bd5..6ccd0c4 100644
--- a/sys/vfs/ufs/ufs_inode.c
+++ b/sys/vfs/ufs/ufs_inode.c@ -116,10 +116,13 @ ufs_reclaim(struct vop_reclaim_args *ap)
  {
      struct inode *ip;
      struct vnode *vp = ap->a_vp;
+    struct ufsmount *ump;
  #ifdef QUOTA
      int i;
  #endif
+    ump = VFSTOUFS;
      if (prtactive && vp->v_sysref.refcnt > 1)
          vprint("ufs_reclaim: pushing active", vp);
      ip = VTOI;@ -146,7 +149,7 @ ufs_reclaim(struct vop_reclaim_args *ap)
       */
      vp->v_data = NULL;
      if (ip) {
-        ufs_ihashrem(ip);
        ufs_ihashrem(ump, ip);
          if (ip->i_devvp) {
              vrele(ip->i_devvp);
              ip->i_devvp = 0;
diff --git a/sys/vfs/ufs/ufs_vfsops.c b/sys/vfs/ufs/ufs_vfsops.c
index bf1ef52..315eed8 100644
--- a/sys/vfs/ufs/ufs_vfsops.c
++ b/sys/vfs/ufs/ufs_vfsops.c@ -192,7 +192,6 @ ufs_init(struct vfsconf *vfsp)
      if (done)
          return (0);
      done = 1;
-    ufs_ihashinit();
  #ifdef QUOTA
      ufs_dqinit();
  #endif
diff --git a/sys/vfs/ufs/ufsmount.h b/sys/vfs/ufs/ufsmount.h
index 1a07f1d..c789428 100644
--- a/sys/vfs/ufs/ufsmount.h
++ b/sys/vfs/ufs/ufsmount.h@ -32,7 +32,6 @
   *
   *    @(#)ufsmount.h    8.6 (Berkeley) 3/30/95
   * $FreeBSD: src/sys/ufs/ufs/ufsmount.h,v 1.17 1999/12/29 04:55:06 peter Exp $
- * $DragonFly: src/sys/vfs/ufs/ufsmount.h,v 1.11 2008/08/04 18:15:47 dillon Exp $
   */
#ifndef VFS_UFS_UFSMOUNT_H
@ -76,13 +75,7 @ struct ufsmount {
      cdev_t    um_dev;                /* device mounted /
      struct    vnode *um_devvp;        / block device mounted vnode */-    union {                    /* pointer to superblock /
-        struct    fs *fs;            / FFS /
-        struct    ext2_sb_info *e2fs;    / EXT2FS /
-    } ufsmount_u;#    define    um_fs    ufsmount_u.fs#    define    um_e2fs    ufsmount_u.e2fs#    define    um_e2fsb ufsmount_u.e2fs>s_es
+    struct    fs *um_fs;            / FFS /
      struct    vnode *um_quotas[MAXQUOTAS];    / pointer to quota files /
      struct    ucred *um_cred[MAXQUOTAS];    / quota file access cred /
      u_long    um_nindir;            / indirect ptrs per block /@ -95,6 +88,8 @ struct ufsmount {
      int64_t    um_savedmaxfilesize;        / XXX - limit maxfilesize /
      struct malloc_type *um_malloctype;    / The inodes malloctype /
      int    um_i_effnlink_valid;        / i_effnlink valid? /
+    struct inode **um_ihashtbl;        / inum to inode map /
+    u_long    um_ihash;            / size of hash table - 1 */
  };
/*
-- 
1.7.12.1.382.gb0576a6-- 
-- vs