[9p] Introduce client side TFSYNC/RFSYNC for dotl.
[platform/adaptation/renesas_rcar/renesas_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 <asm/uaccess.h>
37 #include <linux/idr.h>
38 #include <net/9p/9p.h>
39 #include <net/9p/client.h>
40
41 #include "v9fs.h"
42 #include "v9fs_vfs.h"
43 #include "fid.h"
44 #include "cache.h"
45
46 static const struct file_operations v9fs_cached_file_operations;
47 static const struct file_operations v9fs_cached_file_operations_dotl;
48
49 /**
50  * v9fs_file_open - open a file (or directory)
51  * @inode: inode to be opened
52  * @file: file being opened
53  *
54  */
55
56 int v9fs_file_open(struct inode *inode, struct file *file)
57 {
58         int err;
59         struct v9fs_session_info *v9ses;
60         struct p9_fid *fid;
61         int omode;
62
63         P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
64         v9ses = v9fs_inode2v9ses(inode);
65         if (v9fs_proto_dotl(v9ses))
66                 omode = file->f_flags;
67         else
68                 omode = v9fs_uflags2omode(file->f_flags,
69                                         v9fs_proto_dotu(v9ses));
70         fid = file->private_data;
71         if (!fid) {
72                 fid = v9fs_fid_clone(file->f_path.dentry);
73                 if (IS_ERR(fid))
74                         return PTR_ERR(fid);
75
76                 err = p9_client_open(fid, omode);
77                 if (err < 0) {
78                         p9_client_clunk(fid);
79                         return err;
80                 }
81                 if (file->f_flags & O_TRUNC) {
82                         i_size_write(inode, 0);
83                         inode->i_blocks = 0;
84                 }
85                 if ((file->f_flags & O_APPEND) &&
86                         (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
87                         generic_file_llseek(file, 0, SEEK_END);
88         }
89
90         file->private_data = fid;
91         if ((fid->qid.version) && (v9ses->cache)) {
92                 P9_DPRINTK(P9_DEBUG_VFS, "cached");
93                 /* enable cached file options */
94                 if(file->f_op == &v9fs_file_operations)
95                         file->f_op = &v9fs_cached_file_operations;
96                 else if (file->f_op == &v9fs_file_operations_dotl)
97                         file->f_op = &v9fs_cached_file_operations_dotl;
98
99 #ifdef CONFIG_9P_FSCACHE
100                 v9fs_cache_inode_set_cookie(inode, file);
101 #endif
102         }
103
104         return 0;
105 }
106
107 /**
108  * v9fs_file_lock - lock a file (or directory)
109  * @filp: file to be locked
110  * @cmd: lock command
111  * @fl: file lock structure
112  *
113  * Bugs: this looks like a local only lock, we should extend into 9P
114  *       by using open exclusive
115  */
116
117 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
118 {
119         int res = 0;
120         struct inode *inode = filp->f_path.dentry->d_inode;
121
122         P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
123
124         /* No mandatory locks */
125         if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
126                 return -ENOLCK;
127
128         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
129                 filemap_write_and_wait(inode->i_mapping);
130                 invalidate_mapping_pages(&inode->i_data, 0, -1);
131         }
132
133         return res;
134 }
135
136 /**
137  * v9fs_file_readn - read from a file
138  * @filp: file pointer to read
139  * @data: data buffer to read data into
140  * @udata: user data buffer to read data into
141  * @count: size of buffer
142  * @offset: offset at which to read data
143  *
144  */
145
146 ssize_t
147 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
148                u64 offset)
149 {
150         int n, total, size;
151         struct p9_fid *fid = filp->private_data;
152
153         P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
154                                         (long long unsigned) offset, count);
155
156         n = 0;
157         total = 0;
158         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
159         do {
160                 n = p9_client_read(fid, data, udata, offset, count);
161                 if (n <= 0)
162                         break;
163
164                 if (data)
165                         data += n;
166                 if (udata)
167                         udata += n;
168
169                 offset += n;
170                 count -= n;
171                 total += n;
172         } while (count > 0 && n == size);
173
174         if (n < 0)
175                 total = n;
176
177         return total;
178 }
179
180 /**
181  * v9fs_file_read - read from a file
182  * @filp: file pointer to read
183  * @udata: user data buffer to read data into
184  * @count: size of buffer
185  * @offset: offset at which to read data
186  *
187  */
188
189 static ssize_t
190 v9fs_file_read(struct file *filp, char __user *udata, size_t count,
191                loff_t * offset)
192 {
193         int ret;
194         struct p9_fid *fid;
195         size_t size;
196
197         P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
198         fid = filp->private_data;
199
200         size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
201         if (count > size)
202                 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
203         else
204                 ret = p9_client_read(fid, NULL, udata, *offset, count);
205
206         if (ret > 0)
207                 *offset += ret;
208
209         return ret;
210 }
211
212 /**
213  * v9fs_file_write - write to a file
214  * @filp: file pointer to write
215  * @data: data buffer to write data from
216  * @count: size of buffer
217  * @offset: offset at which to write data
218  *
219  */
220
221 static ssize_t
222 v9fs_file_write(struct file *filp, const char __user * data,
223                 size_t count, loff_t * offset)
224 {
225         ssize_t retval;
226         size_t total = 0;
227         int n;
228         struct p9_fid *fid;
229         struct p9_client *clnt;
230         struct inode *inode = filp->f_path.dentry->d_inode;
231         loff_t origin = *offset;
232         unsigned long pg_start, pg_end;
233
234         P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
235                 (int)count, (int)*offset);
236
237         fid = filp->private_data;
238         clnt = fid->clnt;
239
240         retval = generic_write_checks(filp, &origin, &count, 0);
241         if (retval)
242                 goto out;
243
244         retval = -EINVAL;
245         if ((ssize_t) count < 0)
246                 goto out;
247         retval = 0;
248         if (!count)
249                 goto out;
250
251         do {
252                 n = p9_client_write(fid, NULL, data+total, origin+total, count);
253                 if (n <= 0)
254                         break;
255                 count -= n;
256                 total += n;
257         } while (count > 0);
258
259         if (total > 0) {
260                 pg_start = origin >> PAGE_CACHE_SHIFT;
261                 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
262                 if (inode->i_mapping && inode->i_mapping->nrpages)
263                         invalidate_inode_pages2_range(inode->i_mapping,
264                                                       pg_start, pg_end);
265                 *offset += total;
266                 i_size_write(inode, i_size_read(inode) + total);
267                 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
268         }
269
270         if (n < 0)
271                 retval = n;
272         else
273                 retval = total;
274 out:
275         return retval;
276 }
277
278 static int v9fs_file_fsync(struct file *filp, int datasync)
279 {
280         struct p9_fid *fid;
281         struct p9_wstat wstat;
282         int retval;
283
284         P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
285
286         fid = filp->private_data;
287         v9fs_blank_wstat(&wstat);
288
289         retval = p9_client_wstat(fid, &wstat);
290         return retval;
291 }
292
293 static int v9fs_file_fsync_dotl(struct file *filp, int datasync)
294 {
295         struct p9_fid *fid;
296         int retval;
297
298         P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
299                         filp, datasync);
300
301         fid = filp->private_data;
302
303         retval = p9_client_fsync(fid);
304         return retval;
305 }
306
307 static const struct file_operations v9fs_cached_file_operations = {
308         .llseek = generic_file_llseek,
309         .read = do_sync_read,
310         .aio_read = generic_file_aio_read,
311         .write = v9fs_file_write,
312         .open = v9fs_file_open,
313         .release = v9fs_dir_release,
314         .lock = v9fs_file_lock,
315         .mmap = generic_file_readonly_mmap,
316         .fsync = v9fs_file_fsync,
317 };
318
319 static const struct file_operations v9fs_cached_file_operations_dotl = {
320         .llseek = generic_file_llseek,
321         .read = do_sync_read,
322         .aio_read = generic_file_aio_read,
323         .write = v9fs_file_write,
324         .open = v9fs_file_open,
325         .release = v9fs_dir_release,
326         .lock = v9fs_file_lock,
327         .mmap = generic_file_readonly_mmap,
328         .fsync = v9fs_file_fsync_dotl,
329 };
330
331 const struct file_operations v9fs_file_operations = {
332         .llseek = generic_file_llseek,
333         .read = v9fs_file_read,
334         .write = v9fs_file_write,
335         .open = v9fs_file_open,
336         .release = v9fs_dir_release,
337         .lock = v9fs_file_lock,
338         .mmap = generic_file_readonly_mmap,
339         .fsync = v9fs_file_fsync,
340 };
341
342 const struct file_operations v9fs_file_operations_dotl = {
343         .llseek = generic_file_llseek,
344         .read = v9fs_file_read,
345         .write = v9fs_file_write,
346         .open = v9fs_file_open,
347         .release = v9fs_dir_release,
348         .lock = v9fs_file_lock,
349         .mmap = generic_file_readonly_mmap,
350         .fsync = v9fs_file_fsync_dotl,
351 };