]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/9p/vfs_file.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[net-next-2.6.git] / fs / 9p / vfs_file.c
CommitLineData
e69e7fe5
EVH
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
42e8c509
EVH
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
e69e7fe5
EVH
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>
914e2637 29#include <linux/sched.h>
e69e7fe5
EVH
30#include <linux/file.h>
31#include <linux/stat.h>
32#include <linux/string.h>
e69e7fe5 33#include <linux/inet.h>
e69e7fe5 34#include <linux/list.h>
637d020a 35#include <linux/pagemap.h>
e69e7fe5
EVH
36#include <asm/uaccess.h>
37#include <linux/idr.h>
bd238fb4
LI
38#include <net/9p/9p.h>
39#include <net/9p/client.h>
e69e7fe5 40
e69e7fe5 41#include "v9fs.h"
e69e7fe5
EVH
42#include "v9fs_vfs.h"
43#include "fid.h"
60e78d2c 44#include "cache.h"
e69e7fe5 45
d32b687e
AB
46static const struct file_operations v9fs_cached_file_operations;
47
e69e7fe5
EVH
48/**
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{
6a3124a3 57 int err;
bd238fb4
LI
58 struct v9fs_session_info *v9ses;
59 struct p9_fid *fid;
60 int omode;
e69e7fe5 61
ef56547e 62 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
bd238fb4 63 v9ses = v9fs_inode2v9ses(inode);
ef56547e
MK
64 if (v9fs_proto_dotl(v9ses))
65 omode = file->f_flags;
66 else
67 omode = v9fs_uflags2omode(file->f_flags,
68 v9fs_proto_dotu(v9ses));
bd238fb4
LI
69 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);
9523a841 76 if (err < 0) {
bd238fb4
LI
77 p9_client_clunk(fid);
78 return err;
79 }
ef56547e 80 if (file->f_flags & O_TRUNC) {
7549ae3e 81 i_size_write(inode, 0);
9523a841
EVH
82 inode->i_blocks = 0;
83 }
ef56547e
MK
84 if ((file->f_flags & O_APPEND) &&
85 (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
2e4bef41 86 generic_file_llseek(file, 0, SEEK_END);
6a3124a3 87 }
e69e7fe5 88
bd238fb4
LI
89 file->private_data = fid;
90 if ((fid->qid.version) && (v9ses->cache)) {
91 P9_DPRINTK(P9_DEBUG_VFS, "cached");
e03abc0c
EVH
92 /* enable cached file options */
93 if(file->f_op == &v9fs_file_operations)
94 file->f_op = &v9fs_cached_file_operations;
60e78d2c
AK
95
96#ifdef CONFIG_9P_FSCACHE
97 v9fs_cache_inode_set_cookie(inode, file);
98#endif
e03abc0c
EVH
99 }
100
6a3124a3 101 return 0;
e69e7fe5
EVH
102}
103
104/**
105 * v9fs_file_lock - lock a file (or directory)
ee443996
EVH
106 * @filp: file to be locked
107 * @cmd: lock command
108 * @fl: file lock structure
e69e7fe5 109 *
ee443996 110 * Bugs: this looks like a local only lock, we should extend into 9P
e69e7fe5
EVH
111 * 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;
d6f787bc 117 struct inode *inode = filp->f_path.dentry->d_inode;
e69e7fe5 118
bd238fb4 119 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
e69e7fe5
EVH
120
121 /* No mandatory locks */
f78233dd 122 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
e69e7fe5
EVH
123 return -ENOLCK;
124
125 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
28fd1298 126 filemap_write_and_wait(inode->i_mapping);
fc0ecff6 127 invalidate_mapping_pages(&inode->i_data, 0, -1);
e69e7fe5
EVH
128 }
129
130 return res;
131}
132
133/**
fbedadc1 134 * v9fs_file_readn - read from a file
ee443996 135 * @filp: file pointer to read
e69e7fe5 136 * @data: data buffer to read data into
fbedadc1 137 * @udata: user data buffer to read data into
e69e7fe5
EVH
138 * @count: size of buffer
139 * @offset: offset at which to read data
140 *
141 */
fbedadc1
EVH
142
143ssize_t
144v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
145 u64 offset)
146{
97e8442b 147 int n, total, size;
fbedadc1
EVH
148 struct p9_fid *fid = filp->private_data;
149
51a87c55 150 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
fbedadc1
EVH
151 (long long unsigned) offset, count);
152
153 n = 0;
154 total = 0;
97e8442b 155 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
fbedadc1
EVH
156 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;
97e8442b 169 } while (count > 0 && n == size);
fbedadc1
EVH
170
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
e69e7fe5 186static ssize_t
fbedadc1 187v9fs_file_read(struct file *filp, char __user *udata, size_t count,
19cba8ab 188 loff_t * offset)
e69e7fe5 189{
bd238fb4
LI
190 int ret;
191 struct p9_fid *fid;
97e8442b 192 size_t size;
e69e7fe5 193
ea2e7996 194 P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
bd238fb4 195 fid = filp->private_data;
fbedadc1 196
97e8442b
MK
197 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
198 if (count > size)
fbedadc1
EVH
199 ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
200 else
201 ret = p9_client_read(fid, NULL, udata, *offset, count);
202
bd238fb4
LI
203 if (ret > 0)
204 *offset += ret;
e69e7fe5 205
bd238fb4 206 return ret;
e69e7fe5
EVH
207}
208
209/**
19cba8ab 210 * v9fs_file_write - write to a file
ee443996 211 * @filp: file pointer to write
e69e7fe5
EVH
212 * @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
19cba8ab
LI
219v9fs_file_write(struct file *filp, const char __user * data,
220 size_t count, loff_t * offset)
e69e7fe5 221{
dfb0ec2e 222 int n, rsize, total = 0;
bd238fb4 223 struct p9_fid *fid;
dfb0ec2e 224 struct p9_client *clnt;
9523a841 225 struct inode *inode = filp->f_path.dentry->d_inode;
fc0f2961 226 loff_t origin = *offset;
637d020a 227 unsigned long pg_start, pg_end;
e69e7fe5 228
bd238fb4
LI
229 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
230 (int)count, (int)*offset);
e69e7fe5 231
bd238fb4 232 fid = filp->private_data;
dfb0ec2e
EVH
233 clnt = fid->clnt;
234
97e8442b 235 rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
dfb0ec2e
EVH
236
237 do {
238 if (count < rsize)
239 rsize = count;
240
637d020a 241 n = p9_client_write(fid, NULL, data+total, origin+total,
dfb0ec2e
EVH
242 rsize);
243 if (n <= 0)
244 break;
245 count -= n;
246 total += n;
247 } while (count > 0);
248
249 if (total > 0) {
637d020a
AK
250 pg_start = origin >> PAGE_CACHE_SHIFT;
251 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
60e78d2c
AK
252 if (inode->i_mapping && inode->i_mapping->nrpages)
253 invalidate_inode_pages2_range(inode->i_mapping,
254 pg_start, pg_end);
dfb0ec2e 255 *offset += total;
637d020a 256 i_size_write(inode, i_size_read(inode) + total);
7549ae3e 257 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
9523a841
EVH
258 }
259
dfb0ec2e
EVH
260 if (n < 0)
261 return n;
262
263 return total;
e69e7fe5
EVH
264}
265
7ea80859 266static int v9fs_file_fsync(struct file *filp, int datasync)
7a4439c4
MK
267{
268 struct p9_fid *fid;
269 struct p9_wstat wstat;
270 int retval;
271
7ea80859 272 P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
7a4439c4
MK
273
274 fid = filp->private_data;
275 v9fs_blank_wstat(&wstat);
276
277 retval = p9_client_wstat(fid, &wstat);
278 return retval;
279}
280
d32b687e 281static const struct file_operations v9fs_cached_file_operations = {
e03abc0c
EVH
282 .llseek = generic_file_llseek,
283 .read = do_sync_read,
284 .aio_read = generic_file_aio_read,
285 .write = v9fs_file_write,
286 .open = v9fs_file_open,
287 .release = v9fs_dir_release,
288 .lock = v9fs_file_lock,
14b8869f 289 .mmap = generic_file_readonly_mmap,
7a4439c4 290 .fsync = v9fs_file_fsync,
e03abc0c
EVH
291};
292
4b6f5d20 293const struct file_operations v9fs_file_operations = {
e69e7fe5
EVH
294 .llseek = generic_file_llseek,
295 .read = v9fs_file_read,
296 .write = v9fs_file_write,
297 .open = v9fs_file_open,
298 .release = v9fs_dir_release,
299 .lock = v9fs_file_lock,
14b8869f 300 .mmap = generic_file_readonly_mmap,
7a4439c4 301 .fsync = v9fs_file_fsync,
e69e7fe5 302};
9b6533c9
SK
303
304const struct file_operations v9fs_file_operations_dotl = {
305 .llseek = generic_file_llseek,
306 .read = v9fs_file_read,
307 .write = v9fs_file_write,
308 .open = v9fs_file_open,
309 .release = v9fs_dir_release,
310 .lock = v9fs_file_lock,
311 .mmap = generic_file_readonly_mmap,
312 .fsync = v9fs_file_fsync,
313};