Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[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 static const struct file_operations v9fs_cached_file_operations;
48 static const struct file_operations v9fs_cached_file_operations_dotl;
49
50 /**
51  * v9fs_file_open - open a file (or directory)
52  * @inode: inode to be opened
53  * @file: file being opened
54  *
55  */
56
57 int v9fs_file_open(struct inode *inode, struct file *file)
58 {
59         int err;
60         struct v9fs_session_info *v9ses;
61         struct p9_fid *fid;
62         int omode;
63
64         P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
65         v9ses = v9fs_inode2v9ses(inode);
66         if (v9fs_proto_dotl(v9ses))
67                 omode = file->f_flags;
68         else
69                 omode = v9fs_uflags2omode(file->f_flags,
70                                         v9fs_proto_dotu(v9ses));
71         fid = file->private_data;
72         if (!fid) {
73                 fid = v9fs_fid_clone(file->f_path.dentry);
74                 if (IS_ERR(fid))
75                         return PTR_ERR(fid);
76
77                 err = p9_client_open(fid, omode);
78                 if (err < 0) {
79                         p9_client_clunk(fid);
80                         return err;
81                 }
82                 if (file->f_flags & O_TRUNC) {
83                         i_size_write(inode, 0);
84                         inode->i_blocks = 0;
85                 }
86                 if ((file->f_flags & O_APPEND) &&
87                         (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
88                         generic_file_llseek(file, 0, SEEK_END);
89         }
90
91         file->private_data = fid;
92         if ((fid->qid.version) && (v9ses->cache)) {
93                 P9_DPRINTK(P9_DEBUG_VFS, "cached");
94                 /* enable cached file options */
95                 if(file->f_op == &v9fs_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;
99
100 #ifdef CONFIG_9P_FSCACHE
101                 v9fs_cache_inode_set_cookie(inode, file);
102 #endif
103         }
104
105         return 0;
106 }
107
108 /**
109  * v9fs_file_lock - lock a file (or directory)
110  * @filp: file to be locked
111  * @cmd: lock command
112  * @fl: file lock structure
113  *
114  * Bugs: this looks like a local only lock, we should extend into 9P
115  *       by using open exclusive
116  */
117
118 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
119 {
120         int res = 0;
121         struct inode *inode = filp->f_path.dentry->d_inode;
122
123         P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
124
125         /* No mandatory locks */
126         if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
127                 return -ENOLCK;
128
129         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
130                 filemap_write_and_wait(inode->i_mapping);
131                 invalidate_mapping_pages(&inode->i_data, 0, -1);
132         }
133
134         return res;
135 }
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
337 /**
338  * v9fs_file_readn - read from a file
339  * @filp: file pointer to read
340  * @data: data buffer to read data into
341  * @udata: user data buffer to read data into
342  * @count: size of buffer
343  * @offset: offset at which to read data
344  *
345  */
346
347 ssize_t
348 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
349                u64 offset)
350 {
351         int n, total, size;
352         struct p9_fid *fid = filp->private_data;
353
354         P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
355                                         (long long unsigned) offset, count);
356
357         n = 0;
358         total = 0;
359         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
360         do {
361                 n = p9_client_read(fid, data, udata, offset, count);
362                 if (n <= 0)
363                         break;
364
365                 if (data)
366                         data += n;
367                 if (udata)
368                         udata += n;
369
370                 offset += n;
371                 count -= n;
372                 total += n;
373         } while (count > 0 && n == size);
374
375         if (n < 0)
376                 total = n;
377
378         return total;
379 }
380
381 /**
382  * v9fs_file_read - read from a file
383  * @filp: file pointer to read
384  * @udata: user data buffer to read data into
385  * @count: size of buffer
386  * @offset: offset at which to read data
387  *
388  */
389
390 static ssize_t
391 v9fs_file_read(struct file *filp, char __user *udata, size_t count,
392                loff_t * offset)
393 {
394         int ret;
395         struct p9_fid *fid;
396         size_t size;
397
398         P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
399         fid = filp->private_data;
400
401         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
402         if (count > size)
403                 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
404         else
405                 ret = p9_client_read(fid, NULL, udata, *offset, count);
406
407         if (ret > 0)
408                 *offset += ret;
409
410         return ret;
411 }
412
413 /**
414  * v9fs_file_write - write to a file
415  * @filp: file pointer to write
416  * @data: data buffer to write data from
417  * @count: size of buffer
418  * @offset: offset at which to write data
419  *
420  */
421
422 static ssize_t
423 v9fs_file_write(struct file *filp, const char __user * data,
424                 size_t count, loff_t * offset)
425 {
426         ssize_t retval;
427         size_t total = 0;
428         int n;
429         struct p9_fid *fid;
430         struct p9_client *clnt;
431         struct inode *inode = filp->f_path.dentry->d_inode;
432         loff_t origin = *offset;
433         unsigned long pg_start, pg_end;
434
435         P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
436                 (int)count, (int)*offset);
437
438         fid = filp->private_data;
439         clnt = fid->clnt;
440
441         retval = generic_write_checks(filp, &origin, &count, 0);
442         if (retval)
443                 goto out;
444
445         retval = -EINVAL;
446         if ((ssize_t) count < 0)
447                 goto out;
448         retval = 0;
449         if (!count)
450                 goto out;
451
452         do {
453                 n = p9_client_write(fid, NULL, data+total, origin+total, count);
454                 if (n <= 0)
455                         break;
456                 count -= n;
457                 total += n;
458         } while (count > 0);
459
460         if (total > 0) {
461                 pg_start = origin >> PAGE_CACHE_SHIFT;
462                 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
463                 if (inode->i_mapping && inode->i_mapping->nrpages)
464                         invalidate_inode_pages2_range(inode->i_mapping,
465                                                       pg_start, pg_end);
466                 *offset += total;
467                 i_size_write(inode, i_size_read(inode) + total);
468                 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
469         }
470
471         if (n < 0)
472                 retval = n;
473         else
474                 retval = total;
475 out:
476         return retval;
477 }
478
479 static int v9fs_file_fsync(struct file *filp, int datasync)
480 {
481         struct p9_fid *fid;
482         struct p9_wstat wstat;
483         int retval;
484
485         P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
486
487         fid = filp->private_data;
488         v9fs_blank_wstat(&wstat);
489
490         retval = p9_client_wstat(fid, &wstat);
491         return retval;
492 }
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
508 static const struct file_operations v9fs_cached_file_operations = {
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,
516         .mmap = generic_file_readonly_mmap,
517         .fsync = v9fs_file_fsync,
518 };
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
533 const struct file_operations v9fs_file_operations = {
534         .llseek = generic_file_llseek,
535         .read = v9fs_file_read,
536         .write = v9fs_file_write,
537         .open = v9fs_file_open,
538         .release = v9fs_dir_release,
539         .lock = v9fs_file_lock,
540         .mmap = generic_file_readonly_mmap,
541         .fsync = v9fs_file_fsync,
542 };
543
544 const struct file_operations v9fs_file_operations_dotl = {
545         .llseek = generic_file_llseek,
546         .read = v9fs_file_read,
547         .write = v9fs_file_write,
548         .open = v9fs_file_open,
549         .release = v9fs_dir_release,
550         .lock = v9fs_file_lock_dotl,
551         .flock = v9fs_file_flock_dotl,
552         .mmap = generic_file_readonly_mmap,
553         .fsync = v9fs_file_fsync_dotl,
554 };