[BACK]Return to tmpfs_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / tmpfs

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

Diff for /src/sys/fs/tmpfs/tmpfs_vnops.c between version 1.98.2.4 and 1.99

version 1.98.2.4, 2017/12/03 11:38:43 version 1.99, 2012/11/05 17:24:11
Line 49  __KERNEL_RCSID(0, "$NetBSD$");
Line 49  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/lockf.h>  #include <sys/lockf.h>
 #include <sys/kauth.h>  #include <sys/kauth.h>
 #include <sys/atomic.h>  
   
 #include <uvm/uvm.h>  #include <uvm/uvm.h>
   
Line 74  const struct vnodeopv_entry_desc tmpfs_v
Line 73  const struct vnodeopv_entry_desc tmpfs_v
         { &vop_setattr_desc,            tmpfs_setattr },          { &vop_setattr_desc,            tmpfs_setattr },
         { &vop_read_desc,               tmpfs_read },          { &vop_read_desc,               tmpfs_read },
         { &vop_write_desc,              tmpfs_write },          { &vop_write_desc,              tmpfs_write },
         { &vop_fallocate_desc,          genfs_eopnotsupp },  
         { &vop_fdiscard_desc,           genfs_eopnotsupp },  
         { &vop_ioctl_desc,              tmpfs_ioctl },          { &vop_ioctl_desc,              tmpfs_ioctl },
         { &vop_fcntl_desc,              tmpfs_fcntl },          { &vop_fcntl_desc,              tmpfs_fcntl },
         { &vop_poll_desc,               tmpfs_poll },          { &vop_poll_desc,               tmpfs_poll },
Line 126  const struct vnodeopv_desc tmpfs_vnodeop
Line 123  const struct vnodeopv_desc tmpfs_vnodeop
 int  int
 tmpfs_lookup(void *v)  tmpfs_lookup(void *v)
 {  {
         struct vop_lookup_v2_args /* {          struct vop_lookup_args /* {
                 struct vnode *a_dvp;                  struct vnode *a_dvp;
                 struct vnode **a_vpp;                  struct vnode **a_vpp;
                 struct componentname *a_cnp;                  struct componentname *a_cnp;
Line 164  tmpfs_lookup(void *v)
Line 161  tmpfs_lookup(void *v)
          * Avoid doing a linear scan of the directory if the requested           * Avoid doing a linear scan of the directory if the requested
          * directory/name couple is already in the cache.           * directory/name couple is already in the cache.
          */           */
         cachefound = cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,          cachefound = cache_lookup(dvp, cnp, &iswhiteout, vpp);
                                   cnp->cn_nameiop, cnp->cn_flags,  
                                   &iswhiteout, vpp);  
         if (iswhiteout) {          if (iswhiteout) {
                 cnp->cn_flags |= ISWHITEOUT;                  cnp->cn_flags |= ISWHITEOUT;
         }          }
Line 179  tmpfs_lookup(void *v)
Line 174  tmpfs_lookup(void *v)
                 goto out;                  goto out;
         }          }
   
         /*  
          * Treat an unlinked directory as empty (no "." or "..")  
          */  
         if (dnode->tn_links == 0) {  
                 KASSERT(dnode->tn_size == 0);  
                 error = ENOENT;  
                 goto out;  
         }  
   
         if (cnp->cn_flags & ISDOTDOT) {          if (cnp->cn_flags & ISDOTDOT) {
                 tmpfs_node_t *pnode;                  tmpfs_node_t *pnode;
   
Line 205  tmpfs_lookup(void *v)
Line 191  tmpfs_lookup(void *v)
                         goto out;                          goto out;
                 }                  }
   
                 error = vcache_get(dvp->v_mount, &pnode, sizeof(pnode), vpp);                  /*
                    * Lock the parent tn_vlock before releasing the vnode lock,
                    * and thus prevents parent from disappearing.
                    */
                   mutex_enter(&pnode->tn_vlock);
                   VOP_UNLOCK(dvp);
   
                   /*
                    * Get a vnode of the '..' entry and re-acquire the lock.
                    * Release the tn_vlock.
                    */
                   error = tmpfs_vnode_get(dvp->v_mount, pnode, vpp);
                   vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
                 goto out;                  goto out;
   
         } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {          } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
                 /*                  /*
                  * Lookup of "." case.                   * Lookup of "." case.
Line 279  tmpfs_lookup(void *v)
Line 278  tmpfs_lookup(void *v)
         }          }
   
         /* Get a vnode for the matching entry. */          /* Get a vnode for the matching entry. */
         error = vcache_get(dvp->v_mount, &tnode, sizeof(tnode), vpp);          mutex_enter(&tnode->tn_vlock);
           error = tmpfs_vnode_get(dvp->v_mount, tnode, vpp);
 done:  done:
         /*          /*
          * Cache the result, unless request was for creation (as it does           * Cache the result, unless request was for creation (as it does
          * not improve the performance).           * not improve the performance).
          */           */
         if (cnp->cn_nameiop != CREATE) {          if (cnp->cn_nameiop != CREATE) {
                 cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,                  cache_enter(dvp, *vpp, cnp);
                             cnp->cn_flags);  
         }          }
 out:  out:
           KASSERT((*vpp && VOP_ISLOCKED(*vpp)) || error);
         KASSERT(VOP_ISLOCKED(dvp));          KASSERT(VOP_ISLOCKED(dvp));
   
         return error;          return error;
