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

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

Diff for /src/sys/fs/puffs/puffs_subr.c between version 1.23.2.1 and 1.24

version 1.23.2.1, 2007/07/11 20:09:29 version 1.24, 2007/03/14 12:13:58
Line 15 
Line 15 
  * 2. Redistributions in binary form must reproduce the above copyright   * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the   *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.   *    documentation and/or other materials provided with the distribution.
    * 3. The name of the company nor the name of the author may be used to
    *    endorse or promote products derived from this software without specific
    *    prior written permission.
  *   *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED   * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Line 35  __KERNEL_RCSID(0, "$NetBSD$");
Line 38  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/conf.h>  #include <sys/conf.h>
 #include <sys/hash.h>  #include <sys/hash.h>
 #include <sys/kauth.h>  
 #include <sys/malloc.h>  #include <sys/malloc.h>
 #include <sys/mount.h>  #include <sys/mount.h>
 #include <sys/namei.h>  
 #include <sys/poll.h>  
 #include <sys/socketvar.h>  #include <sys/socketvar.h>
 #include <sys/vnode.h>  #include <sys/vnode.h>
 #include <sys/proc.h>  #include <sys/kauth.h>
   #include <sys/namei.h>
   
 #include <fs/puffs/puffs_msgif.h>  #include <fs/puffs/puffs_msgif.h>
 #include <fs/puffs/puffs_sys.h>  #include <fs/puffs/puffs_sys.h>
Line 50  __KERNEL_RCSID(0, "$NetBSD$");
Line 51  __KERNEL_RCSID(0, "$NetBSD$");
 #include <miscfs/genfs/genfs_node.h>  #include <miscfs/genfs/genfs_node.h>
 #include <miscfs/specfs/specdev.h>  #include <miscfs/specfs/specdev.h>
   
 struct pool puffs_pnpool;  POOL_INIT(puffs_pnpool, sizeof(struct puffs_node), 0, 0, 0, "puffspnpl",
       &pool_allocator_nointr, IPL_NONE);
   
 #ifdef PUFFSDEBUG  #ifdef PUFFSDEBUG
 int puffsdebug;  int puffsdebug;
