[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.63.2.7 and 1.64

version 1.63.2.7, 2008/01/21 09:48:16 version 1.64, 2005/07/10 00:18:52
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"  
 #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 52  __KERNEL_RCSID(0, "$NetBSD$");
Line 48  __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/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 66  __KERNEL_RCSID(0, "$NetBSD$");
Line 58  __KERNEL_RCSID(0, "$NetBSD$");
 #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 "fs_ffs.h"  
   
 #ifdef DIAGNOSTIC  #ifdef DIAGNOSTIC
 int     dirchk = 1;  int     dirchk = 1;
 #else  #else
 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 134  ufs_lookup(void *v)
Line 124  ufs_lookup(void *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;
         kauth_cred_t cred = cnp->cn_cred;          struct ucred *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 145  ufs_lookup(void *v)
Line 137  ufs_lookup(void *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)) != 0)          if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 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) &&
Line 168  ufs_lookup(void *v)
Line 163  ufs_lookup(void *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 248  ufs_lookup(void *v)
Line 240  ufs_lookup(void *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 = ufs_blkatoff(vdp, (off_t)dp->i_offset, NULL, &bp)))                      (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)))
                         goto out;                          return (error);
                 numdirpasses = 2;                  numdirpasses = 2;
                 nchstats.ncs_2passes++;                  nchstats.ncs_2passes++;
         }          }
Line 260  ufs_lookup(void *v)
Line 252  ufs_lookup(void *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();                          preempt(1);
                 /*                  /*
                  * 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, 0);                                  brelse(bp);
                         error = ufs_blkatoff(vdp, (off_t)dp->i_offset, NULL,                          error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL,
                             &bp);                              &bp);
                         if (error)                          if (error)
                                 goto out;                                  return (error);
                         entryoffsetinblock = 0;                          entryoffsetinblock = 0;
                 }                  }
                 /*                  /*
                  * If still looking for a slot, and at a DIRBLKSIZ                   * If still looking for a slot, and at a DIRBLKSIZE
                  * 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 289  searchloop:
Line 281  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 410  notfound:
Line 401  notfound:
                 goto searchloop;                  goto searchloop;
         }          }
         if (bp != NULL)          if (bp != NULL)
                 brelse(bp, 0);                  brelse(bp);
         /*          /*
          * 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 425  notfound:
Line 416  notfound:
                  * 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);                  error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                 if (error)                  if (error)
                         goto out;                          return (error);
                 /*                  /*
                  * 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 471  notfound:
Line 462  notfound:
                  * information cannot be used.                   * information cannot be used.
                  */                   */
                 cnp->cn_flags |= SAVENAME;                  cnp->cn_flags |= SAVENAME;
                 error = EJUSTRETURN;                  if (!lockparent) {
                 goto out;                          VOP_UNLOCK(vdp, 0);
                           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);
         error = ENOENT;          return (ENOENT);
         goto out;  
   
 found:  found:
         if (numdirpasses == 2)          if (numdirpasses == 2)
Line 495  found:
Line 488  found:
                 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;
         }          }
         brelse(bp, 0);          brelse(bp);
   
         /*          /*
          * Found component in pathname.           * Found component in pathname.
Line 508  found:
Line 501  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.
          * Lock the inode, being careful with ".".           * If the wantparent flag isn't set, we return only
            * 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);                  error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                 if (error)                  if (error)
                         goto out;                          return (error);
                 /*                  /*
                  * 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 530  found:
Line 525  found:
                 if (dp->i_number == foundino) {                  if (dp->i_number == foundino) {
                         VREF(vdp);                          VREF(vdp);
                         *vpp = vdp;                          *vpp = vdp;
                         error = 0;                          return (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 539  found:
Line 533  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)
                         goto out;                          return (error);
                 /*                  /*
                  * 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 547  found:
Line 541  found:
                  * implements append-only directories.                   * implements append-only directories.
                  */                   */
                 if ((dp->i_mode & ISVTX) &&                  if ((dp->i_mode & ISVTX) &&
                     kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,                      cred->cr_uid != 0 &&
                      NULL) != 0 &&                      cred->cr_uid != dp->i_uid &&
                     kauth_cred_geteuid(cred) != dp->i_uid &&                      VTOI(tdp)->i_uid != cred->cr_uid) {
                     VTOI(tdp)->i_uid != kauth_cred_geteuid(cred)) {  
                         vput(tdp);                          vput(tdp);
                         error = EPERM;                          return (EPERM);
                         goto out;  
                 }                  }
                 *vpp = tdp;                  *vpp = tdp;
                 error = 0;                  if (!lockparent) {
                 goto out;                          VOP_UNLOCK(vdp, 0);
                           cnp->cn_flags |= PDIRUNLOCK;
                   }
                   return (0);
         }          }
   
         /*          /*
Line 566  found:
Line 561  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 && (flags & ISLASTCN)) {          if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
                 error = VOP_ACCESS(vdp, VWRITE, cred);                  error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
                 if (error)                  if (error)
                         goto out;                          return (error);
                 /*                  /*
                  * 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)
                         error = EISDIR;                          return (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)
                         goto out;                          return (error);
                 *vpp = tdp;                  *vpp = tdp;
                 cnp->cn_flags |= SAVENAME;                  cnp->cn_flags |= SAVENAME;
                 error = 0;                  if (!lockparent) {
                 goto out;                          VOP_UNLOCK(vdp, 0);
                           cnp->cn_flags |= PDIRUNLOCK;
                   }
                   return (0);
         }          }
   
         /*          /*
Line 613  found:
Line 609  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) {
                         goto out;                          if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
                                   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 625  found:
Line 630  found:
         } else {          } else {
                 error = VFS_VGET(vdp->v_mount, foundino, &tdp);                  error = VFS_VGET(vdp->v_mount, foundino, &tdp);
                 if (error)                  if (error)
                         goto out;                          return (error);
                   if (!lockparent || !(flags & ISLASTCN)) {
                           VOP_UNLOCK(pdp, 0);
                           cnp->cn_flags |= PDIRUNLOCK;
                   }
                 *vpp = tdp;                  *vpp = tdp;
         }          }
   
Line 634  found:
Line 643  found:
          */           */
         if (cnp->cn_flags & MAKEENTRY)          if (cnp->cn_flags & MAKEENTRY)
                 cache_enter(vdp, *vpp, cnp);                  cache_enter(vdp, *vpp, cnp);
         error = 0;          return (0);
   
 out:  
         fstrans_done(vdp->v_mount);  
         return error;  
 }  }
   
 void  void