Line 298  out:
Line 298  out:
 int  int
 tmpfs_create(void *v)  tmpfs_create(void *v)
 {  {
         struct vop_create_v3_args /* {          struct vop_create_args /* {
                 struct vnode            *a_dvp;                  struct vnode            *a_dvp;
                 struct vnode            **a_vpp;                  struct vnode            **a_vpp;
                 struct componentname    *a_cnp;                  struct componentname    *a_cnp;
Line 310  tmpfs_create(void *v)
Line 310  tmpfs_create(void *v)
   
         KASSERT(VOP_ISLOCKED(dvp));          KASSERT(VOP_ISLOCKED(dvp));
         KASSERT(vap->va_type == VREG || vap->va_type == VSOCK);          KASSERT(vap->va_type == VREG || vap->va_type == VSOCK);
         return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);          return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 }  }
   
 int  int
 tmpfs_mknod(void *v)  tmpfs_mknod(void *v)
 {  {
         struct vop_mknod_v3_args /* {          struct vop_mknod_args /* {
                 struct vnode            *a_dvp;                  struct vnode            *a_dvp;
                 struct vnode            **a_vpp;                  struct vnode            **a_vpp;
                 struct componentname    *a_cnp;                  struct componentname    *a_cnp;
Line 328  tmpfs_mknod(void *v)
Line 328  tmpfs_mknod(void *v)
         enum vtype vt = vap->va_type;          enum vtype vt = vap->va_type;
   
         if (vt != VBLK && vt != VCHR && vt != VFIFO) {          if (vt != VBLK && vt != VCHR && vt != VFIFO) {
                 *vpp = NULL;                  vput(dvp);
                 return EINVAL;                  return EINVAL;
         }          }
         return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);          return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 }  }
   
 int  int
Line 349  tmpfs_open(void *v)
Line 349  tmpfs_open(void *v)
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
   
         node = VP_TO_TMPFS_NODE(vp);          node = VP_TO_TMPFS_NODE(vp);
           if (node->tn_links < 1) {
                   /*
                    * The file is still active, but all its names have been
                    * removed (e.g. by a "rmdir $(pwd)").  It cannot be opened
                    * any more, as it is about to be destroyed.
                    */
                   return ENOENT;
           }
   
         /* If the file is marked append-only, deny write requests. */          /* If the file is marked append-only, deny write requests. */
         if ((node->tn_flags & APPEND) != 0 &&          if ((node->tn_flags & APPEND) != 0 &&
Line 366  tmpfs_close(void *v)
Line 374  tmpfs_close(void *v)
                 int             a_fflag;                  int             a_fflag;
                 kauth_cred_t    a_cred;                  kauth_cred_t    a_cred;
         } */ *ap = v;          } */ *ap = v;
         vnode_t *vp __diagused = ap->a_vp;          vnode_t *vp = ap->a_vp;
   
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
   
           tmpfs_update(vp, NULL, NULL, NULL, UPDATE_CLOSE);
         return 0;          return 0;
 }  }
   
Line 409  tmpfs_access(void *v)
Line 419  tmpfs_access(void *v)
                 return EPERM;                  return EPERM;
         }          }
   
         return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode,          return kauth_authorize_vnode(cred, kauth_access_action(mode,
             vp->v_type, node->tn_mode), vp, NULL, genfs_can_access(vp->v_type,              vp->v_type, node->tn_mode), vp, NULL, genfs_can_access(vp->v_type,
             node->tn_mode, node->tn_uid, node->tn_gid, mode, cred));              node->tn_mode, node->tn_uid, node->tn_gid, mode, cred));
 }  }
Line 428  tmpfs_getattr(void *v)
Line 438  tmpfs_getattr(void *v)
   
         vattr_null(vap);          vattr_null(vap);
   
           tmpfs_update(vp, NULL, NULL, NULL, 0);
   
         vap->va_type = vp->v_type;          vap->va_type = vp->v_type;
         vap->va_mode = node->tn_mode;          vap->va_mode = node->tn_mode;
         vap->va_nlink = node->tn_links;          vap->va_nlink = node->tn_links;
