[BACK]Return to ufs_lookup.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_lookup.c between version 1.47.2.8 and 1.99.2.2

version 1.47.2.8, 2005/01/24 08:36:05 version 1.99.2.2, 2009/03/03 18:34:40
Line 39 
Line 39 
 #include <sys/cdefs.h>  #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD$");  __KERNEL_RCSID(0, "$NetBSD$");
   
   #ifdef _KERNEL_OPT
   #include "opt_ffs.h"
   #include "fs_ffs.h"
   #endif
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/systm.h>  #include <sys/systm.h>
 #include <sys/namei.h>  #include <sys/namei.h>
Line 48  __KERNEL_RCSID(0, "$NetBSD$");
Line 53  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/mount.h>  #include <sys/mount.h>
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/kernel.h>  #include <sys/kernel.h>
   #include <sys/kauth.h>
   #include <sys/wapbl.h>
   #include <sys/fstrans.h>
   #include <sys/proc.h>
   #include <sys/kmem.h>
   
 #include <ufs/ufs/inode.h>  #include <ufs/ufs/inode.h>
 #include <ufs/ufs/dir.h>  #include <ufs/ufs/dir.h>
Line 57  __KERNEL_RCSID(0, "$NetBSD$");
Line 67  __KERNEL_RCSID(0, "$NetBSD$");
 #include <ufs/ufs/ufsmount.h>  #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/ufs_extern.h>  #include <ufs/ufs/ufs_extern.h>
 #include <ufs/ufs/ufs_bswap.h>  #include <ufs/ufs/ufs_bswap.h>
   #include <ufs/ufs/ufs_wapbl.h>
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
 int     dirchk = 1;  int     dirchk = 1;
