aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 12:25:11 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-28 12:25:11 -0400
commit90a2b69c14d0f0b6cbd124caf429ae9033f0615c (patch)
tree9aa18ac045eec9515ed225f900717e8a5f4fd8d6
parente430426654c6a99fb1977bae71d4844e876c4a52 (diff)
parentf6ac55b6c156cebf750376dc08e06ffdade82717 (diff)
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: (28 commits) net/9p: Return error on read with NULL buffer 9p: Add datasync to client side TFSYNC/RFSYNC for dotl net/9p: Return error if we fail to encode protocol data fs/9p: Use generic_file_open with lookup_instantiate_filp fs/9p: Add missing iput in v9fs_vfs_lookup fs/9p: Use mknod 9p operation on create without open request net/9p: Add waitq to VirtIO transport. [net/9p]Serialize virtqueue operations to make VirtIO transport SMP safe. 9p: Implement TREADLINK operation for 9p2000.L 9p: Use V9FS_MAGIC in statfs 9p: Implement TGETLOCK 9p: Implement TLOCK [9p] Introduce client side TFSYNC/RFSYNC for dotl. [fs/9p] Add file_operations for cached mode in dotl protocol. fs/9p: Add access = client option to opt in acl evaluation. fs/9p: Implement create time inheritance fs/9p: Update ACL on chmod fs/9p: Implement setting posix acl fs/9p: Add xattr callbacks for POSIX ACL fs/9p: Implement POSIX ACL permission checking function ...
-rw-r--r--Documentation/filesystems/9p.txt4
-rw-r--r--fs/9p/Kconfig13
-rw-r--r--fs/9p/Makefile1
-rw-r--r--fs/9p/acl.c392
-rw-r--r--fs/9p/acl.h49
-rw-r--r--fs/9p/fid.c1
-rw-r--r--fs/9p/v9fs.c22
-rw-r--r--fs/9p/v9fs.h10
-rw-r--r--fs/9p/v9fs_vfs.h4
-rw-r--r--fs/9p/vfs_addr.c30
-rw-r--r--fs/9p/vfs_dir.c4
-rw-r--r--fs/9p/vfs_file.c265
-rw-r--r--fs/9p/vfs_inode.c253
-rw-r--r--fs/9p/vfs_super.c14
-rw-r--r--fs/9p/xattr.c52
-rw-r--r--fs/9p/xattr.h6
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/net/9p/9p.h54
-rw-r--r--include/net/9p/client.h4
-rw-r--r--net/9p/client.c178
-rw-r--r--net/9p/protocol.c5
-rw-r--r--net/9p/trans_virtio.c76
22 files changed, 1288 insertions, 150 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index f9765e8cf086..b22abba78fed 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -111,7 +111,7 @@ OPTIONS
111 This can be used to share devices/named pipes/sockets between 111 This can be used to share devices/named pipes/sockets between
112 hosts. This functionality will be expanded in later versions. 112 hosts. This functionality will be expanded in later versions.
113 113
114 access there are three access modes. 114 access there are four access modes.
115 user = if a user tries to access a file on v9fs 115 user = if a user tries to access a file on v9fs
116 filesystem for the first time, v9fs sends an 116 filesystem for the first time, v9fs sends an
117 attach command (Tattach) for that user. 117 attach command (Tattach) for that user.
@@ -120,6 +120,8 @@ OPTIONS
120 the files on the mounted filesystem 120 the files on the mounted filesystem
121 any = v9fs does single attach and performs all 121 any = v9fs does single attach and performs all
122 operations as one user 122 operations as one user
123 client = ACL based access check on the 9p client
124 side for access validation
123 125
124 cachetag cache tag to use the specified persistent cache. 126 cachetag cache tag to use the specified persistent cache.
125 cache tags for existing cache sessions can be listed at 127 cache tags for existing cache sessions can be listed at
diff --git a/fs/9p/Kconfig b/fs/9p/Kconfig
index 795233702a4e..7e0511476797 100644
--- a/fs/9p/Kconfig
+++ b/fs/9p/Kconfig
@@ -17,3 +17,16 @@ config 9P_FSCACHE
17 Choose Y here to enable persistent, read-only local 17 Choose Y here to enable persistent, read-only local
18 caching support for 9p clients using FS-Cache 18 caching support for 9p clients using FS-Cache
19 19
20
21config 9P_FS_POSIX_ACL
22 bool "9P POSIX Access Control Lists"
23 depends on 9P_FS
24 select FS_POSIX_ACL
25 help
26 POSIX Access Control Lists (ACLs) support permissions for users and
27 groups beyond the owner/group/world scheme.
28
29 To learn more about Access Control Lists, visit the POSIX ACLs for
30 Linux website <http://acl.bestbits.at/>.
31
32 If you don't know what Access Control Lists are, say N
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index 91fba025fcbe..f8ba37effd1b 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o
13 xattr_user.o 13 xattr_user.o
14 14
159p-$(CONFIG_9P_FSCACHE) += cache.o 159p-$(CONFIG_9P_FSCACHE) += cache.o
169p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
new file mode 100644
index 000000000000..12d602351dbe
--- /dev/null
+++ b/fs/9p/acl.c
@@ -0,0 +1,392 @@
1/*
2 * Copyright IBM Corporation, 2010
3 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2.1 of the GNU Lesser General Public License
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/fs.h>
17#include <net/9p/9p.h>
18#include <net/9p/client.h>
19#include <linux/slab.h>
20#include <linux/sched.h>
21#include <linux/posix_acl_xattr.h>
22#include "xattr.h"
23#include "acl.h"
24#include "v9fs_vfs.h"
25#include "v9fs.h"
26
27static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
28{
29 ssize_t size;
30 void *value = NULL;
31 struct posix_acl *acl = NULL;;
32
33 size = v9fs_fid_xattr_get(fid, name, NULL, 0);
34 if (size > 0) {
35 value = kzalloc(size, GFP_NOFS);
36 if (!value)
37 return ERR_PTR(-ENOMEM);
38 size = v9fs_fid_xattr_get(fid, name, value, size);
39 if (size > 0) {
40 acl = posix_acl_from_xattr(value, size);
41 if (IS_ERR(acl))
42 goto err_out;
43 }
44 } else if (size == -ENODATA || size == 0 ||
45 size == -ENOSYS || size == -EOPNOTSUPP) {
46 acl = NULL;
47 } else
48 acl = ERR_PTR(-EIO);
49
50err_out:
51 kfree(value);
52 return acl;
53}
54
55int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
56{
57 int retval = 0;
58 struct posix_acl *pacl, *dacl;
59 struct v9fs_session_info *v9ses;
60
61 v9ses = v9fs_inode2v9ses(inode);
62 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
63 set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
64 set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
65 return 0;
66 }
67 /* get the default/access acl values and cache them */
68 dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
69 pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
70
71 if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
72 set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
73 set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
74 posix_acl_release(dacl);
75 posix_acl_release(pacl);
76 } else
77 retval = -EIO;
78
79 return retval;
80}
81
82static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
83{
84 struct posix_acl *acl;
85 /*
86 * 9p Always cache the acl value when
87 * instantiating the inode (v9fs_inode_from_fid)
88 */
89 acl = get_cached_acl(inode, type);
90 BUG_ON(acl == ACL_NOT_CACHED);
91 return acl;
92}
93
94int v9fs_check_acl(struct inode *inode, int mask)
95{
96 struct posix_acl *acl;
97 struct v9fs_session_info *v9ses;
98
99 v9ses = v9fs_inode2v9ses(inode);
100 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
101 /*
102 * On access = client mode get the acl
103 * values from the server
104 */
105 return 0;
106 }
107 acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
108
109 if (IS_ERR(acl))
110 return PTR_ERR(acl);
111 if (acl) {
112 int error = posix_acl_permission(inode, acl, mask);
113 posix_acl_release(acl);
114 return error;
115 }
116 return -EAGAIN;
117}
118
119static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
120{
121 int retval;
122 char *name;
123 size_t size;
124 void *buffer;
125 struct inode *inode = dentry->d_inode;
126
127 set_cached_acl(inode, type, acl);
128 /* Set a setxattr request to server */
129 size = posix_acl_xattr_size(acl->a_count);
130 buffer = kmalloc(size, GFP_KERNEL);
131 if (!buffer)
132 return -ENOMEM;
133 retval = posix_acl_to_xattr(acl, buffer, size);
134 if (retval < 0)
135 goto err_free_out;
136 switch (type) {
137 case ACL_TYPE_ACCESS:
138 name = POSIX_ACL_XATTR_ACCESS;
139 break;
140 case ACL_TYPE_DEFAULT:
141 name = POSIX_ACL_XATTR_DEFAULT;
142 break;
143 default:
144 BUG();
145 }
146 retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
147err_free_out:
148 kfree(buffer);
149 return retval;
150}
151
152int v9fs_acl_chmod(struct dentry *dentry)
153{
154 int retval = 0;
155 struct posix_acl *acl, *clone;
156 struct inode *inode = dentry->d_inode;
157
158 if (S_ISLNK(inode->i_mode))
159 return -EOPNOTSUPP;
160 acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
161 if (acl) {
162 clone = posix_acl_clone(acl, GFP_KERNEL);
163 posix_acl_release(acl);
164 if (!clone)
165 return -ENOMEM;
166 retval = posix_acl_chmod_masq(clone, inode->i_mode);
167 if (!retval)
168 retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
169 posix_acl_release(clone);
170 }
171 return retval;
172}
173
174int v9fs_set_create_acl(struct dentry *dentry,
175 struct posix_acl *dpacl, struct posix_acl *pacl)
176{
177 if (dpacl)
178 v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
179 if (pacl)
180 v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
181 posix_acl_release(dpacl);
182 posix_acl_release(pacl);
183 return 0;
184}
185
186int v9fs_acl_mode(struct inode *dir, mode_t *modep,
187 struct posix_acl **dpacl, struct posix_acl **pacl)
188{
189 int retval = 0;
190 mode_t mode = *modep;
191 struct posix_acl *acl = NULL;
192
193 if (!S_ISLNK(mode)) {
194 acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
195 if (IS_ERR(acl))
196 return PTR_ERR(acl);
197 if (!acl)
198 mode &= ~current_umask();
199 }
200 if (acl) {
201 struct posix_acl *clone;
202
203 if (S_ISDIR(mode))
204 *dpacl = acl;
205 clone = posix_acl_clone(acl, GFP_NOFS);
206 retval = -ENOMEM;
207 if (!clone)
208 goto cleanup;
209
210 retval = posix_acl_create_masq(clone, &mode);
211 if (retval < 0) {
212 posix_acl_release(clone);
213 goto cleanup;
214 }
215 if (retval > 0)
216 *pacl = clone;
217 }
218 *modep = mode;
219 return 0;
220cleanup:
221 posix_acl_release(acl);
222 return retval;
223
224}
225
226static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
227 void *buffer, size_t size, int type)
228{
229 char *full_name;
230
231 switch (type) {
232 case ACL_TYPE_ACCESS:
233 full_name = POSIX_ACL_XATTR_ACCESS;
234 break;
235 case ACL_TYPE_DEFAULT:
236 full_name = POSIX_ACL_XATTR_DEFAULT;
237 break;
238 default:
239 BUG();
240 }
241 return v9fs_xattr_get(dentry, full_name, buffer, size);
242}
243
244static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
245 void *buffer, size_t size, int type)
246{
247 struct v9fs_session_info *v9ses;
248 struct posix_acl *acl;
249 int error;
250
251 if (strcmp(name, "") != 0)
252 return -EINVAL;
253
254 v9ses = v9fs_inode2v9ses(dentry->d_inode);
255 /*
256 * We allow set/get/list of acl when access=client is not specified
257 */
258 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
259 return v9fs_remote_get_acl(dentry, name, buffer, size, type);
260
261 acl = v9fs_get_cached_acl(dentry->d_inode, type);
262 if (IS_ERR(acl))
263 return PTR_ERR(acl);
264 if (acl == NULL)
265 return -ENODATA;
266 error = posix_acl_to_xattr(acl, buffer, size);
267 posix_acl_release(acl);
268
269 return error;
270}
271
272static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
273 const void *value, size_t size,
274 int flags, int type)
275{
276 char *full_name;
277
278 switch (type) {
279 case ACL_TYPE_ACCESS:
280 full_name = POSIX_ACL_XATTR_ACCESS;
281 break;
282 case ACL_TYPE_DEFAULT:
283 full_name = POSIX_ACL_XATTR_DEFAULT;
284 break;
285 default:
286 BUG();
287 }
288 return v9fs_xattr_set(dentry, full_name, value, size, flags);
289}
290
291
292static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
293 const void *value, size_t size,
294 int flags, int type)
295{
296 int retval;
297 struct posix_acl *acl;
298 struct v9fs_session_info *v9ses;
299 struct inode *inode = dentry->d_inode;
300
301 if (strcmp(name, "") != 0)
302 return -EINVAL;
303
304 v9ses = v9fs_inode2v9ses(dentry->d_inode);
305 /*
306 * set the attribute on the remote. Without even looking at the
307 * xattr value. We leave it to the server to validate
308 */
309 if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
310 return v9fs_remote_set_acl(dentry, name,
311 value, size, flags, type);
312
313 if (S_ISLNK(inode->i_mode))
314 return -EOPNOTSUPP;
315 if (!is_owner_or_cap(inode))
316 return -EPERM;
317 if (value) {
318 /* update the cached acl value */
319 acl = posix_acl_from_xattr(value, size);
320 if (IS_ERR(acl))
321 return PTR_ERR(acl);
322 else if (acl) {
323 retval = posix_acl_valid(acl);
324 if (retval)
325 goto err_out;
326 }
327 } else
328 acl = NULL;
329
330 switch (type) {
331 case ACL_TYPE_ACCESS:
332 name = POSIX_ACL_XATTR_ACCESS;
333 if (acl) {
334 mode_t mode = inode->i_mode;
335 retval = posix_acl_equiv_mode(acl, &mode);
336 if (retval < 0)
337 goto err_out;
338 else {
339 struct iattr iattr;
340 if (retval == 0) {
341 /*
342 * ACL can be represented
343 * by the mode bits. So don't
344 * update ACL.
345 */
346 acl = NULL;
347 value = NULL;
348 size = 0;
349 }
350 /* Updte the mode bits */
351 iattr.ia_mode = ((mode & S_IALLUGO) |
352 (inode->i_mode & ~S_IALLUGO));
353 iattr.ia_valid = ATTR_MODE;
354 /* FIXME should we update ctime ?
355 * What is the following setxattr update the
356 * mode ?
357 */
358 v9fs_vfs_setattr_dotl(dentry, &iattr);
359 }
360 }
361 break;
362 case ACL_TYPE_DEFAULT:
363 name = POSIX_ACL_XATTR_DEFAULT;
364 if (!S_ISDIR(inode->i_mode)) {
365 retval = -EINVAL;
366 goto err_out;
367 }
368 break;
369 default:
370 BUG();
371 }
372 retval = v9fs_xattr_set(dentry, name, value, size, flags);
373 if (!retval)
374 set_cached_acl(inode, type, acl);
375err_out:
376 posix_acl_release(acl);
377 return retval;
378}
379
380const struct xattr_handler v9fs_xattr_acl_access_handler = {
381 .prefix = POSIX_ACL_XATTR_ACCESS,
382 .flags = ACL_TYPE_ACCESS,
383 .get = v9fs_xattr_get_acl,
384 .set = v9fs_xattr_set_acl,
385};
386
387const struct xattr_handler v9fs_xattr_acl_default_handler = {
388 .prefix = POSIX_ACL_XATTR_DEFAULT,
389 .flags = ACL_TYPE_DEFAULT,
390 .get = v9fs_xattr_get_acl,
391 .set = v9fs_xattr_set_acl,
392};
diff --git a/fs/9p/acl.h b/fs/9p/acl.h
new file mode 100644
index 000000000000..59e18c2e8c7e
--- /dev/null
+++ b/fs/9p/acl.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright IBM Corporation, 2010
3 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2.1 of the GNU Lesser General Public License
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 */
14#ifndef FS_9P_ACL_H
15#define FS_9P_ACL_H
16
17#ifdef CONFIG_9P_FS_POSIX_ACL
18extern int v9fs_get_acl(struct inode *, struct p9_fid *);
19extern int v9fs_check_acl(struct inode *inode, int mask);
20extern int v9fs_acl_chmod(struct dentry *);
21extern int v9fs_set_create_acl(struct dentry *,
22 struct posix_acl *, struct posix_acl *);
23extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
24 struct posix_acl **dpacl, struct posix_acl **pacl);
25#else
26#define v9fs_check_acl NULL
27static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
28{
29 return 0;
30}
31static inline int v9fs_acl_chmod(struct dentry *dentry)
32{
33 return 0;
34}
35static inline int v9fs_set_create_acl(struct dentry *dentry,
36 struct posix_acl *dpacl,
37 struct posix_acl *pacl)
38{
39 return 0;
40}
41static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
42 struct posix_acl **dpacl,
43 struct posix_acl **pacl)
44{
45 return 0;
46}
47
48#endif
49#endif /* FS_9P_XATTR_H */
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 6406f896bf95..b00223c99d70 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
149 switch (access) { 149 switch (access) {
150 case V9FS_ACCESS_SINGLE: 150 case V9FS_ACCESS_SINGLE:
151 case V9FS_ACCESS_USER: 151 case V9FS_ACCESS_USER:
152 case V9FS_ACCESS_CLIENT:
152 uid = current_fsuid(); 153 uid = current_fsuid();
153 any = 0; 154 any = 0;
154 break; 155 break;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 38dc0e067599..2f77cd33ba83 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
193 v9ses->flags |= V9FS_ACCESS_USER; 193 v9ses->flags |= V9FS_ACCESS_USER;
194 else if (strcmp(s, "any") == 0) 194 else if (strcmp(s, "any") == 0)
195 v9ses->flags |= V9FS_ACCESS_ANY; 195 v9ses->flags |= V9FS_ACCESS_ANY;
196 else { 196 else if (strcmp(s, "client") == 0) {
197#ifdef CONFIG_9P_FS_POSIX_ACL
198 v9ses->flags |= V9FS_ACCESS_CLIENT;
199#else
200 P9_DPRINTK(P9_DEBUG_ERROR,
201 "access=client option not supported\n");
202 kfree(s);
203 ret = -EINVAL;
204 goto free_and_return;
205#endif
206 } else {
197 v9ses->flags |= V9FS_ACCESS_SINGLE; 207 v9ses->flags |= V9FS_ACCESS_SINGLE;
198 v9ses->uid = simple_strtoul(s, &e, 10); 208 v9ses->uid = simple_strtoul(s, &e, 10);
199 if (*e != '\0') 209 if (*e != '\0')
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
278 288
279 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; 289 v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
280 290
291 if (!v9fs_proto_dotl(v9ses) &&
292 ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
293 /*
294 * We support ACCESS_CLIENT only for dotl.
295 * Fall back to ACCESS_USER
296 */
297 v9ses->flags &= ~V9FS_ACCESS_MASK;
298 v9ses->flags |= V9FS_ACCESS_USER;
299 }
300 /*FIXME !! */
281 /* for legacy mode, fall back to V9FS_ACCESS_ANY */ 301 /* for legacy mode, fall back to V9FS_ACCESS_ANY */
282 if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) && 302 if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
283 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { 303 ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 4c963c9fc41f..cb6396855e2d 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -33,13 +33,17 @@
33 * 33 *
34 * Session flags reflect options selected by users at mount time 34 * Session flags reflect options selected by users at mount time
35 */ 35 */
36#define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
37 V9FS_ACCESS_USER | \
38 V9FS_ACCESS_CLIENT)
39#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
40
36enum p9_session_flags { 41enum p9_session_flags {
37 V9FS_PROTO_2000U = 0x01, 42 V9FS_PROTO_2000U = 0x01,
38 V9FS_PROTO_2000L = 0x02, 43 V9FS_PROTO_2000L = 0x02,
39 V9FS_ACCESS_SINGLE = 0x04, 44 V9FS_ACCESS_SINGLE = 0x04,
40 V9FS_ACCESS_USER = 0x08, 45 V9FS_ACCESS_USER = 0x08,
41 V9FS_ACCESS_ANY = 0x0C, 46 V9FS_ACCESS_CLIENT = 0x10
42 V9FS_ACCESS_MASK = 0x0C,
43}; 47};
44 48
45/* possible values of ->cache */ 49/* possible values of ->cache */
@@ -113,8 +117,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses);
113void v9fs_session_cancel(struct v9fs_session_info *v9ses); 117void v9fs_session_cancel(struct v9fs_session_info *v9ses);
114void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); 118void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
115 119
116#define V9FS_MAGIC 0x01021997
117
118/* other default globals */ 120/* other default globals */
119#define V9FS_PORT 564 121#define V9FS_PORT 564
120#define V9FS_DEFUSER "nobody" 122#define V9FS_DEFUSER "nobody"
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 88418c419ea7..bab0eac873f4 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -64,3 +64,7 @@ int v9fs_uflags2omode(int uflags, int extended);
64 64
65ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); 65ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
66void v9fs_blank_wstat(struct p9_wstat *wstat); 66void v9fs_blank_wstat(struct p9_wstat *wstat);
67int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
68int v9fs_file_fsync_dotl(struct file *filp, int datasync);
69
70#define P9_LOCK_TIMEOUT (30*HZ)
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 90e38449f4b3..b7f2a8e3863e 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -154,10 +154,40 @@ static int v9fs_launder_page(struct page *page)
154 return 0; 154 return 0;
155} 155}
156 156
157/**
158 * v9fs_direct_IO - 9P address space operation for direct I/O
159 * @rw: direction (read or write)
160 * @iocb: target I/O control block
161 * @iov: array of vectors that define I/O buffer
162 * @pos: offset in file to begin the operation
163 * @nr_segs: size of iovec array
164 *
165 * The presence of v9fs_direct_IO() in the address space ops vector
166 * allowes open() O_DIRECT flags which would have failed otherwise.
167 *
168 * In the non-cached mode, we shunt off direct read and write requests before
169 * the VFS gets them, so this method should never be called.
170 *
171 * Direct IO is not 'yet' supported in the cached mode. Hence when
172 * this routine is called through generic_file_aio_read(), the read/write fails
173 * with an error.
174 *
175 */
176ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
177 loff_t pos, unsigned long nr_segs)
178{
179 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) "
180 "off/no(%lld/%lu) EINVAL\n",
181 iocb->ki_filp->f_path.dentry->d_name.name,
182 (long long) pos, nr_segs);
183
184 return -EINVAL;
185}
157const struct address_space_operations v9fs_addr_operations = { 186const struct address_space_operations v9fs_addr_operations = {
158 .readpage = v9fs_vfs_readpage, 187 .readpage = v9fs_vfs_readpage,
159 .readpages = v9fs_vfs_readpages, 188 .readpages = v9fs_vfs_readpages,
160 .releasepage = v9fs_release_page, 189 .releasepage = v9fs_release_page,
161 .invalidatepage = v9fs_invalidate_page, 190 .invalidatepage = v9fs_invalidate_page,
162 .launder_page = v9fs_launder_page, 191 .launder_page = v9fs_launder_page,
192 .direct_IO = v9fs_direct_IO,
163}; 193};
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 899f168fd19c..b84ebe8cefed 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -242,7 +242,8 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
242 while (rdir->head < rdir->tail) { 242 while (rdir->head < rdir->tail) {
243 243
244 err = p9dirent_read(rdir->buf + rdir->head, 244 err = p9dirent_read(rdir->buf + rdir->head,
245 buflen - rdir->head, &curdirent, 245 rdir->tail - rdir->head,
246 &curdirent,
246 fid->clnt->proto_version); 247 fid->clnt->proto_version);
247 if (err < 0) { 248 if (err < 0) {
248 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); 249 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
@@ -314,4 +315,5 @@ const struct file_operations v9fs_dir_operations_dotl = {
314 .readdir = v9fs_dir_readdir_dotl, 315 .readdir = v9fs_dir_readdir_dotl,
315 .open = v9fs_file_open, 316 .open = v9fs_file_open,
316 .release = v9fs_dir_release, 317 .release = v9fs_dir_release,
318 .fsync = v9fs_file_fsync_dotl,
317}; 319};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index e97c92bd6f16..240c30674396 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -33,6 +33,7 @@
33#include <linux/inet.h> 33#include <linux/inet.h>
34#include <linux/list.h> 34#include <linux/list.h>
35#include <linux/pagemap.h> 35#include <linux/pagemap.h>
36#include <linux/utsname.h>
36#include <asm/uaccess.h> 37#include <asm/uaccess.h>
37#include <linux/idr.h> 38#include <linux/idr.h>
38#include <net/9p/9p.h> 39#include <net/9p/9p.h>
@@ -44,6 +45,7 @@
44#include "cache.h" 45#include "cache.h"
45 46
46static const struct file_operations v9fs_cached_file_operations; 47static const struct file_operations v9fs_cached_file_operations;
48static const struct file_operations v9fs_cached_file_operations_dotl;
47 49
48/** 50/**
49 * v9fs_file_open - open a file (or directory) 51 * v9fs_file_open - open a file (or directory)
@@ -92,6 +94,8 @@ int v9fs_file_open(struct inode *inode, struct file *file)
92 /* enable cached file options */ 94 /* enable cached file options */
93 if(file->f_op == &v9fs_file_operations) 95 if(file->f_op == &v9fs_file_operations)
94 file->f_op = &v9fs_cached_file_operations; 96 file->f_op = &v9fs_cached_file_operations;
97 else if (file->f_op == &v9fs_file_operations_dotl)
98 file->f_op = &v9fs_cached_file_operations_dotl;
95 99
96#ifdef CONFIG_9P_FSCACHE 100#ifdef CONFIG_9P_FSCACHE
97 v9fs_cache_inode_set_cookie(inode, file); 101 v9fs_cache_inode_set_cookie(inode, file);
@@ -130,6 +134,206 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
130 return res; 134 return res;
131} 135}
132 136
137static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
138{
139 struct p9_flock flock;
140 struct p9_fid *fid;
141 uint8_t status;
142 int res = 0;
143 unsigned char fl_type;
144
145 fid = filp->private_data;
146 BUG_ON(fid == NULL);
147
148 if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
149 BUG();
150
151 res = posix_lock_file_wait(filp, fl);
152 if (res < 0)
153 goto out;
154
155 /* convert posix lock to p9 tlock args */
156 memset(&flock, 0, sizeof(flock));
157 flock.type = fl->fl_type;
158 flock.start = fl->fl_start;
159 if (fl->fl_end == OFFSET_MAX)
160 flock.length = 0;
161 else
162 flock.length = fl->fl_end - fl->fl_start + 1;
163 flock.proc_id = fl->fl_pid;
164 flock.client_id = utsname()->nodename;
165 if (IS_SETLKW(cmd))
166 flock.flags = P9_LOCK_FLAGS_BLOCK;
167
168 /*
169 * if its a blocked request and we get P9_LOCK_BLOCKED as the status
170 * for lock request, keep on trying
171 */
172 for (;;) {
173 res = p9_client_lock_dotl(fid, &flock, &status);
174 if (res < 0)
175 break;
176
177 if (status != P9_LOCK_BLOCKED)
178 break;
179 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
180 break;
181 schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
182 }
183
184 /* map 9p status to VFS status */
185 switch (status) {
186 case P9_LOCK_SUCCESS:
187 res = 0;
188 break;
189 case P9_LOCK_BLOCKED:
190 res = -EAGAIN;
191 break;
192 case P9_LOCK_ERROR:
193 case P9_LOCK_GRACE:
194 res = -ENOLCK;
195 break;
196 default:
197 BUG();
198 }
199
200 /*
201 * incase server returned error for lock request, revert
202 * it locally
203 */
204 if (res < 0 && fl->fl_type != F_UNLCK) {
205 fl_type = fl->fl_type;
206 fl->fl_type = F_UNLCK;
207 res = posix_lock_file_wait(filp, fl);
208 fl->fl_type = fl_type;
209 }
210out:
211 return res;
212}
213
214static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
215{
216 struct p9_getlock glock;
217 struct p9_fid *fid;
218 int res = 0;
219
220 fid = filp->private_data;
221 BUG_ON(fid == NULL);
222
223 posix_test_lock(filp, fl);
224 /*
225 * if we have a conflicting lock locally, no need to validate
226 * with server
227 */
228 if (fl->fl_type != F_UNLCK)
229 return res;
230
231 /* convert posix lock to p9 tgetlock args */
232 memset(&glock, 0, sizeof(glock));
233 glock.type = fl->fl_type;
234 glock.start = fl->fl_start;
235 if (fl->fl_end == OFFSET_MAX)
236 glock.length = 0;
237 else
238 glock.length = fl->fl_end - fl->fl_start + 1;
239 glock.proc_id = fl->fl_pid;
240 glock.client_id = utsname()->nodename;
241
242 res = p9_client_getlock_dotl(fid, &glock);
243 if (res < 0)
244 return res;
245 if (glock.type != F_UNLCK) {
246 fl->fl_type = glock.type;
247 fl->fl_start = glock.start;
248 if (glock.length == 0)
249 fl->fl_end = OFFSET_MAX;
250 else
251 fl->fl_end = glock.start + glock.length - 1;
252 fl->fl_pid = glock.proc_id;
253 } else
254 fl->fl_type = F_UNLCK;
255
256 return res;
257}
258
259/**
260 * v9fs_file_lock_dotl - lock a file (or directory)
261 * @filp: file to be locked
262 * @cmd: lock command
263 * @fl: file lock structure
264 *
265 */
266
267static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
268{
269 struct inode *inode = filp->f_path.dentry->d_inode;
270 int ret = -ENOLCK;
271
272 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
273 cmd, fl, filp->f_path.dentry->d_name.name);
274
275 /* No mandatory locks */
276 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
277 goto out_err;
278
279 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
280 filemap_write_and_wait(inode->i_mapping);
281 invalidate_mapping_pages(&inode->i_data, 0, -1);
282 }
283
284 if (IS_SETLK(cmd) || IS_SETLKW(cmd))
285 ret = v9fs_file_do_lock(filp, cmd, fl);
286 else if (IS_GETLK(cmd))
287 ret = v9fs_file_getlock(filp, fl);
288 else
289 ret = -EINVAL;
290out_err:
291 return ret;
292}
293
294/**
295 * v9fs_file_flock_dotl - lock a file
296 * @filp: file to be locked
297 * @cmd: lock command
298 * @fl: file lock structure
299 *
300 */
301
302static int v9fs_file_flock_dotl(struct file *filp, int cmd,
303 struct file_lock *fl)
304{
305 struct inode *inode = filp->f_path.dentry->d_inode;
306 int ret = -ENOLCK;
307
308 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
309 cmd, fl, filp->f_path.dentry->d_name.name);
310
311 /* No mandatory locks */
312 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
313 goto out_err;
314
315 if (!(fl->fl_flags & FL_FLOCK))
316 goto out_err;
317
318 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
319 filemap_write_and_wait(inode->i_mapping);
320 invalidate_mapping_pages(&inode->i_data, 0, -1);
321 }
322 /* Convert flock to posix lock */
323 fl->fl_owner = (fl_owner_t)filp;
324 fl->fl_start = 0;
325 fl->fl_end = OFFSET_MAX;
326 fl->fl_flags |= FL_POSIX;
327 fl->fl_flags ^= FL_FLOCK;
328
329 if (IS_SETLK(cmd) | IS_SETLKW(cmd))
330 ret = v9fs_file_do_lock(filp, cmd, fl);
331 else
332 ret = -EINVAL;
333out_err:
334 return ret;
335}
336
133/** 337/**
134 * v9fs_file_readn - read from a file 338 * v9fs_file_readn - read from a file
135 * @filp: file pointer to read 339 * @filp: file pointer to read
@@ -219,7 +423,9 @@ static ssize_t
219v9fs_file_write(struct file *filp, const char __user * data, 423v9fs_file_write(struct file *filp, const char __user * data,
220 size_t count, loff_t * offset) 424 size_t count, loff_t * offset)
221{ 425{
222 int n, rsize, total = 0; 426 ssize_t retval;
427 size_t total = 0;
428 int n;
223 struct p9_fid *fid; 429 struct p9_fid *fid;
224 struct p9_client *clnt; 430 struct p9_client *clnt;
225 struct inode *inode = filp->f_path.dentry->d_inode; 431 struct inode *inode = filp->f_path.dentry->d_inode;
@@ -232,14 +438,19 @@ v9fs_file_write(struct file *filp, const char __user * data,
232 fid = filp->private_data; 438 fid = filp->private_data;
233 clnt = fid->clnt; 439 clnt = fid->clnt;
234 440
235 rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ; 441 retval = generic_write_checks(filp, &origin, &count, 0);
442 if (retval)
443 goto out;
236 444
237 do { 445 retval = -EINVAL;
238 if (count < rsize) 446 if ((ssize_t) count < 0)
239 rsize = count; 447 goto out;
448 retval = 0;
449 if (!count)
450 goto out;
240 451
241 n = p9_client_write(fid, NULL, data+total, origin+total, 452 do {
242 rsize); 453 n = p9_client_write(fid, NULL, data+total, origin+total, count);
243 if (n <= 0) 454 if (n <= 0)
244 break; 455 break;
245 count -= n; 456 count -= n;
@@ -258,9 +469,11 @@ v9fs_file_write(struct file *filp, const char __user * data,
258 } 469 }
259 470
260 if (n < 0) 471 if (n < 0)
261 return n; 472 retval = n;
262 473 else
263 return total; 474 retval = total;
475out:
476 return retval;
264} 477}
265 478
266static int v9fs_file_fsync(struct file *filp, int datasync) 479static int v9fs_file_fsync(struct file *filp, int datasync)
@@ -278,6 +491,20 @@ static int v9fs_file_fsync(struct file *filp, int datasync)
278 return retval; 491 return retval;
279} 492}
280 493
494int v9fs_file_fsync_dotl(struct file *filp, int datasync)
495{
496 struct p9_fid *fid;
497 int retval;
498
499 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
500 filp, datasync);
501
502 fid = filp->private_data;
503
504 retval = p9_client_fsync(fid, datasync);
505 return retval;
506}
507
281static const struct file_operations v9fs_cached_file_operations = { 508static const struct file_operations v9fs_cached_file_operations = {
282 .llseek = generic_file_llseek, 509 .llseek = generic_file_llseek,
283 .read = do_sync_read, 510 .read = do_sync_read,
@@ -290,6 +517,19 @@ static const struct file_operations v9fs_cached_file_operations = {
290 .fsync = v9fs_file_fsync, 517 .fsync = v9fs_file_fsync,
291}; 518};
292 519
520static const struct file_operations v9fs_cached_file_operations_dotl = {
521 .llseek = generic_file_llseek,
522 .read = do_sync_read,
523 .aio_read = generic_file_aio_read,
524 .write = v9fs_file_write,
525 .open = v9fs_file_open,
526 .release = v9fs_dir_release,
527 .lock = v9fs_file_lock_dotl,
528 .flock = v9fs_file_flock_dotl,
529 .mmap = generic_file_readonly_mmap,
530 .fsync = v9fs_file_fsync_dotl,
531};
532
293const struct file_operations v9fs_file_operations = { 533const struct file_operations v9fs_file_operations = {
294 .llseek = generic_file_llseek, 534 .llseek = generic_file_llseek,
295 .read = v9fs_file_read, 535 .read = v9fs_file_read,
@@ -307,7 +547,8 @@ const struct file_operations v9fs_file_operations_dotl = {
307 .write = v9fs_file_write, 547 .write = v9fs_file_write,
308 .open = v9fs_file_open, 548 .open = v9fs_file_open,
309 .release = v9fs_dir_release, 549 .release = v9fs_dir_release,
310 .lock = v9fs_file_lock, 550 .lock = v9fs_file_lock_dotl,
551 .flock = v9fs_file_flock_dotl,
311 .mmap = generic_file_readonly_mmap, 552 .mmap = generic_file_readonly_mmap,
312 .fsync = v9fs_file_fsync, 553 .fsync = v9fs_file_fsync_dotl,
313}; 554};
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index ef5905f7c8a3..34bf71b56542 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -36,6 +36,7 @@
36#include <linux/sched.h> 36#include <linux/sched.h>
37#include <linux/slab.h> 37#include <linux/slab.h>
38#include <linux/xattr.h> 38#include <linux/xattr.h>
39#include <linux/posix_acl.h>
39#include <net/9p/9p.h> 40#include <net/9p/9p.h>
40#include <net/9p/client.h> 41#include <net/9p/client.h>
41 42
@@ -44,6 +45,7 @@
44#include "fid.h" 45#include "fid.h"
45#include "cache.h" 46#include "cache.h"
46#include "xattr.h" 47#include "xattr.h"
48#include "acl.h"
47 49
48static const struct inode_operations v9fs_dir_inode_operations; 50static const struct inode_operations v9fs_dir_inode_operations;
49static const struct inode_operations v9fs_dir_inode_operations_dotu; 51static const struct inode_operations v9fs_dir_inode_operations_dotu;
@@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl;
53static const struct inode_operations v9fs_symlink_inode_operations; 55static const struct inode_operations v9fs_symlink_inode_operations;
54static const struct inode_operations v9fs_symlink_inode_operations_dotl; 56static const struct inode_operations v9fs_symlink_inode_operations_dotl;
55 57
58static int
59v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
60 dev_t rdev);
61
56/** 62/**
57 * unixmode2p9mode - convert unix mode bits to plan 9 63 * unixmode2p9mode - convert unix mode bits to plan 9
58 * @v9ses: v9fs session information 64 * @v9ses: v9fs session information
@@ -500,6 +506,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
500 v9fs_vcookie_set_qid(ret, &st->qid); 506 v9fs_vcookie_set_qid(ret, &st->qid);
501 v9fs_cache_inode_get_cookie(ret); 507 v9fs_cache_inode_get_cookie(ret);
502#endif 508#endif
509 err = v9fs_get_acl(ret, fid);
510 if (err) {
511 iput(ret);
512 goto error;
513 }
503 kfree(st); 514 kfree(st);
504 return ret; 515 return ret;
505error: 516error:
@@ -553,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
553 return retval; 564 return retval;
554} 565}
555 566
556static int
557v9fs_open_created(struct inode *inode, struct file *file)
558{
559 return 0;
560}
561
562
563/** 567/**
564 * v9fs_create - Create a file 568 * v9fs_create - Create a file
565 * @v9ses: session information 569 * @v9ses: session information
@@ -655,29 +659,37 @@ error:
655 */ 659 */
656 660
657static int 661static int
658v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, 662v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
659 struct nameidata *nd) 663 struct nameidata *nd)
660{ 664{
661 int err = 0; 665 int err = 0;
662 char *name = NULL; 666 char *name = NULL;
663 gid_t gid; 667 gid_t gid;
664 int flags; 668 int flags;
669 mode_t mode;
665 struct v9fs_session_info *v9ses; 670 struct v9fs_session_info *v9ses;
666 struct p9_fid *fid = NULL; 671 struct p9_fid *fid = NULL;
667 struct p9_fid *dfid, *ofid; 672 struct p9_fid *dfid, *ofid;
668 struct file *filp; 673 struct file *filp;
669 struct p9_qid qid; 674 struct p9_qid qid;
670 struct inode *inode; 675 struct inode *inode;
676 struct posix_acl *pacl = NULL, *dacl = NULL;
671 677
672 v9ses = v9fs_inode2v9ses(dir); 678 v9ses = v9fs_inode2v9ses(dir);
673 if (nd && nd->flags & LOOKUP_OPEN) 679 if (nd && nd->flags & LOOKUP_OPEN)
674 flags = nd->intent.open.flags - 1; 680 flags = nd->intent.open.flags - 1;
675 else 681 else {
676 flags = O_RDWR; 682 /*
683 * create call without LOOKUP_OPEN is due
684 * to mknod of regular files. So use mknod
685 * operation.
686 */
687 return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
688 }
677 689
678 name = (char *) dentry->d_name.name; 690 name = (char *) dentry->d_name.name;
679 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " 691 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
680 "mode:0x%x\n", name, flags, mode); 692 "mode:0x%x\n", name, flags, omode);
681 693
682 dfid = v9fs_fid_lookup(dentry->d_parent); 694 dfid = v9fs_fid_lookup(dentry->d_parent);
683 if (IS_ERR(dfid)) { 695 if (IS_ERR(dfid)) {
@@ -695,6 +707,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
695 } 707 }
696 708
697 gid = v9fs_get_fsgid_for_create(dir); 709 gid = v9fs_get_fsgid_for_create(dir);
710
711 mode = omode;
712 /* Update mode based on ACL value */
713 err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
714 if (err) {
715 P9_DPRINTK(P9_DEBUG_VFS,
716 "Failed to get acl values in creat %d\n", err);
717 goto error;
718 }
698 err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); 719 err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
699 if (err < 0) { 720 if (err < 0) {
700 P9_DPRINTK(P9_DEBUG_VFS, 721 P9_DPRINTK(P9_DEBUG_VFS,
@@ -702,46 +723,52 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
702 err); 723 err);
703 goto error; 724 goto error;
704 } 725 }
726 /* instantiate inode and assign the unopened fid to the dentry */
727 if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE ||
728 (nd && nd->flags & LOOKUP_OPEN)) {
729 fid = p9_client_walk(dfid, 1, &name, 1);
730 if (IS_ERR(fid)) {
731 err = PTR_ERR(fid);
732 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
733 err);
734 fid = NULL;
735 goto error;
736 }
705 737
706 /* No need to populate the inode if we are not opening the file AND 738 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
707 * not in cached mode. 739 if (IS_ERR(inode)) {
708 */ 740 err = PTR_ERR(inode);
709 if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) { 741 P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
710 /* Not in cached mode. No need to populate inode with stat */ 742 err);
711 dentry->d_op = &v9fs_dentry_operations; 743 goto error;
712 p9_client_clunk(ofid); 744 }
713 d_instantiate(dentry, NULL);
714 return 0;
715 }
716
717 /* Now walk from the parent so we can get an unopened fid. */
718 fid = p9_client_walk(dfid, 1, &name, 1);
719 if (IS_ERR(fid)) {
720 err = PTR_ERR(fid);
721 P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
722 fid = NULL;
723 goto error;
724 }
725
726 /* instantiate inode and assign the unopened fid to dentry */
727 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
728 if (IS_ERR(inode)) {
729 err = PTR_ERR(inode);
730 P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
731 goto error;
732 }
733 if (v9ses->cache)
734 dentry->d_op = &v9fs_cached_dentry_operations; 745 dentry->d_op = &v9fs_cached_dentry_operations;
735 else 746 d_instantiate(dentry, inode);
747 err = v9fs_fid_add(dentry, fid);
748 if (err < 0)
749 goto error;
750 /* The fid would get clunked via a dput */
751 fid = NULL;
752 } else {
753 /*
754 * Not in cached mode. No need to populate
755 * inode with stat. We need to get an inode
756 * so that we can set the acl with dentry
757 */
758 inode = v9fs_get_inode(dir->i_sb, mode);
759 if (IS_ERR(inode)) {
760 err = PTR_ERR(inode);
761 goto error;
762 }
736 dentry->d_op = &v9fs_dentry_operations; 763 dentry->d_op = &v9fs_dentry_operations;
737 d_instantiate(dentry, inode); 764 d_instantiate(dentry, inode);
738 err = v9fs_fid_add(dentry, fid); 765 }
739 if (err < 0) 766 /* Now set the ACL based on the default value */
740 goto error; 767 v9fs_set_create_acl(dentry, dacl, pacl);
741 768
742 /* if we are opening a file, assign the open fid to the file */ 769 /* if we are opening a file, assign the open fid to the file */
743 if (nd && nd->flags & LOOKUP_OPEN) { 770 if (nd && nd->flags & LOOKUP_OPEN) {
744 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 771 filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
745 if (IS_ERR(filp)) { 772 if (IS_ERR(filp)) {
746 p9_client_clunk(ofid); 773 p9_client_clunk(ofid);
747 return PTR_ERR(filp); 774 return PTR_ERR(filp);
@@ -800,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
800 827
801 /* if we are opening a file, assign the open fid to the file */ 828 /* if we are opening a file, assign the open fid to the file */
802 if (nd && nd->flags & LOOKUP_OPEN) { 829 if (nd && nd->flags & LOOKUP_OPEN) {
803 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); 830 filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
804 if (IS_ERR(filp)) { 831 if (IS_ERR(filp)) {
805 err = PTR_ERR(filp); 832 err = PTR_ERR(filp);
806 goto error; 833 goto error;
@@ -859,23 +886,28 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
859 * 886 *
860 */ 887 */
861 888
862static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, 889static int v9fs_vfs_mkdir_dotl(struct inode *dir,
863 int mode) 890 struct dentry *dentry, int omode)
864{ 891{
865 int err; 892 int err;
866 struct v9fs_session_info *v9ses; 893 struct v9fs_session_info *v9ses;
867 struct p9_fid *fid = NULL, *dfid = NULL; 894 struct p9_fid *fid = NULL, *dfid = NULL;
868 gid_t gid; 895 gid_t gid;
869 char *name; 896 char *name;
897 mode_t mode;
870 struct inode *inode; 898 struct inode *inode;
871 struct p9_qid qid; 899 struct p9_qid qid;
872 struct dentry *dir_dentry; 900 struct dentry *dir_dentry;
901 struct posix_acl *dacl = NULL, *pacl = NULL;
873 902
874 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); 903 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
875 err = 0; 904 err = 0;
876 v9ses = v9fs_inode2v9ses(dir); 905 v9ses = v9fs_inode2v9ses(dir);
877 906
878 mode |= S_IFDIR; 907 omode |= S_IFDIR;
908 if (dir->i_mode & S_ISGID)
909 omode |= S_ISGID;
910
879 dir_dentry = v9fs_dentry_from_dir_inode(dir); 911 dir_dentry = v9fs_dentry_from_dir_inode(dir);
880 dfid = v9fs_fid_lookup(dir_dentry); 912 dfid = v9fs_fid_lookup(dir_dentry);
881 if (IS_ERR(dfid)) { 913 if (IS_ERR(dfid)) {
@@ -886,11 +918,14 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
886 } 918 }
887 919
888 gid = v9fs_get_fsgid_for_create(dir); 920 gid = v9fs_get_fsgid_for_create(dir);
889 if (gid < 0) { 921 mode = omode;
890 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); 922 /* Update mode based on ACL value */
923 err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
924 if (err) {
925 P9_DPRINTK(P9_DEBUG_VFS,
926 "Failed to get acl values in mkdir %d\n", err);
891 goto error; 927 goto error;
892 } 928 }
893
894 name = (char *) dentry->d_name.name; 929 name = (char *) dentry->d_name.name;
895 err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); 930 err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
896 if (err < 0) 931 if (err < 0)
@@ -920,7 +955,23 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
920 if (err < 0) 955 if (err < 0)
921 goto error; 956 goto error;
922 fid = NULL; 957 fid = NULL;
958 } else {
959 /*
960 * Not in cached mode. No need to populate
961 * inode with stat. We need to get an inode
962 * so that we can set the acl with dentry
963 */
964 inode = v9fs_get_inode(dir->i_sb, mode);
965 if (IS_ERR(inode)) {
966 err = PTR_ERR(inode);
967 goto error;
968 }
969 dentry->d_op = &v9fs_dentry_operations;
970 d_instantiate(dentry, inode);
923 } 971 }
972 /* Now set the ACL based on the default value */
973 v9fs_set_create_acl(dentry, dacl, pacl);
974
924error: 975error:
925 if (fid) 976 if (fid)
926 p9_client_clunk(fid); 977 p9_client_clunk(fid);
@@ -979,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
979 1030
980 result = v9fs_fid_add(dentry, fid); 1031 result = v9fs_fid_add(dentry, fid);
981 if (result < 0) 1032 if (result < 0)
982 goto error; 1033 goto error_iput;
983 1034
984inst_out: 1035inst_out:
985 if (v9ses->cache) 1036 if (v9ses->cache)
@@ -990,6 +1041,8 @@ inst_out:
990 d_add(dentry, inode); 1041 d_add(dentry, inode);
991 return NULL; 1042 return NULL;
992 1043
1044error_iput:
1045 iput(inode);
993error: 1046error:
994 p9_client_clunk(fid); 1047 p9_client_clunk(fid);
995 1048
@@ -1237,7 +1290,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
1237 * 1290 *
1238 */ 1291 */
1239 1292
1240static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) 1293int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
1241{ 1294{
1242 int retval; 1295 int retval;
1243 struct v9fs_session_info *v9ses; 1296 struct v9fs_session_info *v9ses;
@@ -1279,6 +1332,12 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
1279 1332
1280 setattr_copy(dentry->d_inode, iattr); 1333 setattr_copy(dentry->d_inode, iattr);
1281 mark_inode_dirty(dentry->d_inode); 1334 mark_inode_dirty(dentry->d_inode);
1335 if (iattr->ia_valid & ATTR_MODE) {
1336 /* We also want to update ACL when we update mode bits */
1337 retval = v9fs_acl_chmod(dentry);
1338 if (retval < 0)
1339 return retval;
1340 }
1282 return 0; 1341 return 0;
1283} 1342}
1284 1343
@@ -1473,7 +1532,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
1473 if (IS_ERR(fid)) 1532 if (IS_ERR(fid))
1474 return PTR_ERR(fid); 1533 return PTR_ERR(fid);
1475 1534
1476 if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) 1535 if (!v9fs_proto_dotu(v9ses))
1477 return -EBADF; 1536 return -EBADF;
1478 1537
1479 st = p9_client_stat(fid); 1538 st = p9_client_stat(fid);
@@ -1616,11 +1675,6 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
1616 1675
1617 gid = v9fs_get_fsgid_for_create(dir); 1676 gid = v9fs_get_fsgid_for_create(dir);
1618 1677
1619 if (gid < 0) {
1620 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
1621 goto error;
1622 }
1623
1624 /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ 1678 /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
1625 err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); 1679 err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
1626 1680
@@ -1855,21 +1909,23 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1855 * 1909 *
1856 */ 1910 */
1857static int 1911static int
1858v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, 1912v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
1859 dev_t rdev) 1913 dev_t rdev)
1860{ 1914{
1861 int err; 1915 int err;
1862 char *name; 1916 char *name;
1917 mode_t mode;
1863 struct v9fs_session_info *v9ses; 1918 struct v9fs_session_info *v9ses;
1864 struct p9_fid *fid = NULL, *dfid = NULL; 1919 struct p9_fid *fid = NULL, *dfid = NULL;
1865 struct inode *inode; 1920 struct inode *inode;
1866 gid_t gid; 1921 gid_t gid;
1867 struct p9_qid qid; 1922 struct p9_qid qid;
1868 struct dentry *dir_dentry; 1923 struct dentry *dir_dentry;
1924 struct posix_acl *dacl = NULL, *pacl = NULL;
1869 1925
1870 P9_DPRINTK(P9_DEBUG_VFS, 1926 P9_DPRINTK(P9_DEBUG_VFS,
1871 " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1927 " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1872 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1928 dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev));
1873 1929
1874 if (!new_valid_dev(rdev)) 1930 if (!new_valid_dev(rdev))
1875 return -EINVAL; 1931 return -EINVAL;
@@ -1885,11 +1941,14 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
1885 } 1941 }
1886 1942
1887 gid = v9fs_get_fsgid_for_create(dir); 1943 gid = v9fs_get_fsgid_for_create(dir);
1888 if (gid < 0) { 1944 mode = omode;
1889 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); 1945 /* Update mode based on ACL value */
1946 err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
1947 if (err) {
1948 P9_DPRINTK(P9_DEBUG_VFS,
1949 "Failed to get acl values in mknod %d\n", err);
1890 goto error; 1950 goto error;
1891 } 1951 }
1892
1893 name = (char *) dentry->d_name.name; 1952 name = (char *) dentry->d_name.name;
1894 1953
1895 err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid); 1954 err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
@@ -1933,13 +1992,68 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
1933 dentry->d_op = &v9fs_dentry_operations; 1992 dentry->d_op = &v9fs_dentry_operations;
1934 d_instantiate(dentry, inode); 1993 d_instantiate(dentry, inode);
1935 } 1994 }
1936 1995 /* Now set the ACL based on the default value */
1996 v9fs_set_create_acl(dentry, dacl, pacl);
1937error: 1997error:
1938 if (fid) 1998 if (fid)
1939 p9_client_clunk(fid); 1999 p9_client_clunk(fid);
1940 return err; 2000 return err;
1941} 2001}
1942 2002
2003static int
2004v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen)
2005{
2006 int retval;
2007 struct p9_fid *fid;
2008 char *target = NULL;
2009
2010 P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
2011 retval = -EPERM;
2012 fid = v9fs_fid_lookup(dentry);
2013 if (IS_ERR(fid))
2014 return PTR_ERR(fid);
2015
2016 retval = p9_client_readlink(fid, &target);
2017 if (retval < 0)
2018 return retval;
2019
2020 strncpy(buffer, target, buflen);
2021 P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer);
2022
2023 retval = strnlen(buffer, buflen);
2024 return retval;
2025}
2026
2027/**
2028 * v9fs_vfs_follow_link_dotl - follow a symlink path
2029 * @dentry: dentry for symlink
2030 * @nd: nameidata
2031 *
2032 */
2033
2034static void *
2035v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
2036{
2037 int len = 0;
2038 char *link = __getname();
2039
2040 P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
2041
2042 if (!link)
2043 link = ERR_PTR(-ENOMEM);
2044 else {
2045 len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX);
2046 if (len < 0) {
2047 __putname(link);
2048 link = ERR_PTR(len);
2049 } else
2050 link[min(len, PATH_MAX-1)] = 0;
2051 }
2052 nd_set_link(nd, link);
2053
2054 return NULL;
2055}
2056
1943static const struct inode_operations v9fs_dir_inode_operations_dotu = { 2057static const struct inode_operations v9fs_dir_inode_operations_dotu = {
1944 .create = v9fs_vfs_create, 2058 .create = v9fs_vfs_create,
1945 .lookup = v9fs_vfs_lookup, 2059 .lookup = v9fs_vfs_lookup,
@@ -1970,7 +2084,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
1970 .getxattr = generic_getxattr, 2084 .getxattr = generic_getxattr,
1971 .removexattr = generic_removexattr, 2085 .removexattr = generic_removexattr,
1972 .listxattr = v9fs_listxattr, 2086 .listxattr = v9fs_listxattr,
1973 2087 .check_acl = v9fs_check_acl,
1974}; 2088};
1975 2089
1976static const struct inode_operations v9fs_dir_inode_operations = { 2090static const struct inode_operations v9fs_dir_inode_operations = {
@@ -1997,6 +2111,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = {
1997 .getxattr = generic_getxattr, 2111 .getxattr = generic_getxattr,
1998 .removexattr = generic_removexattr, 2112 .removexattr = generic_removexattr,
1999 .listxattr = v9fs_listxattr, 2113 .listxattr = v9fs_listxattr,
2114 .check_acl = v9fs_check_acl,
2000}; 2115};
2001 2116
2002static const struct inode_operations v9fs_symlink_inode_operations = { 2117static const struct inode_operations v9fs_symlink_inode_operations = {
@@ -2008,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
2008}; 2123};
2009 2124
2010static const struct inode_operations v9fs_symlink_inode_operations_dotl = { 2125static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
2011 .readlink = generic_readlink, 2126 .readlink = v9fs_vfs_readlink_dotl,
2012 .follow_link = v9fs_vfs_follow_link, 2127 .follow_link = v9fs_vfs_follow_link_dotl,
2013 .put_link = v9fs_vfs_put_link, 2128 .put_link = v9fs_vfs_put_link,
2014 .getattr = v9fs_vfs_getattr_dotl, 2129 .getattr = v9fs_vfs_getattr_dotl,
2015 .setattr = v9fs_vfs_setattr_dotl, 2130 .setattr = v9fs_vfs_setattr_dotl,
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 1d12ba0ed3db..48d4215c60a8 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -39,6 +39,7 @@
39#include <linux/sched.h> 39#include <linux/sched.h>
40#include <linux/slab.h> 40#include <linux/slab.h>
41#include <linux/statfs.h> 41#include <linux/statfs.h>
42#include <linux/magic.h>
42#include <net/9p/9p.h> 43#include <net/9p/9p.h>
43#include <net/9p/client.h> 44#include <net/9p/client.h>
44 45
@@ -46,6 +47,7 @@
46#include "v9fs_vfs.h" 47#include "v9fs_vfs.h"
47#include "fid.h" 48#include "fid.h"
48#include "xattr.h" 49#include "xattr.h"
50#include "acl.h"
49 51
50static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; 52static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
51 53
@@ -88,6 +90,11 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
88 sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | 90 sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
89 MS_NOATIME; 91 MS_NOATIME;
90 92
93#ifdef CONFIG_9P_FS_POSIX_ACL
94 if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
95 sb->s_flags |= MS_POSIXACL;
96#endif
97
91 save_mount_options(sb, data); 98 save_mount_options(sb, data);
92} 99}
93 100
@@ -149,7 +156,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
149 goto release_sb; 156 goto release_sb;
150 } 157 }
151 sb->s_root = root; 158 sb->s_root = root;
152
153 if (v9fs_proto_dotl(v9ses)) { 159 if (v9fs_proto_dotl(v9ses)) {
154 struct p9_stat_dotl *st = NULL; 160 struct p9_stat_dotl *st = NULL;
155 st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); 161 st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
@@ -174,7 +180,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
174 p9stat_free(st); 180 p9stat_free(st);
175 kfree(st); 181 kfree(st);
176 } 182 }
177 183 retval = v9fs_get_acl(inode, fid);
184 if (retval)
185 goto release_sb;
178 v9fs_fid_add(root, fid); 186 v9fs_fid_add(root, fid);
179 187
180 P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); 188 P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
@@ -249,7 +257,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
249 if (v9fs_proto_dotl(v9ses)) { 257 if (v9fs_proto_dotl(v9ses)) {
250 res = p9_client_statfs(fid, &rs); 258 res = p9_client_statfs(fid, &rs);
251 if (res == 0) { 259 if (res == 0) {
252 buf->f_type = rs.type; 260 buf->f_type = V9FS_MAGIC;
253 buf->f_bsize = rs.bsize; 261 buf->f_bsize = rs.bsize;
254 buf->f_blocks = rs.blocks; 262 buf->f_blocks = rs.blocks;
255 buf->f_bfree = rs.bfree; 263 buf->f_bfree = rs.bfree;
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index f88e5c2dc873..43ec7df84336 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -21,30 +21,13 @@
21#include "fid.h" 21#include "fid.h"
22#include "xattr.h" 22#include "xattr.h"
23 23
24/* 24ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
25 * v9fs_xattr_get() 25 void *buffer, size_t buffer_size)
26 *
27 * Copy an extended attribute into the buffer
28 * provided, or compute the buffer size required.
29 * Buffer is NULL to compute the size of the buffer required.
30 *
31 * Returns a negative error number on failure, or the number of bytes
32 * used / required on success.
33 */
34ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
35 void *buffer, size_t buffer_size)
36{ 26{
37 ssize_t retval; 27 ssize_t retval;
38 int msize, read_count; 28 int msize, read_count;
39 u64 offset = 0, attr_size; 29 u64 offset = 0, attr_size;
40 struct p9_fid *fid, *attr_fid; 30 struct p9_fid *attr_fid;
41
42 P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
43 __func__, name, buffer_size);
44
45 fid = v9fs_fid_lookup(dentry);
46 if (IS_ERR(fid))
47 return PTR_ERR(fid);
48 31
49 attr_fid = p9_client_xattrwalk(fid, name, &attr_size); 32 attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
50 if (IS_ERR(attr_fid)) { 33 if (IS_ERR(attr_fid)) {
@@ -88,6 +71,31 @@ error:
88 71
89} 72}
90 73
74
75/*
76 * v9fs_xattr_get()
77 *
78 * Copy an extended attribute into the buffer
79 * provided, or compute the buffer size required.
80 * Buffer is NULL to compute the size of the buffer required.
81 *
82 * Returns a negative error number on failure, or the number of bytes
83 * used / required on success.
84 */
85ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
86 void *buffer, size_t buffer_size)
87{
88 struct p9_fid *fid;
89
90 P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
91 __func__, name, buffer_size);
92 fid = v9fs_fid_lookup(dentry);
93 if (IS_ERR(fid))
94 return PTR_ERR(fid);
95
96 return v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
97}
98
91/* 99/*
92 * v9fs_xattr_set() 100 * v9fs_xattr_set()
93 * 101 *
@@ -156,5 +164,9 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
156 164
157const struct xattr_handler *v9fs_xattr_handlers[] = { 165const struct xattr_handler *v9fs_xattr_handlers[] = {
158 &v9fs_xattr_user_handler, 166 &v9fs_xattr_user_handler,
167#ifdef CONFIG_9P_FS_POSIX_ACL
168 &v9fs_xattr_acl_access_handler,
169 &v9fs_xattr_acl_default_handler,
170#endif
159 NULL 171 NULL
160}; 172};
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
index 9ddf672ae5c4..eaa837c53bd5 100644
--- a/fs/9p/xattr.h
+++ b/fs/9p/xattr.h
@@ -15,10 +15,16 @@
15#define FS_9P_XATTR_H 15#define FS_9P_XATTR_H
16 16
17#include <linux/xattr.h> 17#include <linux/xattr.h>
18#include <net/9p/9p.h>
19#include <net/9p/client.h>
18 20
19extern const struct xattr_handler *v9fs_xattr_handlers[]; 21extern const struct xattr_handler *v9fs_xattr_handlers[];
20extern struct xattr_handler v9fs_xattr_user_handler; 22extern struct xattr_handler v9fs_xattr_user_handler;
23extern const struct xattr_handler v9fs_xattr_acl_access_handler;
24extern const struct xattr_handler v9fs_xattr_acl_default_handler;
21 25
26extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *,
27 void *, size_t);
22extern ssize_t v9fs_xattr_get(struct dentry *, const char *, 28extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
23 void *, size_t); 29 void *, size_t);
24extern int v9fs_xattr_set(struct dentry *, const char *, 30extern int v9fs_xattr_set(struct dentry *, const char *,
diff --git a/include/linux/magic.h b/include/linux/magic.h
index eb9800f05782..ff690d05f129 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -57,5 +57,6 @@
57 57
58#define DEVPTS_SUPER_MAGIC 0x1cd1 58#define DEVPTS_SUPER_MAGIC 0x1cd1
59#define SOCKFS_MAGIC 0x534F434B 59#define SOCKFS_MAGIC 0x534F434B
60#define V9FS_MAGIC 0x01021997
60 61
61#endif /* __LINUX_MAGIC_H__ */ 62#endif /* __LINUX_MAGIC_H__ */
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index a8de812ccbc8..071fd7a8d781 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -86,6 +86,8 @@ do { \
86 86
87/** 87/**
88 * enum p9_msg_t - 9P message types 88 * enum p9_msg_t - 9P message types
89 * @P9_TLERROR: not used
90 * @P9_RLERROR: response for any failed request for 9P2000.L
89 * @P9_TSTATFS: file system status request 91 * @P9_TSTATFS: file system status request
90 * @P9_RSTATFS: file system status response 92 * @P9_RSTATFS: file system status response
91 * @P9_TSYMLINK: make symlink request 93 * @P9_TSYMLINK: make symlink request
@@ -137,6 +139,8 @@ do { \
137 */ 139 */
138 140
139enum p9_msg_t { 141enum p9_msg_t {
142 P9_TLERROR = 6,
143 P9_RLERROR,
140 P9_TSTATFS = 8, 144 P9_TSTATFS = 8,
141 P9_RSTATFS, 145 P9_RSTATFS,
142 P9_TLOPEN = 12, 146 P9_TLOPEN = 12,
@@ -149,6 +153,8 @@ enum p9_msg_t {
149 P9_RMKNOD, 153 P9_RMKNOD,
150 P9_TRENAME = 20, 154 P9_TRENAME = 20,
151 P9_RRENAME, 155 P9_RRENAME,
156 P9_TREADLINK = 22,
157 P9_RREADLINK,
152 P9_TGETATTR = 24, 158 P9_TGETATTR = 24,
153 P9_RGETATTR, 159 P9_RGETATTR,
154 P9_TSETATTR = 26, 160 P9_TSETATTR = 26,
@@ -159,6 +165,12 @@ enum p9_msg_t {
159 P9_RXATTRCREATE, 165 P9_RXATTRCREATE,
160 P9_TREADDIR = 40, 166 P9_TREADDIR = 40,
161 P9_RREADDIR, 167 P9_RREADDIR,
168 P9_TFSYNC = 50,
169 P9_RFSYNC,
170 P9_TLOCK = 52,
171 P9_RLOCK,
172 P9_TGETLOCK = 54,
173 P9_RGETLOCK,
162 P9_TLINK = 70, 174 P9_TLINK = 70,
163 P9_RLINK, 175 P9_RLINK,
164 P9_TMKDIR = 72, 176 P9_TMKDIR = 72,
@@ -458,6 +470,48 @@ struct p9_iattr_dotl {
458 u64 mtime_nsec; 470 u64 mtime_nsec;
459}; 471};
460 472
473#define P9_LOCK_SUCCESS 0
474#define P9_LOCK_BLOCKED 1
475#define P9_LOCK_ERROR 2
476#define P9_LOCK_GRACE 3
477
478#define P9_LOCK_FLAGS_BLOCK 1
479#define P9_LOCK_FLAGS_RECLAIM 2
480
481/* struct p9_flock: POSIX lock structure
482 * @type - type of lock
483 * @flags - lock flags
484 * @start - starting offset of the lock
485 * @length - number of bytes
486 * @proc_id - process id which wants to take lock
487 * @client_id - client id
488 */
489
490struct p9_flock {
491 u8 type;
492 u32 flags;
493 u64 start;
494 u64 length;
495 u32 proc_id;
496 char *client_id;
497};
498
499/* struct p9_getlock: getlock structure
500 * @type - type of lock
501 * @start - starting offset of the lock
502 * @length - number of bytes
503 * @proc_id - process id which wants to take lock
504 * @client_id - client id
505 */
506
507struct p9_getlock {
508 u8 type;
509 u64 start;
510 u64 length;
511 u32 proc_id;
512 char *client_id;
513};
514
461/* Structures for Protocol Operations */ 515/* Structures for Protocol Operations */
462struct p9_tstatfs { 516struct p9_tstatfs {
463 u32 fid; 517 u32 fid;
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 7f63d5ab7b44..83ba6a4d58a3 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -229,6 +229,7 @@ int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
229int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, 229int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
230 gid_t gid, struct p9_qid *qid); 230 gid_t gid, struct p9_qid *qid);
231int p9_client_clunk(struct p9_fid *fid); 231int p9_client_clunk(struct p9_fid *fid);
232int p9_client_fsync(struct p9_fid *fid, int datasync);
232int p9_client_remove(struct p9_fid *fid); 233int p9_client_remove(struct p9_fid *fid);
233int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, 234int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
234 u64 offset, u32 count); 235 u64 offset, u32 count);
@@ -248,6 +249,8 @@ int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
248 dev_t rdev, gid_t gid, struct p9_qid *); 249 dev_t rdev, gid_t gid, struct p9_qid *);
249int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, 250int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
250 gid_t gid, struct p9_qid *); 251 gid_t gid, struct p9_qid *);
252int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
253int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
251struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); 254struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
252void p9_client_cb(struct p9_client *c, struct p9_req_t *req); 255void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
253 256
@@ -259,5 +262,6 @@ int p9_is_proto_dotu(struct p9_client *clnt);
259int p9_is_proto_dotl(struct p9_client *clnt); 262int p9_is_proto_dotl(struct p9_client *clnt);
260struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); 263struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
261int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); 264int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
265int p9_client_readlink(struct p9_fid *fid, char **target);
262 266
263#endif /* NET_9P_CLIENT_H */ 267#endif /* NET_9P_CLIENT_H */
diff --git a/net/9p/client.c b/net/9p/client.c
index 83bf0541d66f..a848bca9fbff 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
450 return err; 450 return err;
451 } 451 }
452 452
453 if (type == P9_RERROR) { 453 if (type == P9_RERROR || type == P9_RLERROR) {
454 int ecode; 454 int ecode;
455 char *ename;
456 455
457 err = p9pdu_readf(req->rc, c->proto_version, "s?d", 456 if (!p9_is_proto_dotl(c)) {
458 &ename, &ecode); 457 char *ename;
459 if (err) {
460 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
461 err);
462 return err;
463 }
464 458
465 if (p9_is_proto_dotu(c) || 459 err = p9pdu_readf(req->rc, c->proto_version, "s?d",
466 p9_is_proto_dotl(c)) 460 &ename, &ecode);
467 err = -ecode; 461 if (err)
462 goto out_err;
463
464 if (p9_is_proto_dotu(c))
465 err = -ecode;
466
467 if (!err || !IS_ERR_VALUE(err)) {
468 err = p9_errstr2errno(ename, strlen(ename));
469
470 P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
468 471
469 if (!err || !IS_ERR_VALUE(err)) 472 kfree(ename);
470 err = p9_errstr2errno(ename, strlen(ename)); 473 }
474 } else {
475 err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
476 err = -ecode;
471 477
472 P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); 478 P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
479 }
473 480
474 kfree(ename);
475 } else 481 } else
476 err = 0; 482 err = 0;
477 483
478 return err; 484 return err;
485
486out_err:
487 P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
488
489 return err;
479} 490}
480 491
481/** 492/**
@@ -568,11 +579,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
568 va_start(ap, fmt); 579 va_start(ap, fmt);
569 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); 580 err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
570 va_end(ap); 581 va_end(ap);
582 if (err)
583 goto reterr;
571 p9pdu_finalize(req->tc); 584 p9pdu_finalize(req->tc);
572 585
573 err = c->trans_mod->request(c, req); 586 err = c->trans_mod->request(c, req);
574 if (err < 0) { 587 if (err < 0) {
575 c->status = Disconnected; 588 if (err != -ERESTARTSYS)
589 c->status = Disconnected;
576 goto reterr; 590 goto reterr;
577 } 591 }
578 592
@@ -1151,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
1151} 1165}
1152EXPORT_SYMBOL(p9_client_link); 1166EXPORT_SYMBOL(p9_client_link);
1153 1167
1168int p9_client_fsync(struct p9_fid *fid, int datasync)
1169{
1170 int err;
1171 struct p9_client *clnt;
1172 struct p9_req_t *req;
1173
1174 P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
1175 fid->fid, datasync);
1176 err = 0;
1177 clnt = fid->clnt;
1178
1179 req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
1180 if (IS_ERR(req)) {
1181 err = PTR_ERR(req);
1182 goto error;
1183 }
1184
1185 P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
1186
1187 p9_free_req(clnt, req);
1188
1189error:
1190 return err;
1191}
1192EXPORT_SYMBOL(p9_client_fsync);
1193
1154int p9_client_clunk(struct p9_fid *fid) 1194int p9_client_clunk(struct p9_fid *fid)
1155{ 1195{
1156 int err; 1196 int err;
1157 struct p9_client *clnt; 1197 struct p9_client *clnt;
1158 struct p9_req_t *req; 1198 struct p9_req_t *req;
1159 1199
1200 if (!fid) {
1201 P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n");
1202 dump_stack();
1203 return 0;
1204 }
1205
1160 P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); 1206 P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
1161 err = 0; 1207 err = 0;
1162 clnt = fid->clnt; 1208 clnt = fid->clnt;
@@ -1240,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
1240 1286
1241 if (data) { 1287 if (data) {
1242 memmove(data, dataptr, count); 1288 memmove(data, dataptr, count);
1243 } 1289 } else {
1244
1245 if (udata) {
1246 err = copy_to_user(udata, dataptr, count); 1290 err = copy_to_user(udata, dataptr, count);
1247 if (err) { 1291 if (err) {
1248 err = -EFAULT; 1292 err = -EFAULT;
1249 goto free_and_error; 1293 goto free_and_error;
1250 } 1294 }
1251 } 1295 }
1252
1253 p9_free_req(clnt, req); 1296 p9_free_req(clnt, req);
1254 return count; 1297 return count;
1255 1298
@@ -1761,3 +1804,96 @@ error:
1761 1804
1762} 1805}
1763EXPORT_SYMBOL(p9_client_mkdir_dotl); 1806EXPORT_SYMBOL(p9_client_mkdir_dotl);
1807
1808int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
1809{
1810 int err;
1811 struct p9_client *clnt;
1812 struct p9_req_t *req;
1813
1814 err = 0;
1815 clnt = fid->clnt;
1816 P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
1817 "start %lld length %lld proc_id %d client_id %s\n",
1818 fid->fid, flock->type, flock->flags, flock->start,
1819 flock->length, flock->proc_id, flock->client_id);
1820
1821 req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
1822 flock->flags, flock->start, flock->length,
1823 flock->proc_id, flock->client_id);
1824
1825 if (IS_ERR(req))
1826 return PTR_ERR(req);
1827
1828 err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
1829 if (err) {
1830 p9pdu_dump(1, req->rc);
1831 goto error;
1832 }
1833 P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
1834error:
1835 p9_free_req(clnt, req);
1836 return err;
1837
1838}
1839EXPORT_SYMBOL(p9_client_lock_dotl);
1840
1841int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
1842{
1843 int err;
1844 struct p9_client *clnt;
1845 struct p9_req_t *req;
1846
1847 err = 0;
1848 clnt = fid->clnt;
1849 P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
1850 "length %lld proc_id %d client_id %s\n", fid->fid, glock->type,
1851 glock->start, glock->length, glock->proc_id, glock->client_id);
1852
1853 req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type,
1854 glock->start, glock->length, glock->proc_id, glock->client_id);
1855
1856 if (IS_ERR(req))
1857 return PTR_ERR(req);
1858
1859 err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type,
1860 &glock->start, &glock->length, &glock->proc_id,
1861 &glock->client_id);
1862 if (err) {
1863 p9pdu_dump(1, req->rc);
1864 goto error;
1865 }
1866 P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
1867 "proc_id %d client_id %s\n", glock->type, glock->start,
1868 glock->length, glock->proc_id, glock->client_id);
1869error:
1870 p9_free_req(clnt, req);
1871 return err;
1872}
1873EXPORT_SYMBOL(p9_client_getlock_dotl);
1874
1875int p9_client_readlink(struct p9_fid *fid, char **target)
1876{
1877 int err;
1878 struct p9_client *clnt;
1879 struct p9_req_t *req;
1880
1881 err = 0;
1882 clnt = fid->clnt;
1883 P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
1884
1885 req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
1886 if (IS_ERR(req))
1887 return PTR_ERR(req);
1888
1889 err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
1890 if (err) {
1891 p9pdu_dump(1, req->rc);
1892 goto error;
1893 }
1894 P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
1895error:
1896 p9_free_req(clnt, req);
1897 return err;
1898}
1899EXPORT_SYMBOL(p9_client_readlink);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 3acd3afb20c8..45c15f491401 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -122,9 +122,8 @@ static size_t
122pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) 122pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
123{ 123{
124 size_t len = MIN(pdu->capacity - pdu->size, size); 124 size_t len = MIN(pdu->capacity - pdu->size, size);
125 int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); 125 if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
126 if (err) 126 len = 0;
127 printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
128 127
129 pdu->size += len; 128 pdu->size += len;
130 return size - len; 129 return size - len;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index b88515936e4b..c8f3f72ab20e 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -75,6 +75,8 @@ struct virtio_chan {
75 struct p9_client *client; 75 struct p9_client *client;
76 struct virtio_device *vdev; 76 struct virtio_device *vdev;
77 struct virtqueue *vq; 77 struct virtqueue *vq;
78 int ring_bufs_avail;
79 wait_queue_head_t *vc_wq;
78 80
79 /* Scatterlist: can be too big for stack. */ 81 /* Scatterlist: can be too big for stack. */
80 struct scatterlist sg[VIRTQUEUE_NUM]; 82 struct scatterlist sg[VIRTQUEUE_NUM];
@@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq)
134 struct p9_fcall *rc; 136 struct p9_fcall *rc;
135 unsigned int len; 137 unsigned int len;
136 struct p9_req_t *req; 138 struct p9_req_t *req;
139 unsigned long flags;
137 140
138 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); 141 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
139 142
140 while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) { 143 do {
141 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); 144 spin_lock_irqsave(&chan->lock, flags);
142 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); 145 rc = virtqueue_get_buf(chan->vq, &len);
143 req = p9_tag_lookup(chan->client, rc->tag); 146
144 req->status = REQ_STATUS_RCVD; 147 if (rc != NULL) {
145 p9_client_cb(chan->client, req); 148 if (!chan->ring_bufs_avail) {
146 } 149 chan->ring_bufs_avail = 1;
150 wake_up(chan->vc_wq);
151 }
152 spin_unlock_irqrestore(&chan->lock, flags);
153 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
154 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
155 rc->tag);
156 req = p9_tag_lookup(chan->client, rc->tag);
157 req->status = REQ_STATUS_RCVD;
158 p9_client_cb(chan->client, req);
159 } else {
160 spin_unlock_irqrestore(&chan->lock, flags);
161 }
162 } while (rc != NULL);
147} 163}
148 164
149/** 165/**
@@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
199 int in, out; 215 int in, out;
200 struct virtio_chan *chan = client->trans; 216 struct virtio_chan *chan = client->trans;
201 char *rdata = (char *)req->rc+sizeof(struct p9_fcall); 217 char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
218 unsigned long flags;
219 int err;
202 220
203 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); 221 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
204 222
223req_retry:
224 req->status = REQ_STATUS_SENT;
225
226 spin_lock_irqsave(&chan->lock, flags);
205 out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, 227 out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
206 req->tc->size); 228 req->tc->size);
207 in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, 229 in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
208 client->msize); 230 client->msize);
209 231
210 req->status = REQ_STATUS_SENT; 232 err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
211 233 if (err < 0) {
212 if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { 234 if (err == -ENOSPC) {
213 P9_DPRINTK(P9_DEBUG_TRANS, 235 chan->ring_bufs_avail = 0;
214 "9p debug: virtio rpc add_buf returned failure"); 236 spin_unlock_irqrestore(&chan->lock, flags);
215 return -EIO; 237 err = wait_event_interruptible(*chan->vc_wq,
238 chan->ring_bufs_avail);
239 if (err == -ERESTARTSYS)
240 return err;
241
242 P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
243 goto req_retry;
244 } else {
245 spin_unlock_irqrestore(&chan->lock, flags);
246 P9_DPRINTK(P9_DEBUG_TRANS,
247 "9p debug: "
248 "virtio rpc add_buf returned failure");
249 return -EIO;
250 }
216 } 251 }
217 252
218 virtqueue_kick(chan->vq); 253 virtqueue_kick(chan->vq);
254 spin_unlock_irqrestore(&chan->lock, flags);
219 255
220 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); 256 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
221 return 0; 257 return 0;
@@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev)
290 chan->tag_len = tag_len; 326 chan->tag_len = tag_len;
291 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); 327 err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
292 if (err) { 328 if (err) {
293 kfree(tag); 329 goto out_free_tag;
294 goto out_free_vq;
295 } 330 }
331 chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
332 if (!chan->vc_wq) {
333 err = -ENOMEM;
334 goto out_free_tag;
335 }
336 init_waitqueue_head(chan->vc_wq);
337 chan->ring_bufs_avail = 1;
338
296 mutex_lock(&virtio_9p_lock); 339 mutex_lock(&virtio_9p_lock);
297 list_add_tail(&chan->chan_list, &virtio_chan_list); 340 list_add_tail(&chan->chan_list, &virtio_chan_list);
298 mutex_unlock(&virtio_9p_lock); 341 mutex_unlock(&virtio_9p_lock);
299 return 0; 342 return 0;
300 343
344out_free_tag:
345 kfree(tag);
301out_free_vq: 346out_free_vq:
302 vdev->config->del_vqs(vdev); 347 vdev->config->del_vqs(vdev);
303 kfree(chan); 348 kfree(chan);
@@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
371 mutex_unlock(&virtio_9p_lock); 416 mutex_unlock(&virtio_9p_lock);
372 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); 417 sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
373 kfree(chan->tag); 418 kfree(chan->tag);
419 kfree(chan->vc_wq);
374 kfree(chan); 420 kfree(chan);
375 421
376} 422}