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 u9fsuser_zone;
LIST_HEAD(u9fsuserhashhead, u9fsuser) * u9fsuidhashtbl, * u9fsunamehashtbl;
u_long u9fsuidhash;
u_long u9fsunamehash;
MALLOC_DEFINE(M_U9FSBITS, "U9FS bits", "U9FS tag/fid maps");

static int   u9fs_hashname __P((char * name));

void u9fs_uhinit()
{
  u9fsuser_zone = zinit("U9FSUSER", sizeof(struct u9fsuser), 0, 0, 1);
  u9fsuidhashtbl   = phashinit(U9FS_USER_HASHSIZE, M_U9FSHASH, &u9fsuidhash);
  u9fsunamehashtbl = phashinit(U9FS_USER_HASHSIZE, M_U9FSHASH, &u9fsunamehash);
}

void
u9fs_id_init(bits)
     bitstr_t ** bits;
{
  bit_alloc(*bits, 0x10000, M_U9FSBITS, M_WAITOK);
  bit_nset(*bits, 1, 0xffff);  /* we dont use zero */
}

u_short
u9fs_id_new(bits)
     bitstr_t * bits;
{
  int v;

  bit_ffs(bits, 0x10000, &v);
  if( v < 0 )
    panic("no more u9fs bits!");

  bit_clear(bits, v);
  return ((u_short)v);
}

void
u9fs_id_free(bits, v)
     bitstr_t * bits;
     u_short v;
{
  bit_set(bits, v);
}


static int u9fs_hashname(char * cp)
{
  int h = 0;

  cp[U9FS_NAMELEN-1] = 0;
  do
    h += *cp;
  while ( *cp++ );

  return h;
}

void u9fs_hashuser(uid_t uid, char * name)
{
  int h;
  struct u9fsuser * u9p, *u9p2;
  struct u9fsuserhashhead * u9hp;

  if( u9fs_name2uid(name) != 65534 ) /* already hashed by previous mount */
    return;

  u9p = zalloc(u9fsuser_zone);
  bzero(u9p, sizeof(*u9p));
  u9p->u_uid = uid;
  strncpy(u9p->u_name, name, U9FS_NAMELEN);
  u9hp = & u9fsuidhashtbl[uid % u9fsuidhash];
  LIST_INSERT_HEAD(u9hp, u9p, u_hash);
  
  u9p2 = zalloc(u9fsuser_zone);
  bcopy(u9p, u9p2, sizeof(*u9p));
  h = u9fs_hashname(name);
  u9hp = & u9fsunamehashtbl[h%u9fsunamehash];
  LIST_INSERT_HEAD(u9hp, u9p2, u_hash);  
}

/* name must be at least U9FS_NAMELEN long! */
struct u9fsuser * u9fs_finduser(uid_t uid)
{
  struct u9fsuser * u9p;
  struct u9fsuserhashhead * u9hp;

  u9hp = & u9fsuidhashtbl[uid % u9fsuidhash];
  LIST_FOREACH(u9p, u9hp, u_hash)
    if( u9p->u_uid == uid )
      break;

  return u9p;
}

uid_t u9fs_name2uid(char *name)
{
  struct u9fsuser * u9p;
  struct u9fsuserhashhead * u9hp;
  int h;

  h = u9fs_hashname(name);
  u9hp = & u9fsunamehashtbl[h%u9fsunamehash];
  LIST_FOREACH(u9p, u9hp, u_hash)
    if( strcmp(u9p->u_name, name) == 0 )
      break;

  if( u9p )
    return u9p->u_uid;
  else
    return 65534; /* nobody */
}

/*
 * copies a uio scatter/gather list to an mbuf chain.
 */
int
u9fs_uiotombuf(uiop, mq, siz)
        register struct uio *uiop;
        struct mbuf **mq;
        int siz;
{
  register struct mbuf *m;
  struct mbuf * top, **mp;
  int mlen, len, error = 0;

  mp = & top;
  while(siz) {
    MGET(m, M_WAIT, MT_DATA);
    mlen = MLEN;
    if (siz >= MINCLSIZE) {
      MCLGET(m, M_WAIT);
      if ((m->m_flags & M_EXT))
        mlen = MCLBYTES;
    }
    len = min(mlen, siz);
    error = uiomove(mtod(m, caddr_t), (int)len, uiop);
    siz -= len;
    m->m_len = len;
    *mp = m;
    if (error)
      goto release;
    mp = &m->m_next;
  }
  *mq = top;
  return 0;

 release:
  if( top )
    m_freem(top);

  return error;
}

/*
 * copies mbuf chain to the uio scatter/gather list
 */
int
u9fs_mbuftouio(m, uiop, siz)
     struct mbuf *m;
     register struct uio *uiop;
     int siz;
{
  register char *mbufcp, *uiocp;
  register int xfer, left, len;
  long uiosiz;

  mbufcp = mtod(m, char *);
  len = m->m_len;
  while (siz > 0) {
    if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
      return (EFBIG);
    left = uiop->uio_iov->iov_len;
    uiocp = uiop->uio_iov->iov_base;
    if (left > siz)
      left = siz;
    uiosiz = left;
    while (left > 0) {
      while (len == 0) {
        m = m->m_next;
        if (m == NULL)
          return (EBADRPC);
        mbufcp = mtod(m, caddr_t);
        len = m->m_len;
      }
      xfer = (left > len) ? len : left;
      if (uiop->uio_segflg == UIO_SYSSPACE)
        bcopy(mbufcp, uiocp, xfer);
      else
        copyout(mbufcp, uiocp, xfer);
      left -= xfer;
      len -= xfer;
      mbufcp += xfer;
      uiocp += xfer;
      uiop->uio_offset += xfer;
      uiop->uio_resid -= xfer;
    }
    if (uiop->uio_iov->iov_len <= siz) {
      uiop->uio_iovcnt--;
      uiop->uio_iov++;
    } else {
      uiop->uio_iov->iov_base += uiosiz;
      uiop->uio_iov->iov_len -= uiosiz;
    }
    siz -= uiosiz;
  }
  return (0);
}