fs/9p: set fs cache cookie in create path also
[pandora-kernel.git] / fs / 9p / vfs_file.c
1 /*
2  *  linux/fs/9p/vfs_file.c
3  *
4  * This file contians vfs file ops for 9P2000.
5  *
6  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2
11  *  as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to:
20  *  Free Software Foundation
21  *  51 Franklin Street, Fifth Floor
22  *  Boston, MA  02111-1301  USA
23  *
24  */
25
26 #include <linux/module.h>
27 #include <linux/errno.h>
28 #include <linux/fs.h>
29 #include <linux/sched.h>
30 #include <linux/file.h>
31 #include <linux/stat.h>
32 #include <linux/string.h>
33 #include <linux/inet.h>
34 #include <linux/list.h>
35 #include <linux/pagemap.h>
36 #include <linux/utsname.h>
37 #include <asm/uaccess.h>
38 #include <linux/idr.h>
39 #include <net/9p/9p.h>
40 #include <net/9p/client.h>
41
42 #include "v9fs.h"
43 #include "v9fs_vfs.h"
44 #include "fid.h"
45 #include "cache.h"
46
47 /**
48  * v9fs_file_open - open a file (or directory)
49  * @inode: inode to be opened
50  * @file: file being opened
51  *
52  */
53
54 int v9fs_file_open(struct inode *inode, struct file *file)
55 {
56         int err;
57         struct v9fs_session_info *v9ses;
58         struct p9_fid *fid;
59         int omode;
60
61         P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
62         v9ses = v9fs_inode2v9ses(inode);
63         if (v9fs_proto_dotl(v9ses))
64                 omode = file->f_flags;
65         else
66                 omode = v9fs_uflags2omode(file->f_flags,
67                                         v9fs_proto_dotu(v9ses));
68         fid = file->private_data;
69         if (!fid) {
70                 fid = v9fs_fid_clone(file->f_path.dentry);
71                 if (IS_ERR(fid))
72                         return PTR_ERR(fid);
73
74                 err = p9_client_open(fid, omode);
75                 if (err < 0) {
76                         p9_client_clunk(fid);
77                         return err;
78                 }
79                 if (file->f_flags & O_TRUNC) {
80                         i_size_write(inode, 0);
81                         inode->i_blocks = 0;
82                 }
83                 if ((file->f_flags & O_APPEND) &&
84                         (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
85                         generic_file_llseek(file, 0, SEEK_END);
86         }
87
88         file->private_data = fid;
89 #ifdef CONFIG_9P_FSCACHE
90         if (v9ses->cache)
91                 v9fs_cache_inode_set_cookie(inode, file);
92 #endif
93         return 0;
94 }
95
96 /**
97  * v9fs_file_lock - lock a file (or directory)
98  * @filp: file to be locked
99  * @cmd: lock command
100  * @fl: file lock structure
101  *
102  * Bugs: this looks like a local only lock, we should extend into 9P
103  *       by using open exclusive
104  */
105
106 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
107 {
108         int res = 0;
109         struct inode *inode = filp->f_path.dentry->d_inode;
110
111         P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
112
113         /* No mandatory locks */
114         if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
115                 return -ENOLCK;
116
117         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
118                 filemap_write_and_wait(inode->i_mapping);
119                 invalidate_mapping_pages(&inode->i_data, 0, -1);
120         }
121
122         return res;
123 }
124
125 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
126 {
127         struct p9_flock flock;
128         struct p9_fid *fid;
129         uint8_t status;
130         int res = 0;
131         unsigned char fl_type;
132
133         fid = filp->private_data;
134         BUG_ON(fid == NULL);
135
136         if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
137                 BUG();
138
139         res = posix_lock_file_wait(filp, fl);
140         if (res < 0)
141                 goto out;
142
143         /* convert posix lock to p9 tlock args */
144         memset(&flock, 0, sizeof(flock));
145         flock.type = fl->fl_type;
146         flock.start = fl->fl_start;
147         if (fl->fl_end == OFFSET_MAX)
148                 flock.length = 0;
149         else
150                 flock.length = fl->fl_end - fl->fl_start + 1;
151         flock.proc_id = fl->fl_pid;
152         flock.client_id = utsname()->nodename;
153         if (IS_SETLKW(cmd))
154                 flock.flags = P9_LOCK_FLAGS_BLOCK;
155
156         /*
157          * if its a blocked request and we get P9_LOCK_BLOCKED as the status
158          * for lock request, keep on trying
159          */
160         for (;;) {
161                 res = p9_client_lock_dotl(fid, &flock, &status);
162                 if (res < 0)
163                         break;
164
165                 if (status != P9_LOCK_BLOCKED)
166                         break;
167                 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
168                         break;
169                 schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
170         }
171
172         /* map 9p status to VFS status */
173         switch (status) {
174         case P9_LOCK_SUCCESS:
175                 res = 0;
176                 break;
177         case P9_LOCK_BLOCKED:
178                 res = -EAGAIN;
179                 break;
180         case P9_LOCK_ERROR:
181         case P9_LOCK_GRACE:
182                 res = -ENOLCK;
183                 break;
184         default:
185                 BUG();
186         }
187
188         /*
189          * incase server returned error for lock request, revert
190          * it locally
191          */
192         if (res < 0 && fl->fl_type != F_UNLCK) {
193                 fl_type = fl->fl_type;
194                 fl->fl_type = F_UNLCK;
195                 res = posix_lock_file_wait(filp, fl);
196                 fl->fl_type = fl_type;
197         }
198 out:
199         return res;
200 }
201
202 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
203 {
204         struct p9_getlock glock;
205         struct p9_fid *fid;
206         int res = 0;
207
208         fid = filp->private_data;
209         BUG_ON(fid == NULL);
210
211         posix_test_lock(filp, fl);
212         /*
213          * if we have a conflicting lock locally, no need to validate
214          * with server
215          */
216         if (fl->fl_type != F_UNLCK)
217                 return res;
218
219         /* convert posix lock to p9 tgetlock args */
220         memset(&glock, 0, sizeof(glock));
221         glock.type = fl->fl_type;
222         glock.start = fl->fl_start;
223         if (fl->fl_end == OFFSET_MAX)
224                 glock.length = 0;
225         else
226                 glock.length = fl->fl_end - fl->fl_start + 1;
227         glock.proc_id = fl->fl_pid;
228         glock.client_id = utsname()->nodename;
229
230         res = p9_client_getlock_dotl(fid, &glock);
231         if (res < 0)
232                 return res;
233         if (glock.type != F_UNLCK) {
234                 fl->fl_type = glock.type;
235                 fl->fl_start = glock.start;
236                 if (glock.length == 0)
237                         fl->fl_end = OFFSET_MAX;
238                 else
239                         fl->fl_end = glock.start + glock.length - 1;
240                 fl->fl_pid = glock.proc_id;
241         } else
242                 fl->fl_type = F_UNLCK;
243
244         return res;
245 }
246
247 /**
248  * v9fs_file_lock_dotl - lock a file (or directory)
249  * @filp: file to be locked
250  * @cmd: lock command
251  * @fl: file lock structure
252  *
253  */
254
255 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
256 {
257         struct inode *inode = filp->f_path.dentry->d_inode;
258         int ret = -ENOLCK;
259
260         P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
261                                 cmd, fl, filp->f_path.dentry->d_name.name);
262
263         /* No mandatory locks */
264         if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
265                 goto out_err;
266
267         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
268                 filemap_write_and_wait(inode->i_mapping);
269                 invalidate_mapping_pages(&inode->i_data, 0, -1);
270         }
271
272         if (IS_SETLK(cmd) || IS_SETLKW(cmd))
273                 ret = v9fs_file_do_lock(filp, cmd, fl);
274         else if (IS_GETLK(cmd))
275                 ret = v9fs_file_getlock(filp, fl);
276         else
277                 ret = -EINVAL;
278 out_err:
279         return ret;
280 }
281
282 /**
283  * v9fs_file_flock_dotl - lock a file
284  * @filp: file to be locked
285  * @cmd: lock command
286  * @fl: file lock structure
287  *
288  */
289
290 static int v9fs_file_flock_dotl(struct file *filp, int cmd,
291         struct file_lock *fl)
292 {
293         struct inode *inode = filp->f_path.dentry->d_inode;
294         int ret = -ENOLCK;
295
296         P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
297                                 cmd, fl, filp->f_path.dentry->d_name.name);
298
299         /* No mandatory locks */
300         if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
301                 goto out_err;
302
303         if (!(fl->fl_flags & FL_FLOCK))
304                 goto out_err;
305
306         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
307                 filemap_write_and_wait(inode->i_mapping);
308                 invalidate_mapping_pages(&inode->i_data, 0, -1);
309         }
310         /* Convert flock to posix lock */
311         fl->fl_owner = (fl_owner_t)filp;
312         fl->fl_start = 0;
313         fl->fl_end = OFFSET_MAX;
314         fl->fl_flags |= FL_POSIX;
315         fl->fl_flags ^= FL_FLOCK;
316
317         if (IS_SETLK(cmd) | IS_SETLKW(cmd))
318                 ret = v9fs_file_do_lock(filp, cmd, fl);
319         else
320                 ret = -EINVAL;
321 out_err:
322         return ret;
323 }
324
325 /**
326  * v9fs_file_readn - read from a file
327  * @filp: file pointer to read
328  * @data: data buffer to read data into
329  * @udata: user data buffer to read data into
330  * @count: size of buffer
331  * @offset: offset at which to read data
332  *
333  */
334
335 ssize_t
336 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
337                u64 offset)
338 {
339         int n, total, size;
340         struct p9_fid *fid = filp->private_data;
341
342         P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
343                                         (long long unsigned) offset, count);
344
345         n = 0;
346         total = 0;
347         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
348         do {
349                 n = p9_client_read(fid, data, udata, offset, count);
350                 if (n <= 0)
351                         break;
352
353                 if (data)
354                         data += n;
355                 if (udata)
356                         udata += n;
357
358                 offset += n;
359                 count -= n;
360                 total += n;
361         } while (count > 0 && n == size);
362
363         if (n < 0)
364                 total = n;
365
366         return total;
367 }
368
369 /**
370  * v9fs_file_read - read from a file
371  * @filp: file pointer to read
372  * @udata: user data buffer to read data into
373  * @count: size of buffer
374  * @offset: offset at which to read data
375  *
376  */
377
378 static ssize_t
379 v9fs_file_read(struct file *filp, char __user *udata, size_t count,
380                loff_t * offset)
381 {
382         int ret;
383         struct p9_fid *fid;
384         size_t size;
385
386         P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
387         fid = filp->private_data;
388
389         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
390         if (count > size)
391                 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
392         else
393                 ret = p9_client_read(fid, NULL, udata, *offset, count);
394
395         if (ret > 0)
396                 *offset += ret;
397
398         return ret;
399 }
400
401 /**
402  * v9fs_file_write - write to a file
403  * @filp: file pointer to write
404  * @data: data buffer to write data from
405  * @count: size of buffer
406  * @offset: offset at which to write data
407  *
408  */
409
410 static ssize_t
411 v9fs_file_write(struct file *filp, const char __user * data,
412                 size_t count, loff_t * offset)
413 {
414         ssize_t retval;
415         size_t total = 0;
416         int n;
417         struct p9_fid *fid;
418         struct p9_client *clnt;
419         struct inode *inode = filp->f_path.dentry->d_inode;
420         loff_t origin = *offset;
421         unsigned long pg_start, pg_end;
422
423         P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
424                 (int)count, (int)*offset);
425
426         fid = filp->private_data;
427         clnt = fid->clnt;
428
429         retval = generic_write_checks(filp, &origin, &count, 0);
430         if (retval)
431                 goto out;
432
433         retval = -EINVAL;
434         if ((ssize_t) count < 0)
435                 goto out;
436         retval = 0;
437         if (!count)
438                 goto out;
439
440         do {
441                 n = p9_client_write(fid, NULL, data+total, origin+total, count);
442                 if (n <= 0)
443                         break;
444                 count -= n;
445                 total += n;
446         } while (count > 0);
447
448         if (total > 0) {
449                 pg_start = origin >> PAGE_CACHE_SHIFT;
450                 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
451                 if (inode->i_mapping && inode->i_mapping->nrpages)
452                         invalidate_inode_pages2_range(inode->i_mapping,
453                                                       pg_start, pg_end);
454                 *offset += total;
455                 i_size_write(inode, i_size_read(inode) + total);
456                 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
457         }
458
459         if (n < 0)
460                 retval = n;
461         else
462                 retval = total;
463 out:
464         return retval;
465 }
466
467 static int v9fs_file_fsync(struct file *filp, int datasync)
468 {
469         struct p9_fid *fid;
470         struct p9_wstat wstat;
471         int retval;
472
473         P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
474
475         fid = filp->private_data;
476         v9fs_blank_wstat(&wstat);
477
478         retval = p9_client_wstat(fid, &wstat);
479         return retval;
480 }
481
482 int v9fs_file_fsync_dotl(struct file *filp, int datasync)
483 {
484         struct p9_fid *fid;
485         int retval;
486
487         P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
488                         filp, datasync);
489
490         fid = filp->private_data;
491
492         retval = p9_client_fsync(fid, datasync);
493         return retval;
494 }
495
496 const struct file_operations v9fs_cached_file_operations = {
497         .llseek = generic_file_llseek,
498         .read = do_sync_read,
499         .aio_read = generic_file_aio_read,
500         .write = v9fs_file_write,
501         .open = v9fs_file_open,
502         .release = v9fs_dir_release,
503         .lock = v9fs_file_lock,
504         .mmap = generic_file_readonly_mmap,
505         .fsync = v9fs_file_fsync,
506 };
507
508 const struct file_operations v9fs_cached_file_operations_dotl = {
509         .llseek = generic_file_llseek,
510         .read = do_sync_read,
511         .aio_read = generic_file_aio_read,
512         .write = v9fs_file_write,
513         .open = v9fs_file_open,
514         .release = v9fs_dir_release,
515         .lock = v9fs_file_lock_dotl,
516         .flock = v9fs_file_flock_dotl,
517         .mmap = generic_file_readonly_mmap,
518         .fsync = v9fs_file_fsync_dotl,
519 };
520
521 const struct file_operations v9fs_file_operations = {
522         .llseek = generic_file_llseek,
523         .read = v9fs_file_read,
524         .write = v9fs_file_write,
525         .open = v9fs_file_open,
526         .release = v9fs_dir_release,
527         .lock = v9fs_file_lock,
528         .mmap = generic_file_readonly_mmap,
529         .fsync = v9fs_file_fsync,
530 };
531
532 const struct file_operations v9fs_file_operations_dotl = {
533         .llseek = generic_file_llseek,
534         .read = v9fs_file_read,
535         .write = v9fs_file_write,
536         .open = v9fs_file_open,
537         .release = v9fs_dir_release,
538         .lock = v9fs_file_lock_dotl,
539         .flock = v9fs_file_flock_dotl,
540         .mmap = generic_file_readonly_mmap,
541         .fsync = v9fs_file_fsync_dotl,
542 };