blob: 2d34e01bcecf8a8cf2331f72f83897b032aabdf6 [file] [log] [blame]
Miklos Szeredi5e183482001-10-31 14:52:35 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 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
35 req = fuse_get_request(fc);
36 if (!req)
37 return -EINTR;
38
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);
43 req->inode = inode;
44 req->in.numargs = 1;
45 req->in.args[0].size = sizeof(inarg);
46 req->in.args[0].value = &inarg;
47 req->out.numargs = 1;
48 req->out.args[0].size = sizeof(*outargp);
49 req->out.args[0].value = outargp;
50 request_send(fc, req);
51 err = req->out.h.error;
52 fuse_put_request(fc, req);
53
54 return err;
55}
56
57struct fuse_file *fuse_file_alloc(void)
58{
59 struct fuse_file *ff;
60 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
61 if (ff) {
62 ff->release_req = fuse_request_alloc();
63 if (!ff->release_req) {
64 kfree(ff);
65 ff = NULL;
66 }
67 }
68 return ff;
69}
70
71void fuse_file_free(struct fuse_file *ff)
72{
73 fuse_request_free(ff->release_req);
74 kfree(ff);
75}
76
77void fuse_finish_open(struct inode *inode, struct file *file,
78 struct fuse_file *ff, struct fuse_open_out *outarg)
79{
80 if (outarg->open_flags & FOPEN_DIRECT_IO)
81 file->f_op = &fuse_direct_io_file_operations;
82 if (!(outarg->open_flags & FOPEN_KEEP_CACHE))
83#ifdef KERNEL_2_6
84 invalidate_inode_pages(inode->i_mapping);
85#else
86 invalidate_inode_pages(inode);
87#endif
88 ff->fh = outarg->fh;
89 file->private_data = ff;
90}
91
92int fuse_open_common(struct inode *inode, struct file *file, int isdir)
93{
Miklos Szeredi209f5d02004-07-24 19:56:16 +000094 struct fuse_open_out outarg;
95 struct fuse_file *ff;
Miklos Szeredif58cc612004-02-06 13:52:00 +000096 int err;
97
Miklos Szeredif45f3c12005-09-22 15:14:27 +000098 /* VFS checks this, but only _after_ ->open() */
99 if (file->f_flags & O_DIRECT)
100 return -EINVAL;
101
Miklos Szeredif58cc612004-02-06 13:52:00 +0000102 err = generic_file_open(inode, file);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000103 if (err)
Miklos Szeredif58cc612004-02-06 13:52:00 +0000104 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000105
Miklos Szeredife25def2001-12-20 15:38:05 +0000106 /* If opening the root node, no lookup has been performed on
107 it, so the attributes must be refreshed */
Miklos Szeredi039322d2004-12-01 18:39:12 +0000108 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredid9079a72005-10-26 15:29:06 +0000109 err = fuse_do_getattr(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000110 if (err)
Miklos Szeredife25def2001-12-20 15:38:05 +0000111 return err;
112 }
113
Miklos Szeredid9079a72005-10-26 15:29:06 +0000114 ff = fuse_file_alloc();
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000115 if (!ff)
Miklos Szeredid9079a72005-10-26 15:29:06 +0000116 return -ENOMEM;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +0000117
Miklos Szeredid9079a72005-10-26 15:29:06 +0000118 err = fuse_send_open(inode, file, isdir, &outarg);
119 if (err)
120 fuse_file_free(ff);
121 else {
122 if (isdir)
123 outarg.open_flags &= ~FOPEN_DIRECT_IO;
124 fuse_finish_open(inode, file, ff, &outarg);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000125 }
126
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000127 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000128}
129
Miklos Szeredid9079a72005-10-26 15:29:06 +0000130void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff,
131 u64 nodeid, struct inode *inode, int flags, int isdir)
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000132{
Miklos Szeredid9079a72005-10-26 15:29:06 +0000133 struct fuse_req * req = ff->release_req;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000134 struct fuse_release_in *inarg = &req->misc.release_in;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000135
Miklos Szeredie56818b2004-12-12 11:45:24 +0000136 inarg->fh = ff->fh;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000137 inarg->flags = flags;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000138 req->in.h.opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000139 req->in.h.nodeid = nodeid;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000140 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000141 req->in.numargs = 1;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000142 req->in.args[0].size = sizeof(struct fuse_release_in);
143 req->in.args[0].value = inarg;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000144 request_send_background(fc, req);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000145 kfree(ff);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000146}
147
148int fuse_release_common(struct inode *inode, struct file *file, int isdir)
149{
150 struct fuse_file *ff = file->private_data;
151 if (ff) {
152 struct fuse_conn *fc = get_fuse_conn(inode);
153 u64 nodeid = get_node_id(inode);
154 fuse_send_release(fc, ff, nodeid, inode, file->f_flags, isdir);
155 }
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000156
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000157 /* Return value is ignored by VFS */
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000158 return 0;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000159}
160
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000161static int fuse_open(struct inode *inode, struct file *file)
162{
163 return fuse_open_common(inode, file, 0);
164}
165
166static int fuse_release(struct inode *inode, struct file *file)
167{
168 return fuse_release_common(inode, file, 0);
169}
170
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000171static int fuse_flush(struct file *file)
172{
173 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000174 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000175 struct fuse_file *ff = file->private_data;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000176 struct fuse_req *req;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000177 struct fuse_flush_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000178 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000179
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000180 if (is_bad_inode(inode))
181 return -EIO;
182
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000183 if (fc->no_flush)
184 return 0;
185
Miklos Szeredif94e0102005-05-12 14:56:34 +0000186 req = fuse_get_request(fc);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000187 if (!req)
188 return -EINTR;
189
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000190 memset(&inarg, 0, sizeof(inarg));
191 inarg.fh = ff->fh;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000192 req->in.h.opcode = FUSE_FLUSH;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000193 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000194 req->inode = inode;
195 req->file = file;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000196 req->in.numargs = 1;
197 req->in.args[0].size = sizeof(inarg);
198 req->in.args[0].value = &inarg;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000199 request_send(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000200 err = req->out.h.error;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000201 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000202 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000203 fc->no_flush = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000204 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000205 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000206 return err;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000207}
208
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000209int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
210 int isdir)
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000211{
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000212 struct inode *inode = de->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000213 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000214 struct fuse_file *ff = file->private_data;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000215 struct fuse_req *req;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000216 struct fuse_fsync_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000217 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000218
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000219 if (is_bad_inode(inode))
220 return -EIO;
221
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000222 if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000223 return 0;
224
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000225 req = fuse_get_request(fc);
226 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000227 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000228
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000229 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000230 inarg.fh = ff->fh;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000231 inarg.fsync_flags = datasync ? 1 : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000232 req->in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000233 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000234 req->inode = inode;
235 req->file = file;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000236 req->in.numargs = 1;
237 req->in.args[0].size = sizeof(inarg);
238 req->in.args[0].value = &inarg;
239 request_send(fc, req);
240 err = req->out.h.error;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000241 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000242 if (err == -ENOSYS) {
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000243 if (isdir)
244 fc->no_fsyncdir = 1;
245 else
246 fc->no_fsync = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000247 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000248 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000249 return err;
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000250}
Miklos Szeredia181e612001-11-06 12:03:23 +0000251
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000252static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
253{
254 return fuse_fsync_common(file, de, datasync, 0);
255}
256
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000257size_t fuse_send_read_common(struct fuse_req *req, struct file *file,
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000258 struct inode *inode, loff_t pos, size_t count,
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000259 int isdir)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000260{
Miklos Szeredie56818b2004-12-12 11:45:24 +0000261 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000262 struct fuse_file *ff = file->private_data;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000263 struct fuse_read_in inarg;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000264
Miklos Szeredie56818b2004-12-12 11:45:24 +0000265 memset(&inarg, 0, sizeof(struct fuse_read_in));
266 inarg.fh = ff->fh;
267 inarg.offset = pos;
268 inarg.size = count;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000269 req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000270 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000271 req->inode = inode;
272 req->file = file;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000273 req->in.numargs = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000274 req->in.args[0].size = sizeof(struct fuse_read_in);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000275 req->in.args[0].value = &inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000276 req->out.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 req->out.argvar = 1;
278 req->out.numargs = 1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000279 req->out.args[0].size = count;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000280 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000281 return req->out.args[0].size;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000282}
283
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000284static inline size_t fuse_send_read(struct fuse_req *req, struct file *file,
285 struct inode *inode, loff_t pos,
286 size_t count)
287{
288 return fuse_send_read_common(req, file, inode, pos, count, 0);
289}
290
Miklos Szerediad051c32004-07-02 09:22:50 +0000291static int fuse_readpage(struct file *file, struct page *page)
292{
293 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000294 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000295 struct fuse_req *req;
296 int err;
297
298 err = -EIO;
299 if (is_bad_inode(inode))
300 goto out;
301
302 err = -EINTR;
303 req = fuse_get_request(fc);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000304 if (!req)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000305 goto out;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000306
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000307 req->out.page_zeroing = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000308 req->num_pages = 1;
309 req->pages[0] = page;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000310 fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000311 err = req->out.h.error;
312 fuse_put_request(fc, req);
313 if (!err)
Miklos Szerediad051c32004-07-02 09:22:50 +0000314 SetPageUptodate(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000315 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000316 out:
Miklos Szerediad051c32004-07-02 09:22:50 +0000317 unlock_page(page);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000318 return err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000319}
320
Miklos Szeredi58865372004-07-20 14:22:26 +0000321#ifdef KERNEL_2_6
Miklos Szeredie56818b2004-12-12 11:45:24 +0000322static int fuse_send_readpages(struct fuse_req *req, struct file *file,
323 struct inode *inode)
Miklos Szeredi58865372004-07-20 14:22:26 +0000324{
Miklos Szeredi2b478112005-11-28 13:27:10 +0000325 loff_t pos = page_offset(req->pages[0]);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000326 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
Miklos Szeredi58865372004-07-20 14:22:26 +0000327 unsigned i;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000328 req->out.page_zeroing = 1;
329 fuse_send_read(req, file, inode, pos, count);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000330 for (i = 0; i < req->num_pages; i++) {
331 struct page *page = req->pages[i];
332 if (!req->out.h.error)
333 SetPageUptodate(page);
334 unlock_page(page);
335 }
Miklos Szeredie56818b2004-12-12 11:45:24 +0000336 return req->out.h.error;
Miklos Szeredi58865372004-07-20 14:22:26 +0000337}
338
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000339struct fuse_readpages_data {
340 struct fuse_req *req;
341 struct file *file;
342 struct inode *inode;
343};
344
345static int fuse_readpages_fill(void *_data, struct page *page)
Miklos Szeredi58865372004-07-20 14:22:26 +0000346{
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000347 struct fuse_readpages_data *data = _data;
348 struct fuse_req *req = data->req;
349 struct inode *inode = data->inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000350 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000351
352 if (req->num_pages &&
Miklos Szeredi58865372004-07-20 14:22:26 +0000353 (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000354 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
Miklos Szeredi58865372004-07-20 14:22:26 +0000355 req->pages[req->num_pages - 1]->index + 1 != page->index)) {
Miklos Szeredie56818b2004-12-12 11:45:24 +0000356 int err = fuse_send_readpages(req, data->file, inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000357 if (err) {
358 unlock_page(page);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000359 return err;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000360 }
Miklos Szeredie56818b2004-12-12 11:45:24 +0000361 fuse_reset_request(req);
Miklos Szeredi58865372004-07-20 14:22:26 +0000362 }
363 req->pages[req->num_pages] = page;
364 req->num_pages ++;
365 return 0;
366}
367
368static int fuse_readpages(struct file *file, struct address_space *mapping,
369 struct list_head *pages, unsigned nr_pages)
370{
371 struct inode *inode = mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000372 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000373 struct fuse_readpages_data data;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000374 int err;
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000375
376 if (is_bad_inode(inode))
377 return -EIO;
378
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000379 data.file = file;
380 data.inode = inode;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000381 data.req = fuse_get_request(fc);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000382 if (!data.req)
383 return -EINTR;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000384
Miklos Szeredie56818b2004-12-12 11:45:24 +0000385 err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
386 if (!err && data.req->num_pages)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000387 err = fuse_send_readpages(data.req, file, inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000388 fuse_put_request(fc, data.req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000389 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie56818b2004-12-12 11:45:24 +0000390 return err;
Miklos Szeredi58865372004-07-20 14:22:26 +0000391}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000392#else /* KERNEL_2_6 */
Miklos Szeredi83a07442004-11-30 18:25:20 +0000393#define FUSE_BLOCK_SHIFT 16
394#define FUSE_BLOCK_SIZE (1UL << FUSE_BLOCK_SHIFT)
395#define FUSE_BLOCK_MASK (~(FUSE_BLOCK_SIZE-1))
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000396#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
Miklos Szeredi83a07442004-11-30 18:25:20 +0000397#error FUSE_BLOCK_SHIFT too large
398#endif
399
400static int fuse_is_block_uptodate(struct inode *inode, unsigned start,
401 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000402{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000403 int index;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000404
Miklos Szeredi83a07442004-11-30 18:25:20 +0000405 for (index = start; index < end; index++) {
Miklos Szerediad051c32004-07-02 09:22:50 +0000406 struct page *page = find_get_page(inode->i_mapping, index);
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000407 if (!page)
408 return 0;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000409 if (!PageUptodate(page)) {
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000410 page_cache_release(page);
411 return 0;
412 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000413 page_cache_release(page);
414 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000415 return 1;
416}
417
Miklos Szeredie56818b2004-12-12 11:45:24 +0000418static int fuse_file_read_block(struct fuse_req *req, struct file *file,
419 struct inode *inode, unsigned start,
420 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000421{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000422 loff_t pos;
423 size_t count;
424 int index;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000425 int err = -EBUSY;
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000426 int i;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000427
Miklos Szeredi83a07442004-11-30 18:25:20 +0000428 for (index = start; index < end; index++) {
429 struct page *page = grab_cache_page(inode->i_mapping, index);
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000430 if (!page)
Miklos Szeredi83a07442004-11-30 18:25:20 +0000431 goto out;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000432 if (PageUptodate(page)) {
433 unlock_page(page);
434 page_cache_release(page);
435 page = NULL;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000436 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000437 req->pages[req->num_pages++] = page;
438 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000439 pos = (loff_t) start << PAGE_CACHE_SHIFT;
440 count = req->num_pages << PAGE_CACHE_SHIFT;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000441 fuse_send_read(req, file, inode, pos, count);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000442 err = req->out.h.error;
443 out:
444 for (i = 0; i < req->num_pages; i++) {
445 struct page *page = req->pages[i];
Miklos Szeredi039322d2004-12-01 18:39:12 +0000446 if (page) {
447 if (!err)
448 SetPageUptodate(page);
449 unlock_page(page);
450 page_cache_release(page);
451 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000452 }
Miklos Szeredie56818b2004-12-12 11:45:24 +0000453 return err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000454}
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000455
Miklos Szeredi83a07442004-11-30 18:25:20 +0000456static int fuse_file_bigread(struct file *file, struct inode *inode,
457 loff_t pos, size_t count)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000458{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000459 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000460 unsigned starti;
461 unsigned endi;
462 unsigned nexti;
463 struct fuse_req *req;
464 loff_t size = i_size_read(inode);
465 loff_t end = (pos + count + FUSE_BLOCK_SIZE - 1) & FUSE_BLOCK_MASK;
466 end = min(end, size);
467 if (end <= pos)
468 return 0;
469
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000470 starti = (pos & FUSE_BLOCK_MASK) >> PAGE_CACHE_SHIFT;
471 endi = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
472
Miklos Szeredi83a07442004-11-30 18:25:20 +0000473 req = fuse_get_request(fc);
474 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000475 return -EINTR;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000476
Miklos Szeredi83a07442004-11-30 18:25:20 +0000477 for (; starti < endi; starti = nexti) {
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000478 nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000479 nexti = min(nexti, endi);
480 if (!fuse_is_block_uptodate(inode, starti, nexti)) {
Miklos Szeredie56818b2004-12-12 11:45:24 +0000481 if (fuse_file_read_block(req, file, inode, starti, nexti))
482 break;
483
Miklos Szeredi83a07442004-11-30 18:25:20 +0000484 fuse_reset_request(req);
485 }
Miklos Szeredi307242f2004-01-26 11:28:44 +0000486 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000487 fuse_put_request(fc, req);
488 return 0;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000489}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000490#endif /* KERNEL_2_6 */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000491
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000492static size_t fuse_send_write(struct fuse_req *req, struct file *file,
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000493 struct inode *inode, loff_t pos, size_t count)
Miklos Szeredia181e612001-11-06 12:03:23 +0000494{
Miklos Szeredie56818b2004-12-12 11:45:24 +0000495 struct fuse_conn *fc = get_fuse_conn(inode);
496 struct fuse_file *ff = file->private_data;
497 struct fuse_write_in inarg;
498 struct fuse_write_out outarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000499
Miklos Szeredie56818b2004-12-12 11:45:24 +0000500 memset(&inarg, 0, sizeof(struct fuse_write_in));
Miklos Szeredie56818b2004-12-12 11:45:24 +0000501 inarg.fh = ff->fh;
502 inarg.offset = pos;
503 inarg.size = count;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000504 req->in.h.opcode = FUSE_WRITE;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000505 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000506 req->inode = inode;
507 req->file = file;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000508 req->in.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000509 req->in.numargs = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000510 req->in.args[0].size = sizeof(struct fuse_write_in);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000511 req->in.args[0].value = &inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000512 req->in.args[1].size = count;
Miklos Szerediad051c32004-07-02 09:22:50 +0000513 req->out.numargs = 1;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000514 req->out.args[0].size = sizeof(struct fuse_write_out);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000515 req->out.args[0].value = &outarg;
Miklos Szeredif94e0102005-05-12 14:56:34 +0000516 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000517 return outarg.size;
Miklos Szeredia181e612001-11-06 12:03:23 +0000518}
519
Miklos Szeredia181e612001-11-06 12:03:23 +0000520static int fuse_prepare_write(struct file *file, struct page *page,
521 unsigned offset, unsigned to)
522{
523 /* No op */
524 return 0;
525}
526
527static int fuse_commit_write(struct file *file, struct page *page,
528 unsigned offset, unsigned to)
529{
530 int err;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000531 size_t nres;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000532 unsigned count = to - offset;
Miklos Szeredia181e612001-11-06 12:03:23 +0000533 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000534 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000535 loff_t pos = page_offset(page) + offset;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000536 struct fuse_req *req;
537
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000538 if (is_bad_inode(inode))
539 return -EIO;
540
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000541 req = fuse_get_request(fc);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000542 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000543 return -EINTR;
Miklos Szeredia181e612001-11-06 12:03:23 +0000544
Miklos Szeredi039322d2004-12-01 18:39:12 +0000545 req->num_pages = 1;
546 req->pages[0] = page;
547 req->page_offset = offset;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000548 nres = fuse_send_write(req, file, inode, pos, count);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000549 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000550 fuse_put_request(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000551 if (!err && nres != count)
552 err = -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000553 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000554 pos += count;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000555 if (pos > i_size_read(inode))
Miklos Szeredid1199f82004-02-06 15:29:22 +0000556 i_size_write(inode, pos);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000557
558 if (offset == 0 && to == PAGE_CACHE_SIZE) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000559 clear_page_dirty(page);
560 SetPageUptodate(page);
561 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000562 }
563 fuse_invalidate_attr(inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000564 return err;
565}
566
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000567static void fuse_release_user_pages(struct fuse_req *req, int write)
568{
569 unsigned i;
570
571 for (i = 0; i < req->num_pages; i++) {
572 struct page *page = req->pages[i];
Miklos Szeredie56818b2004-12-12 11:45:24 +0000573 if (write)
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000574 set_page_dirty_lock(page);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000575 put_page(page);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000576 }
577}
578
579static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
580 unsigned nbytes, int write)
581{
582 unsigned long user_addr = (unsigned long) buf;
583 unsigned offset = user_addr & ~PAGE_MASK;
584 int npages;
585
Miklos Szeredi89814a12005-04-08 16:39:09 +0000586 /* This doesn't work with nfsd */
587 if (!current->mm)
588 return -EPERM;
589
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000590 nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
591 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000592 npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ);
Miklos Szeredic45d1a62004-12-07 20:13:47 +0000593 down_read(&current->mm->mmap_sem);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000594 npages = get_user_pages(current, current->mm, user_addr, npages, write,
595 0, req->pages, NULL);
Miklos Szeredic45d1a62004-12-07 20:13:47 +0000596 up_read(&current->mm->mmap_sem);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000597 if (npages < 0)
598 return npages;
599
600 req->num_pages = npages;
601 req->page_offset = offset;
602 return 0;
603}
604
605static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
606 size_t count, loff_t *ppos, int write)
Miklos Szerediad051c32004-07-02 09:22:50 +0000607{
608 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000609 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredieab72ef2005-03-31 19:59:12 +0000610 size_t nmax = write ? fc->max_write : fc->max_read;
Miklos Szerediad051c32004-07-02 09:22:50 +0000611 loff_t pos = *ppos;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000612 ssize_t res = 0;
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000613 struct fuse_req *req;
614
615 if (is_bad_inode(inode))
616 return -EIO;
617
618 req = fuse_get_request(fc);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000619 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000620 return -EINTR;
Miklos Szerediad051c32004-07-02 09:22:50 +0000621
Miklos Szerediad051c32004-07-02 09:22:50 +0000622 while (count) {
Miklos Szeredieab72ef2005-03-31 19:59:12 +0000623 size_t nres;
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000624 size_t nbytes = min(count, nmax);
625 int err = fuse_get_user_pages(req, buf, nbytes, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000626 if (err) {
627 res = err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000628 break;
629 }
Miklos Szeredi154ffe22005-12-15 16:41:20 +0000630 nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
631 nbytes = min(count, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000632 if (write)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000633 nres = fuse_send_write(req, file, inode, pos, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000634 else
Miklos Szeredie56818b2004-12-12 11:45:24 +0000635 nres = fuse_send_read(req, file, inode, pos, nbytes);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000636 fuse_release_user_pages(req, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000637 if (req->out.h.error) {
638 if (!res)
639 res = req->out.h.error;
Miklos Szerediad051c32004-07-02 09:22:50 +0000640 break;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000641 } else if (nres > nbytes) {
642 res = -EIO;
643 break;
Miklos Szerediad051c32004-07-02 09:22:50 +0000644 }
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000645 count -= nres;
646 res += nres;
647 pos += nres;
648 buf += nres;
649 if (nres != nbytes)
Miklos Szerediad051c32004-07-02 09:22:50 +0000650 break;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000651 if (count)
652 fuse_reset_request(req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000653 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000654 fuse_put_request(fc, req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000655 if (res > 0) {
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000656 if (write && pos > i_size_read(inode))
Miklos Szerediad051c32004-07-02 09:22:50 +0000657 i_size_write(inode, pos);
658 *ppos = pos;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000659 }
Miklos Szeredi1b188022005-07-28 11:07:29 +0000660 fuse_invalidate_attr(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000661
Miklos Szerediad051c32004-07-02 09:22:50 +0000662 return res;
663}
664
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000665static ssize_t fuse_direct_read(struct file *file, char __user *buf,
666 size_t count, loff_t *ppos)
667{
668 return fuse_direct_io(file, buf, count, ppos, 0);
669}
670
671static ssize_t fuse_direct_write(struct file *file, const char __user *buf,
672 size_t count, loff_t *ppos)
673{
674 struct inode *inode = file->f_dentry->d_inode;
675 ssize_t res;
676 /* Don't allow parallel writes to the same file */
677 down(&inode->i_sem);
678 res = fuse_direct_io(file, buf, count, ppos, 1);
679 up(&inode->i_sem);
680 return res;
681}
682
683#ifndef KERNEL_2_6
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000684static ssize_t fuse_file_read(struct file *file, char __user *buf,
685 size_t count, loff_t *ppos)
686{
687 struct inode *inode = file->f_dentry->d_inode;
688 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000689
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000690 if (is_bad_inode(file))
691 return -EIO;
692
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000693 if (fc->flags & FUSE_LARGE_READ) {
694 int res;
Miklos Szerediad051c32004-07-02 09:22:50 +0000695 down(&inode->i_sem);
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000696 res = fuse_file_bigread(file, inode, *ppos, count);
Miklos Szerediad051c32004-07-02 09:22:50 +0000697 up(&inode->i_sem);
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000698 if (res)
699 return res;
Miklos Szerediad051c32004-07-02 09:22:50 +0000700 }
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000701 return generic_file_read(file, buf, count, ppos);
Miklos Szerediad051c32004-07-02 09:22:50 +0000702}
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000703#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000704static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
705{
Miklos Szeredi2a927272005-01-07 11:14:15 +0000706 if ((vma->vm_flags & VM_SHARED)) {
707 if ((vma->vm_flags & VM_WRITE))
708 return -ENODEV;
709 else
710 vma->vm_flags &= ~VM_MAYWRITE;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000711 }
Miklos Szeredi2a927272005-01-07 11:14:15 +0000712 return generic_file_mmap(file, vma);
Miklos Szerediad051c32004-07-02 09:22:50 +0000713}
714
Miklos Szeredi2a927272005-01-07 11:14:15 +0000715#ifdef KERNEL_2_6
716static int fuse_set_page_dirty(struct page *page)
717{
718 printk("fuse_set_page_dirty: should not happen\n");
719 dump_stack();
720 return 0;
721}
722#endif
723
Miklos Szeredi5e183482001-10-31 14:52:35 +0000724static struct file_operations fuse_file_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +0000725 .llseek = generic_file_llseek,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000726#ifdef KERNEL_2_6
Miklos Szeredi2b478112005-11-28 13:27:10 +0000727 .read = do_sync_read,
728 .write = do_sync_write,
729 .readv = generic_file_readv,
730 .writev = generic_file_writev,
731 .aio_read = generic_file_aio_read,
732 .aio_write = generic_file_aio_write,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000733#else
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000734 .read = fuse_file_read,
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000735 .write = generic_file_write,
Miklos Szeredi2b478112005-11-28 13:27:10 +0000736#endif
Miklos Szerediad051c32004-07-02 09:22:50 +0000737 .mmap = fuse_file_mmap,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000738 .open = fuse_open,
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000739 .flush = fuse_flush,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000740 .release = fuse_release,
741 .fsync = fuse_fsync,
742#ifdef KERNEL_2_6
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000743 .sendfile = generic_file_sendfile,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000744#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000745};
746
Miklos Szeredibb9f5172005-07-03 18:03:11 +0000747static struct file_operations fuse_direct_io_file_operations = {
748 .llseek = generic_file_llseek,
749 .read = fuse_direct_read,
750 .write = fuse_direct_write,
751 .open = fuse_open,
752 .flush = fuse_flush,
753 .release = fuse_release,
754 .fsync = fuse_fsync,
755 /* no mmap and sendfile */
756};
757
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758static struct address_space_operations fuse_file_aops = {
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000759 .readpage = fuse_readpage,
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000760 .prepare_write = fuse_prepare_write,
761 .commit_write = fuse_commit_write,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000762#ifdef KERNEL_2_6
Miklos Szeredi58865372004-07-20 14:22:26 +0000763 .readpages = fuse_readpages,
Miklos Szeredi2a927272005-01-07 11:14:15 +0000764 .set_page_dirty = fuse_set_page_dirty,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000765#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000766};
767
768void fuse_init_file_inode(struct inode *inode)
769{
Miklos Szeredie77cc072005-08-01 11:58:51 +0000770 inode->i_fop = &fuse_file_operations;
771 inode->i_data.a_ops = &fuse_file_aops;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000772}