Line 453  tmpfs_getattr(void *v)
Line 465  tmpfs_getattr(void *v)
         return 0;          return 0;
 }  }
   
   #define GOODTIME(tv)    ((tv)->tv_sec != VNOVAL || (tv)->tv_nsec != VNOVAL)
   /* XXX Should this operation be atomic?  I think it should, but code in
    * XXX other places (e.g., ufs) doesn't seem to be... */
 int  int
 tmpfs_setattr(void *v)  tmpfs_setattr(void *v)
 {  {
Line 472  tmpfs_setattr(void *v)
Line 487  tmpfs_setattr(void *v)
         /* Abort if any unsettable attribute is given. */          /* Abort if any unsettable attribute is given. */
         if (vap->va_type != VNON || vap->va_nlink != VNOVAL ||          if (vap->va_type != VNON || vap->va_nlink != VNOVAL ||
             vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||              vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||
             vap->va_blocksize != VNOVAL || vap->va_ctime.tv_sec != VNOVAL ||              vap->va_blocksize != VNOVAL || GOODTIME(&vap->va_ctime) ||
             vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL ||              vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL ||
             vap->va_bytes != VNOVAL) {              vap->va_bytes != VNOVAL) {
                 return EINVAL;                  return EINVAL;
         }          }
           if (error == 0 && (vap->va_flags != VNOVAL))
         if (error == 0 && vap->va_flags != VNOVAL)  
                 error = tmpfs_chflags(vp, vap->va_flags, cred, l);                  error = tmpfs_chflags(vp, vap->va_flags, cred, l);
   
         if (error == 0 && vap->va_size != VNOVAL)          if (error == 0 && (vap->va_size != VNOVAL))
                 error = tmpfs_chsize(vp, vap->va_size, cred, l);                  error = tmpfs_chsize(vp, vap->va_size, cred, l);
   
         if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))          if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL))
                 error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);                  error = tmpfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
   
         if (error == 0 && vap->va_mode != VNOVAL)          if (error == 0 && (vap->va_mode != VNOVAL))
                 error = tmpfs_chmod(vp, vap->va_mode, cred, l);                  error = tmpfs_chmod(vp, vap->va_mode, cred, l);
   
         const bool chsometime =          if (error == 0 && (GOODTIME(&vap->va_atime) || GOODTIME(&vap->va_mtime)
             vap->va_atime.tv_sec != VNOVAL ||              || GOODTIME(&vap->va_birthtime))) {
             vap->va_mtime.tv_sec != VNOVAL ||  
             vap->va_birthtime.tv_sec != VNOVAL;  
         if (error == 0 && chsometime) {  
                 error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,                  error = tmpfs_chtimes(vp, &vap->va_atime, &vap->va_mtime,
                     &vap->va_birthtime, vap->va_vaflags, cred, l);                      &vap->va_birthtime, vap->va_vaflags, cred, l);
                   if (error == 0)
                           return 0;
         }          }
           tmpfs_update(vp, NULL, NULL, NULL, 0);
         return error;          return error;
 }  }
   
Line 519  tmpfs_read(void *v)
Line 533  tmpfs_read(void *v)
   
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
   
         if (vp->v_type == VDIR) {          if (vp->v_type != VREG) {
                 return EISDIR;                  return EISDIR;
         }          }
         if (uio->uio_offset < 0 || vp->v_type != VREG) {          if (uio->uio_offset < 0) {
                 return EINVAL;                  return EINVAL;
         }          }
   
         /* Note: reading zero bytes should not update atime. */  
         if (uio->uio_resid == 0) {  
                 return 0;  
         }  
   
         node = VP_TO_TMPFS_NODE(vp);          node = VP_TO_TMPFS_NODE(vp);
           node->tn_status |= TMPFS_NODE_ACCESSED;
         uobj = node->tn_spec.tn_reg.tn_aobj;          uobj = node->tn_spec.tn_reg.tn_aobj;
         error = 0;          error = 0;
   
Line 548  tmpfs_read(void *v)
Line 558  tmpfs_read(void *v)
                 error = ubc_uiomove(uobj, uio, len, IO_ADV_DECODE(ioflag),                  error = ubc_uiomove(uobj, uio, len, IO_ADV_DECODE(ioflag),
                     UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));                      UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
         }          }
   
         tmpfs_update(vp, TMPFS_UPDATE_ATIME);  
         return error;          return error;
 }  }
   
Line 568  tmpfs_write(void *v)
Line 576  tmpfs_write(void *v)
         tmpfs_node_t *node;          tmpfs_node_t *node;
         struct uvm_object *uobj;          struct uvm_object *uobj;
         off_t oldsize;          off_t oldsize;
           bool extended;
         int error;          int error;
   
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
Line 575  tmpfs_write(void *v)
Line 584  tmpfs_write(void *v)
         node = VP_TO_TMPFS_NODE(vp);          node = VP_TO_TMPFS_NODE(vp);
         oldsize = node->tn_size;          oldsize = node->tn_size;
   
         if ((vp->v_mount->mnt_flag & MNT_RDONLY) != 0) {  
                 error = EROFS;  
                 goto out;  
         }  
   
         if (uio->uio_offset < 0 || vp->v_type != VREG) {          if (uio->uio_offset < 0 || vp->v_type != VREG) {
                 error = EINVAL;                  error = EINVAL;
                 goto out;                  goto out;
Line 592  tmpfs_write(void *v)
Line 596  tmpfs_write(void *v)
                 uio->uio_offset = node->tn_size;                  uio->uio_offset = node->tn_size;
         }          }
   
         if (uio->uio_offset + uio->uio_resid > node->tn_size) {          extended = uio->uio_offset + uio->uio_resid > node->tn_size;
           if (extended) {
                 error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);                  error = tmpfs_reg_resize(vp, uio->uio_offset + uio->uio_resid);
                 if (error)                  if (error)
                         goto out;                          goto out;
Line 614  tmpfs_write(void *v)
Line 619  tmpfs_write(void *v)
                 (void)tmpfs_reg_resize(vp, oldsize);                  (void)tmpfs_reg_resize(vp, oldsize);
         }          }
   
         tmpfs_update(vp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);          node->tn_status |= TMPFS_NODE_ACCESSED | TMPFS_NODE_MODIFIED |
               (extended ? TMPFS_NODE_CHANGED : 0);
         VN_KNOTE(vp, NOTE_WRITE);          VN_KNOTE(vp, NOTE_WRITE);
 out:  out:
         if (error) {          if (error) {
Line 636  tmpfs_fsync(void *v)
Line 642  tmpfs_fsync(void *v)
                 off_t a_offhi;                  off_t a_offhi;
                 struct lwp *a_l;                  struct lwp *a_l;
         } */ *ap = v;          } */ *ap = v;
         vnode_t *vp __diagused = ap->a_vp;          vnode_t *vp = ap->a_vp;
   
         /* Nothing to do.  Should be up to date. */          /* Nothing to do.  Just update. */
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
           tmpfs_update(vp, NULL, NULL, NULL, 0);
         return 0;          return 0;
 }  }
   
