static int _get_one_file (Path path, char *s, DynStr *ds) { int unique, shared; xpthread_mutex_lock (&path->lock); _count_ioctx (path->ioctx, &shared, &unique); aspf (&ds->s, &ds->len, "%d %d %d %s\n", path->refcount, shared, unique, s); xpthread_mutex_unlock (&path->lock); return 0; }
static int _ioctx_decref (IOCtx ioctx) { int n; xpthread_mutex_lock (&ioctx->lock); n = --ioctx->refcount; xpthread_mutex_unlock (&ioctx->lock); return n; }
/* Clear all state associated with conn out of the srv. * No more I/O is possible; we have disassociated the trans from the conn. */ static void np_conn_reset(Npconn *conn) { int reqslen; Npsrv *srv; Npreq *preqs, **reqs; xpthread_mutex_lock(&conn->lock); conn->resetting = 1; xpthread_mutex_unlock(&conn->lock); xpthread_mutex_lock(&conn->srv->lock); srv = conn->srv; preqs = _get_waiting_reqs (conn); if (_get_working_reqs (conn, &reqs, &reqslen) < 0) { xpthread_mutex_unlock(&conn->srv->lock); goto error; } xpthread_mutex_unlock(&conn->srv->lock); _flush_waiting_reqs (preqs); _flush_working_reqs (reqs, reqslen); xpthread_mutex_lock(&srv->lock); while (_count_working_reqs (conn, 1) > 0) xpthread_cond_wait(&conn->resetcond, &srv->lock); xpthread_mutex_unlock(&srv->lock); xpthread_mutex_lock(&conn->lock); if (conn->fidpool) { np_fidpool_destroy(conn->fidpool); conn->fidpool = NULL; } conn->resetting = 0; xpthread_mutex_unlock(&conn->lock); _free_working_reqs (reqs, reqslen); return; error: return; }
/* increment nonce and return new value */ uint32_t nonce32(void) { #ifdef HAVE_ATOMIC_H return atomic_add_32_nv(&seq, 2); #else xpthread_mutex_lock(&seq_mutex); seq += 2; xpthread_mutex_unlock(&seq_mutex); return seq; #endif /* else !HAVE_ATOMIC_H */ }
/* refcount++ */ Npfid * np_fid_incref (Npfid *f) { NP_ASSERT(f != NULL); NP_ASSERT(f->magic == FID_MAGIC); xpthread_mutex_lock (&f->lock); f->refcount++; xpthread_mutex_unlock (&f->lock); return f; }
void np_usercache_flush (Npsrv *srv) { Npusercache *uc = srv->usercache; Npuser *u; xpthread_mutex_lock (&uc->lock); u = uc->users; while (u) u = _usercache_del (srv, NULL, u); xpthread_mutex_unlock (&uc->lock); }
void np_conn_decref(Npconn *conn) { xpthread_mutex_lock(&conn->lock); assert(conn->refcount > 0); conn->refcount--; if (conn->refcount) { xpthread_mutex_unlock(&conn->lock); return; } if (conn->fidpool) { np_fidpool_destroy(conn->fidpool); conn->fidpool = NULL; } xpthread_mutex_unlock(&conn->lock); pthread_mutex_destroy(&conn->lock); pthread_cond_destroy(&conn->resetcond); free(conn); }
static void np_respond(Nptpool *tp, Npreq *req, Npfcall *rc) { xpthread_mutex_lock(&tp->srv->lock); np_srv_remove_workreq(tp, req); xpthread_mutex_unlock(&tp->srv->lock); xpthread_mutex_lock(&req->lock); req->rcall = rc; if (req->rcall) { np_set_tag(req->rcall, req->tag); if (req->fid != NULL) { np_fid_decref(req->fid); req->fid = NULL; } np_conn_respond(req); } xpthread_mutex_unlock(&req->lock); np_req_unref(req); }
void np_fid_decref_bynum (Npconn *conn, u32 fid) { Npfidpool *pool = conn->fidpool; int hash = fid % pool->size; int refcount = 0; Npfid *f; xpthread_mutex_lock (&pool->lock); if ((f = _lookup_fid (&pool->htable[hash], fid))) { xpthread_mutex_lock (&f->lock); refcount = --f->refcount; xpthread_mutex_unlock (&f->lock); if (refcount == 0) { _unlink_fid (&pool->htable[hash], f); } } xpthread_mutex_unlock (&pool->lock); if (f && refcount == 0) (void) _destroy_fid (f); }
/* Find a fid, then refcount++ */ Npfid * np_fid_find (Npconn *conn, u32 fid) { Npfidpool *pool = conn->fidpool; int hash = fid % pool->size; Npfid *f; xpthread_mutex_lock (&pool->lock); if ((f = _lookup_fid (&pool->htable[hash], fid))) np_fid_incref (f); xpthread_mutex_unlock (&pool->lock); return f; }
int np_srv_add_conn(Npsrv *srv, Npconn *conn) { xpthread_mutex_lock(&srv->lock); conn->srv = srv; conn->next = srv->conns; srv->conns = conn; srv->conncount++; srv->connhistory++; xpthread_cond_signal(&srv->conncountcond); xpthread_mutex_unlock(&srv->lock); return 1; }
static char * _ctl_get_tpools (void *a) { Npsrv *srv = (Npsrv *)a; Nptpool *tp; Npreq *req; char *s = NULL; int n, len = 0; xpthread_mutex_lock(&srv->lock); for (tp = srv->tpool; tp != NULL; tp = tp->next) { xpthread_mutex_lock(&tp->lock); xpthread_mutex_lock(&tp->stats.lock); tp->stats.name = tp->name; tp->stats.numfids = tp->refcount; tp->stats.numreqs = 0; for (req = tp->reqs_first; req != NULL; req = req->next) tp->stats.numreqs++; for (req = tp->workreqs; req != NULL; req = req->next) tp->stats.numreqs++; n = np_encode_tpools_str (&s, &len, &tp->stats); xpthread_mutex_unlock(&tp->stats.lock); xpthread_mutex_unlock(&tp->lock); if (n < 0) { np_uerror (ENOMEM); goto error_unlock; } } xpthread_mutex_unlock(&srv->lock); return s; error_unlock: xpthread_mutex_unlock(&srv->lock); if (s) free(s); return NULL; }
Npuser * np_uname2user (Npsrv *srv, char *uname) { Npusercache *uc = srv->usercache; Npuser *u = NULL; xpthread_mutex_lock (&uc->lock); if (!(u = _usercache_lookup (srv, uname, P9_NONUNAME))) if ((u = _real_lookup_byname (srv, uname))) _usercache_add (srv, u); xpthread_mutex_unlock (&uc->lock); if (u) np_user_incref (u); return u; }
Npuser * np_uid2user (Npsrv *srv, uid_t uid) { Npusercache *uc = srv->usercache; Npuser *u = NULL; xpthread_mutex_lock (&uc->lock); if (!(u = _usercache_lookup (srv, NULL, uid))) if ((u = _real_lookup_byuid (srv, uid))) _usercache_add (srv, u); xpthread_mutex_unlock (&uc->lock); if (u) np_user_incref (u); return u; }
void np_conn_respond(Npreq *req) { int n; Npconn *conn = req->conn; Npsrv *srv = conn->srv; Npfcall *rc = req->rcall; _debug_trace (srv, rc); xpthread_mutex_lock(&conn->wlock); n = np_trans_send(conn->trans, rc); xpthread_mutex_unlock(&conn->wlock); if (n < 0) np_logerr (srv, "send to '%s'", conn->client_id); }
void np_user_decref(Npuser *u) { int n; if (!u) return; xpthread_mutex_lock (&u->lock); n = --u->refcount; xpthread_mutex_unlock (&u->lock); if (n > 0) return; _free_user (u); }
int np_fidpool_count(Npfidpool *pool) { int i; Npfid *f; int count = 0; xpthread_mutex_lock(&pool->lock); for(i = 0; i < pool->size; i++) { for (f = pool->htable[i]; f != NULL; f = f->next) { NP_ASSERT(f->magic == FID_MAGIC); count++; } } xpthread_mutex_unlock(&pool->lock); return count; }
static int npc_rpc(Npcfsys *fs, Npfcall *tc, Npfcall **rcp) { Npfcall *rc = NULL; u16 tag = P9_NOTAG; int n, ret = -1; if (!fs->trans) { np_uerror(ECONNABORTED); goto done; } if (tc->type != P9_TVERSION) tag = npc_get_id(fs->tagpool); np_set_tag(tc, tag); xpthread_mutex_lock(&fs->lock); n = np_trans_send (fs->trans, tc); if (n >= 0) n = np_trans_recv(fs->trans, &rc, fs->msize); xpthread_mutex_unlock(&fs->lock); if (n < 0) goto done; if (rc == NULL) { np_uerror (EPROTO); /* premature EOF */ goto done; } if (tc->tag != rc->tag) { np_uerror (EPROTO); /* unmatched response */ goto done; } if (rc->type == P9_RLERROR) { np_uerror (rc->u.rlerror.ecode); goto done; } *rcp = rc; ret = 0; done: if (tag != P9_NOTAG) npc_put_id(fs->tagpool, tag); if (ret < 0 && rc != NULL) free (rc); return ret; }
int np_srv_add_conn(Npsrv *srv, Npconn *conn) { int ret; ret = 0; xpthread_mutex_lock(&srv->lock); np_conn_incref(conn); conn->srv = srv; conn->next = srv->conns; srv->conns = conn; ret = 1; srv->conncount++; srv->connhistory++; xpthread_cond_signal(&srv->conncountcond); xpthread_mutex_unlock(&srv->lock); return ret; }
void np_srv_add_req(Npsrv *srv, Npreq *req) { Nptpool *tp = NULL; if (req->fid) tp = req->fid->tpool; if (!tp) tp = srv->tpool; xpthread_mutex_lock(&tp->lock); req->prev = tp->reqs_last; if (tp->reqs_last) tp->reqs_last->next = req; tp->reqs_last = req; if (!tp->reqs_first) tp->reqs_first = req; xpthread_mutex_unlock(&tp->lock); xpthread_cond_signal(&tp->reqcond); }
int ioctx_close (Npfid *fid, int seterrno) { Fid *f = fid->aux; int n; int rc = 0; NP_ASSERT (f->ioctx != NULL); xpthread_mutex_lock (&f->path->lock); n = _ioctx_decref (f->ioctx); if (n == 0) _unlink_ioctx (&f->path->ioctx, f->ioctx); xpthread_mutex_unlock (&f->path->lock); if (n == 0) rc = _ioctx_close_destroy (f->ioctx, seterrno); f->ioctx = NULL; return rc; }
int np_fidpool_destroy(Npfidpool *pool) { int i; Npfid *f; int unclunked = 0; xpthread_mutex_lock(&pool->lock); for(i = 0; i < pool->size; i++) { f = pool->htable[i]; while (f != NULL) { f = _destroy_fid (f); unclunked++; } } xpthread_mutex_unlock (&pool->lock); pthread_mutex_destroy (&pool->lock); free(pool); return unclunked; }
u32 npc_get_id(Npcpool *p) { int i, n; u32 ret; u8 *pt; xpthread_mutex_lock(&p->lock); again: for(i = 0; i < p->msize; i++) if (p->map[i] != 0xFF) break; if (i>=p->msize && p->msize*8<p->maxid) { n = p->msize + 32; if (n*8 > p->maxid) n = p->maxid/8 + 1; pt = realloc(p->map, n); if (pt) { memset(pt + p->msize, 0, n - p->msize); p->map = pt; i = p->msize; p->msize = n; } } if (i >= p->msize) { pthread_cond_wait(&p->cond, &p->lock); goto again; } ret = m2id[p->map[i]]; p->map[i] |= 1 << ret; ret += i * 8; xpthread_mutex_unlock(&p->lock); return ret; }
Npreq *np_req_alloc(Npconn *conn, Npfcall *tc) { Npreq *req; req = NULL; xpthread_mutex_lock(&reqpool.lock); if (reqpool.reqlist) { req = reqpool.reqlist; reqpool.reqlist = req->next; reqpool.reqnum--; } xpthread_mutex_unlock(&reqpool.lock); if (!req) { req = malloc(sizeof(*req)); if (!req) return NULL; } np_conn_incref(conn); pthread_mutex_init(&req->lock, NULL); req->refcount = 1; req->conn = conn; req->tag = tc->tag; req->tcall = tc; req->rcall = NULL; req->responded = 0; req->flushreq = NULL; req->next = NULL; req->prev = NULL; req->wthread = NULL; req->fid = NULL; np_preprocess_request (req); /* assigns req->fid */ return req; }
void np_tpool_select (Npreq *req) { Npsrv *srv = req->conn->srv; Nptpool *tp = NULL; NP_ASSERT (srv->tpool != NULL); if (!req->fid || req->fid->tpool) return; xpthread_mutex_lock (&srv->lock); if ((srv->flags & SRV_FLAGS_TPOOL_SINGLE) || !req->fid->aname || *req->fid->aname != '/') { tp = srv->tpool; } if (!tp) { for (tp = srv->tpool; tp != NULL; tp = tp->next) { if (!strcmp (req->fid->aname, tp->name)) break; } } if (!tp) { tp = np_tpool_create(srv, req->fid->aname); if (tp) { NP_ASSERT (srv->tpool); /* default tpool */ tp->next = srv->tpool->next; srv->tpool->next = tp; } else np_logerr (srv, "np_tpool_create %s", req->fid->aname); } if (tp) { np_tpool_incref (tp); req->fid->tpool = tp; } xpthread_mutex_unlock (&srv->lock); }
/* Per-connection read thread. */ static void * np_conn_read_proc(void *a) { int i, n, size; Npsrv *srv; Npconn *conn = (Npconn *)a; Nptrans *trans; Npreq *req; Npfcall *fc, *fc1; pthread_detach(pthread_self()); np_conn_incref(conn); srv = conn->srv; fc = _alloc_npfcall(conn->msize); n = 0; while (fc && conn->trans && (i = np_trans_read(conn->trans, fc->pkt + n, conn->msize - n)) > 0) { n += i; again: size = np_peek_size (fc->pkt, n); if (size == 0 || n < size) continue; /* Corruption on the transport, unhandled op, etc. * is fatal to the connection. We could consider returning * an error to the client here. However, various kernels * may not handle that well, depending on where it happens. */ if (!np_deserialize(fc, fc->pkt)) { _debug_trace (srv, fc); np_logerr (srv, "protocol error - " "dropping connection to '%s'", conn->client_id); break; } if ((srv->flags & SRV_FLAGS_DEBUG_9PTRACE)) _debug_trace (srv, fc); /* Replace fc, and copy any data past the current packet * to the replacement. */ fc1 = _alloc_npfcall(conn->msize); if (!fc1) { np_logerr (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); break; } if (n > size) memmove(fc1->pkt, fc->pkt + size, n - size); n -= size; /* Encapsulate fc in a request and hand to srv worker threads. * In np_req_alloc, req->fid is looked up/initialized. */ req = np_req_alloc(conn, fc); if (!req) { np_logerr (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); break; } np_srv_add_req(srv, req); xpthread_mutex_lock(&conn->lock); conn->reqs_in++; xpthread_mutex_unlock(&conn->lock); fc = fc1; if (n > 0) goto again; } /* Just got EOF on read, or some other fatal error for the * connection like out of memory. */ xpthread_mutex_lock(&conn->lock); trans = conn->trans; conn->trans = NULL; if (fc) _free_npfcall(fc); xpthread_mutex_unlock(&conn->lock); np_srv_remove_conn(conn->srv, conn); np_conn_reset(conn); if (trans) np_trans_destroy(trans); np_conn_decref(conn); return NULL; }
/* Per-connection read thread. */ static void * np_conn_read_proc(void *a) { Npconn *conn = (Npconn *)a; Npsrv *srv = conn->srv; Npreq *req; Npfcall *fc; pthread_detach(pthread_self()); for (;;) { if (np_trans_recv(conn->trans, &fc, conn->msize) < 0) { np_logerr (srv, "recv error - " "dropping connection to '%s'", conn->client_id); break; } if (!fc) /* EOF */ break; _debug_trace (srv, fc); /* Encapsulate fc in a request and hand to srv worker threads. * In np_req_alloc, req->fid is looked up/initialized. */ req = np_req_alloc(conn, fc); if (!req) { np_logmsg (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); free (fc); break; } /* Enqueue request for processing by next available worker * thread, except P9_TFLUSH which is handled immediately. */ if (fc->type == P9_TFLUSH) { if (np_flush (req, fc)) { np_req_respond_flush (req); np_req_unref(req); } xpthread_mutex_lock (&srv->lock); srv->tpool->stats.nreqs[P9_TFLUSH]++; xpthread_mutex_unlock (&srv->lock); } else { xpthread_mutex_lock(&srv->lock); np_srv_add_req(srv, req); xpthread_mutex_unlock(&srv->lock); } } /* Just got EOF on read, or some other fatal error for the * connection like out of memory. */ np_conn_flush (conn); xpthread_mutex_lock(&conn->lock); while (conn->refcount > 0) xpthread_cond_wait(&conn->refcond, &conn->lock); xpthread_mutex_unlock(&conn->lock); np_conn_destroy(conn); return NULL; }
Npfcall* np_flush(Npreq *req, Npfcall *tc) { u16 oldtag = tc->u.tflush.oldtag; Npreq *creq = NULL; Npconn *conn = req->conn; Npfcall *ret = NULL; Nptpool *tp; xpthread_mutex_lock(&conn->srv->lock); // check pending requests for (tp = conn->srv->tpool; tp != NULL; tp = tp->next) { xpthread_mutex_lock(&tp->lock); for(creq = tp->reqs_first; creq != NULL; creq = creq->next) { if (creq->conn==conn && creq->tag==oldtag) { np_srv_remove_req(tp, creq); xpthread_mutex_lock(&creq->lock); np_conn_respond(creq); /* doesn't send anything */ xpthread_mutex_unlock(&creq->lock); np_req_unref(creq); ret = np_create_rflush(); creq = NULL; xpthread_mutex_unlock(&tp->lock); goto done; } } xpthread_mutex_unlock(&tp->lock); } // check working requests for (tp = conn->srv->tpool; tp != NULL; tp = tp->next) { xpthread_mutex_lock(&tp->lock); creq = tp->workreqs; while (creq != NULL) { if (creq->conn==conn && creq->tag==oldtag) { np_req_ref(creq); xpthread_mutex_lock(&creq->lock); req->flushreq = creq->flushreq; creq->flushreq = req; xpthread_mutex_unlock(&creq->lock); xpthread_mutex_unlock(&tp->lock); goto done; } creq = creq->next; } xpthread_mutex_unlock(&tp->lock); } // if not found, return P9_RFLUSH if (!creq) ret = np_create_rflush(); done: xpthread_mutex_unlock(&conn->srv->lock); // if working request found, try to flush it if (creq && req->conn->srv->flush) { (*req->conn->srv->flush)(creq); np_req_unref(creq); } return ret; }
static Npfcall* np_process_request(Npreq *req, Npstats *stats) { Npfcall *rc = NULL; Npfcall *tc = req->tcall; int ecode, valid_op = 1; u64 rbytes = 0, wbytes = 0; np_uerror(0); switch (tc->type) { case P9_TSTATFS: rc = np_statfs(req, tc); break; case P9_TLOPEN: rc = np_lopen(req, tc); break; case P9_TLCREATE: rc = np_lcreate(req, tc); break; case P9_TSYMLINK: rc = np_symlink(req, tc); break; case P9_TMKNOD: rc = np_mknod(req, tc); break; case P9_TRENAME: rc = np_rename(req, tc); break; case P9_TREADLINK: rc = np_readlink(req, tc); break; case P9_TGETATTR: rc = np_getattr(req, tc); break; case P9_TSETATTR: rc = np_setattr(req, tc); break; case P9_TXATTRWALK: rc = np_xattrwalk(req, tc); break; case P9_TXATTRCREATE: rc = np_xattrcreate(req, tc); break; case P9_TREADDIR: rc = np_readdir(req, tc); break; case P9_TFSYNC: rc = np_fsync(req, tc); break; case P9_TLOCK: rc = np_lock(req, tc); break; case P9_TGETLOCK: rc = np_getlock(req, tc); break; case P9_TLINK: rc = np_link(req, tc); break; case P9_TMKDIR: rc = np_mkdir(req, tc); break; case P9_TVERSION: rc = np_version(req, tc); break; case P9_TAUTH: rc = np_auth(req, tc); break; case P9_TATTACH: rc = np_attach(req, tc); break; case P9_TFLUSH: rc = np_flush(req, tc); break; case P9_TWALK: rc = np_walk(req, tc); break; case P9_TREAD: rc = np_read(req, tc); rbytes = rc->u.rread.count; break; case P9_TWRITE: rc = np_write(req, tc); wbytes = rc->u.rwrite.count; break; case P9_TCLUNK: rc = np_clunk(req, tc); break; case P9_TREMOVE: rc = np_remove(req, tc); break; default: /* N.B. shouldn't get here - unhandled ops are * caught in np_deserialize (). */ np_uerror(ENOSYS); valid_op = 0; break; } if ((ecode = np_rerror())) { if (rc) free(rc); rc = np_create_rlerror(ecode); } if (valid_op) { xpthread_mutex_lock (&stats->lock); stats->rbytes += rbytes; stats->wbytes += wbytes; stats->nreqs[tc->type]++; xpthread_mutex_unlock (&stats->lock); } return rc; }