Line 64  int dirchk = 1;
Line 75  int dirchk = 1;
 int     dirchk = 0;  int     dirchk = 0;
 #endif  #endif
   
 #define FSFMT(vp)   (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) ==  0)  #define FSFMT(vp)       (((vp)->v_mount->mnt_iflag & IMNT_DTYPE) == 0)
   
 /*  /*
  * Convert a component of a pathname into a pointer to a locked inode.   * Convert a component of a pathname into a pointer to a locked inode.
Line 100  int dirchk = 0;
Line 111  int dirchk = 0;
  *        nor deleting, add name to cache   *        nor deleting, add name to cache
  */   */
 int  int
 ufs_lookup(v)  ufs_lookup(void *v)
         void *v;  
 {  {
         struct vop_lookup_args /* {          struct vop_lookup_args /* {
                 struct vnode *a_dvp;                  struct vnode *a_dvp;
Line 125  ufs_lookup(v)
Line 135  ufs_lookup(v)
         struct vnode *tdp;              /* returned by VFS_VGET */          struct vnode *tdp;              /* returned by VFS_VGET */
         doff_t enduseful;               /* pointer past last used dir slot */          doff_t enduseful;               /* pointer past last used dir slot */
         u_long bmask;                   /* block offset mask */          u_long bmask;                   /* block offset mask */
         int lockparent;                 /* 1 => lockparent flag is set */  
         int wantparent;                 /* 1 => wantparent or lockparent flag */  
         int namlen, error;          int namlen, error;
         struct vnode **vpp = ap->a_vpp;          struct vnode **vpp = ap->a_vpp;
         struct componentname *cnp = ap->a_cnp;          struct componentname *cnp = ap->a_cnp;
         struct ucred *cred = cnp->cn_cred;          kauth_cred_t cred = cnp->cn_cred;
         int flags;          int flags;
         int nameiop = cnp->cn_nameiop;          int nameiop = cnp->cn_nameiop;
         struct ufsmount *ump = dp->i_ump;          struct ufsmount *ump = dp->i_ump;
Line 138  ufs_lookup(v)
Line 146  ufs_lookup(v)
         int dirblksiz = ump->um_dirblksiz;          int dirblksiz = ump->um_dirblksiz;
         ino_t foundino;          ino_t foundino;
   
         cnp->cn_flags &= ~PDIRUNLOCK;  
         flags = cnp->cn_flags;          flags = cnp->cn_flags;
   
         bp = NULL;          bp = NULL;
         slotoffset = -1;          slotoffset = -1;
         *vpp = NULL;          *vpp = NULL;
         lockparent = flags & LOCKPARENT;  
         wantparent = flags & (LOCKPARENT|WANTPARENT);  
         endsearch = 0; /* silence compiler warning */          endsearch = 0; /* silence compiler warning */
         /*          /*
          * Check accessiblity of directory.           * Check accessiblity of directory.
          */           */
         if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_lwp)) != 0)          if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0)
                 return (error);                  return (error);
   
         if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&          if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
             (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))              (nameiop == DELETE || nameiop == RENAME))
                 return (EROFS);                  return (EROFS);
   
         /*          /*
Line 164  ufs_lookup(v)
Line 169  ufs_lookup(v)
          * check the name cache to see if the directory/name pair           * check the name cache to see if the directory/name pair
          * we are looking for is known already.           * we are looking for is known already.
          */           */
         if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)          if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) {
                 return (error);                  return (error);
           }
   
           fstrans_start(vdp->v_mount, FSTRANS_SHARED);
   
         /*          /*
          * Suppress search for slots unless creating           * Suppress search for slots unless creating
Line 241  ufs_lookup(v)
Line 249  ufs_lookup(v)
         } else {          } else {
                 dp->i_offset = dp->i_diroff;                  dp->i_offset = dp->i_diroff;
                 if ((entryoffsetinblock = dp->i_offset & bmask) &&                  if ((entryoffsetinblock = dp->i_offset & bmask) &&
                     (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))                      (error = ufs_blkatoff(vdp, (off_t)dp->i_offset,
                         return (error);                      NULL, &bp, false)))
                           goto out;
                 numdirpasses = 2;                  numdirpasses = 2;
                 nchstats.ncs_2passes++;                  nchstats.ncs_2passes++;
         }          }
Line 253  ufs_lookup(v)
Line 262  ufs_lookup(v)
 searchloop:  searchloop:
         while (dp->i_offset < endsearch) {          while (dp->i_offset < endsearch) {
                 if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)                  if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
                         preempt(1);                          preempt();
                 /*                  /*
                  * If necessary, get the next directory block.                   * If necessary, get the next directory block.
                  */                   */
                 if ((dp->i_offset & bmask) == 0) {                  if ((dp->i_offset & bmask) == 0) {
                         if (bp != NULL)                          if (bp != NULL)
                                 brelse(bp);                                  brelse(bp, 0);
                         error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL,                          error = ufs_blkatoff(vdp, (off_t)dp->i_offset, NULL,
                             &bp);                              &bp, false);
                         if (error)                          if (error)
                                 return (error);                                  goto out;
                         entryoffsetinblock = 0;                          entryoffsetinblock = 0;
                 }                  }
                 /*                  /*
                  * If still looking for a slot, and at a DIRBLKSIZE                   * If still looking for a slot, and at a DIRBLKSIZ
                  * boundary, have to start looking for free space again.                   * boundary, have to start looking for free space again.
                  */                   */
                 if (slotstatus == NONE &&                  if (slotstatus == NONE &&
Line 282  searchloop:
Line 291  searchloop:
                  * directory. Complete checks can be run by patching                   * directory. Complete checks can be run by patching
                  * "dirchk" to be true.                   * "dirchk" to be true.
                  */                   */
                   KASSERT(bp != NULL);
                 ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock);                  ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock);
                 if (ep->d_reclen == 0 ||                  if (ep->d_reclen == 0 ||
                     (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) {                      (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) {
Line 336  searchloop:
Line 346  searchloop:
                         else                          else
                                 namlen = ep->d_namlen;                                  namlen = ep->d_namlen;
 #else  #else
                         if (FSFMT(vdp) && needswap != 0)                          if (FSFMT(vdp) && needswap != 0)
                                 namlen = ep->d_type;                                  namlen = ep->d_type;
                         else                          else
                                 namlen = ep->d_namlen;                                  namlen = ep->d_namlen;
Line 402  notfound:
Line 412  notfound:
                 goto searchloop;                  goto searchloop;
         }          }
         if (bp != NULL)          if (bp != NULL)
                 brelse(bp);                  brelse(bp, 0);
         /*          /*
          * If creating, and at end of pathname and current           * If creating, and at end of pathname and current
          * directory has not been removed, then can consider           * directory has not been removed, then can consider
Line 412  notfound:
Line 422  notfound:
              (nameiop == DELETE &&               (nameiop == DELETE &&
               (ap->a_cnp->cn_flags & DOWHITEOUT) &&                (ap->a_cnp->cn_flags & DOWHITEOUT) &&
               (ap->a_cnp->cn_flags & ISWHITEOUT))) &&                (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
             (flags & ISLASTCN) && dp->i_ffs_effnlink != 0) {              (flags & ISLASTCN) && dp->i_nlink != 0) {
                 /*                  /*
                  * Access for write is interpreted as allowing                   * Access for write is interpreted as allowing
                  * creation of files in the directory.                   * creation of files in the directory.
                  */                   */
                 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);                  error = VOP_ACCESS(vdp, VWRITE, cred);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 /*                  /*
                  * Return an indication of where the new directory                   * Return an indication of where the new directory
                  * entry should be put.  If we didn't find a slot,                   * entry should be put.  If we didn't find a slot,
Line 463  notfound:
Line 473  notfound:
                  * information cannot be used.                   * information cannot be used.
                  */                   */
                 cnp->cn_flags |= SAVENAME;                  cnp->cn_flags |= SAVENAME;
                 if (!lockparent) {                  error = EJUSTRETURN;
                         VOP_UNLOCK(vdp, 0);                  goto out;
                         cnp->cn_flags |= PDIRUNLOCK;  
                 }  
                 return (EJUSTRETURN);  
         }          }
         /*          /*
          * Insert name into cache (as non-existent) if appropriate.           * Insert name into cache (as non-existent) if appropriate.
          */           */
         if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)          if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
                 cache_enter(vdp, *vpp, cnp);                  cache_enter(vdp, *vpp, cnp);
         return (ENOENT);          error = ENOENT;
           goto out;
   
 found:  found:
         if (numdirpasses == 2)          if (numdirpasses == 2)
