diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-23 11:39:18 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-23 11:39:18 -0800 |
commit | e3b862ed893bf030ebdd78ead99647374a2cfd47 (patch) | |
tree | b14cabf208e78d9fdac71d44ce4258aab4e36db6 | |
parent | a27405b2ed9c7717ac1ea5587d465234a592c3b3 (diff) | |
parent | 1a4f69ef15ec29b213e2b086b2502644e8ef76ee (diff) |
Merge tag '9p-for-6.2-rc1' of https://github.com/martinetd/linux
Pull 9p updates from Dominique Martinet:
- improve p9_check_errors to check buffer size instead of msize when
possible (e.g. not zero-copy)
- some more syzbot and KCSAN fixes
- minor headers include cleanup
* tag '9p-for-6.2-rc1' of https://github.com/martinetd/linux:
9p/client: fix data race on req->status
net/9p: fix response size check in p9_check_errors()
net/9p: distinguish zero-copy requests
9p/xen: do not memcpy header into req->rc
9p: set req refcount to zero to avoid uninitialized usage
9p/net: Remove unneeded idr.h #include
9p/fs: Remove unneeded idr.h #include
-rw-r--r-- | fs/9p/fid.c | 1 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_addr.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_dentry.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_inode_dotl.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 1 | ||||
-rw-r--r-- | include/net/9p/9p.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 33 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 13 | ||||
-rw-r--r-- | net/9p/trans_rdma.c | 5 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 10 | ||||
-rw-r--r-- | net/9p/trans_xen.c | 8 |
15 files changed, 42 insertions, 38 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 23cf9b2fbfe4..805151114e96 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c @@ -11,7 +11,6 @@ #include <linux/fs.h> #include <linux/slab.h> #include <linux/sched.h> -#include <linux/idr.h> #include <net/9p/9p.h> #include <net/9p/client.h> diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0129de2ea31a..3a9c4517265f 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -14,7 +14,6 @@ #include <linux/sched.h> #include <linux/cred.h> #include <linux/parser.h> -#include <linux/idr.h> #include <linux/slab.h> #include <linux/seq_file.h> #include <net/9p/9p.h> diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index a19891015f19..97599edbc300 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -14,7 +14,6 @@ #include <linux/string.h> #include <linux/inet.h> #include <linux/pagemap.h> -#include <linux/idr.h> #include <linux/sched.h> #include <linux/swap.h> #include <linux/uio.h> diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index f89f01734587..65fa2df5e49b 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -15,7 +15,6 @@ #include <linux/string.h> #include <linux/inet.h> #include <linux/namei.h> -#include <linux/idr.h> #include <linux/sched.h> #include <linux/slab.h> #include <net/9p/9p.h> diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 3bb95adc9619..59b0e8948f78 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -14,7 +14,6 @@ #include <linux/string.h> #include <linux/sched.h> #include <linux/inet.h> -#include <linux/idr.h> #include <linux/slab.h> #include <linux/uio.h> #include <linux/fscache.h> diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index aec43ba83799..b740017634ef 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -18,7 +18,6 @@ #include <linux/pagemap.h> #include <linux/utsname.h> #include <linux/uaccess.h> -#include <linux/idr.h> #include <linux/uio.h> #include <linux/slab.h> #include <net/9p/9p.h> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 4d1a4a8d9277..27a04a226d97 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -17,7 +17,6 @@ #include <linux/string.h> #include <linux/inet.h> #include <linux/namei.h> -#include <linux/idr.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/xattr.h> diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 03c1743c4aff..f806b3f11649 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -15,7 +15,6 @@ #include <linux/string.h> #include <linux/inet.h> #include <linux/namei.h> -#include <linux/idr.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/xattr.h> diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 2d9ee073d12c..266c4693e20c 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -15,7 +15,6 @@ #include <linux/inet.h> #include <linux/pagemap.h> #include <linux/mount.h> -#include <linux/idr.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/statfs.h> diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 13abe013af21..429adf6be29c 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h @@ -531,6 +531,7 @@ struct p9_rstatfs { * @offset: used by marshalling routines to track current position in buffer * @capacity: used by marshalling routines to track total malloc'd capacity * @sdata: payload + * @zc: whether zero-copy is used * * &p9_fcall represents the structure for all 9P RPC * transactions. Requests are packaged into fcalls, and reponses @@ -549,6 +550,7 @@ struct p9_fcall { struct kmem_cache *cache; u8 *sdata; + bool zc; }; int p9_errstr2errno(char *errstr, int len); diff --git a/net/9p/client.c b/net/9p/client.c index 0638b12055ba..622ec6a586ee 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -297,6 +297,11 @@ p9_tag_alloc(struct p9_client *c, int8_t type, uint t_size, uint r_size, p9pdu_reset(&req->rc); req->t_err = 0; req->status = REQ_STATUS_ALLOC; + /* refcount needs to be set to 0 before inserting into the idr + * so p9_tag_lookup does not accept a request that is not fully + * initialized. refcount_set to 2 below will mark request ready. + */ + refcount_set(&req->refcount, 0); init_waitqueue_head(&req->wq); INIT_LIST_HEAD(&req->req_list); @@ -438,7 +443,7 @@ void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status) * the status change is visible to another thread */ smp_wmb(); - req->status = status; + WRITE_ONCE(req->status, status); wake_up(&req->wq); p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag); @@ -514,10 +519,9 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) int ecode; 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); + if (req->rc.size > req->rc.capacity && !req->rc.zc) { + pr_err("requested packet size too big: %d does not fit %zu (type=%d)\n", + req->rc.size, req->rc.capacity, req->rc.id); return -EIO; } /* dump the response from server @@ -600,7 +604,7 @@ 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 (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) { if (c->trans_mod->cancelled) c->trans_mod->cancelled(c, oldreq); } @@ -680,6 +684,9 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) if (IS_ERR(req)) return req; + req->tc.zc = false; + req->rc.zc = false; + if (signal_pending(current)) { sigpending = 1; clear_thread_flag(TIF_SIGPENDING); @@ -697,7 +704,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) } again: /* Wait for the response */ - err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD); + err = wait_event_killable(req->wq, + READ_ONCE(req->status) >= REQ_STATUS_RCVD); /* Make sure our req is coherent with regard to updates in other * threads - echoes to wmb() in the callback @@ -711,7 +719,7 @@ again: goto again; } - if (req->status == REQ_STATUS_ERROR) { + if (READ_ONCE(req->status) == REQ_STATUS_ERROR) { p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); err = req->t_err; } @@ -724,7 +732,7 @@ again: p9_client_flush(c, req); /* if we received the response anyway, don't signal error */ - if (req->status == REQ_STATUS_RCVD) + if (READ_ONCE(req->status) == REQ_STATUS_RCVD) err = 0; } recalc_sigpending: @@ -778,6 +786,9 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, if (IS_ERR(req)) return req; + req->tc.zc = true; + req->rc.zc = true; + if (signal_pending(current)) { sigpending = 1; clear_thread_flag(TIF_SIGPENDING); @@ -793,7 +804,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, if (err != -ERESTARTSYS) goto recalc_sigpending; } - if (req->status == REQ_STATUS_ERROR) { + if (READ_ONCE(req->status) == REQ_STATUS_ERROR) { p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); err = req->t_err; } @@ -806,7 +817,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, p9_client_flush(c, req); /* if we received the response anyway, don't signal error */ - if (req->status == REQ_STATUS_RCVD) + if (READ_ONCE(req->status) == REQ_STATUS_RCVD) err = 0; } recalc_sigpending: diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index d9120f14684b..00b684616e8d 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -20,7 +20,6 @@ #include <linux/un.h> #include <linux/uaccess.h> #include <linux/inet.h> -#include <linux/idr.h> #include <linux/file.h> #include <linux/parser.h> #include <linux/slab.h> @@ -202,11 +201,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err) list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { list_move(&req->req_list, &cancel_list); - req->status = REQ_STATUS_ERROR; + WRITE_ONCE(req->status, REQ_STATUS_ERROR); } list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { list_move(&req->req_list, &cancel_list); - req->status = REQ_STATUS_ERROR; + WRITE_ONCE(req->status, REQ_STATUS_ERROR); } spin_unlock(&m->req_lock); @@ -467,7 +466,7 @@ static void p9_write_work(struct work_struct *work) req = list_entry(m->unsent_req_list.next, struct p9_req_t, req_list); - req->status = REQ_STATUS_SENT; + WRITE_ONCE(req->status, REQ_STATUS_SENT); p9_debug(P9_DEBUG_TRANS, "move req %p\n", req); list_move_tail(&req->req_list, &m->req_list); @@ -676,7 +675,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) return m->err; spin_lock(&m->req_lock); - req->status = REQ_STATUS_UNSENT; + WRITE_ONCE(req->status, REQ_STATUS_UNSENT); list_add_tail(&req->req_list, &m->unsent_req_list); spin_unlock(&m->req_lock); @@ -703,7 +702,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; + WRITE_ONCE(req->status, REQ_STATUS_FLSHD); p9_req_put(client, req); ret = 0; } @@ -732,7 +731,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) * remove it from the list. */ list_del(&req->req_list); - req->status = REQ_STATUS_FLSHD; + WRITE_ONCE(req->status, REQ_STATUS_FLSHD); spin_unlock(&m->req_lock); p9_req_put(client, req); diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 6ff706760676..83f9100d46bf 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -21,7 +21,6 @@ #include <linux/un.h> #include <linux/uaccess.h> #include <linux/inet.h> -#include <linux/idr.h> #include <linux/file.h> #include <linux/parser.h> #include <linux/semaphore.h> @@ -507,7 +506,7 @@ dont_need_post_recv: * because doing if after could erase the REQ_STATUS_RCVD * status in case of a very fast reply. */ - req->status = REQ_STATUS_SENT; + WRITE_ONCE(req->status, REQ_STATUS_SENT); err = ib_post_send(rdma->qp, &wr, NULL); if (err) goto send_error; @@ -517,7 +516,7 @@ dont_need_post_recv: /* Handle errors that happened during or while preparing the send: */ send_error: - req->status = REQ_STATUS_ERROR; + WRITE_ONCE(req->status, REQ_STATUS_ERROR); kfree(c); p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index e757f0601304..3c27ffb781e3 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -22,7 +22,6 @@ #include <linux/un.h> #include <linux/uaccess.h> #include <linux/inet.h> -#include <linux/idr.h> #include <linux/file.h> #include <linux/highmem.h> #include <linux/slab.h> @@ -263,7 +262,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n"); - req->status = REQ_STATUS_SENT; + WRITE_ONCE(req->status, REQ_STATUS_SENT); req_retry: spin_lock_irqsave(&chan->lock, flags); @@ -469,7 +468,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, inlen = n; } } - req->status = REQ_STATUS_SENT; + WRITE_ONCE(req->status, REQ_STATUS_SENT); req_retry_pinned: spin_lock_irqsave(&chan->lock, flags); @@ -532,9 +531,10 @@ req_retry_pinned: 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); + err = wait_event_killable(req->wq, + READ_ONCE(req->status) >= REQ_STATUS_RCVD); // RERROR needs reply (== error string) in static data - if (req->status == REQ_STATUS_RCVD && + if (READ_ONCE(req->status) == REQ_STATUS_RCVD && unlikely(req->rc.sdata[4] == P9_RERROR)) handle_rerror(req, in_hdr_len, offs, in_pages); diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index aaa5fd364691..9630b1275557 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c @@ -157,7 +157,7 @@ again: &masked_prod, masked_cons, XEN_9PFS_RING_SIZE(ring)); - p9_req->status = REQ_STATUS_SENT; + WRITE_ONCE(p9_req->status, REQ_STATUS_SENT); virt_wmb(); /* write ring before updating pointer */ prod += size; ring->intf->out_prod = prod; @@ -212,11 +212,13 @@ static void p9_xen_response(struct work_struct *work) dev_warn(&priv->dev->dev, "requested packet size too big: %d for tag %d with capacity %zd\n", h.size, h.tag, req->rc.capacity); - req->status = REQ_STATUS_ERROR; + WRITE_ONCE(req->status, REQ_STATUS_ERROR); goto recv_error; } - memcpy(&req->rc, &h, sizeof(h)); + req->rc.size = h.size; + req->rc.id = h.id; + req->rc.tag = h.tag; req->rc.offset = 0; masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE(ring)); |