diff options
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 83 |
1 files changed, 50 insertions, 33 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 63d2980df5c9..a7ef5e716f3c 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -113,6 +113,14 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) | |||
113 | return err; | 113 | return err; |
114 | } | 114 | } |
115 | 115 | ||
116 | /* Special case for failed iget in CREATE */ | ||
117 | static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) | ||
118 | { | ||
119 | u64 nodeid = req->in.h.nodeid; | ||
120 | fuse_reset_request(req); | ||
121 | fuse_send_forget(fc, req, nodeid, 1); | ||
122 | } | ||
123 | |||
116 | void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, | 124 | void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, |
117 | u64 nodeid, struct inode *inode, int flags, int isdir) | 125 | u64 nodeid, struct inode *inode, int flags, int isdir) |
118 | { | 126 | { |
@@ -128,6 +136,8 @@ void fuse_send_release(struct fuse_conn *fc, struct fuse_file *ff, | |||
128 | req->in.args[0].size = sizeof(struct fuse_release_in); | 136 | req->in.args[0].size = sizeof(struct fuse_release_in); |
129 | req->in.args[0].value = inarg; | 137 | req->in.args[0].value = inarg; |
130 | request_send_background(fc, req); | 138 | request_send_background(fc, req); |
139 | if (!inode) | ||
140 | req->end = fuse_release_end; | ||
131 | kfree(ff); | 141 | kfree(ff); |
132 | } | 142 | } |
133 | 143 | ||
@@ -240,38 +250,35 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) | |||
240 | return fuse_fsync_common(file, de, datasync, 0); | 250 | return fuse_fsync_common(file, de, datasync, 0); |
241 | } | 251 | } |
242 | 252 | ||
243 | size_t fuse_send_read_common(struct fuse_req *req, struct file *file, | 253 | void fuse_read_fill(struct fuse_req *req, struct file *file, |
244 | struct inode *inode, loff_t pos, size_t count, | 254 | struct inode *inode, loff_t pos, size_t count, int opcode) |
245 | int isdir) | ||
246 | { | 255 | { |
247 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
248 | struct fuse_file *ff = file->private_data; | 256 | struct fuse_file *ff = file->private_data; |
249 | struct fuse_read_in inarg; | 257 | struct fuse_read_in *inarg = &req->misc.read_in; |
250 | 258 | ||
251 | memset(&inarg, 0, sizeof(struct fuse_read_in)); | 259 | inarg->fh = ff->fh; |
252 | inarg.fh = ff->fh; | 260 | inarg->offset = pos; |
253 | inarg.offset = pos; | 261 | inarg->size = count; |
254 | inarg.size = count; | 262 | req->in.h.opcode = opcode; |
255 | req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ; | ||
256 | req->in.h.nodeid = get_node_id(inode); | 263 | req->in.h.nodeid = get_node_id(inode); |
257 | req->inode = inode; | 264 | req->inode = inode; |
258 | req->file = file; | 265 | req->file = file; |
259 | req->in.numargs = 1; | 266 | req->in.numargs = 1; |
260 | req->in.args[0].size = sizeof(struct fuse_read_in); | 267 | req->in.args[0].size = sizeof(struct fuse_read_in); |
261 | req->in.args[0].value = &inarg; | 268 | req->in.args[0].value = inarg; |
262 | req->out.argpages = 1; | 269 | req->out.argpages = 1; |
263 | req->out.argvar = 1; | 270 | req->out.argvar = 1; |
264 | req->out.numargs = 1; | 271 | req->out.numargs = 1; |
265 | req->out.args[0].size = count; | 272 | req->out.args[0].size = count; |
266 | request_send(fc, req); | ||
267 | return req->out.args[0].size; | ||
268 | } | 273 | } |
269 | 274 | ||
270 | static inline size_t fuse_send_read(struct fuse_req *req, struct file *file, | 275 | static size_t fuse_send_read(struct fuse_req *req, struct file *file, |
271 | struct inode *inode, loff_t pos, | 276 | struct inode *inode, loff_t pos, size_t count) |
272 | size_t count) | ||
273 | { | 277 | { |
274 | return fuse_send_read_common(req, file, inode, pos, count, 0); | 278 | struct fuse_conn *fc = get_fuse_conn(inode); |
279 | fuse_read_fill(req, file, inode, pos, count, FUSE_READ); | ||
280 | request_send(fc, req); | ||
281 | return req->out.args[0].size; | ||
275 | } | 282 | } |
276 | 283 | ||
277 | static int fuse_readpage(struct file *file, struct page *page) | 284 | static int fuse_readpage(struct file *file, struct page *page) |
@@ -304,21 +311,33 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
304 | return err; | 311 | return err; |
305 | } | 312 | } |
306 | 313 | ||
307 | static int fuse_send_readpages(struct fuse_req *req, struct file *file, | 314 | static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) |
308 | struct inode *inode) | ||
309 | { | 315 | { |
310 | loff_t pos = page_offset(req->pages[0]); | 316 | int i; |
311 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; | 317 | |
312 | unsigned i; | 318 | fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */ |
313 | req->out.page_zeroing = 1; | 319 | |
314 | fuse_send_read(req, file, inode, pos, count); | ||
315 | for (i = 0; i < req->num_pages; i++) { | 320 | for (i = 0; i < req->num_pages; i++) { |
316 | struct page *page = req->pages[i]; | 321 | struct page *page = req->pages[i]; |
317 | if (!req->out.h.error) | 322 | if (!req->out.h.error) |
318 | SetPageUptodate(page); | 323 | SetPageUptodate(page); |
324 | else | ||
325 | SetPageError(page); | ||
319 | unlock_page(page); | 326 | unlock_page(page); |
320 | } | 327 | } |
321 | return req->out.h.error; | 328 | fuse_put_request(fc, req); |
329 | } | ||
330 | |||
331 | static void fuse_send_readpages(struct fuse_req *req, struct file *file, | ||
332 | struct inode *inode) | ||
333 | { | ||
334 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
335 | loff_t pos = page_offset(req->pages[0]); | ||
336 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; | ||
337 | req->out.page_zeroing = 1; | ||
338 | req->end = fuse_readpages_end; | ||
339 | fuse_read_fill(req, file, inode, pos, count, FUSE_READ); | ||
340 | request_send_background(fc, req); | ||
322 | } | 341 | } |
323 | 342 | ||
324 | struct fuse_readpages_data { | 343 | struct fuse_readpages_data { |
@@ -338,12 +357,12 @@ static int fuse_readpages_fill(void *_data, struct page *page) | |||
338 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || | 357 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || |
339 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || | 358 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || |
340 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { | 359 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { |
341 | int err = fuse_send_readpages(req, data->file, inode); | 360 | fuse_send_readpages(req, data->file, inode); |
342 | if (err) { | 361 | data->req = req = fuse_get_request(fc); |
362 | if (!req) { | ||
343 | unlock_page(page); | 363 | unlock_page(page); |
344 | return err; | 364 | return -EINTR; |
345 | } | 365 | } |
346 | fuse_reset_request(req); | ||
347 | } | 366 | } |
348 | req->pages[req->num_pages] = page; | 367 | req->pages[req->num_pages] = page; |
349 | req->num_pages ++; | 368 | req->num_pages ++; |
@@ -368,10 +387,8 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
368 | return -EINTR; | 387 | return -EINTR; |
369 | 388 | ||
370 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); | 389 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); |
371 | if (!err && data.req->num_pages) | 390 | if (!err) |
372 | err = fuse_send_readpages(data.req, file, inode); | 391 | fuse_send_readpages(data.req, file, inode); |
373 | fuse_put_request(fc, data.req); | ||
374 | fuse_invalidate_attr(inode); /* atime changed */ | ||
375 | return err; | 392 | return err; |
376 | } | 393 | } |
377 | 394 | ||