Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag '9p-for-6.15-rc1' of https://github.com/martinetd/linux

Pull 9p updates from Dominique Martinet:

- fix handling of bogus (negative/too long) replies

- fix crash on mkdir with ACLs (... looks like nobody is using ACLs
with semi-recent kernels...)

- ipv6 support for trans=tcp

- minor concurrency fix to make syzbot happy

- minor cleanup

* tag '9p-for-6.15-rc1' of https://github.com/martinetd/linux:
docs: fs/9p: Add missing "not" in cache documentation
9p: Use hashtable.h for hash_errmap
Documentation/fs/9p: fix broken link
9p/trans_fd: mark concurrent read and writes to p9_conn->err
9p/net: return error on bogus (longer than requested) replies
9p/net: fix improper handling of bogus negative read/write replies
fs/9p: fix NULL pointer dereference on mkdir
net/9p/fd: support ipv6 for trans=tcp

+73 -73
+3 -3
Documentation/filesystems/9p.rst
··· 40 40 41 41 mount -t 9p 10.10.1.2 /mnt/9 42 42 43 - For Plan 9 From User Space applications (http://swtch.com/plan9):: 43 + For Plan 9 From User Space applications (https://9fans.github.io/plan9port/):: 44 44 45 45 mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER 46 46 ··· 165 165 do not necessarily validate cached values on the server. In other 166 166 words changes on the server are not guaranteed to be reflected 167 167 on the client system. Only use this mode of operation if you 168 - have an exclusive mount and the server will modify the filesystem 169 - underneath you. 168 + have an exclusive mount and the server will not modify the 169 + filesystem underneath you. 170 170 171 171 debug=n specifies debug level. The debug level is a bitmask. 172 172
+1 -1
fs/9p/vfs_inode_dotl.c
··· 407 407 err); 408 408 goto error; 409 409 } 410 - v9fs_fid_add(dentry, &fid); 411 410 v9fs_set_create_acl(inode, fid, dacl, pacl); 411 + v9fs_fid_add(dentry, &fid); 412 412 d_instantiate(dentry, inode); 413 413 err = 0; 414 414 inc_nlink(dir);
+26 -18
net/9p/client.c
··· 1548 1548 struct p9_client *clnt = fid->clnt; 1549 1549 struct p9_req_t *req; 1550 1550 int count = iov_iter_count(to); 1551 - int rsize, received, non_zc = 0; 1551 + u32 rsize, received; 1552 + bool non_zc = false; 1552 1553 char *dataptr; 1553 1554 1554 1555 *err = 0; ··· 1572 1571 0, 11, "dqd", fid->fid, 1573 1572 offset, rsize); 1574 1573 } else { 1575 - non_zc = 1; 1574 + non_zc = true; 1576 1575 req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, 1577 1576 rsize); 1578 1577 } ··· 1593 1592 return 0; 1594 1593 } 1595 1594 if (rsize < received) { 1596 - pr_err("bogus RREAD count (%d > %d)\n", received, rsize); 1597 - received = rsize; 1595 + pr_err("bogus RREAD count (%u > %u)\n", received, rsize); 1596 + *err = -EIO; 1597 + p9_req_put(clnt, req); 1598 + return 0; 1598 1599 } 1599 1600 1600 - p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", received); 1601 + p9_debug(P9_DEBUG_9P, "<<< RREAD count %u\n", received); 1601 1602 1602 1603 if (non_zc) { 1603 1604 int n = copy_to_iter(dataptr, received, to); ··· 1626 1623 *err = 0; 1627 1624 1628 1625 while (iov_iter_count(from)) { 1629 - int count = iov_iter_count(from); 1630 - int rsize = fid->iounit; 1631 - int written; 1626 + size_t count = iov_iter_count(from); 1627 + u32 rsize = fid->iounit; 1628 + u32 written; 1632 1629 1633 1630 if (!rsize || rsize > clnt->msize - P9_IOHDRSZ) 1634 1631 rsize = clnt->msize - P9_IOHDRSZ; ··· 1636 1633 if (count < rsize) 1637 1634 rsize = count; 1638 1635 1639 - p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d (/%d)\n", 1636 + p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %u (/%zu)\n", 1640 1637 fid->fid, offset, rsize, count); 1641 1638 1642 1639 /* Don't bother zerocopy for small IO (< 1024) */ ··· 1662 1659 break; 1663 1660 } 1664 1661 if (rsize < written) { 1665 - pr_err("bogus RWRITE count (%d > %d)\n", written, rsize); 1666 - written = rsize; 1662 + pr_err("bogus RWRITE count (%u > %u)\n", written, rsize); 1663 + *err = -EIO; 1664 + iov_iter_revert(from, count - iov_iter_count(from)); 1665 + p9_req_put(clnt, req); 1666 + break; 1667 1667 } 1668 1668 1669 - p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", written); 1669 + p9_debug(P9_DEBUG_9P, "<<< RWRITE count %u\n", written); 1670 1670 1671 1671 p9_req_put(clnt, req); 1672 1672 iov_iter_revert(from, count - written - iov_iter_count(from)); ··· 1718 1712 1719 1713 if (written > len) { 1720 1714 pr_err("bogus RWRITE count (%d > %u)\n", written, len); 1721 - written = len; 1715 + written = -EIO; 1722 1716 } 1723 1717 1724 1718 p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", len); ··· 2104 2098 2105 2099 int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) 2106 2100 { 2107 - int err, rsize, non_zc = 0; 2101 + int err, non_zc = 0; 2102 + u32 rsize; 2108 2103 struct p9_client *clnt; 2109 2104 struct p9_req_t *req; 2110 2105 char *dataptr; ··· 2114 2107 2115 2108 iov_iter_kvec(&to, ITER_DEST, &kv, 1, count); 2116 2109 2117 - p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", 2110 + p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %u\n", 2118 2111 fid->fid, offset, count); 2119 2112 2120 2113 clnt = fid->clnt; ··· 2149 2142 goto free_and_error; 2150 2143 } 2151 2144 if (rsize < count) { 2152 - pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); 2153 - count = rsize; 2145 + pr_err("bogus RREADDIR count (%u > %u)\n", count, rsize); 2146 + err = -EIO; 2147 + goto free_and_error; 2154 2148 } 2155 2149 2156 - p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); 2150 + p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %u\n", count); 2157 2151 2158 2152 if (non_zc) 2159 2153 memmove(data, dataptr, count);
+9 -12
net/9p/error.c
··· 16 16 #include <linux/list.h> 17 17 #include <linux/jhash.h> 18 18 #include <linux/errno.h> 19 + #include <linux/hashtable.h> 19 20 #include <net/9p/9p.h> 20 21 21 22 /** ··· 34 33 struct hlist_node list; 35 34 }; 36 35 37 - #define ERRHASHSZ 32 38 - static struct hlist_head hash_errmap[ERRHASHSZ]; 36 + #define ERRHASH_BITS 5 37 + static DEFINE_HASHTABLE(hash_errmap, ERRHASH_BITS); 39 38 40 39 /* FixMe - reduce to a reasonable size */ 41 40 static struct errormap errmap[] = { ··· 177 176 int p9_error_init(void) 178 177 { 179 178 struct errormap *c; 180 - int bucket; 181 - 182 - /* initialize hash table */ 183 - for (bucket = 0; bucket < ERRHASHSZ; bucket++) 184 - INIT_HLIST_HEAD(&hash_errmap[bucket]); 179 + u32 hash; 185 180 186 181 /* load initial error map into hash table */ 187 182 for (c = errmap; c->name; c++) { 188 183 c->namelen = strlen(c->name); 189 - bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ; 184 + hash = jhash(c->name, c->namelen, 0); 190 185 INIT_HLIST_NODE(&c->list); 191 - hlist_add_head(&c->list, &hash_errmap[bucket]); 186 + hash_add(hash_errmap, &c->list, hash); 192 187 } 193 188 194 189 return 1; ··· 202 205 { 203 206 int errno; 204 207 struct errormap *c; 205 - int bucket; 208 + u32 hash; 206 209 207 210 errno = 0; 208 211 c = NULL; 209 - bucket = jhash(errstr, len, 0) % ERRHASHSZ; 210 - hlist_for_each_entry(c, &hash_errmap[bucket], list) { 212 + hash = jhash(errstr, len, 0); 213 + hash_for_each_possible(hash_errmap, c, list, hash) { 211 214 if (c->namelen == len && !memcmp(c->name, errstr, len)) { 212 215 errno = c->val; 213 216 break;
+34 -39
net/9p/trans_fd.c
··· 11 11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 12 12 13 13 #include <linux/in.h> 14 + #include <linux/in6.h> 14 15 #include <linux/module.h> 15 16 #include <linux/net.h> 16 17 #include <linux/ipv6.h> ··· 192 191 193 192 spin_lock(&m->req_lock); 194 193 195 - if (m->err) { 194 + if (READ_ONCE(m->err)) { 196 195 spin_unlock(&m->req_lock); 197 196 return; 198 197 } 199 198 200 - m->err = err; 199 + WRITE_ONCE(m->err, err); 200 + ASSERT_EXCLUSIVE_WRITER(m->err); 201 201 202 202 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { 203 203 list_move(&req->req_list, &cancel_list); ··· 285 283 286 284 m = container_of(work, struct p9_conn, rq); 287 285 288 - if (m->err < 0) 286 + if (READ_ONCE(m->err) < 0) 289 287 return; 290 288 291 289 p9_debug(P9_DEBUG_TRANS, "start mux %p pos %zd\n", m, m->rc.offset); ··· 452 450 453 451 m = container_of(work, struct p9_conn, wq); 454 452 455 - if (m->err < 0) { 453 + if (READ_ONCE(m->err) < 0) { 456 454 clear_bit(Wworksched, &m->wsched); 457 455 return; 458 456 } ··· 624 622 __poll_t n; 625 623 int err = -ECONNRESET; 626 624 627 - if (m->err < 0) 625 + if (READ_ONCE(m->err) < 0) 628 626 return; 629 627 630 628 n = p9_fd_poll(m->client, NULL, &err); ··· 667 665 static int p9_fd_request(struct p9_client *client, struct p9_req_t *req) 668 666 { 669 667 __poll_t n; 668 + int err; 670 669 struct p9_trans_fd *ts = client->trans; 671 670 struct p9_conn *m = &ts->conn; 672 671 ··· 676 673 677 674 spin_lock(&m->req_lock); 678 675 679 - if (m->err < 0) { 676 + err = READ_ONCE(m->err); 677 + if (err < 0) { 680 678 spin_unlock(&m->req_lock); 681 - return m->err; 679 + return err; 682 680 } 683 681 684 682 WRITE_ONCE(req->status, REQ_STATUS_UNSENT); ··· 958 954 kfree(ts); 959 955 } 960 956 961 - /* 962 - * stolen from NFS - maybe should be made a generic function? 963 - */ 964 - static inline int valid_ipaddr4(const char *buf) 965 - { 966 - int rc, count, in[4]; 967 - 968 - rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]); 969 - if (rc != 4) 970 - return -EINVAL; 971 - for (count = 0; count < 4; count++) { 972 - if (in[count] > 255) 973 - return -EINVAL; 974 - } 975 - return 0; 976 - } 977 - 978 957 static int p9_bind_privport(struct socket *sock) 979 958 { 980 - struct sockaddr_in cl; 959 + struct sockaddr_storage stor = { 0 }; 981 960 int port, err = -EINVAL; 982 961 983 - memset(&cl, 0, sizeof(cl)); 984 - cl.sin_family = AF_INET; 985 - cl.sin_addr.s_addr = htonl(INADDR_ANY); 962 + stor.ss_family = sock->ops->family; 963 + if (stor.ss_family == AF_INET) 964 + ((struct sockaddr_in *)&stor)->sin_addr.s_addr = htonl(INADDR_ANY); 965 + else 966 + ((struct sockaddr_in6 *)&stor)->sin6_addr = in6addr_any; 986 967 for (port = p9_ipport_resv_max; port >= p9_ipport_resv_min; port--) { 987 - cl.sin_port = htons((ushort)port); 988 - err = kernel_bind(sock, (struct sockaddr *)&cl, sizeof(cl)); 968 + if (stor.ss_family == AF_INET) 969 + ((struct sockaddr_in *)&stor)->sin_port = htons((ushort)port); 970 + else 971 + ((struct sockaddr_in6 *)&stor)->sin6_port = htons((ushort)port); 972 + err = kernel_bind(sock, (struct sockaddr *)&stor, sizeof(stor)); 989 973 if (err != -EADDRINUSE) 990 974 break; 991 975 } 992 976 return err; 993 977 } 994 978 995 - 996 979 static int 997 980 p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) 998 981 { 999 982 int err; 983 + char port_str[6]; 1000 984 struct socket *csocket; 1001 - struct sockaddr_in sin_server; 985 + struct sockaddr_storage stor = { 0 }; 1002 986 struct p9_fd_opts opts; 1003 987 1004 988 err = parse_opts(args, &opts); 1005 989 if (err < 0) 1006 990 return err; 1007 991 1008 - if (addr == NULL || valid_ipaddr4(addr) < 0) 992 + if (!addr) 1009 993 return -EINVAL; 994 + 995 + sprintf(port_str, "%u", opts.port); 996 + err = inet_pton_with_scope(current->nsproxy->net_ns, AF_UNSPEC, addr, 997 + port_str, &stor); 998 + if (err < 0) 999 + return err; 1010 1000 1011 1001 csocket = NULL; 1012 1002 1013 1003 client->trans_opts.tcp.port = opts.port; 1014 1004 client->trans_opts.tcp.privport = opts.privport; 1015 - sin_server.sin_family = AF_INET; 1016 - sin_server.sin_addr.s_addr = in_aton(addr); 1017 - sin_server.sin_port = htons(opts.port); 1018 - err = __sock_create(current->nsproxy->net_ns, PF_INET, 1005 + err = __sock_create(current->nsproxy->net_ns, stor.ss_family, 1019 1006 SOCK_STREAM, IPPROTO_TCP, &csocket, 1); 1020 1007 if (err) { 1021 1008 pr_err("%s (%d): problem creating socket\n", ··· 1025 1030 } 1026 1031 1027 1032 err = READ_ONCE(csocket->ops)->connect(csocket, 1028 - (struct sockaddr *)&sin_server, 1029 - sizeof(struct sockaddr_in), 0); 1033 + (struct sockaddr *)&stor, 1034 + sizeof(stor), 0); 1030 1035 if (err < 0) { 1031 1036 pr_err("%s (%d): problem connecting socket to %s\n", 1032 1037 __func__, task_pid_nr(current), addr);