Line 488  found:
Line 496  found:
                 dp->i_size = dp->i_offset + DIRSIZ(FSFMT(vdp), ep, needswap);                  dp->i_size = dp->i_offset + DIRSIZ(FSFMT(vdp), ep, needswap);
                 DIP_ASSIGN(dp, size, dp->i_size);                  DIP_ASSIGN(dp, size, dp->i_size);
                 dp->i_flag |= IN_CHANGE | IN_UPDATE;                  dp->i_flag |= IN_CHANGE | IN_UPDATE;
                   UFS_WAPBL_UPDATE(vdp, NULL, NULL, UPDATE_DIROP);
         }          }
         brelse(bp);          brelse(bp, 0);
   
         /*          /*
          * Found component in pathname.           * Found component in pathname.
Line 502  found:
Line 511  found:
         /*          /*
          * If deleting, and at end of pathname, return           * If deleting, and at end of pathname, return
          * parameters which can be used to remove file.           * parameters which can be used to remove file.
          * If the wantparent flag isn't set, we return only           * Lock the inode, being careful with ".".
          * the directory (in ndp->ni_dvp), otherwise we go  
          * on and lock the inode, being careful with ".".  
          */           */
         if (nameiop == DELETE && (flags & ISLASTCN)) {          if (nameiop == DELETE && (flags & ISLASTCN)) {
                 /*                  /*
                  * Write access to directory required to delete files.                   * Write access to directory required to delete files.
                  */                   */
                 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);                  error = VOP_ACCESS(vdp, VWRITE, cred);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 /*                  /*
                  * Return pointer to current entry in dp->i_offset,                   * Return pointer to current entry in dp->i_offset,
                  * and distance past previous entry (if there                   * and distance past previous entry (if there
Line 526  found:
Line 533  found:
                 if (dp->i_number == foundino) {                  if (dp->i_number == foundino) {
                         VREF(vdp);                          VREF(vdp);
                         *vpp = vdp;                          *vpp = vdp;
                         return (0);                          error = 0;
                           goto out;
                 }                  }
                 if (flags & ISDOTDOT)                  if (flags & ISDOTDOT)
                         VOP_UNLOCK(vdp, 0); /* race to get the inode */                          VOP_UNLOCK(vdp, 0); /* race to get the inode */
Line 534  found:
Line 542  found:
                 if (flags & ISDOTDOT)                  if (flags & ISDOTDOT)
                         vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);                          vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 /*                  /*
                  * If directory is "sticky", then user must own                   * If directory is "sticky", then user must own
                  * the directory, or the file in it, else she                   * the directory, or the file in it, else she
Line 542  found:
Line 550  found:
                  * implements append-only directories.                   * implements append-only directories.
                  */                   */
                 if ((dp->i_mode & ISVTX) &&                  if ((dp->i_mode & ISVTX) &&
                     cred->cr_uid != 0 &&                      kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
                     cred->cr_uid != dp->i_uid &&                       NULL) != 0 &&
                     VTOI(tdp)->i_uid != cred->cr_uid) {                      kauth_cred_geteuid(cred) != dp->i_uid &&
                       VTOI(tdp)->i_uid != kauth_cred_geteuid(cred)) {
                         vput(tdp);                          vput(tdp);
                         return (EPERM);                          error = EPERM;
                           goto out;
                 }                  }
                 *vpp = tdp;                  *vpp = tdp;
                 if (!lockparent) {                  error = 0;
                         VOP_UNLOCK(vdp, 0);                  goto out;
                         cnp->cn_flags |= PDIRUNLOCK;  
                 }  
                 return (0);  
         }          }
   
         /*          /*
Line 562  found:
Line 569  found:
          * Must get inode of directory entry to verify it's a           * Must get inode of directory entry to verify it's a
          * regular file, or empty directory.           * regular file, or empty directory.
          */           */
         if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {          if (nameiop == RENAME && (flags & ISLASTCN)) {
                 error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_lwp);                  error = VOP_ACCESS(vdp, VWRITE, cred);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 /*                  /*
                  * Careful about locking second inode.                   * Careful about locking second inode.
                  * This can only occur if the target is ".".                   * This can only occur if the target is ".".
                  */                   */
                 if (dp->i_number == foundino)                  if (dp->i_number == foundino) {
                         return (EISDIR);                          error = EISDIR;
                           goto out;
                   }
                 if (flags & ISDOTDOT)                  if (flags & ISDOTDOT)
                         VOP_UNLOCK(vdp, 0); /* race to get the inode */                          VOP_UNLOCK(vdp, 0); /* race to get the inode */
                 error = VFS_VGET(vdp->v_mount, foundino, &tdp);                  error = VFS_VGET(vdp->v_mount, foundino, &tdp);
                 if (flags & ISDOTDOT)                  if (flags & ISDOTDOT)
                         vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);                          vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 *vpp = tdp;                  *vpp = tdp;
                 cnp->cn_flags |= SAVENAME;                  cnp->cn_flags |= SAVENAME;
                 if (!lockparent) {                  error = 0;
                         VOP_UNLOCK(vdp, 0);                  goto out;
                         cnp->cn_flags |= PDIRUNLOCK;  
                 }  
                 return (0);  
         }          }
   
         /*          /*
Line 610  found:
Line 616  found:
         pdp = vdp;          pdp = vdp;
         if (flags & ISDOTDOT) {          if (flags & ISDOTDOT) {
                 VOP_UNLOCK(pdp, 0);     /* race to get the inode */                  VOP_UNLOCK(pdp, 0);     /* race to get the inode */
                 cnp->cn_flags |= PDIRUNLOCK;  
                 error = VFS_VGET(vdp->v_mount, foundino, &tdp);                  error = VFS_VGET(vdp->v_mount, foundino, &tdp);
                   vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
                 if (error) {                  if (error) {
                         if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)                          goto out;
                                 cnp->cn_flags &= ~PDIRUNLOCK;  
                         return (error);  
                 }  
                 if (lockparent && (flags & ISLASTCN)) {  
                         if ((error = vn_lock(pdp, LK_EXCLUSIVE))) {  
                                 vput(tdp);  
                                 return (error);  
                         }  
                         cnp->cn_flags &= ~PDIRUNLOCK;  
                 }                  }
                 *vpp = tdp;                  *vpp = tdp;
         } else if (dp->i_number == foundino) {          } else if (dp->i_number == foundino) {
Line 631  found:
Line 628  found:
         } else {          } else {
                 error = VFS_VGET(vdp->v_mount, foundino, &tdp);                  error = VFS_VGET(vdp->v_mount, foundino, &tdp);
                 if (error)                  if (error)
                         return (error);                          goto out;
                 if (!lockparent || !(flags & ISLASTCN)) {  
                         VOP_UNLOCK(pdp, 0);  
                         cnp->cn_flags |= PDIRUNLOCK;  
                 }  
                 *vpp = tdp;                  *vpp = tdp;
         }          }
   
