Commit e3b862ed authored by Linus Torvalds's avatar Linus Torvalds

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
parents a27405b2 1a4f69ef
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/idr.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <net/9p/client.h> #include <net/9p/client.h>
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/cred.h> #include <linux/cred.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/idr.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/idr.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/uio.h> #include <linux/uio.h>
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/idr.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/fscache.h> #include <linux/fscache.h>
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/idr.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/xattr.h> #include <linux/xattr.h>
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/xattr.h> #include <linux/xattr.h>
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/idr.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/statfs.h> #include <linux/statfs.h>
......
...@@ -531,6 +531,7 @@ struct p9_rstatfs { ...@@ -531,6 +531,7 @@ struct p9_rstatfs {
* @offset: used by marshalling routines to track current position in buffer * @offset: used by marshalling routines to track current position in buffer
* @capacity: used by marshalling routines to track total malloc'd capacity * @capacity: used by marshalling routines to track total malloc'd capacity
* @sdata: payload * @sdata: payload
* @zc: whether zero-copy is used
* *
* &p9_fcall represents the structure for all 9P RPC * &p9_fcall represents the structure for all 9P RPC
* transactions. Requests are packaged into fcalls, and reponses * transactions. Requests are packaged into fcalls, and reponses
...@@ -549,6 +550,7 @@ struct p9_fcall { ...@@ -549,6 +550,7 @@ struct p9_fcall {
struct kmem_cache *cache; struct kmem_cache *cache;
u8 *sdata; u8 *sdata;
bool zc;
}; };
int p9_errstr2errno(char *errstr, int len); int p9_errstr2errno(char *errstr, int len);
......
...@@ -297,6 +297,11 @@ p9_tag_alloc(struct p9_client *c, int8_t type, uint t_size, uint r_size, ...@@ -297,6 +297,11 @@ p9_tag_alloc(struct p9_client *c, int8_t type, uint t_size, uint r_size,
p9pdu_reset(&req->rc); p9pdu_reset(&req->rc);
req->t_err = 0; req->t_err = 0;
req->status = REQ_STATUS_ALLOC; 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_waitqueue_head(&req->wq);
INIT_LIST_HEAD(&req->req_list); 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) ...@@ -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 * the status change is visible to another thread
*/ */
smp_wmb(); smp_wmb();
req->status = status; WRITE_ONCE(req->status, status);
wake_up(&req->wq); 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);
...@@ -514,10 +519,9 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) ...@@ -514,10 +519,9 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
int ecode; int ecode;
err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
if (req->rc.size >= c->msize) { if (req->rc.size > req->rc.capacity && !req->rc.zc) {
p9_debug(P9_DEBUG_ERROR, pr_err("requested packet size too big: %d does not fit %zu (type=%d)\n",
"requested packet size too big: %d\n", req->rc.size, req->rc.capacity, req->rc.id);
req->rc.size);
return -EIO; return -EIO;
} }
/* dump the response from server /* dump the response from server
...@@ -600,7 +604,7 @@ static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) ...@@ -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, /* if we haven't received a response for oldreq,
* remove it from the list * remove it from the list
*/ */
if (oldreq->status == REQ_STATUS_SENT) { if (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) {
if (c->trans_mod->cancelled) if (c->trans_mod->cancelled)
c->trans_mod->cancelled(c, oldreq); c->trans_mod->cancelled(c, oldreq);
} }
...@@ -680,6 +684,9 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -680,6 +684,9 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
if (IS_ERR(req)) if (IS_ERR(req))
return req; return req;
req->tc.zc = false;
req->rc.zc = false;
if (signal_pending(current)) { if (signal_pending(current)) {
sigpending = 1; sigpending = 1;
clear_thread_flag(TIF_SIGPENDING); clear_thread_flag(TIF_SIGPENDING);
...@@ -697,7 +704,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -697,7 +704,8 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
} }
again: again:
/* Wait for the response */ /* 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 /* Make sure our req is coherent with regard to updates in other
* threads - echoes to wmb() in the callback * threads - echoes to wmb() in the callback
...@@ -711,7 +719,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -711,7 +719,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
goto 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); p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = req->t_err; err = req->t_err;
} }
...@@ -724,7 +732,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) ...@@ -724,7 +732,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
p9_client_flush(c, req); p9_client_flush(c, req);
/* if we received the response anyway, don't signal error */ /* 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; err = 0;
} }
recalc_sigpending: recalc_sigpending:
...@@ -778,6 +786,9 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, ...@@ -778,6 +786,9 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
if (IS_ERR(req)) if (IS_ERR(req))
return req; return req;
req->tc.zc = true;
req->rc.zc = true;
if (signal_pending(current)) { if (signal_pending(current)) {
sigpending = 1; sigpending = 1;
clear_thread_flag(TIF_SIGPENDING); 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, ...@@ -793,7 +804,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
if (err != -ERESTARTSYS) if (err != -ERESTARTSYS)
goto recalc_sigpending; 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); p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
err = 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, ...@@ -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); p9_client_flush(c, req);
/* if we received the response anyway, don't signal error */ /* 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; err = 0;
} }
recalc_sigpending: recalc_sigpending:
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/un.h> #include <linux/un.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/idr.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -202,11 +201,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err) ...@@ -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_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
list_move(&req->req_list, &cancel_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_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
list_move(&req->req_list, &cancel_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); spin_unlock(&m->req_lock);
...@@ -467,7 +466,7 @@ static void p9_write_work(struct work_struct *work) ...@@ -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_entry(m->unsent_req_list.next, struct p9_req_t,
req_list); req_list);
req->status = REQ_STATUS_SENT; WRITE_ONCE(req->status, REQ_STATUS_SENT);
p9_debug(P9_DEBUG_TRANS, "move req %p\n", req); p9_debug(P9_DEBUG_TRANS, "move req %p\n", req);
list_move_tail(&req->req_list, &m->req_list); 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) ...@@ -676,7 +675,7 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
return m->err; return m->err;
spin_lock(&m->req_lock); 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); list_add_tail(&req->req_list, &m->unsent_req_list);
spin_unlock(&m->req_lock); spin_unlock(&m->req_lock);
...@@ -703,7 +702,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req) ...@@ -703,7 +702,7 @@ static int p9_fd_cancel(struct p9_client *client, struct p9_req_t *req)
if (req->status == REQ_STATUS_UNSENT) { if (req->status == REQ_STATUS_UNSENT) {
list_del(&req->req_list); list_del(&req->req_list);
req->status = REQ_STATUS_FLSHD; WRITE_ONCE(req->status, REQ_STATUS_FLSHD);
p9_req_put(client, req); p9_req_put(client, req);
ret = 0; ret = 0;
} }
...@@ -732,7 +731,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) ...@@ -732,7 +731,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
* remove it from the list. * remove it from the list.
*/ */
list_del(&req->req_list); list_del(&req->req_list);
req->status = REQ_STATUS_FLSHD; WRITE_ONCE(req->status, REQ_STATUS_FLSHD);
spin_unlock(&m->req_lock); spin_unlock(&m->req_lock);
p9_req_put(client, req); p9_req_put(client, req);
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/un.h> #include <linux/un.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/idr.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
...@@ -507,7 +506,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req) ...@@ -507,7 +506,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
* because doing if after could erase the REQ_STATUS_RCVD * because doing if after could erase the REQ_STATUS_RCVD
* status in case of a very fast reply. * 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); err = ib_post_send(rdma->qp, &wr, NULL);
if (err) if (err)
goto send_error; goto send_error;
...@@ -517,7 +516,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req) ...@@ -517,7 +516,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
/* Handle errors that happened during or while preparing the send: */ /* Handle errors that happened during or while preparing the send: */
send_error: send_error:
req->status = REQ_STATUS_ERROR; WRITE_ONCE(req->status, REQ_STATUS_ERROR);
kfree(c); kfree(c);
p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err);
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <linux/un.h> #include <linux/un.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/idr.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -263,7 +262,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) ...@@ -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"); p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n");
req->status = REQ_STATUS_SENT; WRITE_ONCE(req->status, REQ_STATUS_SENT);
req_retry: req_retry:
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
...@@ -469,7 +468,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, ...@@ -469,7 +468,7 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
inlen = n; inlen = n;
} }
} }
req->status = REQ_STATUS_SENT; WRITE_ONCE(req->status, REQ_STATUS_SENT);
req_retry_pinned: req_retry_pinned:
spin_lock_irqsave(&chan->lock, flags); spin_lock_irqsave(&chan->lock, flags);
...@@ -532,9 +531,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, ...@@ -532,9 +531,10 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req,
spin_unlock_irqrestore(&chan->lock, flags); spin_unlock_irqrestore(&chan->lock, flags);
kicked = 1; kicked = 1;
p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n"); 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 // 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)) unlikely(req->rc.sdata[4] == P9_RERROR))
handle_rerror(req, in_hdr_len, offs, in_pages); handle_rerror(req, in_hdr_len, offs, in_pages);
......
...@@ -157,7 +157,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req) ...@@ -157,7 +157,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
&masked_prod, masked_cons, &masked_prod, masked_cons,
XEN_9PFS_RING_SIZE(ring)); 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 */ virt_wmb(); /* write ring before updating pointer */
prod += size; prod += size;
ring->intf->out_prod = prod; ring->intf->out_prod = prod;
...@@ -212,11 +212,13 @@ static void p9_xen_response(struct work_struct *work) ...@@ -212,11 +212,13 @@ static void p9_xen_response(struct work_struct *work)
dev_warn(&priv->dev->dev, dev_warn(&priv->dev->dev,
"requested packet size too big: %d for tag %d with capacity %zd\n", "requested packet size too big: %d for tag %d with capacity %zd\n",
h.size, h.tag, req->rc.capacity); h.size, h.tag, req->rc.capacity);
req->status = REQ_STATUS_ERROR; WRITE_ONCE(req->status, REQ_STATUS_ERROR);
goto recv_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; req->rc.offset = 0;
masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE(ring)); masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE(ring));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment