diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 16:22:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-15 16:22:56 -0400 |
commit | fa927894bbb4a4c7669c72bad1924991022fda38 (patch) | |
tree | 93560f1a096973235fe9ff50c436f5239c1c499a /net | |
parent | c841e12add6926d64aa608687893465330b5a03e (diff) | |
parent | 8436318205b9f29e45db88850ec60e326327e241 (diff) |
Merge branch 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull second vfs update from Al Viro:
"Now that net-next went in... Here's the next big chunk - killing
->aio_read() and ->aio_write().
There'll be one more pile today (direct_IO changes and
generic_write_checks() cleanups/fixes), but I'd prefer to keep that
one separate"
* 'for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (37 commits)
->aio_read and ->aio_write removed
pcm: another weird API abuse
infinibad: weird APIs switched to ->write_iter()
kill do_sync_read/do_sync_write
fuse: use iov_iter_get_pages() for non-splice path
fuse: switch to ->read_iter/->write_iter
switch drivers/char/mem.c to ->read_iter/->write_iter
make new_sync_{read,write}() static
coredump: accept any write method
switch /dev/loop to vfs_iter_write()
serial2002: switch to __vfs_read/__vfs_write
ashmem: use __vfs_read()
export __vfs_read()
autofs: switch to __vfs_write()
new helper: __vfs_write()
switch hugetlbfs to ->read_iter()
coda: switch to ->read_iter/->write_iter
ncpfs: switch to ->read_iter/->write_iter
net/9p: remove (now-)unused helpers
p9_client_attach(): set fid->uid correctly
...
Diffstat (limited to 'net')
-rw-r--r-- | net/9p/client.c | 262 | ||||
-rw-r--r-- | net/9p/protocol.c | 24 | ||||
-rw-r--r-- | net/9p/trans_common.c | 42 | ||||
-rw-r--r-- | net/9p/trans_common.h | 2 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 137 | ||||
-rw-r--r-- | net/socket.c | 2 |
6 files changed, 211 insertions, 258 deletions
diff --git a/net/9p/client.c b/net/9p/client.c index e86a9bea1d16..6f4c4c88db84 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; |
@@ -1123,6 +1116,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | |||
1123 | fid = NULL; | 1116 | fid = NULL; |
1124 | goto error; | 1117 | goto error; |
1125 | } | 1118 | } |
1119 | fid->uid = n_uname; | ||
1126 | 1120 | ||
1127 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid, | 1121 | req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid, |
1128 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); | 1122 | afid ? afid->fid : P9_NOFID, uname, aname, n_uname); |
@@ -1541,142 +1535,128 @@ error: | |||
1541 | EXPORT_SYMBOL(p9_client_unlinkat); | 1535 | EXPORT_SYMBOL(p9_client_unlinkat); |
1542 | 1536 | ||
1543 | int | 1537 | int |
1544 | p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | 1538 | p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err) |
1545 | u32 count) | ||
1546 | { | 1539 | { |
1547 | char *dataptr; | 1540 | struct p9_client *clnt = fid->clnt; |
1548 | int kernel_buf = 0; | ||
1549 | struct p9_req_t *req; | 1541 | struct p9_req_t *req; |
1550 | struct p9_client *clnt; | 1542 | int total = 0; |
1551 | int err, rsize, non_zc = 0; | ||
1552 | |||
1553 | 1543 | ||
1554 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", | 1544 | p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", |
1555 | fid->fid, (unsigned long long) offset, count); | 1545 | fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); |
1556 | err = 0; | 1546 | |
1557 | clnt = fid->clnt; | 1547 | while (iov_iter_count(to)) { |
1558 | 1548 | int count = iov_iter_count(to); | |
1559 | rsize = fid->iounit; | 1549 | int rsize, non_zc = 0; |
1560 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | 1550 | char *dataptr; |
1561 | rsize = clnt->msize - P9_IOHDRSZ; | 1551 | |
1562 | 1552 | rsize = fid->iounit; | |
1563 | if (count < rsize) | 1553 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) |
1564 | rsize = count; | 1554 | rsize = clnt->msize - P9_IOHDRSZ; |
1565 | 1555 | ||
1566 | /* Don't bother zerocopy for small IO (< 1024) */ | 1556 | if (count < rsize) |
1567 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1557 | rsize = count; |
1568 | char *indata; | 1558 | |
1569 | if (data) { | 1559 | /* Don't bother zerocopy for small IO (< 1024) */ |
1570 | kernel_buf = 1; | 1560 | if (clnt->trans_mod->zc_request && rsize > 1024) { |
1571 | indata = data; | 1561 | /* |
1572 | } else | 1562 | * response header len is 11 |
1573 | indata = (__force char *)udata; | 1563 | * PDU Header(7) + IO Size (4) |
1574 | /* | 1564 | */ |
1575 | * response header len is 11 | 1565 | req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize, |
1576 | * PDU Header(7) + IO Size (4) | 1566 | 0, 11, "dqd", fid->fid, |
1577 | */ | 1567 | offset, rsize); |
1578 | req = p9_client_zc_rpc(clnt, P9_TREAD, indata, NULL, rsize, 0, | 1568 | } else { |
1579 | 11, kernel_buf, "dqd", fid->fid, | 1569 | non_zc = 1; |
1580 | offset, rsize); | 1570 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, |
1581 | } else { | 1571 | rsize); |
1582 | non_zc = 1; | 1572 | } |
1583 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | 1573 | if (IS_ERR(req)) { |
1584 | rsize); | 1574 | *err = PTR_ERR(req); |
1585 | } | 1575 | break; |
1586 | if (IS_ERR(req)) { | 1576 | } |
1587 | err = PTR_ERR(req); | ||
1588 | goto error; | ||
1589 | } | ||
1590 | 1577 | ||
1591 | err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr); | 1578 | *err = p9pdu_readf(req->rc, clnt->proto_version, |
1592 | if (err) { | 1579 | "D", &count, &dataptr); |
1593 | trace_9p_protocol_dump(clnt, req->rc); | 1580 | if (*err) { |
1594 | goto free_and_error; | 1581 | trace_9p_protocol_dump(clnt, req->rc); |
1595 | } | 1582 | p9_free_req(clnt, req); |
1583 | break; | ||
1584 | } | ||
1596 | 1585 | ||
1597 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1586 | p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1587 | if (!count) { | ||
1588 | p9_free_req(clnt, req); | ||
1589 | break; | ||
1590 | } | ||
1598 | 1591 | ||
1599 | if (non_zc) { | 1592 | if (non_zc) { |
1600 | if (data) { | 1593 | int n = copy_to_iter(dataptr, count, to); |
1601 | memmove(data, dataptr, count); | 1594 | total += n; |
1602 | } else { | 1595 | offset += n; |
1603 | err = copy_to_user(udata, dataptr, count); | 1596 | if (n != count) { |
1604 | if (err) { | 1597 | *err = -EFAULT; |
1605 | err = -EFAULT; | 1598 | p9_free_req(clnt, req); |
1606 | goto free_and_error; | 1599 | break; |
1607 | } | 1600 | } |
1601 | } else { | ||
1602 | iov_iter_advance(to, count); | ||
1603 | total += count; | ||
1604 | offset += count; | ||
1608 | } | 1605 | } |
1606 | p9_free_req(clnt, req); | ||
1609 | } | 1607 | } |
1610 | p9_free_req(clnt, req); | 1608 | return total; |
1611 | return count; | ||
1612 | |||
1613 | free_and_error: | ||
1614 | p9_free_req(clnt, req); | ||
1615 | error: | ||
1616 | return err; | ||
1617 | } | 1609 | } |
1618 | EXPORT_SYMBOL(p9_client_read); | 1610 | EXPORT_SYMBOL(p9_client_read); |
1619 | 1611 | ||
1620 | int | 1612 | int |
1621 | p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | 1613 | p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) |
1622 | u64 offset, u32 count) | ||
1623 | { | 1614 | { |
1624 | int err, rsize; | 1615 | struct p9_client *clnt = fid->clnt; |
1625 | int kernel_buf = 0; | ||
1626 | struct p9_client *clnt; | ||
1627 | struct p9_req_t *req; | 1616 | struct p9_req_t *req; |
1617 | int total = 0; | ||
1618 | |||
1619 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n", | ||
1620 | fid->fid, (unsigned long long) offset, | ||
1621 | iov_iter_count(from)); | ||
1622 | |||
1623 | while (iov_iter_count(from)) { | ||
1624 | int count = iov_iter_count(from); | ||
1625 | int rsize = fid->iounit; | ||
1626 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | ||
1627 | rsize = clnt->msize - P9_IOHDRSZ; | ||
1628 | |||
1629 | if (count < rsize) | ||
1630 | rsize = count; | ||
1631 | |||
1632 | /* Don't bother zerocopy for small IO (< 1024) */ | ||
1633 | if (clnt->trans_mod->zc_request && rsize > 1024) { | ||
1634 | req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0, | ||
1635 | rsize, P9_ZC_HDR_SZ, "dqd", | ||
1636 | fid->fid, offset, rsize); | ||
1637 | } else { | ||
1638 | req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid, | ||
1639 | offset, rsize, from); | ||
1640 | } | ||
1641 | if (IS_ERR(req)) { | ||
1642 | *err = PTR_ERR(req); | ||
1643 | break; | ||
1644 | } | ||
1628 | 1645 | ||
1629 | p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d\n", | 1646 | *err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); |
1630 | fid->fid, (unsigned long long) offset, count); | 1647 | if (*err) { |
1631 | err = 0; | 1648 | trace_9p_protocol_dump(clnt, req->rc); |
1632 | clnt = fid->clnt; | 1649 | p9_free_req(clnt, req); |
1633 | 1650 | } | |
1634 | rsize = fid->iounit; | ||
1635 | if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) | ||
1636 | rsize = clnt->msize - P9_IOHDRSZ; | ||
1637 | 1651 | ||
1638 | if (count < rsize) | 1652 | p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); |
1639 | rsize = count; | ||
1640 | 1653 | ||
1641 | /* Don't bother zerocopy for small IO (< 1024) */ | 1654 | p9_free_req(clnt, req); |
1642 | if (clnt->trans_mod->zc_request && rsize > 1024) { | 1655 | iov_iter_advance(from, count); |
1643 | char *odata; | 1656 | total += count; |
1644 | if (data) { | 1657 | offset += count; |
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 | } else { | ||
1653 | if (data) | ||
1654 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1655 | offset, rsize, data); | ||
1656 | else | ||
1657 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1658 | offset, rsize, udata); | ||
1659 | } | ||
1660 | if (IS_ERR(req)) { | ||
1661 | err = PTR_ERR(req); | ||
1662 | goto error; | ||
1663 | } | ||
1664 | |||
1665 | err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count); | ||
1666 | if (err) { | ||
1667 | trace_9p_protocol_dump(clnt, req->rc); | ||
1668 | goto free_and_error; | ||
1669 | } | 1658 | } |
1670 | 1659 | return total; | |
1671 | p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); | ||
1672 | |||
1673 | p9_free_req(clnt, req); | ||
1674 | return count; | ||
1675 | |||
1676 | free_and_error: | ||
1677 | p9_free_req(clnt, req); | ||
1678 | error: | ||
1679 | return err; | ||
1680 | } | 1660 | } |
1681 | EXPORT_SYMBOL(p9_client_write); | 1661 | EXPORT_SYMBOL(p9_client_write); |
1682 | 1662 | ||
@@ -2068,6 +2048,10 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
2068 | struct p9_client *clnt; | 2048 | struct p9_client *clnt; |
2069 | struct p9_req_t *req; | 2049 | struct p9_req_t *req; |
2070 | char *dataptr; | 2050 | char *dataptr; |
2051 | struct kvec kv = {.iov_base = data, .iov_len = count}; | ||
2052 | struct iov_iter to; | ||
2053 | |||
2054 | iov_iter_kvec(&to, READ | ITER_KVEC, &kv, 1, count); | ||
2071 | 2055 | ||
2072 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", | 2056 | p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", |
2073 | fid->fid, (unsigned long long) offset, count); | 2057 | fid->fid, (unsigned long long) offset, count); |
@@ -2088,8 +2072,8 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
2088 | * response header len is 11 | 2072 | * response header len is 11 |
2089 | * PDU Header(7) + IO Size (4) | 2073 | * PDU Header(7) + IO Size (4) |
2090 | */ | 2074 | */ |
2091 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, data, NULL, rsize, 0, | 2075 | req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0, |
2092 | 11, 1, "dqd", fid->fid, offset, rsize); | 2076 | 11, "dqd", fid->fid, offset, rsize); |
2093 | } else { | 2077 | } else { |
2094 | non_zc = 1; | 2078 | non_zc = 1; |
2095 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | 2079 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index ab9127ec5b7a..e9d0f0c1a048 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/sched.h> | 33 | #include <linux/sched.h> |
34 | #include <linux/stddef.h> | 34 | #include <linux/stddef.h> |
35 | #include <linux/types.h> | 35 | #include <linux/types.h> |
36 | #include <linux/uio.h> | ||
36 | #include <net/9p/9p.h> | 37 | #include <net/9p/9p.h> |
37 | #include <net/9p/client.h> | 38 | #include <net/9p/client.h> |
38 | #include "protocol.h" | 39 | #include "protocol.h" |
@@ -69,10 +70,11 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) | |||
69 | } | 70 | } |
70 | 71 | ||
71 | static size_t | 72 | static size_t |
72 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 73 | pdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size) |
73 | { | 74 | { |
74 | size_t len = min(pdu->capacity - pdu->size, size); | 75 | size_t len = min(pdu->capacity - pdu->size, size); |
75 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) | 76 | struct iov_iter i = *from; |
77 | if (copy_from_iter(&pdu->sdata[pdu->size], len, &i) != len) | ||
76 | len = 0; | 78 | len = 0; |
77 | 79 | ||
78 | pdu->size += len; | 80 | pdu->size += len; |
@@ -437,23 +439,13 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
437 | stbuf->extension, stbuf->n_uid, | 439 | stbuf->extension, stbuf->n_uid, |
438 | stbuf->n_gid, stbuf->n_muid); | 440 | stbuf->n_gid, stbuf->n_muid); |
439 | } break; | 441 | } break; |
440 | case 'D':{ | 442 | case 'V':{ |
441 | uint32_t count = va_arg(ap, uint32_t); | ||
442 | const void *data = va_arg(ap, const void *); | ||
443 | |||
444 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
445 | count); | ||
446 | if (!errcode && pdu_write(pdu, data, count)) | ||
447 | errcode = -EFAULT; | ||
448 | } | ||
449 | break; | ||
450 | case 'U':{ | ||
451 | int32_t count = va_arg(ap, int32_t); | 443 | int32_t count = va_arg(ap, int32_t); |
452 | const char __user *udata = | 444 | struct iov_iter *from = |
453 | va_arg(ap, const void __user *); | 445 | va_arg(ap, struct iov_iter *); |
454 | errcode = p9pdu_writef(pdu, proto_version, "d", | 446 | errcode = p9pdu_writef(pdu, proto_version, "d", |
455 | count); | 447 | count); |
456 | if (!errcode && pdu_write_u(pdu, udata, count)) | 448 | if (!errcode && pdu_write_u(pdu, from, count)) |
457 | errcode = -EFAULT; | 449 | errcode = -EFAULT; |
458 | } | 450 | } |
459 | break; | 451 | break; |
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c index 2ee3879161b1..38aa6345bdfa 100644 --- a/net/9p/trans_common.c +++ b/net/9p/trans_common.c | |||
@@ -12,12 +12,8 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/slab.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <net/9p/9p.h> | ||
18 | #include <net/9p/client.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include "trans_common.h" | ||
21 | 17 | ||
22 | /** | 18 | /** |
23 | * p9_release_req_pages - Release pages after the transaction. | 19 | * p9_release_req_pages - Release pages after the transaction. |
@@ -31,39 +27,3 @@ void p9_release_pages(struct page **pages, int nr_pages) | |||
31 | put_page(pages[i]); | 27 | put_page(pages[i]); |
32 | } | 28 | } |
33 | EXPORT_SYMBOL(p9_release_pages); | 29 | EXPORT_SYMBOL(p9_release_pages); |
34 | |||
35 | /** | ||
36 | * p9_nr_pages - Return number of pages needed to accommodate the payload. | ||
37 | */ | ||
38 | int p9_nr_pages(char *data, int len) | ||
39 | { | ||
40 | unsigned long start_page, end_page; | ||
41 | start_page = (unsigned long)data >> PAGE_SHIFT; | ||
42 | end_page = ((unsigned long)data + len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
43 | return end_page - start_page; | ||
44 | } | ||
45 | EXPORT_SYMBOL(p9_nr_pages); | ||
46 | |||
47 | /** | ||
48 | * payload_gup - Translates user buffer into kernel pages and | ||
49 | * pins them either for read/write through get_user_pages_fast(). | ||
50 | * @req: Request to be sent to server. | ||
51 | * @pdata_off: data offset into the first page after translation (gup). | ||
52 | * @pdata_len: Total length of the IO. gup may not return requested # of pages. | ||
53 | * @nr_pages: number of pages to accommodate the payload | ||
54 | * @rw: Indicates if the pages are for read or write. | ||
55 | */ | ||
56 | |||
57 | int p9_payload_gup(char *data, int *nr_pages, struct page **pages, int write) | ||
58 | { | ||
59 | int nr_mapped_pages; | ||
60 | |||
61 | nr_mapped_pages = get_user_pages_fast((unsigned long)data, | ||
62 | *nr_pages, write, pages); | ||
63 | if (nr_mapped_pages <= 0) | ||
64 | return nr_mapped_pages; | ||
65 | |||
66 | *nr_pages = nr_mapped_pages; | ||
67 | return 0; | ||
68 | } | ||
69 | EXPORT_SYMBOL(p9_payload_gup); | ||
diff --git a/net/9p/trans_common.h b/net/9p/trans_common.h index 173bb550a9eb..c43babb3f635 100644 --- a/net/9p/trans_common.h +++ b/net/9p/trans_common.h | |||
@@ -13,5 +13,3 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | void p9_release_pages(struct page **, int); | 15 | void p9_release_pages(struct page **, int); |
16 | int p9_payload_gup(char *, int *, struct page **, int); | ||
17 | int p9_nr_pages(char *, int); | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 36a1a739ad68..e62bcbbabb5e 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -217,15 +217,15 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) | |||
217 | * @start: which segment of the sg_list to start at | 217 | * @start: which segment of the sg_list to start at |
218 | * @pdata: a list of pages to add into sg. | 218 | * @pdata: a list of pages to add into sg. |
219 | * @nr_pages: number of pages to pack into the scatter/gather list | 219 | * @nr_pages: number of pages to pack into the scatter/gather list |
220 | * @data: data to pack into scatter/gather list | 220 | * @offs: amount of data in the beginning of first page _not_ to pack |
221 | * @count: amount of data to pack into the scatter/gather list | 221 | * @count: amount of data to pack into the scatter/gather list |
222 | */ | 222 | */ |
223 | static int | 223 | static int |
224 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, | 224 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, |
225 | struct page **pdata, int nr_pages, char *data, int count) | 225 | struct page **pdata, int nr_pages, size_t offs, int count) |
226 | { | 226 | { |
227 | int i = 0, s; | 227 | int i = 0, s; |
228 | int data_off; | 228 | int data_off = offs; |
229 | int index = start; | 229 | int index = start; |
230 | 230 | ||
231 | BUG_ON(nr_pages > (limit - start)); | 231 | BUG_ON(nr_pages > (limit - start)); |
@@ -233,16 +233,14 @@ pack_sg_list_p(struct scatterlist *sg, int start, int limit, | |||
233 | * if the first page doesn't start at | 233 | * if the first page doesn't start at |
234 | * page boundary find the offset | 234 | * page boundary find the offset |
235 | */ | 235 | */ |
236 | data_off = offset_in_page(data); | ||
237 | while (nr_pages) { | 236 | while (nr_pages) { |
238 | s = rest_of_page(data); | 237 | s = PAGE_SIZE - data_off; |
239 | if (s > count) | 238 | if (s > count) |
240 | s = count; | 239 | s = count; |
241 | /* Make sure we don't terminate early. */ | 240 | /* Make sure we don't terminate early. */ |
242 | sg_unmark_end(&sg[index]); | 241 | sg_unmark_end(&sg[index]); |
243 | sg_set_page(&sg[index++], pdata[i++], s, data_off); | 242 | sg_set_page(&sg[index++], pdata[i++], s, data_off); |
244 | data_off = 0; | 243 | data_off = 0; |
245 | data += s; | ||
246 | count -= s; | 244 | count -= s; |
247 | nr_pages--; | 245 | nr_pages--; |
248 | } | 246 | } |
@@ -314,11 +312,20 @@ req_retry: | |||
314 | } | 312 | } |
315 | 313 | ||
316 | static int p9_get_mapped_pages(struct virtio_chan *chan, | 314 | static int p9_get_mapped_pages(struct virtio_chan *chan, |
317 | struct page **pages, char *data, | 315 | struct page ***pages, |
318 | int nr_pages, int write, int kern_buf) | 316 | struct iov_iter *data, |
317 | int count, | ||
318 | size_t *offs, | ||
319 | int *need_drop) | ||
319 | { | 320 | { |
321 | int nr_pages; | ||
320 | int err; | 322 | int err; |
321 | if (!kern_buf) { | 323 | |
324 | if (!iov_iter_count(data)) | ||
325 | return 0; | ||
326 | |||
327 | if (!(data->type & ITER_KVEC)) { | ||
328 | int n; | ||
322 | /* | 329 | /* |
323 | * We allow only p9_max_pages pinned. We wait for the | 330 | * We allow only p9_max_pages pinned. We wait for the |
324 | * Other zc request to finish here | 331 | * Other zc request to finish here |
@@ -329,26 +336,49 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, | |||
329 | if (err == -ERESTARTSYS) | 336 | if (err == -ERESTARTSYS) |
330 | return err; | 337 | return err; |
331 | } | 338 | } |
332 | err = p9_payload_gup(data, &nr_pages, pages, write); | 339 | n = iov_iter_get_pages_alloc(data, pages, count, offs); |
333 | if (err < 0) | 340 | if (n < 0) |
334 | return err; | 341 | return n; |
342 | *need_drop = 1; | ||
343 | nr_pages = DIV_ROUND_UP(n + *offs, PAGE_SIZE); | ||
335 | atomic_add(nr_pages, &vp_pinned); | 344 | atomic_add(nr_pages, &vp_pinned); |
345 | return n; | ||
336 | } else { | 346 | } else { |
337 | /* kernel buffer, no need to pin pages */ | 347 | /* kernel buffer, no need to pin pages */ |
338 | int s, index = 0; | 348 | int index; |
339 | int count = nr_pages; | 349 | size_t len; |
340 | while (nr_pages) { | 350 | void *p; |
341 | s = rest_of_page(data); | 351 | |
342 | if (is_vmalloc_addr(data)) | 352 | /* we'd already checked that it's non-empty */ |
343 | pages[index++] = vmalloc_to_page(data); | 353 | while (1) { |
354 | len = iov_iter_single_seg_count(data); | ||
355 | if (likely(len)) { | ||
356 | p = data->kvec->iov_base + data->iov_offset; | ||
357 | break; | ||
358 | } | ||
359 | iov_iter_advance(data, 0); | ||
360 | } | ||
361 | if (len > count) | ||
362 | len = count; | ||
363 | |||
364 | nr_pages = DIV_ROUND_UP((unsigned long)p + len, PAGE_SIZE) - | ||
365 | (unsigned long)p / PAGE_SIZE; | ||
366 | |||
367 | *pages = kmalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); | ||
368 | if (!*pages) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | *need_drop = 0; | ||
372 | p -= (*offs = (unsigned long)p % PAGE_SIZE); | ||
373 | for (index = 0; index < nr_pages; index++) { | ||
374 | if (is_vmalloc_addr(p)) | ||
375 | (*pages)[index] = vmalloc_to_page(p); | ||
344 | else | 376 | else |
345 | pages[index++] = kmap_to_page(data); | 377 | (*pages)[index] = kmap_to_page(p); |
346 | data += s; | 378 | p += PAGE_SIZE; |
347 | nr_pages--; | ||
348 | } | 379 | } |
349 | nr_pages = count; | 380 | return len; |
350 | } | 381 | } |
351 | return nr_pages; | ||
352 | } | 382 | } |
353 | 383 | ||
354 | /** | 384 | /** |
@@ -364,8 +394,8 @@ static int p9_get_mapped_pages(struct virtio_chan *chan, | |||
364 | */ | 394 | */ |
365 | static int | 395 | static int |
366 | p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | 396 | p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, |
367 | char *uidata, char *uodata, int inlen, | 397 | struct iov_iter *uidata, struct iov_iter *uodata, |
368 | int outlen, int in_hdr_len, int kern_buf) | 398 | int inlen, int outlen, int in_hdr_len) |
369 | { | 399 | { |
370 | int in, out, err, out_sgs, in_sgs; | 400 | int in, out, err, out_sgs, in_sgs; |
371 | unsigned long flags; | 401 | unsigned long flags; |
@@ -373,41 +403,32 @@ p9_virtio_zc_request(struct p9_client *client, struct p9_req_t *req, | |||
373 | struct page **in_pages = NULL, **out_pages = NULL; | 403 | struct page **in_pages = NULL, **out_pages = NULL; |
374 | struct virtio_chan *chan = client->trans; | 404 | struct virtio_chan *chan = client->trans; |
375 | struct scatterlist *sgs[4]; | 405 | struct scatterlist *sgs[4]; |
406 | size_t offs; | ||
407 | int need_drop = 0; | ||
376 | 408 | ||
377 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); | 409 | p9_debug(P9_DEBUG_TRANS, "virtio request\n"); |
378 | 410 | ||
379 | if (uodata) { | 411 | if (uodata) { |
380 | out_nr_pages = p9_nr_pages(uodata, outlen); | 412 | int n = p9_get_mapped_pages(chan, &out_pages, uodata, |
381 | out_pages = kmalloc(sizeof(struct page *) * out_nr_pages, | 413 | outlen, &offs, &need_drop); |
382 | GFP_NOFS); | 414 | if (n < 0) |
383 | if (!out_pages) { | 415 | return n; |
384 | err = -ENOMEM; | 416 | out_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); |
385 | goto err_out; | 417 | if (n != outlen) { |
386 | } | 418 | __le32 v = cpu_to_le32(n); |
387 | out_nr_pages = p9_get_mapped_pages(chan, out_pages, uodata, | 419 | memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4); |
388 | out_nr_pages, 0, kern_buf); | 420 | outlen = n; |
389 | if (out_nr_pages < 0) { | ||
390 | err = out_nr_pages; | ||
391 | kfree(out_pages); | ||
392 | out_pages = NULL; | ||
393 | goto err_out; | ||
394 | } | 421 | } |
395 | } | 422 | } else if (uidata) { |
396 | if (uidata) { | 423 | int n = p9_get_mapped_pages(chan, &in_pages, uidata, |
397 | in_nr_pages = p9_nr_pages(uidata, inlen); | 424 | inlen, &offs, &need_drop); |
398 | in_pages = kmalloc(sizeof(struct page *) * in_nr_pages, | 425 | if (n < 0) |
399 | GFP_NOFS); | 426 | return n; |
400 | if (!in_pages) { | 427 | in_nr_pages = DIV_ROUND_UP(n + offs, PAGE_SIZE); |
401 | err = -ENOMEM; | 428 | if (n != inlen) { |
402 | goto err_out; | 429 | __le32 v = cpu_to_le32(n); |
403 | } | 430 | memcpy(&req->tc->sdata[req->tc->size - 4], &v, 4); |
404 | in_nr_pages = p9_get_mapped_pages(chan, in_pages, uidata, | 431 | inlen = n; |
405 | in_nr_pages, 1, kern_buf); | ||
406 | if (in_nr_pages < 0) { | ||
407 | err = in_nr_pages; | ||
408 | kfree(in_pages); | ||
409 | in_pages = NULL; | ||
410 | goto err_out; | ||
411 | } | 432 | } |
412 | } | 433 | } |
413 | req->status = REQ_STATUS_SENT; | 434 | req->status = REQ_STATUS_SENT; |
@@ -426,7 +447,7 @@ req_retry_pinned: | |||
426 | if (out_pages) { | 447 | if (out_pages) { |
427 | sgs[out_sgs++] = chan->sg + out; | 448 | sgs[out_sgs++] = chan->sg + out; |
428 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | 449 | out += pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, |
429 | out_pages, out_nr_pages, uodata, outlen); | 450 | out_pages, out_nr_pages, offs, outlen); |
430 | } | 451 | } |
431 | 452 | ||
432 | /* | 453 | /* |
@@ -444,7 +465,7 @@ req_retry_pinned: | |||
444 | if (in_pages) { | 465 | if (in_pages) { |
445 | sgs[out_sgs + in_sgs++] = chan->sg + out + in; | 466 | sgs[out_sgs + in_sgs++] = chan->sg + out + in; |
446 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, | 467 | in += pack_sg_list_p(chan->sg, out + in, VIRTQUEUE_NUM, |
447 | in_pages, in_nr_pages, uidata, inlen); | 468 | in_pages, in_nr_pages, offs, inlen); |
448 | } | 469 | } |
449 | 470 | ||
450 | BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs)); | 471 | BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs)); |
@@ -478,7 +499,7 @@ req_retry_pinned: | |||
478 | * Non kernel buffers are pinned, unpin them | 499 | * Non kernel buffers are pinned, unpin them |
479 | */ | 500 | */ |
480 | err_out: | 501 | err_out: |
481 | if (!kern_buf) { | 502 | if (need_drop) { |
482 | if (in_pages) { | 503 | if (in_pages) { |
483 | p9_release_pages(in_pages, in_nr_pages); | 504 | p9_release_pages(in_pages, in_nr_pages); |
484 | atomic_sub(in_nr_pages, &vp_pinned); | 505 | atomic_sub(in_nr_pages, &vp_pinned); |
diff --git a/net/socket.c b/net/socket.c index 5b0126234606..3e33959f3ce5 100644 --- a/net/socket.c +++ b/net/socket.c | |||
@@ -140,8 +140,6 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, | |||
140 | static const struct file_operations socket_file_ops = { | 140 | static const struct file_operations socket_file_ops = { |
141 | .owner = THIS_MODULE, | 141 | .owner = THIS_MODULE, |
142 | .llseek = no_llseek, | 142 | .llseek = no_llseek, |
143 | .read = new_sync_read, | ||
144 | .write = new_sync_write, | ||
145 | .read_iter = sock_read_iter, | 143 | .read_iter = sock_read_iter, |
146 | .write_iter = sock_write_iter, | 144 | .write_iter = sock_write_iter, |
147 | .poll = sock_poll, | 145 | .poll = sock_poll, |