diff options
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r-- | fs/9p/vfs_file.c | 265 |
1 files changed, 253 insertions, 12 deletions
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 | }; |