--- /dev/null
+From 7e3be23e7a0de68c73fdbea2ca5306cd3903e294 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Sat, 8 Sep 2018 00:10:57 +0900
+Subject: 9p: acl: fix uninitialized iattr access
+
+[ Upstream commit e02a53d92e197706cad1627bd84705d4aa20a145 ]
+
+iattr is passed to v9fs_vfs_setattr_dotl which does send various
+values from iattr over the wire, even if it tells the server to
+only look at iattr.ia_valid fields this could leak some stack data.
+
+Link: http://lkml.kernel.org/r/1536339057-21974-2-git-send-email-asmadeus@codewreck.org
+Addresses-Coverity-ID: 1195601 ("Uninitalized scalar variable")
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/9p/acl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/9p/acl.c b/fs/9p/acl.c
+index 082d227fa56b..6261719f6f2a 100644
+--- a/fs/9p/acl.c
++++ b/fs/9p/acl.c
+@@ -276,7 +276,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
+ switch (handler->flags) {
+ case ACL_TYPE_ACCESS:
+ if (acl) {
+- struct iattr iattr;
++ struct iattr iattr = { 0 };
+ struct posix_acl *old_acl = acl;
+
+ retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
+--
+2.20.1
+
--- /dev/null
+From 88bf06736a8b5c38a831b73166d9bbcd49fd8825 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Mon, 30 Jul 2018 15:14:37 +0900
+Subject: 9p: add a per-client fcall kmem_cache
+
+[ Upstream commit 91a76be37ff89795526c452a6799576b03bec501 ]
+
+Having a specific cache for the fcall allocations helps speed up
+end-to-end latency.
+
+The caches will automatically be merged if there are multiple caches
+of items with the same size so we do not need to try to share a cache
+between different clients of the same size.
+
+Since the msize is negotiated with the server, only allocate the cache
+after that negotiation has happened - previous allocations or
+allocations of different sizes (e.g. zero-copy fcall) are made with
+kmalloc directly.
+
+Some figures on two beefy VMs with Connect-IB (sriov) / trans=rdma,
+with ior running 32 processes in parallel doing small 32 bytes IOs:
+ - no alloc (4.18-rc7 request cache): 65.4k req/s
+ - non-power of two alloc, no patch: 61.6k req/s
+ - power of two alloc, no patch: 62.2k req/s
+ - non-power of two alloc, with patch: 64.7k req/s
+ - power of two alloc, with patch: 65.1k req/s
+
+Link: http://lkml.kernel.org/r/1532943263-24378-2-git-send-email-asmadeus@codewreck.org
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Acked-by: Jun Piao <piaojun@huawei.com>
+Cc: Matthew Wilcox <willy@infradead.org>
+Cc: Greg Kurz <groug@kaod.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/9p/9p.h | 4 ++++
+ include/net/9p/client.h | 1 +
+ net/9p/client.c | 37 ++++++++++++++++++++++++++++++++-----
+ 3 files changed, 37 insertions(+), 5 deletions(-)
+
+diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
+index b8eb51a661e5..4ab293f574e0 100644
+--- a/include/net/9p/9p.h
++++ b/include/net/9p/9p.h
+@@ -336,6 +336,9 @@ enum p9_qid_t {
+ #define P9_NOFID (u32)(~0)
+ #define P9_MAXWELEM 16
+
++/* Minimal header size: size[4] type[1] tag[2] */
++#define P9_HDRSZ 7
++
+ /* ample room for Twrite/Rread header */
+ #define P9_IOHDRSZ 24
+
+@@ -558,6 +561,7 @@ struct p9_fcall {
+ size_t offset;
+ size_t capacity;
+
++ struct kmem_cache *cache;
+ u8 *sdata;
+ };
+
+diff --git a/include/net/9p/client.h b/include/net/9p/client.h
+index c2671d40bb6b..735f3979d559 100644
+--- a/include/net/9p/client.h
++++ b/include/net/9p/client.h
+@@ -123,6 +123,7 @@ struct p9_client {
+ struct p9_trans_module *trans_mod;
+ enum p9_trans_status status;
+ void *trans;
++ struct kmem_cache *fcall_cache;
+
+ union {
+ struct {
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 83e39fef58e1..7ef54719c6f7 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -237,9 +237,16 @@ static int parse_opts(char *opts, struct p9_client *clnt)
+ return ret;
+ }
+
+-static int p9_fcall_init(struct p9_fcall *fc, int alloc_msize)
++static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
++ int alloc_msize)
+ {
+- fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
++ 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;
+@@ -248,7 +255,16 @@ static int p9_fcall_init(struct p9_fcall *fc, int alloc_msize)
+
+ void p9_fcall_fini(struct p9_fcall *fc)
+ {
+- kfree(fc->sdata);
++ /* 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);
+
+@@ -273,9 +289,9 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ if (!req)
+ return NULL;
+
+- if (p9_fcall_init(&req->tc, alloc_msize))
++ if (p9_fcall_init(c, &req->tc, alloc_msize))
+ goto free_req;
+- if (p9_fcall_init(&req->rc, alloc_msize))
++ if (p9_fcall_init(c, &req->rc, alloc_msize))
+ goto free;
+
+ p9pdu_reset(&req->tc);
+@@ -965,6 +981,7 @@ 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);
+@@ -1008,6 +1025,15 @@ 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:
+@@ -1039,6 +1065,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);
+--
+2.20.1
+
--- /dev/null
+From 407b1adf790f60daa865ecf8cc216e0c31fcce5d Mon Sep 17 00:00:00 2001
+From: Tomas Bortoli <tomasbortoli@gmail.com>
+Date: Tue, 14 Aug 2018 19:43:42 +0200
+Subject: 9p: Add refcount to p9_req_t
+
+[ Upstream commit 728356dedeff8ef999cb436c71333ef4ac51a81c ]
+
+To avoid use-after-free(s), use a refcount to keep track of the
+usable references to any instantiated struct p9_req_t.
+
+This commit adds p9_req_put(), p9_req_get() and p9_req_try_get() as
+wrappers to kref_put(), kref_get() and kref_get_unless_zero().
+These are used by the client and the transports to keep track of
+valid requests' references.
+
+p9_free_req() is added back and used as callback by kref_put().
+
+Add SLAB_TYPESAFE_BY_RCU as it ensures that the memory freed by
+kmem_cache_free() will not be reused for another type until the rcu
+synchronisation period is over, so an address gotten under rcu read
+lock is safe to inc_ref() without corrupting random memory while
+the lock is held.
+
+Link: http://lkml.kernel.org/r/1535626341-20693-1-git-send-email-asmadeus@codewreck.org
+Co-developed-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Tomas Bortoli <tomasbortoli@gmail.com>
+Reported-by: syzbot+467050c1ce275af2a5b8@syzkaller.appspotmail.com
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/9p/client.h | 14 ++++++++++
+ net/9p/client.c | 57 ++++++++++++++++++++++++++++++++++++-----
+ net/9p/trans_fd.c | 11 +++++++-
+ net/9p/trans_rdma.c | 1 +
+ net/9p/trans_virtio.c | 26 ++++++++++++++++---
+ net/9p/trans_xen.c | 1 +
+ 6 files changed, 98 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/9p/client.h b/include/net/9p/client.h
+index 735f3979d559..947a570307a6 100644
+--- a/include/net/9p/client.h
++++ b/include/net/9p/client.h
+@@ -94,6 +94,7 @@ enum p9_req_status_t {
+ struct p9_req_t {
+ int status;
+ int t_err;
++ struct kref refcount;
+ wait_queue_head_t wq;
+ struct p9_fcall tc;
+ struct p9_fcall rc;
+@@ -233,6 +234,19 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
+ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
+ void p9_fcall_fini(struct p9_fcall *fc);
+ struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
++
++static inline void p9_req_get(struct p9_req_t *r)
++{
++ kref_get(&r->refcount);
++}
++
++static inline int p9_req_try_get(struct p9_req_t *r)
++{
++ return kref_get_unless_zero(&r->refcount);
++}
++
++int p9_req_put(struct p9_req_t *r);
++
+ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);
+
+ int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 3cde9f619980..4becde979462 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -313,6 +313,18 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ 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;
+
+ free:
+@@ -336,10 +348,21 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
+ struct p9_req_t *req;
+
+ rcu_read_lock();
++again:
+ req = idr_find(&c->reqs, tag);
+- /* There's no refcount on the req; a malicious server could cause
+- * us to dereference a NULL pointer
+- */
++ 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 req;
+@@ -353,7 +376,7 @@ EXPORT_SYMBOL(p9_tag_lookup);
+ *
+ * Context: Any context.
+ */
+-static void p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
++static int p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
+ {
+ unsigned long flags;
+ u16 tag = r->tc.tag;
+@@ -362,11 +385,23 @@ static void p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
+ spin_lock_irqsave(&c->lock, flags);
+ idr_remove(&c->reqs, tag);
+ spin_unlock_irqrestore(&c->lock, flags);
++ return p9_req_put(r);
++}
++
++static void p9_req_free(struct kref *ref)
++{
++ 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);
+ }
+
++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
+ * @c: v9fs client struct
+@@ -382,7 +417,9 @@ static void p9_tag_cleanup(struct p9_client *c)
+ rcu_read_lock();
+ idr_for_each_entry(&c->reqs, req, id) {
+ pr_info("Tag %d still in use\n", id);
+- p9_tag_remove(c, req);
++ if (p9_tag_remove(c, req) == 0)
++ pr_warn("Packet with tag %d has still references",
++ req->tc.tag);
+ }
+ rcu_read_unlock();
+ }
+@@ -406,6 +443,7 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
+
+ wake_up(&req->wq);
+ p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag);
++ p9_req_put(req);
+ }
+ EXPORT_SYMBOL(p9_client_cb);
+
+@@ -646,9 +684,10 @@ 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_tag_remove(c, req);
+ return 0;
+@@ -685,6 +724,8 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
+ return req;
+ reterr:
+ 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);
+ }
+
+@@ -719,6 +760,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;
+@@ -2259,7 +2302,7 @@ EXPORT_SYMBOL(p9_client_readlink);
+
+ int __init p9_client_init(void)
+ {
+- p9_req_cache = KMEM_CACHE(p9_req_t, 0);
++ p9_req_cache = KMEM_CACHE(p9_req_t, SLAB_TYPESAFE_BY_RCU);
+ return p9_req_cache ? 0 : -ENOMEM;
+ }
+
+diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
+index 51615c0fb744..aca528722183 100644
+--- a/net/9p/trans_fd.c
++++ b/net/9p/trans_fd.c
+@@ -132,6 +132,7 @@ struct p9_conn {
+ struct list_head req_list;
+ struct list_head unsent_req_list;
+ struct p9_req_t *req;
++ struct p9_req_t *wreq;
+ char tmp_buf[7];
+ struct p9_fcall rc;
+ int wpos;
+@@ -383,6 +384,7 @@ static void p9_read_work(struct work_struct *work)
+ m->rc.sdata = NULL;
+ m->rc.offset = 0;
+ m->rc.capacity = 0;
++ p9_req_put(m->req);
+ m->req = NULL;
+ }
+
+@@ -472,6 +474,8 @@ static void p9_write_work(struct work_struct *work)
+ m->wbuf = req->tc.sdata;
+ m->wsize = req->tc.size;
+ m->wpos = 0;
++ p9_req_get(req);
++ m->wreq = req;
+ spin_unlock(&m->client->lock);
+ }
+
+@@ -492,8 +496,11 @@ static void p9_write_work(struct work_struct *work)
+ }
+
+ m->wpos += err;
+- if (m->wpos == m->wsize)
++ if (m->wpos == m->wsize) {
+ m->wpos = m->wsize = 0;
++ p9_req_put(m->wreq);
++ m->wreq = NULL;
++ }
+
+ end_clear:
+ clear_bit(Wworksched, &m->wsched);
+@@ -694,6 +701,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
+ if (req->status == REQ_STATUS_UNSENT) {
+ list_del(&req->req_list);
+ req->status = REQ_STATUS_FLSHD;
++ p9_req_put(req);
+ ret = 0;
+ }
+ spin_unlock(&client->lock);
+@@ -711,6 +719,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
+ spin_lock(&client->lock);
+ list_del(&req->req_list);
+ spin_unlock(&client->lock);
++ p9_req_put(req);
+
+ return 0;
+ }
+diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
+index 5b0cda1aaa7a..9cc9b3a19ee7 100644
+--- a/net/9p/trans_rdma.c
++++ b/net/9p/trans_rdma.c
+@@ -365,6 +365,7 @@ send_done(struct ib_cq *cq, struct ib_wc *wc)
+ c->busa, c->req->tc.size,
+ DMA_TO_DEVICE);
+ up(&rdma->sq_sem);
++ p9_req_put(c->req);
+ kfree(c);
+ }
+
+diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
+index 3dd6ce1c0f2d..eb596c2ed546 100644
+--- a/net/9p/trans_virtio.c
++++ b/net/9p/trans_virtio.c
+@@ -207,6 +207,13 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req)
+ return 1;
+ }
+
++/* Reply won't come, so drop req ref */
++static int p9_virtio_cancelled(struct p9_client *client, struct p9_req_t *req)
++{
++ p9_req_put(req);
++ return 0;
++}
++
+ /**
+ * pack_sg_list_p - Just like pack_sg_list. Instead of taking a buffer,
+ * this takes a list of pages.
+@@ -404,6 +411,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ struct scatterlist *sgs[4];
+ size_t offs;
+ int need_drop = 0;
++ int kicked = 0;
+
+ p9_debug(P9_DEBUG_TRANS, "virtio request\n");
+
+@@ -411,8 +419,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ __le32 sz;
+ int n = p9_get_mapped_pages(chan, &out_pages, uodata,
+ outlen, &offs, &need_drop);
+- if (n < 0)
+- return n;
++ if (n < 0) {
++ err = n;
++ goto err_out;
++ }
+ out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
+ if (n != outlen) {
+ __le32 v = cpu_to_le32(n);
+@@ -428,8 +438,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ } else if (uidata) {
+ int n = p9_get_mapped_pages(chan, &in_pages, uidata,
+ inlen, &offs, &need_drop);
+- if (n < 0)
+- return n;
++ if (n < 0) {
++ err = n;
++ goto err_out;
++ }
+ in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
+ if (n != inlen) {
+ __le32 v = cpu_to_le32(n);
+@@ -498,6 +510,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ }
+ virtqueue_kick(chan->vq);
+ spin_unlock_irqrestore(&chan->lock, flags);
++ kicked = 1;
+ p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n");
+ err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD);
+ /*
+@@ -518,6 +531,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ }
+ kvfree(in_pages);
+ kvfree(out_pages);
++ if (!kicked) {
++ /* reply won't come */
++ p9_req_put(req);
++ }
+ return err;
+ }
+
+@@ -750,6 +767,7 @@ static struct p9_trans_module p9_virtio_trans = {
+ .request = p9_virtio_request,
+ .zc_request = p9_virtio_zc_request,
+ .cancel = p9_virtio_cancel,
++ .cancelled = p9_virtio_cancelled,
+ /*
+ * We leave one entry for input and one entry for response
+ * headers. We also skip one more entry to accomodate, address
+diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
+index 782a07f2ad0c..e2fbf3677b9b 100644
+--- a/net/9p/trans_xen.c
++++ b/net/9p/trans_xen.c
+@@ -185,6 +185,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
+ ring->intf->out_prod = prod;
+ spin_unlock_irqrestore(&ring->lock, flags);
+ notify_remote_via_irq(ring->irq);
++ p9_req_put(p9_req);
+
+ return 0;
+ }
+--
+2.20.1
+
--- /dev/null
+From 900e89fb536b17d1564f9e57aba9620d2a644484 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Mon, 30 Jul 2018 05:55:19 +0000
+Subject: 9p: embed fcall in req to round down buffer allocs
+
+[ Upstream commit 523adb6cc10b48655c0abe556505240741425b49 ]
+
+'msize' is often a power of two, or at least page-aligned, so avoiding
+an overhead of two dozen bytes for each allocation will help the
+allocator do its work and reduce memory fragmentation.
+
+Link: http://lkml.kernel.org/r/1533825236-22896-1-git-send-email-asmadeus@codewreck.org
+Suggested-by: Matthew Wilcox <willy@infradead.org>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Reviewed-by: Greg Kurz <groug@kaod.org>
+Acked-by: Jun Piao <piaojun@huawei.com>
+Cc: Matthew Wilcox <willy@infradead.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/9p/client.h | 5 +-
+ net/9p/client.c | 167 +++++++++++++++++++++-------------------
+ net/9p/trans_fd.c | 12 +--
+ net/9p/trans_rdma.c | 29 +++----
+ net/9p/trans_virtio.c | 18 ++---
+ net/9p/trans_xen.c | 12 +--
+ 6 files changed, 125 insertions(+), 118 deletions(-)
+
+diff --git a/include/net/9p/client.h b/include/net/9p/client.h
+index a4dc42c53d18..c2671d40bb6b 100644
+--- a/include/net/9p/client.h
++++ b/include/net/9p/client.h
+@@ -95,8 +95,8 @@ struct p9_req_t {
+ int status;
+ int t_err;
+ wait_queue_head_t wq;
+- struct p9_fcall *tc;
+- struct p9_fcall *rc;
++ struct p9_fcall tc;
++ struct p9_fcall rc;
+ void *aux;
+ struct list_head req_list;
+ };
+@@ -230,6 +230,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
+ kgid_t gid, struct p9_qid *);
+ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
+ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
++void p9_fcall_fini(struct p9_fcall *fc);
+ struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
+ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status);
+
+diff --git a/net/9p/client.c b/net/9p/client.c
+index d8949c59d46e..83e39fef58e1 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -237,16 +237,20 @@ static int parse_opts(char *opts, struct p9_client *clnt)
+ return ret;
+ }
+
+-static struct p9_fcall *p9_fcall_alloc(int alloc_msize)
++static int p9_fcall_init(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;
++ fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
++ 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)
++{
++ kfree(fc->sdata);
+ }
++EXPORT_SYMBOL(p9_fcall_fini);
+
+ static struct kmem_cache *p9_req_cache;
+
+@@ -269,13 +273,13 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ if (!req)
+ return NULL;
+
+- req->tc = p9_fcall_alloc(alloc_msize);
+- req->rc = p9_fcall_alloc(alloc_msize);
+- if (!req->tc || !req->rc)
++ if (p9_fcall_init(&req->tc, alloc_msize))
++ goto free_req;
++ if (p9_fcall_init(&req->rc, alloc_msize))
+ goto free;
+
+- p9pdu_reset(req->tc);
+- p9pdu_reset(req->rc);
++ p9pdu_reset(&req->tc);
++ p9pdu_reset(&req->rc);
+ req->status = REQ_STATUS_ALLOC;
+ init_waitqueue_head(&req->wq);
+ INIT_LIST_HEAD(&req->req_list);
+@@ -287,7 +291,7 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ GFP_NOWAIT);
+ else
+ tag = idr_alloc(&c->reqs, req, 0, P9_NOTAG, GFP_NOWAIT);
+- req->tc->tag = tag;
++ req->tc.tag = tag;
+ spin_unlock_irq(&c->lock);
+ idr_preload_end();
+ if (tag < 0)
+@@ -296,8 +300,9 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ return req;
+
+ free:
+- kfree(req->tc);
+- kfree(req->rc);
++ p9_fcall_fini(&req->tc);
++ p9_fcall_fini(&req->rc);
++free_req:
+ kmem_cache_free(p9_req_cache, req);
+ return ERR_PTR(-ENOMEM);
+ }
+@@ -335,14 +340,14 @@ EXPORT_SYMBOL(p9_tag_lookup);
+ static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
+ {
+ unsigned long flags;
+- u16 tag = r->tc->tag;
++ 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);
+- kfree(r->tc);
+- kfree(r->rc);
++ p9_fcall_fini(&r->tc);
++ p9_fcall_fini(&r->rc);
+ kmem_cache_free(p9_req_cache, r);
+ }
+
+@@ -374,7 +379,7 @@ static void p9_tag_cleanup(struct p9_client *c)
+ */
+ 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
+@@ -384,7 +389,7 @@ 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);
+ }
+ EXPORT_SYMBOL(p9_client_cb);
+
+@@ -455,18 +460,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;
+@@ -476,7 +481,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;
+@@ -492,7 +497,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);
+@@ -526,12 +531,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;
+@@ -546,13 +551,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,
+@@ -562,7 +567,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;
+@@ -578,7 +583,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);
+@@ -611,7 +616,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;
+
+@@ -655,12 +660,12 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
+ return req;
+
+ /* marshall the data */
+- p9pdu_prepare(req->tc, 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, req->tc->tag);
++ p9pdu_finalize(c, &req->tc);
++ trace_9p_client_req(c, type, req->tc.tag);
+ return req;
+ reterr:
+ p9_free_req(c, req);
+@@ -745,7 +750,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
+ 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:
+@@ -827,7 +832,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
+ 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:
+@@ -910,10 +915,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;
+ }
+
+@@ -1077,9 +1082,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto error;
+ }
+@@ -1134,9 +1139,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto clunk_fid;
+ }
+@@ -1201,9 +1206,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;
+ }
+
+@@ -1245,9 +1250,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;
+ }
+
+@@ -1290,9 +1295,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;
+ }
+
+@@ -1329,9 +1334,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;
+ }
+
+@@ -1527,10 +1532,10 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ break;
+ }
+@@ -1600,9 +1605,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ break;
+ }
+@@ -1644,9 +1649,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto error;
+ }
+@@ -1697,9 +1702,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto error;
+ }
+@@ -1849,11 +1854,11 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto error;
+ }
+@@ -1957,9 +1962,9 @@ 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);
++ trace_9p_protocol_dump(clnt, &req->rc);
+ p9_free_req(clnt, req);
+ goto clunk_fid;
+ }
+@@ -2045,9 +2050,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) {
+@@ -2086,9 +2091,9 @@ 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,
+@@ -2117,9 +2122,9 @@ 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,
+@@ -2152,9 +2157,9 @@ 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);
+@@ -2183,11 +2188,11 @@ 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 "
+@@ -2213,9 +2218,9 @@ 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);
+diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
+index e2ef3c782c53..51615c0fb744 100644
+--- a/net/9p/trans_fd.c
++++ b/net/9p/trans_fd.c
+@@ -354,7 +354,7 @@ static void p9_read_work(struct work_struct *work)
+ goto error;
+ }
+
+- if (m->req->rc == NULL) {
++ if (!m->req->rc.sdata) {
+ p9_debug(P9_DEBUG_ERROR,
+ "No recv fcall for tag %d (req %p), disconnecting!\n",
+ m->rc.tag, m->req);
+@@ -362,7 +362,7 @@ static void p9_read_work(struct work_struct *work)
+ err = -EIO;
+ goto error;
+ }
+- m->rc.sdata = (char *)m->req->rc + sizeof(struct p9_fcall);
++ m->rc.sdata = m->req->rc.sdata;
+ memcpy(m->rc.sdata, m->tmp_buf, m->rc.capacity);
+ m->rc.capacity = m->rc.size;
+ }
+@@ -372,7 +372,7 @@ static void p9_read_work(struct work_struct *work)
+ */
+ if ((m->req) && (m->rc.offset == m->rc.capacity)) {
+ p9_debug(P9_DEBUG_TRANS, "got new packet\n");
+- m->req->rc->size = m->rc.offset;
++ m->req->rc.size = m->rc.offset;
+ spin_lock(&m->client->lock);
+ if (m->req->status != REQ_STATUS_ERROR)
+ status = REQ_STATUS_RCVD;
+@@ -469,8 +469,8 @@ static void p9_write_work(struct work_struct *work)
+ p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
+ list_move_tail(&req->req_list, &m->req_list);
+
+- m->wbuf = req->tc->sdata;
+- m->wsize = req->tc->size;
++ m->wbuf = req->tc.sdata;
++ m->wsize = req->tc.size;
+ m->wpos = 0;
+ spin_unlock(&m->client->lock);
+ }
+@@ -663,7 +663,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
+ struct p9_conn *m = &ts->conn;
+
+ p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",
+- m, current, req->tc, req->tc->id);
++ m, current, &req->tc, req->tc.id);
+ if (m->err < 0)
+ return m->err;
+
+diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
+index b513cffeeb3c..5b0cda1aaa7a 100644
+--- a/net/9p/trans_rdma.c
++++ b/net/9p/trans_rdma.c
+@@ -122,7 +122,7 @@ struct p9_rdma_context {
+ dma_addr_t busa;
+ union {
+ struct p9_req_t *req;
+- struct p9_fcall *rc;
++ struct p9_fcall rc;
+ };
+ };
+
+@@ -320,8 +320,8 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
+ if (wc->status != IB_WC_SUCCESS)
+ goto err_out;
+
+- c->rc->size = wc->byte_len;
+- err = p9_parse_header(c->rc, NULL, NULL, &tag, 1);
++ c->rc.size = wc->byte_len;
++ err = p9_parse_header(&c->rc, NULL, NULL, &tag, 1);
+ if (err)
+ goto err_out;
+
+@@ -331,12 +331,13 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)
+
+ /* Check that we have not yet received a reply for this request.
+ */
+- if (unlikely(req->rc)) {
++ if (unlikely(req->rc.sdata)) {
+ pr_err("Duplicate reply for request %d", tag);
+ goto err_out;
+ }
+
+- req->rc = c->rc;
++ req->rc.size = c->rc.size;
++ req->rc.sdata = c->rc.sdata;
+ p9_client_cb(client, req, REQ_STATUS_RCVD);
+
+ out:
+@@ -361,7 +362,7 @@ send_done(struct ib_cq *cq, struct ib_wc *wc)
+ container_of(wc->wr_cqe, struct p9_rdma_context, cqe);
+
+ ib_dma_unmap_single(rdma->cm_id->device,
+- c->busa, c->req->tc->size,
++ c->busa, c->req->tc.size,
+ DMA_TO_DEVICE);
+ up(&rdma->sq_sem);
+ kfree(c);
+@@ -401,7 +402,7 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c)
+ struct ib_sge sge;
+
+ c->busa = ib_dma_map_single(rdma->cm_id->device,
+- c->rc->sdata, client->msize,
++ c->rc.sdata, client->msize,
+ DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(rdma->cm_id->device, c->busa))
+ goto error;
+@@ -443,9 +444,9 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ **/
+ if (unlikely(atomic_read(&rdma->excess_rc) > 0)) {
+ if ((atomic_sub_return(1, &rdma->excess_rc) >= 0)) {
+- /* Got one ! */
+- kfree(req->rc);
+- req->rc = NULL;
++ /* Got one! */
++ p9_fcall_fini(&req->rc);
++ req->rc.sdata = NULL;
+ goto dont_need_post_recv;
+ } else {
+ /* We raced and lost. */
+@@ -459,7 +460,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ err = -ENOMEM;
+ goto recv_error;
+ }
+- rpl_context->rc = req->rc;
++ rpl_context->rc.sdata = req->rc.sdata;
+
+ /*
+ * Post a receive buffer for this request. We need to ensure
+@@ -479,7 +480,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ goto recv_error;
+ }
+ /* remove posted receive buffer from request structure */
+- req->rc = NULL;
++ req->rc.sdata = NULL;
+
+ dont_need_post_recv:
+ /* Post the request */
+@@ -491,7 +492,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ c->req = req;
+
+ c->busa = ib_dma_map_single(rdma->cm_id->device,
+- c->req->tc->sdata, c->req->tc->size,
++ c->req->tc.sdata, c->req->tc.size,
+ DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(rdma->cm_id->device, c->busa)) {
+ err = -EIO;
+@@ -501,7 +502,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ c->cqe.done = send_done;
+
+ sge.addr = c->busa;
+- sge.length = c->req->tc->size;
++ sge.length = c->req->tc.size;
+ sge.lkey = rdma->pd->local_dma_lkey;
+
+ wr.next = NULL;
+diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
+index 7728b0acde09..3dd6ce1c0f2d 100644
+--- a/net/9p/trans_virtio.c
++++ b/net/9p/trans_virtio.c
+@@ -155,7 +155,7 @@ static void req_done(struct virtqueue *vq)
+ }
+
+ if (len) {
+- req->rc->size = len;
++ req->rc.size = len;
+ p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
+ }
+ }
+@@ -273,12 +273,12 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
+ out_sgs = in_sgs = 0;
+ /* Handle out VirtIO ring buffers */
+ out = pack_sg_list(chan->sg, 0,
+- VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
++ VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
+ if (out)
+ sgs[out_sgs++] = chan->sg;
+
+ in = pack_sg_list(chan->sg, out,
+- VIRTQUEUE_NUM, req->rc->sdata, req->rc->capacity);
++ VIRTQUEUE_NUM, req->rc.sdata, req->rc.capacity);
+ if (in)
+ sgs[out_sgs + in_sgs++] = chan->sg + out;
+
+@@ -416,15 +416,15 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
+ if (n != outlen) {
+ __le32 v = cpu_to_le32(n);
+- memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
++ memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
+ outlen = n;
+ }
+ /* The size field of the message must include the length of the
+ * header and the length of the data. We didn't actually know
+ * the length of the data until this point so add it in now.
+ */
+- sz = cpu_to_le32(req->tc->size + outlen);
+- memcpy(&req->tc->sdata[0], &sz, sizeof(sz));
++ sz = cpu_to_le32(req->tc.size + outlen);
++ memcpy(&req->tc.sdata[0], &sz, sizeof(sz));
+ } else if (uidata) {
+ int n = p9_get_mapped_pages(chan, &in_pages, uidata,
+ inlen, &offs, &need_drop);
+@@ -433,7 +433,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE);
+ if (n != inlen) {
+ __le32 v = cpu_to_le32(n);
+- memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4);
++ memcpy(&req->tc.sdata[req->tc.size - 4], &v, 4);
+ inlen = n;
+ }
+ }
+@@ -445,7 +445,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+
+ /* out data */
+ out = pack_sg_list(chan->sg, 0,
+- VIRTQUEUE_NUM, req->tc->sdata, req->tc->size);
++ VIRTQUEUE_NUM, req->tc.sdata, req->tc.size);
+
+ if (out)
+ sgs[out_sgs++] = chan->sg;
+@@ -464,7 +464,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
+ * alloced memory and payload onto the user buffer.
+ */
+ in = pack_sg_list(chan->sg, out,
+- VIRTQUEUE_NUM, req->rc->sdata, in_hdr_len);
++ VIRTQUEUE_NUM, req->rc.sdata, in_hdr_len);
+ if (in)
+ sgs[out_sgs + in_sgs++] = chan->sg + out;
+
+diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
+index 843cb823d9b9..782a07f2ad0c 100644
+--- a/net/9p/trans_xen.c
++++ b/net/9p/trans_xen.c
+@@ -141,7 +141,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
+ struct xen_9pfs_front_priv *priv = NULL;
+ RING_IDX cons, prod, masked_cons, masked_prod;
+ unsigned long flags;
+- u32 size = p9_req->tc->size;
++ u32 size = p9_req->tc.size;
+ struct xen_9pfs_dataring *ring;
+ int num;
+
+@@ -154,7 +154,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
+ if (!priv || priv->client != client)
+ return -EINVAL;
+
+- num = p9_req->tc->tag % priv->num_rings;
++ num = p9_req->tc.tag % priv->num_rings;
+ ring = &priv->rings[num];
+
+ again:
+@@ -176,7 +176,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
+ masked_prod = xen_9pfs_mask(prod, XEN_9PFS_RING_SIZE);
+ masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE);
+
+- xen_9pfs_write_packet(ring->data.out, p9_req->tc->sdata, size,
++ xen_9pfs_write_packet(ring->data.out, p9_req->tc.sdata, size,
+ &masked_prod, masked_cons, XEN_9PFS_RING_SIZE);
+
+ p9_req->status = REQ_STATUS_SENT;
+@@ -229,12 +229,12 @@ static void p9_xen_response(struct work_struct *work)
+ continue;
+ }
+
+- memcpy(req->rc, &h, sizeof(h));
+- req->rc->offset = 0;
++ memcpy(&req->rc, &h, sizeof(h));
++ req->rc.offset = 0;
+
+ masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE);
+ /* Then, read the whole packet (including the header) */
+- xen_9pfs_read_packet(req->rc->sdata, ring->data.in, h.size,
++ xen_9pfs_read_packet(req->rc.sdata, ring->data.in, h.size,
+ masked_prod, &masked_cons,
+ XEN_9PFS_RING_SIZE);
+
+--
+2.20.1
+
--- /dev/null
+From e127daee55b27e4dce1403e9b2e2b2323cfece4a Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Sat, 8 Sep 2018 00:36:08 +0900
+Subject: 9p: p9dirent_read: check network-provided name length
+
+[ Upstream commit ef5305f1f72eb1cfcda25c382bb0368509c0385b ]
+
+strcpy to dirent->d_name could overflow the buffer, use strscpy to check
+the provided string length and error out if the size was too big.
+
+While we are here, make the function return an error when the pdu
+parsing failed, instead of returning the pdu offset as if it had been a
+success...
+
+Link: http://lkml.kernel.org/r/1536339057-21974-4-git-send-email-asmadeus@codewreck.org
+Addresses-Coverity-ID: 139133 ("Copy into fixed size buffer")
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/protocol.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/net/9p/protocol.c b/net/9p/protocol.c
+index b4d80c533f89..462ba144cb39 100644
+--- a/net/9p/protocol.c
++++ b/net/9p/protocol.c
+@@ -623,13 +623,19 @@ int p9dirent_read(struct p9_client *clnt, char *buf, int len,
+ if (ret) {
+ p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
+ trace_9p_protocol_dump(clnt, &fake_pdu);
+- goto out;
++ return ret;
+ }
+
+- strcpy(dirent->d_name, nameptr);
++ ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
++ if (ret < 0) {
++ p9_debug(P9_DEBUG_ERROR,
++ "On the wire dirent name too long: %s\n",
++ nameptr);
++ kfree(nameptr);
++ return ret;
++ }
+ kfree(nameptr);
+
+-out:
+ return fake_pdu.offset;
+ }
+ EXPORT_SYMBOL(p9dirent_read);
+--
+2.20.1
+
--- /dev/null
+From 1bf47ad7306660e0d0aa4ca0a3f1f96ada81a363 Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Wed, 26 Sep 2018 13:39:34 +0300
+Subject: 9p: potential NULL dereference
+
+[ Upstream commit 72ea0321088df2c41eca8cc6160c24bcceb56ac7 ]
+
+p9_tag_alloc() is supposed to return error pointers, but we accidentally
+return a NULL here. It would cause a NULL dereference in the caller.
+
+Link: http://lkml.kernel.org/m/20180926103934.GA14535@mwanda
+Fixes: 996d5b4db4b1 ("9p: Use a slab for allocating requests")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/client.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 4becde979462..b615aae5a0f8 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -287,7 +287,7 @@ p9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size)
+ int tag;
+
+ if (!req)
+- return NULL;
++ return ERR_PTR(-ENOMEM);
+
+ if (p9_fcall_init(c, &req->tc, alloc_msize))
+ goto free_req;
+--
+2.20.1
+
--- /dev/null
+From a4cdf04d2a16298843246f7a7c0dfb650c540d9c Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Thu, 30 Aug 2018 19:29:36 +0900
+Subject: 9p/rdma: do not disconnect on down_interruptible EAGAIN
+
+[ Upstream commit 8b894adb2b7e1d1e64b8954569c761eaf3d51ab5 ]
+
+9p/rdma would sometimes drop the connection and display errors in
+recv_done when the user does ^C.
+The errors were caused by recv buffers that were posted at the time
+of disconnect, and we just do not want to disconnect when
+down_interruptible is... interrupted.
+
+Link: http://lkml.kernel.org/r/1535625307-18019-1-git-send-email-asmadeus@codewreck.org
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_rdma.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
+index 9cc9b3a19ee7..9719bc4d9424 100644
+--- a/net/9p/trans_rdma.c
++++ b/net/9p/trans_rdma.c
+@@ -477,7 +477,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+
+ err = post_recv(client, rpl_context);
+ if (err) {
+- p9_debug(P9_DEBUG_FCALL, "POST RECV failed\n");
++ p9_debug(P9_DEBUG_ERROR, "POST RECV failed: %d\n", err);
+ goto recv_error;
+ }
+ /* remove posted receive buffer from request structure */
+@@ -546,7 +546,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
+ recv_error:
+ kfree(rpl_context);
+ spin_lock_irqsave(&rdma->req_lock, flags);
+- if (rdma->state < P9_RDMA_CLOSING) {
++ if (err != -EINTR && rdma->state < P9_RDMA_CLOSING) {
+ rdma->state = P9_RDMA_CLOSING;
+ spin_unlock_irqrestore(&rdma->req_lock, flags);
+ rdma_disconnect(rdma->cm_id);
+--
+2.20.1
+
--- /dev/null
+From 60bde75379faa65ea117eea23694c41076f51a51 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Sat, 8 Sep 2018 00:26:50 +0900
+Subject: 9p/rdma: remove useless check in cm_event_handler
+
+[ Upstream commit 473c7dd1d7b59ff8f88a5154737e3eac78a96e5b ]
+
+the client c is always dereferenced to get the rdma struct, so c has to
+be a valid pointer at this point.
+Gcc would optimize that away but let's make coverity happy...
+
+Link: http://lkml.kernel.org/r/1536339057-21974-3-git-send-email-asmadeus@codewreck.org
+Addresses-Coverity-ID: 102778 ("Dereference before null check")
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_rdma.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
+index 9719bc4d9424..119103bfa82e 100644
+--- a/net/9p/trans_rdma.c
++++ b/net/9p/trans_rdma.c
+@@ -274,8 +274,7 @@ p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
+ case RDMA_CM_EVENT_DISCONNECTED:
+ if (rdma)
+ rdma->state = P9_RDMA_CLOSED;
+- if (c)
+- c->status = Disconnected;
++ c->status = Disconnected;
+ break;
+
+ case RDMA_CM_EVENT_TIMEWAIT_EXIT:
+--
+2.20.1
+
--- /dev/null
+From 88d4d894ebd7dbe5f31e765434cbe08ca0ea46e7 Mon Sep 17 00:00:00 2001
+From: Tomas Bortoli <tomasbortoli@gmail.com>
+Date: Sat, 11 Aug 2018 16:42:53 +0200
+Subject: 9p: rename p9_free_req() function
+
+[ Upstream commit 43cbcbee9938b17f77cf34f1bc12d302f456810f ]
+
+In sight of the next patch to add a refcount in p9_req_t, rename
+the p9_free_req() function in p9_release_req().
+
+In the next patch the actual kfree will be moved to another function.
+
+Link: http://lkml.kernel.org/r/20180811144254.23665-1-tomasbortoli@gmail.com
+Signed-off-by: Tomas Bortoli <tomasbortoli@gmail.com>
+Acked-by: Jun Piao <piaojun@huawei.com>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/client.c | 100 ++++++++++++++++++++++++------------------------
+ 1 file changed, 50 insertions(+), 50 deletions(-)
+
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 7ef54719c6f7..3cde9f619980 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -347,13 +347,13 @@ struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
+ EXPORT_SYMBOL(p9_tag_lookup);
+
+ /**
+- * p9_free_req - Free a request.
++ * p9_tag_remove - Remove a tag.
+ * @c: Client session.
+- * @r: Request to free.
++ * @r: Request of reference.
+ *
+ * Context: Any context.
+ */
+-static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
++static void p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
+ {
+ unsigned long flags;
+ u16 tag = r->tc.tag;
+@@ -382,7 +382,7 @@ static void p9_tag_cleanup(struct p9_client *c)
+ rcu_read_lock();
+ idr_for_each_entry(&c->reqs, req, id) {
+ pr_info("Tag %d still in use\n", id);
+- p9_free_req(c, req);
++ p9_tag_remove(c, req);
+ }
+ rcu_read_unlock();
+ }
+@@ -650,7 +650,7 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
+ if (c->trans_mod->cancelled)
+ c->trans_mod->cancelled(c, oldreq);
+
+- p9_free_req(c, req);
++ p9_tag_remove(c, req);
+ return 0;
+ }
+
+@@ -684,7 +684,7 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
+ trace_9p_client_req(c, type, req->tc.tag);
+ return req;
+ reterr:
+- p9_free_req(c, req);
++ p9_tag_remove(c, req);
+ return ERR_PTR(err);
+ }
+
+@@ -694,7 +694,7 @@ static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
+ * @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 *
+@@ -770,7 +770,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
+ if (!err)
+ return req;
+ reterr:
+- p9_free_req(c, req);
++ p9_tag_remove(c, req);
+ return ERR_PTR(safe_errno(err));
+ }
+
+@@ -785,7 +785,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
+ * @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,
+@@ -852,7 +852,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
+ if (!err)
+ return req;
+ reterr:
+- p9_free_req(c, req);
++ p9_tag_remove(c, req);
+ return ERR_PTR(safe_errno(err));
+ }
+
+@@ -963,7 +963,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;
+ }
+@@ -1112,7 +1112,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", &qid);
+ if (err) {
+ trace_9p_protocol_dump(clnt, &req->rc);
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ goto error;
+ }
+
+@@ -1121,7 +1121,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:
+@@ -1169,10 +1169,10 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
+ 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);
++ 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);
+
+@@ -1247,7 +1247,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;
+ }
+@@ -1292,7 +1292,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;
+ }
+@@ -1337,7 +1337,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;
+ }
+@@ -1371,7 +1371,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;
+ }
+@@ -1391,7 +1391,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);
+@@ -1415,7 +1415,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;
+@@ -1450,7 +1450,7 @@ int p9_client_clunk(struct p9_fid *fid)
+
+ 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
+@@ -1484,7 +1484,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);
+@@ -1511,7 +1511,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;
+ }
+@@ -1563,7 +1563,7 @@ p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
+ "D", &count, &dataptr);
+ if (*err) {
+ trace_9p_protocol_dump(clnt, &req->rc);
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ break;
+ }
+ if (rsize < count) {
+@@ -1573,7 +1573,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;
+ }
+
+@@ -1583,7 +1583,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 {
+@@ -1591,7 +1591,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;
+ }
+@@ -1635,7 +1635,7 @@ p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
+ *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &count);
+ if (*err) {
+ trace_9p_protocol_dump(clnt, &req->rc);
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ break;
+ }
+ if (rsize < count) {
+@@ -1645,7 +1645,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;
+@@ -1679,7 +1679,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
+ 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);
++ p9_tag_remove(clnt, req);
+ goto error;
+ }
+
+@@ -1696,7 +1696,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:
+@@ -1732,7 +1732,7 @@ struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
+ err = p9pdu_readf(&req->rc, clnt->proto_version, "A", ret);
+ if (err) {
+ trace_9p_protocol_dump(clnt, &req->rc);
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ goto error;
+ }
+
+@@ -1757,7 +1757,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:
+@@ -1826,7 +1826,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;
+ }
+@@ -1858,7 +1858,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;
+ }
+@@ -1886,7 +1886,7 @@ int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
+ &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
+ if (err) {
+ trace_9p_protocol_dump(clnt, &req->rc);
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ goto error;
+ }
+
+@@ -1897,7 +1897,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;
+ }
+@@ -1925,7 +1925,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;
+ }
+@@ -1955,7 +1955,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;
+ }
+@@ -1992,10 +1992,10 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
+ 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);
++ 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;
+@@ -2029,7 +2029,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;
+ }
+@@ -2092,11 +2092,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;
+ }
+@@ -2127,7 +2127,7 @@ int p9_client_mknod_dotl(struct p9_fid *fid, const char *name, int mode,
+ (unsigned long long)qid->path, qid->version);
+
+ error:
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ return err;
+
+ }
+@@ -2158,7 +2158,7 @@ int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
+ (unsigned long long)qid->path, qid->version);
+
+ error:
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ return err;
+
+ }
+@@ -2191,7 +2191,7 @@ int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
+ }
+ p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
+ error:
+- p9_free_req(clnt, req);
++ p9_tag_remove(clnt, req);
+ return err;
+
+ }
+@@ -2226,7 +2226,7 @@ int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
+ "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);
+@@ -2252,7 +2252,7 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
+ }
+ 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);
+--
+2.20.1
+
--- /dev/null
+From 02d2b1cb4288e1415904551c8d589cef979258ba Mon Sep 17 00:00:00 2001
+From: Tomas Bortoli <tomasbortoli@gmail.com>
+Date: Mon, 3 Sep 2018 18:03:21 +0200
+Subject: 9p: Rename req to rreq in trans_fd
+
+[ Upstream commit 6d35190f395316916c8bb4aabd35a182890bf856 ]
+
+In struct p9_conn, rename req to rreq as it is used by the read routine.
+
+Link: http://lkml.kernel.org/r/20180903160321.2181-1-tomasbortoli@gmail.com
+Signed-off-by: Tomas Bortoli <tomasbortoli@gmail.com>
+Suggested-by: Jun Piao <piaojun@huawei.com>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_fd.c | 30 +++++++++++++++---------------
+ 1 file changed, 15 insertions(+), 15 deletions(-)
+
+diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
+index aca528722183..12559c474dde 100644
+--- a/net/9p/trans_fd.c
++++ b/net/9p/trans_fd.c
+@@ -131,7 +131,7 @@ struct p9_conn {
+ int err;
+ struct list_head req_list;
+ struct list_head unsent_req_list;
+- struct p9_req_t *req;
++ struct p9_req_t *rreq;
+ struct p9_req_t *wreq;
+ char tmp_buf[7];
+ struct p9_fcall rc;
+@@ -323,7 +323,7 @@ static void p9_read_work(struct work_struct *work)
+ m->rc.offset += err;
+
+ /* header read in */
+- if ((!m->req) && (m->rc.offset == m->rc.capacity)) {
++ if ((!m->rreq) && (m->rc.offset == m->rc.capacity)) {
+ p9_debug(P9_DEBUG_TRANS, "got new header\n");
+
+ /* Header size */
+@@ -347,23 +347,23 @@ static void p9_read_work(struct work_struct *work)
+ "mux %p pkt: size: %d bytes tag: %d\n",
+ m, m->rc.size, m->rc.tag);
+
+- m->req = p9_tag_lookup(m->client, m->rc.tag);
+- if (!m->req || (m->req->status != REQ_STATUS_SENT)) {
++ m->rreq = p9_tag_lookup(m->client, m->rc.tag);
++ if (!m->rreq || (m->rreq->status != REQ_STATUS_SENT)) {
+ p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n",
+ m->rc.tag);
+ err = -EIO;
+ goto error;
+ }
+
+- if (!m->req->rc.sdata) {
++ if (!m->rreq->rc.sdata) {
+ p9_debug(P9_DEBUG_ERROR,
+ "No recv fcall for tag %d (req %p), disconnecting!\n",
+- m->rc.tag, m->req);
+- m->req = NULL;
++ m->rc.tag, m->rreq);
++ m->rreq = NULL;
+ err = -EIO;
+ goto error;
+ }
+- m->rc.sdata = m->req->rc.sdata;
++ m->rc.sdata = m->rreq->rc.sdata;
+ memcpy(m->rc.sdata, m->tmp_buf, m->rc.capacity);
+ m->rc.capacity = m->rc.size;
+ }
+@@ -371,21 +371,21 @@ static void p9_read_work(struct work_struct *work)
+ /* packet is read in
+ * not an else because some packets (like clunk) have no payload
+ */
+- if ((m->req) && (m->rc.offset == m->rc.capacity)) {
++ if ((m->rreq) && (m->rc.offset == m->rc.capacity)) {
+ p9_debug(P9_DEBUG_TRANS, "got new packet\n");
+- m->req->rc.size = m->rc.offset;
++ m->rreq->rc.size = m->rc.offset;
+ spin_lock(&m->client->lock);
+- if (m->req->status != REQ_STATUS_ERROR)
++ if (m->rreq->status != REQ_STATUS_ERROR)
+ status = REQ_STATUS_RCVD;
+- list_del(&m->req->req_list);
++ list_del(&m->rreq->req_list);
+ /* update req->status while holding client->lock */
+- p9_client_cb(m->client, m->req, status);
++ p9_client_cb(m->client, m->rreq, status);
+ spin_unlock(&m->client->lock);
+ m->rc.sdata = NULL;
+ m->rc.offset = 0;
+ m->rc.capacity = 0;
+- p9_req_put(m->req);
+- m->req = NULL;
++ p9_req_put(m->rreq);
++ m->rreq = NULL;
+ }
+
+ end_clear:
+--
+2.20.1
+
--- /dev/null
+From 7c574af33f301066e6e23624f2f0b42c2763dae9 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Tue, 9 Oct 2018 11:18:52 +0900
+Subject: 9p/trans_fd: abort p9_read_work if req status changed
+
+[ Upstream commit e4ca13f7d075e551dc158df6af18fb412a1dba0a ]
+
+p9_read_work would try to handle an errored req even if it got put to
+error state by another thread between the lookup (that worked) and the
+time it had been fully read.
+The request itself is safe to use because we hold a ref to it from the
+lookup (for m->rreq, so it was safe to read into the request data buffer
+until this point), but the req_list has been deleted at the same time
+status changed, and client_cb already has been called as well, so we
+should not do either.
+
+Link: http://lkml.kernel.org/r/1539057956-23741-1-git-send-email-asmadeus@codewreck.org
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Reported-by: syzbot+2222c34dc40b515f30dc@syzkaller.appspotmail.com
+Cc: Eric Van Hensbergen <ericvh@gmail.com>
+Cc: Latchesar Ionkov <lucho@ionkov.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_fd.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
+index 12559c474dde..a0317d459cde 100644
+--- a/net/9p/trans_fd.c
++++ b/net/9p/trans_fd.c
+@@ -292,7 +292,6 @@ static void p9_read_work(struct work_struct *work)
+ __poll_t n;
+ int err;
+ struct p9_conn *m;
+- int status = REQ_STATUS_ERROR;
+
+ m = container_of(work, struct p9_conn, rq);
+
+@@ -375,11 +374,17 @@ static void p9_read_work(struct work_struct *work)
+ p9_debug(P9_DEBUG_TRANS, "got new packet\n");
+ m->rreq->rc.size = m->rc.offset;
+ spin_lock(&m->client->lock);
+- if (m->rreq->status != REQ_STATUS_ERROR)
+- status = REQ_STATUS_RCVD;
+- list_del(&m->rreq->req_list);
+- /* update req->status while holding client->lock */
+- p9_client_cb(m->client, m->rreq, status);
++ if (m->rreq->status == REQ_STATUS_SENT) {
++ list_del(&m->rreq->req_list);
++ p9_client_cb(m->client, m->rreq, REQ_STATUS_RCVD);
++ } else {
++ spin_unlock(&m->client->lock);
++ p9_debug(P9_DEBUG_ERROR,
++ "Request tag %d errored out while we were reading the reply\n",
++ m->rc.tag);
++ err = -EIO;
++ goto error;
++ }
+ spin_unlock(&m->client->lock);
+ m->rc.sdata = NULL;
+ m->rc.offset = 0;
+--
+2.20.1
+
--- /dev/null
+From 9208d3efd469cb372f4d2cc9c3813a96a9b75059 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Tue, 9 Oct 2018 11:38:00 +0900
+Subject: 9p/trans_fd: put worker reqs on destroy
+
+[ Upstream commit fb488fc1f2b4c5128540b032892ddec91edaf8d9 ]
+
+p9_read_work/p9_write_work might still hold references to a req after
+having been cancelled; make sure we put any of these to avoid potential
+request leak on disconnect.
+
+Fixes: 728356dedeff8 ("9p: Add refcount to p9_req_t")
+Link: http://lkml.kernel.org/r/1539057956-23741-2-git-send-email-asmadeus@codewreck.org
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Cc: Eric Van Hensbergen <ericvh@gmail.com>
+Cc: Latchesar Ionkov <lucho@ionkov.net>
+Reviewed-by: Tomas Bortoli <tomasbortoli@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_fd.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
+index a0317d459cde..f868cf6fba79 100644
+--- a/net/9p/trans_fd.c
++++ b/net/9p/trans_fd.c
+@@ -876,7 +876,15 @@ static void p9_conn_destroy(struct p9_conn *m)
+
+ p9_mux_poll_stop(m);
+ cancel_work_sync(&m->rq);
++ if (m->rreq) {
++ p9_req_put(m->rreq);
++ m->rreq = NULL;
++ }
+ cancel_work_sync(&m->wq);
++ if (m->wreq) {
++ p9_req_put(m->wreq);
++ m->wreq = NULL;
++ }
+
+ p9_conn_cancel(m, -ECONNRESET);
+
+--
+2.20.1
+
--- /dev/null
+From a69554b8cb8348d09321240c12d36418eda20d12 Mon Sep 17 00:00:00 2001
+From: Matthew Wilcox <willy@infradead.org>
+Date: Wed, 11 Jul 2018 14:02:24 -0700
+Subject: 9p: Use a slab for allocating requests
+
+[ Upstream commit 996d5b4db4b191f2676cf8775565cab8a5e2753b ]
+
+Replace the custom batch allocation with a slab. Use an IDR to store
+pointers to the active requests instead of an array. We don't try to
+handle P9_NOTAG specially; the IDR will happily shrink all the way back
+once the TVERSION call has completed.
+
+Link: http://lkml.kernel.org/r/20180711210225.19730-6-willy@infradead.org
+Signed-off-by: Matthew Wilcox <willy@infradead.org>
+Cc: Eric Van Hensbergen <ericvh@gmail.com>
+Cc: Ron Minnich <rminnich@sandia.gov>
+Cc: Latchesar Ionkov <lucho@ionkov.net>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/9p/client.h | 51 ++-------
+ net/9p/client.c | 238 ++++++++++++++--------------------------
+ net/9p/mod.c | 9 +-
+ 3 files changed, 102 insertions(+), 196 deletions(-)
+
+diff --git a/include/net/9p/client.h b/include/net/9p/client.h
+index 0fa0fbab33b0..a4dc42c53d18 100644
+--- a/include/net/9p/client.h
++++ b/include/net/9p/client.h
+@@ -64,22 +64,15 @@ enum p9_trans_status {
+
+ /**
+ * enum p9_req_status_t - status of a request
+- * @REQ_STATUS_IDLE: request slot unused
+ * @REQ_STATUS_ALLOC: request has been allocated but not sent
+ * @REQ_STATUS_UNSENT: request waiting to be sent
+ * @REQ_STATUS_SENT: request sent to server
+ * @REQ_STATUS_RCVD: response received from server
+ * @REQ_STATUS_FLSHD: request has been flushed
+ * @REQ_STATUS_ERROR: request encountered an error on the client side
+- *
+- * The @REQ_STATUS_IDLE state is used to mark a request slot as unused
+- * but use is actually tracked by the idpool structure which handles tag
+- * id allocation.
+- *
+ */
+
+ enum p9_req_status_t {
+- REQ_STATUS_IDLE,
+ REQ_STATUS_ALLOC,
+ REQ_STATUS_UNSENT,
+ REQ_STATUS_SENT,
+@@ -92,24 +85,12 @@ enum p9_req_status_t {
+ * struct p9_req_t - request slots
+ * @status: status of this request slot
+ * @t_err: transport error
+- * @flush_tag: tag of request being flushed (for flush requests)
+ * @wq: wait_queue for the client to block on for this request
+ * @tc: the request fcall structure
+ * @rc: the response fcall structure
+ * @aux: transport specific data (provided for trans_fd migration)
+ * @req_list: link for higher level objects to chain requests
+- *
+- * Transport use an array to track outstanding requests
+- * instead of a list. While this may incurr overhead during initial
+- * allocation or expansion, it makes request lookup much easier as the
+- * tag id is a index into an array. (We use tag+1 so that we can accommodate
+- * the -1 tag for the T_VERSION request).
+- * This also has the nice effect of only having to allocate wait_queues
+- * once, instead of constantly allocating and freeing them. Its possible
+- * other resources could benefit from this scheme as well.
+- *
+ */
+-
+ struct p9_req_t {
+ int status;
+ int t_err;
+@@ -117,40 +98,26 @@ struct p9_req_t {
+ struct p9_fcall *tc;
+ struct p9_fcall *rc;
+ void *aux;
+-
+ struct list_head req_list;
+ };
+
+ /**
+ * struct p9_client - per client instance state
+- * @lock: protect @fidlist
++ * @lock: protect @fids and @reqs
+ * @msize: maximum data size negotiated by protocol
+- * @dotu: extension flags negotiated by protocol
+ * @proto_version: 9P protocol version to use
+ * @trans_mod: module API instantiated with this client
++ * @status: connection state
+ * @trans: tranport instance state and API
+ * @fids: All active FID handles
+- * @tagpool - transaction id accounting for session
+- * @reqs - 2D array of requests
+- * @max_tag - current maximum tag id allocated
+- * @name - node name used as client id
++ * @reqs: All active requests.
++ * @name: node name used as client id
+ *
+ * The client structure is used to keep track of various per-client
+ * state that has been instantiated.
+- * In order to minimize per-transaction overhead we use a
+- * simple array to lookup requests instead of a hash table
+- * or linked list. In order to support larger number of
+- * transactions, we make this a 2D array, allocating new rows
+- * when we need to grow the total number of the transactions.
+- *
+- * Each row is 256 requests and we'll support up to 256 rows for
+- * a total of 64k concurrent requests per session.
+- *
+- * Bugs: duplicated data and potentially unnecessary elements.
+ */
+-
+ struct p9_client {
+- spinlock_t lock; /* protect client structure */
++ spinlock_t lock;
+ unsigned int msize;
+ unsigned char proto_version;
+ struct p9_trans_module *trans_mod;
+@@ -170,10 +137,7 @@ struct p9_client {
+ } trans_opts;
+
+ struct idr fids;
+-
+- struct p9_idpool *tagpool;
+- struct p9_req_t *reqs[P9_ROW_MAXTAG];
+- int max_tag;
++ struct idr reqs;
+
+ char name[__NEW_UTS_LEN + 1];
+ };
+@@ -279,4 +243,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
+ int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
+ int p9_client_readlink(struct p9_fid *fid, char **target);
+
++int p9_client_init(void);
++void p9_client_exit(void);
++
+ #endif /* NET_9P_CLIENT_H */
+diff --git a/net/9p/client.c b/net/9p/client.c
+index 23ec6187dc07..d8949c59d46e 100644
+--- a/net/9p/client.c
++++ b/net/9p/client.c
+@@ -248,132 +248,102 @@ static struct p9_fcall *p9_fcall_alloc(int alloc_msize)
+ return fc;
+ }
+
++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;
++ if (!req)
++ return NULL;
+
+- 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);
++ req->tc = p9_fcall_alloc(alloc_msize);
++ req->rc = p9_fcall_alloc(alloc_msize);
+ if (!req->tc || !req->rc)
+- goto grow_failed;
++ goto free;
+
+ p9pdu_reset(req->tc);
+ p9pdu_reset(req->rc);
+-
+- req->tc->tag = tag-1;
+ 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;
+
+ return req;
+
+-grow_failed:
+- pr_err("Couldn't grow tag array\n");
++free:
+ kfree(req->tc);
+ kfree(req->rc);
+- req->tc = req->rc = NULL;
++ 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();
++ req = idr_find(&c->reqs, tag);
++ /* There's no refcount on the req; a malicious server could cause
++ * us to dereference a NULL pointer
++ */
++ 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_free_req - Free a request.
++ * @c: Client session.
++ * @r: Request to free.
+ *
++ * Context: Any context.
+ */
+-
+-static int p9_tag_init(struct p9_client *c)
++static void p9_free_req(struct p9_client *c, struct p9_req_t *r)
+ {
+- int err = 0;
++ unsigned long flags;
++ u16 tag = r->tc->tag;
+
+- 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;
++ 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);
++ kfree(r->tc);
++ kfree(r->rc);
++ kmem_cache_free(p9_req_cache, r);
+ }
+
+ /**
+@@ -385,52 +355,15 @@ static int p9_tag_init(struct p9_client *c)
+ */
+ 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);
++ p9_free_req(c, req);
+ }
+- 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();
+ }
+
+ /**
+@@ -704,7 +637,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);
+@@ -717,24 +650,17 @@ 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);
++ 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);
++ trace_9p_client_req(c, type, req->tc->tag);
+ return req;
+ reterr:
+ p9_free_req(c, req);
+@@ -1040,14 +966,11 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
+
+ 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();
+@@ -1056,7 +979,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",
+@@ -1086,8 +1009,6 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
+ 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);
+@@ -2303,3 +2224,14 @@ int p9_client_readlink(struct p9_fid *fid, char **target)
+ return err;
+ }
+ EXPORT_SYMBOL(p9_client_readlink);
++
++int __init p9_client_init(void)
++{
++ p9_req_cache = KMEM_CACHE(p9_req_t, 0);
++ return p9_req_cache ? 0 : -ENOMEM;
++}
++
++void __exit p9_client_exit(void)
++{
++ kmem_cache_destroy(p9_req_cache);
++}
+diff --git a/net/9p/mod.c b/net/9p/mod.c
+index 253ba824a325..0da56d6af73b 100644
+--- a/net/9p/mod.c
++++ b/net/9p/mod.c
+@@ -171,11 +171,17 @@ void v9fs_put_trans(struct p9_trans_module *m)
+ */
+ static int __init init_p9(void)
+ {
++ int ret;
++
++ ret = p9_client_init();
++ if (ret)
++ return ret;
++
+ p9_error_init();
+ pr_info("Installing 9P2000 support\n");
+ p9_trans_fd_init();
+
+- return 0;
++ return ret;
+ }
+
+ /**
+@@ -188,6 +194,7 @@ static void __exit exit_p9(void)
+ pr_info("Unloading 9P2000 support\n");
+
+ p9_trans_fd_exit();
++ p9_client_exit();
+ }
+
+ module_init(init_p9)
+--
+2.20.1
+
--- /dev/null
+From 8535a8e62b2c7452ddec9c32ed184f35d37bc1fb Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@cea.fr>
+Date: Tue, 14 Aug 2018 02:43:48 +0000
+Subject: 9p/xen: fix check for xenbus_read error in front_probe
+
+[ Upstream commit 2f9ad0ac947ccbe3ffe7c6229c9330f2a7755f64 ]
+
+If the xen bus exists but does not expose the proper interface, it is
+possible to get a non-zero length but still some error, leading to
+strcmp failing trying to load invalid memory addresses e.g.
+fffffffffffffffe.
+
+There is then no need to check length when there is no error, as the
+xenbus driver guarantees that the string is nul-terminated.
+
+Link: http://lkml.kernel.org/r/1534236007-10170-1-git-send-email-asmadeus@codewreck.org
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
+Cc: Eric Van Hensbergen <ericvh@gmail.com>
+Cc: Latchesar Ionkov <lucho@ionkov.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_xen.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
+index c2d54ac76bfd..843cb823d9b9 100644
+--- a/net/9p/trans_xen.c
++++ b/net/9p/trans_xen.c
+@@ -391,8 +391,8 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev,
+ unsigned int max_rings, max_ring_order, len = 0;
+
+ versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len);
+- if (!len)
+- return -EINVAL;
++ if (IS_ERR(versions))
++ return PTR_ERR(versions);
+ if (strcmp(versions, "1")) {
+ kfree(versions);
+ return -EINVAL;
+--
+2.20.1
+
--- /dev/null
+From f46adcd7b195a6d28e36f157fbca17f101ac65fa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Adeodato=20Sim=C3=B3?= <dato@net.com.org.es>
+Date: Tue, 13 Nov 2018 03:28:53 -0300
+Subject: net/9p: include trans_common.h to fix missing prototype warning.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+[ Upstream commit 52ad259eaac0454c1ac7123e7148cf8d6e6f5301 ]
+
+This silences -Wmissing-prototypes when defining p9_release_pages.
+
+Link: http://lkml.kernel.org/r/b1c4df8f21689b10d451c28fe38e860722d20e71.1542089696.git.dato@net.com.org.es
+Signed-off-by: Adeodato Simó <dato@net.com.org.es>
+Signed-off-by: Dominique Martinet <dominique.martinet@cea.fr>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/9p/trans_common.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c
+index b718db2085b2..3dff68f05fb9 100644
+--- a/net/9p/trans_common.c
++++ b/net/9p/trans_common.c
+@@ -14,6 +14,7 @@
+
+ #include <linux/mm.h>
+ #include <linux/module.h>
++#include "trans_common.h"
+
+ /**
+ * p9_release_pages - Release pages after the transaction.
+--
+2.20.1
+
arm64-don-t-unconditionally-add-wno-psabi-to-kbuild_cflags.patch
revert-x86-uaccess-ftrace-fix-ftrace_likely_update-v.patch
ib-hfi1-close-psm-sdma_progress-sleep-window.patch
+9p-xen-fix-check-for-xenbus_read-error-in-front_prob.patch
+9p-use-a-slab-for-allocating-requests.patch
+9p-embed-fcall-in-req-to-round-down-buffer-allocs.patch
+9p-add-a-per-client-fcall-kmem_cache.patch
+9p-rename-p9_free_req-function.patch
+9p-add-refcount-to-p9_req_t.patch
+9p-rdma-do-not-disconnect-on-down_interruptible-eaga.patch
+9p-rename-req-to-rreq-in-trans_fd.patch
+9p-acl-fix-uninitialized-iattr-access.patch
+9p-rdma-remove-useless-check-in-cm_event_handler.patch
+9p-p9dirent_read-check-network-provided-name-length.patch
+9p-potential-null-dereference.patch
+9p-trans_fd-abort-p9_read_work-if-req-status-changed.patch
+9p-trans_fd-put-worker-reqs-on-destroy.patch
+net-9p-include-trans_common.h-to-fix-missing-prototy.patch