Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: fs/9p: Add hardlink support to .u extension 9P2010.L handshake: .L protocol negotiation 9P2010.L handshake: Remove "dotu" variable 9P2010.L handshake: Add mount option 9P2010.L handshake: Add VFS flags net/9p: Handle mount errors correctly. net/9p: Remove MAX_9P_CHAN limit net/9p: Add multi channel support.
This commit is contained in:
commit
b13d3c6e8a
|
@ -151,7 +151,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
|
||||||
if (access == V9FS_ACCESS_SINGLE)
|
if (access == V9FS_ACCESS_SINGLE)
|
||||||
return ERR_PTR(-EPERM);
|
return ERR_PTR(-EPERM);
|
||||||
|
|
||||||
if (v9fs_extended(v9ses))
|
if (v9fs_proto_dotu(v9ses))
|
||||||
uname = NULL;
|
uname = NULL;
|
||||||
else
|
else
|
||||||
uname = v9ses->uname;
|
uname = v9ses->uname;
|
||||||
|
|
|
@ -241,7 +241,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
||||||
list_add(&v9ses->slist, &v9fs_sessionlist);
|
list_add(&v9ses->slist, &v9fs_sessionlist);
|
||||||
spin_unlock(&v9fs_sessionlist_lock);
|
spin_unlock(&v9fs_sessionlist_lock);
|
||||||
|
|
||||||
v9ses->flags = V9FS_EXTENDED | V9FS_ACCESS_USER;
|
v9ses->flags = V9FS_PROTO_2000U | V9FS_ACCESS_USER;
|
||||||
strcpy(v9ses->uname, V9FS_DEFUSER);
|
strcpy(v9ses->uname, V9FS_DEFUSER);
|
||||||
strcpy(v9ses->aname, V9FS_DEFANAME);
|
strcpy(v9ses->aname, V9FS_DEFANAME);
|
||||||
v9ses->uid = ~0;
|
v9ses->uid = ~0;
|
||||||
|
@ -262,13 +262,13 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!v9ses->clnt->dotu)
|
if (!p9_is_proto_dotu(v9ses->clnt))
|
||||||
v9ses->flags &= ~V9FS_EXTENDED;
|
v9ses->flags &= ~V9FS_PROTO_2000U;
|
||||||
|
|
||||||
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
|
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
|
||||||
|
|
||||||
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
|
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
|
||||||
if (!v9fs_extended(v9ses) &&
|
if (!v9fs_proto_dotu(v9ses) &&
|
||||||
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
|
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
|
||||||
|
|
||||||
v9ses->flags &= ~V9FS_ACCESS_MASK;
|
v9ses->flags &= ~V9FS_ACCESS_MASK;
|
||||||
|
|
23
fs/9p/v9fs.h
23
fs/9p/v9fs.h
|
@ -23,7 +23,8 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum p9_session_flags - option flags for each 9P session
|
* enum p9_session_flags - option flags for each 9P session
|
||||||
* @V9FS_EXTENDED: whether or not to use 9P2000.u extensions
|
* @V9FS_PROTO_2000U: whether or not to use 9P2000.u extensions
|
||||||
|
* @V9FS_PROTO_2010L: whether or not to use 9P2010.l extensions
|
||||||
* @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
|
* @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_USER: a new attach will be issued for every user (default)
|
||||||
* @V9FS_ACCESS_ANY: use a single attach for all users
|
* @V9FS_ACCESS_ANY: use a single attach for all users
|
||||||
|
@ -32,11 +33,12 @@
|
||||||
* Session flags reflect options selected by users at mount time
|
* Session flags reflect options selected by users at mount time
|
||||||
*/
|
*/
|
||||||
enum p9_session_flags {
|
enum p9_session_flags {
|
||||||
V9FS_EXTENDED = 0x01,
|
V9FS_PROTO_2000U = 0x01,
|
||||||
V9FS_ACCESS_SINGLE = 0x02,
|
V9FS_PROTO_2010L = 0x02,
|
||||||
V9FS_ACCESS_USER = 0x04,
|
V9FS_ACCESS_SINGLE = 0x04,
|
||||||
V9FS_ACCESS_ANY = 0x06,
|
V9FS_ACCESS_USER = 0x08,
|
||||||
V9FS_ACCESS_MASK = 0x06,
|
V9FS_ACCESS_ANY = 0x0C,
|
||||||
|
V9FS_ACCESS_MASK = 0x0C,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* possible values of ->cache */
|
/* possible values of ->cache */
|
||||||
|
@ -121,7 +123,12 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
|
||||||
return (inode->i_sb->s_fs_info);
|
return (inode->i_sb->s_fs_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int v9fs_extended(struct v9fs_session_info *v9ses)
|
static inline int v9fs_proto_dotu(struct v9fs_session_info *v9ses)
|
||||||
{
|
{
|
||||||
return v9ses->flags & V9FS_EXTENDED;
|
return v9ses->flags & V9FS_PROTO_2000U;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses)
|
||||||
|
{
|
||||||
|
return v9ses->flags & V9FS_PROTO_2010L;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||||
while (rdir->head < rdir->tail) {
|
while (rdir->head < rdir->tail) {
|
||||||
err = p9stat_read(rdir->buf + rdir->head,
|
err = p9stat_read(rdir->buf + rdir->head,
|
||||||
buflen - rdir->head, &st,
|
buflen - rdir->head, &st,
|
||||||
fid->clnt->dotu);
|
fid->clnt->proto_version);
|
||||||
if (err) {
|
if (err) {
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
|
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
|
|
@ -61,7 +61,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
|
P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
|
||||||
v9ses = v9fs_inode2v9ses(inode);
|
v9ses = v9fs_inode2v9ses(inode);
|
||||||
omode = v9fs_uflags2omode(file->f_flags, v9fs_extended(v9ses));
|
omode = v9fs_uflags2omode(file->f_flags, v9fs_proto_dotu(v9ses));
|
||||||
fid = file->private_data;
|
fid = file->private_data;
|
||||||
if (!fid) {
|
if (!fid) {
|
||||||
fid = v9fs_fid_clone(file->f_path.dentry);
|
fid = v9fs_fid_clone(file->f_path.dentry);
|
||||||
|
@ -77,7 +77,7 @@ int v9fs_file_open(struct inode *inode, struct file *file)
|
||||||
i_size_write(inode, 0);
|
i_size_write(inode, 0);
|
||||||
inode->i_blocks = 0;
|
inode->i_blocks = 0;
|
||||||
}
|
}
|
||||||
if ((file->f_flags & O_APPEND) && (!v9fs_extended(v9ses)))
|
if ((file->f_flags & O_APPEND) && (!v9fs_proto_dotu(v9ses)))
|
||||||
generic_file_llseek(file, 0, SEEK_END);
|
generic_file_llseek(file, 0, SEEK_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
|
||||||
res = mode & 0777;
|
res = mode & 0777;
|
||||||
if (S_ISDIR(mode))
|
if (S_ISDIR(mode))
|
||||||
res |= P9_DMDIR;
|
res |= P9_DMDIR;
|
||||||
if (v9fs_extended(v9ses)) {
|
if (v9fs_proto_dotu(v9ses)) {
|
||||||
if (S_ISLNK(mode))
|
if (S_ISLNK(mode))
|
||||||
res |= P9_DMSYMLINK;
|
res |= P9_DMSYMLINK;
|
||||||
if (v9ses->nodev == 0) {
|
if (v9ses->nodev == 0) {
|
||||||
|
@ -102,21 +102,21 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
|
||||||
|
|
||||||
if ((mode & P9_DMDIR) == P9_DMDIR)
|
if ((mode & P9_DMDIR) == P9_DMDIR)
|
||||||
res |= S_IFDIR;
|
res |= S_IFDIR;
|
||||||
else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses)))
|
else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))
|
||||||
res |= S_IFLNK;
|
res |= S_IFLNK;
|
||||||
else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses))
|
else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))
|
||||||
&& (v9ses->nodev == 0))
|
&& (v9ses->nodev == 0))
|
||||||
res |= S_IFSOCK;
|
res |= S_IFSOCK;
|
||||||
else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses))
|
else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))
|
||||||
&& (v9ses->nodev == 0))
|
&& (v9ses->nodev == 0))
|
||||||
res |= S_IFIFO;
|
res |= S_IFIFO;
|
||||||
else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses))
|
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
|
||||||
&& (v9ses->nodev == 0))
|
&& (v9ses->nodev == 0))
|
||||||
res |= S_IFBLK;
|
res |= S_IFBLK;
|
||||||
else
|
else
|
||||||
res |= S_IFREG;
|
res |= S_IFREG;
|
||||||
|
|
||||||
if (v9fs_extended(v9ses)) {
|
if (v9fs_proto_dotu(v9ses)) {
|
||||||
if ((mode & P9_DMSETUID) == P9_DMSETUID)
|
if ((mode & P9_DMSETUID) == P9_DMSETUID)
|
||||||
res |= S_ISUID;
|
res |= S_ISUID;
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
||||||
case S_IFBLK:
|
case S_IFBLK:
|
||||||
case S_IFCHR:
|
case S_IFCHR:
|
||||||
case S_IFSOCK:
|
case S_IFSOCK:
|
||||||
if (!v9fs_extended(v9ses)) {
|
if (!v9fs_proto_dotu(v9ses)) {
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||||
"special files without extended mode\n");
|
"special files without extended mode\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
@ -278,7 +278,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
||||||
inode->i_fop = &v9fs_file_operations;
|
inode->i_fop = &v9fs_file_operations;
|
||||||
break;
|
break;
|
||||||
case S_IFLNK:
|
case S_IFLNK:
|
||||||
if (!v9fs_extended(v9ses)) {
|
if (!v9fs_proto_dotu(v9ses)) {
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||||
"extended modes used w/o 9P2000.u\n");
|
"extended modes used w/o 9P2000.u\n");
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
@ -288,7 +288,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
||||||
break;
|
break;
|
||||||
case S_IFDIR:
|
case S_IFDIR:
|
||||||
inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
if (v9fs_extended(v9ses))
|
if (v9fs_proto_dotu(v9ses))
|
||||||
inode->i_op = &v9fs_dir_inode_operations_ext;
|
inode->i_op = &v9fs_dir_inode_operations_ext;
|
||||||
else
|
else
|
||||||
inode->i_op = &v9fs_dir_inode_operations;
|
inode->i_op = &v9fs_dir_inode_operations;
|
||||||
|
@ -575,7 +575,8 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
||||||
flags = O_RDWR;
|
flags = O_RDWR;
|
||||||
|
|
||||||
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
|
||||||
v9fs_uflags2omode(flags, v9fs_extended(v9ses)));
|
v9fs_uflags2omode(flags,
|
||||||
|
v9fs_proto_dotu(v9ses)));
|
||||||
if (IS_ERR(fid)) {
|
if (IS_ERR(fid)) {
|
||||||
err = PTR_ERR(fid);
|
err = PTR_ERR(fid);
|
||||||
fid = NULL;
|
fid = NULL;
|
||||||
|
@ -858,7 +859,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
||||||
if (iattr->ia_valid & ATTR_SIZE)
|
if (iattr->ia_valid & ATTR_SIZE)
|
||||||
wstat.length = iattr->ia_size;
|
wstat.length = iattr->ia_size;
|
||||||
|
|
||||||
if (v9fs_extended(v9ses)) {
|
if (v9fs_proto_dotu(v9ses)) {
|
||||||
if (iattr->ia_valid & ATTR_UID)
|
if (iattr->ia_valid & ATTR_UID)
|
||||||
wstat.n_uid = iattr->ia_uid;
|
wstat.n_uid = iattr->ia_uid;
|
||||||
|
|
||||||
|
@ -886,6 +887,8 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
|
||||||
struct super_block *sb)
|
struct super_block *sb)
|
||||||
{
|
{
|
||||||
char ext[32];
|
char ext[32];
|
||||||
|
char tag_name[14];
|
||||||
|
unsigned int i_nlink;
|
||||||
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
||||||
|
|
||||||
inode->i_nlink = 1;
|
inode->i_nlink = 1;
|
||||||
|
@ -897,11 +900,26 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
|
||||||
inode->i_uid = v9ses->dfltuid;
|
inode->i_uid = v9ses->dfltuid;
|
||||||
inode->i_gid = v9ses->dfltgid;
|
inode->i_gid = v9ses->dfltgid;
|
||||||
|
|
||||||
if (v9fs_extended(v9ses)) {
|
if (v9fs_proto_dotu(v9ses)) {
|
||||||
inode->i_uid = stat->n_uid;
|
inode->i_uid = stat->n_uid;
|
||||||
inode->i_gid = stat->n_gid;
|
inode->i_gid = stat->n_gid;
|
||||||
}
|
}
|
||||||
|
if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {
|
||||||
|
if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) {
|
||||||
|
/*
|
||||||
|
* Hadlink support got added later to
|
||||||
|
* to the .u extension. So there can be
|
||||||
|
* server out there that doesn't support
|
||||||
|
* this even with .u extension. So check
|
||||||
|
* for non NULL stat->extension
|
||||||
|
*/
|
||||||
|
strncpy(ext, stat->extension, sizeof(ext));
|
||||||
|
/* HARDLINKCOUNT %u */
|
||||||
|
sscanf(ext, "%13s %u", tag_name, &i_nlink);
|
||||||
|
if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
|
||||||
|
inode->i_nlink = i_nlink;
|
||||||
|
}
|
||||||
|
}
|
||||||
inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
|
inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
|
||||||
if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
|
if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
|
||||||
char type = 0;
|
char type = 0;
|
||||||
|
@ -976,7 +994,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
|
||||||
if (IS_ERR(fid))
|
if (IS_ERR(fid))
|
||||||
return PTR_ERR(fid);
|
return PTR_ERR(fid);
|
||||||
|
|
||||||
if (!v9fs_extended(v9ses))
|
if (!v9fs_proto_dotu(v9ses))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
st = p9_client_stat(fid);
|
st = p9_client_stat(fid);
|
||||||
|
@ -1066,7 +1084,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
|
|
||||||
v9ses = v9fs_inode2v9ses(dir);
|
v9ses = v9fs_inode2v9ses(dir);
|
||||||
if (!v9fs_extended(v9ses)) {
|
if (!v9fs_proto_dotu(v9ses)) {
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
|
P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,4 @@
|
||||||
#include <linux/virtio_ids.h>
|
#include <linux/virtio_ids.h>
|
||||||
#include <linux/virtio_config.h>
|
#include <linux/virtio_config.h>
|
||||||
|
|
||||||
/* Maximum number of virtio channels per partition (1 for now) */
|
|
||||||
#define MAX_9P_CHAN 1
|
|
||||||
|
|
||||||
#endif /* _LINUX_VIRTIO_9P_H */
|
#endif /* _LINUX_VIRTIO_9P_H */
|
||||||
|
|
|
@ -29,6 +29,19 @@
|
||||||
/* Number of requests per row */
|
/* Number of requests per row */
|
||||||
#define P9_ROW_MAXTAG 255
|
#define P9_ROW_MAXTAG 255
|
||||||
|
|
||||||
|
/** enum p9_proto_versions - 9P protocol versions
|
||||||
|
* @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u
|
||||||
|
* @p9_proto_2000u: 9P2000.u extension
|
||||||
|
* @p9_proto_2010L: 9P2010.L extension
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum p9_proto_versions{
|
||||||
|
p9_proto_legacy = 0,
|
||||||
|
p9_proto_2000u = 1,
|
||||||
|
p9_proto_2010L = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum p9_trans_status - different states of underlying transports
|
* enum p9_trans_status - different states of underlying transports
|
||||||
* @Connected: transport is connected and healthy
|
* @Connected: transport is connected and healthy
|
||||||
|
@ -111,6 +124,7 @@ struct p9_req_t {
|
||||||
* @lock: protect @fidlist
|
* @lock: protect @fidlist
|
||||||
* @msize: maximum data size negotiated by protocol
|
* @msize: maximum data size negotiated by protocol
|
||||||
* @dotu: extension flags negotiated by protocol
|
* @dotu: extension flags negotiated by protocol
|
||||||
|
* @proto_version: 9P protocol version to use
|
||||||
* @trans_mod: module API instantiated with this client
|
* @trans_mod: module API instantiated with this client
|
||||||
* @trans: tranport instance state and API
|
* @trans: tranport instance state and API
|
||||||
* @conn: connection state information used by trans_fd
|
* @conn: connection state information used by trans_fd
|
||||||
|
@ -137,7 +151,7 @@ struct p9_req_t {
|
||||||
struct p9_client {
|
struct p9_client {
|
||||||
spinlock_t lock; /* protect client structure */
|
spinlock_t lock; /* protect client structure */
|
||||||
int msize;
|
int msize;
|
||||||
unsigned char dotu;
|
unsigned char proto_version;
|
||||||
struct p9_trans_module *trans_mod;
|
struct p9_trans_module *trans_mod;
|
||||||
enum p9_trans_status status;
|
enum p9_trans_status status;
|
||||||
void *trans;
|
void *trans;
|
||||||
|
@ -209,5 +223,7 @@ int p9_parse_header(struct p9_fcall *, int32_t *, int8_t *, int16_t *, int);
|
||||||
int p9stat_read(char *, int, struct p9_wstat *, int);
|
int p9stat_read(char *, int, struct p9_wstat *, int);
|
||||||
void p9stat_free(struct p9_wstat *);
|
void p9stat_free(struct p9_wstat *);
|
||||||
|
|
||||||
|
int p9_is_proto_dotu(struct p9_client *clnt);
|
||||||
|
int p9_is_proto_dotl(struct p9_client *clnt);
|
||||||
|
|
||||||
#endif /* NET_9P_CLIENT_H */
|
#endif /* NET_9P_CLIENT_H */
|
||||||
|
|
114
net/9p/client.c
114
net/9p/client.c
|
@ -46,6 +46,7 @@ enum {
|
||||||
Opt_msize,
|
Opt_msize,
|
||||||
Opt_trans,
|
Opt_trans,
|
||||||
Opt_legacy,
|
Opt_legacy,
|
||||||
|
Opt_version,
|
||||||
Opt_err,
|
Opt_err,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,9 +54,42 @@ static const match_table_t tokens = {
|
||||||
{Opt_msize, "msize=%u"},
|
{Opt_msize, "msize=%u"},
|
||||||
{Opt_legacy, "noextend"},
|
{Opt_legacy, "noextend"},
|
||||||
{Opt_trans, "trans=%s"},
|
{Opt_trans, "trans=%s"},
|
||||||
|
{Opt_version, "version=%s"},
|
||||||
{Opt_err, NULL},
|
{Opt_err, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline int p9_is_proto_dotl(struct p9_client *clnt)
|
||||||
|
{
|
||||||
|
return (clnt->proto_version == p9_proto_2010L);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_is_proto_dotl);
|
||||||
|
|
||||||
|
inline int p9_is_proto_dotu(struct p9_client *clnt)
|
||||||
|
{
|
||||||
|
return (clnt->proto_version == p9_proto_2000u);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_is_proto_dotu);
|
||||||
|
|
||||||
|
/* Interpret mount option for protocol version */
|
||||||
|
static unsigned char get_protocol_version(const substring_t *name)
|
||||||
|
{
|
||||||
|
unsigned char version = -EINVAL;
|
||||||
|
if (!strncmp("9p2000", name->from, name->to-name->from)) {
|
||||||
|
version = p9_proto_legacy;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n");
|
||||||
|
} else if (!strncmp("9p2000.u", name->from, name->to-name->from)) {
|
||||||
|
version = p9_proto_2000u;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
|
||||||
|
} else if (!strncmp("9p2010.L", name->from, name->to-name->from)) {
|
||||||
|
version = p9_proto_2010L;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "Protocol version: 9P2010.L\n");
|
||||||
|
} else {
|
||||||
|
P9_DPRINTK(P9_DEBUG_ERROR, "Unknown protocol version %s. ",
|
||||||
|
name->from);
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
static struct p9_req_t *
|
static struct p9_req_t *
|
||||||
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
|
p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
|
||||||
|
|
||||||
|
@ -75,7 +109,7 @@ static int parse_opts(char *opts, struct p9_client *clnt)
|
||||||
int option;
|
int option;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
clnt->dotu = 1;
|
clnt->proto_version = p9_proto_2000u;
|
||||||
clnt->msize = 8192;
|
clnt->msize = 8192;
|
||||||
|
|
||||||
if (!opts)
|
if (!opts)
|
||||||
|
@ -118,7 +152,13 @@ static int parse_opts(char *opts, struct p9_client *clnt)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Opt_legacy:
|
case Opt_legacy:
|
||||||
clnt->dotu = 0;
|
clnt->proto_version = p9_proto_legacy;
|
||||||
|
break;
|
||||||
|
case Opt_version:
|
||||||
|
ret = get_protocol_version(&args[0]);
|
||||||
|
if (ret == -EINVAL)
|
||||||
|
goto free_and_return;
|
||||||
|
clnt->proto_version = ret;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
|
@ -410,14 +450,15 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
||||||
int ecode;
|
int ecode;
|
||||||
char *ename;
|
char *ename;
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, c->dotu, "s?d", &ename, &ecode);
|
err = p9pdu_readf(req->rc, c->proto_version, "s?d",
|
||||||
|
&ename, &ecode);
|
||||||
if (err) {
|
if (err) {
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
|
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
|
||||||
err);
|
err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->dotu)
|
if (p9_is_proto_dotu(c))
|
||||||
err = -ecode;
|
err = -ecode;
|
||||||
|
|
||||||
if (!err || !IS_ERR_VALUE(err))
|
if (!err || !IS_ERR_VALUE(err))
|
||||||
|
@ -515,7 +556,7 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
|
||||||
/* marshall the data */
|
/* marshall the data */
|
||||||
p9pdu_prepare(req->tc, tag, type);
|
p9pdu_prepare(req->tc, tag, type);
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
err = p9pdu_vwritef(req->tc, c->dotu, fmt, ap);
|
err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
p9pdu_finalize(req->tc);
|
p9pdu_finalize(req->tc);
|
||||||
|
|
||||||
|
@ -627,14 +668,31 @@ int p9_client_version(struct p9_client *c)
|
||||||
char *version;
|
char *version;
|
||||||
int msize;
|
int msize;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d extended %d\n",
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
|
||||||
c->msize, c->dotu);
|
c->msize, c->proto_version);
|
||||||
req = p9_client_rpc(c, P9_TVERSION, "ds", c->msize,
|
|
||||||
c->dotu ? "9P2000.u" : "9P2000");
|
switch (c->proto_version) {
|
||||||
|
case p9_proto_2010L:
|
||||||
|
req = p9_client_rpc(c, P9_TVERSION, "ds",
|
||||||
|
c->msize, "9P2010.L");
|
||||||
|
break;
|
||||||
|
case p9_proto_2000u:
|
||||||
|
req = p9_client_rpc(c, P9_TVERSION, "ds",
|
||||||
|
c->msize, "9P2000.u");
|
||||||
|
break;
|
||||||
|
case p9_proto_legacy:
|
||||||
|
req = p9_client_rpc(c, P9_TVERSION, "ds",
|
||||||
|
c->msize, "9P2000");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ERR(req))
|
if (IS_ERR(req))
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, c->dotu, "ds", &msize, &version);
|
err = p9pdu_readf(req->rc, c->proto_version, "ds", &msize, &version);
|
||||||
if (err) {
|
if (err) {
|
||||||
P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
|
P9_DPRINTK(P9_DEBUG_9P, "version error %d\n", err);
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
|
@ -642,10 +700,12 @@ int p9_client_version(struct p9_client *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
|
||||||
if (!memcmp(version, "9P2000.u", 8))
|
if (!strncmp(version, "9P2010.L", 8))
|
||||||
c->dotu = 1;
|
c->proto_version = p9_proto_2010L;
|
||||||
else if (!memcmp(version, "9P2000", 6))
|
else if (!strncmp(version, "9P2000.u", 8))
|
||||||
c->dotu = 0;
|
c->proto_version = p9_proto_2000u;
|
||||||
|
else if (!strncmp(version, "9P2000", 6))
|
||||||
|
c->proto_version = p9_proto_legacy;
|
||||||
else {
|
else {
|
||||||
err = -EREMOTEIO;
|
err = -EREMOTEIO;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -700,8 +760,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
|
||||||
goto put_trans;
|
goto put_trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d dotu %d\n",
|
P9_DPRINTK(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
|
||||||
clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
|
clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
|
||||||
|
|
||||||
err = clnt->trans_mod->create(clnt, dev_name, options);
|
err = clnt->trans_mod->create(clnt, dev_name, options);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -784,7 +844,7 @@ struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
p9_free_req(clnt, req);
|
p9_free_req(clnt, req);
|
||||||
|
@ -833,7 +893,7 @@ p9_client_auth(struct p9_client *clnt, char *uname, u32 n_uname, char *aname)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "Q", &qid);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "Q", &qid);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
p9_free_req(clnt, req);
|
p9_free_req(clnt, req);
|
||||||
|
@ -891,7 +951,7 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "R", &nwqids, &wqids);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "R", &nwqids, &wqids);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
p9_free_req(clnt, req);
|
p9_free_req(clnt, req);
|
||||||
|
@ -952,7 +1012,7 @@ int p9_client_open(struct p9_fid *fid, int mode)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
goto free_and_error;
|
goto free_and_error;
|
||||||
|
@ -997,7 +1057,7 @@ int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "Qd", &qid, &iounit);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "Qd", &qid, &iounit);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
goto free_and_error;
|
goto free_and_error;
|
||||||
|
@ -1098,7 +1158,7 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "D", &count, &dataptr);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
goto free_and_error;
|
goto free_and_error;
|
||||||
|
@ -1159,7 +1219,7 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "d", &count);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "d", &count);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
goto free_and_error;
|
goto free_and_error;
|
||||||
|
@ -1199,7 +1259,7 @@ struct p9_wstat *p9_client_stat(struct p9_fid *fid)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, clnt->dotu, "wS", &ignored, ret);
|
err = p9pdu_readf(req->rc, clnt->proto_version, "wS", &ignored, ret);
|
||||||
if (err) {
|
if (err) {
|
||||||
p9pdu_dump(1, req->rc);
|
p9pdu_dump(1, req->rc);
|
||||||
p9_free_req(clnt, req);
|
p9_free_req(clnt, req);
|
||||||
|
@ -1226,7 +1286,7 @@ error:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(p9_client_stat);
|
EXPORT_SYMBOL(p9_client_stat);
|
||||||
|
|
||||||
static int p9_client_statsize(struct p9_wstat *wst, int optional)
|
static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1245,7 +1305,7 @@ static int p9_client_statsize(struct p9_wstat *wst, int optional)
|
||||||
if (wst->muid)
|
if (wst->muid)
|
||||||
ret += strlen(wst->muid);
|
ret += strlen(wst->muid);
|
||||||
|
|
||||||
if (optional) {
|
if (proto_version == p9_proto_2000u) {
|
||||||
ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
|
ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
|
||||||
if (wst->extension)
|
if (wst->extension)
|
||||||
ret += strlen(wst->extension);
|
ret += strlen(wst->extension);
|
||||||
|
@ -1262,7 +1322,7 @@ int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
clnt = fid->clnt;
|
clnt = fid->clnt;
|
||||||
wst->size = p9_client_statsize(wst, clnt->dotu);
|
wst->size = p9_client_statsize(wst, clnt->proto_version);
|
||||||
P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid);
|
||||||
P9_DPRINTK(P9_DEBUG_9P,
|
P9_DPRINTK(P9_DEBUG_9P,
|
||||||
" sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
|
" sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...);
|
p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
|
||||||
|
|
||||||
#ifdef CONFIG_NET_9P_DEBUG
|
#ifdef CONFIG_NET_9P_DEBUG
|
||||||
void
|
void
|
||||||
|
@ -144,7 +144,8 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||||
|
va_list ap)
|
||||||
{
|
{
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
int errcode = 0;
|
int errcode = 0;
|
||||||
|
@ -194,7 +195,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
int16_t len;
|
int16_t len;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
errcode = p9pdu_readf(pdu, optional, "w", &len);
|
errcode = p9pdu_readf(pdu, proto_version,
|
||||||
|
"w", &len);
|
||||||
if (errcode)
|
if (errcode)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -217,7 +219,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
struct p9_qid *qid =
|
struct p9_qid *qid =
|
||||||
va_arg(ap, struct p9_qid *);
|
va_arg(ap, struct p9_qid *);
|
||||||
|
|
||||||
errcode = p9pdu_readf(pdu, optional, "bdq",
|
errcode = p9pdu_readf(pdu, proto_version, "bdq",
|
||||||
&qid->type, &qid->version,
|
&qid->type, &qid->version,
|
||||||
&qid->path);
|
&qid->path);
|
||||||
}
|
}
|
||||||
|
@ -230,7 +232,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
|
stbuf->n_uid = stbuf->n_gid = stbuf->n_muid =
|
||||||
-1;
|
-1;
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_readf(pdu, optional,
|
p9pdu_readf(pdu, proto_version,
|
||||||
"wwdQdddqssss?sddd",
|
"wwdQdddqssss?sddd",
|
||||||
&stbuf->size, &stbuf->type,
|
&stbuf->size, &stbuf->type,
|
||||||
&stbuf->dev, &stbuf->qid,
|
&stbuf->dev, &stbuf->qid,
|
||||||
|
@ -250,7 +252,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
void **data = va_arg(ap, void **);
|
void **data = va_arg(ap, void **);
|
||||||
|
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_readf(pdu, optional, "d", count);
|
p9pdu_readf(pdu, proto_version, "d", count);
|
||||||
if (!errcode) {
|
if (!errcode) {
|
||||||
*count =
|
*count =
|
||||||
MIN(*count,
|
MIN(*count,
|
||||||
|
@ -263,8 +265,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
int16_t *nwname = va_arg(ap, int16_t *);
|
int16_t *nwname = va_arg(ap, int16_t *);
|
||||||
char ***wnames = va_arg(ap, char ***);
|
char ***wnames = va_arg(ap, char ***);
|
||||||
|
|
||||||
errcode =
|
errcode = p9pdu_readf(pdu, proto_version,
|
||||||
p9pdu_readf(pdu, optional, "w", nwname);
|
"w", nwname);
|
||||||
if (!errcode) {
|
if (!errcode) {
|
||||||
*wnames =
|
*wnames =
|
||||||
kmalloc(sizeof(char *) * *nwname,
|
kmalloc(sizeof(char *) * *nwname,
|
||||||
|
@ -278,7 +280,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
|
|
||||||
for (i = 0; i < *nwname; i++) {
|
for (i = 0; i < *nwname; i++) {
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_readf(pdu, optional,
|
p9pdu_readf(pdu,
|
||||||
|
proto_version,
|
||||||
"s",
|
"s",
|
||||||
&(*wnames)[i]);
|
&(*wnames)[i]);
|
||||||
if (errcode)
|
if (errcode)
|
||||||
|
@ -306,7 +309,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
*wqids = NULL;
|
*wqids = NULL;
|
||||||
|
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_readf(pdu, optional, "w", nwqid);
|
p9pdu_readf(pdu, proto_version, "w", nwqid);
|
||||||
if (!errcode) {
|
if (!errcode) {
|
||||||
*wqids =
|
*wqids =
|
||||||
kmalloc(*nwqid *
|
kmalloc(*nwqid *
|
||||||
|
@ -321,7 +324,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
|
|
||||||
for (i = 0; i < *nwqid; i++) {
|
for (i = 0; i < *nwqid; i++) {
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_readf(pdu, optional,
|
p9pdu_readf(pdu,
|
||||||
|
proto_version,
|
||||||
"Q",
|
"Q",
|
||||||
&(*wqids)[i]);
|
&(*wqids)[i]);
|
||||||
if (errcode)
|
if (errcode)
|
||||||
|
@ -336,7 +340,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
if (!optional)
|
if (proto_version != p9_proto_2000u)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -352,7 +356,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||||
|
va_list ap)
|
||||||
{
|
{
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
int errcode = 0;
|
int errcode = 0;
|
||||||
|
@ -389,7 +394,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
if (sptr)
|
if (sptr)
|
||||||
len = MIN(strlen(sptr), USHORT_MAX);
|
len = MIN(strlen(sptr), USHORT_MAX);
|
||||||
|
|
||||||
errcode = p9pdu_writef(pdu, optional, "w", len);
|
errcode = p9pdu_writef(pdu, proto_version,
|
||||||
|
"w", len);
|
||||||
if (!errcode && pdu_write(pdu, sptr, len))
|
if (!errcode && pdu_write(pdu, sptr, len))
|
||||||
errcode = -EFAULT;
|
errcode = -EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -398,7 +404,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
const struct p9_qid *qid =
|
const struct p9_qid *qid =
|
||||||
va_arg(ap, const struct p9_qid *);
|
va_arg(ap, const struct p9_qid *);
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_writef(pdu, optional, "bdq",
|
p9pdu_writef(pdu, proto_version, "bdq",
|
||||||
qid->type, qid->version,
|
qid->type, qid->version,
|
||||||
qid->path);
|
qid->path);
|
||||||
} break;
|
} break;
|
||||||
|
@ -406,7 +412,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
const struct p9_wstat *stbuf =
|
const struct p9_wstat *stbuf =
|
||||||
va_arg(ap, const struct p9_wstat *);
|
va_arg(ap, const struct p9_wstat *);
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_writef(pdu, optional,
|
p9pdu_writef(pdu, proto_version,
|
||||||
"wwdQdddqssss?sddd",
|
"wwdQdddqssss?sddd",
|
||||||
stbuf->size, stbuf->type,
|
stbuf->size, stbuf->type,
|
||||||
stbuf->dev, &stbuf->qid,
|
stbuf->dev, &stbuf->qid,
|
||||||
|
@ -421,8 +427,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
int32_t count = va_arg(ap, int32_t);
|
int32_t count = va_arg(ap, int32_t);
|
||||||
const void *data = va_arg(ap, const void *);
|
const void *data = va_arg(ap, const void *);
|
||||||
|
|
||||||
errcode =
|
errcode = p9pdu_writef(pdu, proto_version, "d",
|
||||||
p9pdu_writef(pdu, optional, "d", count);
|
count);
|
||||||
if (!errcode && pdu_write(pdu, data, count))
|
if (!errcode && pdu_write(pdu, data, count))
|
||||||
errcode = -EFAULT;
|
errcode = -EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -431,8 +437,8 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
int32_t count = va_arg(ap, int32_t);
|
int32_t count = va_arg(ap, int32_t);
|
||||||
const char __user *udata =
|
const char __user *udata =
|
||||||
va_arg(ap, const void __user *);
|
va_arg(ap, const void __user *);
|
||||||
errcode =
|
errcode = p9pdu_writef(pdu, proto_version, "d",
|
||||||
p9pdu_writef(pdu, optional, "d", count);
|
count);
|
||||||
if (!errcode && pdu_write_u(pdu, udata, count))
|
if (!errcode && pdu_write_u(pdu, udata, count))
|
||||||
errcode = -EFAULT;
|
errcode = -EFAULT;
|
||||||
}
|
}
|
||||||
|
@ -441,14 +447,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
int16_t nwname = va_arg(ap, int);
|
int16_t nwname = va_arg(ap, int);
|
||||||
const char **wnames = va_arg(ap, const char **);
|
const char **wnames = va_arg(ap, const char **);
|
||||||
|
|
||||||
errcode =
|
errcode = p9pdu_writef(pdu, proto_version, "w",
|
||||||
p9pdu_writef(pdu, optional, "w", nwname);
|
nwname);
|
||||||
if (!errcode) {
|
if (!errcode) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nwname; i++) {
|
for (i = 0; i < nwname; i++) {
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_writef(pdu, optional,
|
p9pdu_writef(pdu,
|
||||||
|
proto_version,
|
||||||
"s",
|
"s",
|
||||||
wnames[i]);
|
wnames[i]);
|
||||||
if (errcode)
|
if (errcode)
|
||||||
|
@ -462,14 +469,15 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
struct p9_qid *wqids =
|
struct p9_qid *wqids =
|
||||||
va_arg(ap, struct p9_qid *);
|
va_arg(ap, struct p9_qid *);
|
||||||
|
|
||||||
errcode =
|
errcode = p9pdu_writef(pdu, proto_version, "w",
|
||||||
p9pdu_writef(pdu, optional, "w", nwqid);
|
nwqid);
|
||||||
if (!errcode) {
|
if (!errcode) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nwqid; i++) {
|
for (i = 0; i < nwqid; i++) {
|
||||||
errcode =
|
errcode =
|
||||||
p9pdu_writef(pdu, optional,
|
p9pdu_writef(pdu,
|
||||||
|
proto_version,
|
||||||
"Q",
|
"Q",
|
||||||
&wqids[i]);
|
&wqids[i]);
|
||||||
if (errcode)
|
if (errcode)
|
||||||
|
@ -479,7 +487,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
if (!optional)
|
if (proto_version != p9_proto_2000u)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -494,32 +502,32 @@ p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap)
|
||||||
return errcode;
|
return errcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...)
|
int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ret = p9pdu_vreadf(pdu, optional, fmt, ap);
|
ret = p9pdu_vreadf(pdu, proto_version, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
p9pdu_writef(struct p9_fcall *pdu, int optional, const char *fmt, ...)
|
p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ret = p9pdu_vwritef(pdu, optional, fmt, ap);
|
ret = p9pdu_vwritef(pdu, proto_version, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
|
int p9stat_read(char *buf, int len, struct p9_wstat *st, int proto_version)
|
||||||
{
|
{
|
||||||
struct p9_fcall fake_pdu;
|
struct p9_fcall fake_pdu;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -529,7 +537,7 @@ int p9stat_read(char *buf, int len, struct p9_wstat *st, int dotu)
|
||||||
fake_pdu.sdata = buf;
|
fake_pdu.sdata = buf;
|
||||||
fake_pdu.offset = 0;
|
fake_pdu.offset = 0;
|
||||||
|
|
||||||
ret = p9pdu_readf(&fake_pdu, dotu, "S", st);
|
ret = p9pdu_readf(&fake_pdu, proto_version, "S", st);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
|
P9_DPRINTK(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret);
|
||||||
p9pdu_dump(1, &fake_pdu);
|
p9pdu_dump(1, &fake_pdu);
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
|
||||||
p9pdu_vwritef(struct p9_fcall *pdu, int optional, const char *fmt, va_list ap);
|
va_list ap);
|
||||||
int p9pdu_readf(struct p9_fcall *pdu, int optional, const char *fmt, ...);
|
int p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
|
||||||
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
|
int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type);
|
||||||
int p9pdu_finalize(struct p9_fcall *pdu);
|
int p9pdu_finalize(struct p9_fcall *pdu);
|
||||||
void p9pdu_dump(int, struct p9_fcall *);
|
void p9pdu_dump(int, struct p9_fcall *);
|
||||||
|
|
|
@ -49,8 +49,6 @@
|
||||||
|
|
||||||
/* a single mutex to manage channel initialization and attachment */
|
/* a single mutex to manage channel initialization and attachment */
|
||||||
static DEFINE_MUTEX(virtio_9p_lock);
|
static DEFINE_MUTEX(virtio_9p_lock);
|
||||||
/* global which tracks highest initialized channel */
|
|
||||||
static int chan_index;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct virtio_chan - per-instance transport information
|
* struct virtio_chan - per-instance transport information
|
||||||
|
@ -68,8 +66,7 @@ static int chan_index;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct virtio_chan {
|
struct virtio_chan {
|
||||||
bool initialized;
|
|
||||||
bool inuse;
|
bool inuse;
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
@ -80,7 +77,11 @@ static struct virtio_chan {
|
||||||
|
|
||||||
/* Scatterlist: can be too big for stack. */
|
/* Scatterlist: can be too big for stack. */
|
||||||
struct scatterlist sg[VIRTQUEUE_NUM];
|
struct scatterlist sg[VIRTQUEUE_NUM];
|
||||||
} channels[MAX_9P_CHAN];
|
|
||||||
|
struct list_head chan_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct list_head virtio_chan_list;
|
||||||
|
|
||||||
/* How many bytes left in this page. */
|
/* How many bytes left in this page. */
|
||||||
static unsigned int rest_of_page(void *data)
|
static unsigned int rest_of_page(void *data)
|
||||||
|
@ -217,9 +218,7 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
|
||||||
* p9_virtio_probe - probe for existence of 9P virtio channels
|
* p9_virtio_probe - probe for existence of 9P virtio channels
|
||||||
* @vdev: virtio device to probe
|
* @vdev: virtio device to probe
|
||||||
*
|
*
|
||||||
* This probes for existing virtio channels. At present only
|
* This probes for existing virtio channels.
|
||||||
* a single channel is in use, so in the future more work may need
|
|
||||||
* to be done here.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -227,16 +226,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct virtio_chan *chan;
|
struct virtio_chan *chan;
|
||||||
int index;
|
|
||||||
|
|
||||||
mutex_lock(&virtio_9p_lock);
|
chan = kmalloc(sizeof(struct virtio_chan), GFP_KERNEL);
|
||||||
index = chan_index++;
|
if (!chan) {
|
||||||
chan = &channels[index];
|
printk(KERN_ERR "9p: Failed to allocate virtio 9P channel\n");
|
||||||
mutex_unlock(&virtio_9p_lock);
|
|
||||||
|
|
||||||
if (chan_index > MAX_9P_CHAN) {
|
|
||||||
printk(KERN_ERR "9p: virtio: Maximum channels exceeded\n");
|
|
||||||
BUG();
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -255,15 +248,15 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
||||||
sg_init_table(chan->sg, VIRTQUEUE_NUM);
|
sg_init_table(chan->sg, VIRTQUEUE_NUM);
|
||||||
|
|
||||||
chan->inuse = false;
|
chan->inuse = false;
|
||||||
chan->initialized = true;
|
mutex_lock(&virtio_9p_lock);
|
||||||
|
list_add_tail(&chan->chan_list, &virtio_chan_list);
|
||||||
|
mutex_unlock(&virtio_9p_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_free_vq:
|
out_free_vq:
|
||||||
vdev->config->del_vqs(vdev);
|
vdev->config->del_vqs(vdev);
|
||||||
|
kfree(chan);
|
||||||
fail:
|
fail:
|
||||||
mutex_lock(&virtio_9p_lock);
|
|
||||||
chan_index--;
|
|
||||||
mutex_unlock(&virtio_9p_lock);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,35 +273,31 @@ fail:
|
||||||
* We use a simple reference count mechanism to ensure that only a single
|
* We use a simple reference count mechanism to ensure that only a single
|
||||||
* mount has a channel open at a time.
|
* mount has a channel open at a time.
|
||||||
*
|
*
|
||||||
* Bugs: doesn't allow identification of a specific channel
|
|
||||||
* to allocate, channels are allocated sequentially. This was
|
|
||||||
* a pragmatic decision to get things rolling, but ideally some
|
|
||||||
* way of identifying the channel to attach to would be nice
|
|
||||||
* if we are going to support multiple channels.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
p9_virtio_create(struct p9_client *client, const char *devname, char *args)
|
p9_virtio_create(struct p9_client *client, const char *devname, char *args)
|
||||||
{
|
{
|
||||||
struct virtio_chan *chan = channels;
|
struct virtio_chan *chan;
|
||||||
int index = 0;
|
int ret = -ENOENT;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
mutex_lock(&virtio_9p_lock);
|
mutex_lock(&virtio_9p_lock);
|
||||||
while (index < MAX_9P_CHAN) {
|
list_for_each_entry(chan, &virtio_chan_list, chan_list) {
|
||||||
if (chan->initialized && !chan->inuse) {
|
if (!strcmp(devname, dev_name(&chan->vdev->dev))) {
|
||||||
chan->inuse = true;
|
if (!chan->inuse) {
|
||||||
break;
|
chan->inuse = true;
|
||||||
} else {
|
found = 1;
|
||||||
index++;
|
break;
|
||||||
chan = &channels[index];
|
}
|
||||||
|
ret = -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&virtio_9p_lock);
|
mutex_unlock(&virtio_9p_lock);
|
||||||
|
|
||||||
if (index >= MAX_9P_CHAN) {
|
if (!found) {
|
||||||
printk(KERN_ERR "9p: no channels available\n");
|
printk(KERN_ERR "9p: no channels available\n");
|
||||||
return -ENODEV;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
client->trans = (void *)chan;
|
client->trans = (void *)chan;
|
||||||
|
@ -329,11 +318,13 @@ static void p9_virtio_remove(struct virtio_device *vdev)
|
||||||
struct virtio_chan *chan = vdev->priv;
|
struct virtio_chan *chan = vdev->priv;
|
||||||
|
|
||||||
BUG_ON(chan->inuse);
|
BUG_ON(chan->inuse);
|
||||||
|
vdev->config->del_vqs(vdev);
|
||||||
|
|
||||||
|
mutex_lock(&virtio_9p_lock);
|
||||||
|
list_del(&chan->chan_list);
|
||||||
|
mutex_unlock(&virtio_9p_lock);
|
||||||
|
kfree(chan);
|
||||||
|
|
||||||
if (chan->initialized) {
|
|
||||||
vdev->config->del_vqs(vdev);
|
|
||||||
chan->initialized = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct virtio_device_id id_table[] = {
|
static struct virtio_device_id id_table[] = {
|
||||||
|
@ -364,10 +355,7 @@ static struct p9_trans_module p9_virtio_trans = {
|
||||||
/* The standard init function */
|
/* The standard init function */
|
||||||
static int __init p9_virtio_init(void)
|
static int __init p9_virtio_init(void)
|
||||||
{
|
{
|
||||||
int count;
|
INIT_LIST_HEAD(&virtio_chan_list);
|
||||||
|
|
||||||
for (count = 0; count < MAX_9P_CHAN; count++)
|
|
||||||
channels[count].initialized = false;
|
|
||||||
|
|
||||||
v9fs_register_trans(&p9_virtio_trans);
|
v9fs_register_trans(&p9_virtio_trans);
|
||||||
return register_virtio_driver(&p9_virtio_drv);
|
return register_virtio_driver(&p9_virtio_drv);
|
||||||
|
|
Loading…
Reference in New Issue