Line 644  found:
Line 637  found:
          */           */
         if (cnp->cn_flags & MAKEENTRY)          if (cnp->cn_flags & MAKEENTRY)
                 cache_enter(vdp, *vpp, cnp);                  cache_enter(vdp, *vpp, cnp);
         return (0);          error = 0;
   
   out:
           fstrans_done(vdp->v_mount);
           return error;
 }  }
   
 void  void
 ufs_dirbad(ip, offset, how)  ufs_dirbad(struct inode *ip, doff_t offset, const char *how)
         struct inode *ip;  
         doff_t offset;  
         char *how;  
 {  {
         struct mount *mp;          struct mount *mp;
   
         mp = ITOV(ip)->v_mount;          mp = ITOV(ip)->v_mount;
         printf("%s: bad dir ino %d at offset %d: %s\n",          printf("%s: bad dir ino %llu at offset %d: %s\n",
             mp->mnt_stat.f_mntonname, ip->i_number, offset, how);              mp->mnt_stat.f_mntonname, (unsigned long long)ip->i_number,
               offset, how);
         if ((mp->mnt_stat.f_flag & MNT_RDONLY) == 0)          if ((mp->mnt_stat.f_flag & MNT_RDONLY) == 0)
                 panic("bad dir");                  panic("bad dir");
 }  }
Line 667  ufs_dirbad(ip, offset, how)
Line 662  ufs_dirbad(ip, offset, how)
  *      record length must be multiple of 4   *      record length must be multiple of 4
  *      entry must fit in rest of its DIRBLKSIZ block   *      entry must fit in rest of its DIRBLKSIZ block
  *      record must be large enough to contain entry   *      record must be large enough to contain entry
  *      name is not longer than MAXNAMLEN   *      name is not longer than FFS_MAXNAMLEN
  *      name must be as long as advertised, and null terminated   *      name must be as long as advertised, and null terminated
  */   */
 int  int
 ufs_dirbadentry(dp, ep, entryoffsetinblock)  ufs_dirbadentry(struct vnode *dp, struct direct *ep, int entryoffsetinblock)
         struct vnode *dp;  
         struct direct *ep;  
         int entryoffsetinblock;  
 {  {
         int i;          int i;
         int namlen;          int namlen;
Line 698  ufs_dirbadentry(dp, ep, entryoffsetinblo
Line 690  ufs_dirbadentry(dp, ep, entryoffsetinblo
                 dirblksiz - (entryoffsetinblock & (dirblksiz - 1)) ||                  dirblksiz - (entryoffsetinblock & (dirblksiz - 1)) ||
             ufs_rw16(ep->d_reclen, needswap) <              ufs_rw16(ep->d_reclen, needswap) <
                 DIRSIZ(FSFMT(dp), ep, needswap) ||                  DIRSIZ(FSFMT(dp), ep, needswap) ||
             namlen > MAXNAMLEN) {              namlen > FFS_MAXNAMLEN) {
                 /*return (1); */                  /*return (1); */
                 printf("First bad, reclen=%x, DIRSIZ=%lu, namlen=%d, flags=%x "                  printf("First bad, reclen=%#x, DIRSIZ=%lu, namlen=%d, "
                         "entryoffsetinblock=%d, dirblksiz = %d\n",                          "flags=%#x, entryoffsetinblock=%d, dirblksiz = %d\n",
                         ufs_rw16(ep->d_reclen, needswap),                          ufs_rw16(ep->d_reclen, needswap),
                         (u_long)DIRSIZ(FSFMT(dp), ep, needswap),                          (u_long)DIRSIZ(FSFMT(dp), ep, needswap),
                         namlen, dp->v_mount->mnt_flag, entryoffsetinblock,dirblksiz);                          namlen, dp->v_mount->mnt_flag, entryoffsetinblock,
                           dirblksiz);
                 goto bad;                  goto bad;
         }          }
         if (ep->d_ino == 0)          if (ep->d_ino == 0)
Line 728  bad:
Line 721  bad:
  * argument ip is the inode to which the new directory entry will refer.   * argument ip is the inode to which the new directory entry will refer.
  */   */
 void  void
 ufs_makedirentry(ip, cnp, newdirp)  ufs_makedirentry(struct inode *ip, struct componentname *cnp,
         struct inode *ip;      struct direct *newdirp)
         struct componentname *cnp;  
         struct direct *newdirp;  
 {  {
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
         if ((cnp->cn_flags & SAVENAME) == 0)          if ((cnp->cn_flags & SAVENAME) == 0)
Line 757  ufs_makedirentry(ip, cnp, newdirp)
Line 748  ufs_makedirentry(ip, cnp, newdirp)
  * soft dependency code).   * soft dependency code).
  */   */
 int  int
 ufs_direnter(dvp, tvp, dirp, cnp, newdirbp)  ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,
         struct vnode *dvp;      struct componentname *cnp, struct buf *newdirbp)
         struct vnode *tvp;  
         struct direct *dirp;  
         struct componentname *cnp;  
         struct buf *newdirbp;  
 {  {
         struct ucred *cr;          kauth_cred_t cr;
         struct lwp *l;          struct lwp *l;
         int newentrysize;          int newentrysize;
         struct inode *dp;          struct inode *dp;
         struct buf *bp;          struct buf *bp;
         u_int dsize;          u_int dsize;
         struct direct *ep, *nep;          struct direct *ep, *nep;
         int error, ret, blkoff, loc, spacefree, flags;          int error, ret, blkoff, loc, spacefree;
         char *dirbuf;          char *dirbuf;
         struct timespec ts;          struct timespec ts;
         struct ufsmount *ump = VFSTOUFS(dvp->v_mount);          struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
         const int needswap = UFS_MPNEEDSWAP(ump);          const int needswap = UFS_MPNEEDSWAP(ump);
         int dirblksiz = ump->um_dirblksiz;          int dirblksiz = ump->um_dirblksiz;
   
           UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
   
         error = 0;          error = 0;
         cr = cnp->cn_cred;          cr = cnp->cn_cred;
         l = cnp->cn_lwp;          l = curlwp;
   
         dp = VTOI(dvp);          dp = VTOI(dvp);
         newentrysize = DIRSIZ(0, dirp, 0);          newentrysize = DIRSIZ(0, dirp, 0);
Line 794  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 783  ufs_direnter(dvp, tvp, dirp, cnp, newdir
                  */                   */
                 if (dp->i_offset & (dirblksiz - 1))                  if (dp->i_offset & (dirblksiz - 1))
                         panic("ufs_direnter: newblk");                          panic("ufs_direnter: newblk");
                 flags = B_CLRBUF;                  if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, dirblksiz,
                 if (!DOINGSOFTDEP(dvp))                      cr, B_CLRBUF | B_SYNC, &bp)) != 0) {
                         flags |= B_SYNC;  
                 if ((error = VOP_BALLOC(dvp, (off_t)dp->i_offset, dirblksiz,  
                     cr, flags, &bp)) != 0) {  
                         if (DOINGSOFTDEP(dvp) && newdirbp != NULL)  
                                 bdwrite(newdirbp);  
                         return (error);                          return (error);
                 }                  }
                 dp->i_size = dp->i_offset + dirblksiz;                  dp->i_size = dp->i_offset + dirblksiz;
Line 821  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 805  ufs_direnter(dvp, tvp, dirp, cnp, newdir
                         }                          }
                 }                  }
                 blkoff = dp->i_offset & (ump->um_mountp->mnt_stat.f_iosize - 1);                  blkoff = dp->i_offset & (ump->um_mountp->mnt_stat.f_iosize - 1);
                 memcpy((caddr_t)bp->b_data + blkoff, (caddr_t)dirp,                  memcpy((char *)bp->b_data + blkoff, dirp, newentrysize);
                     newentrysize);  
 #ifdef UFS_DIRHASH  #ifdef UFS_DIRHASH
                 if (dp->i_dirhash != NULL) {                  if (dp->i_dirhash != NULL) {
                         ufsdirhash_newblk(dp, dp->i_offset);                          ufsdirhash_newblk(dp, dp->i_offset);
Line 831  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 814  ufs_direnter(dvp, tvp, dirp, cnp, newdir
                             dp->i_offset);                              dp->i_offset);
                 }                  }
 #endif  #endif
                 if (DOINGSOFTDEP(dvp)) {                  error = VOP_BWRITE(bp);
                         /*                  vfs_timestamp(&ts);
                          * Ensure that the entire newly allocated block is a                  ret = UFS_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);
                          * valid directory so that future growth within the  
                          * block does not have to ensure that the block is  
                          * written before the inode.  
                          */  
                         blkoff += dirblksiz;  
                         while (blkoff < bp->b_bcount) {  
                                 ((struct direct *)  
                                    (bp->b_data + blkoff))->d_reclen = dirblksiz;  
                                 blkoff += dirblksiz;  
                         }  
                         if (softdep_setup_directory_add(bp, dp, dp->i_offset,  
                             ufs_rw32(dirp->d_ino, needswap), newdirbp, 1) == 0) {  
                                 bdwrite(bp);  
                                 TIMEVAL_TO_TIMESPEC(&time, &ts);  
                                 return VOP_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);  
                         }  
                         /* We have just allocated a directory block in an  
                          * indirect block. Rather than tracking when it gets  
                          * claimed by the inode, we simply do a VOP_FSYNC  
                          * now to ensure that it is there (in case the user  
                          * does a future fsync). Note that we have to unlock  
                          * the inode for the entry that we just entered, as  
                          * the VOP_FSYNC may need to lock other inodes which  
                          * can lead to deadlock if we also hold a lock on  
                          * the newly entered node.  
                          */  
                         error = VOP_BWRITE(bp);  
                         if (error != 0)  
                                 return (error);  
                         if (tvp != NULL)  
                                 VOP_UNLOCK(tvp, 0);  
                         error = VOP_FSYNC(dvp, l->l_proc->p_ucred, FSYNC_WAIT, 0, 0, l);  
                         if (tvp != 0)  
                                 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);  
                         return (error);  
                 } else {  
                         error = VOP_BWRITE(bp);  
                 }  
                 TIMEVAL_TO_TIMESPEC(&time, &ts);  
                 ret = VOP_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);  
                 if (error == 0)                  if (error == 0)
                         return (ret);                          return (ret);
                 return (error);                  return (error);
