Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <sys/param.h>
#include <sys/sockio.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/systm.h>
#include <sys/protosw.h>
#include <sys/syslog.h>

#include <netinet/in.h>
#include <netinet/tcp.h>

#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vm_zone.h>

#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>

#include <9fs/bitstring.h>
#include <9fs/9p.h>
#include <9fs/9auth.h>
#include <9fs/9fs.h>

vm_zone_t u9fsnode_zone;
static LIST_HEAD(u9fsnodehashhead, u9fsnode) *u9fsnodehashtbl;
static u_long u9fsnodehash;
MALLOC_DEFINE(M_U9FSHASH, "U9FS hash", "U9FS hash tables");

/*
 * Initialize hash links for u9fsnodes
 * and build u9fsnode free list.
 */
void
u9fs_nhinit()
{
  u9fsnode_zone = zinit("U9FSNODE", sizeof(struct u9fsnode), 0, 0, 1);
  u9fsnodehashtbl = phashinit(desiredvnodes, M_U9FSHASH, &u9fsnodehash);
}

/*
 * Look up a vnode/u9fsnode by file handle.
 * Callers must check for mount points!!
 * In all cases, a pointer to a
 * u9fsnode structure is returned.
 */
static int u9fs_node_hash_lock;

int
u9fs_nget(mntp, fh, npp, p)
     struct mount *mntp;
     register u9fsfh_t fh;
     struct u9fsnode **npp;
     struct proc * p;
{
  struct u9fsnode *np;
  struct u9fsnodehashhead *nhpp;
  register struct vnode *vp;
  struct vnode *nvp;
  int error;

  nhpp = U9FSNOHASH(fh);
loop:
  for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
    if (mntp != U9FSTOV(np)->v_mount || fh != np->n_qid.path )
      continue;
    vp = U9FSTOV(np);
    if (vget(vp, LK_EXCLUSIVE, p))
      goto loop;
    *npp = np;
    return(0);
  }
  /*
   * Obtain a lock to prevent a race condition if the getnewvnode()
   * or MALLOC() below happens to block.
   */
  if (u9fs_node_hash_lock) {
    while (u9fs_node_hash_lock) {
      u9fs_node_hash_lock = -1;
      tsleep(&u9fs_node_hash_lock, PVM, "u9fsngt", 0);
    }
    goto loop;
  }
  u9fs_node_hash_lock = 1;

  /*
   * allocate before getnewvnode since doing so afterward
   * might cause a bogus v_data pointer to get dereferenced
   * elsewhere if zalloc should block.
   */
  np = zalloc(u9fsnode_zone);
  
  error = getnewvnode(VT_U9FS, mntp, u9fs_vnodeop_p, &nvp);
  if (error) {
    if (u9fs_node_hash_lock < 0)
      wakeup(&u9fs_node_hash_lock);
    u9fs_node_hash_lock = 0;
    *npp = 0;
    zfree(u9fsnode_zone, np);
    return (error);
  }
  vp = nvp;
  bzero((caddr_t)np, sizeof *np);
  vp->v_data = np;
  np->n_vnode = vp;
  /*
   * Insert the u9fsnode in the hash queue for its new file handle
   */
  LIST_INSERT_HEAD(nhpp, np, n_hash);
  np->n_qid.path = fh;
  np->n_qid.vers = 0; /* not in cache yet */
  np->n_fid = 0; /* should be set by the caller */
  *npp = np;

  if (u9fs_node_hash_lock < 0)
    wakeup(&u9fs_node_hash_lock);
  u9fs_node_hash_lock = 0;

  /*
   * Lock the new u9fsnode.
   */
  vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
  
  return (0);
}