Line 652  tmpfs_fsync(void *v)
Line 659  tmpfs_fsync(void *v)
 int  int
 tmpfs_remove(void *v)  tmpfs_remove(void *v)
 {  {
         struct vop_remove_v2_args /* {          struct vop_remove_args /* {
                 struct vnode *a_dvp;                  struct vnode *a_dvp;
                 struct vnode *a_vp;                  struct vnode *a_vp;
                 struct componentname *a_cnp;                  struct componentname *a_cnp;
         } */ *ap = v;          } */ *ap = v;
         vnode_t *dvp = ap->a_dvp, *vp = ap->a_vp;          vnode_t *dvp = ap->a_dvp, *vp = ap->a_vp;
         tmpfs_node_t *dnode, *node;          tmpfs_node_t *node;
         tmpfs_dirent_t *de;          tmpfs_dirent_t *de;
         int error;          int error;
   
Line 669  tmpfs_remove(void *v)
Line 676  tmpfs_remove(void *v)
                 error = EPERM;                  error = EPERM;
                 goto out;                  goto out;
         }          }
         dnode = VP_TO_TMPFS_DIR(dvp);  
         node = VP_TO_TMPFS_NODE(vp);          node = VP_TO_TMPFS_NODE(vp);
   
         /*          /* Files marked as immutable or append-only cannot be deleted. */
          * Files marked as immutable or append-only cannot be deleted.  
          * Likewise, files residing on directories marked as append-only  
          * cannot be deleted.  
          */  
         if (node->tn_flags & (IMMUTABLE | APPEND)) {          if (node->tn_flags & (IMMUTABLE | APPEND)) {
                 error = EPERM;                  error = EPERM;
                 goto out;                  goto out;
         }          }
         if (dnode->tn_flags & APPEND) {  
                 error = EPERM;  
                 goto out;  
         }  
   
         /* Lookup the directory entry (check the cached hint first). */          /* Lookup the directory entry (check the cached hint first). */
         de = tmpfs_dir_cached(node);          de = tmpfs_dir_cached(node);
         if (de == NULL) {          if (de == NULL) {
                   tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);
                 struct componentname *cnp = ap->a_cnp;                  struct componentname *cnp = ap->a_cnp;
                 de = tmpfs_dir_lookup(dnode, cnp);                  de = tmpfs_dir_lookup(dnode, cnp);
         }          }
Line 696  tmpfs_remove(void *v)
Line 695  tmpfs_remove(void *v)
   
         /*          /*
          * Remove the entry from the directory (drops the link count) and           * Remove the entry from the directory (drops the link count) and
          * destroy it or replace with a whiteout.           * destroy it or replace it with a whiteout.
          *           * Note: the inode referred by it will not be destroyed
          * Note: the inode referred by it will not be destroyed until the           * until the vnode is reclaimed/recycled.
          * vnode is reclaimed/recycled.  
          */           */
           tmpfs_dir_detach(dvp, de);
         tmpfs_dir_detach(dnode, de);  
   
         if (ap->a_cnp->cn_flags & DOWHITEOUT)          if (ap->a_cnp->cn_flags & DOWHITEOUT)
                 tmpfs_dir_attach(dnode, de, TMPFS_NODE_WHITEOUT);                  tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
         else          else
                 tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);                  tmpfs_free_dirent(VFS_TO_TMPFS(vp->v_mount), de);
   
         if (node->tn_links > 0) {  
                 /* We removed a hard link. */  
                 tmpfs_update(vp, TMPFS_UPDATE_CTIME);  
         }  
         tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);  
         error = 0;          error = 0;
 out:  out:
         /* Drop the reference and unlock the node. */          /* Drop the references and unlock the vnodes. */
           vput(vp);
         if (dvp == vp) {          if (dvp == vp) {
                 vrele(vp);                  vrele(dvp);
         } else {          } else {
                 vput(vp);                  vput(dvp);
         }          }
         return error;          return error;
 }  }