Line 891  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 834  ufs_direnter(dvp, tvp, dirp, cnp, newdir
         /*          /*
          * Increase size of directory if entry eats into new space.           * Increase size of directory if entry eats into new space.
          * This should never push the size past a new multiple of           * This should never push the size past a new multiple of
          * DIRBLKSIZE.           * DIRBLKSIZ.
          *           *
          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.           * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
          */           */
Line 899  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 842  ufs_direnter(dvp, tvp, dirp, cnp, newdir
                 dp->i_size = dp->i_offset + dp->i_count;                  dp->i_size = dp->i_offset + dp->i_count;
                 DIP_ASSIGN(dp, size, dp->i_size);                  DIP_ASSIGN(dp, size, dp->i_size);
                 dp->i_flag |= IN_CHANGE | IN_UPDATE;                  dp->i_flag |= IN_CHANGE | IN_UPDATE;
                   UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
         }          }
         /*          /*
          * Get the block containing the space for the new directory entry.           * Get the block containing the space for the new directory entry.
          */           */
         error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp);          error = ufs_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, &bp, true);
         if (error) {          if (error) {
                 if (DOINGSOFTDEP(dvp) && newdirbp != NULL)  
                         bdwrite(newdirbp);  
                 return (error);                  return (error);
         }          }
         /*          /*
Line 916  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 858  ufs_direnter(dvp, tvp, dirp, cnp, newdir
          * dp->i_offset + dp->i_count would yield the space.           * dp->i_offset + dp->i_count would yield the space.
          */           */
         ep = (struct direct *)dirbuf;          ep = (struct direct *)dirbuf;
         dsize = DIRSIZ(FSFMT(dvp), ep, needswap);          dsize = (ep->d_ino != 0) ?  DIRSIZ(FSFMT(dvp), ep, needswap) : 0;
         spacefree = ufs_rw16(ep->d_reclen, needswap) - dsize;          spacefree = ufs_rw16(ep->d_reclen, needswap) - dsize;
         for (loc = ufs_rw16(ep->d_reclen, needswap); loc < dp->i_count; ) {          for (loc = ufs_rw16(ep->d_reclen, needswap); loc < dp->i_count; ) {
                   uint16_t reclen;
   
                 nep = (struct direct *)(dirbuf + loc);                  nep = (struct direct *)(dirbuf + loc);
                 if (ep->d_ino) {  
                         /* trim the existing slot */                  /* Trim the existing slot (NB: dsize may be zero). */
                         ep->d_reclen = ufs_rw16(dsize, needswap);                  ep->d_reclen = ufs_rw16(dsize, needswap);
                         ep = (struct direct *)((char *)ep + dsize);                  ep = (struct direct *)((char *)ep + dsize);
                 } else {  
                         /* overwrite; nothing there; header is ours */                  reclen = ufs_rw16(nep->d_reclen, needswap);
                         spacefree += dsize;                  loc += reclen;
                   if (nep->d_ino == 0) {
                           /*
                            * A mid-block unused entry. Such entries are
                            * never created by the kernel, but fsck_ffs
                            * can create them (and it doesn't fix them).
                            *
                            * Add up the free space, and initialise the
                            * relocated entry since we don't memcpy it.
                            */
                           spacefree += reclen;
                           ep->d_ino = 0;
                           dsize = 0;
                           continue;
                 }                  }
                 dsize = DIRSIZ(FSFMT(dvp), nep, needswap);                  dsize = DIRSIZ(FSFMT(dvp), nep, needswap);
                 spacefree += ufs_rw16(nep->d_reclen, needswap) - dsize;                  spacefree += reclen - dsize;
                 loc += ufs_rw16(nep->d_reclen, needswap);  
 #ifdef UFS_DIRHASH  #ifdef UFS_DIRHASH
                 if (dp->i_dirhash != NULL)                  if (dp->i_dirhash != NULL)
                         ufsdirhash_move(dp, nep,                          ufsdirhash_move(dp, nep,
                             dp->i_offset + ((char *)nep - dirbuf),                              dp->i_offset + ((char *)nep - dirbuf),
                             dp->i_offset + ((char *)ep - dirbuf));                              dp->i_offset + ((char *)ep - dirbuf));
 #endif  #endif
                 if (DOINGSOFTDEP(dvp))                  memcpy((void *)ep, (void *)nep, dsize);
                         softdep_change_directoryentry_offset(dp, dirbuf,  
                             (caddr_t)nep, (caddr_t)ep, dsize);  
                 else  
                         memcpy((caddr_t)ep, (caddr_t)nep, dsize);  
         }          }
         /*          /*
            * Here, `ep' points to a directory entry containing `dsize' in-use
            * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0,
            * then the entry is completely unused (dsize == 0). The value
            * of ep->d_reclen is always indeterminate.
            *
          * Update the pointer fields in the previous entry (if any),           * Update the pointer fields in the previous entry (if any),
          * copy in the new entry, and write out the block.           * copy in the new entry, and write out the block.
          */           */
