Merge tag '9p-for-6.7-rc1' of https://github.com/martinetd/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Nov 2023 19:20:04 +0000 (09:20 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Nov 2023 19:20:04 +0000 (09:20 -1000)
Pull 9p updates from Dominique Martinet:
 A bunch of small fixes:

   - three W=1 warning fixes: the NULL -> "" replacement isn't trivial
     but is serialized identically by the protocol layer and has been
     tested

   - one syzbot/KCSAN datarace annotation where we don't care about
     users messing with the fd they passed to mount -t 9p

   - removing a declaration without implementation

   - yet another race fix for trans_fd around connection close: the
     'err' field is also used in potentially racy calls and this isn't
     complete, but it's better than what we had

   - and finally a theorical memory leak fix on serialization failure"

* tag '9p-for-6.7-rc1' of https://github.com/martinetd/linux:
  9p/net: fix possible memory leak in p9_check_errors()
  9p/fs: add MODULE_DESCRIPTION
  9p/net: xen: fix false positive printf format overflow warning
  9p: v9fs_listxattr: fix %s null argument warning
  9p/trans_fd: Annotate data-racy writes to file::f_flags
  fs/9p: Remove unused function declaration v9fs_inode2stat()
  9p/trans_fd: avoid sending req to a cancelled conn

fs/9p/v9fs.c
fs/9p/v9fs_vfs.h
fs/9p/xattr.c
net/9p/client.c
net/9p/trans_fd.c
net/9p/trans_xen.c

index d525957..61dbe52 100644 (file)
@@ -732,4 +732,5 @@ module_exit(exit_v9fs)
 MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
 MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
 MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
+MODULE_DESCRIPTION("9P Client File System");
 MODULE_LICENSE("GPL");
index cdf441f..731e3d1 100644 (file)
@@ -52,7 +52,6 @@ void v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
                           unsigned int flags);
 int v9fs_dir_release(struct inode *inode, struct file *filp);
 int v9fs_file_open(struct inode *inode, struct file *file);
-void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
 int v9fs_uflags2omode(int uflags, int extended);
 
 void v9fs_blank_wstat(struct p9_wstat *wstat);
index 053d1ce..8604e33 100644 (file)
@@ -68,7 +68,7 @@ ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
        struct p9_fid *fid;
        int ret;
 