Line 731  out:
Line 722  out:
 int  int
 tmpfs_link(void *v)  tmpfs_link(void *v)
 {  {
         struct vop_link_v2_args /* {          struct vop_link_args /* {
                 struct vnode *a_dvp;                  struct vnode *a_dvp;
                 struct vnode *a_vp;                  struct vnode *a_vp;
                 struct componentname *a_cnp;                  struct componentname *a_cnp;
Line 773  tmpfs_link(void *v)
Line 764  tmpfs_link(void *v)
                 goto out;                  goto out;
         }          }
   
         /*          /*
          * Insert the entry into the directory.           * Insert the entry into the directory.
          * It will increase the inode link count.           * It will increase the inode link count.
          */           */
         tmpfs_dir_attach(dnode, de, node);          tmpfs_dir_attach(dvp, de, node);
         tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);  
   
         /* Update the timestamps and trigger the event. */          /* Update the timestamps and trigger the event. */
         if (node->tn_vnode) {          if (node->tn_vnode) {
                 VN_KNOTE(node->tn_vnode, NOTE_LINK);                  VN_KNOTE(node->tn_vnode, NOTE_LINK);
         }          }
         tmpfs_update(vp, TMPFS_UPDATE_CTIME);          node->tn_status |= TMPFS_NODE_CHANGED;
           tmpfs_update(vp, NULL, NULL, NULL, 0);
         error = 0;          error = 0;
 out:  out:
         VOP_UNLOCK(vp);          VOP_UNLOCK(vp);
           vput(dvp);
         return error;          return error;
 }  }
   
 int  int
 tmpfs_mkdir(void *v)  tmpfs_mkdir(void *v)
 {  {
         struct vop_mkdir_v3_args /* {          struct vop_mkdir_args /* {
                 struct vnode            *a_dvp;                  struct vnode            *a_dvp;
                 struct vnode            **a_vpp;                  struct vnode            **a_vpp;
                 struct componentname    *a_cnp;                  struct componentname    *a_cnp;
Line 806  tmpfs_mkdir(void *v)
Line 798  tmpfs_mkdir(void *v)
         struct vattr *vap = ap->a_vap;          struct vattr *vap = ap->a_vap;
   
         KASSERT(vap->va_type == VDIR);          KASSERT(vap->va_type == VDIR);
         return tmpfs_construct_node(dvp, vpp, vap, cnp, NULL);          return tmpfs_alloc_file(dvp, vpp, vap, cnp, NULL);
 }  }
   
 int  int
 tmpfs_rmdir(void *v)  tmpfs_rmdir(void *v)
 {  {
         struct vop_rmdir_v2_args /* {          struct vop_rmdir_args /* {
                 struct vnode            *a_dvp;                  struct vnode            *a_dvp;
                 struct vnode            *a_vp;                  struct vnode            *a_vp;
                 struct componentname    *a_cnp;                  struct componentname    *a_cnp;
Line 827  tmpfs_rmdir(void *v)
Line 819  tmpfs_rmdir(void *v)
   
         KASSERT(VOP_ISLOCKED(dvp));          KASSERT(VOP_ISLOCKED(dvp));
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
           KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);
   
         /*          /*
          * Directories with more than two entries ('.' and '..') cannot be           * Directories with more than two non-whiteout
          * removed.  There may be whiteout entries, which we will destroy.           * entries ('.' and '..') cannot be removed.
          */           */
         if (node->tn_size > 0) {          if (node->tn_size > 0) {
                 /*                  KASSERT(error == 0);
                  * If never had whiteout entries, the directory is certainly  
                  * not empty.  Otherwise, scan for any non-whiteout entry.  
                  */  
                 if ((node->tn_gen & TMPFS_WHITEOUT_BIT) == 0) {  
                         error = ENOTEMPTY;  
                         goto out;  
                 }  
                 TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {                  TAILQ_FOREACH(de, &node->tn_spec.tn_dir.tn_dir, td_entries) {
                         if (de->td_node != TMPFS_NODE_WHITEOUT) {                          if (de->td_node != TMPFS_NODE_WHITEOUT) {
                                 error = ENOTEMPTY;                                  error = ENOTEMPTY;
                                 goto out;                                  break;
                         }                          }
                 }                  }
                 KASSERT(error == 0);                  if (error)
                           goto out;
         }          }
   
         KASSERT(node->tn_spec.tn_dir.tn_parent == dnode);  
   
         /* Lookup the directory entry (check the cached hint first). */          /* Lookup the directory entry (check the cached hint first). */
         de = tmpfs_dir_cached(node);          de = tmpfs_dir_cached(node);
         if (de == NULL) {          if (de == NULL) {
Line 868  tmpfs_rmdir(void *v)
Line 853  tmpfs_rmdir(void *v)
   
         /* Decrement the link count for the virtual '.' entry. */          /* Decrement the link count for the virtual '.' entry. */
         node->tn_links--;          node->tn_links--;
           node->tn_status |= TMPFS_NODE_STATUSALL;
   
         /* Detach the directory entry from the directory. */          /* Detach the directory entry from the directory. */
         tmpfs_dir_detach(dnode, de);          tmpfs_dir_detach(dvp, de);
   
         /* Purge the cache for parent. */          /* Purge the cache for parent. */
         cache_purge(dvp);          cache_purge(dvp);
   
         /*          /*
          * Destroy the directory entry or replace it with a whiteout.           * Destroy the directory entry or replace it with a whiteout.
          *           * Note: the inode referred by it will not be destroyed
          * Note: the inode referred by it will not be destroyed until the           * until the vnode is reclaimed.
          * vnode is reclaimed.  
          */           */
         if (ap->a_cnp->cn_flags & DOWHITEOUT)          if (ap->a_cnp->cn_flags & DOWHITEOUT)
                 tmpfs_dir_attach(dnode, de, TMPFS_NODE_WHITEOUT);                  tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
         else          else
                 tmpfs_free_dirent(tmp, de);                  tmpfs_free_dirent(tmp, de);
   
         /* Destroy the whiteout entries from the node. */          /* Destroy the whiteout entries from the node. */
         while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {          while ((de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir)) != NULL) {
                 KASSERT(de->td_node == TMPFS_NODE_WHITEOUT);                  KASSERT(de->td_node == TMPFS_NODE_WHITEOUT);
                 tmpfs_dir_detach(node, de);                  tmpfs_dir_detach(vp, de);
                 tmpfs_free_dirent(tmp, de);                  tmpfs_free_dirent(tmp, de);
         }          }
         tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);  
   
         KASSERT(node->tn_size == 0);  
         KASSERT(node->tn_links == 0);          KASSERT(node->tn_links == 0);
 out:  out:
         /* Release the node. */          /* Release the nodes. */
         KASSERT(dvp != vp);          vput(dvp);
         vput(vp);          vput(vp);
         return error;          return error;
 }  }
