diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-01 19:57:53 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:28:25 -0400 |
commit | 4f3b35c157e43107cc7e1f1aa06694e8b22e10bb (patch) | |
tree | 2e871c8698529878f93c225b818f4aa4b871f3c6 /net/9p/client.c | |
parent | 6e242a1ceeb1bcf55ffefa84d3079f711fe8a667 (diff) |
net/9p: switch the guts of p9_client_{read,write}() to iov_iter
... and have get_user_pages_fast() mapping fewer pages than requested
to generate a short read/write.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
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, |