Line 978  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 935  ufs_direnter(dvp, tvp, dirp, cnp, newdir
             dirp->d_reclen == spacefree))              dirp->d_reclen == spacefree))
                 ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf));                  ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf));
 #endif  #endif
         memcpy((caddr_t)ep, (caddr_t)dirp, (u_int)newentrysize);          memcpy((void *)ep, (void *)dirp, (u_int)newentrysize);
 #ifdef UFS_DIRHASH  #ifdef UFS_DIRHASH
         if (dp->i_dirhash != NULL)          if (dp->i_dirhash != NULL)
                 ufsdirhash_checkblock(dp, dirbuf -                  ufsdirhash_checkblock(dp, dirbuf -
                     (dp->i_offset & (dirblksiz - 1)),                      (dp->i_offset & (dirblksiz - 1)),
                     dp->i_offset & ~(dirblksiz - 1));                      dp->i_offset & ~(dirblksiz - 1));
 #endif  #endif
         if (DOINGSOFTDEP(dvp)) {          error = VOP_BWRITE(bp);
                 softdep_setup_directory_add(bp, dp,  
                     dp->i_offset + (caddr_t)ep - dirbuf,  
                         ufs_rw32(dirp->d_ino, needswap), newdirbp, 0);  
                 bdwrite(bp);  
         } else {  
                 error = VOP_BWRITE(bp);  
         }  
         dp->i_flag |= IN_CHANGE | IN_UPDATE;          dp->i_flag |= IN_CHANGE | IN_UPDATE;
         /*          /*
          * If all went well, and the directory can be shortened, proceed           * If all went well, and the directory can be shortened, proceed
Line 1002  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 952  ufs_direnter(dvp, tvp, dirp, cnp, newdir
          * lock on the newly entered node.           * lock on the newly entered node.
          */           */
         if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) {          if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) {
                 if (DOINGSOFTDEP(dvp) && (tvp != NULL))  
                         VOP_UNLOCK(tvp, 0);  
 #ifdef UFS_DIRHASH  #ifdef UFS_DIRHASH
                 if (dp->i_dirhash != NULL)                  if (dp->i_dirhash != NULL)
                         ufsdirhash_dirtrunc(dp, dp->i_endoff);                          ufsdirhash_dirtrunc(dp, dp->i_endoff);
 #endif  #endif
                 (void) VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, l);                  (void) UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr);
                 if (DOINGSOFTDEP(dvp) && (tvp != NULL))  
                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);  
         }          }
           UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
         return (error);          return (error);
 }  }
   