Line 906  out:
Line 889  out:
 int  int
 tmpfs_symlink(void *v)  tmpfs_symlink(void *v)
 {  {
         struct vop_symlink_v3_args /* {          struct vop_symlink_args /* {
                 struct vnode            *a_dvp;                  struct vnode            *a_dvp;
                 struct vnode            **a_vpp;                  struct vnode            **a_vpp;
                 struct componentname    *a_cnp;                  struct componentname    *a_cnp;
Line 920  tmpfs_symlink(void *v)
Line 903  tmpfs_symlink(void *v)
         char *target = ap->a_target;          char *target = ap->a_target;
   
         KASSERT(vap->va_type == VLNK);          KASSERT(vap->va_type == VLNK);
         return tmpfs_construct_node(dvp, vpp, vap, cnp, target);          return tmpfs_alloc_file(dvp, vpp, vap, cnp, target);
 }  }
   
 int  int
Line 952  tmpfs_readdir(void *v)
Line 935  tmpfs_readdir(void *v)
         node = VP_TO_TMPFS_DIR(vp);          node = VP_TO_TMPFS_DIR(vp);
         startoff = uio->uio_offset;          startoff = uio->uio_offset;
         cnt = 0;          cnt = 0;
           if (node->tn_links == 0) {
         /*  
          * Retrieve the directory entries, unless it is being destroyed.  
          */  
         if (node->tn_links) {  
                 error = tmpfs_dir_getdents(node, uio, &cnt);  
         } else {  
                 error = 0;                  error = 0;
                   goto out;
         }          }
   
           if (uio->uio_offset == TMPFS_DIRCOOKIE_DOT) {
                   error = tmpfs_dir_getdotdent(node, uio);
                   if (error != 0) {
                           if (error == -1)
                                   error = 0;
                           goto out;
                   }
                   cnt++;
           }
           if (uio->uio_offset == TMPFS_DIRCOOKIE_DOTDOT) {
                   error = tmpfs_dir_getdotdotdent(node, uio);
                   if (error != 0) {
                           if (error == -1)
                                   error = 0;
                           goto out;
                   }
                   cnt++;
           }
           error = tmpfs_dir_getdents(node, uio, &cnt);
           if (error == -1) {
                   error = 0;
           }
           KASSERT(error >= 0);
   out:
         if (eofflag != NULL) {          if (eofflag != NULL) {
                 *eofflag = !error && uio->uio_offset == TMPFS_DIRSEQ_EOF;                  *eofflag = (!error && uio->uio_offset == TMPFS_DIRCOOKIE_EOF);
         }          }
         if (error || cookies == NULL || ncookies == NULL) {          if (error || cookies == NULL || ncookies == NULL) {
                 return error;                  return error;
         }          }
   
         /* Update NFS-related variables, if any. */          /* Update NFS-related variables, if any. */
         tmpfs_dirent_t *de = NULL;  
         off_t i, off = startoff;          off_t i, off = startoff;
           tmpfs_dirent_t *de = NULL;
   
         *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);          *cookies = malloc(cnt * sizeof(off_t), M_TEMP, M_WAITOK);
         *ncookies = cnt;          *ncookies = cnt;
   
         for (i = 0; i < cnt; i++) {          for (i = 0; i < cnt; i++) {
                 KASSERT(off != TMPFS_DIRSEQ_EOF);                  KASSERT(off != TMPFS_DIRCOOKIE_EOF);
                 if (off != TMPFS_DIRSEQ_DOT) {                  if (off != TMPFS_DIRCOOKIE_DOT) {
                         if (off == TMPFS_DIRSEQ_DOTDOT) {                          if (off == TMPFS_DIRCOOKIE_DOTDOT) {
                                 de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);                                  de = TAILQ_FIRST(&node->tn_spec.tn_dir.tn_dir);
                         } else if (de != NULL) {                          } else if (de != NULL) {
                                 de = TAILQ_NEXT(de, td_entries);                                  de = TAILQ_NEXT(de, td_entries);
                         } else {                          } else {
                                 de = tmpfs_dir_lookupbyseq(node, off);                                  de = tmpfs_dir_lookupbycookie(node, off);
                                 KASSERT(de != NULL);                                  KASSERT(de != NULL);
                                 de = TAILQ_NEXT(de, td_entries);                                  de = TAILQ_NEXT(de, td_entries);
                         }                          }
                         if (de == NULL) {                          if (de == NULL) {
                                 off = TMPFS_DIRSEQ_EOF;                                  off = TMPFS_DIRCOOKIE_EOF;
                         } else {                          } else {
                                 off = tmpfs_dir_getseq(node, de);                                  off = tmpfs_dircookie(de);
                         }                          }
                 } else {                  } else {
                         off = TMPFS_DIRSEQ_DOTDOT;                          off = TMPFS_DIRCOOKIE_DOTDOT;
                 }                  }
                 (*cookies)[i] = off;                  (*cookies)[i] = off;
         }          }
