[BACK]Return to puffs_msgif.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_msgif.c between version 1.47.2.1 and 1.47.2.2

version 1.47.2.1, 2007/10/25 22:39:57 version 1.47.2.2, 2007/11/13 16:01:44
Line 35  __KERNEL_RCSID(0, "$NetBSD$");
Line 35  __KERNEL_RCSID(0, "$NetBSD$");
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/fstrans.h>  #include <sys/fstrans.h>
 #include <sys/kmem.h>  #include <sys/kmem.h>
   #include <sys/kthread.h>
   #include <sys/lock.h>
 #include <sys/malloc.h>  #include <sys/malloc.h>
 #include <sys/mount.h>  #include <sys/mount.h>
 #include <sys/vnode.h>  #include <sys/namei.h>
 #include <sys/lock.h>  
 #include <sys/proc.h>  #include <sys/proc.h>
   #include <sys/vnode.h>
   
   #include <dev/putter/putter_sys.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>
   
   #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */
   
 /*  /*
  * waitq data structures   * waitq data structures
  */   */
Line 76  struct puffs_msgpark {
Line 82  struct puffs_msgpark {
 #define PARKFLAG_CALL           0x10  #define PARKFLAG_CALL           0x10
 #define PARKFLAG_WANTREPLY      0x20  #define PARKFLAG_WANTREPLY      0x20
   
 static struct pool_cache parkpc;  static pool_cache_t parkpc;
 static struct pool parkpool;  
   
 static int  static int
 makepark(void *arg, void *obj, int flags)  makepark(void *arg, void *obj, int flags)
Line 103  void
Line 108  void
 puffs_msgif_init()  puffs_msgif_init()
 {  {
   
         pool_init(&parkpool, sizeof(struct puffs_msgpark), 0, 0, 0,          parkpc = pool_cache_init(sizeof(struct puffs_msgpark), 0, 0, 0,
             "puffprkl", &pool_allocator_nointr, IPL_NONE);              "puffprkl", NULL, IPL_NONE, makepark, nukepark, NULL);
         pool_cache_init(&parkpc, &parkpool, makepark, nukepark, NULL);  
 }  }
   
 void  void
 puffs_msgif_destroy()  puffs_msgif_destroy()
 {  {
   
         pool_cache_destroy(&parkpc);          pool_cache_destroy(parkpc);
         pool_destroy(&parkpool);  
 }  }
   
 static int alloced;  static int alloced;
Line 123  puffs_msgpark_alloc(int waitok)
Line 126  puffs_msgpark_alloc(int waitok)
 {  {
         struct puffs_msgpark *park;          struct puffs_msgpark *park;
   
         park = pool_cache_get(&parkpc, waitok ? PR_WAITOK : PR_NOWAIT);          park = pool_cache_get(parkpc, waitok ? PR_WAITOK : PR_NOWAIT);
         if (park == NULL)          if (park == NULL)
                 return park;                  return park;
   
Line 161  puffs_msgpark_release1(struct puffs_msgp
Line 164  puffs_msgpark_release1(struct puffs_msgp
                 alloced--;                  alloced--;
                 if (preq)                  if (preq)
                         kmem_free(preq, park->park_maxlen);                          kmem_free(preq, park->park_maxlen);
                 pool_cache_put(&parkpc, park);                  pool_cache_put(parkpc, park);
         }          }
 }  }
 #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)  #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)
Line 385  puffs_msg_errnotify(struct puffs_mount *
Line 388  puffs_msg_errnotify(struct puffs_mount *
 }  }
   
 /*  /*
  * Wait for the userspace ping-pong game in calling process context.   * Wait for the userspace ping-pong game in calling process context,
  *   * unless a FAF / async call, in which case just enqueues the request
  * This unlocks vnodes if they are supplied.  vp1 is the vnode   * and return immediately.
  * before in the locking order, i.e. the one which must be locked  
  * before accessing vp2.  This is done here so that operations are  
  * already ordered in the queue when vnodes are unlocked (I'm not  
  * sure if that's really necessary, but it can't hurt).  Okok, maybe  
  * there's a slight ugly-factor also, but let's not worry about that.  
  */   */
 static int  static int
 touser(struct puffs_mount *pmp, struct puffs_msgpark *park)  touser(struct puffs_mount *pmp, struct puffs_msgpark *park)
Line 417  touser(struct puffs_mount *pmp, struct p
Line 415  touser(struct puffs_mount *pmp, struct p
         preq->preq_lid = l->l_lid;          preq->preq_lid = l->l_lid;
   
         /*          /*
          * To support PCATCH, yet another movie: check if there are signals           * To support cv_sig, yet another movie: check if there are signals
          * pending and we are issueing a non-FAF.  If so, return an error           * pending and we are issueing a non-FAF.  If so, return an error
          * directly UNLESS we are issueing INACTIVE.  In that case, convert           * directly UNLESS we are issueing INACTIVE.  In that case, convert
          * it to a FAF, fire off to the file server and return an error.           * it to a FAF, fire off to the file server and return an error.
Line 491  touser(struct puffs_mount *pmp, struct p
Line 489  touser(struct puffs_mount *pmp, struct p
             preq->preq_opclass, preq->preq_optype, park->park_flags));              preq->preq_opclass, preq->preq_optype, park->park_flags));
   
         cv_broadcast(&pmp->pmp_msg_waiter_cv);          cv_broadcast(&pmp->pmp_msg_waiter_cv);
         selnotify(pmp->pmp_sel, 0);          putter_notify(pmp->pmp_pi);
   
         if ((park->park_flags & PARKFLAG_WANTREPLY)          if ((park->park_flags & PARKFLAG_WANTREPLY)
             && (park->park_flags & PARKFLAG_CALL) == 0) {              && (park->park_flags & PARKFLAG_CALL) == 0) {
Line 556  touser(struct puffs_mount *pmp, struct p
Line 554  touser(struct puffs_mount *pmp, struct p
                         fstrans_start(mp, FSTRANS_NORMAL);                          fstrans_start(mp, FSTRANS_NORMAL);
                         fstrans_done(mp);                          fstrans_done(mp);
                 }                  }
   
         } else {          } else {
                 /*                  /*
                  * Take extra reference for FAF, i.e. don't free us                   * Take extra reference for FAF, i.e. don't free us
Line 590  puffs_msgif_getout(void *this, size_t ma
Line 589  puffs_msgif_getout(void *this, size_t ma
   
         error = 0;          error = 0;
         mutex_enter(&pmp->pmp_lock);          mutex_enter(&pmp->pmp_lock);
           puffs_mp_reference(pmp);
         for (;;) {          for (;;) {
                 /* RIP? */                  /* RIP? */
                 if (pmp->pmp_status != PUFFSTAT_RUNNING) {                  if (pmp->pmp_status != PUFFSTAT_RUNNING) {
Line 616  puffs_msgif_getout(void *this, size_t ma
Line 616  puffs_msgif_getout(void *this, size_t ma
                 }                  }
   
                 park = TAILQ_FIRST(&pmp->pmp_msg_touser);                  park = TAILQ_FIRST(&pmp->pmp_msg_touser);
                   if (park == NULL)
                           continue;
   
                 mutex_enter(&park->park_mtx);                  mutex_enter(&park->park_mtx);
                 puffs_msgpark_reference(park);                  puffs_msgpark_reference(park);
   
Line 627  puffs_msgif_getout(void *this, size_t ma
Line 630  puffs_msgif_getout(void *this, size_t ma
                         puffs_msgpark_release(park);                          puffs_msgpark_release(park);
                         continue;                          continue;
                 }                  }
                   preq = park->park_preq;
   
   #if 0
                 /* check size */                  /* check size */
                 preq = park->park_preq;                  /*
                    * XXX: this check is not valid for now, we don't know
                    * the size of the caller's input buffer.  i.e. this
                    * will most likely go away
                    */
                 if (maxsize < preq->preq_frhdr.pfr_len) {                  if (maxsize < preq->preq_frhdr.pfr_len) {
                         DPRINTF(("buffer too small\n"));                          DPRINTF(("buffer too small\n"));
                         puffs_msgpark_release(park);                          puffs_msgpark_release(park);
                         error = E2BIG;                          error = E2BIG;
                         break;                          break;
                 }                  }
   #endif
   
                 DPRINTF(("returning\n"));                  DPRINTF(("returning\n"));
   
Line 657  puffs_msgif_getout(void *this, size_t ma
Line 667  puffs_msgif_getout(void *this, size_t ma
   
                 break;                  break;
         }          }
           puffs_mp_release(pmp);
         mutex_exit(&pmp->pmp_lock);          mutex_exit(&pmp->pmp_lock);
   
         if (error == 0) {          if (error == 0) {
                 *data = (uint8_t *)preq;                  *data = (uint8_t *)preq;
                 preq->preq_frhdr.pfr_len = park->park_copylen;                  preq->preq_pth.pth_framelen = park->park_copylen;
                 preq->preq_frhdr.pfr_alloclen = park->park_maxlen;                  *dlen = preq->preq_pth.pth_framelen;
                 preq->preq_frhdr.pfr_type = preq->preq_opclass; /* yay! */  
                 *dlen = preq->preq_frhdr.pfr_len;  
                 *parkptr = park;                  *parkptr = park;
         }          }
   
         return error;          return error;
 }  }
   
Line 706  puffs_msgif_releaseout(void *this, void 
Line 715  puffs_msgif_releaseout(void *this, void 
         mutex_exit(&pmp->pmp_lock);          mutex_exit(&pmp->pmp_lock);
 }  }
   
 void  size_t
 puffs_msgif_incoming(void *this, void *buf)  puffs_msgif_waitcount(void *this)
 {  {
         struct puffs_mount *pmp = this;          struct puffs_mount *pmp = this;
         struct puffs_req *preq = buf;          size_t rv;
         struct puffs_frame *pfr = &preq->preq_frhdr;  
           mutex_enter(&pmp->pmp_lock);
           rv = pmp->pmp_msg_touser_count;
           mutex_exit(&pmp->pmp_lock);
   
           return rv;
   }
   
   /*
    * XXX: locking with this one?
    */
   static void
   puffsop_msg(void *this, struct puffs_req *preq)
   {
           struct puffs_mount *pmp = this;
           struct putter_hdr *pth = &preq->preq_pth;
         struct puffs_msgpark *park;          struct puffs_msgpark *park;
         int release, wgone;          int release, wgone;
   
Line 736  puffs_msgif_incoming(void *this, void *b
Line 760  puffs_msgif_incoming(void *this, void *b
   
         mutex_enter(&park->park_mtx);          mutex_enter(&park->park_mtx);
         puffs_msgpark_reference(park);          puffs_msgpark_reference(park);
         if (pfr->pfr_len > park->park_maxlen) {          if (pth->pth_framelen > park->park_maxlen) {
                 DPRINTF(("puffs_msgif_income: invalid buffer length: "                  DPRINTF(("puffs_msgif_income: invalid buffer length: "
                     "%zu (req %" PRIu64 ", \n", pfr->pfr_len, preq->preq_id));                      "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen,
                       preq->preq_id));
                 park->park_preq->preq_rv = EPROTO;                  park->park_preq->preq_rv = EPROTO;
                 cv_signal(&park->park_cv);                  cv_signal(&park->park_cv);
                 puffs_msgpark_release(park);                  puffs_msgpark_release(park);
Line 760  puffs_msgif_incoming(void *this, void *b
Line 785  puffs_msgif_incoming(void *this, void *b
                 if (park->park_flags & PARKFLAG_CALL) {                  if (park->park_flags & PARKFLAG_CALL) {
                         DPRINTF(("puffs_msgif_income: call for %p, arg %p\n",                          DPRINTF(("puffs_msgif_income: call for %p, arg %p\n",
                             park->park_preq, park->park_donearg));                              park->park_preq, park->park_donearg));
                         park->park_done(pmp, buf, park->park_donearg);                          park->park_done(pmp, preq, park->park_donearg);
                         release = 2;                          release = 2;
                 } else {                  } else {
                         /* XXX: yes, I know */                          /* XXX: yes, I know */
                         memcpy(park->park_preq, buf, pfr->pfr_len);                          memcpy(park->park_preq, preq, pth->pth_framelen);
                         release = 1;                          release = 1;
                 }                  }
         }          }
Line 780  puffs_msgif_incoming(void *this, void *b
Line 805  puffs_msgif_incoming(void *this, void *b
 }  }
   
 /*  /*
    * helpers
    */
   static void
   dosuspendresume(void *arg)
   {
           struct puffs_mount *pmp = arg;
           struct mount *mp;
           int rv;
   
           mp = PMPTOMP(pmp);
           /*
            * XXX?  does this really do any good or is it just
            * paranoid stupidity?  or stupid paranoia?
            */
           if (mp->mnt_iflag & IMNT_UNMOUNT) {
                   printf("puffs dosuspendresume(): detected suspend on "
                       "unmounting fs\n");
                   goto out;
           }
   
           /* Do the dance.  Allow only one concurrent suspend */
           rv = vfs_suspend(PMPTOMP(pmp), 1);
           if (rv == 0)
                   vfs_resume(PMPTOMP(pmp));
   
    out:
           mutex_enter(&pmp->pmp_lock);
           KASSERT(pmp->pmp_suspend == 1);
           pmp->pmp_suspend = 0;
           puffs_mp_release(pmp);
           mutex_exit(&pmp->pmp_lock);
   
           kthread_exit(0);
   }
   
   static void
   puffsop_suspend(struct puffs_mount *pmp)
   {
           int rv = 0;
   
           mutex_enter(&pmp->pmp_lock);
           if (pmp->pmp_suspend || pmp->pmp_status != PUFFSTAT_RUNNING) {
                   rv = EBUSY;
           } else {
                   puffs_mp_reference(pmp);
                   pmp->pmp_suspend = 1;
           }
           mutex_exit(&pmp->pmp_lock);
           if (rv)
                   return;
           rv = kthread_create(PRI_NONE, 0, NULL, dosuspendresume,
               pmp, NULL, "puffsusp");
   
           /* XXX: "return" rv */
   }
   
   static int
   puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
   {
           struct vnode *vp;
           voff_t offlo, offhi;
           int rv, flags = 0;
   
           /* XXX: slurry */
           if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) {
                   cache_purgevfs(PMPTOMP(pmp));
                   return 0;
           }
   
           /*
            * Get vnode, don't lock it.  Namecache is protected by its own lock
            * and we have a reference to protect against premature harvesting.
            *
            * The node we want here might be locked and the op is in
            * userspace waiting for us to complete ==> deadlock.  Another
            * reason we need to eventually bump locking to userspace, as we
            * will need to lock the node if we wish to do flushes.
            */
           rv = puffs_cookie2vnode(pmp, pf->pf_cookie, 0, 0, &vp);
           if (rv) {
                   if (rv == PUFFS_NOSUCHCOOKIE)
                           return ENOENT;
                   return rv;
           }
   
           switch (pf->pf_op) {
   #if 0
           /* not quite ready, yet */
           case PUFFS_INVAL_NAMECACHE_NODE:
           struct componentname *pf_cn;
           char *name;
                   /* get comfortab^Wcomponentname */
                   MALLOC(pf_cn, struct componentname *,
                       sizeof(struct componentname), M_PUFFS, M_WAITOK | M_ZERO);
                   memset(pf_cn, 0, sizeof(struct componentname));
                   break;
   
   #endif
           case PUFFS_INVAL_NAMECACHE_DIR:
                   if (vp->v_type != VDIR) {
                           rv = EINVAL;
                           break;
                   }
                   cache_purge1(vp, NULL, PURGE_CHILDREN);
                   break;
   
           case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
                   flags = PGO_FREE;
                   /*FALLTHROUGH*/
           case PUFFS_FLUSH_PAGECACHE_NODE_RANGE:
                   if (flags == 0)
                           flags = PGO_CLEANIT;
   
                   if (pf->pf_end > vp->v_size || vp->v_type != VREG) {
                           rv = EINVAL;
                           break;
                   }
   
                   offlo = trunc_page(pf->pf_start);
                   offhi = round_page(pf->pf_end);
                   if (offhi != 0 && offlo >= offhi) {
                           rv = EINVAL;
                           break;
                   }
   
                   simple_lock(&vp->v_uobj.vmobjlock);
                   rv = VOP_PUTPAGES(vp, offlo, offhi, flags);
                   break;
   
           default:
                   rv = EINVAL;
           }
   
           vrele(vp);
   
           return rv;
   }
   
   int
   puffs_msgif_dispatch(void *this, struct putter_hdr *pth)
   {
           struct puffs_mount *pmp = this;
           struct puffs_req *preq = (struct puffs_req *)pth;
   
           /* XXX: need to send error to userspace */
           if (pth->pth_framelen < sizeof(struct puffs_req))
                   return EINVAL; /* E2SMALL */
   
           switch (PUFFSOP_OPCLASS(preq->preq_opclass)) {
           case PUFFSOP_VN:
           case PUFFSOP_VFS:
                   puffsop_msg(pmp, preq);
                   break;
           case PUFFSOP_FLUSH:
                   if (pth->pth_framelen != sizeof(struct puffs_flush))
                           return EINVAL;
                   puffsop_flush(pmp, (struct puffs_flush *)preq);
                   break;
           case PUFFSOP_SUSPEND:
                   puffsop_suspend(pmp);
                   break;
           default:
                   /* XXX: send error */
                   break;
           }
   
           return 0;
   }
   
   int
   puffs_msgif_close(void *this)
   {
           struct puffs_mount *pmp = this;
           struct mount *mp = PMPTOMP(pmp);
           int gone, rv;
   
           mutex_enter(&pmp->pmp_lock);
           puffs_mp_reference(pmp);
   
           /*
            * Free the waiting callers before proceeding any further.
            * The syncer might be jogging around in this file system
            * currently.  If we allow it to go to the userspace of no
            * return while trying to get the syncer lock, well ...
            * synclk: I feel happy, I feel fine.
            * lockmgr: You're not fooling anyone, you know.
            */
           puffs_userdead(pmp);
   
           /*
            * Make sure someone from puffs_unmount() isn't currently in
            * userspace.  If we don't take this precautionary step,
            * they might notice that the mountpoint has disappeared
            * from under them once they return.  Especially note that we
            * cannot simply test for an unmounter before calling
            * dounmount(), since it might be possible that that particular
            * invocation of unmount was called without MNT_FORCE.  Here we
            * *must* make sure unmount succeeds.  Also, restart is necessary
            * since pmp isn't locked.  We might end up with PUTTER_DEAD after
            * restart and exit from there.
            */
           if (pmp->pmp_unmounting) {
                   cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock);
                   puffs_mp_release(pmp);
                   mutex_exit(&pmp->pmp_lock);
                   DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, "
                       "restart\n", pmp));
                   return ERESTART;
           }
   
           /* Won't access pmp from here anymore */
           puffs_mp_release(pmp);
           mutex_exit(&pmp->pmp_lock);
   
           /*
            * Detach from VFS.  First do necessary XXX-dance (from
            * sys_unmount() & other callers of dounmount()
            *
            * XXX Freeze syncer.  Must do this before locking the
            * mount point.  See dounmount() for details.
            *
            * XXX2: take a reference to the mountpoint before starting to
            * wait for syncer_mutex.  Otherwise the mointpoint can be
            * wiped out while we wait.
            */
           simple_lock(&mp->mnt_slock);
           mp->mnt_wcnt++;
           simple_unlock(&mp->mnt_slock);
   
           mutex_enter(&syncer_mutex);
   
           simple_lock(&mp->mnt_slock);
           mp->mnt_wcnt--;
           if (mp->mnt_wcnt == 0)
                   wakeup(&mp->mnt_wcnt);
           gone = mp->mnt_iflag & IMNT_GONE;
           simple_unlock(&mp->mnt_slock);
           if (gone) {
                   mutex_exit(&syncer_mutex);
                   return 0;
           }
   
           /*
            * microscopic race condition here (although not with the current
            * kernel), but can't really fix it without starting a crusade
            * against vfs_busy(), so let it be, let it be, let it be
            */
   
           /*
            * The only way vfs_busy() will fail for us is if the filesystem
            * is already a goner.
            * XXX: skating on the thin ice of modern calling conventions ...
            */
           if (vfs_busy(mp, 0, 0)) {
                   mutex_exit(&syncer_mutex);
                   return 0;
           }
   
           /*
            * Once we have the mount point, unmount() can't interfere..
            * or at least in theory it shouldn't.  dounmount() reentracy
            * might require some visiting at some point.
            */
           rv = dounmount(mp, MNT_FORCE, curlwp);
           KASSERT(rv == 0);
   
           return 0;
   }
   
   /*
  * We're dead, kaput, RIP, slightly more than merely pining for the   * We're dead, kaput, RIP, slightly more than merely pining for the
  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet   * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!   * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
Line 811  puffs_userdead(struct puffs_mount *pmp)
Line 1106  puffs_userdead(struct puffs_mount *pmp)
                 pmp->pmp_msg_touser_count--;                  pmp->pmp_msg_touser_count--;
   
                 /*                  /*
                  * If the waiter is gone, we may *NOT* access preq anymore.                   * Even though waiters on QUEUE1 are removed in touser()
                    * in case of WAITERGONE, it is still possible for us to
                    * get raced here due to having to retake locks in said
                    * touser().  In the race case simply "ignore" the item
                    * on the queue and move on to the next one.
                  */                   */
                 if (park->park_flags & PARKFLAG_WAITERGONE) {                  if (park->park_flags & PARKFLAG_WAITERGONE) {
                         KASSERT((park->park_flags & PARKFLAG_CALL) == 0);                          KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
                         KASSERT(park->park_flags & PARKFLAG_WANTREPLY);                          KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
                         puffs_msgpark_release(park);                          puffs_msgpark_release(park);
   
                 } else {                  } else {
                         opclass = park->park_preq->preq_opclass;                          opclass = park->park_preq->preq_opclass;
                         park->park_preq->preq_rv = ENXIO;                          park->park_preq->preq_rv = ENXIO;
Line 847  puffs_userdead(struct puffs_mount *pmp)
Line 1147  puffs_userdead(struct puffs_mount *pmp)
                 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);                  TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
                 park->park_flags &= ~PARKFLAG_ONQUEUE2;                  park->park_flags &= ~PARKFLAG_ONQUEUE2;
   
                 /*  
                  * If the waiter is gone, we may *NOT* access preq anymore.  
                  */  
                 if (park->park_flags & PARKFLAG_WAITERGONE) {                  if (park->park_flags & PARKFLAG_WAITERGONE) {
                         KASSERT((park->park_flags & PARKFLAG_CALL) == 0);                          KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
                         puffs_msgpark_release(park);                          puffs_msgpark_release(park);
Line 865  puffs_userdead(struct puffs_mount *pmp)
Line 1162  puffs_userdead(struct puffs_mount *pmp)
                         }                          }
                 }                  }
         }          }
   
           cv_broadcast(&pmp->pmp_msg_waiter_cv);
 }  }

Legend:
Removed from v.1.47.2.1  
changed lines
  Added in v.1.47.2.2

CVSweb <webmaster@jp.NetBSD.org>