[BACK]Return to ufs_dirhash.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / ufs / ufs

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/ufs/ufs/ufs_dirhash.c between version 1.5.2.1 and 1.13.2.4

version 1.5.2.1, 2005/10/20 03:00:31 version 1.13.2.4, 2007/07/15 13:28:20
Line 44 
Line 44 
 #include <sys/pool.h>  #include <sys/pool.h>
 #include <sys/sysctl.h>  #include <sys/sysctl.h>
   
 #include <ufs/ufs/quota.h>  
 #include <ufs/ufs/inode.h>  #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>  #include <ufs/ufs/dir.h>
 #include <ufs/ufs/dirhash.h>  #include <ufs/ufs/dirhash.h>
Line 57 
Line 56 
 #define OFSFMT(ip)              ((ip)->i_ump->um_maxsymlinklen <= 0)  #define OFSFMT(ip)              ((ip)->i_ump->um_maxsymlinklen <= 0)
 #define BLKFREE2IDX(n)          ((n) > DH_NFSTATS ? DH_NFSTATS : (n))  #define BLKFREE2IDX(n)          ((n) > DH_NFSTATS ? DH_NFSTATS : (n))
   
 static MALLOC_DEFINE(M_DIRHASH, "UFS dirhash", "UFS directory hash tables");  static MALLOC_JUSTDEFINE(M_DIRHASH, "UFS dirhash", "UFS directory hash tables");
   
 static int ufs_dirhashminblks = 5;  static int ufs_dirhashminblks = 5;
 static int ufs_dirhashmaxmem = 2 * 1024 * 1024;  static int ufs_dirhashmaxmem = 2 * 1024 * 1024;
