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

+42 -38
-1
fs/9p/fid.c
··· 11 #include <linux/fs.h> 12 #include <linux/slab.h> 13 #include <linux/sched.h> 14 - #include <linux/idr.h> 15 #include <net/9p/9p.h> 16 #include <net/9p/client.h> 17
··· 11 #include <linux/fs.h> 12 #include <linux/slab.h> 13 #include <linux/sched.h> 14 #include <net/9p/9p.h> 15 #include <net/9p/client.h> 16
-1
fs/9p/v9fs.c
··· 14 #include <linux/sched.h> 15 #include <linux/cred.h> 16 #include <linux/parser.h> 17 - #include <linux/idr.h> 18 #include <linux/slab.h> 19 #include <linux/seq_file.h> 20 #include <net/9p/9p.h>
··· 14 #include <linux/sched.h> 15 #include <linux/cred.h> 16 #include <linux/parser.h> 17 #include <linux/slab.h> 18 #include <linux/seq_file.h> 19 #include <net/9p/9p.h>
-1
fs/9p/vfs_addr.c
··· 14 #include <linux/string.h> 15 #include <linux/inet.h> 16 #include <linux/pagemap.h> 17 - #include <linux/idr.h> 18 #include <linux/sched.h> 19 #include <linux/swap.h> 20 #include <linux/uio.h>
··· 14 #include <linux/string.h> 15 #include <linux/inet.h> 16 #include <linux/pagemap.h> 17 #include <linux/sched.h> 18 #include <linux/swap.h> 19 #include <linux/uio.h>
-1
fs/9p/vfs_dentry.c
··· 15 #include <linux/string.h> 16 #include <linux/inet.h> 17 #include <linux/namei.h> 18 - #include <linux/idr.h> 19 #include <linux/sched.h> 20 #include <linux/slab.h> 21 #include <net/9p/9p.h>
··· 15 #include <linux/string.h> 16 #include <linux/inet.h> 17 #include <linux/namei.h> 18 #include <linux/sched.h> 19 #include <linux/slab.h> 20 #include <net/9p/9p.h>
-1
fs/9p/vfs_dir.c
··· 14 #include <linux/string.h> 15 #include <linux/sched.h> 16 #include <linux/inet.h> 17 - #include <linux/idr.h> 18 #include <linux/slab.h> 19 #include <linux/uio.h> 20 #include <linux/fscache.h>
··· 14 #include <linux/string.h> 15 #include <linux/sched.h> 16 #include <linux/inet.h> 17 #include <linux/slab.h> 18 #include <linux/uio.h> 19 #include <linux/fscache.h>
-1
fs/9p/vfs_file.c
··· 18 #include <linux/pagemap.h> 19 #include <linux/utsname.h> 20 #include <linux/uaccess.h> 21 - #include <linux/idr.h> 22 #include <linux/uio.h> 23 #include <linux/slab.h> 24 #include <net/9p/9p.h>
··· 18 #include <linux/pagemap.h> 19 #include <linux/utsname.h> 20 #include <linux/uaccess.h> 21 #include <linux/uio.h> 22 #include <linux/slab.h> 23 #include <net/9p/9p.h>
-1
fs/9p/vfs_inode.c
··· 17 #include <linux/string.h> 18 #include <linux/inet.h> 19 #include <linux/namei.h> 20 - #include <linux/idr.h> 21 #include <linux/sched.h> 22 #include <linux/slab.h> 23 #include <linux/xattr.h>
··· 17 #include <linux/string.h> 18 #include <linux/inet.h> 19 #include <linux/namei.h> 20 #include <linux/sched.h> 21 #include <linux/slab.h> 22 #include <linux/xattr.h>
-1
fs/9p/vfs_inode_dotl.c
··· 15 #include <linux/string.h> 16 #include <linux/inet.h> 17 #include <linux/namei.h> 18 - #include <linux/idr.h> 19 #include <linux/sched.h> 20 #include <linux/slab.h> 21 #include <linux/xattr.h>
··· 15 #include <linux/string.h> 16 #include <linux/inet.h> 17 #include <linux/namei.h> 18 #include <linux/sched.h> 19 #include <linux/slab.h> 20 #include <linux/xattr.h>
-1
fs/9p/vfs_super.c
··· 15 #include <linux/inet.h> 16 #include <linux/pagemap.h> 17 #include <linux/mount.h> 18 - #include <linux/idr.h> 19 #include <linux/sched.h> 20 #include <linux/slab.h> 21 #include <linux/statfs.h>
··· 15 #include <linux/inet.h> 16 #include <linux/pagemap.h> 17 #include <linux/mount.h> 18 #include <linux/sched.h> 19 #include <linux/slab.h> 20 #include <linux/statfs.h>
+2
include/net/9p/9p.h
··· 531 * @offset: used by marshalling routines to track current position in buffer 532 * @capacity: used by marshalling routines to track total malloc'd capacity 533 * @sdata: payload 534 * 535 * &p9_fcall represents the structure for all 9P RPC 536 * transactions. Requests are packaged into fcalls, and reponses ··· 550 551 struct kmem_cache *cache; 552 u8 *sdata; 553 }; 554 555 int p9_errstr2errno(char *errstr, int len);
··· 531 * @offset: used by marshalling routines to track current position in buffer 532 * @capacity: used by marshalling routines to track total malloc'd capacity 533 * @sdata: payload 534 + * @zc: whether zero-copy is used 535 * 536 * &p9_fcall represents the structure for all 9P RPC 537 * transactions. Requests are packaged into fcalls, and reponses ··· 549 550 struct kmem_cache *cache; 551 u8 *sdata; 552 + bool zc; 553 }; 554 555 int p9_errstr2errno(char *errstr, int len);
+22 -11
net/9p/client.c
··· 297 p9pdu_reset(&req->rc); 298 req->t_err = 0; 299 req->status = REQ_STATUS_ALLOC; 300 init_waitqueue_head(&req->wq); 301 INIT_LIST_HEAD(&req->req_list); 302 ··· 443 * the status change is visible to another thread 444 */ 445 smp_wmb(); 446 - req->status = status; 447 448 wake_up(&req->wq); 449 p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag); ··· 519 int ecode; 520 521 err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); 522 - if (req->rc.size >= c->msize) { 523 - p9_debug(P9_DEBUG_ERROR, 524 - "requested packet size too big: %d\n", 525 - req->rc.size); 526 return -EIO; 527 } 528 /* dump the response from server ··· 604 /* if we haven't received a response for oldreq, 605 * remove it from the list 606 */ 607 - if (oldreq->status == REQ_STATUS_SENT) { 608 if (c->trans_mod->cancelled) 609 c->trans_mod->cancelled(c, oldreq); 610 } ··· 684 if (IS_ERR(req)) 685 return req; 686 687 if (signal_pending(current)) { 688 sigpending = 1; 689 clear_thread_flag(TIF_SIGPENDING); ··· 704 } 705 again: 706 /* Wait for the response */ 707 - err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD); 708 709 /* Make sure our req is coherent with regard to updates in other 710 * threads - echoes to wmb() in the callback ··· 719 goto again; 720 } 721 722 - if (req->status == REQ_STATUS_ERROR) { 723 p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 724 err = req->t_err; 725 } ··· 732 p9_client_flush(c, req); 733 734 /* if we received the response anyway, don't signal error */ 735 - if (req->status == REQ_STATUS_RCVD) 736 err = 0; 737 } 738 recalc_sigpending: ··· 786 if (IS_ERR(req)) 787 return req; 788 789 if (signal_pending(current)) { 790 sigpending = 1; 791 clear_thread_flag(TIF_SIGPENDING); ··· 804 if (err != -ERESTARTSYS) 805 goto recalc_sigpending; 806 } 807 - if (req->status == REQ_STATUS_ERROR) { 808 p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 809 err = req->t_err; 810 } ··· 817 p9_client_flush(c, req); 818 819 /* if we received the response anyway, don't signal error */ 820 - if (req->status == REQ_STATUS_RCVD) 821 err = 0; 822 } 823 recalc_sigpending:
··· 297 p9pdu_reset(&req->rc); 298 req->t_err = 0; 299 req->status = REQ_STATUS_ALLOC; 300 + /* refcount needs to be set to 0 before inserting into the idr 301 + * so p9_tag_lookup does not accept a request that is not fully 302 + * initialized. refcount_set to 2 below will mark request ready. 303 + */ 304 + refcount_set(&req->refcount, 0); 305 init_waitqueue_head(&req->wq); 306 INIT_LIST_HEAD(&req->req_list); 307 ··· 438 * the status change is visible to another thread 439 */ 440 smp_wmb(); 441 + WRITE_ONCE(req->status, status); 442 443 wake_up(&req->wq); 444 p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag); ··· 514 int ecode; 515 516 err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); 517 + if (req->rc.size > req->rc.capacity && !req->rc.zc) { 518 + pr_err("requested packet size too big: %d does not fit %zu (type=%d)\n", 519 + req->rc.size, req->rc.capacity, req->rc.id); 520 return -EIO; 521 } 522 /* dump the response from server ··· 600 /* if we haven't received a response for oldreq, 601 * remove it from the list 602 */ 603 + if (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) { 604 if (c->trans_mod->cancelled) 605 c->trans_mod->cancelled(c, oldreq); 606 } ··· 680 if (IS_ERR(req)) 681 return req; 682 683 + req->tc.zc = false; 684 + req->rc.zc = false; 685 + 686 if (signal_pending(current)) { 687 sigpending = 1; 688 clear_thread_flag(TIF_SIGPENDING); ··· 697 } 698 again: 699 /* Wait for the response */ 700 + err = wait_event_killable(req->wq, 701 + READ_ONCE(req->status) >= REQ_STATUS_RCVD); 702 703 /* Make sure our req is coherent with regard to updates in other 704 * threads - echoes to wmb() in the callback ··· 711 goto again; 712 } 713 714 + if (READ_ONCE(req->status) == REQ_STATUS_ERROR) { 715 p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 716 err = req->t_err; 717 } ··· 724 p9_client_flush(c, req); 725 726 /* if we received the response anyway, don't signal error */ 727 + if (READ_ONCE(req->status) == REQ_STATUS_RCVD) 728 err = 0; 729 } 730 recalc_sigpending: ··· 778 if (IS_ERR(req)) 779 return req; 780 781 + req->tc.zc = true; 782 + req->rc.zc = true; 783 + 784 if (signal_pending(current)) { 785 sigpending = 1; 786 clear_thread_flag(TIF_SIGPENDING); ··· 793 if (err != -ERESTARTSYS) 794 goto recalc_sigpending; 795 } 796 + if (READ_ONCE(req->status) == REQ_STATUS_ERROR) { 797 p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 798 err = req->t_err; 799 } ··· 806 p9_client_flush(c, req); 807 808 /* if we received the response anyway, don't signal error */ 809 + if (READ_ONCE(req->status) == REQ_STATUS_RCVD) 810 err = 0; 811 } 812 recalc_sigpending:
+6 -7
net/9p/trans_fd.c
··· 20 #include <linux/un.h> 21 #include <linux/uaccess.h> 22 #include <linux/inet.h> 23 - #include <linux/idr.h> 24 #include <linux/file.h> 25 #include <linux/parser.h> 26 #include <linux/slab.h> ··· 201 202 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 203 list_move(&req->req_list, &cancel_list); 204 - req->status = REQ_STATUS_ERROR; 205 } 206 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { 207 list_move(&req->req_list, &cancel_list); 208 - req->status = REQ_STATUS_ERROR; 209 } 210 211 spin_unlock(&m->req_lock); ··· 466 467 req = list_entry(m->unsent_req_list.next, struct p9_req_t, 468 req_list); 469 - req->status = REQ_STATUS_SENT; 470 p9_debug(P9_DEBUG_TRANS, "move req %p\n", req); 471 list_move_tail(&req->req_list, &m->req_list); 472 ··· 675 return m->err; 676 677 spin_lock(&m->req_lock); 678 - req->status = REQ_STATUS_UNSENT; 679 list_add_tail(&req->req_list, &m->unsent_req_list); 680 spin_unlock(&m->req_lock); 681 ··· 702 703 if (req->status == REQ_STATUS_UNSENT) { 704 list_del(&req->req_list); 705 - req->status = REQ_STATUS_FLSHD; 706 p9_req_put(client, req); 707 ret = 0; 708 } ··· 731 * remove it from the list. 732 */ 733 list_del(&req->req_list); 734 - req->status = REQ_STATUS_FLSHD; 735 spin_unlock(&m->req_lock); 736 737 p9_req_put(client, req);
··· 20 #include <linux/un.h> 21 #include <linux/uaccess.h> 22 #include <linux/inet.h> 23 #include <linux/file.h> 24 #include <linux/parser.h> 25 #include <linux/slab.h> ··· 202 203 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 204 list_move(&req->req_list, &cancel_list); 205 + WRITE_ONCE(req->status, REQ_STATUS_ERROR); 206 } 207 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { 208 list_move(&req->req_list, &cancel_list); 209 + WRITE_ONCE(req->status, REQ_STATUS_ERROR); 210 } 211 212 spin_unlock(&m->req_lock); ··· 467 468 req = list_entry(m->unsent_req_list.next, struct p9_req_t, 469 req_list); 470 + WRITE_ONCE(req->status, REQ_STATUS_SENT); 471 p9_debug(P9_DEBUG_TRANS, "move req %p\n", req); 472 list_move_tail(&req->req_list, &m->req_list); 473 ··· 676 return m->err; 677 678 spin_lock(&m->req_lock); 679 + WRITE_ONCE(req->status, REQ_STATUS_UNSENT); 680 list_add_tail(&req->req_list, &m->unsent_req_list); 681 spin_unlock(&m->req_lock); 682 ··· 703 704 if (req->status == REQ_STATUS_UNSENT) { 705 list_del(&req->req_list); 706 + WRITE_ONCE(req->status, REQ_STATUS_FLSHD); 707 p9_req_put(client, req); 708 ret = 0; 709 } ··· 732 * remove it from the list. 733 */ 734 list_del(&req->req_list); 735 + WRITE_ONCE(req->status, REQ_STATUS_FLSHD); 736 spin_unlock(&m->req_lock); 737 738 p9_req_put(client, req);
+2 -3
net/9p/trans_rdma.c
··· 21 #include <linux/un.h> 22 #include <linux/uaccess.h> 23 #include <linux/inet.h> 24 - #include <linux/idr.h> 25 #include <linux/file.h> 26 #include <linux/parser.h> 27 #include <linux/semaphore.h> ··· 506 * because doing if after could erase the REQ_STATUS_RCVD 507 * status in case of a very fast reply. 508 */ 509 - req->status = REQ_STATUS_SENT; 510 err = ib_post_send(rdma->qp, &wr, NULL); 511 if (err) 512 goto send_error; ··· 516 517 /* Handle errors that happened during or while preparing the send: */ 518 send_error: 519 - req->status = REQ_STATUS_ERROR; 520 kfree(c); 521 p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); 522
··· 21 #include <linux/un.h> 22 #include <linux/uaccess.h> 23 #include <linux/inet.h> 24 #include <linux/file.h> 25 #include <linux/parser.h> 26 #include <linux/semaphore.h> ··· 507 * because doing if after could erase the REQ_STATUS_RCVD 508 * status in case of a very fast reply. 509 */ 510 + WRITE_ONCE(req->status, REQ_STATUS_SENT); 511 err = ib_post_send(rdma->qp, &wr, NULL); 512 if (err) 513 goto send_error; ··· 517 518 /* Handle errors that happened during or while preparing the send: */ 519 send_error: 520 + WRITE_ONCE(req->status, REQ_STATUS_ERROR); 521 kfree(c); 522 p9_debug(P9_DEBUG_ERROR, "Error %d in rdma_request()\n", err); 523
+5 -5
net/9p/trans_virtio.c
··· 22 #include <linux/un.h> 23 #include <linux/uaccess.h> 24 #include <linux/inet.h> 25 - #include <linux/idr.h> 26 #include <linux/file.h> 27 #include <linux/highmem.h> 28 #include <linux/slab.h> ··· 262 263 p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n"); 264 265 - req->status = REQ_STATUS_SENT; 266 req_retry: 267 spin_lock_irqsave(&chan->lock, flags); 268 ··· 468 inlen = n; 469 } 470 } 471 - req->status = REQ_STATUS_SENT; 472 req_retry_pinned: 473 spin_lock_irqsave(&chan->lock, flags); 474 ··· 531 spin_unlock_irqrestore(&chan->lock, flags); 532 kicked = 1; 533 p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n"); 534 - err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD); 535 // RERROR needs reply (== error string) in static data 536 - if (req->status == REQ_STATUS_RCVD && 537 unlikely(req->rc.sdata[4] == P9_RERROR)) 538 handle_rerror(req, in_hdr_len, offs, in_pages); 539
··· 22 #include <linux/un.h> 23 #include <linux/uaccess.h> 24 #include <linux/inet.h> 25 #include <linux/file.h> 26 #include <linux/highmem.h> 27 #include <linux/slab.h> ··· 263 264 p9_debug(P9_DEBUG_TRANS, "9p debug: virtio request\n"); 265 266 + WRITE_ONCE(req->status, REQ_STATUS_SENT); 267 req_retry: 268 spin_lock_irqsave(&chan->lock, flags); 269 ··· 469 inlen = n; 470 } 471 } 472 + WRITE_ONCE(req->status, REQ_STATUS_SENT); 473 req_retry_pinned: 474 spin_lock_irqsave(&chan->lock, flags); 475 ··· 532 spin_unlock_irqrestore(&chan->lock, flags); 533 kicked = 1; 534 p9_debug(P9_DEBUG_TRANS, "virtio request kicked\n"); 535 + err = wait_event_killable(req->wq, 536 + READ_ONCE(req->status) >= REQ_STATUS_RCVD); 537 // RERROR needs reply (== error string) in static data 538 + if (READ_ONCE(req->status) == REQ_STATUS_RCVD && 539 unlikely(req->rc.sdata[4] == P9_RERROR)) 540 handle_rerror(req, in_hdr_len, offs, in_pages); 541
+5 -3
net/9p/trans_xen.c
··· 157 &masked_prod, masked_cons, 158 XEN_9PFS_RING_SIZE(ring)); 159 160 - p9_req->status = REQ_STATUS_SENT; 161 virt_wmb(); /* write ring before updating pointer */ 162 prod += size; 163 ring->intf->out_prod = prod; ··· 212 dev_warn(&priv->dev->dev, 213 "requested packet size too big: %d for tag %d with capacity %zd\n", 214 h.size, h.tag, req->rc.capacity); 215 - req->status = REQ_STATUS_ERROR; 216 goto recv_error; 217 } 218 219 - memcpy(&req->rc, &h, sizeof(h)); 220 req->rc.offset = 0; 221 222 masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE(ring));
··· 157 &masked_prod, masked_cons, 158 XEN_9PFS_RING_SIZE(ring)); 159 160 + WRITE_ONCE(p9_req->status, REQ_STATUS_SENT); 161 virt_wmb(); /* write ring before updating pointer */ 162 prod += size; 163 ring->intf->out_prod = prod; ··· 212 dev_warn(&priv->dev->dev, 213 "requested packet size too big: %d for tag %d with capacity %zd\n", 214 h.size, h.tag, req->rc.capacity); 215 + WRITE_ONCE(req->status, REQ_STATUS_ERROR); 216 goto recv_error; 217 } 218 219 + req->rc.size = h.size; 220 + req->rc.id = h.id; 221 + req->rc.tag = h.tag; 222 req->rc.offset = 0; 223 224 masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE(ring));