blob: bb1da5a5ac465a461c8ca483fff648ea2bf92b35 [file] [log] [blame]
Miklos Szeredi5e183482001-10-31 14:52:35 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi5e183482001-10-31 14:52:35 +00004
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
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>
14#include <linux/module.h>
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000015#include <linux/rmap.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000016#ifdef KERNEL_2_6
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000017#include <linux/writeback.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000018#include <linux/moduleparam.h>
Miklos Szeredif85ab242004-01-07 12:16:45 +000019#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +000020#include <asm/uaccess.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000021
Miklos Szeredi209f5d02004-07-24 19:56:16 +000022static int user_mmap;
23#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +000024module_param(user_mmap, int, 0644);
Miklos Szeredi209f5d02004-07-24 19:56:16 +000025#else
26MODULE_PARM(user_mmap, "i");
Miklos Szeredi13ed4822004-11-20 11:12:21 +000027#define PageUptodate(page) Page_Uptodate(page)
Miklos Szeredi209f5d02004-07-24 19:56:16 +000028#endif
Miklos Szeredi209f5d02004-07-24 19:56:16 +000029MODULE_PARM_DESC(user_mmap, "Allow non root user to create a shared writable mapping");
30
Miklos Szeredi5e183482001-10-31 14:52:35 +000031static int fuse_open(struct inode *inode, struct file *file)
32{
Miklos Szeredi039322d2004-12-01 18:39:12 +000033 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000034 struct fuse_req *req;
Miklos Szeredi43696432001-11-18 19:15:05 +000035 struct fuse_open_in inarg;
Miklos Szeredi209f5d02004-07-24 19:56:16 +000036 struct fuse_open_out outarg;
37 struct fuse_file *ff;
Miklos Szeredif58cc612004-02-06 13:52:00 +000038 int err;
39
40 err = generic_file_open(inode, file);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000041 if (err)
Miklos Szeredif58cc612004-02-06 13:52:00 +000042 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +000043
Miklos Szeredife25def2001-12-20 15:38:05 +000044 /* If opening the root node, no lookup has been performed on
45 it, so the attributes must be refreshed */
Miklos Szeredi039322d2004-12-01 18:39:12 +000046 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000047 int err = fuse_do_getattr(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000048 if (err)
Miklos Szeredife25def2001-12-20 15:38:05 +000049 return err;
50 }
51
Miklos Szerediad051c32004-07-02 09:22:50 +000052 down(&inode->i_sem);
53 err = -ERESTARTSYS;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000054 req = fuse_get_request(fc);
55 if (!req)
Miklos Szerediad051c32004-07-02 09:22:50 +000056 goto out;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000057
Miklos Szerediad051c32004-07-02 09:22:50 +000058 err = -ENOMEM;
Miklos Szeredi209f5d02004-07-24 19:56:16 +000059 ff = kmalloc(sizeof(struct fuse_file), GFP_KERNEL);
60 if (!ff)
Miklos Szerediad051c32004-07-02 09:22:50 +000061 goto out_put_request;
Miklos Szeredid3dd2d52004-06-22 18:46:02 +000062
Miklos Szeredi209f5d02004-07-24 19:56:16 +000063 ff->release_req = fuse_request_alloc();
64 if (!ff->release_req) {
65 kfree(ff);
66 goto out_put_request;
67 }
68
Miklos Szeredi43696432001-11-18 19:15:05 +000069 memset(&inarg, 0, sizeof(inarg));
70 inarg.flags = file->f_flags & ~O_EXCL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000071 req->in.h.opcode = FUSE_OPEN;
Miklos Szeredi039322d2004-12-01 18:39:12 +000072 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000073 req->in.numargs = 1;
74 req->in.args[0].size = sizeof(inarg);
75 req->in.args[0].value = &inarg;
Miklos Szeredi209f5d02004-07-24 19:56:16 +000076 req->out.numargs = 1;
77 req->out.args[0].size = sizeof(outarg);
78 req->out.args[0].value = &outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000079 request_send(fc, req);
80 err = req->out.h.error;
81 if (!err && !(fc->flags & FUSE_KERNEL_CACHE)) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000082#ifdef KERNEL_2_6
83 invalidate_inode_pages(inode->i_mapping);
84#else
Miklos Szeredia181e612001-11-06 12:03:23 +000085 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000086#endif
87 }
Miklos Szeredi209f5d02004-07-24 19:56:16 +000088 if (err) {
89 fuse_request_free(ff->release_req);
90 kfree(ff);
91 }
92 else {
93 ff->fh = outarg.fh;
94 file->private_data = ff;
95 INIT_LIST_HEAD(&ff->ff_list);
96 }
Miklos Szerediad051c32004-07-02 09:22:50 +000097
98 out_put_request:
Miklos Szeredi7eafcce2004-06-19 22:42:38 +000099 fuse_put_request(fc, req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000100 out:
101 up(&inode->i_sem);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000102 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000103}
104
Miklos Szeredi58615e02004-07-04 21:21:08 +0000105void fuse_sync_inode(struct inode *inode)
106{
107#ifdef KERNEL_2_6
108 filemap_fdatawrite(inode->i_mapping);
109 filemap_fdatawait(inode->i_mapping);
110#else
111#ifndef NO_MM
112 filemap_fdatasync(inode->i_mapping);
113 filemap_fdatawait(inode->i_mapping);
114#endif
115#endif
116}
117
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000118static int fuse_release(struct inode *inode, struct file *file)
119{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000120 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000121 struct fuse_file *ff = file->private_data;
122 struct fuse_req *req = ff->release_req;
Miklos Szeredi72cf5c92004-11-20 16:10:30 +0000123 struct fuse_release_in inarg;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000124
Miklos Szerediad051c32004-07-02 09:22:50 +0000125 down(&inode->i_sem);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000126 if (file->f_mode & FMODE_WRITE)
127 fuse_sync_inode(inode);
128
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000129 if (!list_empty(&ff->ff_list)) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000130 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000131 down_write(&fi->write_sem);
132 list_del(&ff->ff_list);
133 up_write(&fi->write_sem);
134 }
135
Miklos Szeredi72cf5c92004-11-20 16:10:30 +0000136 memset(&inarg, 0, sizeof(inarg));
137 inarg.fh = ff->fh;
138 inarg.flags = file->f_flags & ~O_EXCL;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000139 req->in.h.opcode = FUSE_RELEASE;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000140 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000141 req->in.numargs = 1;
Miklos Szeredi72cf5c92004-11-20 16:10:30 +0000142 req->in.args[0].size = sizeof(inarg);
143 req->in.args[0].value = &inarg;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000144 request_send(fc, req);
Miklos Szeredi556d03d2004-06-30 11:13:41 +0000145 fuse_put_request(fc, req);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000146 kfree(ff);
Miklos Szerediad051c32004-07-02 09:22:50 +0000147 up(&inode->i_sem);
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000148
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000149 /* Return value is ignored by VFS */
Miklos Szeredi383a9df2002-12-10 14:54:57 +0000150 return 0;
Miklos Szeredic8ba2372002-12-10 12:26:00 +0000151}
152
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000153static int fuse_flush(struct file *file)
154{
155 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000156 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000157 struct fuse_file *ff = file->private_data;
Miklos Szeredid45baf42004-10-10 07:56:12 +0000158 struct fuse_req *req = ff->release_req;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000159 struct fuse_flush_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000160 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000161
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000162 if (fc->no_flush)
163 return 0;
164
Miklos Szeredid45baf42004-10-10 07:56:12 +0000165 down(&inode->i_sem);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000166 memset(&inarg, 0, sizeof(inarg));
167 inarg.fh = ff->fh;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000168 req->in.h.opcode = FUSE_FLUSH;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000169 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000170 req->in.numargs = 1;
171 req->in.args[0].size = sizeof(inarg);
172 req->in.args[0].value = &inarg;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000173 request_send(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000174 err = req->out.h.error;
Miklos Szeredi95a2bfc2004-10-26 21:32:13 +0000175 fuse_reset_request(req);
Miklos Szeredid45baf42004-10-10 07:56:12 +0000176 up(&inode->i_sem);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000177 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000178 fc->no_flush = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000179 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000180 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000181 return err;
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000182}
183
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000184static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
185{
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000186 struct inode *inode = de->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000187 struct fuse_inode *fi = get_fuse_inode(inode);
188 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000189 struct fuse_file *ff = file->private_data;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000190 struct fuse_req *req;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000191 struct fuse_fsync_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000192 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000193
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000194 if (fc->no_fsync)
195 return 0;
196
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000197 req = fuse_get_request(fc);
198 if (!req)
199 return -ERESTARTSYS;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000200
201 /* Make sure all writes to this inode are completed before
202 issuing the FSYNC request */
203 down_write(&fi->write_sem);
204 up_write(&fi->write_sem);
205
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000206 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000207 inarg.fh = ff->fh;
Miklos Szeredi5e43f2c2003-12-12 14:06:41 +0000208 inarg.datasync = datasync;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 req->in.h.opcode = FUSE_FSYNC;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000210 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 req->in.numargs = 1;
212 req->in.args[0].size = sizeof(inarg);
213 req->in.args[0].value = &inarg;
214 request_send(fc, req);
215 err = req->out.h.error;
216 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000217 fc->no_fsync = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000218 err = 0;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000219 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000220 fuse_put_request(fc, req);
221 return err;
Miklos Szeredie4cf7332003-12-12 11:53:31 +0000222}
Miklos Szeredia181e612001-11-06 12:03:23 +0000223
Miklos Szeredi83a07442004-11-30 18:25:20 +0000224static void fuse_read_init(struct fuse_req *req, struct file *file,
225 struct inode *inode, loff_t pos, size_t count)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000226{
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000227 struct fuse_file *ff = file->private_data;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000228 struct fuse_read_in *inarg = &req->misc.read_in;
229
230 inarg->fh = ff->fh;
231 inarg->offset = pos;
232 inarg->size = count;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000233 req->in.h.opcode = FUSE_READ;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000234 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 req->in.numargs = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000236 req->in.args[0].size = sizeof(struct fuse_read_in);
237 req->in.args[0].value = inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000238 req->out.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000239 req->out.argvar = 1;
240 req->out.numargs = 1;
Miklos Szerediad051c32004-07-02 09:22:50 +0000241 req->out.args[0].size = count;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000242}
243
Miklos Szerediad051c32004-07-02 09:22:50 +0000244static int fuse_readpage(struct file *file, struct page *page)
245{
246 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000247 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000248 struct fuse_req *req = fuse_get_request_nonint(fc);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000249 loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000250 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000251
252 fuse_read_init(req, file, inode, pos, PAGE_CACHE_SIZE);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000253 req->out.page_zeroing = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000254 req->num_pages = 1;
255 req->pages[0] = page;
256 request_send(fc, req);
257 err = req->out.h.error;
258 fuse_put_request(fc, req);
259 if (!err)
Miklos Szerediad051c32004-07-02 09:22:50 +0000260 SetPageUptodate(page);
Miklos Szerediad051c32004-07-02 09:22:50 +0000261 unlock_page(page);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000262 return err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000263}
264
Miklos Szeredi58865372004-07-20 14:22:26 +0000265#ifdef KERNEL_2_6
Miklos Szeredi58865372004-07-20 14:22:26 +0000266static void read_pages_end(struct fuse_conn *fc, struct fuse_req *req)
267{
268 unsigned i;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000269 for (i = 0; i < req->num_pages; i++) {
270 struct page *page = req->pages[i];
271 if (!req->out.h.error)
272 SetPageUptodate(page);
273 unlock_page(page);
274 }
Miklos Szeredi58865372004-07-20 14:22:26 +0000275 fuse_put_request(fc, req);
276}
277
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000278static void fuse_send_readpages(struct fuse_req *req, struct file *file,
279 struct inode *inode)
Miklos Szeredi58865372004-07-20 14:22:26 +0000280{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000281 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000282 loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT;
283 size_t count = req->num_pages << PAGE_CACHE_SHIFT;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000284 fuse_read_init(req, file, inode, pos, count);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000285 req->out.page_zeroing = 1;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000286 request_send_async(fc, req, read_pages_end);
Miklos Szeredi58865372004-07-20 14:22:26 +0000287}
288
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000289struct fuse_readpages_data {
290 struct fuse_req *req;
291 struct file *file;
292 struct inode *inode;
293};
294
295static int fuse_readpages_fill(void *_data, struct page *page)
Miklos Szeredi58865372004-07-20 14:22:26 +0000296{
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000297 struct fuse_readpages_data *data = _data;
298 struct fuse_req *req = data->req;
299 struct inode *inode = data->inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000300 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000301
302 if (req->num_pages &&
Miklos Szeredi58865372004-07-20 14:22:26 +0000303 (req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000304 (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
Miklos Szeredi58865372004-07-20 14:22:26 +0000305 req->pages[req->num_pages - 1]->index + 1 != page->index)) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000306 struct fuse_conn *fc = get_fuse_conn(page->mapping->host);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000307 fuse_send_readpages(req, data->file, inode);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000308 data->req = req = fuse_get_request_nonint(fc);
Miklos Szeredi58865372004-07-20 14:22:26 +0000309 }
310 req->pages[req->num_pages] = page;
311 req->num_pages ++;
312 return 0;
313}
314
315static int fuse_readpages(struct file *file, struct address_space *mapping,
316 struct list_head *pages, unsigned nr_pages)
317{
318 struct inode *inode = mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000319 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000320 struct fuse_readpages_data data;
321
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000322 data.req = fuse_get_request_nonint(fc);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000323 data.file = file;
324 data.inode = inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000325
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000326 read_cache_pages(mapping, pages, fuse_readpages_fill, &data);
327 if (data.req->num_pages)
328 fuse_send_readpages(data.req, file, inode);
Miklos Szeredi58865372004-07-20 14:22:26 +0000329 else
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000330 fuse_put_request(fc, data.req);
Miklos Szeredi58865372004-07-20 14:22:26 +0000331
332 return 0;
333}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000334#else /* KERNEL_2_6 */
Miklos Szeredi83a07442004-11-30 18:25:20 +0000335#define FUSE_BLOCK_SHIFT 16
336#define FUSE_BLOCK_SIZE (1UL << FUSE_BLOCK_SHIFT)
337#define FUSE_BLOCK_MASK (~(FUSE_BLOCK_SIZE-1))
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000338#if (1UL << (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)) > FUSE_MAX_PAGES_PER_REQ
Miklos Szeredi83a07442004-11-30 18:25:20 +0000339#error FUSE_BLOCK_SHIFT too large
340#endif
341
342static int fuse_is_block_uptodate(struct inode *inode, unsigned start,
343 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000344{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000345 int index;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000346
Miklos Szeredi83a07442004-11-30 18:25:20 +0000347 for (index = start; index < end; index++) {
Miklos Szerediad051c32004-07-02 09:22:50 +0000348 struct page *page = find_get_page(inode->i_mapping, index);
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000349 if (!page)
350 return 0;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000351 if (!PageUptodate(page)) {
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000352 page_cache_release(page);
353 return 0;
354 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000355 page_cache_release(page);
356 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000357 return 1;
358}
359
Miklos Szeredi83a07442004-11-30 18:25:20 +0000360static void fuse_file_read_block(struct fuse_req *req, struct file *file,
361 struct inode *inode, unsigned start,
362 unsigned end)
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000363{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000364 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000365 loff_t pos;
366 size_t count;
367 int index;
368 int err = 1;
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000369 int i;
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000370
Miklos Szeredi83a07442004-11-30 18:25:20 +0000371 for (index = start; index < end; index++) {
372 struct page *page = grab_cache_page(inode->i_mapping, index);
Michael Grigoriev37b3f3b2003-11-09 15:33:24 +0000373 if (!page)
Miklos Szeredi83a07442004-11-30 18:25:20 +0000374 goto out;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000375 if (PageUptodate(page)) {
376 unlock_page(page);
377 page_cache_release(page);
378 page = NULL;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000379 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000380 req->pages[req->num_pages++] = page;
381 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000382 pos = (loff_t) start << PAGE_CACHE_SHIFT;
383 count = req->num_pages << PAGE_CACHE_SHIFT;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000384 fuse_read_init(req, file, inode, pos, count);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000385 request_send(fc, req);
386 err = req->out.h.error;
387 out:
388 for (i = 0; i < req->num_pages; i++) {
389 struct page *page = req->pages[i];
Miklos Szeredi039322d2004-12-01 18:39:12 +0000390 if (page) {
391 if (!err)
392 SetPageUptodate(page);
393 unlock_page(page);
394 page_cache_release(page);
395 }
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000396 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000397}
Miklos Szeredi36ca5562003-11-03 19:32:14 +0000398
Miklos Szeredi83a07442004-11-30 18:25:20 +0000399static int fuse_file_bigread(struct file *file, struct inode *inode,
400 loff_t pos, size_t count)
Miklos Szeredi307242f2004-01-26 11:28:44 +0000401{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000402 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000403 unsigned starti;
404 unsigned endi;
405 unsigned nexti;
406 struct fuse_req *req;
407 loff_t size = i_size_read(inode);
408 loff_t end = (pos + count + FUSE_BLOCK_SIZE - 1) & FUSE_BLOCK_MASK;
409 end = min(end, size);
410 if (end <= pos)
411 return 0;
412
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000413 starti = (pos & FUSE_BLOCK_MASK) >> PAGE_CACHE_SHIFT;
414 endi = (end + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
415
Miklos Szeredi83a07442004-11-30 18:25:20 +0000416 req = fuse_get_request(fc);
417 if (!req)
418 return -ERESTARTSYS;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000419
Miklos Szeredi83a07442004-11-30 18:25:20 +0000420 for (; starti < endi; starti = nexti) {
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000421 nexti = starti + (FUSE_BLOCK_SIZE >> PAGE_CACHE_SHIFT);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000422 nexti = min(nexti, endi);
423 if (!fuse_is_block_uptodate(inode, starti, nexti)) {
424 fuse_file_read_block(req, file, inode, starti, nexti);
425 fuse_reset_request(req);
426 }
Miklos Szeredi307242f2004-01-26 11:28:44 +0000427 }
Miklos Szeredi83a07442004-11-30 18:25:20 +0000428 fuse_put_request(fc, req);
429 return 0;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000430}
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000431#endif /* KERNEL_2_6 */
Miklos Szeredi307242f2004-01-26 11:28:44 +0000432
Miklos Szeredi039322d2004-12-01 18:39:12 +0000433static void fuse_write_init(struct fuse_req *req, struct fuse_file *ff,
434 struct inode *inode, loff_t pos, size_t count,
435 int iswritepage)
Miklos Szeredia181e612001-11-06 12:03:23 +0000436{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000437 struct fuse_write_in *inarg = &req->misc.write.in;
438
439 inarg->writepage = iswritepage;
440 inarg->fh = ff->fh;
441 inarg->offset = pos;
442 inarg->size = count;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000443 req->in.h.opcode = FUSE_WRITE;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000444 req->in.h.nodeid = get_node_id(inode);
445 if (iswritepage) {
446 req->in.h.uid = 0;
447 req->in.h.gid = 0;
448 req->in.h.pid = 0;
449 }
450 req->in.argpages = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000451 req->in.numargs = 2;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000452 req->in.args[0].size = sizeof(struct fuse_write_in);
453 req->in.args[0].value = inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000454 req->in.args[1].size = count;
Miklos Szerediad051c32004-07-02 09:22:50 +0000455 req->out.numargs = 1;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000456 req->out.args[0].size = sizeof(struct fuse_write_out);
457 req->out.args[0].value = &req->misc.write.out;
Miklos Szeredia181e612001-11-06 12:03:23 +0000458}
459
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000460static int get_write_count(struct inode *inode, struct page *page)
Miklos Szeredia181e612001-11-06 12:03:23 +0000461{
Miklos Szeredia181e612001-11-06 12:03:23 +0000462 unsigned long end_index;
Miklos Szeredid1199f82004-02-06 15:29:22 +0000463 loff_t size = i_size_read(inode);
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000464 int count;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000465
466 end_index = size >> PAGE_CACHE_SHIFT;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000467 if (page->index < end_index)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000468 count = PAGE_CACHE_SIZE;
Miklos Szeredia181e612001-11-06 12:03:23 +0000469 else {
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000470 count = size & (PAGE_CACHE_SIZE - 1);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000471 if (page->index > end_index || count == 0)
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000472 return 0;
Miklos Szeredia181e612001-11-06 12:03:23 +0000473 }
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000474 return count;
Miklos Szeredia181e612001-11-06 12:03:23 +0000475}
476
Miklos Szeredi039322d2004-12-01 18:39:12 +0000477static inline struct fuse_file *get_write_file(struct fuse_inode *fi)
478{
479 BUG_ON(list_empty(&fi->write_files));
480 return list_entry(fi->write_files.next, struct fuse_file, ff_list);
481}
482
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000483#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000484static void write_page_end(struct fuse_conn *fc, struct fuse_req *req)
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000485{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000486 struct page *page = req->pages[0];
Miklos Szeredi069c9502004-07-16 16:17:02 +0000487 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000488 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000489 if (!req->out.h.error &&
490 req->misc.write.out.size != req->in.args[1].size)
Miklos Szerediad051c32004-07-02 09:22:50 +0000491 req->out.h.error = -EPROTO;
Miklos Szerediad051c32004-07-02 09:22:50 +0000492
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000493 if (req->out.h.error) {
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000494 SetPageError(page);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000495 if (req->out.h.error == -ENOSPC)
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000496 set_bit(AS_ENOSPC, &page->mapping->flags);
497 else
498 set_bit(AS_EIO, &page->mapping->flags);
499 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000500 up_read(&fi->write_sem);
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000501 end_page_writeback(page);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000502 fuse_put_request(fc, req);
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000503}
504
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000505static int fuse_writepage(struct page *page, struct writeback_control *wbc)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000506{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000507 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000508 struct fuse_conn *fc = get_fuse_conn(inode);
509 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000510 struct fuse_req *req;
511 int err;
512
513 err = -EWOULDBLOCK;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000514 if (wbc->nonblocking)
515 req = fuse_get_request_nonblock(fc);
516 else
517 req = fuse_get_request_nonint(fc);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000518 if (req) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000519 int locked = 1;
520 if (wbc->nonblocking)
521 locked = down_read_trylock(&fi->write_sem);
522 else
523 down_read(&fi->write_sem);
524 if (locked) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000525 unsigned count = get_write_count(inode, page);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000526 loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000527 err = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000528 if (count) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000529 struct fuse_file *ff = get_write_file(fi);
530 SetPageWriteback(page);
531 fuse_write_init(req, ff, inode, pos, count, 1);
532 req->num_pages = 1;
533 req->pages[0] = page;
534 request_send_async(fc, req, write_page_end);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000535 goto out;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000536 }
537 up_read(&fi->write_sem);
538 }
539 fuse_put_request(fc, req);
540 }
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000541 if (err == -EWOULDBLOCK) {
542#ifdef KERNEL_2_6_6_PLUS
543 redirty_page_for_writepage(wbc, page);
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000544#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000545 __set_page_dirty_nobuffers(page);
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000546#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000547 err = 0;
548 }
549 out:
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000550 unlock_page(page);
551 return err;
552}
553#else
Miklos Szeredi039322d2004-12-01 18:39:12 +0000554static int fuse_writepage(struct page *page)
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000555{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000556 int err;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000557 unsigned count;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000558 struct inode *inode = page->mapping->host;
559 struct fuse_conn *fc = get_fuse_conn(inode);
560 struct fuse_inode *fi = get_fuse_inode(inode);
561 struct fuse_req *req = fuse_get_request_nonint(fc);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000562
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000563 down_read(&fi->write_sem);
564 count = get_write_count(inode, page);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000565 err = 0;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000566 if (count) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000567 struct fuse_file *ff = get_write_file(fi);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000568 loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000569
570 fuse_write_init(req, ff, inode, pos, count, 1);
571 req->num_pages = 1;
572 req->pages[0] = page;
573 request_send(fc, req);
574 err = req->out.h.error;
575 if (!err && req->misc.write.out.size != count)
576 err = -EPROTO;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000577 }
578 up_read(&fi->write_sem);
579 fuse_put_request(fc, req);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000580 if (err)
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000581 SetPageError(page);
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000582 unlock_page(page);
583 return err;
584}
585#endif
Miklos Szeredia181e612001-11-06 12:03:23 +0000586
587static int fuse_prepare_write(struct file *file, struct page *page,
588 unsigned offset, unsigned to)
589{
590 /* No op */
591 return 0;
592}
593
594static int fuse_commit_write(struct file *file, struct page *page,
595 unsigned offset, unsigned to)
596{
597 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000598 unsigned count = to - offset;
Miklos Szeredia181e612001-11-06 12:03:23 +0000599 struct inode *inode = page->mapping->host;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000600 struct fuse_file *ff = file->private_data;
601 struct fuse_conn *fc = get_fuse_conn(inode);
602 struct fuse_req *req = fuse_get_request(fc);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000603 loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000604 if (!req)
605 return -ERESTARTSYS;
Miklos Szeredia181e612001-11-06 12:03:23 +0000606
Miklos Szeredi039322d2004-12-01 18:39:12 +0000607 fuse_write_init(req, ff, inode, pos, count, 0);
608 req->num_pages = 1;
609 req->pages[0] = page;
610 req->page_offset = offset;
611 request_send(fc, req);
612 err = req->out.h.error;
613 if (!err && req->misc.write.out.size != count)
614 err = -EPROTO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000615 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000616 pos += count;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000617 if (pos > i_size_read(inode))
Miklos Szeredid1199f82004-02-06 15:29:22 +0000618 i_size_write(inode, pos);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000619
620 if (offset == 0 && to == PAGE_CACHE_SIZE) {
Miklos Szeredid66d3942004-07-24 13:47:44 +0000621#ifdef KERNEL_2_6
Miklos Szeredi069c9502004-07-16 16:17:02 +0000622 clear_page_dirty(page);
Miklos Szeredid66d3942004-07-24 13:47:44 +0000623#else
624 ClearPageDirty(page);
625#endif
Miklos Szeredi069c9502004-07-16 16:17:02 +0000626 SetPageUptodate(page);
627 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000628 }
Miklos Szeredi039322d2004-12-01 18:39:12 +0000629 fuse_put_request(fc, req);
Miklos Szeredia181e612001-11-06 12:03:23 +0000630 return err;
631}
632
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000633static void fuse_release_user_pages(struct fuse_req *req, int write)
634{
635 unsigned i;
636
637 for (i = 0; i < req->num_pages; i++) {
638 struct page *page = req->pages[i];
639 if (write) {
640#ifdef KERNEL_2_6
641 set_page_dirty_lock(page);
642#else
643 lock_page(page);
644 set_page_dirty(page);
645 unlock_page(page);
646#endif
647 }
648 page_cache_release(page);
649 }
650}
651
652static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,
653 unsigned nbytes, int write)
654{
655 unsigned long user_addr = (unsigned long) buf;
656 unsigned offset = user_addr & ~PAGE_MASK;
657 int npages;
658
659 nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
660 npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
661 npages = min(npages, FUSE_MAX_PAGES_PER_REQ);
662 npages = get_user_pages(current, current->mm, user_addr, npages, write,
663 0, req->pages, NULL);
664 if (npages < 0)
665 return npages;
666
667 req->num_pages = npages;
668 req->page_offset = offset;
669 return 0;
670}
671
672static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
673 size_t count, loff_t *ppos, int write)
Miklos Szerediad051c32004-07-02 09:22:50 +0000674{
675 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000676 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000677 struct fuse_file *ff = file->private_data;
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000678 unsigned nmax = write ? fc->max_write : fc->max_read;
Miklos Szerediad051c32004-07-02 09:22:50 +0000679 loff_t pos = *ppos;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000680 ssize_t res = 0;
681 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000682 if (!req)
683 return -ERESTARTSYS;
Miklos Szerediad051c32004-07-02 09:22:50 +0000684
Miklos Szerediad051c32004-07-02 09:22:50 +0000685 while (count) {
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000686 unsigned tmp;
687 unsigned nres;
688 size_t nbytes = min(count, nmax);
689 int err = fuse_get_user_pages(req, buf, nbytes, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000690 if (err) {
691 res = err;
Miklos Szerediad051c32004-07-02 09:22:50 +0000692 break;
693 }
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000694 tmp = (req->num_pages << PAGE_SHIFT) - req->page_offset;
695 nbytes = min(nbytes, tmp);
696 if (write)
697 fuse_write_init(req, ff, inode, pos, nbytes, 0);
698 else
699 fuse_read_init(req, file, inode, pos, nbytes);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000700 request_send(fc, req);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000701 fuse_release_user_pages(req, !write);
Miklos Szeredi039322d2004-12-01 18:39:12 +0000702 if (req->out.h.error) {
703 if (!res)
704 res = req->out.h.error;
Miklos Szerediad051c32004-07-02 09:22:50 +0000705 break;
706 }
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000707 if (write) {
708 nres = req->misc.write.out.size;
709 if (nres > nbytes) {
710 res = -EPROTO;
711 break;
712 }
713 }
714 else
715 nres = req->out.args[0].size;
716 count -= nres;
717 res += nres;
718 pos += nres;
719 buf += nres;
720 if (nres != nbytes)
Miklos Szerediad051c32004-07-02 09:22:50 +0000721 break;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000722 if (count)
723 fuse_reset_request(req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000724 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000725 fuse_put_request(fc, req);
Miklos Szerediad051c32004-07-02 09:22:50 +0000726 if (res > 0) {
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000727 if (write && pos > i_size_read(inode))
Miklos Szerediad051c32004-07-02 09:22:50 +0000728 i_size_write(inode, pos);
729 *ppos = pos;
730 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000731 return res;
732}
733
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000734static ssize_t fuse_file_read(struct file *file, char __user *buf,
735 size_t count, loff_t *ppos)
736{
737 struct inode *inode = file->f_dentry->d_inode;
738 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000739
740 if (fc->flags & FUSE_DIRECT_IO)
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000741 return fuse_direct_io(file, buf, count, ppos, 0);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000742#ifndef KERNEL_2_6
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000743 else {
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000744 if (fc->flags & FUSE_LARGE_READ) {
745 down(&inode->i_sem);
746 res = fuse_file_bigread(file, inode, *ppos, count);
747 up(&inode->i_sem);
748 if (res)
749 return res;
750 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000751 return generic_file_read(file, buf, count, ppos);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000752 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000753#else
754 else
755 return generic_file_read(file, buf, count, ppos);
756#endif
757
758}
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000759
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000760static ssize_t fuse_file_write(struct file *file, const char __user *buf,
Miklos Szerediad051c32004-07-02 09:22:50 +0000761 size_t count, loff_t *ppos)
762{
763 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000764 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000765
Miklos Szerediad051c32004-07-02 09:22:50 +0000766 if (fc->flags & FUSE_DIRECT_IO) {
767 ssize_t res;
768 down(&inode->i_sem);
Miklos Szeredi5c7e63e2004-12-01 23:31:03 +0000769 res = fuse_direct_io(file, buf, count, ppos, 1);
Miklos Szerediad051c32004-07-02 09:22:50 +0000770 up(&inode->i_sem);
771 return res;
772 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000773 else
Miklos Szerediad051c32004-07-02 09:22:50 +0000774 return generic_file_write(file, buf, count, ppos);
775}
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000776
Miklos Szerediad051c32004-07-02 09:22:50 +0000777static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
778{
779 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000780 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szerediad051c32004-07-02 09:22:50 +0000781
782 if (fc->flags & FUSE_DIRECT_IO)
783 return -ENODEV;
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000784 else {
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000785 if ((vma->vm_flags & (VM_WRITE | VM_SHARED)) ==
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000786 (VM_WRITE | VM_SHARED)) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000787 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000788 struct fuse_file *ff = file->private_data;
789
790 if (!user_mmap && current->uid != 0)
791 return -EPERM;
792
793 down_write(&fi->write_sem);
794 if (list_empty(&ff->ff_list))
795 list_add(&ff->ff_list, &fi->write_files);
796 up_write(&fi->write_sem);
797 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000798 return generic_file_mmap(file, vma);
Miklos Szeredi209f5d02004-07-24 19:56:16 +0000799 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000800}
801
Miklos Szeredi5e183482001-10-31 14:52:35 +0000802static struct file_operations fuse_file_operations = {
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000803 .read = fuse_file_read,
Miklos Szerediad051c32004-07-02 09:22:50 +0000804 .write = fuse_file_write,
805 .mmap = fuse_file_mmap,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000806 .open = fuse_open,
Miklos Szeredie2e4ac22004-05-18 08:45:28 +0000807 .flush = fuse_flush,
Miklos Szeredi89b86af2004-02-06 17:02:08 +0000808 .release = fuse_release,
809 .fsync = fuse_fsync,
810#ifdef KERNEL_2_6
811 .sendfile = generic_file_sendfile,
812#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000813};
814
815static struct address_space_operations fuse_file_aops = {
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000816 .readpage = fuse_readpage,
817 .writepage = fuse_writepage,
818 .prepare_write = fuse_prepare_write,
819 .commit_write = fuse_commit_write,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000820#ifdef KERNEL_2_6
Miklos Szeredi58865372004-07-20 14:22:26 +0000821 .readpages = fuse_readpages,
Miklos Szeredi84ba0f42004-07-18 11:32:59 +0000822 .set_page_dirty = __set_page_dirty_nobuffers,
Miklos Szeredi015fe702004-07-12 11:52:24 +0000823#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000824};
825
826void fuse_init_file_inode(struct inode *inode)
827{
828 inode->i_fop = &fuse_file_operations;
829 inode->i_data.a_ops = &fuse_file_aops;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000830}