diff options
-rw-r--r-- | Documentation/filesystems/9p.txt | 18 | ||||
-rw-r--r-- | fs/9p/fid.c | 12 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 21 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 1 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 2 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 9 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 3 | ||||
-rw-r--r-- | include/net/9p/client.h | 2 | ||||
-rw-r--r-- | net/9p/client.c | 23 |
9 files changed, 78 insertions, 13 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt index 57e0b80a5274..c0236e753bc8 100644 --- a/Documentation/filesystems/9p.txt +++ b/Documentation/filesystems/9p.txt | |||
@@ -37,6 +37,15 @@ For Plan 9 From User Space applications (http://swtch.com/plan9) | |||
37 | 37 | ||
38 | mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER | 38 | mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER |
39 | 39 | ||
40 | For server running on QEMU host with virtio transport: | ||
41 | |||
42 | mount -t 9p -o trans=virtio <mount_tag> /mnt/9 | ||
43 | |||
44 | where mount_tag is the tag associated by the server to each of the exported | ||
45 | mount points. Each 9P export is seen by the client as a virtio device with an | ||
46 | associated "mount_tag" property. Available mount tags can be | ||
47 | seen by reading /sys/bus/virtio/drivers/9pnet_virtio/virtio<n>/mount_tag files. | ||
48 | |||
40 | OPTIONS | 49 | OPTIONS |
41 | ======= | 50 | ======= |
42 | 51 | ||
@@ -47,7 +56,7 @@ OPTIONS | |||
47 | fd - used passed file descriptors for connection | 56 | fd - used passed file descriptors for connection |
48 | (see rfdno and wfdno) | 57 | (see rfdno and wfdno) |
49 | virtio - connect to the next virtio channel available | 58 | virtio - connect to the next virtio channel available |
50 | (from lguest or KVM with trans_virtio module) | 59 | (from QEMU with trans_virtio module) |
51 | rdma - connect to a specified RDMA channel | 60 | rdma - connect to a specified RDMA channel |
52 | 61 | ||
53 | uname=name user name to attempt mount as on the remote server. The | 62 | uname=name user name to attempt mount as on the remote server. The |
@@ -85,7 +94,12 @@ OPTIONS | |||
85 | 94 | ||
86 | port=n port to connect to on the remote server | 95 | port=n port to connect to on the remote server |
87 | 96 | ||
88 | noextend force legacy mode (no 9p2000.u semantics) | 97 | noextend force legacy mode (no 9p2000.u or 9p2000.L semantics) |
98 | |||
99 | version=name Select 9P protocol version. Valid options are: | ||
100 | 9p2000 - Legacy mode (same as noextend) | ||
101 | 9p2000.u - Use 9P2000.u protocol | ||
102 | 9p2000.L - Use 9P2000.L protocol | ||
89 | 103 | ||
90 | dfltuid attempt to mount as a particular uid | 104 | dfltuid attempt to mount as a particular uid |
91 | 105 | ||
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 82ee460e534d..7317b39b2815 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
@@ -111,7 +111,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
111 | { | 111 | { |
112 | int i, n, l, clone, any, access; | 112 | int i, n, l, clone, any, access; |
113 | u32 uid; | 113 | u32 uid; |
114 | struct p9_fid *fid; | 114 | struct p9_fid *fid, *old_fid = NULL; |
115 | struct dentry *d, *ds; | 115 | struct dentry *d, *ds; |
116 | struct v9fs_session_info *v9ses; | 116 | struct v9fs_session_info *v9ses; |
117 | char **wnames, *uname; | 117 | char **wnames, *uname; |
@@ -184,10 +184,18 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
184 | l = min(n - i, P9_MAXWELEM); | 184 | l = min(n - i, P9_MAXWELEM); |
185 | fid = p9_client_walk(fid, l, &wnames[i], clone); | 185 | fid = p9_client_walk(fid, l, &wnames[i], clone); |
186 | if (IS_ERR(fid)) { | 186 | if (IS_ERR(fid)) { |
187 | if (old_fid) { | ||
188 | /* | ||
189 | * If we fail, clunk fid which are mapping | ||
190 | * to path component and not the last component | ||
191 | * of the path. | ||
192 | */ | ||
193 | p9_client_clunk(old_fid); | ||
194 | } | ||
187 | kfree(wnames); | 195 | kfree(wnames); |
188 | return fid; | 196 | return fid; |
189 | } | 197 | } |
190 | 198 | old_fid = fid; | |
191 | i += l; | 199 | i += l; |
192 | clone = 0; | 200 | clone = 0; |
193 | } | 201 | } |
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index cb57d3326182..5c5bc8480070 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -242,7 +242,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
242 | list_add(&v9ses->slist, &v9fs_sessionlist); | 242 | list_add(&v9ses->slist, &v9fs_sessionlist); |
243 | spin_unlock(&v9fs_sessionlist_lock); | 243 | spin_unlock(&v9fs_sessionlist_lock); |
244 | 244 | ||
245 | v9ses->flags = V9FS_PROTO_2000U | V9FS_ACCESS_USER; | 245 | v9ses->flags = V9FS_ACCESS_USER; |
246 | strcpy(v9ses->uname, V9FS_DEFUSER); | 246 | strcpy(v9ses->uname, V9FS_DEFUSER); |
247 | strcpy(v9ses->aname, V9FS_DEFANAME); | 247 | strcpy(v9ses->aname, V9FS_DEFANAME); |
248 | v9ses->uid = ~0; | 248 | v9ses->uid = ~0; |
@@ -263,8 +263,10 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
263 | goto error; | 263 | goto error; |
264 | } | 264 | } |
265 | 265 | ||
266 | if (!p9_is_proto_dotu(v9ses->clnt)) | 266 | if (p9_is_proto_dotl(v9ses->clnt)) |
267 | v9ses->flags &= ~V9FS_PROTO_2000U; | 267 | v9ses->flags |= V9FS_PROTO_2000L; |
268 | else if (p9_is_proto_dotu(v9ses->clnt)) | ||
269 | v9ses->flags |= V9FS_PROTO_2000U; | ||
268 | 270 | ||
269 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; | 271 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; |
270 | 272 | ||
@@ -341,6 +343,19 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses) { | |||
341 | p9_client_disconnect(v9ses->clnt); | 343 | p9_client_disconnect(v9ses->clnt); |
342 | } | 344 | } |
343 | 345 | ||
346 | /** | ||
347 | * v9fs_session_begin_cancel - Begin terminate of a session | ||
348 | * @v9ses: session to terminate | ||
349 | * | ||
350 | * After this call we don't allow any request other than clunk. | ||
351 | */ | ||
352 | |||
353 | void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses) | ||
354 | { | ||
355 | P9_DPRINTK(P9_DEBUG_ERROR, "begin cancel session %p\n", v9ses); | ||
356 | p9_client_begin_disconnect(v9ses->clnt); | ||
357 | } | ||
358 | |||
344 | extern int v9fs_error_init(void); | 359 | extern int v9fs_error_init(void); |
345 | 360 | ||
346 | static struct kobject *v9fs_kobj; | 361 | static struct kobject *v9fs_kobj; |
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 6b801d1ddf4b..a0a8d3dd1361 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h | |||
@@ -108,6 +108,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, | |||
108 | char *); | 108 | char *); |
109 | void v9fs_session_close(struct v9fs_session_info *v9ses); | 109 | void v9fs_session_close(struct v9fs_session_info *v9ses); |
110 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); | 110 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); |
111 | void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); | ||
111 | 112 | ||
112 | #define V9FS_MAGIC 0x01021997 | 113 | #define V9FS_MAGIC 0x01021997 |
113 | 114 | ||
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 909711f57c0d..0adfd64dfcee 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -131,6 +131,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
131 | rdir = (struct p9_rdir *) fid->rdir; | 131 | rdir = (struct p9_rdir *) fid->rdir; |
132 | 132 | ||
133 | err = mutex_lock_interruptible(&rdir->mutex); | 133 | err = mutex_lock_interruptible(&rdir->mutex); |
134 | if (err) | ||
135 | return err; | ||
134 | while (err == 0) { | 136 | while (err == 0) { |
135 | if (rdir->tail == rdir->head) { | 137 | if (rdir->tail == rdir->head) { |
136 | err = v9fs_file_readn(filp, rdir->buf, NULL, | 138 | err = v9fs_file_readn(filp, rdir->buf, NULL, |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 63c2b5af268a..f2434fc9d2c4 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -432,6 +432,7 @@ error: | |||
432 | 432 | ||
433 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 433 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) |
434 | { | 434 | { |
435 | int retval; | ||
435 | struct inode *file_inode; | 436 | struct inode *file_inode; |
436 | struct v9fs_session_info *v9ses; | 437 | struct v9fs_session_info *v9ses; |
437 | struct p9_fid *v9fid; | 438 | struct p9_fid *v9fid; |
@@ -445,7 +446,10 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
445 | if (IS_ERR(v9fid)) | 446 | if (IS_ERR(v9fid)) |
446 | return PTR_ERR(v9fid); | 447 | return PTR_ERR(v9fid); |
447 | 448 | ||
448 | return p9_client_remove(v9fid); | 449 | retval = p9_client_remove(v9fid); |
450 | if (!retval) | ||
451 | drop_nlink(file_inode); | ||
452 | return retval; | ||
449 | } | 453 | } |
450 | 454 | ||
451 | static int | 455 | static int |
@@ -657,6 +661,9 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
657 | P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 661 | P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", |
658 | dir, dentry->d_name.name, dentry, nameidata); | 662 | dir, dentry->d_name.name, dentry, nameidata); |
659 | 663 | ||
664 | if (dentry->d_name.len > NAME_MAX) | ||
665 | return ERR_PTR(-ENAMETOOLONG); | ||
666 | |||
660 | sb = dir->i_sb; | 667 | sb = dir->i_sb; |
661 | v9ses = v9fs_inode2v9ses(dir); | 668 | v9ses = v9fs_inode2v9ses(dir); |
662 | dfid = v9fs_fid_lookup(dentry->d_parent); | 669 | dfid = v9fs_fid_lookup(dentry->d_parent); |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index a271549d9e21..491108bd6e0d 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -194,6 +194,7 @@ static void v9fs_kill_super(struct super_block *s) | |||
194 | 194 | ||
195 | kill_anon_super(s); | 195 | kill_anon_super(s); |
196 | 196 | ||
197 | v9fs_session_cancel(v9ses); | ||
197 | v9fs_session_close(v9ses); | 198 | v9fs_session_close(v9ses); |
198 | kfree(v9ses); | 199 | kfree(v9ses); |
199 | s->s_fs_info = NULL; | 200 | s->s_fs_info = NULL; |
@@ -206,7 +207,7 @@ v9fs_umount_begin(struct super_block *sb) | |||
206 | struct v9fs_session_info *v9ses; | 207 | struct v9fs_session_info *v9ses; |
207 | 208 | ||
208 | v9ses = sb->s_fs_info; | 209 | v9ses = sb->s_fs_info; |
209 | v9fs_session_cancel(v9ses); | 210 | v9fs_session_begin_cancel(v9ses); |
210 | } | 211 | } |
211 | 212 | ||
212 | static const struct super_operations v9fs_super_ops = { | 213 | static const struct super_operations v9fs_super_ops = { |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index f076dfa75ae8..4f3760afc20f 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -54,6 +54,7 @@ enum p9_proto_versions{ | |||
54 | 54 | ||
55 | enum p9_trans_status { | 55 | enum p9_trans_status { |
56 | Connected, | 56 | Connected, |
57 | BeginDisconnect, | ||
57 | Disconnected, | 58 | Disconnected, |
58 | Hung, | 59 | Hung, |
59 | }; | 60 | }; |
@@ -198,6 +199,7 @@ int p9_client_version(struct p9_client *); | |||
198 | struct p9_client *p9_client_create(const char *dev_name, char *options); | 199 | struct p9_client *p9_client_create(const char *dev_name, char *options); |
199 | void p9_client_destroy(struct p9_client *clnt); | 200 | void p9_client_destroy(struct p9_client *clnt); |
200 | void p9_client_disconnect(struct p9_client *clnt); | 201 | void p9_client_disconnect(struct p9_client *clnt); |
202 | void p9_client_begin_disconnect(struct p9_client *clnt); | ||
201 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | 203 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, |
202 | char *uname, u32 n_uname, char *aname); | 204 | char *uname, u32 n_uname, char *aname); |
203 | struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, | 205 | struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, |
diff --git a/net/9p/client.c b/net/9p/client.c index 6e6b928a5972..0aa79faa9850 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -72,9 +72,10 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) | |||
72 | EXPORT_SYMBOL(p9_is_proto_dotu); | 72 | EXPORT_SYMBOL(p9_is_proto_dotu); |
73 | 73 | ||
74 | /* Interpret mount option for protocol version */ | 74 | /* Interpret mount option for protocol version */ |
75 | static unsigned char get_protocol_version(const substring_t *name) | 75 | static int get_protocol_version(const substring_t *name) |
76 | { | 76 | { |
77 | unsigned char version = -EINVAL; | 77 | int version = -EINVAL; |
78 | |||
78 | if (!strncmp("9p2000", name->from, name->to-name->from)) { | 79 | if (!strncmp("9p2000", name->from, name->to-name->from)) { |
79 | version = p9_proto_legacy; | 80 | version = p9_proto_legacy; |
80 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); | 81 | P9_DPRINTK(P9_DEBUG_9P, "Protocol version: Legacy\n"); |
@@ -534,7 +535,12 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
534 | 535 | ||
535 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); | 536 | P9_DPRINTK(P9_DEBUG_MUX, "client %p op %d\n", c, type); |
536 | 537 | ||
537 | if (c->status != Connected) | 538 | /* we allow for any status other than disconnected */ |
539 | if (c->status == Disconnected) | ||
540 | return ERR_PTR(-EIO); | ||
541 | |||
542 | /* if status is begin_disconnected we allow only clunk request */ | ||
543 | if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) | ||
538 | return ERR_PTR(-EIO); | 544 | return ERR_PTR(-EIO); |
539 | 545 | ||
540 | if (signal_pending(current)) { | 546 | if (signal_pending(current)) { |
@@ -800,8 +806,10 @@ void p9_client_destroy(struct p9_client *clnt) | |||
800 | 806 | ||
801 | v9fs_put_trans(clnt->trans_mod); | 807 | v9fs_put_trans(clnt->trans_mod); |
802 | 808 | ||
803 | list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) | 809 | list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist) { |
810 | printk(KERN_INFO "Found fid %d not clunked\n", fid->fid); | ||
804 | p9_fid_destroy(fid); | 811 | p9_fid_destroy(fid); |
812 | } | ||
805 | 813 | ||
806 | if (clnt->fidpool) | 814 | if (clnt->fidpool) |
807 | p9_idpool_destroy(clnt->fidpool); | 815 | p9_idpool_destroy(clnt->fidpool); |
@@ -819,6 +827,13 @@ void p9_client_disconnect(struct p9_client *clnt) | |||
819 | } | 827 | } |
820 | EXPORT_SYMBOL(p9_client_disconnect); | 828 | EXPORT_SYMBOL(p9_client_disconnect); |
821 | 829 | ||
830 | void p9_client_begin_disconnect(struct p9_client *clnt) | ||
831 | { | ||
832 | P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt); | ||
833 | clnt->status = BeginDisconnect; | ||
834 | } | ||
835 | EXPORT_SYMBOL(p9_client_begin_disconnect); | ||
836 | |||
822 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, | 837 | struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, |
823 | char *uname, u32 n_uname, char *aname) | 838 | char *uname, u32 n_uname, char *aname) |
824 | { | 839 | { |