aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-05-14 22:30:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-14 22:30:51 -0400
commit8f40f672e6bb071812f61bfbd30efc3fc1263ad1 (patch)
tree8dcdbbb7adc68647267794c4e3a4686afd94ad65 /fs
parent8978a318837d7acefca82645017c0534aeba5a36 (diff)
parent887b3ece65be7b643dfdae0d433c91a26a3f437d (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of ssh://master.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: 9p: fix error path during early mount 9p: make cryptic unknown error from server less scary 9p: fix flags length in net 9p: Correct fidpool creation failure in p9_client_create 9p: use struct mutex instead of struct semaphore 9p: propagate parse_option changes to client and transports fs/9p/v9fs.c (v9fs_parse_options): Handle kstrdup and match_strdup failure. 9p: Documentation updates add match_strlcpy() us it to make v9fs make uname and remotename parsing more robust
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/fid.h15
-rw-r--r--fs/9p/v9fs.c57
-rw-r--r--fs/9p/v9fs.h85
-rw-r--r--fs/9p/vfs_addr.c2
-rw-r--r--fs/9p/vfs_dir.c2
-rw-r--r--fs/9p/vfs_file.c11
-rw-r--r--fs/9p/vfs_inode.c50
-rw-r--r--fs/9p/vfs_super.c35
8 files changed, 181 insertions, 76 deletions
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 26e07df783b9..c3bbd6af996d 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -22,6 +22,21 @@
22 22
23#include <linux/list.h> 23#include <linux/list.h>
24 24
25/**
26 * struct v9fs_dentry - 9p private data stored in dentry d_fsdata
27 * @lock: protects the fidlist
28 * @fidlist: list of FIDs currently associated with this dentry
29 *
30 * This structure defines the 9p private data associated with
31 * a particular dentry. In particular, this private data is used
32 * to lookup which 9P FID handle should be used for a particular VFS
33 * operation. FID handles are associated with dentries instead of
34 * inodes in order to more closely map functionality to the Plan 9
35 * expected behavior for FID reclaimation and tracking.
36 *
37 * See Also: Mapping FIDs to Linux VFS model in
38 * Design and Implementation of the Linux 9P File System documentation
39 */
25struct v9fs_dentry { 40struct v9fs_dentry {
26 spinlock_t lock; /* protect fidlist */ 41 spinlock_t lock; /* protect fidlist */
27 struct list_head fidlist; 42 struct list_head fidlist;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 9b0f0222e8bb..047c791427aa 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -71,19 +71,19 @@ static match_table_t tokens = {
71 71
72/** 72/**
73 * v9fs_parse_options - parse mount options into session structure 73 * v9fs_parse_options - parse mount options into session structure
74 * @options: options string passed from mount
75 * @v9ses: existing v9fs session information 74 * @v9ses: existing v9fs session information
76 * 75 *
76 * Return 0 upon success, -ERRNO upon failure.
77 */ 77 */
78 78
79static void v9fs_parse_options(struct v9fs_session_info *v9ses) 79static int v9fs_parse_options(struct v9fs_session_info *v9ses)
80{ 80{
81 char *options; 81 char *options;
82 substring_t args[MAX_OPT_ARGS]; 82 substring_t args[MAX_OPT_ARGS];
83 char *p; 83 char *p;
84 int option = 0; 84 int option = 0;
85 char *s, *e; 85 char *s, *e;
86 int ret; 86 int ret = 0;
87 87
88 /* setup defaults */ 88 /* setup defaults */
89 v9ses->afid = ~0; 89 v9ses->afid = ~0;
@@ -91,19 +91,26 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
91 v9ses->cache = 0; 91 v9ses->cache = 0;
92 92
93 if (!v9ses->options) 93 if (!v9ses->options)
94 return; 94 return 0;
95 95
96 options = kstrdup(v9ses->options, GFP_KERNEL); 96 options = kstrdup(v9ses->options, GFP_KERNEL);
97 if (!options) {
98 P9_DPRINTK(P9_DEBUG_ERROR,
99 "failed to allocate copy of option string\n");
100 return -ENOMEM;
101 }
102
97 while ((p = strsep(&options, ",")) != NULL) { 103 while ((p = strsep(&options, ",")) != NULL) {
98 int token; 104 int token;
99 if (!*p) 105 if (!*p)
100 continue; 106 continue;
101 token = match_token(p, tokens, args); 107 token = match_token(p, tokens, args);
102 if (token < Opt_uname) { 108 if (token < Opt_uname) {
103 ret = match_int(&args[0], &option); 109 int r = match_int(&args[0], &option);
104 if (ret < 0) { 110 if (r < 0) {
105 P9_DPRINTK(P9_DEBUG_ERROR, 111 P9_DPRINTK(P9_DEBUG_ERROR,
106 "integer field, but no integer?\n"); 112 "integer field, but no integer?\n");
113 ret = r;
107 continue; 114 continue;
108 } 115 }
109 } 116 }
@@ -125,10 +132,10 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
125 v9ses->afid = option; 132 v9ses->afid = option;
126 break; 133 break;
127 case Opt_uname: 134 case Opt_uname:
128 match_strcpy(v9ses->uname, &args[0]); 135 match_strlcpy(v9ses->uname, &args[0], PATH_MAX);
129 break; 136 break;
130 case Opt_remotename: 137 case Opt_remotename:
131 match_strcpy(v9ses->aname, &args[0]); 138 match_strlcpy(v9ses->aname, &args[0], PATH_MAX);
132 break; 139 break;
133 case Opt_nodevmap: 140 case Opt_nodevmap:
134 v9ses->nodev = 1; 141 v9ses->nodev = 1;
@@ -139,6 +146,13 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
139 146
140 case Opt_access: 147 case Opt_access:
141 s = match_strdup(&args[0]); 148 s = match_strdup(&args[0]);
149 if (!s) {
150 P9_DPRINTK(P9_DEBUG_ERROR,
151 "failed to allocate copy"
152 " of option argument\n");
153 ret = -ENOMEM;
154 break;
155 }
142 v9ses->flags &= ~V9FS_ACCESS_MASK; 156 v9ses->flags &= ~V9FS_ACCESS_MASK;
143 if (strcmp(s, "user") == 0) 157 if (strcmp(s, "user") == 0)
144 v9ses->flags |= V9FS_ACCESS_USER; 158 v9ses->flags |= V9FS_ACCESS_USER;
@@ -158,6 +172,7 @@ static void v9fs_parse_options(struct v9fs_session_info *v9ses)
158 } 172 }
159 } 173 }
160 kfree(options); 174 kfree(options);
175 return ret;
161} 176}
162 177
163/** 178/**
@@ -173,6 +188,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
173{ 188{
174 int retval = -EINVAL; 189 int retval = -EINVAL;
175 struct p9_fid *fid; 190 struct p9_fid *fid;
191 int rc;
176 192
177 v9ses->uname = __getname(); 193 v9ses->uname = __getname();
178 if (!v9ses->uname) 194 if (!v9ses->uname)
@@ -190,8 +206,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
190 v9ses->uid = ~0; 206 v9ses->uid = ~0;
191 v9ses->dfltuid = V9FS_DEFUID; 207 v9ses->dfltuid = V9FS_DEFUID;
192 v9ses->dfltgid = V9FS_DEFGID; 208 v9ses->dfltgid = V9FS_DEFGID;
193 v9ses->options = kstrdup(data, GFP_KERNEL); 209 if (data) {
194 v9fs_parse_options(v9ses); 210 v9ses->options = kstrdup(data, GFP_KERNEL);
211 if (!v9ses->options) {
212 P9_DPRINTK(P9_DEBUG_ERROR,
213 "failed to allocate copy of option string\n");
214 retval = -ENOMEM;
215 goto error;
216 }
217 }
218
219 rc = v9fs_parse_options(v9ses);
220 if (rc < 0) {
221 retval = rc;
222 goto error;
223 }
195 224
196 v9ses->clnt = p9_client_create(dev_name, v9ses->options); 225 v9ses->clnt = p9_client_create(dev_name, v9ses->options);
197 226
@@ -233,7 +262,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
233 return fid; 262 return fid;
234 263
235error: 264error:
236 v9fs_session_close(v9ses);
237 return ERR_PTR(retval); 265 return ERR_PTR(retval);
238} 266}
239 267
@@ -256,9 +284,12 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
256} 284}
257 285
258/** 286/**
259 * v9fs_session_cancel - mark transport as disconnected 287 * v9fs_session_cancel - terminate a session
260 * and cancel all pending requests. 288 * @v9ses: session to terminate
289 *
290 * mark transport as disconnected and cancel all pending requests.
261 */ 291 */
292
262void v9fs_session_cancel(struct v9fs_session_info *v9ses) { 293void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
263 P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); 294 P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
264 p9_client_disconnect(v9ses->clnt); 295 p9_client_disconnect(v9ses->clnt);
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 7d3a1018db52..a7d567192998 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -21,18 +21,69 @@
21 * 21 *
22 */ 22 */
23 23
24/* 24/**
25 * Session structure provides information for an opened session 25 * enum p9_session_flags - option flags for each 9P session
26 * 26 * @V9FS_EXTENDED: whether or not to use 9P2000.u extensions
27 */ 27 * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy
28 * @V9FS_ACCESS_USER: a new attach will be issued for every user (default)
29 * @V9FS_ACCESS_ANY: use a single attach for all users
30 * @V9FS_ACCESS_MASK: bit mask of different ACCESS options
31 *
32 * Session flags reflect options selected by users at mount time
33 */
34enum p9_session_flags {
35 V9FS_EXTENDED = 0x01,
36 V9FS_ACCESS_SINGLE = 0x02,
37 V9FS_ACCESS_USER = 0x04,
38 V9FS_ACCESS_ANY = 0x06,
39 V9FS_ACCESS_MASK = 0x06,
40};
41
42/* possible values of ->cache */
43/**
44 * enum p9_cache_modes - user specified cache preferences
45 * @CACHE_NONE: do not cache data, dentries, or directory contents (default)
46 * @CACHE_LOOSE: cache data, dentries, and directory contents w/no consistency
47 *
48 * eventually support loose, tight, time, session, default always none
49 */
50
51enum p9_cache_modes {
52 CACHE_NONE,
53 CACHE_LOOSE,
54};
55
56/**
57 * struct v9fs_session_info - per-instance session information
58 * @flags: session options of type &p9_session_flags
59 * @nodev: set to 1 to disable device mapping
60 * @debug: debug level
61 * @afid: authentication handle
62 * @cache: cache mode of type &p9_cache_modes
63 * @options: copy of options string given by user
64 * @uname: string user name to mount hierarchy as
65 * @aname: mount specifier for remote hierarchy
66 * @maxdata: maximum data to be sent/recvd per protocol message
67 * @dfltuid: default numeric userid to mount hierarchy as
68 * @dfltgid: default numeric groupid to mount hierarchy as
69 * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy
70 * @clnt: reference to 9P network client instantiated for this session
71 * @debugfs_dir: reference to debugfs_dir which can be used for add'l debug
72 *
73 * This structure holds state for each session instance established during
74 * a sys_mount() .
75 *
76 * Bugs: there seems to be a lot of state which could be condensed and/or
77 * removed.
78 */
28 79
29struct v9fs_session_info { 80struct v9fs_session_info {
30 /* options */ 81 /* options */
31 unsigned char flags; /* session flags */ 82 unsigned char flags;
32 unsigned char nodev; /* set to 1 if no disable device mapping */ 83 unsigned char nodev;
33 unsigned short debug; /* debug level */ 84 unsigned short debug;
34 unsigned int afid; /* authentication fid */ 85 unsigned int afid;
35 unsigned int cache; /* cache mode */ 86 unsigned int cache;
36 87
37 char *options; /* copy of mount options */ 88 char *options; /* copy of mount options */
38 char *uname; /* user name to mount as */ 89 char *uname; /* user name to mount as */
@@ -45,22 +96,6 @@ struct v9fs_session_info {
45 struct dentry *debugfs_dir; 96 struct dentry *debugfs_dir;
46}; 97};
47 98
48/* session flags */
49enum {
50 V9FS_EXTENDED = 0x01, /* 9P2000.u */
51 V9FS_ACCESS_MASK = 0x06, /* access mask */
52 V9FS_ACCESS_SINGLE = 0x02, /* only one user can access the files */
53 V9FS_ACCESS_USER = 0x04, /* attache per user */
54 V9FS_ACCESS_ANY = 0x06, /* use the same attach for all users */
55};
56
57/* possible values of ->cache */
58/* eventually support loose, tight, time, session, default always none */
59enum {
60 CACHE_NONE, /* default */
61 CACHE_LOOSE, /* no consistency */
62};
63
64extern struct dentry *v9fs_debugfs_root; 99extern struct dentry *v9fs_debugfs_root;
65 100
66struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, 101struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 6248f0e727a3..97d3aed57983 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -43,7 +43,7 @@
43/** 43/**
44 * v9fs_vfs_readpage - read an entire page in from 9P 44 * v9fs_vfs_readpage - read an entire page in from 9P
45 * 45 *
46 * @file: file being read 46 * @filp: file being read
47 * @page: structure to page 47 * @page: structure to page
48 * 48 *
49 */ 49 */
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 0924d4477da3..88e3787c6ea9 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -60,7 +60,7 @@ static inline int dt_type(struct p9_stat *mistat)
60 60
61/** 61/**
62 * v9fs_dir_readdir - read a directory 62 * v9fs_dir_readdir - read a directory
63 * @filep: opened file structure 63 * @filp: opened file structure
64 * @dirent: directory structure ??? 64 * @dirent: directory structure ???
65 * @filldir: function to populate directory structure ??? 65 * @filldir: function to populate directory structure ???
66 * 66 *
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index a616fff8906d..0d55affe37d4 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -90,10 +90,11 @@ int v9fs_file_open(struct inode *inode, struct file *file)
90 90
91/** 91/**
92 * v9fs_file_lock - lock a file (or directory) 92 * v9fs_file_lock - lock a file (or directory)
93 * @inode: inode to be opened 93 * @filp: file to be locked
94 * @file: file being opened 94 * @cmd: lock command
95 * @fl: file lock structure
95 * 96 *
96 * XXX - this looks like a local only lock, we should extend into 9P 97 * Bugs: this looks like a local only lock, we should extend into 9P
97 * by using open exclusive 98 * by using open exclusive
98 */ 99 */
99 100
@@ -118,7 +119,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
118 119
119/** 120/**
120 * v9fs_file_read - read from a file 121 * v9fs_file_read - read from a file
121 * @filep: file pointer to read 122 * @filp: file pointer to read
122 * @data: data buffer to read data into 123 * @data: data buffer to read data into
123 * @count: size of buffer 124 * @count: size of buffer
124 * @offset: offset at which to read data 125 * @offset: offset at which to read data
@@ -142,7 +143,7 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count,
142 143
143/** 144/**
144 * v9fs_file_write - write to a file 145 * v9fs_file_write - write to a file
145 * @filep: file pointer to write 146 * @filp: file pointer to write
146 * @data: data buffer to write data from 147 * @data: data buffer to write data from
147 * @count: size of buffer 148 * @count: size of buffer
148 * @offset: offset at which to write data 149 * @offset: offset at which to write data
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 6a28842052ea..40fa807bd929 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -129,6 +129,12 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
129 return res; 129 return res;
130} 130}
131 131
132/**
133 * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
134 * @uflags: flags to convert
135 *
136 */
137
132int v9fs_uflags2omode(int uflags) 138int v9fs_uflags2omode(int uflags)
133{ 139{
134 int ret; 140 int ret;
@@ -312,6 +318,14 @@ error:
312} 318}
313*/ 319*/
314 320
321/**
322 * v9fs_inode_from_fid - populate an inode by issuing a attribute request
323 * @v9ses: session information
324 * @fid: fid to issue attribute request for
325 * @sb: superblock on which to create inode
326 *
327 */
328
315static struct inode * 329static struct inode *
316v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 330v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
317 struct super_block *sb) 331 struct super_block *sb)
@@ -384,9 +398,12 @@ v9fs_open_created(struct inode *inode, struct file *file)
384 398
385/** 399/**
386 * v9fs_create - Create a file 400 * v9fs_create - Create a file
401 * @v9ses: session information
402 * @dir: directory that dentry is being created in
387 * @dentry: dentry that is being created 403 * @dentry: dentry that is being created
388 * @perm: create permissions 404 * @perm: create permissions
389 * @mode: open mode 405 * @mode: open mode
406 * @extension: 9p2000.u extension string to support devices, etc.
390 * 407 *
391 */ 408 */
392static struct p9_fid * 409static struct p9_fid *
@@ -461,7 +478,7 @@ error:
461 478
462/** 479/**
463 * v9fs_vfs_create - VFS hook to create files 480 * v9fs_vfs_create - VFS hook to create files
464 * @inode: directory inode that is being created 481 * @dir: directory inode that is being created
465 * @dentry: dentry that is being deleted 482 * @dentry: dentry that is being deleted
466 * @mode: create permissions 483 * @mode: create permissions
467 * @nd: path information 484 * @nd: path information
@@ -519,7 +536,7 @@ error:
519 536
520/** 537/**
521 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory 538 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
522 * @inode: inode that is being unlinked 539 * @dir: inode that is being unlinked
523 * @dentry: dentry that is being unlinked 540 * @dentry: dentry that is being unlinked
524 * @mode: mode for new directory 541 * @mode: mode for new directory
525 * 542 *
@@ -703,9 +720,9 @@ done:
703 720
704/** 721/**
705 * v9fs_vfs_getattr - retrieve file metadata 722 * v9fs_vfs_getattr - retrieve file metadata
706 * @mnt - mount information 723 * @mnt: mount information
707 * @dentry - file to get attributes on 724 * @dentry: file to get attributes on
708 * @stat - metadata structure to populate 725 * @stat: metadata structure to populate
709 * 726 *
710 */ 727 */
711 728
@@ -928,7 +945,7 @@ done:
928/** 945/**
929 * v9fs_vfs_readlink - read a symlink's location 946 * v9fs_vfs_readlink - read a symlink's location
930 * @dentry: dentry for symlink 947 * @dentry: dentry for symlink
931 * @buf: buffer to load symlink location into 948 * @buffer: buffer to load symlink location into
932 * @buflen: length of buffer 949 * @buflen: length of buffer
933 * 950 *
934 */ 951 */
@@ -996,10 +1013,12 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
996 * v9fs_vfs_put_link - release a symlink path 1013 * v9fs_vfs_put_link - release a symlink path
997 * @dentry: dentry for symlink 1014 * @dentry: dentry for symlink
998 * @nd: nameidata 1015 * @nd: nameidata
1016 * @p: unused
999 * 1017 *
1000 */ 1018 */
1001 1019
1002static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) 1020static void
1021v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1003{ 1022{
1004 char *s = nd_get_link(nd); 1023 char *s = nd_get_link(nd);
1005 1024
@@ -1008,6 +1027,15 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
1008 __putname(s); 1027 __putname(s);
1009} 1028}
1010 1029
1030/**
1031 * v9fs_vfs_mkspecial - create a special file
1032 * @dir: inode to create special file in
1033 * @dentry: dentry to create
1034 * @mode: mode to create special file
1035 * @extension: 9p2000.u format extension string representing special file
1036 *
1037 */
1038
1011static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, 1039static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1012 int mode, const char *extension) 1040 int mode, const char *extension)
1013{ 1041{
@@ -1037,7 +1065,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1037 * @dentry: dentry for symlink 1065 * @dentry: dentry for symlink
1038 * @symname: symlink data 1066 * @symname: symlink data
1039 * 1067 *
1040 * See 9P2000.u RFC for more information 1068 * See Also: 9P2000.u RFC for more information
1041 * 1069 *
1042 */ 1070 */
1043 1071
@@ -1058,10 +1086,6 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
1058 * 1086 *
1059 */ 1087 */
1060 1088
1061/* XXX - lots of code dup'd from symlink and creates,
1062 * figure out a better reuse strategy
1063 */
1064
1065static int 1089static int
1066v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, 1090v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1067 struct dentry *dentry) 1091 struct dentry *dentry)
@@ -1098,7 +1122,7 @@ clunk_fid:
1098 * @dir: inode destination for new link 1122 * @dir: inode destination for new link
1099 * @dentry: dentry for file 1123 * @dentry: dentry for file
1100 * @mode: mode for creation 1124 * @mode: mode for creation
1101 * @dev_t: device associated with special file 1125 * @rdev: device associated with special file
1102 * 1126 *
1103 */ 1127 */
1104 1128
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index a452ac67fc94..bf59c3960494 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -75,6 +75,7 @@ static int v9fs_set_super(struct super_block *s, void *data)
75 * v9fs_fill_super - populate superblock with info 75 * v9fs_fill_super - populate superblock with info
76 * @sb: superblock 76 * @sb: superblock
77 * @v9ses: session information 77 * @v9ses: session information
78 * @flags: flags propagated from v9fs_get_sb()
78 * 79 *
79 */ 80 */
80 81
@@ -127,29 +128,26 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
127 fid = v9fs_session_init(v9ses, dev_name, data); 128 fid = v9fs_session_init(v9ses, dev_name, data);
128 if (IS_ERR(fid)) { 129 if (IS_ERR(fid)) {
129 retval = PTR_ERR(fid); 130 retval = PTR_ERR(fid);
130 fid = NULL; 131 goto close_session;
131 kfree(v9ses);
132 v9ses = NULL;
133 goto error;
134 } 132 }
135 133
136 st = p9_client_stat(fid); 134 st = p9_client_stat(fid);
137 if (IS_ERR(st)) { 135 if (IS_ERR(st)) {
138 retval = PTR_ERR(st); 136 retval = PTR_ERR(st);
139 goto error; 137 goto clunk_fid;
140 } 138 }
141 139
142 sb = sget(fs_type, NULL, v9fs_set_super, v9ses); 140 sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
143 if (IS_ERR(sb)) { 141 if (IS_ERR(sb)) {
144 retval = PTR_ERR(sb); 142 retval = PTR_ERR(sb);
145 goto error; 143 goto free_stat;
146 } 144 }
147 v9fs_fill_super(sb, v9ses, flags); 145 v9fs_fill_super(sb, v9ses, flags);
148 146
149 inode = v9fs_get_inode(sb, S_IFDIR | mode); 147 inode = v9fs_get_inode(sb, S_IFDIR | mode);
150 if (IS_ERR(inode)) { 148 if (IS_ERR(inode)) {
151 retval = PTR_ERR(inode); 149 retval = PTR_ERR(inode);
152 goto error; 150 goto release_sb;
153 } 151 }
154 152
155 inode->i_uid = uid; 153 inode->i_uid = uid;
@@ -158,7 +156,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
158 root = d_alloc_root(inode); 156 root = d_alloc_root(inode);
159 if (!root) { 157 if (!root) {
160 retval = -ENOMEM; 158 retval = -ENOMEM;
161 goto error; 159 goto release_sb;
162 } 160 }
163 161
164 sb->s_root = root; 162 sb->s_root = root;
@@ -169,21 +167,22 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
169 167
170 return simple_set_mnt(mnt, sb); 168 return simple_set_mnt(mnt, sb);
171 169
172error: 170release_sb:
173 kfree(st);
174 if (fid)
175 p9_client_clunk(fid);
176
177 if (v9ses) {
178 v9fs_session_close(v9ses);
179 kfree(v9ses);
180 }
181
182 if (sb) { 171 if (sb) {
183 up_write(&sb->s_umount); 172 up_write(&sb->s_umount);
184 deactivate_super(sb); 173 deactivate_super(sb);
185 } 174 }
186 175
176free_stat:
177 kfree(st);
178
179clunk_fid:
180 p9_client_clunk(fid);
181
182close_session:
183 v9fs_session_close(v9ses);
184 kfree(v9ses);
185
187 return retval; 186 return retval;
188} 187}
189 188