diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:25:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-28 12:25:11 -0400 |
commit | 90a2b69c14d0f0b6cbd124caf429ae9033f0615c (patch) | |
tree | 9aa18ac045eec9515ed225f900717e8a5f4fd8d6 | |
parent | e430426654c6a99fb1977bae71d4844e876c4a52 (diff) | |
parent | f6ac55b6c156cebf750376dc08e06ffdade82717 (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.txt | 4 | ||||
-rw-r--r-- | fs/9p/Kconfig | 13 | ||||
-rw-r--r-- | fs/9p/Makefile | 1 | ||||
-rw-r--r-- | fs/9p/acl.c | 392 | ||||
-rw-r--r-- | fs/9p/acl.h | 49 | ||||
-rw-r--r-- | fs/9p/fid.c | 1 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 22 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 10 | ||||
-rw-r--r-- | fs/9p/v9fs_vfs.h | 4 | ||||
-rw-r--r-- | fs/9p/vfs_addr.c | 30 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 4 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 265 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 253 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 14 | ||||
-rw-r--r-- | fs/9p/xattr.c | 52 | ||||
-rw-r--r-- | fs/9p/xattr.h | 6 | ||||
-rw-r--r-- | include/linux/magic.h | 1 | ||||
-rw-r--r-- | include/net/9p/9p.h | 54 | ||||
-rw-r--r-- | include/net/9p/client.h | 4 | ||||
-rw-r--r-- | net/9p/client.c | 178 | ||||
-rw-r--r-- | net/9p/protocol.c | 5 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 76 |
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 | |||
21 | config 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 | ||
15 | 9p-$(CONFIG_9P_FSCACHE) += cache.o | 15 | 9p-$(CONFIG_9P_FSCACHE) += cache.o |
16 | 9p-$(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 | |||
27 | static 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 | |||
50 | err_out: | ||
51 | kfree(value); | ||
52 | return acl; | ||
53 | } | ||
54 | |||
55 | int 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 | |||
82 | static 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 | |||
94 | int 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 | |||
119 | static 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); | ||
147 | err_free_out: | ||
148 | kfree(buffer); | ||
149 | return retval; | ||
150 | } | ||
151 | |||
152 | int 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 | |||
174 | int 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 | |||
186 | int 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; | ||
220 | cleanup: | ||
221 | posix_acl_release(acl); | ||
222 | return retval; | ||
223 | |||
224 | } | ||
225 | |||
226 | static 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 | |||
244 | static 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 | |||
272 | static 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 | |||
292 | static 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); | ||
375 | err_out: | ||
376 | posix_acl_release(acl); | ||
377 | return retval; | ||
378 | } | ||
379 | |||
380 | const 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 | |||
387 | const 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 | ||
18 | extern int v9fs_get_acl(struct inode *, struct p9_fid *); | ||
19 | extern int v9fs_check_acl(struct inode *inode, int mask); | ||
20 | extern int v9fs_acl_chmod(struct dentry *); | ||
21 | extern int v9fs_set_create_acl(struct dentry *, | ||
22 | struct posix_acl *, struct posix_acl *); | ||
23 | extern 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 | ||
27 | static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) | ||
28 | { | ||
29 | return 0; | ||
30 | } | ||
31 | static inline int v9fs_acl_chmod(struct dentry *dentry) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | static inline int v9fs_set_create_acl(struct dentry *dentry, | ||
36 | struct posix_acl *dpacl, | ||
37 | struct posix_acl *pacl) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | static 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 | |||
36 | enum p9_session_flags { | 41 | enum 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); | |||
113 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); | 117 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); |
114 | void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); | 118 | void 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 | ||
65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | 65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); |
66 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 66 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
67 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | ||
68 | int 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 | */ | ||
176 | ssize_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 | } | ||
157 | const struct address_space_operations v9fs_addr_operations = { | 186 | const 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 | ||
46 | static const struct file_operations v9fs_cached_file_operations; | 47 | static const struct file_operations v9fs_cached_file_operations; |
48 | static 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 | ||
137 | static 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 | } | ||
210 | out: | ||
211 | return res; | ||
212 | } | ||
213 | |||
214 | static 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 | |||
267 | static 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; | ||
290 | out_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 | |||
302 | static 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; | ||
333 | out_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 | |||
219 | v9fs_file_write(struct file *filp, const char __user * data, | 423 | v9fs_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; |
475 | out: | ||
476 | return retval; | ||
264 | } | 477 | } |
265 | 478 | ||
266 | static int v9fs_file_fsync(struct file *filp, int datasync) | 479 | static 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 | ||
494 | int 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 | |||
281 | static const struct file_operations v9fs_cached_file_operations = { | 508 | static 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 | ||
520 | static 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 | |||
293 | const struct file_operations v9fs_file_operations = { | 533 | const 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 | ||
48 | static const struct inode_operations v9fs_dir_inode_operations; | 50 | static const struct inode_operations v9fs_dir_inode_operations; |
49 | static const struct inode_operations v9fs_dir_inode_operations_dotu; | 51 | static const struct inode_operations v9fs_dir_inode_operations_dotu; |
@@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl; | |||
53 | static const struct inode_operations v9fs_symlink_inode_operations; | 55 | static const struct inode_operations v9fs_symlink_inode_operations; |
54 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; | 56 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; |
55 | 57 | ||
58 | static int | ||
59 | v9fs_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; |
505 | error: | 516 | error: |
@@ -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 | ||
556 | static int | ||
557 | v9fs_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 | ||
657 | static int | 661 | static int |
658 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | 662 | v9fs_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 | ||
862 | static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, | 889 | static 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 | |||
924 | error: | 975 | error: |
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 | ||
984 | inst_out: | 1035 | inst_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 | ||
1044 | error_iput: | ||
1045 | iput(inode); | ||
993 | error: | 1046 | error: |
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 | ||
1240 | static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | 1293 | int 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 | */ |
1857 | static int | 1911 | static int |
1858 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, | 1912 | v9fs_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); | ||
1937 | error: | 1997 | error: |
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 | ||
2003 | static int | ||
2004 | v9fs_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 | |||
2034 | static void * | ||
2035 | v9fs_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 | |||
1943 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 2057 | static 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 | ||
1976 | static const struct inode_operations v9fs_dir_inode_operations = { | 2090 | static 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 | ||
2002 | static const struct inode_operations v9fs_symlink_inode_operations = { | 2117 | static 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 | ||
2010 | static const struct inode_operations v9fs_symlink_inode_operations_dotl = { | 2125 | static 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 | ||
50 | static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; | 52 | static 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 | /* | 24 | ssize_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 | */ | ||
34 | ssize_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 | */ | ||
85 | ssize_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 | ||
157 | const struct xattr_handler *v9fs_xattr_handlers[] = { | 165 | const 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 | ||
19 | extern const struct xattr_handler *v9fs_xattr_handlers[]; | 21 | extern const struct xattr_handler *v9fs_xattr_handlers[]; |
20 | extern struct xattr_handler v9fs_xattr_user_handler; | 22 | extern struct xattr_handler v9fs_xattr_user_handler; |
23 | extern const struct xattr_handler v9fs_xattr_acl_access_handler; | ||
24 | extern const struct xattr_handler v9fs_xattr_acl_default_handler; | ||
21 | 25 | ||
26 | extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *, | ||
27 | void *, size_t); | ||
22 | extern ssize_t v9fs_xattr_get(struct dentry *, const char *, | 28 | extern ssize_t v9fs_xattr_get(struct dentry *, const char *, |
23 | void *, size_t); | 29 | void *, size_t); |
24 | extern int v9fs_xattr_set(struct dentry *, const char *, | 30 | extern 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 | ||
139 | enum p9_msg_t { | 141 | enum 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 | |||
490 | struct 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 | |||
507 | struct 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 */ |
462 | struct p9_tstatfs { | 516 | struct 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, | |||
229 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | 229 | int 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); |
231 | int p9_client_clunk(struct p9_fid *fid); | 231 | int p9_client_clunk(struct p9_fid *fid); |
232 | int p9_client_fsync(struct p9_fid *fid, int datasync); | ||
232 | int p9_client_remove(struct p9_fid *fid); | 233 | int p9_client_remove(struct p9_fid *fid); |
233 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 234 | int 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 *); |
249 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | 250 | int 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 *); |
252 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); | ||
253 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); | ||
251 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); | 254 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); |
252 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); | 255 | void 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); | |||
259 | int p9_is_proto_dotl(struct p9_client *clnt); | 262 | int p9_is_proto_dotl(struct p9_client *clnt); |
260 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); | 263 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); |
261 | int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); | 264 | int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); |
265 | int 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 | |||
486 | out_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 | } |
1152 | EXPORT_SYMBOL(p9_client_link); | 1166 | EXPORT_SYMBOL(p9_client_link); |
1153 | 1167 | ||
1168 | int 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 | |||
1189 | error: | ||
1190 | return err; | ||
1191 | } | ||
1192 | EXPORT_SYMBOL(p9_client_fsync); | ||
1193 | |||
1154 | int p9_client_clunk(struct p9_fid *fid) | 1194 | int 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 | } |
1763 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1806 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
1807 | |||
1808 | int 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); | ||
1834 | error: | ||
1835 | p9_free_req(clnt, req); | ||
1836 | return err; | ||
1837 | |||
1838 | } | ||
1839 | EXPORT_SYMBOL(p9_client_lock_dotl); | ||
1840 | |||
1841 | int 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); | ||
1869 | error: | ||
1870 | p9_free_req(clnt, req); | ||
1871 | return err; | ||
1872 | } | ||
1873 | EXPORT_SYMBOL(p9_client_getlock_dotl); | ||
1874 | |||
1875 | int 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); | ||
1895 | error: | ||
1896 | p9_free_req(clnt, req); | ||
1897 | return err; | ||
1898 | } | ||
1899 | EXPORT_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 | |||
122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 122 | pdu_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 | ||
223 | req_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 | ||
344 | out_free_tag: | ||
345 | kfree(tag); | ||
301 | out_free_vq: | 346 | out_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 | } |