mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
This is mostly a huge wave of LLM-driven fixes
A few exceptions: - a new vsock transport was added, since it's a variant of the existing fd/tcp transport there is little harm in taking it in - there's an incomplete fix for when file actual size doesn't match the size attribute (e.g. exports of sysfs), the fix addresses when st_size > actual size with cache=none but just about everything else is still broken (st_size=0 with actual data regardless of cache, or with data cache st_size > actual is still wrong and so are symlinks with 0 size)... Maybe at some point I'll find time to understand how netfs works and address these :| - some fixes for the usbg transport by its author, thank you! -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAmrpzl8ACgkQq06b7GqY 5nA7SxAAmThz0j/BVRmej5Ii8ZWE18tibAG5o4EgEqTX15HfaePc3BxaogayrZkh xueb3ZBqN0jdKqScIL+6SeQcFwskoSohfZeFv5c75zafw+2x9MrmxVLeJw0oU2N0 vybsMzLJOjMX7gRP3FUangqKlIoeQVOuP8XzYsbqLziMknQp4N2cAsZ/seuZOo+H +JBDWry3qok39TLEhIcFEACW+X3RNW2asRBtDNvjGrASBWRZsJSNnLdSIZ00XYPe BYddasTbBjkX3cdyXfEdtcYRb3BNmcNhdBEVpEuhVyUc/qL+Aft0lBTbIt1CIbdO LOmX/vbCvj4kTee7SjkE59aFp84wcZ+tYx0+4RmZBQPJE8FbqxMrtQ0i7Z6XNee4 mgugn5OnnH37Fw8z3EhRMVDZrNXjaS7tl5gJxfEWuyn6RdKWWICWlm8K5P58WGy3 HOU21/uOLxACLoAZLqudjA6CfjGoJXuk9T9+cnh4lqu9ghPgfY39lWVjXKSNpjg7 4A1DNRn6fwfJiC7JtTlfbV9xtHmdsGV5syClKWNVGaCLUp+KDCs3J3aigHiUVt+y biBeB+yvU+0NkvAmzKUv97X7wBCzW0HgruZQQJ1rSEBAtrlaC4ev5CyjBOhn3//P wZ7wvAmW2fr2INo0nE4usv46jF6emLWH/kbWAKHzAW/BzFGaiUw= =oC41 -----END PGP SIGNATURE----- Merge tag '9p-for-7.4-rc2' of https://github.com/martinetd/linux Pull late 9p updates from Dominique Martinet: "This is mostly a huge wave of LLM-driven fixes. At least the LLM fixes sort of slowed down recently? Or maybe it's just the time of the cycle and/or I got used to it, time will tell... A few exceptions: - a new vsock transport was added, since it's a variant of the existing fd/tcp transport there is little harm in taking it in - there's an incomplete fix for when file actual size doesn't match the size attribute (e.g. exports of sysfs). The fix addresses when st_size > actual size with cache=none but just about everything else is still broken (st_size=0 with actual data regardless of cache, or with data cache st_size > actual is still wrong and so are symlinks with 0 size)... Maybe at some point I'll find time to understand how netfs works and address these :| - some fixes for the usbg transport by its author, thank you!" * tag '9p-for-7.4-rc2' of https://github.com/martinetd/linux: (39 commits) 9p: optimize p9_fcall struct 9p: reject RERROR/RLERROR with zero errcode 9p: do not store the create fid on special files 9p: fall back to the normal open path for non-regular files 9p: don't decrement a server-owned zero nlink 9p: fix kernel-doc warning for enum p9_session_flags 9p: treat read return values of 0 as EOF 9p/xen: validate the response size from the backend 9p: fix typo in file header comments 9p: remove duplicated assignment in v9fs_fill_super() 9p: fix typos and wrong parameter docs in vfs_inode.c 9p: fix header guard comment in acl.h net/9p/usbg: clear stale client pointer on close net/9p/usbg: remove bogus context initialization in alloc_requests net/9p/usbg: fix out_req buffer leak in disable_usb9pfs net/9p/usbg: call disable_usb9pfs() from usb9pfs_disable() net/9p/usbg: always reset completion when disconnecting net/9p/usbg: set client to Disconnected on usb9pfs_disable net/9p/usbg: also disable endpoints on p9_usbg_close net/9p/usbg: Fix use-after-free in disable_usb9pfs() ...
This commit is contained in:
commit
7d1471e509
|
|
@ -50,6 +50,14 @@ mount points. Each 9P export is seen by the client as a virtio device with an
|
|||
associated "mount_tag" property. Available mount tags can be
|
||||
seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files.
|
||||
|
||||
For server accessible over vsock (VM sockets)::
|
||||
|
||||
mount -t 9p -o trans=vsock[,port=<port>] <CID> /mnt/9
|
||||
|
||||
where CID is the vsock Context ID of the remote endpoint (2 for host from
|
||||
a guest VM, 3+ for guest VMs from the host). The port to connect to can be
|
||||
specified with the port option (default: 564).
|
||||
|
||||
USBG Usage
|
||||
==========
|
||||
|
||||
|
|
@ -117,6 +125,8 @@ Options
|
|||
tcp specifying a normal TCP/IP connection
|
||||
fd used passed file descriptors for connection
|
||||
(see rfdno and wfdno)
|
||||
vsock connect over VM sockets (vsock) using
|
||||
CID as the mount source
|
||||
virtio connect to the next virtio channel available
|
||||
(from QEMU with trans_virtio module)
|
||||
rdma connect to a specified RDMA channel
|
||||
|
|
@ -228,7 +238,7 @@ Options
|
|||
any
|
||||
v9fs does single attach and performs all
|
||||
operations as one user
|
||||
clien
|
||||
client
|
||||
ACL based access check on the 9p client
|
||||
side for access validation
|
||||
|
||||
|
|
|
|||
|
|
@ -51,4 +51,4 @@ static inline int v9fs_acl_mode(struct inode *dir, umode_t *modep,
|
|||
}
|
||||
|
||||
#endif
|
||||
#endif /* FS_9P_XATTR_H */
|
||||
#endif /* FS_9P_ACL_H */
|
||||
|
|
|
|||
|
|
@ -20,17 +20,14 @@ int v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses,
|
|||
const char *dev_name)
|
||||
{
|
||||
struct fscache_volume *vcookie;
|
||||
char *name, *p;
|
||||
char *name;
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "9p,%s,%s",
|
||||
dev_name, v9ses->cachetag ?: v9ses->aname);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '/')
|
||||
*p = ';';
|
||||
|
||||
strreplace(name, '/', ';');
|
||||
vcookie = fscache_acquire_volume(name, NULL, NULL, 0);
|
||||
p9_debug(P9_DEBUG_FSC, "session %p get volume %p (%s)\n",
|
||||
v9ses, vcookie, name);
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ static int build_path_from_dentry(struct v9fs_session_info *v9ses,
|
|||
for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
|
||||
n++;
|
||||
|
||||
wnames = kmalloc_array(n, sizeof(char *), GFP_KERNEL);
|
||||
wnames = kmalloc_array(n, sizeof(*wnames), GFP_KERNEL);
|
||||
if (!wnames)
|
||||
goto err_out;
|
||||
|
||||
|
|
|
|||
18
fs/9p/v9fs.c
18
fs/9p/v9fs.c
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/fs_context.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
#include <net/9p/transport.h>
|
||||
|
|
@ -406,7 +407,7 @@ int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||
break;
|
||||
case Opt_privport:
|
||||
fd_opts->privport = true;
|
||||
rdma_opts->port = true;
|
||||
rdma_opts->privport = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -617,21 +618,14 @@ static ssize_t caches_show(struct kobject *kobj,
|
|||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t n = 0, count = 0, limit = PAGE_SIZE;
|
||||
ssize_t count = 0;
|
||||
struct v9fs_session_info *v9ses;
|
||||
|
||||
spin_lock(&v9fs_sessionlist_lock);
|
||||
list_for_each_entry(v9ses, &v9fs_sessionlist, slist) {
|
||||
if (v9ses->cachetag) {
|
||||
n = snprintf(buf + count, limit, "%s\n", v9ses->cachetag);
|
||||
if (n < 0) {
|
||||
count = n;
|
||||
break;
|
||||
}
|
||||
|
||||
count += n;
|
||||
limit -= n;
|
||||
}
|
||||
if (v9ses->cachetag)
|
||||
count += sysfs_emit_at(buf, count, "%s\n",
|
||||
v9ses->cachetag);
|
||||
}
|
||||
|
||||
spin_unlock(&v9fs_sessionlist_lock);
|
||||
|
|
|
|||
26
fs/9p/v9fs.h
26
fs/9p/v9fs.h
|
|
@ -21,20 +21,16 @@
|
|||
* @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
|
||||
* @V9FS_ACCESS_USER: a new attach will be issued for every user (default)
|
||||
* @V9FS_ACCESS_CLIENT: Just like user, but access check is performed on client.
|
||||
* @V9FS_ACCESS_ANY: use a single attach for all users
|
||||
* @V9FS_ACCESS_MASK: bit mask of different ACCESS options
|
||||
* @V9FS_POSIX_ACL: POSIX ACLs are enforced
|
||||
* @V9FS_NO_XATTR: do not offer xattr functions on this mount
|
||||
* @V9FS_IGNORE_QV: ignore qid.version==0 as a marker to disable data cache
|
||||
* @V9FS_DIRECT_IO: disable data read/write cache
|
||||
* @V9FS_SYNC: disable data write cache
|
||||
* @V9FS_NDENTRY_TIMEOUT_SET: Has negative dentry timeout retention time been
|
||||
* overridden by negtimeout mount option
|
||||
*
|
||||
* Session flags reflect options selected by users at mount time
|
||||
*/
|
||||
#define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
|
||||
V9FS_ACCESS_USER | \
|
||||
V9FS_ACCESS_CLIENT)
|
||||
#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
|
||||
#define V9FS_ACL_MASK V9FS_POSIX_ACL
|
||||
|
||||
enum p9_session_flags {
|
||||
V9FS_PROTO_2000U = 0x01,
|
||||
V9FS_PROTO_2000L = 0x02,
|
||||
|
|
@ -49,6 +45,20 @@ enum p9_session_flags {
|
|||
V9FS_NDENTRY_TIMEOUT_SET = 0x400,
|
||||
};
|
||||
|
||||
/**
|
||||
* V9FS_ACCESS_ANY - use a single attach for all users
|
||||
*/
|
||||
#define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
|
||||
V9FS_ACCESS_USER | \
|
||||
V9FS_ACCESS_CLIENT)
|
||||
|
||||
/**
|
||||
* V9FS_ACCESS_MASK - bit mask of different ACCESS options
|
||||
*/
|
||||
#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
|
||||
|
||||
#define V9FS_ACL_MASK V9FS_POSIX_ACL
|
||||
|
||||
/**
|
||||
* enum p9_cache_shortcuts - human readable cache preferences
|
||||
* @CACHE_SC_NONE: disable all caches
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This file contians vfs address (mmap) ops for 9P2000.
|
||||
* This file contains vfs address (mmap) ops for 9P2000.
|
||||
*
|
||||
* Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
|
||||
|
|
@ -99,6 +99,7 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
|
|||
char *target;
|
||||
unsigned long long pos = subreq->start + subreq->transferred;
|
||||
int total = 0, err, len, n;
|
||||
size_t to_read = iov_iter_count(&subreq->io_iter);
|
||||
|
||||
if (S_ISLNK(rreq->inode->i_mode)) {
|
||||
/* p9_client_readlink() must not be called for legacy protocols
|
||||
|
|
@ -131,6 +132,8 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq)
|
|||
__set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags);
|
||||
if (pos + total >= i_size_read(rreq->inode))
|
||||
__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);
|
||||
if (!err && !total && to_read)
|
||||
__set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags);
|
||||
if (!err && total) {
|
||||
subreq->transferred += total;
|
||||
__set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags);
|
||||
|
|
@ -165,13 +168,16 @@ static int v9fs_init_request(struct netfs_io_request *rreq, struct file *file)
|
|||
goto no_fid;
|
||||
p9_fid_get(fid);
|
||||
} else if (S_ISLNK(rreq->inode->i_mode)) {
|
||||
/* racing unlink/rename can make this fail with -ENOENT;
|
||||
* that's expected, not a kernel bug, so don't WARN
|
||||
*/
|
||||
dentry = d_find_any_alias(rreq->inode);
|
||||
if (!dentry)
|
||||
goto no_fid;
|
||||
fid = v9fs_fid_lookup(dentry);
|
||||
dput(dentry);
|
||||
if (IS_ERR(fid))
|
||||
goto no_fid;
|
||||
return PTR_ERR(fid);
|
||||
} else {
|
||||
fid = v9fs_fid_find_inode(rreq->inode, writing, INVALID_UID, true);
|
||||
if (!fid)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This file contians vfs dentry ops for the 9P2000 protocol.
|
||||
* This file contains vfs dentry ops for the 9P2000 protocol.
|
||||
*
|
||||
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
|
|||
|
||||
static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
bool over;
|
||||
struct p9_wstat st;
|
||||
int err = 0;
|
||||
struct p9_fid *fid;
|
||||
|
|
@ -125,6 +124,9 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
|||
rdir->offset = ctx->pos;
|
||||
}
|
||||
while (rdir->head < rdir->tail) {
|
||||
bool over = false;
|
||||
size_t namelen;
|
||||
|
||||
err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
|
||||
rdir->tail - rdir->head, &st);
|
||||
if (err <= 0) {
|
||||
|
|
@ -132,8 +134,15 @@ static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
over = !dir_emit(ctx, st.name, strlen(st.name),
|
||||
QID2INO(&st.qid), dt_type(&st));
|
||||
namelen = strlen(st.name);
|
||||
if (namelen > NAME_MAX) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"skip dentry: name length %zu > NAME_MAX\n",
|
||||
namelen);
|
||||
} else {
|
||||
over = !dir_emit(ctx, st.name, namelen,
|
||||
QID2INO(&st.qid), dt_type(&st));
|
||||
}
|
||||
p9stat_free(&st);
|
||||
if (over)
|
||||
return 0;
|
||||
|
|
@ -184,6 +193,7 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
|
|||
}
|
||||
|
||||
while (rdir->head < rdir->tail) {
|
||||
size_t namelen;
|
||||
|
||||
err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
|
||||
rdir->tail - rdir->head,
|
||||
|
|
@ -193,11 +203,19 @@ static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (!dir_emit(ctx, curdirent.d_name,
|
||||
strlen(curdirent.d_name),
|
||||
QID2INO(&curdirent.qid),
|
||||
curdirent.d_type))
|
||||
namelen = strlen(curdirent.d_name);
|
||||
if (namelen > NAME_MAX) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"skip dentry: name length %zu > NAME_MAX\n",
|
||||
namelen);
|
||||
} else if (!dir_emit(ctx, curdirent.d_name, namelen,
|
||||
QID2INO(&curdirent.qid),
|
||||
curdirent.d_type)) {
|
||||
kfree(curdirent.d_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kfree(curdirent.d_name);
|
||||
|
||||
ctx->pos = curdirent.d_off;
|
||||
rdir->head += err;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* This file contians vfs file ops for 9P2000.
|
||||
* This file contains vfs file ops for 9P2000.
|
||||
*
|
||||
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
|
||||
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ static int v9fs_at_to_dotl_flags(int flags)
|
|||
}
|
||||
|
||||
/**
|
||||
* v9fs_dec_count - helper functon to drop i_nlink.
|
||||
* v9fs_dec_count - helper function to drop i_nlink.
|
||||
*
|
||||
* If a directory had nlink <= 2 (including . and ..), then we should not drop
|
||||
* the link count, which indicates the underlying exported fs doesn't maintain
|
||||
|
|
@ -495,6 +495,12 @@ static int v9fs_at_to_dotl_flags(int flags)
|
|||
* nothing and races with concurrent metadata fetches that may already
|
||||
* have observed the post-unlink value (nlink == 0).
|
||||
*
|
||||
* The same applies to a regular file whose cached nlink has already been
|
||||
* driven to zero by the server: in the cached modes the attributes come
|
||||
* from GETATTR and are applied verbatim, so decrementing a link count the
|
||||
* server does not maintain only trips the drop_nlink() WARN_ON and
|
||||
* underflows i_nlink.
|
||||
*
|
||||
* @inode: inode whose nlink is being dropped
|
||||
*/
|
||||
static void v9fs_dec_count(struct inode *inode)
|
||||
|
|
@ -503,6 +509,8 @@ static void v9fs_dec_count(struct inode *inode)
|
|||
|
||||
if (!(v9ses->cache & (CACHE_META | CACHE_LOOSE)))
|
||||
return;
|
||||
if (inode->i_nlink == 0)
|
||||
return;
|
||||
if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)
|
||||
drop_nlink(inode);
|
||||
}
|
||||
|
|
@ -673,8 +681,8 @@ v9fs_vfs_create(const struct mnt_idmap *idmap, struct inode *dir,
|
|||
/**
|
||||
* v9fs_vfs_mkdir - VFS mkdir hook to create a directory
|
||||
* @idmap: idmap of the mount
|
||||
* @dir: inode that is being unlinked
|
||||
* @dentry: dentry that is being unlinked
|
||||
* @dir: inode of the parent directory
|
||||
* @dentry: dentry representing the directory being created
|
||||
* @mode: mode for new directory
|
||||
*
|
||||
*/
|
||||
|
|
@ -802,6 +810,16 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
v9fs_invalidate_inode_attr(dir);
|
||||
inode = d_inode(dentry);
|
||||
v9inode = V9FS_I(inode);
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
* Not a regular file. v9fs_create() already stored the
|
||||
* unopened fid on the dentry. Clunk the opened fid from
|
||||
* the create and let the VFS call ->open.
|
||||
*/
|
||||
p9_fid_put(fid);
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
return finish_no_open(file, NULL);
|
||||
}
|
||||
err = finish_open(file, dentry, generic_file_open);
|
||||
if (unlikely(err)) {
|
||||
p9_fid_put(fid);
|
||||
|
|
@ -1134,7 +1152,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
|
|||
if (v9fs_proto_dotu(v9ses)) {
|
||||
unsigned int i_nlink;
|
||||
/*
|
||||
* Hadlink support got added later to the .u extension.
|
||||
* Hardlink support got added later to the .u extension.
|
||||
* So there can be a server out there that doesn't
|
||||
* support this even with .u extension. That would
|
||||
* just leave us with stat->extension being an empty
|
||||
|
|
|
|||
|
|
@ -312,20 +312,40 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
|
|||
v9fs_fid_add(dentry, &fid);
|
||||
d_instantiate(dentry, inode);
|
||||
|
||||
if (!S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
* Not a regular file. The unopened fid is already on the
|
||||
* dentry. Clunk the opened create fid and let the VFS call
|
||||
* ->open.
|
||||
*/
|
||||
p9_fid_put(ofid);
|
||||
ofid = NULL;
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
err = finish_no_open(file, NULL);
|
||||
goto out;
|
||||
}
|
||||
/* Since we are opening a file, assign the open fid to the file */
|
||||
err = finish_open(file, dentry, generic_file_open);
|
||||
if (err)
|
||||
goto out;
|
||||
file->private_data = ofid;
|
||||
/*
|
||||
* Special files have type-specific fops that own
|
||||
* file->private_data. The create fid is unused
|
||||
* there: leave it for p9_fid_put() on the out
|
||||
* path so it is clunked before we return.
|
||||
*/
|
||||
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) {
|
||||
file->private_data = ofid;
|
||||
#ifdef CONFIG_9P_FSCACHE
|
||||
if (v9ses->cache & CACHE_FSCACHE) {
|
||||
struct v9fs_inode *v9inode = V9FS_I(inode);
|
||||
fscache_use_cookie(v9fs_inode_cookie(v9inode),
|
||||
file->f_mode & FMODE_WRITE);
|
||||
}
|
||||
if (v9ses->cache & CACHE_FSCACHE) {
|
||||
struct v9fs_inode *v9inode = V9FS_I(inode);
|
||||
fscache_use_cookie(v9fs_inode_cookie(v9inode),
|
||||
file->f_mode & FMODE_WRITE);
|
||||
}
|
||||
#endif
|
||||
v9fs_fid_add_modes(ofid, v9ses->flags, v9ses->cache, flags);
|
||||
v9fs_open_fid_add(inode, &ofid);
|
||||
v9fs_fid_add_modes(ofid, v9ses->flags, v9ses->cache, flags);
|
||||
v9fs_open_fid_add(inode, &ofid);
|
||||
}
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
out:
|
||||
p9_fid_put(dfid);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
|
|||
static int v9fs_fill_super(struct super_block *sb)
|
||||
{
|
||||
int ret;
|
||||
struct v9fs_session_info *v9ses = v9ses = sb->s_fs_info;
|
||||
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
||||
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ void _p9_debug(enum p9_debug_flags level, const char *func,
|
|||
* @P9_RCREATE: response with file access information
|
||||
* @P9_TREAD: request to transfer data from a file or directory
|
||||
* @P9_RREAD: response with data requested
|
||||
* @P9_TWRITE: reuqest to transfer data to a file
|
||||
* @P9_TWRITE: request to transfer data to a file
|
||||
* @P9_RWRITE: response with out much data was transferred to file
|
||||
* @P9_TCLUNK: forget about a handle to an entity within the file system
|
||||
* @P9_RCLUNK: response when server has forgotten about the handle
|
||||
|
|
@ -581,6 +581,7 @@ struct p9_rstatfs {
|
|||
struct p9_fcall {
|
||||
u32 size;
|
||||
u8 id;
|
||||
bool zc;
|
||||
u16 tag;
|
||||
|
||||
size_t offset;
|
||||
|
|
@ -588,7 +589,6 @@ struct p9_fcall {
|
|||
|
||||
struct kmem_cache *cache;
|
||||
u8 *sdata;
|
||||
bool zc;
|
||||
};
|
||||
|
||||
int p9_errstr2errno(char *errstr, int len);
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ struct p9_req_t {
|
|||
* @proto_version: 9P protocol version to use
|
||||
* @trans_mod: module API instantiated with this client
|
||||
* @status: connection state
|
||||
* @trans: tranport instance state and API
|
||||
* @trans: transport instance state and API
|
||||
* @fids: All active FID handles
|
||||
* @reqs: All active requests.
|
||||
* @name: node name used as client id
|
||||
|
|
@ -122,8 +122,12 @@ struct p9_client {
|
|||
struct {
|
||||
u16 port;
|
||||
bool privport;
|
||||
|
||||
} tcp;
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
struct {
|
||||
u32 port;
|
||||
} vsock;
|
||||
#endif
|
||||
} trans_opts;
|
||||
|
||||
struct idr fids;
|
||||
|
|
@ -151,13 +155,13 @@ struct p9_client_opts {
|
|||
* struct p9_fd_opts - per-transport options for fd transport
|
||||
* @rfd: file descriptor for reading (trans=fd)
|
||||
* @wfd: file descriptor for writing (trans=fd)
|
||||
* @port: port to connect to (trans=tcp)
|
||||
* @port: port to connect to (trans=tcp, trans=vsock)
|
||||
* @privport: port is privileged
|
||||
*/
|
||||
struct p9_fd_opts {
|
||||
int rfd;
|
||||
int wfd;
|
||||
u16 port;
|
||||
u32 port;
|
||||
bool privport;
|
||||
};
|
||||
|
||||
|
|
@ -270,7 +274,7 @@ struct p9_dirent {
|
|||
struct p9_qid qid;
|
||||
u64 d_off;
|
||||
unsigned char d_type;
|
||||
char d_name[256];
|
||||
char *d_name;
|
||||
};
|
||||
|
||||
struct iov_iter;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,16 @@ config NET_9P_VIRTIO
|
|||
This builds support for a transports between
|
||||
guest partitions and a host partition.
|
||||
|
||||
config NET_9P_VSOCK
|
||||
depends on NET_9P_FD
|
||||
depends on VSOCKETS
|
||||
bool "9P VSOCK Transport"
|
||||
help
|
||||
This builds support for a transport for 9pfs over
|
||||
virtual sockets (vsock). This is useful for communication
|
||||
between virtual machines and their host without requiring
|
||||
TCP/IP networking configuration or additional userspace software.
|
||||
|
||||
config NET_9P_XEN
|
||||
depends on XEN
|
||||
select XEN_XENBUS_FRONTEND
|
||||
|
|
|
|||
|
|
@ -448,6 +448,9 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|||
p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
err = -EPROTO;
|
||||
|
||||
return err;
|
||||
|
||||
out_err:
|
||||
|
|
|
|||
|
|
@ -770,7 +770,7 @@ int p9dirent_read(struct p9_client *clnt, char *buf, int len,
|
|||
{
|
||||
struct p9_fcall fake_pdu;
|
||||
int ret;
|
||||
char *nameptr;
|
||||
char *nameptr = NULL;
|
||||
|
||||
fake_pdu.size = len;
|
||||
fake_pdu.capacity = len;
|
||||
|
|
@ -785,15 +785,7 @@ int p9dirent_read(struct p9_client *clnt, char *buf, int len,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name));
|
||||
if (ret < 0) {
|
||||
p9_debug(P9_DEBUG_ERROR,
|
||||
"On the wire dirent name too long: %s\n",
|
||||
nameptr);
|
||||
kfree(nameptr);
|
||||
return ret;
|
||||
}
|
||||
kfree(nameptr);
|
||||
dirent->d_name = nameptr;
|
||||
|
||||
return fake_pdu.offset;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
#include <net/9p/9p.h>
|
||||
#include <net/9p/client.h>
|
||||
#include <net/9p/transport.h>
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
#include <uapi/linux/vm_sockets.h>
|
||||
#endif
|
||||
|
||||
#include <linux/syscalls.h> /* killme */
|
||||
|
||||
|
|
@ -36,6 +39,9 @@
|
|||
|
||||
static struct p9_trans_module p9_tcp_trans;
|
||||
static struct p9_trans_module p9_fd_trans;
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
static struct p9_trans_module p9_vsock_trans;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
Rworksched = 1, /* read work scheduled or running */
|
||||
|
|
@ -714,6 +720,12 @@ static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
|
|||
if (clnt->trans_opts.fd.wfd != ~0)
|
||||
seq_printf(m, ",wfd=%u", clnt->trans_opts.fd.wfd);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
else if (clnt->trans_mod == &p9_vsock_trans) {
|
||||
if (clnt->trans_opts.vsock.port != P9_FD_PORT)
|
||||
seq_printf(m, ",port=%u", clnt->trans_opts.vsock.port);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -875,7 +887,7 @@ p9_fd_create_tcp(struct p9_client *client, struct fs_context *fc)
|
|||
const char *addr = fc->source;
|
||||
struct v9fs_context *ctx = fc->fs_private;
|
||||
int err;
|
||||
char port_str[6];
|
||||
char port_str[11];
|
||||
struct socket *csocket;
|
||||
struct sockaddr_storage stor = { 0 };
|
||||
struct p9_fd_opts opts;
|
||||
|
|
@ -887,8 +899,8 @@ p9_fd_create_tcp(struct p9_client *client, struct fs_context *fc)
|
|||
return -EINVAL;
|
||||
|
||||
sprintf(port_str, "%u", opts.port);
|
||||
err = inet_pton_with_scope(current->nsproxy->net_ns, AF_UNSPEC, addr,
|
||||
port_str, &stor);
|
||||
err = inet_pton_with_scope(fc->net_ns, AF_UNSPEC, addr, port_str,
|
||||
&stor);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
|
@ -896,8 +908,8 @@ p9_fd_create_tcp(struct p9_client *client, struct fs_context *fc)
|
|||
|
||||
client->trans_opts.tcp.port = opts.port;
|
||||
client->trans_opts.tcp.privport = opts.privport;
|
||||
err = __sock_create(current->nsproxy->net_ns, stor.ss_family,
|
||||
SOCK_STREAM, IPPROTO_TCP, &csocket, 1);
|
||||
err = __sock_create(fc->net_ns, stor.ss_family, SOCK_STREAM,
|
||||
IPPROTO_TCP, &csocket, 1);
|
||||
if (err) {
|
||||
pr_err("%s (%d): problem creating socket\n",
|
||||
__func__, task_pid_nr(current));
|
||||
|
|
@ -946,8 +958,7 @@ p9_fd_create_unix(struct p9_client *client, struct fs_context *fc)
|
|||
__func__, task_pid_nr(current), addr);
|
||||
return -ENAMETOOLONG;
|
||||
}
|
||||
err = __sock_create(current->nsproxy->net_ns, PF_UNIX,
|
||||
SOCK_STREAM, 0, &csocket, 1);
|
||||
err = __sock_create(fc->net_ns, PF_UNIX, SOCK_STREAM, 0, &csocket, 1);
|
||||
if (err < 0) {
|
||||
pr_err("%s (%d): problem creating socket\n",
|
||||
__func__, task_pid_nr(current));
|
||||
|
|
@ -966,6 +977,67 @@ p9_fd_create_unix(struct p9_client *client, struct fs_context *fc)
|
|||
return p9_socket_open(client, csocket);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
static int
|
||||
p9_fd_create_vsock(struct p9_client *client, struct fs_context *fc)
|
||||
{
|
||||
const char *addr = fc->source;
|
||||
struct v9fs_context *ctx = fc->fs_private;
|
||||
int err;
|
||||
struct socket *csocket;
|
||||
struct sockaddr_vm addr_vm = { 0 };
|
||||
struct p9_fd_opts opts;
|
||||
unsigned int cid;
|
||||
|
||||
/* opts are already parsed in context */
|
||||
opts = ctx->fd_opts;
|
||||
|
||||
if (opts.privport) {
|
||||
// TODO: implement vsock privileged port binding
|
||||
pr_err("%s (%d): privport currently not implemented for vsock\n",
|
||||
__func__, task_pid_nr(current));
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
err = kstrtouint(addr, 10, &cid);
|
||||
if (err < 0) {
|
||||
pr_err("%s (%d): invalid CID: %s\n",
|
||||
__func__, task_pid_nr(current), addr);
|
||||
return err;
|
||||
}
|
||||
|
||||
csocket = NULL;
|
||||
|
||||
client->trans_opts.vsock.port = opts.port;
|
||||
err = __sock_create(fc->net_ns, AF_VSOCK,
|
||||
SOCK_STREAM, 0, &csocket, 1);
|
||||
if (err) {
|
||||
pr_err("%s (%d): problem creating socket\n",
|
||||
__func__, task_pid_nr(current));
|
||||
return err;
|
||||
}
|
||||
|
||||
addr_vm.svm_family = AF_VSOCK;
|
||||
addr_vm.svm_port = opts.port;
|
||||
addr_vm.svm_cid = cid;
|
||||
|
||||
err = READ_ONCE(csocket->ops)->connect(csocket,
|
||||
(struct sockaddr_unsized *)&addr_vm,
|
||||
sizeof(addr_vm), 0);
|
||||
if (err < 0) {
|
||||
pr_err("%s (%d): problem connecting socket to %s:%u\n",
|
||||
__func__, task_pid_nr(current), addr, opts.port);
|
||||
sock_release(csocket);
|
||||
return err;
|
||||
}
|
||||
|
||||
return p9_socket_open(client, csocket);
|
||||
}
|
||||
#endif /* CONFIG_NET_9P_VSOCK */
|
||||
|
||||
static int
|
||||
p9_fd_create(struct p9_client *client, struct fs_context *fc)
|
||||
{
|
||||
|
|
@ -1036,6 +1108,23 @@ static struct p9_trans_module p9_fd_trans = {
|
|||
};
|
||||
MODULE_ALIAS_9P("fd");
|
||||
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
static struct p9_trans_module p9_vsock_trans = {
|
||||
.name = "vsock",
|
||||
.maxsize = MAX_SOCK_BUF,
|
||||
.def = false,
|
||||
.supports_vmalloc = true,
|
||||
.create = p9_fd_create_vsock,
|
||||
.close = p9_fd_close,
|
||||
.request = p9_fd_request,
|
||||
.cancel = p9_fd_cancel,
|
||||
.cancelled = p9_fd_cancelled,
|
||||
.show_options = p9_fd_show_options,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
MODULE_ALIAS_9P("vsock");
|
||||
#endif
|
||||
|
||||
/**
|
||||
* p9_poll_workfn - poll worker thread
|
||||
* @work: work queue
|
||||
|
|
@ -1073,6 +1162,9 @@ static int __init p9_trans_fd_init(void)
|
|||
v9fs_register_trans(&p9_tcp_trans);
|
||||
v9fs_register_trans(&p9_unix_trans);
|
||||
v9fs_register_trans(&p9_fd_trans);
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
v9fs_register_trans(&p9_vsock_trans);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1083,6 +1175,9 @@ static void __exit p9_trans_fd_exit(void)
|
|||
v9fs_unregister_trans(&p9_tcp_trans);
|
||||
v9fs_unregister_trans(&p9_unix_trans);
|
||||
v9fs_unregister_trans(&p9_fd_trans);
|
||||
#if IS_ENABLED(CONFIG_NET_9P_VSOCK)
|
||||
v9fs_unregister_trans(&p9_vsock_trans);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(p9_trans_fd_init);
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ rdma_create_trans(struct p9_client *client, struct fs_context *fc)
|
|||
return -ENOMEM;
|
||||
|
||||
/* Create the RDMA CM ID */
|
||||
rdma->cm_id = rdma_create_id(&init_net, p9_cm_event_handler, client,
|
||||
rdma->cm_id = rdma_create_id(fc->net_ns, p9_cm_event_handler, client,
|
||||
RDMA_PS_TCP, IB_QPT_RC);
|
||||
if (IS_ERR(rdma->cm_id))
|
||||
goto error;
|
||||
|
|
|
|||
|
|
@ -149,7 +149,8 @@ static void usb9pfs_tx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
{
|
||||
struct f_usb9pfs *usb9pfs = ep->driver_data;
|
||||
struct usb_composite_dev *cdev = usb9pfs->function.config->cdev;
|
||||
struct p9_req_t *p9_tx_req = req->context;
|
||||
struct p9_client *client;
|
||||
struct p9_req_t *p9_tx_req;
|
||||
unsigned long flags;
|
||||
|
||||
/* reset zero packages */
|
||||
|
|
@ -165,18 +166,25 @@ static void usb9pfs_tx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
ep->name, req->status, req->actual, req->length);
|
||||
|
||||
spin_lock_irqsave(&usb9pfs->lock, flags);
|
||||
WRITE_ONCE(p9_tx_req->status, REQ_STATUS_SENT);
|
||||
|
||||
p9_req_put(usb9pfs->client, p9_tx_req);
|
||||
|
||||
client = usb9pfs->client;
|
||||
p9_tx_req = req->context;
|
||||
req->context = NULL;
|
||||
|
||||
if (!client || !p9_tx_req)
|
||||
goto unlock_complete;
|
||||
|
||||
WRITE_ONCE(p9_tx_req->status, REQ_STATUS_SENT);
|
||||
|
||||
p9_req_put(client, p9_tx_req);
|
||||
|
||||
unlock_complete:
|
||||
spin_unlock_irqrestore(&usb9pfs->lock, flags);
|
||||
|
||||
complete(&usb9pfs->send);
|
||||
}
|
||||
|
||||
static struct p9_req_t *usb9pfs_rx_header(struct f_usb9pfs *usb9pfs, void *buf)
|
||||
static struct p9_req_t *usb9pfs_rx_header(struct f_usb9pfs *usb9pfs,
|
||||
struct p9_client *client, void *buf)
|
||||
{
|
||||
struct p9_req_t *p9_rx_req;
|
||||
struct p9_fcall rc;
|
||||
|
|
@ -202,7 +210,7 @@ static struct p9_req_t *usb9pfs_rx_header(struct f_usb9pfs *usb9pfs, void *buf)
|
|||
"mux %p pkt: size: %d bytes tag: %d\n",
|
||||
usb9pfs, rc.size, rc.tag);
|
||||
|
||||
p9_rx_req = p9_tag_lookup(usb9pfs->client, rc.tag);
|
||||
p9_rx_req = p9_tag_lookup(client, rc.tag);
|
||||
if (!p9_rx_req || p9_rx_req->status != REQ_STATUS_SENT) {
|
||||
p9_debug(P9_DEBUG_ERROR, "Unexpected packet tag %d\n", rc.tag);
|
||||
return NULL;
|
||||
|
|
@ -212,7 +220,7 @@ static struct p9_req_t *usb9pfs_rx_header(struct f_usb9pfs *usb9pfs, void *buf)
|
|||
p9_debug(P9_DEBUG_ERROR,
|
||||
"requested packet size too big: %d for tag %d with capacity %zd\n",
|
||||
rc.size, rc.tag, p9_rx_req->rc.capacity);
|
||||
p9_req_put(usb9pfs->client, p9_rx_req);
|
||||
p9_req_put(client, p9_rx_req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +228,7 @@ static struct p9_req_t *usb9pfs_rx_header(struct f_usb9pfs *usb9pfs, void *buf)
|
|||
p9_debug(P9_DEBUG_ERROR,
|
||||
"No recv fcall for tag %d (req %p), disconnecting!\n",
|
||||
rc.tag, p9_rx_req);
|
||||
p9_req_put(usb9pfs->client, p9_rx_req);
|
||||
p9_req_put(client, p9_rx_req);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -231,8 +239,10 @@ static void usb9pfs_rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
{
|
||||
struct f_usb9pfs *usb9pfs = ep->driver_data;
|
||||
struct usb_composite_dev *cdev = usb9pfs->function.config->cdev;
|
||||
struct p9_client *client;
|
||||
struct p9_req_t *p9_rx_req;
|
||||
unsigned int req_size = req->actual;
|
||||
unsigned long flags;
|
||||
int status = REQ_STATUS_RCVD;
|
||||
|
||||
if (req->status) {
|
||||
|
|
@ -241,9 +251,16 @@ static void usb9pfs_rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
return;
|
||||
}
|
||||
|
||||
p9_rx_req = usb9pfs_rx_header(usb9pfs, req->buf);
|
||||
if (!p9_rx_req)
|
||||
spin_lock_irqsave(&usb9pfs->lock, flags);
|
||||
client = usb9pfs->client;
|
||||
if (!client) {
|
||||
spin_unlock_irqrestore(&usb9pfs->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
p9_rx_req = usb9pfs_rx_header(usb9pfs, client, req->buf);
|
||||
if (!p9_rx_req)
|
||||
goto out_unlock;
|
||||
|
||||
if (req_size > p9_rx_req->rc.capacity) {
|
||||
dev_err(&cdev->gadget->dev,
|
||||
|
|
@ -257,8 +274,11 @@ static void usb9pfs_rx_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
|
||||
p9_rx_req->rc.size = req_size;
|
||||
|
||||
p9_client_cb(usb9pfs->client, p9_rx_req, status);
|
||||
p9_req_put(usb9pfs->client, p9_rx_req);
|
||||
p9_client_cb(client, p9_rx_req, status);
|
||||
p9_req_put(client, p9_rx_req);
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&usb9pfs->lock, flags);
|
||||
|
||||
complete(&usb9pfs->received);
|
||||
}
|
||||
|
|
@ -278,18 +298,18 @@ static void disable_usb9pfs(struct f_usb9pfs *usb9pfs)
|
|||
struct usb_composite_dev *cdev =
|
||||
usb9pfs->function.config->cdev;
|
||||
|
||||
disable_ep(cdev, usb9pfs->in_ep);
|
||||
disable_ep(cdev, usb9pfs->out_ep);
|
||||
|
||||
if (usb9pfs->in_req) {
|
||||
usb_ep_free_request(usb9pfs->in_ep, usb9pfs->in_req);
|
||||
usb9pfs->in_req = NULL;
|
||||
}
|
||||
|
||||
if (usb9pfs->out_req) {
|
||||
usb_ep_free_request(usb9pfs->out_ep, usb9pfs->out_req);
|
||||
free_ep_req(usb9pfs->out_ep, usb9pfs->out_req);
|
||||
usb9pfs->out_req = NULL;
|
||||
}
|
||||
|
||||
disable_ep(cdev, usb9pfs->in_ep);
|
||||
disable_ep(cdev, usb9pfs->out_ep);
|
||||
dev_dbg(&cdev->gadget->dev, "%s disabled\n",
|
||||
usb9pfs->function.name);
|
||||
}
|
||||
|
|
@ -314,10 +334,6 @@ static int alloc_requests(struct usb_composite_dev *cdev,
|
|||
usb9pfs->in_req->complete = usb9pfs_tx_complete;
|
||||
usb9pfs->out_req->complete = usb9pfs_rx_complete;
|
||||
|
||||
/* length will be set in complete routine */
|
||||
usb9pfs->in_req->context = usb9pfs;
|
||||
usb9pfs->out_req->context = usb9pfs;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_in:
|
||||
|
|
@ -391,7 +407,7 @@ static int p9_usbg_create(struct p9_client *client, struct fs_context *fc)
|
|||
guard(mutex)(&usb9pfs_lock);
|
||||
|
||||
list_for_each_entry(dev, &usbg_instance_list, usb9pfs_instance) {
|
||||
if (!strncmp(devname, dev->tag, strlen(devname))) {
|
||||
if (!strcmp(devname, dev->tag)) {
|
||||
if (!dev->inuse) {
|
||||
dev->inuse = true;
|
||||
found = 1;
|
||||
|
|
@ -416,7 +432,9 @@ static int p9_usbg_create(struct p9_client *client, struct fs_context *fc)
|
|||
client->status = Disconnected;
|
||||
else
|
||||
client->status = Connected;
|
||||
spin_lock_irq(&usb9pfs->lock);
|
||||
usb9pfs->client = client;
|
||||
spin_unlock_irq(&usb9pfs->lock);
|
||||
|
||||
client->trans_mod->maxsize = usb9pfs->buflen;
|
||||
|
||||
|
|
@ -427,18 +445,31 @@ static int p9_usbg_create(struct p9_client *client, struct fs_context *fc)
|
|||
|
||||
static void usb9pfs_clear_tx(struct f_usb9pfs *usb9pfs)
|
||||
{
|
||||
struct p9_client *client;
|
||||
struct p9_req_t *req;
|
||||
unsigned long flags;
|
||||
|
||||
guard(spinlock_irqsave)(&usb9pfs->lock);
|
||||
spin_lock_irqsave(&usb9pfs->lock, flags);
|
||||
client = usb9pfs->client;
|
||||
usb9pfs->client = NULL;
|
||||
req = usb9pfs->in_req ? usb9pfs->in_req->context : NULL;
|
||||
if (usb9pfs->in_req)
|
||||
usb9pfs->in_req->context = NULL;
|
||||
spin_unlock_irqrestore(&usb9pfs->lock, flags);
|
||||
|
||||
req = usb9pfs->in_req->context;
|
||||
if (!req)
|
||||
if (!req || !client)
|
||||
return;
|
||||
|
||||
usb9pfs->in_req->context = NULL;
|
||||
|
||||
if (!usb9pfs->client)
|
||||
return;
|
||||
|
||||
if (!req->t_err)
|
||||
req->t_err = -ECONNRESET;
|
||||
|
||||
p9_client_cb(usb9pfs->client, req, REQ_STATUS_ERROR);
|
||||
p9_client_cb(client, req, REQ_STATUS_ERROR);
|
||||
usb9pfs->in_req->context = NULL;
|
||||
}
|
||||
|
||||
static void p9_usbg_close(struct p9_client *client)
|
||||
|
|
@ -457,6 +488,7 @@ static void p9_usbg_close(struct p9_client *client)
|
|||
client->status = Disconnected;
|
||||
|
||||
usb9pfs_clear_tx(usb9pfs);
|
||||
usb9pfs->client = NULL;
|
||||
|
||||
opts = container_of(usb9pfs->function.fi,
|
||||
struct f_usb9pfs_opts, func_inst);
|
||||
|
|
@ -466,6 +498,9 @@ static void p9_usbg_close(struct p9_client *client)
|
|||
mutex_lock(&usb9pfs_lock);
|
||||
dev->inuse = false;
|
||||
mutex_unlock(&usb9pfs_lock);
|
||||
|
||||
disable_usb9pfs(usb9pfs);
|
||||
reinit_completion(&usb9pfs->send);
|
||||
}
|
||||
|
||||
static int p9_usbg_request(struct p9_client *client, struct p9_req_t *p9_req)
|
||||
|
|
@ -725,8 +760,6 @@ static void usb9pfs_free_func(struct usb_function *f)
|
|||
struct f_usb9pfs *usb9pfs = func_to_usb9pfs(f);
|
||||
struct f_usb9pfs_opts *opts;
|
||||
|
||||
kfree(usb9pfs);
|
||||
|
||||
opts = container_of(f->fi, struct f_usb9pfs_opts, func_inst);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
|
|
@ -734,6 +767,8 @@ static void usb9pfs_free_func(struct usb_function *f)
|
|||
mutex_unlock(&opts->lock);
|
||||
|
||||
usb_free_all_descriptors(f);
|
||||
|
||||
kfree(usb9pfs);
|
||||
}
|
||||
|
||||
static int usb9pfs_set_alt(struct usb_function *f,
|
||||
|
|
@ -748,8 +783,18 @@ static int usb9pfs_set_alt(struct usb_function *f,
|
|||
static void usb9pfs_disable(struct usb_function *f)
|
||||
{
|
||||
struct f_usb9pfs *usb9pfs = func_to_usb9pfs(f);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&usb9pfs->lock, flags);
|
||||
if (usb9pfs->client)
|
||||
usb9pfs->client->status = Disconnected;
|
||||
spin_unlock_irqrestore(&usb9pfs->lock, flags);
|
||||
usb9pfs_clear_tx(usb9pfs);
|
||||
|
||||
if (usb9pfs->in_ep->enabled)
|
||||
disable_usb9pfs(usb9pfs);
|
||||
|
||||
reinit_completion(&usb9pfs->send);
|
||||
}
|
||||
|
||||
static struct usb_function *usb9pfs_alloc(struct usb_function_instance *fi)
|
||||
|
|
|
|||
|
|
@ -633,6 +633,11 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|||
err = -EINVAL;
|
||||
goto out_free_vq;
|
||||
}
|
||||
if (tag_len > NAME_MAX) {
|
||||
dev_err(&vdev->dev, "mount tag too long (%u bytes)\n", tag_len);
|
||||
err = -EINVAL;
|
||||
goto out_free_vq;
|
||||
}
|
||||
tag = kzalloc(tag_len + 1, GFP_KERNEL);
|
||||
if (!tag) {
|
||||
err = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ struct xen_9pfs_front_priv {
|
|||
char *tag;
|
||||
struct p9_client *client;
|
||||
|
||||
struct xen_9pfs_dataring *rings;
|
||||
struct xen_9pfs_dataring rings[XEN_9PFS_NUM_RINGS];
|
||||
};
|
||||
|
||||
static LIST_HEAD(xen_9pfs_devs);
|
||||
|
|
@ -200,9 +200,19 @@ static void p9_xen_response(struct work_struct *work)
|
|||
masked_prod, &masked_cons,
|
||||
XEN_9PFS_RING_SIZE(ring));
|
||||
|
||||
if (h.size < sizeof(h) ||
|
||||
h.size > xen_9pfs_queued(prod, cons,
|
||||
XEN_9PFS_RING_SIZE(ring))) {
|
||||
dev_warn_ratelimited(&priv->dev->dev,
|
||||
"bad response size %u from backend\n", h.size);
|
||||
break;
|
||||
}
|
||||
|
||||
req = p9_tag_lookup(priv->client, h.tag);
|
||||
if (!req || req->status != REQ_STATUS_SENT) {
|
||||
dev_warn(&priv->dev->dev, "Wrong req tag=%x\n", h.tag);
|
||||
if (req)
|
||||
p9_req_put(priv->client, req);
|
||||
cons += h.size;
|
||||
virt_mb();
|
||||
ring->intf->in_cons = cons;
|
||||
|
|
@ -277,41 +287,37 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
|
|||
{
|
||||
int i, j;
|
||||
|
||||
if (priv->rings) {
|
||||
for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
|
||||
struct xen_9pfs_dataring *ring = &priv->rings[i];
|
||||
for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
|
||||
struct xen_9pfs_dataring *ring = &priv->rings[i];
|
||||
|
||||
cancel_work_sync(&ring->work);
|
||||
|
||||
if (!ring->intf)
|
||||
break;
|
||||
if (ring->irq >= 0) {
|
||||
unbind_from_irqhandler(ring->irq, ring);
|
||||
ring->irq = -1;
|
||||
}
|
||||
if (ring->data.in) {
|
||||
for (j = 0; j < (1 << ring->intf->ring_order);
|
||||
j++) {
|
||||
grant_ref_t ref;
|
||||
|
||||
ref = ring->intf->ref[j];
|
||||
gnttab_end_foreign_access(ref, NULL);
|
||||
ring->intf->ref[j] = INVALID_GRANT_REF;
|
||||
}
|
||||
free_pages_exact(ring->data.in,
|
||||
1UL << (ring->intf->ring_order +
|
||||
XEN_PAGE_SHIFT));
|
||||
ring->data.in = NULL;
|
||||
ring->data.out = NULL;
|
||||
}
|
||||
if (ring->ref != INVALID_GRANT_REF) {
|
||||
gnttab_end_foreign_access(ring->ref, NULL);
|
||||
ring->ref = INVALID_GRANT_REF;
|
||||
}
|
||||
free_page((unsigned long)ring->intf);
|
||||
ring->intf = NULL;
|
||||
if (!ring->intf)
|
||||
break;
|
||||
if (ring->irq >= 0) {
|
||||
unbind_from_irqhandler(ring->irq, ring);
|
||||
ring->irq = -1;
|
||||
}
|
||||
kfree(priv->rings);
|
||||
cancel_work_sync(&ring->work);
|
||||
|
||||
if (ring->data.in) {
|
||||
for (j = 0; j < (1 << ring->intf->ring_order); j++) {
|
||||
grant_ref_t ref;
|
||||
|
||||
ref = ring->intf->ref[j];
|
||||
gnttab_end_foreign_access(ref, NULL);
|
||||
ring->intf->ref[j] = INVALID_GRANT_REF;
|
||||
}
|
||||
free_pages_exact(ring->data.in,
|
||||
1UL << (ring->intf->ring_order +
|
||||
XEN_PAGE_SHIFT));
|
||||
ring->data.in = NULL;
|
||||
ring->data.out = NULL;
|
||||
}
|
||||
if (ring->ref != INVALID_GRANT_REF) {
|
||||
gnttab_end_foreign_access(ring->ref, NULL);
|
||||
ring->ref = INVALID_GRANT_REF;
|
||||
}
|
||||
free_page((unsigned long)ring->intf);
|
||||
ring->intf = NULL;
|
||||
}
|
||||
kfree(priv->tag);
|
||||
kfree(priv);
|
||||
|
|
@ -450,11 +456,6 @@ static int xen_9pfs_front_init(struct xenbus_device *dev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
priv->dev = dev;
|
||||
priv->rings = kzalloc_objs(*priv->rings, XEN_9PFS_NUM_RINGS);
|
||||
if (!priv->rings) {
|
||||
kfree(priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < XEN_9PFS_NUM_RINGS; i++) {
|
||||
priv->rings[i].priv = priv;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user