-       p9_debug(P9_DEBUG_VFS, "name = %s value_len = %zu\n",
+       p9_debug(P9_DEBUG_VFS, "name = '%s' value_len = %zu\n",
                 name, buffer_size);
        fid = v9fs_fid_lookup(dentry);
        if (IS_ERR(fid))
@@ -139,7 +139,8 @@ int v9fs_fid_xattr_set(struct p9_fid *fid, const char *name,
 
 ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
 {
-       return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
+       /* Txattrwalk with an empty string lists xattrs instead */
+       return v9fs_xattr_get(dentry, "", buffer, buffer_size);
 }
 
 static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
index 86bbc71..e265a0c 100644 (file)
@@ -540,12 +540,14 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
                return 0;
 
        if (!p9_is_proto_dotl(c)) {
-               char *ename;
+               char *ename = NULL;
 
                err = p9pdu_readf(&req->rc, c->proto_version, "s?d",
                                  &ename, &ecode);
-               if (err)
+               if (err) {
+                       kfree(ename);
                        goto out_err;
+               }
 
                if (p9_is_proto_dotu(c) && ecode < 512)
                        err = -ecode;
@@ -1979,7 +1981,7 @@ struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
                goto error;
        }
        p9_debug(P9_DEBUG_9P,
-                ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n",
+                ">>> TXATTRWALK file_fid %d, attr_fid %d name '%s'\n",
                 file_fid->fid, attr_fid->fid, attr_name);
 
        req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
index c4015f3..1a3948b 100644 (file)
@@ -671,10 +671,14 @@ static int p9_fd_request(struct p9_client *client, struct p9_req_t *req)
 
        p9_debug(P9_DEBUG_TRANS, "mux %p task %p tcall %p id %d\n",
                 m, current, &req->tc, req->tc.id);
-       if (m->err < 0)
-               return m->err;
 
        spin_lock(&m->req_lock);
+
+       if (m->err < 0) {
+               spin_unlock(&m->req_lock);
+               return m->err;
+       }
+
        WRITE_ONCE(req->status, REQ_STATUS_UNSENT);
        list_add_tail(&req->req_list, &m->unsent_req_list);
        spin_unlock(&m->req_lock);
@@ -832,14 +836,21 @@ static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
                goto out_free_ts;
        if (!(ts->rd->f_mode & FMODE_READ))
                goto out_put_rd;
-       /* prevent workers from hanging on IO when fd is a pipe */
-       ts->rd->f_flags |= O_NONBLOCK;
+       /* Prevent workers from hanging on IO when fd is a pipe.
+        * It's technically possible for userspace or concurrent mounts to
+        * modify this flag concurrently, which will likely result in a
+        * broken filesystem. However, just having bad flags here should
+        * not crash the kernel or cause any other sort of bug, so mark this
+        * particular data race as intentional so that tooling (like KCSAN)
+        * can allow it and detect further problems.
+        */
+       data_race(ts->rd->f_flags |= O_NONBLOCK);
        ts->wr = fget(wfd);
        if (!ts->wr)
                goto out_put_rd;
        if (!(ts->wr->f_mode & FMODE_WRITE))
                goto out_put_wr;
-       ts->wr->f_flags |= O_NONBLOCK;
+       data_race(ts->wr->f_flags |= O_NONBLOCK);
 
        client->trans = ts;
        client->status = Connected;
index 1fffe2b..dfdbe1c 100644 (file)
@@ -54,7 +54,6 @@ struct xen_9pfs_front_priv {
        char *tag;
        struct p9_client *client;
 
-       int num_rings;
        struct xen_9pfs_dataring *rings;
 };
 
@@ -131,7 +130,7 @@ static int p9_xen_request(struct p9_client *client, struct p9_req_t *p9_req)
        if (list_entry_is_head(priv, &xen_9pfs_devs, list))
                return -EINVAL;
 
-       num = p9_req->tc.tag % priv->num_rings;
+       num = p9_req->tc.tag % XEN_9PFS_NUM_RINGS;
        ring = &priv->rings[num];
 
 again:
@@ -279,7 +278,7 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
        list_del(&priv->list);
        write_unlock(&xen_9pfs_lock);
 
-       for (i = 0; i < priv->num_rings; i++) {
+       for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
                struct xen_9pfs_dataring *ring = &priv->rings[i];
 
                cancel_work_sync(&ring->work);
@@ -408,15 +407,14 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
        if (p9_xen_trans.maxsize > XEN_FLEX_RING_SIZE(max_ring_order))
                p9_xen_trans.maxsize = XEN_FLEX_RING_SIZE(max_ring_order) / 2;
 
-       priv->num_rings = XEN_9PFS_NUM_RINGS;
-       priv->rings = kcalloc(priv->num_rings, sizeof(*priv->rings),
+       priv->rings = kcalloc(XEN_9PFS_NUM_RINGS, sizeof(*priv->rings),
                              GFP_KERNEL);
        if (!priv->rings) {
                kfree(priv);
                return -ENOMEM;
        }
 
-       for (i = 0; i < priv->num_rings; i++) {
+       for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
                priv->rings[i].priv = priv;
                ret = xen_9pfs_front_alloc_dataring(dev, &priv->rings[i],
                                                    max_ring_order);
@@ -434,10 +432,11 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
        if (ret)
                goto error_xenbus;
        ret = xenbus_printf(xbt, dev->nodename, "num-rings", "%u",
-                           priv->num_rings);
+                           XEN_9PFS_NUM_RINGS);
        if (ret)
                goto error_xenbus;
-       for (i = 0; i < priv->num_rings; i++) {
+
+       for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
                char str[16];
 
                BUILD_BUG_ON(XEN_9PFS_NUM_RINGS > 9);