Line 74  static doff_t ufsdirhash_getprev(struct 
Line 73  static doff_t ufsdirhash_getprev(struct 
            int dirblksiz);             int dirblksiz);
 static int ufsdirhash_recycle(int wanted);  static int ufsdirhash_recycle(int wanted);
   
 POOL_INIT(ufsdirhash_pool, DH_NBLKOFF * sizeof(daddr_t), 0, 0, 0, "ufsdirhash",  #define DIRHASHLIST_LOCK()              mutex_enter(&ufsdirhash_lock)
     &pool_allocator_nointr);  #define DIRHASHLIST_UNLOCK()            mutex_exit(&ufsdirhash_lock)
   #define DIRHASH_LOCK(dh)                mutex_enter(&(dh)->dh_lock)
 #define DIRHASHLIST_LOCK()              do { } while (0)  #define DIRHASH_UNLOCK(dh)              mutex_exit(&(dh)->dh_lock)
 #define DIRHASHLIST_UNLOCK()            do { } while (0)  
 #define DIRHASH_LOCK(dh)                do { } while (0)  
 #define DIRHASH_UNLOCK(dh)              do { } while (0)  
 #define DIRHASH_BLKALLOC_WAITOK()       pool_get(&ufsdirhash_pool, PR_WAITOK)  #define DIRHASH_BLKALLOC_WAITOK()       pool_get(&ufsdirhash_pool, PR_WAITOK)
 #define DIRHASH_BLKFREE(ptr)            pool_put(&ufsdirhash_pool, ptr)  #define DIRHASH_BLKFREE(ptr)            pool_put(&ufsdirhash_pool, ptr)
   
 /* Dirhash list; recently-used entries are near the tail. */  /* Dirhash list; recently-used entries are near the tail. */
 static TAILQ_HEAD(, dirhash) ufsdirhash_list;  static TAILQ_HEAD(, dirhash) ufsdirhash_list;
   
   /* Protects: ufsdirhash_list, `dh_list' field, ufs_dirhashmem. */
   static kmutex_t ufsdirhash_lock;
   
   /*
    * Locking order:
    *      ufsdirhash_lock
    *      dh_lock
    *
    * The dh_lock mutex should be acquired either via the inode lock, or via
    * ufsdirhash_lock. Only the owner of the inode may free the associated
    * dirhash, but anything can steal its memory and set dh_hash to NULL.
    */
   
 /*  /*
  * Attempt to build up a hash table for the directory contents in   * Attempt to build up a hash table for the directory contents in
  * inode 'ip'. Returns 0 on success, or -1 of the operation failed.   * inode 'ip'. Returns 0 on success, or -1 of the operation failed.
Line 163  ufsdirhash_build(struct inode *ip)
Line 172  ufsdirhash_build(struct inode *ip)
                 DIRHASHLIST_UNLOCK();                  DIRHASHLIST_UNLOCK();
                 return (-1);                  return (-1);
         }          }
         MALLOC(dh->dh_hash, doff_t **, narrays * sizeof(dh->dh_hash[0]),          mutex_init(&dh->dh_lock, MUTEX_DEFAULT, IPL_NONE);
           dh->dh_hash = (doff_t **)malloc(narrays * sizeof(dh->dh_hash[0]),
             M_DIRHASH, M_NOWAIT | M_ZERO);              M_DIRHASH, M_NOWAIT | M_ZERO);
         MALLOC(dh->dh_blkfree, u_int8_t *, nblocks * sizeof(dh->dh_blkfree[0]),          dh->dh_blkfree = (u_int8_t *)malloc(nblocks * sizeof(dh->dh_blkfree[0]),
             M_DIRHASH, M_NOWAIT);              M_DIRHASH, M_NOWAIT);
         if (dh->dh_hash == NULL || dh->dh_blkfree == NULL)          if (dh->dh_hash == NULL || dh->dh_blkfree == NULL)
                 goto fail;                  goto fail;
Line 194  ufsdirhash_build(struct inode *ip)
Line 204  ufsdirhash_build(struct inode *ip)
         bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;          bmask = VFSTOUFS(vp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
         pos = 0;          pos = 0;
         while (pos < ip->i_size) {          while (pos < ip->i_size) {
                   if ((curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
                       != 0) {
                           preempt();
                   }
                 /* If necessary, get the next directory block. */                  /* If necessary, get the next directory block. */
                 if ((pos & bmask) == 0) {                  if ((pos & bmask) == 0) {
                         if (bp != NULL)                          if (bp != NULL)
                                 brelse(bp);                                  brelse(bp, 0);
                         if (UFS_BLKATOFF(vp, (off_t)pos, NULL, &bp) != 0)                          if (ufs_blkatoff(vp, (off_t)pos, NULL, &bp) != 0)
                                 goto fail;                                  goto fail;
                 }                  }
   
Line 207  ufsdirhash_build(struct inode *ip)
Line 221  ufsdirhash_build(struct inode *ip)
                 if (ep->d_reclen == 0 || ep->d_reclen >                  if (ep->d_reclen == 0 || ep->d_reclen >
                     dirblksiz - (pos & (dirblksiz - 1))) {                      dirblksiz - (pos & (dirblksiz - 1))) {
                         /* Corrupted directory. */                          /* Corrupted directory. */
                         brelse(bp);                          brelse(bp, 0);
                         goto fail;                          goto fail;
                 }                  }
                 if (ep->d_ino != 0) {                  if (ep->d_ino != 0) {
Line 224  ufsdirhash_build(struct inode *ip)
Line 238  ufsdirhash_build(struct inode *ip)
         }          }
   
         if (bp != NULL)          if (bp != NULL)
                 brelse(bp);                  brelse(bp, 0);
         DIRHASHLIST_LOCK();          DIRHASHLIST_LOCK();
         TAILQ_INSERT_TAIL(&ufsdirhash_list, dh, dh_list);          TAILQ_INSERT_TAIL(&ufsdirhash_list, dh, dh_list);
         dh->dh_onlist = 1;          dh->dh_onlist = 1;
