2 * linux/fs/9p/vfs_file.c
4 * This file contians vfs file ops for 9P2000.
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
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.
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.
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
26 #include <linux/module.h>
27 #include <linux/errno.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>
48 * v9fs_file_open - open a file (or directory)
49 * @inode: inode to be opened
50 * @file: file being opened
54 int v9fs_file_open(struct inode *inode, struct file *file)
57 struct v9fs_session_info *v9ses;
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;
66 omode = v9fs_uflags2omode(file->f_flags,
67 v9fs_proto_dotu(v9ses));
68 fid = file->private_data;
70 fid = v9fs_fid_clone(file->f_path.dentry);
74 err = p9_client_open(fid, omode);
79 if (file->f_flags & O_TRUNC) {
80 i_size_write(inode, 0);
83 if ((file->f_flags & O_APPEND) &&
84 (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
85 generic_file_llseek(file, 0, SEEK_END);
88 file->private_data = fid;
89 #ifdef CONFIG_9P_FSCACHE
91 v9fs_cache_inode_set_cookie(inode, file);
97 * v9fs_file_lock - lock a file (or directory)
98 * @filp: file to be locked
100 * @fl: file lock structure
102 * Bugs: this looks like a local only lock, we should extend into 9P
103 * by using open exclusive
106 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
109 struct inode *inode = filp->f_path.dentry->d_inode;
111 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
113 /* No mandatory locks */
114 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
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);
125 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
127 struct p9_flock flock;
131 unsigned char fl_type;
133 fid = filp->private_data;
136 if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
139 res = posix_lock_file_wait(filp, fl);
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)
150 flock.length = fl->fl_end - fl->fl_start + 1;
151 flock.proc_id = fl->fl_pid;
152 flock.client_id = utsname()->nodename;
154 flock.flags = P9_LOCK_FLAGS_BLOCK;
157 * if its a blocked request and we get P9_LOCK_BLOCKED as the status
158 * for lock request, keep on trying
161 res = p9_client_lock_dotl(fid, &flock, &status);
165 if (status != P9_LOCK_BLOCKED)
167 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
169 schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
172 /* map 9p status to VFS status */
174 case P9_LOCK_SUCCESS:
177 case P9_LOCK_BLOCKED:
189 * incase server returned error for lock request, revert
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;
202 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
204 struct p9_getlock glock;
208 fid = filp->private_data;
211 posix_test_lock(filp, fl);
213 * if we have a conflicting lock locally, no need to validate
216 if (fl->fl_type != F_UNLCK)
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)
226 glock.length = fl->fl_end - fl->fl_start + 1;
227 glock.proc_id = fl->fl_pid;
228 glock.client_id = utsname()->nodename;
230 res = p9_client_getlock_dotl(fid, &glock);
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;
239 fl->fl_end = glock.start + glock.length - 1;
240 fl->fl_pid = glock.proc_id;
242 fl->fl_type = F_UNLCK;
248 * v9fs_file_lock_dotl - lock a file (or directory)
249 * @filp: file to be locked
251 * @fl: file lock structure
255 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
257 struct inode *inode = filp->f_path.dentry->d_inode;
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);
263 /* No mandatory locks */
264 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
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);
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);
283 * v9fs_file_flock_dotl - lock a file
284 * @filp: file to be locked
286 * @fl: file lock structure
290 static int v9fs_file_flock_dotl(struct file *filp, int cmd,
291 struct file_lock *fl)
293 struct inode *inode = filp->f_path.dentry->d_inode;
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);
299 /* No mandatory locks */
300 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
303 if (!(fl->fl_flags & FL_FLOCK))
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);
310 /* Convert flock to posix lock */
311 fl->fl_owner = (fl_owner_t)filp;
313 fl->fl_end = OFFSET_MAX;
314 fl->fl_flags |= FL_POSIX;
315 fl->fl_flags ^= FL_FLOCK;
317 if (IS_SETLK(cmd) | IS_SETLKW(cmd))
318 ret = v9fs_file_do_lock(filp, cmd, fl);
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
336 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
340 struct p9_fid *fid = filp->private_data;
342 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
343 (long long unsigned) offset, count);
347 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
349 n = p9_client_read(fid, data, udata, offset, count);
361 } while (count > 0 && n == size);
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
379 v9fs_file_read(struct file *filp, char __user *udata, size_t count,
386 P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
387 fid = filp->private_data;
389 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
391 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
393 ret = p9_client_read(fid, NULL, udata, *offset, count);
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
411 v9fs_file_write(struct file *filp, const char __user * data,
412 size_t count, loff_t * offset)
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;
423 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
424 (int)count, (int)*offset);
426 fid = filp->private_data;
429 retval = generic_write_checks(filp, &origin, &count, 0);
434 if ((ssize_t) count < 0)
441 n = p9_client_write(fid, NULL, data+total, origin+total, count);
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,
455 i_size_write(inode, i_size_read(inode) + total);
456 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
467 static int v9fs_file_fsync(struct file *filp, int datasync)
470 struct p9_wstat wstat;
473 P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
475 fid = filp->private_data;
476 v9fs_blank_wstat(&wstat);
478 retval = p9_client_wstat(fid, &wstat);
482 int v9fs_file_fsync_dotl(struct file *filp, int datasync)
487 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
490 fid = filp->private_data;
492 retval = p9_client_fsync(fid, datasync);
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,
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,
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,
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,