Line 1028  ufs_direnter(dvp, tvp, dirp, cnp, newdir
Line 975  ufs_direnter(dvp, tvp, dirp, cnp, newdir
  * to the size of the previous entry.   * to the size of the previous entry.
  */   */
 int  int
 ufs_dirremove(dvp, ip, flags, isrmdir)  ufs_dirremove(struct vnode *dvp, struct inode *ip, int flags, int isrmdir)
         struct vnode *dvp;  
         struct inode *ip;  
         int flags;  
         int isrmdir;  
 {  {
         struct inode *dp = VTOI(dvp);          struct inode *dp = VTOI(dvp);
         struct direct *ep;          struct direct *ep;
Line 1042  ufs_dirremove(dvp, ip, flags, isrmdir)
Line 985  ufs_dirremove(dvp, ip, flags, isrmdir)
         const int needswap = UFS_MPNEEDSWAP(dp->i_ump);          const int needswap = UFS_MPNEEDSWAP(dp->i_ump);
 #endif  #endif
   
           UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
   
         if (flags & DOWHITEOUT) {          if (flags & DOWHITEOUT) {
                 /*                  /*
                  * Whiteout entry: set d_ino to WINO.                   * Whiteout entry: set d_ino to WINO.
                  */                   */
                 error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (void *)&ep,                  error = ufs_blkatoff(dvp, (off_t)dp->i_offset, (void *)&ep,
                                      &bp);                                       &bp, true);
                 if (error)                  if (error)
                         return (error);                          return (error);
                 ep->d_ino = ufs_rw32(WINO, needswap);                  ep->d_ino = ufs_rw32(WINO, needswap);
Line 1055  ufs_dirremove(dvp, ip, flags, isrmdir)
Line 1000  ufs_dirremove(dvp, ip, flags, isrmdir)
                 goto out;                  goto out;
         }          }
   
         if ((error = VOP_BLKATOFF(dvp,          if ((error = ufs_blkatoff(dvp,
             (off_t)(dp->i_offset - dp->i_count), (void *)&ep, &bp)) != 0)              (off_t)(dp->i_offset - dp->i_count), (void *)&ep, &bp, true)) != 0)
                 return (error);                  return (error);
   
 #ifdef UFS_DIRHASH  #ifdef UFS_DIRHASH
Line 1066  ufs_dirremove(dvp, ip, flags, isrmdir)
Line 1011  ufs_dirremove(dvp, ip, flags, isrmdir)
          */           */
         if (dp->i_dirhash != NULL)          if (dp->i_dirhash != NULL)
                 ufsdirhash_remove(dp, (dp->i_count == 0) ? ep :                  ufsdirhash_remove(dp, (dp->i_count == 0) ? ep :
                    (struct direct *)((char *)ep + ep->d_reclen), dp->i_offset);                     (struct direct *)((char *)ep +
                      ufs_rw16(ep->d_reclen, needswap)), dp->i_offset);
 #endif  #endif
   
         if (dp->i_count == 0) {          if (dp->i_count == 0) {
Line 1093  ufs_dirremove(dvp, ip, flags, isrmdir)
Line 1039  ufs_dirremove(dvp, ip, flags, isrmdir)
 #endif  #endif
   
 out:  out:
         if (DOINGSOFTDEP(dvp)) {          if (ip) {
                 if (ip) {                  ip->i_nlink--;
                         ip->i_ffs_effnlink--;                  DIP_ASSIGN(ip, nlink, ip->i_nlink);
                         softdep_change_linkcnt(ip);                  ip->i_flag |= IN_CHANGE;
                         softdep_setup_remove(bp, dp, ip, isrmdir);                  UFS_WAPBL_UPDATE(ITOV(ip), NULL, NULL, 0);
                 }  
                 bdwrite(bp);  
         } else {  
                 if (ip) {  
                         ip->i_ffs_effnlink--;  
                         ip->i_nlink--;  
                         DIP_ASSIGN(ip, nlink, ip->i_nlink);  
                         ip->i_flag |= IN_CHANGE;  
                 }  
                 error = VOP_BWRITE(bp);  
         }          }
           error = VOP_BWRITE(bp);
         dp->i_flag |= IN_CHANGE | IN_UPDATE;          dp->i_flag |= IN_CHANGE | IN_UPDATE;
   #ifdef FFS
         /*          /*
          * If the last named reference to a snapshot goes away,           * If the last named reference to a snapshot goes away,
          * drop its snapshot reference so that it will be reclaimed           * drop its snapshot reference so that it will be reclaimed
          * when last open reference goes away.           * when last open reference goes away.
          */           */
         if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 &&          if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 &&
             ip->i_ffs_effnlink == 0)              ip->i_nlink == 0)
                 ffs_snapgone(ip);                  ffs_snapgone(ip);
           UFS_WAPBL_UPDATE(dvp, NULL, NULL, 0);
   #endif
         return (error);          return (error);
 }  }
   
Line 1127  out:
Line 1067  out:
  * set up by a call to namei.   * set up by a call to namei.
  */   */
 int  int
 ufs_dirrewrite(dp, oip, newinum, newtype, isrmdir, iflags)  ufs_dirrewrite(struct inode *dp, struct inode *oip, ino_t newinum, int newtype,
         struct inode *dp, *oip;      int isrmdir, int iflags)
         ino_t newinum;  
         int newtype;  
         int isrmdir;  
         int iflags;  
 {  {
         struct buf *bp;          struct buf *bp;
         struct direct *ep;          struct direct *ep;
         struct vnode *vdp = ITOV(dp);          struct vnode *vdp = ITOV(dp);
         int error;          int error;
   
         error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (void *)&ep, &bp);          error = ufs_blkatoff(vdp, (off_t)dp->i_offset, (void *)&ep, &bp, true);
         if (error)          if (error)
                 return (error);                  return (error);
         ep->d_ino = ufs_rw32(newinum, UFS_MPNEEDSWAP(dp->i_ump));          ep->d_ino = ufs_rw32(newinum, UFS_MPNEEDSWAP(dp->i_ump));
         if (!FSFMT(vdp))          if (!FSFMT(vdp))
                 ep->d_type = newtype;                  ep->d_type = newtype;
         oip->i_ffs_effnlink--;          oip->i_nlink--;
         if (DOINGSOFTDEP(vdp)) {          DIP_ASSIGN(oip, nlink, oip->i_nlink);
                 softdep_change_linkcnt(oip);          oip->i_flag |= IN_CHANGE;
                 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir);          UFS_WAPBL_UPDATE(ITOV(oip), NULL, NULL, UPDATE_DIROP);
                 bdwrite(bp);          error = VOP_BWRITE(bp);
         } else {  
                 oip->i_nlink--;  
                 DIP_ASSIGN(oip, nlink, oip->i_nlink);  
                 oip->i_flag |= IN_CHANGE;  
                 error = VOP_BWRITE(bp);  
         }  
         dp->i_flag |= iflags;          dp->i_flag |= iflags;
   #ifdef FFS
         /*          /*
          * If the last named reference to a snapshot goes away,           * If the last named reference to a snapshot goes away,
          * drop its snapshot reference so that it will be reclaimed           * drop its snapshot reference so that it will be reclaimed
          * when last open reference goes away.           * when last open reference goes away.
          */           */
         if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_ffs_effnlink == 0)          if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_nlink == 0)
                 ffs_snapgone(oip);                  ffs_snapgone(oip);
           UFS_WAPBL_UPDATE(vdp, NULL, NULL, UPDATE_DIROP);
   #endif
         return (error);          return (error);
 }  }
   