Line 240  fail:
Line 254  fail:
         }          }
         if (dh->dh_blkfree != NULL)          if (dh->dh_blkfree != NULL)
                 FREE(dh->dh_blkfree, M_DIRHASH);                  FREE(dh->dh_blkfree, M_DIRHASH);
           mutex_destroy(&dh->dh_lock);
         FREE(dh, M_DIRHASH);          FREE(dh, M_DIRHASH);
         ip->i_dirhash = NULL;          ip->i_dirhash = NULL;
         DIRHASHLIST_LOCK();          DIRHASHLIST_LOCK();
Line 278  ufsdirhash_free(struct inode *ip)
Line 293  ufsdirhash_free(struct inode *ip)
                     dh->dh_narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +                      dh->dh_narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
                     dh->dh_nblk * sizeof(*dh->dh_blkfree);                      dh->dh_nblk * sizeof(*dh->dh_blkfree);
         }          }
           mutex_destroy(&dh->dh_lock);
         FREE(dh, M_DIRHASH);          FREE(dh, M_DIRHASH);
         ip->i_dirhash = NULL;          ip->i_dirhash = NULL;
   
Line 314  ufsdirhash_lookup(struct inode *ip, cons
Line 330  ufsdirhash_lookup(struct inode *ip, cons
                 return (EJUSTRETURN);                  return (EJUSTRETURN);
         /*          /*
          * Move this dirhash towards the end of the list if it has a           * Move this dirhash towards the end of the list if it has a
          * score higher than the next entry, and acquire the dh_mtx.           * score higher than the next entry, and acquire the dh_lock.
          * Optimise the case where it's already the last by performing           * Optimise the case where it's already the last by performing
          * an unlocked read of the TAILQ_NEXT pointer.           * an unlocked read of the TAILQ_NEXT pointer.
          *           *
          * In both cases, end up holding just dh_mtx.           * In both cases, end up holding just dh_lock.
          */           */
         if (TAILQ_NEXT(dh, dh_list) != NULL) {          if (TAILQ_NEXT(dh, dh_list) != NULL) {
                 DIRHASHLIST_LOCK();                  DIRHASHLIST_LOCK();
Line 391  restart:
Line 407  restart:
                         panic("ufsdirhash_lookup: bad offset in hash array");                          panic("ufsdirhash_lookup: bad offset in hash array");
                 if ((offset & ~bmask) != blkoff) {                  if ((offset & ~bmask) != blkoff) {
                         if (bp != NULL)                          if (bp != NULL)
                                 brelse(bp);                                  brelse(bp, 0);
                         blkoff = offset & ~bmask;                          blkoff = offset & ~bmask;
                         if (UFS_BLKATOFF(vp, (off_t)blkoff, NULL, &bp) != 0)                          if (ufs_blkatoff(vp, (off_t)blkoff, NULL, &bp) != 0)
                                 return (EJUSTRETURN);                                  return (EJUSTRETURN);
                 }                  }
                 dp = (struct direct *)(bp->b_data + (offset & bmask));                  dp = (struct direct *)((char *)bp->b_data + (offset & bmask));
                 if (dp->d_reclen == 0 || dp->d_reclen >                  if (dp->d_reclen == 0 || dp->d_reclen >
                     dirblksiz - (offset & (dirblksiz - 1))) {                      dirblksiz - (offset & (dirblksiz - 1))) {
                         /* Corrupted directory. */                          /* Corrupted directory. */
                         brelse(bp);                          brelse(bp, 0);
                         return (EJUSTRETURN);                          return (EJUSTRETURN);
                 }                  }
                 if (dp->d_namlen == namelen &&                  if (dp->d_namlen == namelen &&
Line 411  restart:
Line 427  restart:
                                         prevoff = ufsdirhash_getprev(dp,                                          prevoff = ufsdirhash_getprev(dp,
                                             offset, dirblksiz);                                              offset, dirblksiz);
                                         if (prevoff == -1) {                                          if (prevoff == -1) {
                                                 brelse(bp);                                                  brelse(bp, 0);
                                                 return (EJUSTRETURN);                                                  return (EJUSTRETURN);
                                         }                                          }
                                 } else                                  } else
Line 433  restart:
Line 449  restart:
                 if (dh->dh_hash == NULL) {                  if (dh->dh_hash == NULL) {
                         DIRHASH_UNLOCK(dh);                          DIRHASH_UNLOCK(dh);
                         if (bp != NULL)                          if (bp != NULL)
                                 brelse(bp);                                  brelse(bp, 0);
                         ufsdirhash_free(ip);                          ufsdirhash_free(ip);
                         return (EJUSTRETURN);                          return (EJUSTRETURN);
                 }                  }
Line 448  restart:
Line 464  restart:
         }          }
         DIRHASH_UNLOCK(dh);          DIRHASH_UNLOCK(dh);
         if (bp != NULL)          if (bp != NULL)
                 brelse(bp);                  brelse(bp, 0);
         return (ENOENT);          return (ENOENT);
 }  }
   