Line 647  ufs_dirbad(struct inode *ip, doff_t offs
Line 652  ufs_dirbad(struct inode *ip, doff_t offs
         struct mount *mp;          struct mount *mp;
   
         mp = ITOV(ip)->v_mount;          mp = ITOV(ip)->v_mount;
         printf("%s: bad dir ino %llu at offset %d: %s\n",          printf("%s: bad dir ino %d at offset %d: %s\n",
             mp->mnt_stat.f_mntonname, (unsigned long long)ip->i_number,              mp->mnt_stat.f_mntonname, ip->i_number, offset, how);
             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 659  ufs_dirbad(struct inode *ip, doff_t offs
Line 663  ufs_dirbad(struct inode *ip, doff_t offs
  *      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 FFS_MAXNAMLEN   *      name is not longer than MAXNAMLEN
  *      name must be as long as advertised, and null terminated   *      name must be as long as advertised, and null terminated
  */   */
 int  int
Line 687  ufs_dirbadentry(struct vnode *dp, struct
Line 691  ufs_dirbadentry(struct vnode *dp, struct
                 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 > FFS_MAXNAMLEN) {              namlen > 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, flags=%x "
                         "entryoffsetinblock=%d, dirblksiz = %d\n",                          "entryoffsetinblock=%d, dirblksiz = %d\n",
Line 747  int
Line 751  int
 ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,  ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,
     struct componentname *cnp, struct buf *newdirbp)      struct componentname *cnp, struct buf *newdirbp)
 {  {
         kauth_cred_t cr;          struct ucred *cr;
         struct lwp *l;          struct proc *p;
         int newentrysize;          int newentrysize;
         struct inode *dp;          struct inode *dp;
         struct buf *bp;          struct buf *bp;
Line 763  ufs_direnter(struct vnode *dvp, struct v
Line 767  ufs_direnter(struct vnode *dvp, struct v
   
         error = 0;          error = 0;
         cr = cnp->cn_cred;          cr = cnp->cn_cred;
         l = curlwp;          p = cnp->cn_proc;
   
         dp = VTOI(dvp);          dp = VTOI(dvp);
         newentrysize = DIRSIZ(0, dirp, 0);          newentrysize = DIRSIZ(0, dirp, 0);
Line 780  ufs_direnter(struct vnode *dvp, struct v
Line 784  ufs_direnter(struct vnode *dvp, struct v
                 flags = B_CLRBUF;                  flags = B_CLRBUF;
                 if (!DOINGSOFTDEP(dvp))                  if (!DOINGSOFTDEP(dvp))
                         flags |= B_SYNC;                          flags |= B_SYNC;
                 if ((error = UFS_BALLOC(dvp, (off_t)dp->i_offset, dirblksiz,                  if ((error = VOP_BALLOC(dvp, (off_t)dp->i_offset, dirblksiz,
                     cr, flags, &bp)) != 0) {                      cr, flags, &bp)) != 0) {
                         if (DOINGSOFTDEP(dvp) && newdirbp != NULL)                          if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
                                 bdwrite(newdirbp);                                  bdwrite(newdirbp);
Line 804  ufs_direnter(struct vnode *dvp, struct v
Line 808  ufs_direnter(struct vnode *dvp, struct v
                         }                          }
                 }                  }
                 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((char *)bp->b_data + blkoff, dirp, newentrysize);                  memcpy((caddr_t)bp->b_data + blkoff, (caddr_t)dirp,
                       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 823  ufs_direnter(struct vnode *dvp, struct v
Line 828  ufs_direnter(struct vnode *dvp, struct v
                         blkoff += dirblksiz;                          blkoff += dirblksiz;
                         while (blkoff < bp->b_bcount) {                          while (blkoff < bp->b_bcount) {
                                 ((struct direct *)                                  ((struct direct *)
                                    ((char *)bp->b_data + blkoff))->d_reclen = dirblksiz;                                     (bp->b_data + blkoff))->d_reclen = dirblksiz;
                                 blkoff += dirblksiz;                                  blkoff += dirblksiz;
                         }                          }
                         if (softdep_setup_directory_add(bp, dp, dp->i_offset,                          if (softdep_setup_directory_add(bp, dp, dp->i_offset,
                             ufs_rw32(dirp->d_ino, needswap), newdirbp, 1) == 0) {                              ufs_rw32(dirp->d_ino, needswap), newdirbp, 1) == 0) {
                                 bdwrite(bp);                                  bdwrite(bp);
                                 vfs_timestamp(&ts);                                  TIMEVAL_TO_TIMESPEC(&time, &ts);
                                 return UFS_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);                                  return VOP_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);
                         }                          }
                         /* We have just allocated a directory block in an                          /* We have just allocated a directory block in an
                          * indirect block. Rather than tracking when it gets                           * indirect block. Rather than tracking when it gets
Line 847  ufs_direnter(struct vnode *dvp, struct v
Line 852  ufs_direnter(struct vnode *dvp, struct v
                                 return (error);                                  return (error);
                         if (tvp != NULL)                          if (tvp != NULL)
                                 VOP_UNLOCK(tvp, 0);                                  VOP_UNLOCK(tvp, 0);
                         error = VOP_FSYNC(dvp, l->l_cred, FSYNC_WAIT, 0, 0);                          error = VOP_FSYNC(dvp, p->p_ucred, FSYNC_WAIT, 0, 0, p);
                         if (tvp != 0)                          if (tvp != 0)
                                 vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);                                  vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
                         return (error);                          return (error);
                 } else {                  } else {
                         error = VOP_BWRITE(bp);                          error = VOP_BWRITE(bp);
                 }                  }
                 vfs_timestamp(&ts);                  TIMEVAL_TO_TIMESPEC(&time, &ts);
                 ret = UFS_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);                  ret = VOP_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);
                 if (error == 0)                  if (error == 0)
                         return (ret);                          return (ret);
                 return (error);                  return (error);
Line 873  ufs_direnter(struct vnode *dvp, struct v
Line 878  ufs_direnter(struct vnode *dvp, struct v
         /*          /*
          * 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
          * DIRBLKSIZ.           * DIRBLKSIZE.
          *           *
          * 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 885  ufs_direnter(struct vnode *dvp, struct v
Line 890  ufs_direnter(struct vnode *dvp, struct v
         /*          /*
          * Get the block containing the space for the new directory entry.           * Get the block containing the space for the new directory entry.
          */           */
         error = ufs_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, &bp);          error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp);
         if (error) {          if (error) {
                 if (DOINGSOFTDEP(dvp) && newdirbp != NULL)                  if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
                         bdwrite(newdirbp);                          bdwrite(newdirbp);
Line 898  ufs_direnter(struct vnode *dvp, struct v
Line 903  ufs_direnter(struct vnode *dvp, struct v
          * 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 = (ep->d_ino != 0) ?  DIRSIZ(FSFMT(dvp), ep, needswap) : 0;          dsize = DIRSIZ(FSFMT(dvp), ep, needswap);
         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 (NB: dsize may be zero). */                          /* trim the existing slot */
                 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 {
                 reclen = ufs_rw16(nep->d_reclen, needswap);                          /* overwrite; nothing there; header is ours */
                 loc += reclen;                          spacefree += dsize;
                 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 += reclen - dsize;                  spacefree += ufs_rw16(nep->d_reclen, needswap) - 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,
Line 935  ufs_direnter(struct vnode *dvp, struct v
Line 926  ufs_direnter(struct vnode *dvp, struct v
 #endif  #endif
                 if (DOINGSOFTDEP(dvp))                  if (DOINGSOFTDEP(dvp))
                         softdep_change_directoryentry_offset(dp, dirbuf,                          softdep_change_directoryentry_offset(dp, dirbuf,
                             (void *)nep, (void *)ep, dsize);                              (caddr_t)nep, (caddr_t)ep, dsize);
                 else                  else
                         memcpy((void *)ep, (void *)nep, dsize);                          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 979  ufs_direnter(struct vnode *dvp, struct v
Line 965  ufs_direnter(struct vnode *dvp, struct v
             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((void *)ep, (void *)dirp, (u_int)newentrysize);          memcpy((caddr_t)ep, (caddr_t)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 -
Line 988  ufs_direnter(struct vnode *dvp, struct v
Line 974  ufs_direnter(struct vnode *dvp, struct v
 #endif  #endif
         if (DOINGSOFTDEP(dvp)) {          if (DOINGSOFTDEP(dvp)) {
                 softdep_setup_directory_add(bp, dp,                  softdep_setup_directory_add(bp, dp,
                     dp->i_offset + (char *)ep - dirbuf,                      dp->i_offset + (caddr_t)ep - dirbuf,
                         ufs_rw32(dirp->d_ino, needswap), newdirbp, 0);                          ufs_rw32(dirp->d_ino, needswap), newdirbp, 0);
                 bdwrite(bp);                  bdwrite(bp);
         } else {          } else {
Line 1009  ufs_direnter(struct vnode *dvp, struct v
Line 995  ufs_direnter(struct vnode *dvp, struct v
                 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) UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr);                  (void) VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, cr, p);
                 if (DOINGSOFTDEP(dvp) && (tvp != NULL))                  if (DOINGSOFTDEP(dvp) && (tvp != NULL))
                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);                          vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
         }          }
Line 1043  ufs_dirremove(struct vnode *dvp, struct 
Line 1029  ufs_dirremove(struct vnode *dvp, struct 
                 /*                  /*
                  * Whiteout entry: set d_ino to WINO.                   * Whiteout entry: set d_ino to WINO.
                  */                   */
                 error = ufs_blkatoff(dvp, (off_t)dp->i_offset, (void *)&ep,                  error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (void *)&ep,
                                      &bp);                                       &bp);
                 if (error)                  if (error)
                         return (error);                          return (error);
Line 1052  ufs_dirremove(struct vnode *dvp, struct 
Line 1038  ufs_dirremove(struct vnode *dvp, struct 
                 goto out;                  goto out;
         }          }
   
         if ((error = ufs_blkatoff(dvp,          if ((error = VOP_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)) != 0)
                 return (error);                  return (error);
   
Line 1063  ufs_dirremove(struct vnode *dvp, struct 
Line 1049  ufs_dirremove(struct vnode *dvp, struct 
          */           */
         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 +                     (struct direct *)((char *)ep + ep->d_reclen), dp->i_offset);
                    ufs_rw16(ep->d_reclen, needswap)), dp->i_offset);  
 #endif  #endif
   
         if (dp->i_count == 0) {          if (dp->i_count == 0) {
Line 1108  out:
Line 1093  out:
                 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
Line 1117  out:
Line 1101  out:
         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_ffs_effnlink == 0)
                 ffs_snapgone(ip);                  ffs_snapgone(ip);
 #endif  
         return (error);          return (error);
 }  }
   
Line 1135  ufs_dirrewrite(struct inode *dp, struct 
Line 1118  ufs_dirrewrite(struct inode *dp, struct 
         struct vnode *vdp = ITOV(dp);          struct vnode *vdp = ITOV(dp);
         int error;          int error;
   
         error = ufs_blkatoff(vdp, (off_t)dp->i_offset, (void *)&ep, &bp);          error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (void *)&ep, &bp);
         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));
Line 1153  ufs_dirrewrite(struct inode *dp, struct 
Line 1136  ufs_dirrewrite(struct inode *dp, struct 
                 error = VOP_BWRITE(bp);                  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
Line 1161  ufs_dirrewrite(struct inode *dp, struct 
Line 1143  ufs_dirrewrite(struct inode *dp, struct 
          */           */
         if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_ffs_effnlink == 0)          if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_ffs_effnlink == 0)
                 ffs_snapgone(oip);                  ffs_snapgone(oip);
 #endif  
         return (error);          return (error);
 }  }
   
Line 1175  ufs_dirrewrite(struct inode *dp, struct 
Line 1156  ufs_dirrewrite(struct inode *dp, struct 
  * NB: does not handle corrupted directories.   * NB: does not handle corrupted directories.
  */   */
 int  int
 ufs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred)  ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
 {  {
         doff_t off;          doff_t off;
         struct dirtemplate dbuf;          struct dirtemplate dbuf;
Line 1187  ufs_dirempty(struct inode *ip, ino_t par
Line 1168  ufs_dirempty(struct inode *ip, ino_t par
   
         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), (void *)dp, MINDIRSIZ, off,                  error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)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 1239  ufs_dirempty(struct inode *ip, ino_t par
Line 1220  ufs_dirempty(struct inode *ip, ino_t par
  * The target is always vput before returning.   * The target is always vput before returning.
  */   */
 int  int
 ufs_checkpath(struct inode *source, struct inode *target, kauth_cred_t cred)  ufs_checkpath(struct inode *source, struct inode *target, struct ucred *cred)
 {  {
         struct vnode *vp = ITOV(target);          struct vnode *vp = ITOV(target);
         int error, rootino, namlen;          int error, rootino, namlen;
Line 1261  ufs_checkpath(struct inode *source, stru
Line 1242  ufs_checkpath(struct inode *source, stru
                         error = ENOTDIR;                          error = ENOTDIR;
                         break;                          break;
                 }                  }
                 error = vn_rdwr(UIO_READ, vp, (void *)&dirbuf,                  error = vn_rdwr(UIO_READ, vp, (caddr_t)&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 1305  out:
Line 1286  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.  
  */  
   
 int  
 ufs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)  
 {  
         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, &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.63.2.7  
changed lines
  Added in v.1.64

CVSweb <webmaster@jp.NetBSD.org>