|
@@ -231,144 +231,170 @@ free_and_return:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static struct p9_fcall *p9_fcall_alloc(int alloc_msize)
|
|
|
+static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
|
|
|
+ int alloc_msize)
|
|
|
{
|
|
|
- struct p9_fcall *fc;
|
|
|
- fc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, GFP_NOFS);
|
|
|
- if (!fc)
|
|
|
- return NULL;
|
|
|
+ if (likely(c->fcall_cache) && alloc_msize == c->msize) {
|
|
|
+ fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS);
|
|
|
+ fc->cache = c->fcall_cache;
|
|
|
+ } else {
|
|
|
+ fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
|
|
|
+ fc->cache = NULL;
|
|
|
+ }
|
|
|
+ if (!fc->sdata)
|
|
|
+ return -ENOMEM;
|
|
|
fc->capacity = alloc_msize;
|
|
|
- fc->sdata = (char *) fc + sizeof(struct p9_fcall);
|
|
|
- return fc;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void p9_fcall_fini(struct p9_fcall *fc)
|
|
|
+{
|
|
|
+ /* sdata can be NULL for interrupted requests in trans_rdma,
|
|
|
+ * and kmem_cache_free does not do NULL-check for us
|
|
|
+ */
|
|
|
+ if (unlikely(!fc->sdata))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (fc->cache)
|
|
|
+ kmem_cache_free(fc->cache, fc->sdata);
|
|
|
+ else
|
|
|
+ kfree(fc->sdata);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(p9_fcall_fini);
|
|
|
+
|
|
|
+static struct kmem_cache *p9_req_cache;
|
|
|
|
|
|
/**
|
|
|
- * p9_tag_alloc - lookup/allocate a request by tag
|
|
|
- * @c: client session to lookup tag within
|
|
|
- * @tag: numeric id for transaction
|
|
|
- *
|
|
|
- * this is a simple array lookup, but will grow the
|
|
|
- * request_slots as necessary to accommodate transaction
|
|
|
- * ids which did not previously have a slot.
|
|
|
- *
|
|
|
- * this code relies on the client spinlock to manage locks, its
|
|
|
- * possible we should switch to something else, but I'd rather
|
|
|
- * stick with something low-overhead for the common case.
|
|
|
+ * p9_req_alloc - Allocate a new request.
|
|
|
+ * @c: Client session.
|
|
|
+ * @type: Transaction type.
|
|
|
+ * @max_size: Maximum packet size for this request.
|
|
|
*
|
|
|
+ * Context: Process context.
|
|
|
+ * Return: Pointer to new request.
|
|
|
*/
|
|
|
-
|
|
|
static struct p9_req_t *
|
|
|
-p9_tag_alloc(struct p9_client *c, u16 tag, unsigned int max_size)
|
|
|
+p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
|
|
|
{
|
|
|
- unsigned long flags;
|
|
|
- int row, col;
|
|
|
- struct p9_req_t *req;
|
|
|
+ struct p9_req_t *req = kmem_cache_alloc(p9_req_cache, GFP_NOFS);
|
|
|
int alloc_msize = min(c->msize, max_size);
|
|
|
+ int tag;
|
|
|
|
|
|
- /* This looks up the original request by tag so we know which
|
|
|
- * buffer to read the data into */
|
|
|
- tag++;
|
|
|
-
|
|
|
- if (tag >= c->max_tag) {
|
|
|
- spin_lock_irqsave(&c->lock, flags);
|
|
|
- /* check again since original check was outside of lock */
|
|
|
- while (tag >= c->max_tag) {
|
|
|
- row = (tag / P9_ROW_MAXTAG);
|
|
|
- c->reqs[row] = kcalloc(P9_ROW_MAXTAG,
|
|
|
- sizeof(struct p9_req_t), GFP_ATOMIC);
|
|
|
-
|
|
|
- if (!c->reqs[row]) {
|
|
|
- pr_err("Couldn't grow tag array\n");
|
|
|
- spin_unlock_irqrestore(&c->lock, flags);
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
- for (col = 0; col < P9_ROW_MAXTAG; col++) {
|
|
|
- req = &c->reqs[row][col];
|
|
|
- req->status = REQ_STATUS_IDLE;
|
|
|
- init_waitqueue_head(&req->wq);
|
|
|
- }
|
|
|
- c->max_tag += P9_ROW_MAXTAG;
|
|
|
- }
|
|
|
- spin_unlock_irqrestore(&c->lock, flags);
|
|
|
- }
|
|
|
- row = tag / P9_ROW_MAXTAG;
|
|
|
- col = tag % P9_ROW_MAXTAG;
|
|
|
-
|
|
|
- req = &c->reqs[row][col];
|
|
|
- if (!req->tc)
|
|
|
- req->tc = p9_fcall_alloc(alloc_msize);
|
|
|
- if (!req->rc)
|
|
|
- req->rc = p9_fcall_alloc(alloc_msize);
|
|
|
- if (!req->tc || !req->rc)
|
|
|
- goto grow_failed;
|
|
|
+ if (!req)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- p9pdu_reset(req->tc);
|
|
|
- p9pdu_reset(req->rc);
|
|
|
+ if (p9_fcall_init(c, &req->tc, alloc_msize))
|
|
|
+ goto free_req;
|
|
|
+ if (p9_fcall_init(c, &req->rc, alloc_msize))
|
|
|
+ goto free;
|
|
|
|
|
|
- req->tc->tag = tag-1;
|
|
|
+ p9pdu_reset(&req->tc);
|
|
|
+ p9pdu_reset(&req->rc);
|
|
|
req->status = REQ_STATUS_ALLOC;
|
|
|
+ init_waitqueue_head(&req->wq);
|
|
|
+ INIT_LIST_HEAD(&req->req_list);
|
|
|
+
|
|
|
+ idr_preload(GFP_NOFS);
|
|
|
+ spin_lock_irq(&c->lock);
|
|
|
+ if (type == P9_TVERSION)
|
|
|
+ tag = idr_alloc(&c->reqs, req, P9_NOTAG, P9_NOTAG + 1,
|
|
|
+ GFP_NOWAIT);
|
|
|
+ else
|
|
|
+ tag = idr_alloc(&c->reqs, req, 0, P9_NOTAG, GFP_NOWAIT);
|
|
|
+ req->tc.tag = tag;
|
|
|
+ spin_unlock_irq(&c->lock);
|
|
|
+ idr_preload_end();
|
|
|
+ if (tag < 0)
|
|
|
+ goto free;
|
|
|
+
|
|
|
+ /* Init ref to two because in the general case there is one ref
|
|
|
+ * that is put asynchronously by a writer thread, one ref
|
|
|
+ * temporarily given by p9_tag_lookup and put by p9_client_cb
|
|
|
+ * in the recv thread, and one ref put by p9_tag_remove in the
|
|
|
+ * main thread. The only exception is virtio that does not use
|
|
|
+ * p9_tag_lookup but does not have a writer thread either
|
|
|
+ * (the write happens synchronously in the request/zc_request
|
|
|
+ * callback), so p9_client_cb eats the second ref there
|
|
|
+ * as the pointer is duplicated directly by virtqueue_add_sgs()
|
|
|
+ */
|
|
|
+ refcount_set(&req->refcount.refcount, 2);
|
|
|
|
|
|
return req;
|
|
|
|
|
|
-grow_failed:
|
|
|
- pr_err("Couldn't grow tag array\n");
|
|
|
- kfree(req->tc);
|
|
|
- kfree(req->rc);
|
|
|
- req->tc = req->rc = NULL;
|
|
|
+free:
|
|
|
+ p9_fcall_fini(&req->tc);
|
|
|
+ p9_fcall_fini(&req->rc);
|
|
|
+free_req:
|
|
|
+ kmem_cache_free(p9_req_cache, req);
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * p9_tag_lookup - lookup a request by tag
|
|
|
- * @c: client session to lookup tag within
|
|
|
- * @tag: numeric id for transaction
|
|
|
+ * p9_tag_lookup - Look up a request by tag.
|
|
|
+ * @c: Client session.
|
|
|
+ * @tag: Transaction ID.
|
|
|
*
|
|
|
+ * Context: Any context.
|
|
|
+ * Return: A request, or %NULL if there is no request with that tag.
|
|
|
*/
|
|
|
-
|
|
|
struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
|
|
|
{
|
|
|
- int row, col;
|
|
|
-
|
|
|
- /* This looks up the original request by tag so we know which
|
|
|
- * buffer to read the data into */
|
|
|
- tag++;
|
|
|
-
|
|
|
- if (tag >= c->max_tag)
|
|
|
- return NULL;
|
|
|
+ struct p9_req_t *req;
|
|
|
|
|
|
- row = tag / P9_ROW_MAXTAG;
|
|
|
- col = tag % P9_ROW_MAXTAG;
|
|
|
+ rcu_read_lock();
|
|
|
+again:
|
|
|
+ req = idr_find(&c->reqs, tag);
|
|
|
+ if (req) {
|
|
|
+ /* We have to be careful with the req found under rcu_read_lock
|
|
|
+ * Thanks to SLAB_TYPESAFE_BY_RCU we can safely try to get the
|
|
|
+ * ref again without corrupting other data, then check again
|
|
|
+ * that the tag matches once we have the ref
|
|
|
+ */
|
|
|
+ if (!p9_req_try_get(req))
|
|
|
+ goto again;
|
|
|
+ if (req->tc.tag != tag) {
|
|
|
+ p9_req_put(req);
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rcu_read_unlock();
|
|
|
|
|
|
- return &c->reqs[row][col];
|
|
|
+ return req;
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_tag_lookup);
|
|
|
|
|
|
/**
|
|
|
- * p9_tag_init - setup tags structure and contents
|
|
|
- * @c: v9fs client struct
|
|
|
- *
|
|
|
- * This initializes the tags structure for each client instance.
|
|
|
+ * p9_tag_remove - Remove a tag.
|
|
|
+ * @c: Client session.
|
|
|
+ * @r: Request of reference.
|
|
|
*
|
|
|
+ * Context: Any context.
|
|
|
*/
|
|
|
+static int p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ u16 tag = r->tc.tag;
|
|
|
+
|
|
|
+ p9_debug(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
|
|
|
+ spin_lock_irqsave(&c->lock, flags);
|
|
|
+ idr_remove(&c->reqs, tag);
|
|
|
+ spin_unlock_irqrestore(&c->lock, flags);
|
|
|
+ return p9_req_put(r);
|
|
|
+}
|
|
|
|
|
|
-static int p9_tag_init(struct p9_client *c)
|
|
|
+static void p9_req_free(struct kref *ref)
|
|
|
{
|
|
|
- int err = 0;
|
|
|
+ struct p9_req_t *r = container_of(ref, struct p9_req_t, refcount);
|
|
|
+ p9_fcall_fini(&r->tc);
|
|
|
+ p9_fcall_fini(&r->rc);
|
|
|
+ kmem_cache_free(p9_req_cache, r);
|
|
|
+}
|
|
|
|
|
|
- c->tagpool = p9_idpool_create();
|
|
|
- if (IS_ERR(c->tagpool)) {
|
|
|
- err = PTR_ERR(c->tagpool);
|
|
|
- goto error;
|
|
|
- }
|
|
|
- err = p9_idpool_get(c->tagpool); /* reserve tag 0 */
|
|
|
- if (err < 0) {
|
|
|
- p9_idpool_destroy(c->tagpool);
|
|
|
- goto error;
|
|
|
- }
|
|
|
- c->max_tag = 0;
|
|
|
-error:
|
|
|
- return err;
|
|
|
+int p9_req_put(struct p9_req_t *r)
|
|
|
+{
|
|
|
+ return kref_put(&r->refcount, p9_req_free);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(p9_req_put);
|
|
|
|
|
|
/**
|
|
|
* p9_tag_cleanup - cleans up tags structure and reclaims resources
|
|
@@ -379,52 +405,17 @@ error:
|
|
|
*/
|
|
|
static void p9_tag_cleanup(struct p9_client *c)
|
|
|
{
|
|
|
- int row, col;
|
|
|
-
|
|
|
- /* check to insure all requests are idle */
|
|
|
- for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
|
|
|
- for (col = 0; col < P9_ROW_MAXTAG; col++) {
|
|
|
- if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
|
|
|
- p9_debug(P9_DEBUG_MUX,
|
|
|
- "Attempting to cleanup non-free tag %d,%d\n",
|
|
|
- row, col);
|
|
|
- /* TODO: delay execution of cleanup */
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (c->tagpool) {
|
|
|
- p9_idpool_put(0, c->tagpool); /* free reserved tag 0 */
|
|
|
- p9_idpool_destroy(c->tagpool);
|
|
|
- }
|
|
|
+ struct p9_req_t *req;
|
|
|
+ int id;
|
|
|
|
|
|
- /* free requests associated with tags */
|
|
|
- for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
|
|
|
- for (col = 0; col < P9_ROW_MAXTAG; col++) {
|
|
|
- kfree(c->reqs[row][col].tc);
|
|
|
- kfree(c->reqs[row][col].rc);
|
|
|
- }
|
|
|
- kfree(c->reqs[row]);
|
|
|
+ rcu_read_lock();
|
|
|
+ idr_for_each_entry(&c->reqs, req, id) {
|
|
|
+ pr_info("Tag %d still in use\n", id);
|
|
|
+ if (p9_tag_remove(c, req) == 0)
|
|
|
+ pr_warn("Packet with tag %d has still references",
|
|
|
+ req->tc.tag);
|
|
|
}
|
|
|
- c->max_tag = 0;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * p9_free_req - free a request and clean-up as necessary
|
|
|
- * c: client state
|
|
|
- * r: request to release
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
|
|
|
-{
|
|
|
- int tag = r->tc->tag;
|
|
|
- p9_debug(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag);
|
|
|
-
|
|
|
- r->status = REQ_STATUS_IDLE;
|
|
|
- if (tag != P9_NOTAG && p9_idpool_check(tag, c->tagpool))
|
|
|
- p9_idpool_put(tag, c->tagpool);
|
|
|
+ rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -435,7 +426,7 @@ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
|
|
|
*/
|
|
|
void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
|
|
|
{
|
|
|
- p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc->tag);
|
|
|
+ p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc.tag);
|
|
|
|
|
|
/*
|
|
|
* This barrier is needed to make sure any change made to req before
|
|
@@ -445,7 +436,8 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
|
|
|
req->status = status;
|
|
|
|
|
|
wake_up(&req->wq);
|
|
|
- p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
|
|
|
+ p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag);
|
|
|
+ p9_req_put(req);
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_client_cb);
|
|
|
|
|
@@ -516,18 +508,18 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|
|
int err;
|
|
|
int ecode;
|
|
|
|
|
|
- err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
|
|
|
- if (req->rc->size >= c->msize) {
|
|
|
+ err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
|
|
|
+ if (req->rc.size >= c->msize) {
|
|
|
p9_debug(P9_DEBUG_ERROR,
|
|
|
"requested packet size too big: %d\n",
|
|
|
- req->rc->size);
|
|
|
+ req->rc.size);
|
|
|
return -EIO;
|
|
|
}
|
|
|
/*
|
|
|
* dump the response from server
|
|
|
* This should be after check errors which poplulate pdu_fcall.
|
|
|
*/
|
|
|
- trace_9p_protocol_dump(c, req->rc);
|
|
|
+ trace_9p_protocol_dump(c, &req->rc);
|
|
|
if (err) {
|
|
|
p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
|
|
|
return err;
|
|
@@ -537,7 +529,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|
|
|
|
|
if (!p9_is_proto_dotl(c)) {
|
|
|
char *ename;
|
|
|
- err = p9pdu_readf(req->rc, c->proto_version, "s?d",
|
|
|
+ err = p9pdu_readf(&req->rc, c->proto_version, "s?d",
|
|
|
&ename, &ecode);
|
|
|
if (err)
|
|
|
goto out_err;
|
|
@@ -553,7 +545,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|
|
}
|
|
|
kfree(ename);
|
|
|
} else {
|
|
|
- err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
|
|
|
+ err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode);
|
|
|
err = -ecode;
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
|
|
@@ -587,12 +579,12 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
|
|
int8_t type;
|
|
|
char *ename = NULL;
|
|
|
|
|
|
- err = p9_parse_header(req->rc, NULL, &type, NULL, 0);
|
|
|
+ err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
|
|
|
/*
|
|
|
* dump the response from server
|
|
|
* This should be after parse_header which poplulate pdu_fcall.
|
|
|
*/
|
|
|
- trace_9p_protocol_dump(c, req->rc);
|
|
|
+ trace_9p_protocol_dump(c, &req->rc);
|
|
|
if (err) {
|
|
|
p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
|
|
|
return err;
|
|
@@ -607,13 +599,13 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
|
|
/* 7 = header size for RERROR; */
|
|
|
int inline_len = in_hdrlen - 7;
|
|
|
|
|
|
- len = req->rc->size - req->rc->offset;
|
|
|
+ len = req->rc.size - req->rc.offset;
|
|
|
if (len > (P9_ZC_HDR_SZ - 7)) {
|
|
|
err = -EFAULT;
|
|
|
goto out_err;
|
|
|
}
|
|
|
|
|
|
- ename = &req->rc->sdata[req->rc->offset];
|
|
|
+ ename = &req->rc.sdata[req->rc.offset];
|
|
|
if (len > inline_len) {
|
|
|
/* We have error in external buffer */
|
|
|
if (!copy_from_iter_full(ename + inline_len,
|
|
@@ -623,7 +615,7 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
|
|
}
|
|
|
}
|
|
|
ename = NULL;
|
|
|
- err = p9pdu_readf(req->rc, c->proto_version, "s?d",
|
|
|
+ err = p9pdu_readf(&req->rc, c->proto_version, "s?d",
|
|
|
&ename, &ecode);
|
|
|
if (err)
|
|
|
goto out_err;
|
|
@@ -639,7 +631,7 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req,
|
|
|
}
|
|
|
kfree(ename);
|
|
|
} else {
|
|
|
- err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
|
|
|
+ err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode);
|
|
|
err = -ecode;
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
|
|
@@ -672,7 +664,7 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
|
|
|
int16_t oldtag;
|
|
|
int err;
|
|
|
|
|
|
- err = p9_parse_header(oldreq->tc, NULL, NULL, &oldtag, 1);
|
|
|
+ err = p9_parse_header(&oldreq->tc, NULL, NULL, &oldtag, 1);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -686,11 +678,12 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
|
|
|
* if we haven't received a response for oldreq,
|
|
|
* remove it from the list
|
|
|
*/
|
|
|
- if (oldreq->status == REQ_STATUS_SENT)
|
|
|
+ if (oldreq->status == REQ_STATUS_SENT) {
|
|
|
if (c->trans_mod->cancelled)
|
|
|
c->trans_mod->cancelled(c, oldreq);
|
|
|
+ }
|
|
|
|
|
|
- p9_free_req(c, req);
|
|
|
+ p9_tag_remove(c, req);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -698,7 +691,7 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
|
|
|
int8_t type, int req_size,
|
|
|
const char *fmt, va_list ap)
|
|
|
{
|
|
|
- int tag, err;
|
|
|
+ int err;
|
|
|
struct p9_req_t *req;
|
|
|
|
|
|
p9_debug(P9_DEBUG_MUX, "client %p op %d\n", c, type);
|
|
@@ -711,27 +704,22 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
|
|
|
if ((c->status == BeginDisconnect) && (type != P9_TCLUNK))
|
|
|
return ERR_PTR(-EIO);
|
|
|
|
|
|
- tag = P9_NOTAG;
|
|
|
- if (type != P9_TVERSION) {
|
|
|
- tag = p9_idpool_get(c->tagpool);
|
|
|
- if (tag < 0)
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
-
|
|
|
- req = p9_tag_alloc(c, tag, req_size);
|
|
|
+ req = p9_tag_alloc(c, type, req_size);
|
|
|
if (IS_ERR(req))
|
|
|
return req;
|
|
|
|
|
|
/* marshall the data */
|
|
|
- p9pdu_prepare(req->tc, tag, type);
|
|
|
- err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
|
|
|
+ p9pdu_prepare(&req->tc, req->tc.tag, type);
|
|
|
+ err = p9pdu_vwritef(&req->tc, c->proto_version, fmt, ap);
|
|
|
if (err)
|
|
|
goto reterr;
|
|
|
- p9pdu_finalize(c, req->tc);
|
|
|
- trace_9p_client_req(c, type, tag);
|
|
|
+ p9pdu_finalize(c, &req->tc);
|
|
|
+ trace_9p_client_req(c, type, req->tc.tag);
|
|
|
return req;
|
|
|
reterr:
|
|
|
- p9_free_req(c, req);
|
|
|
+ p9_tag_remove(c, req);
|
|
|
+ /* We have to put also the 2nd reference as it won't be used */
|
|
|
+ p9_req_put(req);
|
|
|
return ERR_PTR(err);
|
|
|
}
|
|
|
|
|
@@ -741,7 +729,7 @@ reterr:
|
|
|
* @type: type of request
|
|
|
* @fmt: protocol format string (see protocol.c)
|
|
|
*
|
|
|
- * Returns request structure (which client must free using p9_free_req)
|
|
|
+ * Returns request structure (which client must free using p9_tag_remove)
|
|
|
*/
|
|
|
|
|
|
static struct p9_req_t *
|
|
@@ -766,6 +754,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
|
|
|
|
|
|
err = c->trans_mod->request(c, req);
|
|
|
if (err < 0) {
|
|
|
+ /* write won't happen */
|
|
|
+ p9_req_put(req);
|
|
|
if (err != -ERESTARTSYS && err != -EFAULT)
|
|
|
c->status = Disconnected;
|
|
|
goto recalc_sigpending;
|
|
@@ -813,11 +803,11 @@ recalc_sigpending:
|
|
|
goto reterr;
|
|
|
|
|
|
err = p9_check_errors(c, req);
|
|
|
- trace_9p_client_res(c, type, req->rc->tag, err);
|
|
|
+ trace_9p_client_res(c, type, req->rc.tag, err);
|
|
|
if (!err)
|
|
|
return req;
|
|
|
reterr:
|
|
|
- p9_free_req(c, req);
|
|
|
+ p9_tag_remove(c, req);
|
|
|
return ERR_PTR(safe_errno(err));
|
|
|
}
|
|
|
|
|
@@ -832,7 +822,7 @@ reterr:
|
|
|
* @hdrlen: reader header size, This is the size of response protocol data
|
|
|
* @fmt: protocol format string (see protocol.c)
|
|
|
*
|
|
|
- * Returns request structure (which client must free using p9_free_req)
|
|
|
+ * Returns request structure (which client must free using p9_tag_remove)
|
|
|
*/
|
|
|
static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
|
|
|
struct iov_iter *uidata,
|
|
@@ -895,11 +885,11 @@ recalc_sigpending:
|
|
|
goto reterr;
|
|
|
|
|
|
err = p9_check_zc_errors(c, req, uidata, in_hdrlen);
|
|
|
- trace_9p_client_res(c, type, req->rc->tag, err);
|
|
|
+ trace_9p_client_res(c, type, req->rc.tag, err);
|
|
|
if (!err)
|
|
|
return req;
|
|
|
reterr:
|
|
|
- p9_free_req(c, req);
|
|
|
+ p9_tag_remove(c, req);
|
|
|
return ERR_PTR(safe_errno(err));
|
|
|
}
|
|
|
|
|
@@ -978,10 +968,10 @@ static int p9_client_version(struct p9_client *c)
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
|
|
|
+ err = p9pdu_readf(&req->rc, c->proto_version, "ds", &msize, &version);
|
|
|
if (err) {
|
|
|
p9_debug(P9_DEBUG_9P, "version error %d\n", err);
|
|
|
- trace_9p_protocol_dump(c, req->rc);
|
|
|
+ trace_9p_protocol_dump(c, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -1002,7 +992,7 @@ static int p9_client_version(struct p9_client *c)
|
|
|
|
|
|
error:
|
|
|
kfree(version);
|
|
|
- p9_free_req(c, req);
|
|
|
+ p9_tag_remove(c, req);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
@@ -1020,20 +1010,18 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
|
|
|
|
|
|
clnt->trans_mod = NULL;
|
|
|
clnt->trans = NULL;
|
|
|
+ clnt->fcall_cache = NULL;
|
|
|
|
|
|
client_id = utsname()->nodename;
|
|
|
memcpy(clnt->name, client_id, strlen(client_id) + 1);
|
|
|
|
|
|
spin_lock_init(&clnt->lock);
|
|
|
idr_init(&clnt->fids);
|
|
|
-
|
|
|
- err = p9_tag_init(clnt);
|
|
|
- if (err < 0)
|
|
|
- goto free_client;
|
|
|
+ idr_init(&clnt->reqs);
|
|
|
|
|
|
err = parse_opts(options, clnt);
|
|
|
if (err < 0)
|
|
|
- goto destroy_tagpool;
|
|
|
+ goto free_client;
|
|
|
|
|
|
if (!clnt->trans_mod)
|
|
|
clnt->trans_mod = v9fs_get_default_trans();
|
|
@@ -1042,7 +1030,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
|
|
|
err = -EPROTONOSUPPORT;
|
|
|
p9_debug(P9_DEBUG_ERROR,
|
|
|
"No transport defined or default transport\n");
|
|
|
- goto destroy_tagpool;
|
|
|
+ goto free_client;
|
|
|
}
|
|
|
|
|
|
p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
|
|
@@ -1059,14 +1047,21 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
|
|
|
if (err)
|
|
|
goto close_trans;
|
|
|
|
|
|
+ /* P9_HDRSZ + 4 is the smallest packet header we can have that is
|
|
|
+ * followed by data accessed from userspace by read
|
|
|
+ */
|
|
|
+ clnt->fcall_cache =
|
|
|
+ kmem_cache_create_usercopy("9p-fcall-cache", clnt->msize,
|
|
|
+ 0, 0, P9_HDRSZ + 4,
|
|
|
+ clnt->msize - (P9_HDRSZ + 4),
|
|
|
+ NULL);
|
|
|
+
|
|
|
return clnt;
|
|
|
|
|
|
close_trans:
|
|
|
clnt->trans_mod->close(clnt);
|
|
|
put_trans:
|
|
|
v9fs_put_trans(clnt->trans_mod);
|
|
|
-destroy_tagpool:
|
|
|
- p9_idpool_destroy(clnt->tagpool);
|
|
|
free_client:
|
|
|
kfree(clnt);
|
|
|
return ERR_PTR(err);
|
|
@@ -1092,6 +1087,7 @@ void p9_client_destroy(struct p9_client *clnt)
|
|
|
|
|
|
p9_tag_cleanup(clnt);
|
|
|
|
|
|
+ kmem_cache_destroy(clnt->fcall_cache);
|
|
|
kfree(clnt);
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_client_destroy);
|
|
@@ -1135,10 +1131,10 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", &qid);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -1147,7 +1143,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
|
|
|
|
|
|
memmove(&fid->qid, &qid, sizeof(struct p9_qid));
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return fid;
|
|
|
|
|
|
error:
|
|
@@ -1192,13 +1188,13 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "R", &nwqids, &wqids);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto clunk_fid;
|
|
|
}
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
|
|
|
|
|
@@ -1259,9 +1255,9 @@ int p9_client_open(struct p9_fid *fid, int mode)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto free_and_error;
|
|
|
}
|
|
|
|
|
@@ -1273,7 +1269,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
|
|
|
fid->iounit = iounit;
|
|
|
|
|
|
free_and_error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1303,9 +1299,9 @@ int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", qid, &iounit);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", qid, &iounit);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto free_and_error;
|
|
|
}
|
|
|
|
|
@@ -1318,7 +1314,7 @@ int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32
|
|
|
ofid->iounit = iounit;
|
|
|
|
|
|
free_and_error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1348,9 +1344,9 @@ int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto free_and_error;
|
|
|
}
|
|
|
|
|
@@ -1363,7 +1359,7 @@ int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode,
|
|
|
fid->iounit = iounit;
|
|
|
|
|
|
free_and_error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1387,9 +1383,9 @@ int p9_client_symlink(struct p9_fid *dfid, const char *name,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto free_and_error;
|
|
|
}
|
|
|
|
|
@@ -1397,7 +1393,7 @@ int p9_client_symlink(struct p9_fid *dfid, const char *name,
|
|
|
qid->type, (unsigned long long)qid->path, qid->version);
|
|
|
|
|
|
free_and_error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1417,7 +1413,7 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, const char *newna
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RLINK\n");
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_client_link);
|
|
@@ -1441,7 +1437,7 @@ int p9_client_fsync(struct p9_fid *fid, int datasync)
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
|
|
|
error:
|
|
|
return err;
|
|
@@ -1476,7 +1472,7 @@ again:
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
/*
|
|
|
* Fid is not valid even after a failed clunk
|
|
@@ -1510,7 +1506,7 @@ int p9_client_remove(struct p9_fid *fid)
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
if (err == -ERESTARTSYS)
|
|
|
p9_client_clunk(fid);
|
|
@@ -1537,7 +1533,7 @@ int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1585,11 +1581,11 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- *err = p9pdu_readf(req->rc, clnt->proto_version,
|
|
|
+ *err = p9pdu_readf(&req->rc, clnt->proto_version,
|
|
|
"D", &count, &dataptr);
|
|
|
if (*err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
break;
|
|
|
}
|
|
|
if (rsize < count) {
|
|
@@ -1599,7 +1595,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
|
|
|
if (!count) {
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -1609,7 +1605,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
|
|
offset += n;
|
|
|
if (n != count) {
|
|
|
*err = -EFAULT;
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
@@ -1617,7 +1613,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
|
|
|
total += count;
|
|
|
offset += count;
|
|
|
}
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
}
|
|
|
return total;
|
|
|
}
|
|
@@ -1658,10 +1654,10 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- *err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
|
|
|
+ *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &count);
|
|
|
if (*err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
break;
|
|
|
}
|
|
|
if (rsize < count) {
|
|
@@ -1671,7 +1667,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
iov_iter_advance(from, count);
|
|
|
total += count;
|
|
|
offset += count;
|
|
@@ -1702,10 +1698,10 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "wS", &ignored, ret);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -1722,7 +1718,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
|
|
|
from_kgid(&init_user_ns, ret->n_gid),
|
|
|
from_kuid(&init_user_ns, ret->n_muid));
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return ret;
|
|
|
|
|
|
error:
|
|
@@ -1755,10 +1751,10 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "A", ret);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "A", ret);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -1783,7 +1779,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
|
|
|
ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec,
|
|
|
ret->st_gen, ret->st_data_version);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return ret;
|
|
|
|
|
|
error:
|
|
@@ -1852,7 +1848,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1884,7 +1880,7 @@ int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1907,12 +1903,12 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
|
|
|
- &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
|
|
|
- &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
|
|
|
+ &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
|
|
|
+ &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
@@ -1923,7 +1919,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
|
|
|
sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree,
|
|
|
sb->fsid, (long int)sb->namelen);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1951,7 +1947,7 @@ int p9_client_rename(struct p9_fid *fid,
|
|
|
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -1981,7 +1977,7 @@ int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
|
|
|
newdirfid->fid, new_name);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -2015,13 +2011,13 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
|
|
|
err = PTR_ERR(req);
|
|
|
goto error;
|
|
|
}
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "q", attr_size);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "q", attr_size);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
goto clunk_fid;
|
|
|
}
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n",
|
|
|
attr_fid->fid, *attr_size);
|
|
|
return attr_fid;
|
|
@@ -2055,7 +2051,7 @@ int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -2103,9 +2099,9 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
|
|
|
goto error;
|
|
|
}
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "D", &count, &dataptr);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto free_and_error;
|
|
|
}
|
|
|
if (rsize < count) {
|
|
@@ -2118,11 +2114,11 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
|
|
|
if (non_zc)
|
|
|
memmove(data, dataptr, count);
|
|
|
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return count;
|
|
|
|
|
|
free_and_error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
error:
|
|
|
return err;
|
|
|
}
|
|
@@ -2144,16 +2140,16 @@ int p9_client_mknod_dotl(struct p9_fid *fid, const char *name, int mode,
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type,
|
|
|
(unsigned long long)qid->path, qid->version);
|
|
|
|
|
|
error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return err;
|
|
|
|
|
|
}
|
|
@@ -2175,16 +2171,16 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "Q", qid);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
|
|
|
(unsigned long long)qid->path, qid->version);
|
|
|
|
|
|
error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return err;
|
|
|
|
|
|
}
|
|
@@ -2210,14 +2206,14 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "b", status);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
|
|
|
error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return err;
|
|
|
|
|
|
}
|
|
@@ -2241,18 +2237,18 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type,
|
|
|
- &glock->start, &glock->length, &glock->proc_id,
|
|
|
- &glock->client_id);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "bqqds", &glock->type,
|
|
|
+ &glock->start, &glock->length, &glock->proc_id,
|
|
|
+ &glock->client_id);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
|
|
|
"proc_id %d client_id %s\n", glock->type, glock->start,
|
|
|
glock->length, glock->proc_id, glock->client_id);
|
|
|
error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_client_getlock_dotl);
|
|
@@ -2271,14 +2267,25 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
|
|
|
if (IS_ERR(req))
|
|
|
return PTR_ERR(req);
|
|
|
|
|
|
- err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
|
|
|
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "s", target);
|
|
|
if (err) {
|
|
|
- trace_9p_protocol_dump(clnt, req->rc);
|
|
|
+ trace_9p_protocol_dump(clnt, &req->rc);
|
|
|
goto error;
|
|
|
}
|
|
|
p9_debug(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
|
|
|
error:
|
|
|
- p9_free_req(clnt, req);
|
|
|
+ p9_tag_remove(clnt, req);
|
|
|
return err;
|
|
|
}
|
|
|
EXPORT_SYMBOL(p9_client_readlink);
|
|
|
+
|
|
|
+int __init p9_client_init(void)
|
|
|
+{
|
|
|
+ p9_req_cache = KMEM_CACHE(p9_req_t, SLAB_TYPESAFE_BY_RCU);
|
|
|
+ return p9_req_cache ? 0 : -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+void __exit p9_client_exit(void)
|
|
|
+{
|
|
|
+ kmem_cache_destroy(p9_req_cache);
|
|
|
+}
|