blob: f455c45a8c5fe15a90d83a185a391aad8d1c52d7 [file] [log] [blame]
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -07001/*
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
Eric Van Hensbergen42e8c502006-03-25 03:07:28 -080010 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070012 *
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>
Al Viro914e2632006-10-18 13:55:46 -040029#include <linux/sched.h>
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070030#include <linux/file.h>
31#include <linux/stat.h>
32#include <linux/string.h>
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070033#include <linux/inet.h>
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070034#include <linux/list.h>
Abhishek Kulkarni637d0202009-09-22 11:34:05 -050035#include <linux/pagemap.h>
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070036#include <asm/uaccess.h>
37#include <linux/idr.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050038#include <net/9p/9p.h>
39#include <net/9p/client.h>
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070040
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070041#include "v9fs.h"
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070042#include "v9fs_vfs.h"
43#include "fid.h"
Abhishek Kulkarni60e78d22009-09-23 13:00:27 -050044#include "cache.h"
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070045
Adrian Bunkd32b6872007-03-05 02:49:48 +010046static const struct file_operations v9fs_cached_file_operations;
47
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070048/**
49 * v9fs_file_open - open a file (or directory)
50 * @inode: inode to be opened
51 * @file: file being opened
52 *
53 */
54
55int v9fs_file_open(struct inode *inode, struct file *file)
56{
Latchesar Ionkov6a3124a2006-03-02 02:54:30 -080057 int err;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050058 struct v9fs_session_info *v9ses;
59 struct p9_fid *fid;
60 int omode;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -070061
M. Mohan Kumaref565472010-06-22 19:47:50 +053062 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050063 v9ses = v9fs_inode2v9ses(inode);
M. Mohan Kumaref565472010-06-22 19:47:50 +053064 if (v9fs_proto_dotl(v9ses))
65 omode = file->f_flags;
66 else
67 omode = v9fs_uflags2omode(file->f_flags,
68 v9fs_proto_dotu(v9ses));
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050069 fid = file->private_data;
70 if (!fid) {
71 fid = v9fs_fid_clone(file->f_path.dentry);
72 if (IS_ERR(fid))
73 return PTR_ERR(fid);
74
75 err = p9_client_open(fid, omode);
Eric Van Hensbergen9523a842007-07-13 13:01:27 -050076 if (err < 0) {
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050077 p9_client_clunk(fid);
78 return err;
79 }
M. Mohan Kumaref565472010-06-22 19:47:50 +053080 if (file->f_flags & O_TRUNC) {
Abhishek Kulkarni7549ae32009-09-22 11:34:05 -050081 i_size_write(inode, 0);
Eric Van Hensbergen9523a842007-07-13 13:01:27 -050082 inode->i_blocks = 0;
83 }
M. Mohan Kumaref565472010-06-22 19:47:50 +053084 if ((file->f_flags & O_APPEND) &&
85 (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
Eric Van Hensbergen2e4bef42008-06-24 17:39:39 -050086 generic_file_llseek(file, 0, SEEK_END);
Latchesar Ionkov6a3124a2006-03-02 02:54:30 -080087 }
88
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050089 file->private_data = fid;
90 if ((fid->qid.version) && (v9ses->cache)) {
91 P9_DPRINTK(P9_DEBUG_VFS, "cached");
Eric Van Hensbergene03abc02007-02-11 13:21:39 -060092 /* enable cached file options */
93 if(file->f_op == &v9fs_file_operations)
94 file->f_op = &v9fs_cached_file_operations;
Abhishek Kulkarni60e78d22009-09-23 13:00:27 -050095
96#ifdef CONFIG_9P_FSCACHE
97 v9fs_cache_inode_set_cookie(inode, file);
98#endif
Eric Van Hensbergene03abc02007-02-11 13:21:39 -060099 }
100
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700101 return 0;
102}
103
104/**
105 * v9fs_file_lock - lock a file (or directory)
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600106 * @filp: file to be locked
107 * @cmd: lock command
108 * @fl: file lock structure
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700109 *
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600110 * Bugs: this looks like a local only lock, we should extend into 9P
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700111 * by using open exclusive
112 */
113
114static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
115{
116 int res = 0;
Josef "Jeff" Sipekd6f787b2006-12-08 02:36:45 -0800117 struct inode *inode = filp->f_path.dentry->d_inode;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700118
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500119 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700120
121 /* No mandatory locks */
Sachin Prabhuf78233d2010-03-13 09:03:55 -0600122 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700123 return -ENOLCK;
124
125 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
OGAWA Hirofumi28fd1292006-01-08 01:02:14 -0800126 filemap_write_and_wait(inode->i_mapping);
Andrew Mortonfc0ecff2007-02-10 01:45:39 -0800127 invalidate_mapping_pages(&inode->i_data, 0, -1);
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700128 }
129
130 return res;
131}
132
133/**
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500134 * v9fs_file_readn - read from a file
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600135 * @filp: file pointer to read
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700136 * @data: data buffer to read data into
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500137 * @udata: user data buffer to read data into
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700138 * @count: size of buffer
139 * @offset: offset at which to read data
140 *
141 */
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500142
143ssize_t
144v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
145 u64 offset)
146{
M. Mohan Kumar97e84422010-06-04 11:59:07 +0000147 int n, total, size;
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500148 struct p9_fid *fid = filp->private_data;
149
Eric Van Hensbergen51a87c52008-10-16 08:30:07 -0500150 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500151 (long long unsigned) offset, count);
152
153 n = 0;
154 total = 0;
M. Mohan Kumar97e84422010-06-04 11:59:07 +0000155 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500156 do {
157 n = p9_client_read(fid, data, udata, offset, count);
158 if (n <= 0)
159 break;
160
161 if (data)
162 data += n;
163 if (udata)
164 udata += n;
165
166 offset += n;
167 count -= n;
168 total += n;
M. Mohan Kumar97e84422010-06-04 11:59:07 +0000169 } while (count > 0 && n == size);
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500170
171 if (n < 0)
172 total = n;
173
174 return total;
175}
176
177/**
178 * v9fs_file_read - read from a file
179 * @filp: file pointer to read
180 * @udata: user data buffer to read data into
181 * @count: size of buffer
182 * @offset: offset at which to read data
183 *
184 */
185
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700186static ssize_t
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500187v9fs_file_read(struct file *filp, char __user *udata, size_t count,
Latchesar Ionkov19cba8a2005-10-11 08:29:03 -0700188 loff_t * offset)
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700189{
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500190 int ret;
191 struct p9_fid *fid;
M. Mohan Kumar97e84422010-06-04 11:59:07 +0000192 size_t size;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700193
Eric Van Hensbergenea2e7992008-10-22 18:48:45 -0500194 P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500195 fid = filp->private_data;
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500196
M. Mohan Kumar97e84422010-06-04 11:59:07 +0000197 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
198 if (count > size)
Eric Van Hensbergenfbedadc2008-10-13 20:36:16 -0500199 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
200 else
201 ret = p9_client_read(fid, NULL, udata, *offset, count);
202
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500203 if (ret > 0)
204 *offset += ret;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700205
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500206 return ret;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700207}
208
209/**
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700210 * v9fs_file_write - write to a file
Eric Van Hensbergenee443992008-03-05 07:08:09 -0600211 * @filp: file pointer to write
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700212 * @data: data buffer to write data from
213 * @count: size of buffer
214 * @offset: offset at which to write data
215 *
216 */
217
218static ssize_t
219v9fs_file_write(struct file *filp, const char __user * data,
220 size_t count, loff_t * offset)
221{
Harsh Prateek Bora3834b122010-08-03 11:55:40 +0000222 ssize_t retval;
223 size_t total = 0;
jvrao8d40fa22010-08-30 13:23:20 -0500224 int n;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500225 struct p9_fid *fid;
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500226 struct p9_client *clnt;
Eric Van Hensbergen9523a842007-07-13 13:01:27 -0500227 struct inode *inode = filp->f_path.dentry->d_inode;
jvraofc0f2962010-03-08 22:07:02 +0000228 loff_t origin = *offset;
Abhishek Kulkarni637d0202009-09-22 11:34:05 -0500229 unsigned long pg_start, pg_end;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700230
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500231 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
232 (int)count, (int)*offset);
Latchesar Ionkov19cba8a2005-10-11 08:29:03 -0700233
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500234 fid = filp->private_data;
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500235 clnt = fid->clnt;
236
Harsh Prateek Bora3834b122010-08-03 11:55:40 +0000237 retval = generic_write_checks(filp, &origin, &count, 0);
238 if (retval)
239 goto out;
240
241 retval = -EINVAL;
242 if ((ssize_t) count < 0)
243 goto out;
244 retval = 0;
245 if (!count)
246 goto out;
247
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500248 do {
jvrao8d40fa22010-08-30 13:23:20 -0500249 n = p9_client_write(fid, NULL, data+total, origin+total, count);
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500250 if (n <= 0)
251 break;
252 count -= n;
253 total += n;
254 } while (count > 0);
255
256 if (total > 0) {
Abhishek Kulkarni637d0202009-09-22 11:34:05 -0500257 pg_start = origin >> PAGE_CACHE_SHIFT;
258 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
Abhishek Kulkarni60e78d22009-09-23 13:00:27 -0500259 if (inode->i_mapping && inode->i_mapping->nrpages)
260 invalidate_inode_pages2_range(inode->i_mapping,
261 pg_start, pg_end);
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500262 *offset += total;
Abhishek Kulkarni637d0202009-09-22 11:34:05 -0500263 i_size_write(inode, i_size_read(inode) + total);
Abhishek Kulkarni7549ae32009-09-22 11:34:05 -0500264 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
Eric Van Hensbergen9523a842007-07-13 13:01:27 -0500265 }
266
Eric Van Hensbergendfb0ec22008-10-13 20:36:16 -0500267 if (n < 0)
Harsh Prateek Bora3834b122010-08-03 11:55:40 +0000268 retval = n;
269 else
270 retval = total;
271out:
272 return retval;
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700273}
274
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200275static int v9fs_file_fsync(struct file *filp, int datasync)
M. Mohan Kumar7a4439c2010-02-08 15:36:48 -0600276{
277 struct p9_fid *fid;
278 struct p9_wstat wstat;
279 int retval;
280
Christoph Hellwig7ea80852010-05-26 17:53:25 +0200281 P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
M. Mohan Kumar7a4439c2010-02-08 15:36:48 -0600282
283 fid = filp->private_data;
284 v9fs_blank_wstat(&wstat);
285
286 retval = p9_client_wstat(fid, &wstat);
287 return retval;
288}
289
Adrian Bunkd32b6872007-03-05 02:49:48 +0100290static const struct file_operations v9fs_cached_file_operations = {
Eric Van Hensbergene03abc02007-02-11 13:21:39 -0600291 .llseek = generic_file_llseek,
292 .read = do_sync_read,
293 .aio_read = generic_file_aio_read,
294 .write = v9fs_file_write,
295 .open = v9fs_file_open,
296 .release = v9fs_dir_release,
297 .lock = v9fs_file_lock,
Eric Van Hensbergen14b88692008-02-06 19:25:05 -0600298 .mmap = generic_file_readonly_mmap,
M. Mohan Kumar7a4439c2010-02-08 15:36:48 -0600299 .fsync = v9fs_file_fsync,
Eric Van Hensbergene03abc02007-02-11 13:21:39 -0600300};
301
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -0800302const struct file_operations v9fs_file_operations = {
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700303 .llseek = generic_file_llseek,
304 .read = v9fs_file_read,
305 .write = v9fs_file_write,
306 .open = v9fs_file_open,
307 .release = v9fs_dir_release,
308 .lock = v9fs_file_lock,
Eric Van Hensbergen14b88692008-02-06 19:25:05 -0600309 .mmap = generic_file_readonly_mmap,
M. Mohan Kumar7a4439c2010-02-08 15:36:48 -0600310 .fsync = v9fs_file_fsync,
Eric Van Hensbergene69e7fe2005-09-09 13:04:18 -0700311};
Sripathi Kodi9b6533c2010-03-25 12:41:54 +0000312
313const struct file_operations v9fs_file_operations_dotl = {
314 .llseek = generic_file_llseek,
315 .read = v9fs_file_read,
316 .write = v9fs_file_write,
317 .open = v9fs_file_open,
318 .release = v9fs_dir_release,
319 .lock = v9fs_file_lock,
320 .mmap = generic_file_readonly_mmap,
321 .fsync = v9fs_file_fsync,
322};