blob: 61eba561eab893236896feca34fc418976482dfb [file] [log] [blame]
Miklos Szeredi5e183482001-10-31 14:52:35 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi95da8602006-01-06 18:29:40 +00003 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi5e183482001-10-31 14:52:35 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredi5e183482001-10-31 14:52:35 +00007*/
Miklos Szeredi83a07442004-11-30 18:25:20 +00008
Miklos Szeredi5e183482001-10-31 14:52:35 +00009#include "fuse_i.h"
10
Miklos Szeredi5e183482001-10-31 14:52:35 +000011#include <linux/pagemap.h>
Miklos Szeredia181e612001-11-06 12:03:23 +000012#include <linux/slab.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#include <linux/kernel.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000014
Miklos Szeredie56818b2004-12-12 11:45:24 +000015#ifndef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +000016#define PageUptodate(page) Page_Uptodate(page)
Miklos Szeredie56818b2004-12-12 11:45:24 +000017#define clear_page_dirty(page) ClearPageDirty(page)
Miklos Szeredi209f5d02004-07-24 19:56:16 +000018#endif
Miklos Szeredibb4b9742005-11-29 11:29:44 +000019#ifndef KERNEL_2_6_11_PLUS
20static inline loff_t page_offset(struct page *page)
21{
22 return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
23}
24#endif
Miklos Szeredie77cc072005-08-01 11:58:51 +000025static struct file_operations fuse_direct_io_file_operations;
26
Miklos Szeredid9079a72005-10-26 15:29:06 +000027static int fuse_send_open(struct inode *inode, struct file *file, int isdir,
28 struct fuse_open_out *outargp)
Miklos Szeredi5e183482001-10-31 14:52:35 +000029{
Miklos Szeredi039322d2004-12-01 18:39:12 +000030 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi43696432001-11-18 19:15:05 +000031 struct fuse_open_in inarg;
Miklos Szeredid9079a72005-10-26 15:29:06 +000032 struct fuse_req *req;
33 int err;
34
Miklos Szeredi7a2814c2006-04-12 10:41:50 +000035 req = fuse_get_req(fc);
36 if (IS_ERR(req))
37 return PTR_ERR(req);
Miklos Szeredid9079a72005-10-26 15:29:06 +000038
39 memset(&inarg, 0, sizeof(inarg));
40 inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
41 req->in.h.opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN;
42 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredid9079a72005-10-26 15:29:06 +000043 req->in.numargs = 1;
44 req->in.args[0].size = sizeof(inarg);
45 req->in.args[0].value = &inarg;
46 req->out.numargs = 1;
47 req->out.args[0].size = sizeof(*outargp);
48 req->out.args[0].value = outargp;
49 request_send(fc, req);
50 err = req->out.h.error;
51 fuse_put_request(fc, req);
52
53 return err;
54}
55
56struct fuse_file *fuse_file_alloc(void)
57{
58 struct fuse_file *ff;
59 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
60 if (ff) {
Miklos Szeredi91762cd2006-06-29 14:38:35 +000061 ff->reserved_req = fuse_request_alloc();
62 if (!ff->reserved_req) {
Miklos Szeredid9079a72005-10-26 15:29:06 +000063 kfree(ff);
64 ff = NULL;
65 }
66 }
67 return ff;
68}
69
70void fuse_file_free(struct fuse_file *ff)
71{
Miklos Szeredi91762cd2006-06-29 14:38:35 +000072 fuse_request_free(ff->reserved_req);
Miklos Szeredid9079a72005-10-26 15:29:06 +000073 kfree(ff);
74}
75
76void fuse_finish_open(struct inode *inode, struct file *file,
77 struct fuse_file *ff, struct fuse_open_out *outarg)
78{
79 if (outarg->open_flags & FOPEN_DIRECT_IO)
80 file->f_op = &fuse_direct_io_file_operations;
81 if (!(outarg->open_flags & FOPEN_KEEP_CACHE))
82#ifdef KERNEL_2_6
83 invalidate_inode_pages(inode->i_mapping);
84#else
85 invalidate_inode_pages(inode);
86#endif
87 ff->fh = outarg->fh;
88 file->private_data = ff;
89}
90
91int fuse_open_common(struct inode *inode, struct file *file, int isdir)
92{
Miklos Szeredi209f5d02004-07-24 19:56:16 +000093 struct fuse_open_out outarg;
94 struct fuse_file *ff;
Miklos Szeredif58cc612004-02-06 13:52:00 +000095 int err;
96
Miklos Szeredif45f3c12005-09-22 15:14:27 +000097 /* VFS checks this, but only _after_ ->open() */
98 if (file->f_flags & O_DIRECT)
99 return -EINVAL;
100
Miklos Szeredif58cc612004-02-06 13:52:00 +0000101 err = generic_file_open(inode, file);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000102 if (err)
Miklos Szeredif58cc612004-02-06 13:52:00 +0000103 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000104
Miklos Szeredife25def2001-12-20 15:38:05 +0000105 /* If opening the root node, no lookup has been performed on
106 it, so the attributes must be refreshed */
Miklos Szeredi039322d2004-12-01 18:39:12 +0000107 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredid9079a72005-10-26 15:29:06 +0000108 err = fuse_do_getattr(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000109 if (err)
Miklos Szeredife25def2001-12-20 15:38:05 +0000110 return err;
111 }
112
Miklos Szeredid9079a72005-10-26 15:29:06 +0000113 ff = fuse_file_alloc();
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000114 if (!ff)
Miklos Szeredid9079a72005-10-26 15:29:06 +0000115 return -ENOMEM;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000116
Miklos Szeredid9079a72005-10-26 15:29:06 +0000117 err = fuse_send_open(inode, file, isdir, &outarg);
118 if (err)
119 fuse_file_free(ff);
120 else {
121 if (isdir)
122 outarg.open_flags &= ~FOPEN_DIRECT_IO;
123 fuse_finish_open(inode, file, ff, &outarg);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000124 }
125
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000126 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000127}
128
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000129struct fuse_req *fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags,
130 int opcode)
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000131{
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000132 struct fuse_req *req = ff->reserved_req;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000133 struct fuse_release_in *inarg = &req->misc.release_in;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000134
Miklos Szeredie56818b2004-12-12 11:45:24 +0000135 inarg->fh = ff->fh;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000136 inarg->flags = flags;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000137 req->in.h.opcode = opcode;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000138 req->in.h.nodeid = nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000139 req->in.numargs = 1;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000140 req->in.args[0].size = sizeof(struct fuse_release_in);
141 req->in.args[0].value = inarg;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000142 kfree(ff);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000143
144 return req;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000145}
146
147int fuse_release_common(struct inode *inode, struct file *file, int isdir)
148{
149 struct fuse_file *ff = file->private_data;
150 if (ff) {
151 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000152 struct fuse_req *req;
153
154 req = fuse_release_fill(ff, get_node_id(inode), file->f_flags,
155 isdir ? FUSE_RELEASEDIR : FUSE_RELEASE);
156
157 /* Hold vfsmount and dentry until release is finished */
158 req->vfsmount = mntget(file->f_vfsmnt);
159 req->dentry = dget(file->f_dentry);
160 request_send_background(fc, req);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000161 }
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000162
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000163 /* Return value is ignored by VFS */
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000164 return 0;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000165}
166
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000167static int fuse_open(struct inode *inode, struct file *file)
168{
169 return fuse_open_common(inode, file, 0);
170}
171
172static int fuse_release(struct inode *inode, struct file *file)
173{
174 return fuse_release_common(inode, file, 0);
175}
176
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000177/*
178 * Scramble the ID space with XTEA, so that the value of the files_struct
179 * pointer is not exposed to userspace.
180 */
181static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id)
182{
183 u32 *k = fc->scramble_key;
184 u64 v = (unsigned long) id;
185 u32 v0 = v;
186 u32 v1 = v >> 32;
187 u32 sum = 0;
188 int i;
189
190 for (i = 0; i < 32; i++) {
191 v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + k[sum & 3]);
192 sum += 0x9E3779B9;
193 v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + k[sum>>11 & 3]);
194 }
195
196 return (u64) v0 + ((u64) v1 << 32);
197}
198
199#ifdef KERNEL_2_6_18_PLUS
200static int fuse_flush(struct file *file, fl_owner_t id)
201#else
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000202static int fuse_flush(struct file *file)
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000203#endif
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000204{
205 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000206 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000207 struct fuse_file *ff = file->private_data;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000208 struct fuse_req *req;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000209 struct fuse_flush_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000211
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000212 if (is_bad_inode(inode))
213 return -EIO;
214
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000215 if (fc->no_flush)
216 return 0;
217
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000218 req = fuse_get_req_nofail(fc, file);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000219 memset(&inarg, 0, sizeof(inarg));
220 inarg.fh = ff->fh;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000221#ifdef KERNEL_2_6_18_PLUS
222 inarg.lock_owner = fuse_lock_owner_id(fc, id);
223#else
224 inarg.lock_owner = fuse_lock_owner_id(fc, NULL);
225#endif
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000226 req->in.h.opcode = FUSE_FLUSH;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000227 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000228 req->in.numargs = 1;
229 req->in.args[0].size = sizeof(inarg);
230 req->in.args[0].value = &inarg;
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000231 req->force = 1;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000232 request_send(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000233 err = req->out.h.error;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000234 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000236 fc->no_flush = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000237 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000238 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000239 return err;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000240}
241
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000242int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
243 int isdir)
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000244{
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000245 struct inode *inode = de->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000246 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000247 struct fuse_file *ff = file->private_data;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000248 struct fuse_req *req;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000249 struct fuse_fsync_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000250 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000251
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000252 if (is_bad_inode(inode))
253 return -EIO;
254
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000255 if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000256 return 0;
257
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000258 req = fuse_get_req(fc);
259 if (IS_ERR(req))
260 return PTR_ERR(req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000261
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000262 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000263 inarg.fh = ff->fh;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000264 inarg.fsync_flags = datasync ? 1 : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000265 req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000266 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000267 req->in.numargs = 1;
268 req->in.args[0].size = sizeof(inarg);
269 req->in.args[0].value = &inarg;
270 request_send(fc, req);
271 err = req->out.h.error;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000272 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000273 if (err == -ENOSYS) {
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000274 if (isdir)
275 fc->no_fsyncdir = 1;
276 else
277 fc->no_fsync = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000278 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000279 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000280 return err;
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000281}
Miklos Szeredia181e612001-11-06 12:03:23 +0000282
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000283static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
284{
285 return fuse_fsync_common(file, de, datasync, 0);
286}
287
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000288void fuse_read_fill(struct fuse_req *req, struct file *file,
289 struct inode *inode, loff_t pos, size_t count, int opcode)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000290{
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000291 struct fuse_file *ff = file->private_data;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000292 struct fuse_read_in *inarg = &req->misc.read_in;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000293
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000294 inarg->fh = ff->fh;
295 inarg->offset = pos;
296 inarg->size = count;
297 req->in.h.opcode = opcode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000298 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000299 req->in.numargs = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000300 req->in.args[0].size = sizeof(struct fuse_read_in);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000301 req->in.args[0].value = inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000302 req->out.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 req->out.argvar = 1;
304 req->out.numargs = 1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000305 req->out.args[0].size = count;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000306}
307
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000308static size_t fuse_send_read(struct fuse_req *req, struct file *file,
309 struct inode *inode, loff_t pos, size_t count)
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000310{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000311 struct fuse_conn *fc = get_fuse_conn(inode);
312 fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
313 request_send(fc, req);
314 return req->out.args[0].size;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000315}
316
Miklos Szerediad051c32004-07-02 09:22:50 +0000317static int fuse_readpage(struct file *file, struct page *page)
318{
319 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000320 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000321 struct fuse_req *req;
322 int err;
323
324 err = -EIO;
325 if (is_bad_inode(inode))
326 goto out;
327
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000328 req = fuse_get_req(fc);
329 err = PTR_ERR(req);
330 if (IS_ERR(req))
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000331 goto out;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000332
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000333 req->out.page_zeroing = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000334 req->num_pages = 1;
335 req->pages[0] = page;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000336 fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000337 err = req->out.h.error;
338 fuse_put_request(fc, req);
339 if (!err)
Miklos Szerediad051c32004-07-02 09:22:50 +0000340 SetPageUptodate(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000341 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000342 out:
Miklos Szerediad051c32004-07-02 09:22:50 +0000343 unlock_page(page);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000344 return err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000345}
346
Miklos Szeredi58865372004-07-20 14:22:26 +0000347#ifdef KERNEL_2_6
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000348static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
Miklos Szeredi58865372004-07-20 14:22:26 +0000349{
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000350 int i;
351
352 fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */
353
Miklos Szeredi83a07442004-11-30 18:25:20 +0000354 for (i = 0; i < req->num_pages; i++) {
355 struct page *page = req->pages[i];
356 if (!req->out.h.error)
357 SetPageUptodate(page);
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000358 else
359 SetPageError(page);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000360 unlock_page(page);
361 }
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000362 fuse_put_request(fc, req);
363}
364
365static void fuse_send_readpages(struct fuse_req *req, struct file *file,
366 struct inode *inode)
367{
368 struct fuse_conn *fc = get_fuse_conn(inode);
369 loff_t pos = page_offset(req->pages[0]);
370 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
371 req->out.page_zeroing = 1;
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000372 fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
Miklos Szeredi065f2222006-01-20 15:15:21 +0000373 if (fc->async_read) {
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000374 get_file(file);
375 req->file = file;
Miklos Szeredi065f2222006-01-20 15:15:21 +0000376 req->end = fuse_readpages_end;
377 request_send_background(fc, req);
378 } else {
379 request_send(fc, req);
380 fuse_readpages_end(fc, req);
381 }
Miklos Szeredi58865372004-07-20 14:22:26 +0000382}
383
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000384struct fuse_readpages_data {
385 struct fuse_req *req;
386 struct file *file;
387 struct inode *inode;
388};
389
390static int fuse_readpages_fill(void *_data, struct page *page)
Miklos Szeredi58865372004-07-20 14:22:26 +0000391{
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000392 struct fuse_readpages_data *data = _data;
393 struct fuse_req *req = data->req;
394 struct inode *inode = data->inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000395 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000396 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000397
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000398 if (req && req->num_pages &&
Miklos Szeredi58865372004-07-20 14:22:26 +0000399 (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000400 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
Miklos Szeredi58865372004-07-20 14:22:26 +0000401 req->pages[req->num_pages - 1]->index + 1 != page->index)) {
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000402 fuse_send_readpages(req, data->file, inode);
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000403 req = NULL;
404 }
405 if (!req) {
406 err = -EIO;
407 if (is_bad_inode(inode))
408 goto out_unlock_page;
409
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000410 data->req = req = fuse_get_req(fc);
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000411 err = PTR_ERR(req);
412 if (IS_ERR(req))
413 goto out_unlock_page;
Miklos Szeredi58865372004-07-20 14:22:26 +0000414 }
415 req->pages[req->num_pages] = page;
416 req->num_pages ++;
417 return 0;
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000418
419 out_unlock_page:
420 unlock_page(page);
421 return err;
Miklos Szeredi58865372004-07-20 14:22:26 +0000422}
423
424static int fuse_readpages(struct file *file, struct address_space *mapping,
425 struct list_head *pages, unsigned nr_pages)
426{
427 struct inode *inode = mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000428 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000429 struct fuse_readpages_data data;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000430 int err;
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000431
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000432 data.file = file;
433 data.inode = inode;
Miklos Szeredi63d3c402006-08-18 16:38:08 +0000434 data.req = NULL;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000435
Miklos Szeredie56818b2004-12-12 11:45:24 +0000436 err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000437 if (!err) {
438 if (data.req->num_pages)
439 fuse_send_readpages(data.req, file, inode);
440 else
441 fuse_put_request(fc, data.req);
442 }
Miklos Szeredie56818b2004-12-12 11:45:24 +0000443 return err;
Miklos Szeredi58865372004-07-20 14:22:26 +0000444}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000445#else /* KERNEL_2_6 */
Miklos Szeredi83a07442004-11-30 18:25:20 +0000446#define FUSE_BLOCK_SHIFT 16
447#define FUSE_BLOCK_SIZE (1UL << FUSE_BLOCK_SHIFT)
448#define FUSE_BLOCK_MASK (~(FUSE_BLOCK_SIZE-1))
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000449#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
Miklos Szeredi83a07442004-11-30 18:25:20 +0000450#error FUSE_BLOCK_SHIFT too large
451#endif
452
453static int fuse_is_block_uptodate(struct inode *inode, unsigned start,
454 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000455{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000456 int index;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000457
Miklos Szeredi83a07442004-11-30 18:25:20 +0000458 for (index = start; index < end; index++) {
Miklos Szerediad051c32004-07-02 09:22:50 +0000459 struct page *page = find_get_page(inode->i_mapping, index);
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000460 if (!page)
461 return 0;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000462 if (!PageUptodate(page)) {
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000463 page_cache_release(page);
464 return 0;
465 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000466 page_cache_release(page);
467 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000468 return 1;
469}
470
Miklos Szeredie56818b2004-12-12 11:45:24 +0000471static int fuse_file_read_block(struct fuse_req *req, struct file *file,
472 struct inode *inode, unsigned start,
473 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000474{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000475 loff_t pos;
476 size_t count;
477 int index;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000478 int err = -EBUSY;
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000479 int i;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000480
Miklos Szeredi83a07442004-11-30 18:25:20 +0000481 for (index = start; index < end; index++) {
482 struct page *page = grab_cache_page(inode->i_mapping, index);
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000483 if (!page)
Miklos Szeredi83a07442004-11-30 18:25:20 +0000484 goto out;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000485 if (PageUptodate(page)) {
486 unlock_page(page);
487 page_cache_release(page);
488 page = NULL;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000489 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000490 req->pages[req->num_pages++] = page;
491 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000492 pos = (loff_t) start << PAGE_CACHE_SHIFT;
493 count = req->num_pages << PAGE_CACHE_SHIFT;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000494 fuse_send_read(req, file, inode, pos, count);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000495 err = req->out.h.error;
496 out:
497 for (i = 0; i < req->num_pages; i++) {
498 struct page *page = req->pages[i];
Miklos Szeredi039322d2004-12-01 18:39:12 +0000499 if (page) {
500 if (!err)
501 SetPageUptodate(page);
502 unlock_page(page);
503 page_cache_release(page);
504 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000505 }
Miklos Szeredie56818b2004-12-12 11:45:24 +0000506 return err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000507}
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000508
Miklos Szeredi83a07442004-11-30 18:25:20 +0000509static int fuse_file_bigread(struct file *file, struct inode *inode,
510 loff_t pos, size_t count)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000511{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000512 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000513 unsigned starti;
514 unsigned endi;
515 unsigned nexti;
516 struct fuse_req *req;
517 loff_t size = i_size_read(inode);
518 loff_t end = (pos + count + FUSE_BLOCK_SIZE - 1) & FUSE_BLOCK_MASK;
519 end = min(end, size);
520 if (end <= pos)
521 return 0;
522
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000523 starti = (pos & FUSE_BLOCK_MASK) >> PAGE_CACHE_SHIFT;
524 endi = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
525
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000526 req = fuse_get_req(fc);
527 if (IS_ERR(req))
528 return PTR_ERR(req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000529
Miklos Szeredi83a07442004-11-30 18:25:20 +0000530 for (; starti < endi; starti = nexti) {
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000531 nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000532 nexti = min(nexti, endi);
533 if (!fuse_is_block_uptodate(inode, starti, nexti)) {
Miklos Szeredie56818b2004-12-12 11:45:24 +0000534 if (fuse_file_read_block(req, file, inode, starti, nexti))
535 break;
536
Miklos Szeredi83a07442004-11-30 18:25:20 +0000537 fuse_reset_request(req);
538 }
Miklos Szeredi307242f2004-01-26 11:28:44 +0000539 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000540 fuse_put_request(fc, req);
541 return 0;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000542}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000543#endif /* KERNEL_2_6 */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000544
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000545static size_t fuse_send_write(struct fuse_req *req, struct file *file,
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000546 struct inode *inode, loff_t pos, size_t count)
Miklos Szeredia181e612001-11-06 12:03:23 +0000547{
Miklos Szeredie56818b2004-12-12 11:45:24 +0000548 struct fuse_conn *fc = get_fuse_conn(inode);
549 struct fuse_file *ff = file->private_data;
550 struct fuse_write_in inarg;
551 struct fuse_write_out outarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000552
Miklos Szeredie56818b2004-12-12 11:45:24 +0000553 memset(&inarg, 0, sizeof(struct fuse_write_in));
Miklos Szeredie56818b2004-12-12 11:45:24 +0000554 inarg.fh = ff->fh;
555 inarg.offset = pos;
556 inarg.size = count;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000557 req->in.h.opcode = FUSE_WRITE;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000558 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000559 req->in.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000560 req->in.numargs = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000561 req->in.args[0].size = sizeof(struct fuse_write_in);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000562 req->in.args[0].value = &inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000563 req->in.args[1].size = count;
Miklos Szerediad051c32004-07-02 09:22:50 +0000564 req->out.numargs = 1;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000565 req->out.args[0].size = sizeof(struct fuse_write_out);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000566 req->out.args[0].value = &outarg;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000567 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000568 return outarg.size;
Miklos Szeredia181e612001-11-06 12:03:23 +0000569}
570
Miklos Szeredia181e612001-11-06 12:03:23 +0000571static int fuse_prepare_write(struct file *file, struct page *page,
572 unsigned offset, unsigned to)
573{
574 /* No op */
575 return 0;
576}
577
578static int fuse_commit_write(struct file *file, struct page *page,
579 unsigned offset, unsigned to)
580{
581 int err;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000582 size_t nres;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000583 unsigned count = to - offset;
Miklos Szeredia181e612001-11-06 12:03:23 +0000584 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000585 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000586 loff_t pos = page_offset(page) + offset;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000587 struct fuse_req *req;
588
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000589 if (is_bad_inode(inode))
590 return -EIO;
591
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000592 req = fuse_get_req(fc);
593 if (IS_ERR(req))
594 return PTR_ERR(req);
Miklos Szeredia181e612001-11-06 12:03:23 +0000595
Miklos Szeredi039322d2004-12-01 18:39:12 +0000596 req->num_pages = 1;
597 req->pages[0] = page;
598 req->page_offset = offset;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000599 nres = fuse_send_write(req, file, inode, pos, count);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000600 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000601 fuse_put_request(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000602 if (!err && nres != count)
603 err = -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000604 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000605 pos += count;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000606 if (pos > i_size_read(inode))
Miklos Szeredid1199f82004-02-06 15:29:22 +0000607 i_size_write(inode, pos);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000608
609 if (offset == 0 && to == PAGE_CACHE_SIZE) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000610 clear_page_dirty(page);
611 SetPageUptodate(page);
612 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000613 }
614 fuse_invalidate_attr(inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000615 return err;
616}
617
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000618static void fuse_release_user_pages(struct fuse_req *req, int write)
619{
620 unsigned i;
621
622 for (i = 0; i < req->num_pages; i++) {
623 struct page *page = req->pages[i];
Miklos Szeredie56818b2004-12-12 11:45:24 +0000624 if (write)
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000625 set_page_dirty_lock(page);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000626 put_page(page);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000627 }
628}
629
630static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
631 unsigned nbytes, int write)
632{
633 unsigned long user_addr = (unsigned long) buf;
634 unsigned offset = user_addr & ~PAGE_MASK;
635 int npages;
636
Miklos Szeredi89814a12005-04-08 16:39:09 +0000637 /* This doesn't work with nfsd */
638 if (!current->mm)
639 return -EPERM;
640
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000641 nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
642 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
Miklos Szeredi1f6a5342006-01-06 13:40:07 +0000643 npages = max(npages, 1);
644 npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
Miklos Szeredic45d1a62004-12-07 20:13:47 +0000645 down_read(&current->mm->mmap_sem);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000646 npages = get_user_pages(current, current->mm, user_addr, npages, write,
647 0, req->pages, NULL);
Miklos Szeredic45d1a62004-12-07 20:13:47 +0000648 up_read(&current->mm->mmap_sem);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000649 if (npages < 0)
650 return npages;
651
652 req->num_pages = npages;
653 req->page_offset = offset;
654 return 0;
655}
656
657static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
658 size_t count, loff_t *ppos, int write)
Miklos Szerediad051c32004-07-02 09:22:50 +0000659{
660 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000661 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredieab72ef2005-03-31 19:59:12 +0000662 size_t nmax = write ? fc->max_write : fc->max_read;
Miklos Szerediad051c32004-07-02 09:22:50 +0000663 loff_t pos = *ppos;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000664 ssize_t res = 0;
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000665 struct fuse_req *req;
666
667 if (is_bad_inode(inode))
668 return -EIO;
669
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000670 req = fuse_get_req(fc);
671 if (IS_ERR(req))
672 return PTR_ERR(req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000673
Miklos Szerediad051c32004-07-02 09:22:50 +0000674 while (count) {
Miklos Szeredieab72ef2005-03-31 19:59:12 +0000675 size_t nres;
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000676 size_t nbytes = min(count, nmax);
677 int err = fuse_get_user_pages(req, buf, nbytes, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000678 if (err) {
679 res = err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000680 break;
681 }
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000682 nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
683 nbytes = min(count, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000684 if (write)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000685 nres = fuse_send_write(req, file, inode, pos, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000686 else
Miklos Szeredie56818b2004-12-12 11:45:24 +0000687 nres = fuse_send_read(req, file, inode, pos, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000688 fuse_release_user_pages(req, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000689 if (req->out.h.error) {
690 if (!res)
691 res = req->out.h.error;
Miklos Szerediad051c32004-07-02 09:22:50 +0000692 break;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000693 } else if (nres > nbytes) {
694 res = -EIO;
695 break;
Miklos Szerediad051c32004-07-02 09:22:50 +0000696 }
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000697 count -= nres;
698 res += nres;
699 pos += nres;
700 buf += nres;
701 if (nres != nbytes)
Miklos Szerediad051c32004-07-02 09:22:50 +0000702 break;
Miklos Szeredi7a2814c2006-04-12 10:41:50 +0000703 if (count) {
704 fuse_put_request(fc, req);
705 req = fuse_get_req(fc);
706 if (IS_ERR(req))
707 break;
708 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000709 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000710 fuse_put_request(fc, req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000711 if (res > 0) {
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000712 if (write && pos > i_size_read(inode))
Miklos Szerediad051c32004-07-02 09:22:50 +0000713 i_size_write(inode, pos);
714 *ppos = pos;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000715 }
Miklos Szeredi1b188022005-07-28 11:07:29 +0000716 fuse_invalidate_attr(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000717
Miklos Szerediad051c32004-07-02 09:22:50 +0000718 return res;
719}
720
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000721static ssize_t fuse_direct_read(struct file *file, char __user *buf,
722 size_t count, loff_t *ppos)
723{
724 return fuse_direct_io(file, buf, count, ppos, 0);
725}
726
727static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
728 size_t count, loff_t *ppos)
729{
730 struct inode *inode = file->f_dentry->d_inode;
731 ssize_t res;
732 /* Don't allow parallel writes to the same file */
Miklos Szeredie089b712006-01-17 12:42:39 +0000733#ifdef KERNEL_2_6_16_PLUS
734 mutex_lock(&inode->i_mutex);
735 res = fuse_direct_io(file, buf, count, ppos, 1);
736 mutex_unlock(&inode->i_mutex);
737#else
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000738 down(&inode->i_sem);
739 res = fuse_direct_io(file, buf, count, ppos, 1);
740 up(&inode->i_sem);
Miklos Szeredie089b712006-01-17 12:42:39 +0000741#endif
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000742 return res;
743}
744
745#ifndef KERNEL_2_6
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000746static ssize_t fuse_file_read(struct file *file, char __user *buf,
747 size_t count, loff_t *ppos)
748{
749 struct inode *inode = file->f_dentry->d_inode;
750 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000751
Miklos Szeredi23f49a02006-01-06 13:04:46 +0000752 if (is_bad_inode(inode))
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000753 return -EIO;
754
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000755 if (fc->flags & FUSE_LARGE_READ) {
756 int res;
Miklos Szerediad051c32004-07-02 09:22:50 +0000757 down(&inode->i_sem);
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000758 res = fuse_file_bigread(file, inode, *ppos, count);
Miklos Szerediad051c32004-07-02 09:22:50 +0000759 up(&inode->i_sem);
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000760 if (res)
761 return res;
Miklos Szerediad051c32004-07-02 09:22:50 +0000762 }
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000763 return generic_file_read(file, buf, count, ppos);
Miklos Szerediad051c32004-07-02 09:22:50 +0000764}
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000765#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000766static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
767{
Miklos Szeredi2a927272005-01-07 11:14:15 +0000768 if ((vma->vm_flags & VM_SHARED)) {
769 if ((vma->vm_flags & VM_WRITE))
770 return -ENODEV;
771 else
772 vma->vm_flags &= ~VM_MAYWRITE;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000773 }
Miklos Szeredi2a927272005-01-07 11:14:15 +0000774 return generic_file_mmap(file, vma);
Miklos Szerediad051c32004-07-02 09:22:50 +0000775}
776
Miklos Szeredi2a927272005-01-07 11:14:15 +0000777#ifdef KERNEL_2_6
778static int fuse_set_page_dirty(struct page *page)
779{
780 printk("fuse_set_page_dirty: should not happen\n");
781 dump_stack();
782 return 0;
783}
784#endif
785
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000786static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
787 struct file_lock *fl)
788{
789 switch (ffl->type) {
790 case F_UNLCK:
791 break;
792
793 case F_RDLCK:
794 case F_WRLCK:
795 if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||
796 ffl->end < ffl->start)
797 return -EIO;
798
799 fl->fl_start = ffl->start;
800 fl->fl_end = ffl->end;
801 fl->fl_pid = ffl->pid;
802 break;
803
804 default:
805 return -EIO;
806 }
807 fl->fl_type = ffl->type;
808 return 0;
809}
810
811static void fuse_lk_fill(struct fuse_req *req, struct file *file,
812 const struct file_lock *fl, int opcode, pid_t pid)
813{
814 struct inode *inode = file->f_dentry->d_inode;
815 struct fuse_conn *fc = get_fuse_conn(inode);
816 struct fuse_file *ff = file->private_data;
817 struct fuse_lk_in *arg = &req->misc.lk_in;
818
819 arg->fh = ff->fh;
820 arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);
821 arg->lk.start = fl->fl_start;
822 arg->lk.end = fl->fl_end;
823 arg->lk.type = fl->fl_type;
824 arg->lk.pid = pid;
825 req->in.h.opcode = opcode;
826 req->in.h.nodeid = get_node_id(inode);
827 req->in.numargs = 1;
828 req->in.args[0].size = sizeof(*arg);
829 req->in.args[0].value = arg;
830}
831
832static int fuse_getlk(struct file *file, struct file_lock *fl)
833{
834 struct inode *inode = file->f_dentry->d_inode;
835 struct fuse_conn *fc = get_fuse_conn(inode);
836 struct fuse_req *req;
837 struct fuse_lk_out outarg;
838 int err;
839
840 req = fuse_get_req(fc);
841 if (IS_ERR(req))
842 return PTR_ERR(req);
843
844 fuse_lk_fill(req, file, fl, FUSE_GETLK, 0);
845 req->out.numargs = 1;
846 req->out.args[0].size = sizeof(outarg);
847 req->out.args[0].value = &outarg;
848 request_send(fc, req);
849 err = req->out.h.error;
850 fuse_put_request(fc, req);
851 if (!err)
852 err = convert_fuse_file_lock(&outarg.lk, fl);
853
854 return err;
855}
856
857static int fuse_setlk(struct file *file, struct file_lock *fl)
858{
859 struct inode *inode = file->f_dentry->d_inode;
860 struct fuse_conn *fc = get_fuse_conn(inode);
861 struct fuse_req *req;
862 int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
863 pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
864 int err;
865
866#ifdef KERNEL_2_6_18_PLUS
867 /* Unlock on close is handled by the flush method */
868 if (fl->fl_flags & FL_CLOSE)
869 return 0;
870#endif
871
872 req = fuse_get_req(fc);
873 if (IS_ERR(req))
874 return PTR_ERR(req);
875
876 fuse_lk_fill(req, file, fl, opcode, pid);
877 request_send(fc, req);
878 err = req->out.h.error;
879 /* locking is restartable */
880 if (err == -EINTR)
881 err = -ERESTARTSYS;
882 fuse_put_request(fc, req);
883 return err;
884}
885
886static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
887{
888 struct inode *inode = file->f_dentry->d_inode;
889 struct fuse_conn *fc = get_fuse_conn(inode);
890 int err;
891
892 if (cmd == F_GETLK) {
893 if (fc->no_lock) {
894#ifdef KERNEL_2_6_17_PLUS
895 if (!posix_test_lock(file, fl, fl))
896 fl->fl_type = F_UNLCK;
897#else
898 struct file_lock *cfl = posix_test_lock(file, fl);
899 if (!cfl)
900 fl->fl_type = F_UNLCK;
901 else
902 *fl = *cfl;
903#endif
904 err = 0;
905 } else
906 err = fuse_getlk(file, fl);
907 } else {
908 if (fc->no_lock)
909 err = posix_lock_file_wait(file, fl);
910 else
911 err = fuse_setlk(file, fl);
912 }
913 return err;
914}
915
Miklos Szeredi5e183482001-10-31 14:52:35 +0000916static struct file_operations fuse_file_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +0000917 .llseek = generic_file_llseek,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000918#ifdef KERNEL_2_6
Miklos Szeredi15af1b82006-01-16 17:52:24 +0000919 .read = generic_file_read,
920 .write = generic_file_write,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000921#else
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000922 .read = fuse_file_read,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000923 .write = generic_file_write,
Miklos Szeredi2b478112005-11-28 13:27:10 +0000924#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000925 .mmap = fuse_file_mmap,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000926 .open = fuse_open,
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000927 .flush = fuse_flush,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000928 .release = fuse_release,
929 .fsync = fuse_fsync,
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000930 .lock = fuse_file_lock,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000931#ifdef KERNEL_2_6
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000932 .sendfile = generic_file_sendfile,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000933#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000934};
935
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000936static struct file_operations fuse_direct_io_file_operations = {
937 .llseek = generic_file_llseek,
938 .read = fuse_direct_read,
939 .write = fuse_direct_write,
940 .open = fuse_open,
941 .flush = fuse_flush,
942 .release = fuse_release,
943 .fsync = fuse_fsync,
Miklos Szeredi91762cd2006-06-29 14:38:35 +0000944 .lock = fuse_file_lock,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000945 /* no mmap and sendfile */
946};
947
Miklos Szeredi5e183482001-10-31 14:52:35 +0000948static struct address_space_operations fuse_file_aops = {
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000949 .readpage = fuse_readpage,
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000950 .prepare_write = fuse_prepare_write,
951 .commit_write = fuse_commit_write,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000952#ifdef KERNEL_2_6
Miklos Szeredi58865372004-07-20 14:22:26 +0000953 .readpages = fuse_readpages,
Miklos Szeredi2a927272005-01-07 11:14:15 +0000954 .set_page_dirty = fuse_set_page_dirty,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000955#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000956};
957
958void fuse_init_file_inode(struct inode *inode)
959{
Miklos Szeredie77cc072005-08-01 11:58:51 +0000960 inode->i_fop = &fuse_file_operations;
961 inode->i_data.a_ops = &fuse_file_aops;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000962}