Line 85  puffs_getvnode(struct mount *mp, void *c
Line 87  puffs_getvnode(struct mount *mp, void *c
         struct puffs_node_hashlist *plist;          struct puffs_node_hashlist *plist;
         int error;          int error;
   
         if (type <= VNON || type >= VBAD)  
                 return EINVAL;  
   
         pmp = MPTOPUFFSMP(mp);          pmp = MPTOPUFFSMP(mp);
   
         /*          /*
Line 135  puffs_getvnode(struct mount *mp, void *c
Line 134  puffs_getvnode(struct mount *mp, void *c
          * clerical tasks & footwork           * clerical tasks & footwork
          */           */
   
         /* default size */  
         uvm_vnp_setsize(vp, 0);  
   
         /* dances based on vnode type. almost ufs_vinit(), but not quite */          /* dances based on vnode type. almost ufs_vinit(), but not quite */
         switch (type) {          switch (type) {
         case VCHR:          case VCHR:
Line 189  puffs_getvnode(struct mount *mp, void *c
Line 185  puffs_getvnode(struct mount *mp, void *c
         pnode = pool_get(&puffs_pnpool, PR_WAITOK);          pnode = pool_get(&puffs_pnpool, PR_WAITOK);
         pnode->pn_cookie = cookie;          pnode->pn_cookie = cookie;
         pnode->pn_stat = 0;          pnode->pn_stat = 0;
         pnode->pn_refcount = 1;  
   
         mutex_init(&pnode->pn_mtx, MUTEX_DEFAULT, IPL_NONE);  
         SLIST_INIT(&pnode->pn_sel.sel_klist);  
         pnode->pn_revents = 0;  
   
         plist = puffs_cookie2hashlist(pmp, cookie);          plist = puffs_cookie2hashlist(pmp, cookie);
         LIST_INSERT_HEAD(plist, pnode, pn_hashent);          LIST_INSERT_HEAD(plist, pnode, pn_hashent);
         vp->v_data = pnode;          vp->v_data = pnode;
Line 233  puffs_newnode(struct mount *mp, struct v
Line 223  puffs_newnode(struct mount *mp, struct v
          * XXX: technically this error check should punish the fs,           * XXX: technically this error check should punish the fs,
          * not the caller.           * not the caller.
          */           */
         mutex_enter(&pmp->pmp_lock);          simple_lock(&pmp->pmp_lock);
         if (cookie == pmp->pmp_root_cookie          if (cookie == pmp->pmp_rootcookie
             || puffs_cookie2pnode(pmp, cookie) != NULL) {              || puffs_cookie2pnode(pmp, cookie) != NULL) {
                 mutex_exit(&pmp->pmp_lock);                  simple_unlock(&pmp->pmp_lock);
                 error = EEXIST;                  error = EEXIST;
                 return error;                  return error;
         }          }
         mutex_exit(&pmp->pmp_lock);          simple_unlock(&pmp->pmp_lock);
   
         error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);          error = puffs_getvnode(dvp->v_mount, cookie, type, 0, rdev, &vp);
         if (error)          if (error)
Line 250  puffs_newnode(struct mount *mp, struct v
Line 240  puffs_newnode(struct mount *mp, struct v
         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);          vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
         *vpp = vp;          *vpp = vp;
   
         if ((cnp->cn_flags & MAKEENTRY) && PUFFS_USE_NAMECACHE(pmp))          if ((cnp->cn_flags & MAKEENTRY) && PUFFS_DOCACHE(pmp))
                 cache_enter(dvp, vp, cnp);                  cache_enter(dvp, vp, cnp);
   
         return 0;          return 0;
 }  }
   
 /*  
  * Release pnode structure which dealing with references to the  
  * puffs_node instead of the vnode.  Can't use vref()/vrele() on  
  * the vnode there, since that causes the lovely VOP_INACTIVE(),  
  * which in turn causes the lovely deadlock when called by the one  
  * who is supposed to handle it.  
  */  
 void  
 puffs_releasenode(struct puffs_node *pn)  
 {  
   
         mutex_enter(&pn->pn_mtx);  
         if (--pn->pn_refcount == 0) {  
                 mutex_exit(&pn->pn_mtx);  
                 mutex_destroy(&pn->pn_mtx);  
                 pool_put(&puffs_pnpool, pn);  
         } else {  
                 mutex_exit(&pn->pn_mtx);  
         }  
 }  
   
 /*  
  * Add reference to node.  
  *  mutex held on entry and return  
  */  
 void  
 puffs_referencenode(struct puffs_node *pn)  
 {  
   
         KASSERT(mutex_owned(&pn->pn_mtx));  
         pn->pn_refcount++;  
 }  
   
 void  void
 puffs_putvnode(struct vnode *vp)  puffs_putvnode(struct vnode *vp)
 {  {
Line 305  puffs_putvnode(struct vnode *vp)
Line 262  puffs_putvnode(struct vnode *vp)
   
         LIST_REMOVE(pnode, pn_hashent);          LIST_REMOVE(pnode, pn_hashent);
         genfs_node_destroy(vp);          genfs_node_destroy(vp);
         puffs_releasenode(pnode);          pool_put(&puffs_pnpool, vp->v_data);
         vp->v_data = NULL;          vp->v_data = NULL;
   
         return;          return;
Line 340  puffs_cookie2pnode(struct puffs_mount *p
Line 297  puffs_cookie2pnode(struct puffs_mount *p
 }  }
   
 /*  /*
  * Make sure root vnode exists and reference it.  Does NOT lock.  
  */  
 static int  
 puffs_makeroot(struct puffs_mount *pmp)  
 {  
         struct vnode *vp;  
         int rv;  
   
         /*  
          * pmp_lock must be held if vref()'ing or vrele()'ing the  
          * root vnode.  the latter is controlled by puffs_inactive().  
          *  
          * pmp_root is set here and cleared in puffs_reclaim().  
          */  
  retry:  
         mutex_enter(&pmp->pmp_lock);  
         vp = pmp->pmp_root;  
         if (vp) {  
                 simple_lock(&vp->v_interlock);  
                 mutex_exit(&pmp->pmp_lock);  
                 if (vget(vp, LK_INTERLOCK) == 0)  
                         return 0;  
         } else  
                 mutex_exit(&pmp->pmp_lock);  
   
         /*  
          * So, didn't have the magic root vnode available.  
          * No matter, grab another an stuff it with the cookie.  
          */  
         if ((rv = puffs_getvnode(pmp->pmp_mp, pmp->pmp_root_cookie,  
             pmp->pmp_root_vtype, pmp->pmp_root_vsize, pmp->pmp_root_rdev, &vp)))  
                 return rv;  
   
         /*  
          * Someone magically managed to race us into puffs_getvnode?  
          * Put our previous new vnode back and retry.  
          */  
         mutex_enter(&pmp->pmp_lock);  
         if (pmp->pmp_root) {  
                 mutex_exit(&pmp->pmp_lock);  
                 puffs_putvnode(vp);  
                 goto retry;  
         }  
   
         /* store cache */  
         vp->v_flag = VROOT;  
         pmp->pmp_root = vp;  
         mutex_exit(&pmp->pmp_lock);  
   
         return 0;  
 }  
   
 /*  
  * Locate the in-kernel vnode based on the cookie received given   * Locate the in-kernel vnode based on the cookie received given
  * from userspace.  Returns a vnode, if found, NULL otherwise.   * from userspace.  Returns a vnode, if found, NULL otherwise.
  * The parameter "lock" control whether to lock the possible or   * The parameter "lock" control whether to lock the possible or
Line 400  puffs_makeroot(struct puffs_mount *pmp)
Line 304  puffs_makeroot(struct puffs_mount *pmp)
  * in situations where we want the vnode but don't care for the   * in situations where we want the vnode but don't care for the
  * vnode lock, e.g. file server issued putpages.   * vnode lock, e.g. file server issued putpages.
  */   */
 int  struct vnode *
 puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock,  puffs_pnode2vnode(struct puffs_mount *pmp, void *cookie, int lock)
         struct vnode **vpp)  
 {  {
         struct puffs_node *pnode;          struct puffs_node *pnode;
         struct vnode *vp;          struct vnode *vp;
         int vgetflags, rv;          int vgetflags;
   
         /*          /*
          * Handle root in a special manner, since we want to make sure           * If we're trying to get the root vnode, return it through
          * pmp_root is properly set.           * puffs_root() to get all the right things set.  Lock must
            * be set, since VFS_ROOT() always locks the returned vnode.
          */           */
         if (cookie == pmp->pmp_root_cookie) {          if (cookie == pmp->pmp_rootcookie) {
                 if ((rv = puffs_makeroot(pmp)))                  if (!lock)
                         return rv;                          return NULL;
                 if (lock)                  if (VFS_ROOT(pmp->pmp_mp, &vp))
                         vn_lock(pmp->pmp_root, LK_EXCLUSIVE | LK_RETRY);                          return NULL;
   
                 *vpp = pmp->pmp_root;                  return vp;
                 return 0;  
         }          }
   
         mutex_enter(&pmp->pmp_lock);          vgetflags = LK_INTERLOCK;
           if (lock)
                   vgetflags |= LK_EXCLUSIVE | LK_RETRY;
   
           simple_lock(&pmp->pmp_lock);
         pnode = puffs_cookie2pnode(pmp, cookie);          pnode = puffs_cookie2pnode(pmp, cookie);
   
         if (pnode == NULL) {          if (pnode == NULL) {
                 mutex_exit(&pmp->pmp_lock);                  simple_unlock(&pmp->pmp_lock);
                 return ENOENT;                  return NULL;
         }          }
   
         vp = pnode->pn_vp;          vp = pnode->pn_vp;
   
         simple_lock(&vp->v_interlock);          simple_lock(&vp->v_interlock);
         mutex_exit(&pmp->pmp_lock);          simple_unlock(&pmp->pmp_lock);
   
         vgetflags = LK_INTERLOCK;          if (vget(vp, vgetflags))
         if (lock)                  return NULL;
                 vgetflags |= LK_EXCLUSIVE | LK_RETRY;  
         if ((rv = vget(vp, vgetflags)))  
                 return rv;  
   
         *vpp = vp;          return vp;
         return 0;  
 }  }
   
 void  void
 puffs_makecn(struct puffs_kcn *pkcn, struct puffs_kcred *pkcr,  puffs_makecn(struct puffs_kcn *pkcn, const struct componentname *cn)
         struct puffs_kcid *pkcid, const struct componentname *cn, int full)  
 {  {
   
         pkcn->pkcn_nameiop = cn->cn_nameiop;          pkcn->pkcn_nameiop = cn->cn_nameiop;
         pkcn->pkcn_flags = cn->cn_flags;          pkcn->pkcn_flags = cn->cn_flags;
         puffs_cidcvt(pkcid, cn->cn_lwp);          pkcn->pkcn_pid = cn->cn_lwp->l_proc->p_pid;
           puffs_credcvt(&pkcn->pkcn_cred, cn->cn_cred);
   
         if (full) {          (void)memcpy(&pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);
                 (void)strcpy(pkcn->pkcn_name, cn->cn_nameptr);          pkcn->pkcn_name[cn->cn_namelen] = '\0';
         } else {  
                 (void)memcpy(pkcn->pkcn_name, cn->cn_nameptr, cn->cn_namelen);  
                 pkcn->pkcn_name[cn->cn_namelen] = '\0';  
         }  
         pkcn->pkcn_namelen = cn->cn_namelen;          pkcn->pkcn_namelen = cn->cn_namelen;
         pkcn->pkcn_consume = 0;  
   
         puffs_credcvt(pkcr, cn->cn_cred);  
 }  }
   
 /*  /*
  * Convert given credentials to struct puffs_kcred for userspace.   * Convert given credentials to struct puffs_cred for userspace.
  */   */
 void  void
 puffs_credcvt(struct puffs_kcred *pkcr, const kauth_cred_t cred)  puffs_credcvt(struct puffs_cred *pcr, const kauth_cred_t cred)
 {  {
   
         memset(pkcr, 0, sizeof(struct puffs_kcred));          memset(pcr, 0, sizeof(struct puffs_cred));
   
         if (cred == NOCRED || cred == FSCRED) {          if (cred == NOCRED || cred == FSCRED) {
                 pkcr->pkcr_type = PUFFCRED_TYPE_INTERNAL;                  pcr->pcr_type = PUFFCRED_TYPE_INTERNAL;
                 if (cred == NOCRED)                  if (cred == NOCRED)
                         pkcr->pkcr_internal = PUFFCRED_CRED_NOCRED;                          pcr->pcr_internal = PUFFCRED_CRED_NOCRED;
                 if (cred == FSCRED)                  if (cred == FSCRED)
                         pkcr->pkcr_internal = PUFFCRED_CRED_FSCRED;                          pcr->pcr_internal = PUFFCRED_CRED_FSCRED;
         } else {          } else {
                 pkcr->pkcr_type = PUFFCRED_TYPE_UUC;                  pcr->pcr_type = PUFFCRED_TYPE_UUC;
                 kauth_cred_to_uucred(&pkcr->pkcr_uuc, cred);                  kauth_cred_to_uucred(&pcr->pcr_uuc, cred);
         }          }
 }  }
   
 void  /*
 puffs_cidcvt(struct puffs_kcid *pkcid, const struct lwp *l)   * Return pid.  In case the operation is coming from within the
    * kernel without any process context, borrow the swapper's pid.
    */
   pid_t
   puffs_lwp2pid(struct lwp *l)
 {  {
   
         if (l) {          return l ? l->l_proc->p_pid : 0;
                 pkcid->pkcid_type = PUFFCID_TYPE_REAL;  
                 pkcid->pkcid_pid = l->l_proc->p_pid;  
                 pkcid->pkcid_lwpid = l->l_lid;  
         } else {  
                 pkcid->pkcid_type = PUFFCID_TYPE_FAKE;  
                 pkcid->pkcid_pid = 0;  
                 pkcid->pkcid_lwpid = 0;  
         }  
 }  }
   
   
 static void  static void
 puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,  puffs_gop_size(struct vnode *vp, off_t size, off_t *eobp,
         int flags)          int flags)
Line 525  puffs_gop_markupdate(struct vnode *vp, i
Line 418  puffs_gop_markupdate(struct vnode *vp, i
 void  void
 puffs_updatenode(struct vnode *vp, int flags)  puffs_updatenode(struct vnode *vp, int flags)
 {  {
         struct puffs_node *pn;  
         struct timespec ts;          struct timespec ts;
           struct puffs_vnreq_setattr *setattr_arg;
   
         if (flags == 0)          if (flags == 0)
                 return;                  return;
   
         pn = VPTOPP(vp);          setattr_arg = malloc(sizeof(struct puffs_vnreq_setattr), M_PUFFS,
               M_NOWAIT | M_ZERO);
           if (setattr_arg == NULL)
                   return; /* 2bad */
   
         nanotime(&ts);          nanotime(&ts);
   
         if (flags & PUFFS_UPDATEATIME) {          VATTR_NULL(&setattr_arg->pvnr_va);
                 pn->pn_mc_atime = ts;          if (flags & PUFFS_UPDATEATIME)
                 pn->pn_stat |= PNODE_METACACHE_ATIME;                  setattr_arg->pvnr_va.va_atime = ts;
         }          if (flags & PUFFS_UPDATECTIME)
         if (flags & PUFFS_UPDATECTIME) {                  setattr_arg->pvnr_va.va_ctime = ts;
                 pn->pn_mc_ctime = ts;          if (flags & PUFFS_UPDATEMTIME)
                 pn->pn_stat |= PNODE_METACACHE_CTIME;                  setattr_arg->pvnr_va.va_mtime = ts;
         }          if (flags & PUFFS_UPDATESIZE)
         if (flags & PUFFS_UPDATEMTIME) {                  setattr_arg->pvnr_va.va_size = vp->v_size;
                 pn->pn_mc_mtime = ts;  
                 pn->pn_stat |= PNODE_METACACHE_MTIME;          setattr_arg->pvnr_pid = 0;
         }          puffs_credcvt(&setattr_arg->pvnr_cred, NOCRED);
         if (flags & PUFFS_UPDATESIZE) {  
                 pn->pn_mc_size = vp->v_size;          /* setattr_arg ownership shifted to callee */
                 pn->pn_stat |= PNODE_METACACHE_SIZE;          puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_SETATTR,
         }              setattr_arg, sizeof(struct puffs_vnreq_setattr), VPTOPNC(vp));
 }  }
   
 void  void
Line 564  puffs_updatevpsize(struct vnode *vp)
Line 461  puffs_updatevpsize(struct vnode *vp)
                 vp->v_size = va.va_size;                  vp->v_size = va.va_size;
 }  }
   
   /*
    * We're dead, kaput, RIP, slightly more than merely pining for the
    * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
    * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
    *
    * Caller must hold puffs spinlock.
    */
 void  void
 puffs_parkdone_asyncbioread(struct puffs_req *preq, void *arg)  puffs_userdead(struct puffs_mount *pmp)
 {  {
         struct puffs_vnreq_read *read_argp = (void *)preq;          struct puffs_park *park;
         struct buf *bp = arg;          struct buf *bp;
         size_t moved;  
           /*
         bp->b_error = preq->preq_rv;           * Mark filesystem status as dying so that operations don't
         if (bp->b_error == 0) {           * attempt to march to userspace any longer.
                 moved = bp->b_bcount - read_argp->pvnr_resid;           */
                 bp->b_resid = read_argp->pvnr_resid;          pmp->pmp_status = PUFFSTAT_DYING;
   
                 memcpy(bp->b_data, read_argp->pvnr_data, moved);          /* and wakeup processes waiting for a reply from userspace */
         } else {          TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) {
                 bp->b_flags |= B_ERROR;                  if (park->park_preq)
                           park->park_preq->preq_rv = ENXIO;
                   TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries);
                   if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) {
                           bp = park->park_bp;
                           bp->b_error = ENXIO;
                           bp->b_flags |= B_ERROR;
                           biodone(bp);
                   } else {
                           wakeup(park);
                   }
         }          }
   
         biodone(bp);          /* wakeup waiters for completion of vfs/vnode requests */
         free(preq, M_PUFFS);          TAILQ_FOREACH(park, &pmp->pmp_req_touser, park_entries) {
                   if (park->park_preq)
                           park->park_preq->preq_rv = ENXIO;
                   TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries);
                   if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) {
                           bp = park->park_bp;
                           bp->b_error = ENXIO;
                           bp->b_flags |= B_ERROR;
                           biodone(bp);
                   } else {
                           wakeup(park);
                   }
           }
 }  }
   
 void  /*
 puffs_parkdone_poll(struct puffs_req *preq, void *arg)   * Converts a non-FAF op to a FAF.  This simply involves making copies
    * of the park and request structures and tagging the request as a FAF.
    * It is safe to block here, since the original op is not a FAF.
    */
   struct puffs_park *
   puffs_reqtofaf(struct puffs_park *ppark)
 {  {
         struct puffs_vnreq_poll *poll_argp = (void *)preq;          struct puffs_park *newpark;
         struct puffs_node *pn = arg;          struct puffs_req *newpreq;
         int revents;  
   
         if (preq->preq_rv == 0)  
                 revents = poll_argp->pvnr_events;  
         else  
                 revents = POLLERR;  
   
         mutex_enter(&pn->pn_mtx);  
         pn->pn_revents |= revents;  
         mutex_exit(&pn->pn_mtx);  
   
         selnotify(&pn->pn_sel, 0);          KASSERT((ppark->park_preq->preq_opclass & PUFFSOPFLAG_FAF) == 0);
         free(preq, M_PUFFS);  
   
         puffs_releasenode(pn);  
 }  
   
 void          MALLOC(newpark, struct puffs_park *, sizeof(struct puffs_park),
 puffs_mp_reference(struct puffs_mount *pmp)              M_PUFFS, M_ZERO | M_WAITOK);
 {          MALLOC(newpreq, struct puffs_req *, sizeof(struct puffs_req),
               M_PUFFS, M_ZERO | M_WAITOK);
   
         KASSERT(mutex_owned(&pmp->pmp_lock));          memcpy(newpark, ppark, sizeof(struct puffs_park));
         pmp->pmp_refcount++;          memcpy(newpreq, ppark->park_preq, sizeof(struct puffs_req));
 }  
   
 void          newpark->park_preq = newpreq;
 puffs_mp_release(struct puffs_mount *pmp)          newpark->park_preq->preq_opclass |= PUFFSOPFLAG_FAF;
 {  
   
         KASSERT(mutex_owned(&pmp->pmp_lock));          return newpark;
         if (--pmp->pmp_refcount == 0)  
                 cv_broadcast(&pmp->pmp_refcount_cv);  
 }  }

Legend:
Removed from v.1.23.2.1  
changed lines
  Added in v.1.24

CVSweb <webmaster@jp.NetBSD.org>