Line 502  ufsdirhash_findfree(struct inode *ip, in
Line 518  ufsdirhash_findfree(struct inode *ip, in
             dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN));              dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN));
         DIRHASH_UNLOCK(dh);          DIRHASH_UNLOCK(dh);
         pos = dirblock * dirblksiz;          pos = dirblock * dirblksiz;
         error = UFS_BLKATOFF(ip->i_vnode, (off_t)pos, (void *)&dp, &bp);          error = ufs_blkatoff(ip->i_vnode, (off_t)pos, (void *)&dp, &bp);
         if (error)          if (error)
                 return (-1);                  return (-1);
         /* Find the first entry with free space. */          /* Find the first entry with free space. */
         for (i = 0; i < dirblksiz; ) {          for (i = 0; i < dirblksiz; ) {
                 if (dp->d_reclen == 0) {                  if (dp->d_reclen == 0) {
                         brelse(bp);                          brelse(bp, 0);
                         return (-1);                          return (-1);
                 }                  }
                 if (dp->d_ino == 0 || dp->d_reclen > DIRSIZ(0, dp, needswap))                  if (dp->d_ino == 0 || dp->d_reclen > DIRSIZ(0, dp, needswap))
Line 517  ufsdirhash_findfree(struct inode *ip, in
Line 533  ufsdirhash_findfree(struct inode *ip, in
                 dp = (struct direct *)((char *)dp + dp->d_reclen);                  dp = (struct direct *)((char *)dp + dp->d_reclen);
         }          }
         if (i > dirblksiz) {          if (i > dirblksiz) {
                 brelse(bp);                  brelse(bp, 0);
                 return (-1);                  return (-1);
         }          }
         slotstart = pos + i;          slotstart = pos + i;
Line 529  ufsdirhash_findfree(struct inode *ip, in
Line 545  ufsdirhash_findfree(struct inode *ip, in
                 if (dp->d_ino != 0)                  if (dp->d_ino != 0)
                         freebytes -= DIRSIZ(0, dp, needswap);                          freebytes -= DIRSIZ(0, dp, needswap);
                 if (dp->d_reclen == 0) {                  if (dp->d_reclen == 0) {
                         brelse(bp);                          brelse(bp, 0);
                         return (-1);                          return (-1);
                 }                  }
                 i += dp->d_reclen;                  i += dp->d_reclen;
                 dp = (struct direct *)((char *)dp + dp->d_reclen);                  dp = (struct direct *)((char *)dp + dp->d_reclen);
         }          }
         if (i > dirblksiz) {          if (i > dirblksiz) {
                 brelse(bp);                  brelse(bp, 0);
                 return (-1);                  return (-1);
         }          }
         if (freebytes < slotneeded)          if (freebytes < slotneeded)
                 panic("ufsdirhash_findfree: free mismatch");                  panic("ufsdirhash_findfree: free mismatch");
         brelse(bp);          brelse(bp, 0);
         *slotsize = pos + i - slotstart;          *slotsize = pos + i - slotstart;
         return (slotstart);          return (slotstart);
 }  }
