diff options
Diffstat (limited to 'net/9p/client.c')
| -rw-r--r-- | net/9p/client.c | 117 |
1 files changed, 59 insertions, 58 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index e86a9bea1d16..9ef5d85f082f 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 35 | #include <linux/sched.h> | 35 | #include <linux/sched.h> |
| 36 | #include <linux/uaccess.h> | 36 | #include <linux/uaccess.h> |
| 37 | #include <linux/uio.h> | ||
| 37 | #include <net/9p/9p.h> | 38 | #include <net/9p/9p.h> |
| 38 | #include <linux/parser.h> | 39 | #include <linux/parser.h> |
| 39 | #include <net/9p/client.h> | 40 | #include <net/9p/client.h> |
| @@ -555,7 +556,7 @@ out_err: | |||
| 555 | */ | 556 | */ |
| 556 | 557 | ||
| 557 | static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | 558 | static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, |
| 558 | char *uidata, int in_hdrlen, int kern_buf) | 559 | struct iov_iter *uidata, int in_hdrlen) |
| 559 | { | 560 | { |
| 560 | int err; | 561 | int err; |
| 561 | int ecode; | 562 | int ecode; |
| @@ -591,16 +592,11 @@ static int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, | |||
| 591 | ename = &req->rc->sdata[req->rc->offset]; | 592 | ename = &req->rc->sdata[req->rc->offset]; |
| 592 | if (len > inline_len) { | 593 | if (len > inline_len) { |
| 593 | /* We have error in external buffer */ | 594 | /* We have error in external buffer */ |
| 594 | if (kern_buf) { | 595 | err = copy_from_iter(ename + inline_len, |
| 595 | memcpy(ename + inline_len, uidata, | 596 | len - inline_len, uidata); |
| 596 | len - inline_len); | 597 | if (err != len - inline_len) { |
| 597 | } else { | 598 | err = -EFAULT; |
| 598 | err = copy_from_user(ename + inline_len, | 599 | goto out_err; |
| 599 | uidata, len - inline_len); | ||
| 600 | if (err) { | ||
| 601 | err = -EFAULT; | ||
| 602 | goto out_err; | ||
| 603 | } | ||
| 604 | } | 600 | } |
| 605 | } | 601 | } |
| 606 | ename = NULL; | 602 | ename = NULL; |
| @@ -806,8 +802,8 @@ reterr: | |||
| 806 | * p9_client_zc_rpc - issue a request and wait for a response | 802 | * p9_client_zc_rpc - issue a request and wait for a response |
| 807 | * @c: client session | 803 | * @c: client session |
| 808 | * @type: type of request | 804 | * @type: type of request |
| 809 | * @uidata: user bffer that should be ued for zero copy read | 805 | * @uidata: destination for zero copy read |
| 810 | * @uodata: user buffer that shoud be user for zero copy write | 806 | * @uodata: source for zero copy write |
| 811 | * @inlen: read buffer size | 807 | * @inlen: read buffer size |
| 812 | * @olen: write buffer size | 808 | * @olen: write buffer size |
| 813 | * @hdrlen: reader header size, This is the size of response protocol data | 809 | * @hdrlen: reader header size, This is the size of response protocol data |
| @@ -816,9 +812,10 @@ reterr: | |||
| 816 | * Returns request structure (which client must free using p9_free_req) | 812 | * Returns request structure (which client must free using p9_free_req) |
| 817 | */ | 813 | */ |
| 818 | static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | 814 | static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, |
| 819 | char *uidata, char *uodata, | 815 | struct iov_iter *uidata, |
| 816 | struct iov_iter *uodata, | ||
| 820 | int inlen, int olen, int in_hdrlen, | 817 | int inlen, int olen, int in_hdrlen, |
| 821 | int kern_buf, const char *fmt, ...) | 818 | const char *fmt, ...) |
| 822 | { | 819 | { |
| 823 | va_list ap; | 820 | va_list ap; |
| 824 | int sigpending, err; | 821 | int sigpending, err; |
| @@ -841,12 +838,8 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | |||
| 841 | } else | 838 | } else |
| 842 | sigpending = 0; | 839 | sigpending = 0; |
| 843 | 840 | ||
| 844 | /* If we are called with KERNEL_DS force kern_buf */ | ||
| 845 | if (segment_eq(get_fs(), KERNEL_DS)) | ||
| 846 | kern_buf = 1; | ||
| 847 | |||
| 848 | err = c->trans_mod->zc_request(c, req, uidata, uodata, | 841 | err = c->trans_mod->zc_request(c, req, uidata, uodata, |
| 849 | inlen, olen, in_hdrlen, kern_buf); | 842 | inlen, olen, in_hdrlen); |
| 850 | if (err < 0) { | 843 | if (err < 0) { |
| 851 | if (err == -EIO) | 844 | if (err == -EIO) |
| 852 | c->status = Disconnected; | 845 | c->status = Disconnected; |
| @@ -876,7 +869,7 @@ static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, | |||
| 876 | if (err < 0) | 869 | if (err < 0) |
| 877 | goto reterr; | 870 | goto reterr; |
| 878 | 871 | ||
| 879 | err = p9_check_zc_errors(c, req, uidata, in_hdrlen, kern_buf); | 872 | err = p9_check_zc_errors(c, req, uidata, in_hdrlen); |
| 880 | trace_9p_client_res(c, type, req->rc->tag, err); | 873 | trace_9p_client_res(c, type, req->rc->tag, err); |
| 881 | if (!err) | 874 | if (!err) |
| 882 | return req; | 875 | return req; |
| @@ -1545,11 +1538,24 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
| 1545 | u32 count) | 1538 | u32 count) |
| 1546 | { | 1539 | { |
| 1547 | char *dataptr; | 1540 | char *dataptr; |
| 1548 | int kernel_buf = 0; | ||
| 1549 | struct p9_req_t *req; | 1541 | struct p9_req_t *req; |
| 1550 | struct p9_client *clnt; | 1542 | struct p9_client *clnt; |
| 1551 | int err, rsize, non_zc = 0; | 1543 | int err, rsize, non_zc = 0; |
| 1552 | 1544 | struct iov_iter to; | |
| 1545 | union { | ||
| 1546 | struct kvec kv; | ||
| 1547 | struct iovec iov; | ||
| 1548 | } v; | ||
| 1549 | |||
| 1550 | if (data) { | ||
| 1551 | v.kv.iov_base = data; | ||
| 1552 | v.kv.iov_len = count; | ||
| 1553 | iov_iter_kvec(&to, ITER_KVEC | READ, &v.kv, 1, count); | ||
| 1554 | } else { | ||
| 1555 | v.iov.iov_base = udata; | ||
| 1556 | v.iov.iov_len = count; | ||
| 1557 | iov_iter_init(&to, READ, &v.iov, 1, count); | ||
| 1558 | } | ||
| 1553 | 1559 | ||
| 1554 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", | 1560 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", |
| 1555 | fid->fid, (unsigned long long) offset, count); | 1561 | fid->fid, (unsigned long long) offset, count); |
| @@ -1565,18 +1571,12 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
| 1565 | 1571 | ||
| 1566 | /* Don't bother zerocopy for small IO (< 1024) */ | 1572 | /* Don't bother zerocopy for small IO (< 1024) */ |
| 1567 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1573 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
| 1568 | char *indata; | ||
| 1569 | if (data) { | ||
| 1570 | kernel_buf = 1; | ||
| 1571 | indata = data; | ||
| 1572 | } else | ||
| 1573 | indata = (__force char *)udata; | ||
| 1574 | /* | 1574 | /* |
| 1575 | * response header len is 11 | 1575 | * response header len is 11 |
| 1576 | * PDU Header(7) + IO Size (4) | 1576 | * PDU Header(7) + IO Size (4) |
| 1577 | */ | 1577 | */ |
| 1578 | req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0, | 1578 | req = p9_client_zc_rpc(clnt, P9_TREAD, &to, NULL, rsize, 0, |
| 1579 | 11, kernel_buf, "dqd", fid->fid, | 1579 | 11, "dqd", fid->fid, |
| 1580 | offset, rsize); | 1580 | offset, rsize); |
| 1581 | } else { | 1581 | } else { |
| 1582 | non_zc = 1; | 1582 | non_zc = 1; |
| @@ -1596,16 +1596,9 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
| 1596 | 1596 | ||
| 1597 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1597 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
| 1598 | 1598 | ||
| 1599 | if (non_zc) { | 1599 | if (non_zc && copy_to_iter(dataptr, count, &to) != count) { |
| 1600 | if (data) { | 1600 | err = -EFAULT; |
| 1601 | memmove(data, dataptr, count); | 1601 | goto free_and_error; |
| 1602 | } else { | ||
| 1603 | err = copy_to_user(udata, dataptr, count); | ||
| 1604 | if (err) { | ||
| 1605 | err = -EFAULT; | ||
| 1606 | goto free_and_error; | ||
| 1607 | } | ||
| 1608 | } | ||
| 1609 | } | 1602 | } |
| 1610 | p9_free_req(clnt, req); | 1603 | p9_free_req(clnt, req); |
| 1611 | return count; | 1604 | return count; |
| @@ -1622,9 +1615,23 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
| 1622 | u64 offset, u32 count) | 1615 | u64 offset, u32 count) |
| 1623 | { | 1616 | { |
| 1624 | int err, rsize; | 1617 | int err, rsize; |
| 1625 | int kernel_buf = 0; | ||
| 1626 | struct p9_client *clnt; | 1618 | struct p9_client *clnt; |
| 1627 | struct p9_req_t *req; | 1619 | struct p9_req_t *req; |
| 1620 | struct iov_iter from; | ||
| 1621 | union { | ||
| 1622 | struct kvec kv; | ||
| 1623 | struct iovec iov; | ||
| 1624 | } v; | ||
| 1625 | |||
| 1626 | if (data) { | ||
| 1627 | v.kv.iov_base = data; | ||
| 1628 | v.kv.iov_len = count; | ||
| 1629 | iov_iter_kvec(&from, ITER_KVEC | WRITE, &v.kv, 1, count); | ||
| 1630 | } else { | ||
| 1631 | v.iov.iov_base = udata; | ||
| 1632 | v.iov.iov_len = count; | ||
| 1633 | iov_iter_init(&from, WRITE, &v.iov, 1, count); | ||
| 1634 | } | ||
| 1628 | 1635 | ||
| 1629 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", | 1636 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", |
| 1630 | fid->fid, (unsigned long long) offset, count); | 1637 | fid->fid, (unsigned long long) offset, count); |
| @@ -1640,22 +1647,12 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
| 1640 | 1647 | ||
| 1641 | /* Don't bother zerocopy for small IO (< 1024) */ | 1648 | /* Don't bother zerocopy for small IO (< 1024) */ |
| 1642 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1649 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
| 1643 | char *odata; | 1650 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, &from, 0, rsize, |
| 1644 | if (data) { | 1651 | P9_ZC_HDR_SZ, "dqd", |
| 1645 | kernel_buf = 1; | ||
| 1646 | odata = data; | ||
| 1647 | } else | ||
| 1648 | odata = (char *)udata; | ||
| 1649 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, odata, 0, rsize, | ||
| 1650 | P9_ZC_HDR_SZ, kernel_buf, "dqd", | ||
| 1651 | fid->fid, offset, rsize); | 1652 | fid->fid, offset, rsize); |
| 1652 | } else { | 1653 | } else { |
| 1653 | if (data) | 1654 | req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid, |
| 1654 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | 1655 | offset, rsize, &from); |
| 1655 | offset, rsize, data); | ||
| 1656 | else | ||
| 1657 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
| 1658 | offset, rsize, udata); | ||
| 1659 | } | 1656 | } |
| 1660 | if (IS_ERR(req)) { | 1657 | if (IS_ERR(req)) { |
| 1661 | err = PTR_ERR(req); | 1658 | err = PTR_ERR(req); |
| @@ -2068,6 +2065,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
| 2068 | struct p9_client *clnt; | 2065 | struct p9_client *clnt; |
| 2069 | struct p9_req_t *req; | 2066 | struct p9_req_t *req; |
| 2070 | char *dataptr; | 2067 | char *dataptr; |
| 2068 | struct kvec kv = {.iov_base = data, .iov_len = count}; | ||
| 2069 | struct iov_iter to; | ||
| 2070 | |||
| 2071 | iov_iter_kvec(&to, READ | ITER_KVEC, &kv, 1, count); | ||
| 2071 | 2072 | ||
| 2072 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", | 2073 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", |
| 2073 | fid->fid, (unsigned long long) offset, count); | 2074 | fid->fid, (unsigned long long) offset, count); |
| @@ -2088,8 +2089,8 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
| 2088 | * response header len is 11 | 2089 | * response header len is 11 |
| 2089 | * PDU Header(7) + IO Size (4) | 2090 | * PDU Header(7) + IO Size (4) |
| 2090 | */ | 2091 | */ |
| 2091 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0, | 2092 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0, |
| 2092 | 11, 1, "dqd", fid->fid, offset, rsize); | 2093 | 11, "dqd", fid->fid, offset, rsize); |
| 2093 | } else { | 2094 | } else { |
| 2094 | non_zc = 1; | 2095 | non_zc = 1; |
| 2095 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | 2096 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, |
