9p: fix error path during early mount
There was some cleanup issues during early mount which would trigger a kernel bug for certain types of failure. This patch reorganizes the cleanup to get rid of the bad behavior. This also merges the 9pnet and 9pnet_fd modules for the purpose of configuration and initialization. Keeping the fd transport separate from the core 9pnet code seemed like a good idea at the time, but in practice has caused more harm and confusion than good. Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
This commit is contained in:
parent
332c421e67
commit
887b3ece65
13
fs/9p/v9fs.c
13
fs/9p/v9fs.c
|
@ -206,12 +206,14 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
||||||
v9ses->uid = ~0;
|
v9ses->uid = ~0;
|
||||||
v9ses->dfltuid = V9FS_DEFUID;
|
v9ses->dfltuid = V9FS_DEFUID;
|
||||||
v9ses->dfltgid = V9FS_DEFGID;
|
v9ses->dfltgid = V9FS_DEFGID;
|
||||||
v9ses->options = kstrdup(data, GFP_KERNEL);
|
if (data) {
|
||||||
if (!v9ses->options) {
|
v9ses->options = kstrdup(data, GFP_KERNEL);
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
if (!v9ses->options) {
|
||||||
|
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||||
"failed to allocate copy of option string\n");
|
"failed to allocate copy of option string\n");
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = v9fs_parse_options(v9ses);
|
rc = v9fs_parse_options(v9ses);
|
||||||
|
@ -260,7 +262,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
||||||
return fid;
|
return fid;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
v9fs_session_close(v9ses);
|
|
||||||
return ERR_PTR(retval);
|
return ERR_PTR(retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,29 +128,26 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||||
fid = v9fs_session_init(v9ses, dev_name, data);
|
fid = v9fs_session_init(v9ses, dev_name, data);
|
||||||
if (IS_ERR(fid)) {
|
if (IS_ERR(fid)) {
|
||||||
retval = PTR_ERR(fid);
|
retval = PTR_ERR(fid);
|
||||||
fid = NULL;
|
goto close_session;
|
||||||
kfree(v9ses);
|
|
||||||
v9ses = NULL;
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
st = p9_client_stat(fid);
|
st = p9_client_stat(fid);
|
||||||
if (IS_ERR(st)) {
|
if (IS_ERR(st)) {
|
||||||
retval = PTR_ERR(st);
|
retval = PTR_ERR(st);
|
||||||
goto error;
|
goto clunk_fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
|
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
|
||||||
if (IS_ERR(sb)) {
|
if (IS_ERR(sb)) {
|
||||||
retval = PTR_ERR(sb);
|
retval = PTR_ERR(sb);
|
||||||
goto error;
|
goto free_stat;
|
||||||
}
|
}
|
||||||
v9fs_fill_super(sb, v9ses, flags);
|
v9fs_fill_super(sb, v9ses, flags);
|
||||||
|
|
||||||
inode = v9fs_get_inode(sb, S_IFDIR | mode);
|
inode = v9fs_get_inode(sb, S_IFDIR | mode);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
retval = PTR_ERR(inode);
|
retval = PTR_ERR(inode);
|
||||||
goto error;
|
goto release_sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
inode->i_uid = uid;
|
inode->i_uid = uid;
|
||||||
|
@ -159,7 +156,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||||
root = d_alloc_root(inode);
|
root = d_alloc_root(inode);
|
||||||
if (!root) {
|
if (!root) {
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
goto error;
|
goto release_sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
sb->s_root = root;
|
sb->s_root = root;
|
||||||
|
@ -170,21 +167,22 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||||
|
|
||||||
return simple_set_mnt(mnt, sb);
|
return simple_set_mnt(mnt, sb);
|
||||||
|
|
||||||
error:
|
release_sb:
|
||||||
kfree(st);
|
|
||||||
if (fid)
|
|
||||||
p9_client_clunk(fid);
|
|
||||||
|
|
||||||
if (v9ses) {
|
|
||||||
v9fs_session_close(v9ses);
|
|
||||||
kfree(v9ses);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sb) {
|
if (sb) {
|
||||||
up_write(&sb->s_umount);
|
up_write(&sb->s_umount);
|
||||||
deactivate_super(sb);
|
deactivate_super(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_stat:
|
||||||
|
kfree(st);
|
||||||
|
|
||||||
|
clunk_fid:
|
||||||
|
p9_client_clunk(fid);
|
||||||
|
|
||||||
|
close_session:
|
||||||
|
v9fs_session_close(v9ses);
|
||||||
|
kfree(v9ses);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -595,4 +595,5 @@ int p9_idpool_check(int id, struct p9_idpool *p);
|
||||||
|
|
||||||
int p9_error_init(void);
|
int p9_error_init(void);
|
||||||
int p9_errstr2errno(char *, int);
|
int p9_errstr2errno(char *, int);
|
||||||
|
int p9_trans_fd_init(void);
|
||||||
#endif /* NET_9P_H */
|
#endif /* NET_9P_H */
|
||||||
|
|
|
@ -96,5 +96,4 @@ struct p9_trans_module {
|
||||||
void v9fs_register_trans(struct p9_trans_module *m);
|
void v9fs_register_trans(struct p9_trans_module *m);
|
||||||
struct p9_trans_module *v9fs_match_trans(const substring_t *name);
|
struct p9_trans_module *v9fs_match_trans(const substring_t *name);
|
||||||
struct p9_trans_module *v9fs_default_trans(void);
|
struct p9_trans_module *v9fs_default_trans(void);
|
||||||
|
|
||||||
#endif /* NET_9P_TRANSPORT_H */
|
#endif /* NET_9P_TRANSPORT_H */
|
||||||
|
|
|
@ -13,16 +13,6 @@ menuconfig NET_9P
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config NET_9P_FD
|
|
||||||
depends on NET_9P
|
|
||||||
default y if NET_9P
|
|
||||||
tristate "9P File Descriptor Transports (Experimental)"
|
|
||||||
help
|
|
||||||
This builds support for file descriptor transports for 9p
|
|
||||||
which includes support for TCP/IP, named pipes, or passed
|
|
||||||
file descriptors. TCP/IP is the default transport for 9p,
|
|
||||||
so if you are going to use 9p, you'll likely want this.
|
|
||||||
|
|
||||||
config NET_9P_VIRTIO
|
config NET_9P_VIRTIO
|
||||||
depends on NET_9P && EXPERIMENTAL && VIRTIO
|
depends on NET_9P && EXPERIMENTAL && VIRTIO
|
||||||
tristate "9P Virtio Transport (Experimental)"
|
tristate "9P Virtio Transport (Experimental)"
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
obj-$(CONFIG_NET_9P) := 9pnet.o
|
obj-$(CONFIG_NET_9P) := 9pnet.o
|
||||||
obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o
|
|
||||||
obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
|
obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
|
||||||
|
|
||||||
9pnet-objs := \
|
9pnet-objs := \
|
||||||
|
@ -9,8 +8,6 @@ obj-$(CONFIG_NET_9P_VIRTIO) += 9pnet_virtio.o
|
||||||
error.o \
|
error.o \
|
||||||
fcprint.o \
|
fcprint.o \
|
||||||
util.o \
|
util.o \
|
||||||
|
|
||||||
9pnet_fd-objs := \
|
|
||||||
trans_fd.o \
|
trans_fd.o \
|
||||||
|
|
||||||
9pnet_virtio-objs := \
|
9pnet_virtio-objs := \
|
||||||
|
|
|
@ -107,6 +107,7 @@ static int __init init_p9(void)
|
||||||
|
|
||||||
p9_error_init();
|
p9_error_init();
|
||||||
printk(KERN_INFO "Installing 9P2000 support\n");
|
printk(KERN_INFO "Installing 9P2000 support\n");
|
||||||
|
p9_trans_fd_init();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1433,6 +1433,23 @@ static void p9_fd_close(struct p9_trans *trans)
|
||||||
kfree(ts);
|
kfree(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stolen from NFS - maybe should be made a generic function?
|
||||||
|
*/
|
||||||
|
static inline int valid_ipaddr4(const char *buf)
|
||||||
|
{
|
||||||
|
int rc, count, in[4];
|
||||||
|
|
||||||
|
rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
|
||||||
|
if (rc != 4)
|
||||||
|
return -EINVAL;
|
||||||
|
for (count = 0; count < 4; count++) {
|
||||||
|
if (in[count] > 255)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct p9_trans *
|
static struct p9_trans *
|
||||||
p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
|
p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
|
||||||
{
|
{
|
||||||
|
@ -1447,6 +1464,9 @@ p9_trans_create_tcp(const char *addr, char *args, int msize, unsigned char dotu)
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
if (valid_ipaddr4(addr) < 0)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
csocket = NULL;
|
csocket = NULL;
|
||||||
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
|
trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
|
||||||
if (!trans)
|
if (!trans)
|
||||||
|
@ -1625,7 +1645,7 @@ static struct p9_trans_module p9_fd_trans = {
|
||||||
.create = p9_trans_create_fd,
|
.create = p9_trans_create_fd,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init p9_trans_fd_init(void)
|
int p9_trans_fd_init(void)
|
||||||
{
|
{
|
||||||
int ret = p9_mux_global_init();
|
int ret = p9_mux_global_init();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1639,9 +1659,4 @@ static int __init p9_trans_fd_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(p9_trans_fd_init);
|
||||||
module_init(p9_trans_fd_init);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
|
|
||||||
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
|
|
Loading…
Reference in New Issue