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 | { |