Line 1012  tmpfs_readlink(void *v)
Line 1014  tmpfs_readlink(void *v)
         } */ *ap = v;          } */ *ap = v;
         vnode_t *vp = ap->a_vp;          vnode_t *vp = ap->a_vp;
         struct uio *uio = ap->a_uio;          struct uio *uio = ap->a_uio;
         tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);          tmpfs_node_t *node;
         int error;          int error;
   
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
         KASSERT(uio->uio_offset == 0);          KASSERT(uio->uio_offset == 0);
         KASSERT(vp->v_type == VLNK);          KASSERT(vp->v_type == VLNK);
   
         /* Note: readlink(2) returns the path without NUL terminator. */          node = VP_TO_TMPFS_NODE(vp);
         if (node->tn_size > 0) {          error = uiomove(node->tn_spec.tn_lnk.tn_link,
                 error = uiomove(node->tn_spec.tn_lnk.tn_link,              MIN(node->tn_size, uio->uio_resid), uio);
                     MIN(node->tn_size, uio->uio_resid), uio);          node->tn_status |= TMPFS_NODE_ACCESSED;
         } else {  
                 error = 0;  
         }  
         tmpfs_update(vp, TMPFS_UPDATE_ATIME);  
   
         return error;          return error;
 }  }
Line 1034  tmpfs_readlink(void *v)
Line 1032  tmpfs_readlink(void *v)
 int  int
 tmpfs_inactive(void *v)  tmpfs_inactive(void *v)
 {  {
         struct vop_inactive_v2_args /* {          struct vop_inactive_args /* {
                 struct vnode *a_vp;                  struct vnode *a_vp;
                 bool *a_recycle;                  bool *a_recycle;
         } */ *ap = v;          } */ *ap = v;
Line 1044  tmpfs_inactive(void *v)
Line 1042  tmpfs_inactive(void *v)
         KASSERT(VOP_ISLOCKED(vp));          KASSERT(VOP_ISLOCKED(vp));
   
         node = VP_TO_TMPFS_NODE(vp);          node = VP_TO_TMPFS_NODE(vp);
         if (node->tn_links == 0) {          *ap->a_recycle = (node->tn_links == 0);
                 /*          VOP_UNLOCK(vp);
                  * Mark node as dead by setting its generation to zero.  
                  */  
                 atomic_and_32(&node->tn_gen, ~TMPFS_NODE_GEN_MASK);  
                 *ap->a_recycle = true;  
         } else {  
                 *ap->a_recycle = false;  
         }  
   
         return 0;          return 0;
 }  }
Line 1060  tmpfs_inactive(void *v)
Line 1051  tmpfs_inactive(void *v)
 int  int
 tmpfs_reclaim(void *v)  tmpfs_reclaim(void *v)
 {  {
         struct vop_reclaim_v2_args /* {          struct vop_reclaim_args /* {
                 struct vnode *a_vp;                  struct vnode *a_vp;
         } */ *ap = v;          } */ *ap = v;
         vnode_t *vp = ap->a_vp;          vnode_t *vp = ap->a_vp;
         tmpfs_mount_t *tmp = VFS_TO_TMPFS(vp->v_mount);          tmpfs_mount_t *tmp = VFS_TO_TMPFS(vp->v_mount);
         tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);          tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
           bool racing;
         /* Unlock vnode.  We still have exclusive access to it. */  
         VOP_UNLOCK(vp);  
   
         /* Disassociate inode from vnode. */          /* Disassociate inode from vnode. */
           mutex_enter(&node->tn_vlock);
         node->tn_vnode = NULL;          node->tn_vnode = NULL;
         vp->v_data = NULL;          vp->v_data = NULL;
           /* Check if tmpfs_vnode_get() is racing with us. */
           racing = TMPFS_NODE_RECLAIMING(node);
           mutex_exit(&node->tn_vlock);
   
         /* If inode is not referenced, i.e. no links, then destroy it. */          /*
         if (node->tn_links == 0)           * If inode is not referenced, i.e. no links, then destroy it.
            * Note: if racing - inode is about to get a new vnode, leave it.
            */
           if (node->tn_links == 0 && !racing) {
                 tmpfs_free_node(tmp, node);                  tmpfs_free_node(tmp, node);
           }
         return 0;          return 0;
 }  }
   