Line 1177  ufs_dirrewrite(dp, oip, newinum, newtype
Line 1110  ufs_dirrewrite(dp, oip, newinum, newtype
  * NB: does not handle corrupted directories.   * NB: does not handle corrupted directories.
  */   */
 int  int
 ufs_dirempty(ip, parentino, cred)  ufs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred)
         struct inode *ip;  
         ino_t parentino;  
         struct ucred *cred;  
 {  {
         doff_t off;          doff_t off;
         struct dirtemplate dbuf;          struct dirtemplate dbuf;
Line 1192  ufs_dirempty(ip, parentino, cred)
Line 1122  ufs_dirempty(ip, parentino, cred)
   
         for (off = 0; off < ip->i_size;          for (off = 0; off < ip->i_size;
             off += ufs_rw16(dp->d_reclen, needswap)) {              off += ufs_rw16(dp->d_reclen, needswap)) {
                 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,                  error = vn_rdwr(UIO_READ, ITOV(ip), (void *)dp, MINDIRSIZ, off,
                    UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);                     UIO_SYSSPACE, IO_NODELOCKED, cred, &count, NULL);
                 /*                  /*
                  * Since we read MINDIRSIZ, residual must                   * Since we read MINDIRSIZ, residual must
Line 1244  ufs_dirempty(ip, parentino, cred)
Line 1174  ufs_dirempty(ip, parentino, cred)
  * The target is always vput before returning.   * The target is always vput before returning.
  */   */
 int  int
 ufs_checkpath(source, target, cred)  ufs_checkpath(struct inode *source, struct inode *target, kauth_cred_t cred)
         struct inode *source, *target;  
         struct ucred *cred;  
 {  {
         struct vnode *vp = ITOV(target);          struct vnode *vp = ITOV(target);
         int error, rootino, namlen;          int error, rootino, namlen;
Line 1268  ufs_checkpath(source, target, cred)
Line 1196  ufs_checkpath(source, target, cred)
                         error = ENOTDIR;                          error = ENOTDIR;
                         break;                          break;
                 }                  }
                 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,                  error = vn_rdwr(UIO_READ, vp, (void *)&dirbuf,
                     sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,                      sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
                     IO_NODELOCKED, cred, NULL, NULL);                      IO_NODELOCKED, cred, NULL, NULL);
                 if (error != 0)                  if (error != 0)
Line 1312  out:
Line 1240  out:
                 vput(vp);                  vput(vp);
         return (error);          return (error);
 }  }
   
   #define UFS_DIRRABLKS 0
   int ufs_dirrablks = UFS_DIRRABLKS;
   
   /*
    * ufs_blkatoff: Return buffer with the contents of block "offset" from
    * the beginning of directory "vp".  If "res" is non-zero, fill it in with
    * a pointer to the remaining space in the directory.  If the caller intends
    * to modify the buffer returned, "modify" must be true.
    */
   
   int
   ufs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp,
       bool modify)
   {
           struct inode *ip;
           struct buf *bp;
           daddr_t lbn;
           const int dirrablks = ufs_dirrablks;
           daddr_t *blks;
           int *blksizes;
           int run, error;
           struct mount *mp = vp->v_mount;
           const int bshift = mp->mnt_fs_bshift;
           const int bsize = 1 << bshift;
           off_t eof;
   
           blks = kmem_alloc((1 + dirrablks) * sizeof(daddr_t), KM_SLEEP);
           blksizes = kmem_alloc((1 + dirrablks) * sizeof(int), KM_SLEEP);
           ip = VTOI(vp);
           KASSERT(vp->v_size == ip->i_size);
           GOP_SIZE(vp, vp->v_size, &eof, 0);
           lbn = offset >> bshift;
   
           for (run = 0; run <= dirrablks;) {
                   const off_t curoff = lbn << bshift;
                   const int size = MIN(eof - curoff, bsize);
   
                   if (size == 0) {
                           break;
                   }
                   KASSERT(curoff < eof);
                   blks[run] = lbn;
                   blksizes[run] = size;
                   lbn++;
                   run++;
                   if (size != bsize) {
                           break;
                   }
           }
           KASSERT(run >= 1);
           error = breadn(vp, blks[0], blksizes[0], &blks[1], &blksizes[1],
               run - 1, NOCRED, (modify ? B_MODIFY : 0), &bp);
           if (error != 0) {
                   brelse(bp, 0);
                   *bpp = NULL;
                   goto out;
           }
           if (res) {
                   *res = (char *)bp->b_data + (offset & (bsize - 1));
           }
           *bpp = bp;
   
    out:
           kmem_free(blks, (1 + dirrablks) * sizeof(daddr_t));
           kmem_free(blksizes, (1 + dirrablks) * sizeof(int));
           return error;
   }

Legend:
Removed from v.1.47.2.8  
changed lines
  Added in v.1.99.2.2

CVSweb <webmaster@jp.NetBSD.org>