Line 871  ufsdirhash_hash(struct dirhash *dh, cons
Line 887  ufsdirhash_hash(struct dirhash *dh, cons
  * by the value specified by `diff'.   * by the value specified by `diff'.
  *   *
  * The caller must ensure we have exclusive access to `dh'; normally   * The caller must ensure we have exclusive access to `dh'; normally
  * that means that dh_mtx should be held, but this is also called   * that means that dh_lock should be held, but this is also called
  * from ufsdirhash_build() where exclusive access can be assumed.   * from ufsdirhash_build() where exclusive access can be assumed.
  */   */
 static void  static void
Line 915  ufsdirhash_findslot(struct dirhash *dh, 
Line 931  ufsdirhash_findslot(struct dirhash *dh, 
 {  {
         int slot;          int slot;
   
           KASSERT(mutex_owned(&dh->dh_lock));
   
           KASSERT(mutex_owned(&dh->dh_lock));
   
         /* Find the entry. */          /* Find the entry. */
         KASSERT(dh->dh_hused < dh->dh_hlen);          KASSERT(dh->dh_hused < dh->dh_hlen);
         slot = ufsdirhash_hash(dh, name, namelen);          slot = ufsdirhash_hash(dh, name, namelen);
Line 937  ufsdirhash_delslot(struct dirhash *dh, i
Line 957  ufsdirhash_delslot(struct dirhash *dh, i
 {  {
         int i;          int i;
   
           KASSERT(mutex_owned(&dh->dh_lock));
   
           KASSERT(mutex_owned(&dh->dh_lock));
   
         /* Mark the entry as deleted. */          /* Mark the entry as deleted. */
         DH_ENTRY(dh, slot) = DIRHASH_DEL;          DH_ENTRY(dh, slot) = DIRHASH_DEL;
   
Line 1047  ufsdirhash_recycle(int wanted)
Line 1071  ufsdirhash_recycle(int wanted)
 void  void
 ufsdirhash_init()  ufsdirhash_init()
 {  {
 #ifdef _LKM  
         pool_init(&ufsdirhash_pool, DH_NBLKOFF * sizeof(daddr_t), 0, 0, 0,          pool_init(&ufsdirhash_pool, DH_NBLKOFF * sizeof(daddr_t), 0, 0, 0,
             "ufsdirhash", &pool_allocator_nointr);              "ufsdirhash", &pool_allocator_nointr, IPL_NONE);
 #endif          mutex_init(&ufsdirhash_lock, MUTEX_DEFAULT, IPL_NONE);
         TAILQ_INIT(&ufsdirhash_list);          TAILQ_INIT(&ufsdirhash_list);
 }  }
   
Line 1058  void
Line 1081  void
 ufsdirhash_done(void)  ufsdirhash_done(void)
 {  {
         KASSERT(TAILQ_EMPTY(&ufsdirhash_list));          KASSERT(TAILQ_EMPTY(&ufsdirhash_list));
 #ifdef _LKM  
         pool_destroy(&ufsdirhash_pool);          pool_destroy(&ufsdirhash_pool);
 #endif          mutex_destroy(&ufsdirhash_lock);
 }  }
   
 SYSCTL_SETUP(sysctl_vfs_ufs_setup, "sysctl vfs.ufs.dirhash subtree setup")  SYSCTL_SETUP(sysctl_vfs_ufs_setup, "sysctl vfs.ufs.dirhash subtree setup")

Legend:
Removed from v.1.5.2.1  
changed lines
  Added in v.1.13.2.4

CVSweb <webmaster@jp.NetBSD.org>