Line 1166  tmpfs_getpages(void *v)
Line 1163  tmpfs_getpages(void *v)
         KASSERT(vp->v_type == VREG);          KASSERT(vp->v_type == VREG);
         KASSERT(mutex_owned(vp->v_interlock));          KASSERT(mutex_owned(vp->v_interlock));
   
           node = VP_TO_TMPFS_NODE(vp);
           uobj = node->tn_spec.tn_reg.tn_aobj;
   
         /*          /*
          * Currently, PGO_PASTEOF is not supported.           * Currently, PGO_PASTEOF is not supported.
          */           */
Line 1182  tmpfs_getpages(void *v)
Line 1182  tmpfs_getpages(void *v)
         if ((flags & PGO_LOCKED) != 0)          if ((flags & PGO_LOCKED) != 0)
                 return EBUSY;                  return EBUSY;
   
         if (vdead_check(vp, VDEAD_NOWAIT) != 0)  
                 return ENOENT;  
   
         node = VP_TO_TMPFS_NODE(vp);  
         uobj = node->tn_spec.tn_reg.tn_aobj;  
   
         if ((flags & PGO_NOTIMESTAMP) == 0) {          if ((flags & PGO_NOTIMESTAMP) == 0) {
                 u_int tflags = 0;  
   
                 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)                  if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
                         tflags |= TMPFS_UPDATE_ATIME;                          node->tn_status |= TMPFS_NODE_ACCESSED;
   
                 if ((access_type & VM_PROT_WRITE) != 0) {                  if ((access_type & VM_PROT_WRITE) != 0) {
                         tflags |= TMPFS_UPDATE_MTIME;                          node->tn_status |= TMPFS_NODE_MODIFIED;
                         if (vp->v_mount->mnt_flag & MNT_RELATIME)                          if (vp->v_mount->mnt_flag & MNT_RELATIME)
                                 tflags |= TMPFS_UPDATE_ATIME;                                  node->tn_status |= TMPFS_NODE_ACCESSED;
                 }                  }
                 tmpfs_update(vp, tflags);  
         }          }
   
         /*          /*
Line 1273  tmpfs_whiteout(void *v)
Line 1264  tmpfs_whiteout(void *v)
         struct componentname *cnp = ap->a_cnp;          struct componentname *cnp = ap->a_cnp;
         const int flags = ap->a_flags;          const int flags = ap->a_flags;
         tmpfs_mount_t *tmp = VFS_TO_TMPFS(dvp->v_mount);          tmpfs_mount_t *tmp = VFS_TO_TMPFS(dvp->v_mount);
         tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp);  
         tmpfs_dirent_t *de;          tmpfs_dirent_t *de;
         int error;          int error;
   
Line 1285  tmpfs_whiteout(void *v)
Line 1275  tmpfs_whiteout(void *v)
                     cnp->cn_namelen, &de);                      cnp->cn_namelen, &de);
                 if (error)                  if (error)
                         return error;                          return error;
                 tmpfs_dir_attach(dnode, de, TMPFS_NODE_WHITEOUT);                  tmpfs_dir_attach(dvp, de, TMPFS_NODE_WHITEOUT);
                 break;                  break;
         case DELETE:          case DELETE:
                 cnp->cn_flags &= ~DOWHITEOUT; /* when in doubt, cargo cult */                  cnp->cn_flags &= ~DOWHITEOUT; /* when in doubt, cargo cult */
                 de = tmpfs_dir_lookup(dnode, cnp);                  de = tmpfs_dir_lookup(VP_TO_TMPFS_DIR(dvp), cnp);
                 if (de == NULL)                  if (de == NULL)
                         return ENOENT;                          return ENOENT;
                 tmpfs_dir_detach(dnode, de);                  tmpfs_dir_detach(dvp, de);
                 tmpfs_free_dirent(tmp, de);                  tmpfs_free_dirent(tmp, de);
                 break;                  break;
         }          }
         tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME);  
         return 0;          return 0;
 }  }
   
Line 1310  tmpfs_print(void *v)
Line 1299  tmpfs_print(void *v)
         tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);          tmpfs_node_t *node = VP_TO_TMPFS_NODE(vp);
   
         printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n"          printf("tag VT_TMPFS, tmpfs_node %p, flags 0x%x, links %d\n"
             "\tmode 0%o, owner %d, group %d, size %" PRIdMAX,              "\tmode 0%o, owner %d, group %d, size %" PRIdMAX ", status 0x%x",
             node, node->tn_flags, node->tn_links, node->tn_mode, node->tn_uid,              node, node->tn_flags, node->tn_links, node->tn_mode, node->tn_uid,
             node->tn_gid, (uintmax_t)node->tn_size);              node->tn_gid, (uintmax_t)node->tn_size, node->tn_status);
         if (vp->v_type == VFIFO) {          if (vp->v_type == VFIFO) {
                 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);                  VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
         }          }

Legend:
Removed from v.1.98.2.4  
changed lines
  Added in v.1.99

CVSweb <webmaster@jp.NetBSD.org>