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);
}