diff options
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 134 |
1 files changed, 88 insertions, 46 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2ca86141d13a..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 | ||
@@ -163,6 +173,9 @@ static int fuse_flush(struct file *file) | |||
163 | struct fuse_flush_in inarg; | 173 | struct fuse_flush_in inarg; |
164 | int err; | 174 | int err; |
165 | 175 | ||
176 | if (is_bad_inode(inode)) | ||
177 | return -EIO; | ||
178 | |||
166 | if (fc->no_flush) | 179 | if (fc->no_flush) |
167 | return 0; | 180 | return 0; |
168 | 181 | ||
@@ -199,6 +212,9 @@ int fuse_fsync_common(struct file *file, struct dentry *de, int datasync, | |||
199 | struct fuse_fsync_in inarg; | 212 | struct fuse_fsync_in inarg; |
200 | int err; | 213 | int err; |
201 | 214 | ||
215 | if (is_bad_inode(inode)) | ||
216 | return -EIO; | ||
217 | |||
202 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) | 218 | if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) |
203 | return 0; | 219 | return 0; |
204 | 220 | ||
@@ -234,54 +250,57 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) | |||
234 | return fuse_fsync_common(file, de, datasync, 0); | 250 | return fuse_fsync_common(file, de, datasync, 0); |
235 | } | 251 | } |
236 | 252 | ||
237 | 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, |
238 | struct inode *inode, loff_t pos, size_t count, | 254 | struct inode *inode, loff_t pos, size_t count, int opcode) |
239 | int isdir) | ||
240 | { | 255 | { |
241 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
242 | struct fuse_file *ff = file->private_data; | 256 | struct fuse_file *ff = file->private_data; |
243 | struct fuse_read_in inarg; | 257 | struct fuse_read_in *inarg = &req->misc.read_in; |
244 | 258 | ||
245 | memset(&inarg, 0, sizeof(struct fuse_read_in)); | 259 | inarg->fh = ff->fh; |
246 | inarg.fh = ff->fh; | 260 | inarg->offset = pos; |
247 | inarg.offset = pos; | 261 | inarg->size = count; |
248 | inarg.size = count; | 262 | req->in.h.opcode = opcode; |
249 | req->in.h.opcode = isdir ? FUSE_READDIR : FUSE_READ; | ||
250 | req->in.h.nodeid = get_node_id(inode); | 263 | req->in.h.nodeid = get_node_id(inode); |
251 | req->inode = inode; | 264 | req->inode = inode; |
252 | req->file = file; | 265 | req->file = file; |
253 | req->in.numargs = 1; | 266 | req->in.numargs = 1; |
254 | req->in.args[0].size = sizeof(struct fuse_read_in); | 267 | req->in.args[0].size = sizeof(struct fuse_read_in); |
255 | req->in.args[0].value = &inarg; | 268 | req->in.args[0].value = inarg; |
256 | req->out.argpages = 1; | 269 | req->out.argpages = 1; |
257 | req->out.argvar = 1; | 270 | req->out.argvar = 1; |
258 | req->out.numargs = 1; | 271 | req->out.numargs = 1; |
259 | req->out.args[0].size = count; | 272 | req->out.args[0].size = count; |
260 | request_send(fc, req); | ||
261 | return req->out.args[0].size; | ||
262 | } | 273 | } |
263 | 274 | ||
264 | 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, |
265 | struct inode *inode, loff_t pos, | 276 | struct inode *inode, loff_t pos, size_t count) |
266 | size_t count) | ||
267 | { | 277 | { |
268 | 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; | ||
269 | } | 282 | } |
270 | 283 | ||
271 | static int fuse_readpage(struct file *file, struct page *page) | 284 | static int fuse_readpage(struct file *file, struct page *page) |
272 | { | 285 | { |
273 | struct inode *inode = page->mapping->host; | 286 | struct inode *inode = page->mapping->host; |
274 | struct fuse_conn *fc = get_fuse_conn(inode); | 287 | struct fuse_conn *fc = get_fuse_conn(inode); |
275 | loff_t pos = (loff_t) page->index << PAGE_CACHE_SHIFT; | 288 | struct fuse_req *req; |
276 | struct fuse_req *req = fuse_get_request(fc); | 289 | int err; |
277 | int err = -EINTR; | 290 | |
291 | err = -EIO; | ||
292 | if (is_bad_inode(inode)) | ||
293 | goto out; | ||
294 | |||
295 | err = -EINTR; | ||
296 | req = fuse_get_request(fc); | ||
278 | if (!req) | 297 | if (!req) |
279 | goto out; | 298 | goto out; |
280 | 299 | ||
281 | req->out.page_zeroing = 1; | 300 | req->out.page_zeroing = 1; |
282 | req->num_pages = 1; | 301 | req->num_pages = 1; |
283 | req->pages[0] = page; | 302 | req->pages[0] = page; |
284 | fuse_send_read(req, file, inode, pos, PAGE_CACHE_SIZE); | 303 | fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE); |
285 | err = req->out.h.error; | 304 | err = req->out.h.error; |
286 | fuse_put_request(fc, req); | 305 | fuse_put_request(fc, req); |
287 | if (!err) | 306 | if (!err) |
@@ -292,21 +311,33 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
292 | return err; | 311 | return err; |
293 | } | 312 | } |
294 | 313 | ||
295 | 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) |
296 | struct inode *inode) | ||
297 | { | 315 | { |
298 | loff_t pos = (loff_t) req->pages[0]->index << PAGE_CACHE_SHIFT; | 316 | int i; |
299 | size_t count = req->num_pages << PAGE_CACHE_SHIFT; | 317 | |
300 | unsigned i; | 318 | fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */ |
301 | req->out.page_zeroing = 1; | 319 | |
302 | fuse_send_read(req, file, inode, pos, count); | ||
303 | for (i = 0; i < req->num_pages; i++) { | 320 | for (i = 0; i < req->num_pages; i++) { |
304 | struct page *page = req->pages[i]; | 321 | struct page *page = req->pages[i]; |
305 | if (!req->out.h.error) | 322 | if (!req->out.h.error) |
306 | SetPageUptodate(page); | 323 | SetPageUptodate(page); |
324 | else | ||
325 | SetPageError(page); | ||
307 | unlock_page(page); | 326 | unlock_page(page); |
308 | } | 327 | } |
309 | 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); | ||
310 | } | 341 | } |
311 | 342 | ||
312 | struct fuse_readpages_data { | 343 | struct fuse_readpages_data { |
@@ -326,12 +357,12 @@ static int fuse_readpages_fill(void *_data, struct page *page) | |||
326 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || | 357 | (req->num_pages == FUSE_MAX_PAGES_PER_REQ || |
327 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || | 358 | (req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read || |
328 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { | 359 | req->pages[req->num_pages - 1]->index + 1 != page->index)) { |
329 | int err = fuse_send_readpages(req, data->file, inode); | 360 | fuse_send_readpages(req, data->file, inode); |
330 | if (err) { | 361 | data->req = req = fuse_get_request(fc); |
362 | if (!req) { | ||
331 | unlock_page(page); | 363 | unlock_page(page); |
332 | return err; | 364 | return -EINTR; |
333 | } | 365 | } |
334 | fuse_reset_request(req); | ||
335 | } | 366 | } |
336 | req->pages[req->num_pages] = page; | 367 | req->pages[req->num_pages] = page; |
337 | req->num_pages ++; | 368 | req->num_pages ++; |
@@ -345,6 +376,10 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
345 | struct fuse_conn *fc = get_fuse_conn(inode); | 376 | struct fuse_conn *fc = get_fuse_conn(inode); |
346 | struct fuse_readpages_data data; | 377 | struct fuse_readpages_data data; |
347 | int err; | 378 | int err; |
379 | |||
380 | if (is_bad_inode(inode)) | ||
381 | return -EIO; | ||
382 | |||
348 | data.file = file; | 383 | data.file = file; |
349 | data.inode = inode; | 384 | data.inode = inode; |
350 | data.req = fuse_get_request(fc); | 385 | data.req = fuse_get_request(fc); |
@@ -352,10 +387,8 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
352 | return -EINTR; | 387 | return -EINTR; |
353 | 388 | ||
354 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); | 389 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); |
355 | if (!err && data.req->num_pages) | 390 | if (!err) |
356 | err = fuse_send_readpages(data.req, file, inode); | 391 | fuse_send_readpages(data.req, file, inode); |
357 | fuse_put_request(fc, data.req); | ||
358 | fuse_invalidate_attr(inode); /* atime changed */ | ||
359 | return err; | 392 | return err; |
360 | } | 393 | } |
361 | 394 | ||
@@ -402,8 +435,13 @@ static int fuse_commit_write(struct file *file, struct page *page, | |||
402 | unsigned count = to - offset; | 435 | unsigned count = to - offset; |
403 | struct inode *inode = page->mapping->host; | 436 | struct inode *inode = page->mapping->host; |
404 | struct fuse_conn *fc = get_fuse_conn(inode); | 437 | struct fuse_conn *fc = get_fuse_conn(inode); |
405 | loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + offset; | 438 | loff_t pos = page_offset(page) + offset; |
406 | struct fuse_req *req = fuse_get_request(fc); | 439 | struct fuse_req *req; |
440 | |||
441 | if (is_bad_inode(inode)) | ||
442 | return -EIO; | ||
443 | |||
444 | req = fuse_get_request(fc); | ||
407 | if (!req) | 445 | if (!req) |
408 | return -EINTR; | 446 | return -EINTR; |
409 | 447 | ||
@@ -454,7 +492,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
454 | 492 | ||
455 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | 493 | nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); |
456 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; | 494 | npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT; |
457 | npages = min(npages, FUSE_MAX_PAGES_PER_REQ); | 495 | npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ); |
458 | down_read(¤t->mm->mmap_sem); | 496 | down_read(¤t->mm->mmap_sem); |
459 | npages = get_user_pages(current, current->mm, user_addr, npages, write, | 497 | npages = get_user_pages(current, current->mm, user_addr, npages, write, |
460 | 0, req->pages, NULL); | 498 | 0, req->pages, NULL); |
@@ -475,12 +513,16 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
475 | size_t nmax = write ? fc->max_write : fc->max_read; | 513 | size_t nmax = write ? fc->max_write : fc->max_read; |
476 | loff_t pos = *ppos; | 514 | loff_t pos = *ppos; |
477 | ssize_t res = 0; | 515 | ssize_t res = 0; |
478 | struct fuse_req *req = fuse_get_request(fc); | 516 | struct fuse_req *req; |
517 | |||
518 | if (is_bad_inode(inode)) | ||
519 | return -EIO; | ||
520 | |||
521 | req = fuse_get_request(fc); | ||
479 | if (!req) | 522 | if (!req) |
480 | return -EINTR; | 523 | return -EINTR; |
481 | 524 | ||
482 | while (count) { | 525 | while (count) { |
483 | size_t tmp; | ||
484 | size_t nres; | 526 | size_t nres; |
485 | size_t nbytes = min(count, nmax); | 527 | size_t nbytes = min(count, nmax); |
486 | int err = fuse_get_user_pages(req, buf, nbytes, !write); | 528 | int err = fuse_get_user_pages(req, buf, nbytes, !write); |
@@ -488,8 +530,8 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
488 | res = err; | 530 | res = err; |
489 | break; | 531 | break; |
490 | } | 532 | } |
491 | tmp = (req->num_pages << PAGE_SHIFT) - req->page_offset; | 533 | nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset; |
492 | nbytes = min(nbytes, tmp); | 534 | nbytes = min(count, nbytes); |
493 | if (write) | 535 | if (write) |
494 | nres = fuse_send_write(req, file, inode, pos, nbytes); | 536 | nres = fuse_send_write(req, file, inode, pos, nbytes); |
495 | else | 537 | else |
@@ -535,9 +577,9 @@ static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | |||
535 | struct inode *inode = file->f_dentry->d_inode; | 577 | struct inode *inode = file->f_dentry->d_inode; |
536 | ssize_t res; | 578 | ssize_t res; |
537 | /* Don't allow parallel writes to the same file */ | 579 | /* Don't allow parallel writes to the same file */ |
538 | down(&inode->i_sem); | 580 | mutex_lock(&inode->i_mutex); |
539 | res = fuse_direct_io(file, buf, count, ppos, 1); | 581 | res = fuse_direct_io(file, buf, count, ppos, 1); |
540 | up(&inode->i_sem); | 582 | mutex_unlock(&inode->i_mutex); |
541 | return res; | 583 | return res; |
542 | } | 584 | } |
543 | 585 | ||