diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 99 | ||||
-rw-r--r-- | fs/fuse/file.c | 4 |
2 files changed, 69 insertions, 34 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 334e0b18a014..8964cf3999b2 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -154,7 +154,7 @@ u64 fuse_get_attr_version(struct fuse_conn *fc) | |||
154 | * the lookup once more. If the lookup results in the same inode, | 154 | * the lookup once more. If the lookup results in the same inode, |
155 | * then refresh the attributes, timeouts and mark the dentry valid. | 155 | * then refresh the attributes, timeouts and mark the dentry valid. |
156 | */ | 156 | */ |
157 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | 157 | static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) |
158 | { | 158 | { |
159 | struct inode *inode; | 159 | struct inode *inode; |
160 | 160 | ||
@@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
174 | if (!inode) | 174 | if (!inode) |
175 | return 0; | 175 | return 0; |
176 | 176 | ||
177 | if (nd && (nd->flags & LOOKUP_RCU)) | 177 | if (flags & LOOKUP_RCU) |
178 | return -ECHILD; | 178 | return -ECHILD; |
179 | 179 | ||
180 | fc = get_fuse_conn(inode); | 180 | fc = get_fuse_conn(inode); |
@@ -249,7 +249,7 @@ static struct dentry *fuse_d_add_directory(struct dentry *entry, | |||
249 | /* This tries to shrink the subtree below alias */ | 249 | /* This tries to shrink the subtree below alias */ |
250 | fuse_invalidate_entry(alias); | 250 | fuse_invalidate_entry(alias); |
251 | dput(alias); | 251 | dput(alias); |
252 | if (!list_empty(&inode->i_dentry)) | 252 | if (!hlist_empty(&inode->i_dentry)) |
253 | return ERR_PTR(-EBUSY); | 253 | return ERR_PTR(-EBUSY); |
254 | } else { | 254 | } else { |
255 | dput(alias); | 255 | dput(alias); |
@@ -316,7 +316,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
316 | } | 316 | } |
317 | 317 | ||
318 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 318 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
319 | struct nameidata *nd) | 319 | unsigned int flags) |
320 | { | 320 | { |
321 | int err; | 321 | int err; |
322 | struct fuse_entry_out outarg; | 322 | struct fuse_entry_out outarg; |
@@ -370,7 +370,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
370 | * 'mknod' + 'open' requests. | 370 | * 'mknod' + 'open' requests. |
371 | */ | 371 | */ |
372 | static int fuse_create_open(struct inode *dir, struct dentry *entry, | 372 | static int fuse_create_open(struct inode *dir, struct dentry *entry, |
373 | umode_t mode, struct nameidata *nd) | 373 | struct file *file, unsigned flags, |
374 | umode_t mode, int *opened) | ||
374 | { | 375 | { |
375 | int err; | 376 | int err; |
376 | struct inode *inode; | 377 | struct inode *inode; |
@@ -381,15 +382,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
381 | struct fuse_open_out outopen; | 382 | struct fuse_open_out outopen; |
382 | struct fuse_entry_out outentry; | 383 | struct fuse_entry_out outentry; |
383 | struct fuse_file *ff; | 384 | struct fuse_file *ff; |
384 | struct file *file; | ||
385 | int flags = nd->intent.open.flags; | ||
386 | |||
387 | if (fc->no_create) | ||
388 | return -ENOSYS; | ||
389 | 385 | ||
390 | forget = fuse_alloc_forget(); | 386 | forget = fuse_alloc_forget(); |
387 | err = -ENOMEM; | ||
391 | if (!forget) | 388 | if (!forget) |
392 | return -ENOMEM; | 389 | goto out_err; |
393 | 390 | ||
394 | req = fuse_get_req(fc); | 391 | req = fuse_get_req(fc); |
395 | err = PTR_ERR(req); | 392 | err = PTR_ERR(req); |
@@ -428,11 +425,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
428 | req->out.args[1].value = &outopen; | 425 | req->out.args[1].value = &outopen; |
429 | fuse_request_send(fc, req); | 426 | fuse_request_send(fc, req); |
430 | err = req->out.h.error; | 427 | err = req->out.h.error; |
431 | if (err) { | 428 | if (err) |
432 | if (err == -ENOSYS) | ||
433 | fc->no_create = 1; | ||
434 | goto out_free_ff; | 429 | goto out_free_ff; |
435 | } | ||
436 | 430 | ||
437 | err = -EIO; | 431 | err = -EIO; |
438 | if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) | 432 | if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) |
@@ -448,28 +442,74 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, | |||
448 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 442 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
449 | fuse_sync_release(ff, flags); | 443 | fuse_sync_release(ff, flags); |
450 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); | 444 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); |
451 | return -ENOMEM; | 445 | err = -ENOMEM; |
446 | goto out_err; | ||
452 | } | 447 | } |
453 | kfree(forget); | 448 | kfree(forget); |
454 | d_instantiate(entry, inode); | 449 | d_instantiate(entry, inode); |
455 | fuse_change_entry_timeout(entry, &outentry); | 450 | fuse_change_entry_timeout(entry, &outentry); |
456 | fuse_invalidate_attr(dir); | 451 | fuse_invalidate_attr(dir); |
457 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | 452 | err = finish_open(file, entry, generic_file_open, opened); |
458 | if (IS_ERR(file)) { | 453 | if (err) { |
459 | fuse_sync_release(ff, flags); | 454 | fuse_sync_release(ff, flags); |
460 | return PTR_ERR(file); | 455 | } else { |
456 | file->private_data = fuse_file_get(ff); | ||
457 | fuse_finish_open(inode, file); | ||
461 | } | 458 | } |
462 | file->private_data = fuse_file_get(ff); | 459 | return err; |
463 | fuse_finish_open(inode, file); | ||
464 | return 0; | ||
465 | 460 | ||
466 | out_free_ff: | 461 | out_free_ff: |
467 | fuse_file_free(ff); | 462 | fuse_file_free(ff); |
468 | out_put_request: | 463 | out_put_request: |
469 | fuse_put_request(fc, req); | 464 | fuse_put_request(fc, req); |
470 | out_put_forget_req: | 465 | out_put_forget_req: |
471 | kfree(forget); | 466 | kfree(forget); |
467 | out_err: | ||
468 | return err; | ||
469 | } | ||
470 | |||
471 | static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t); | ||
472 | static int fuse_atomic_open(struct inode *dir, struct dentry *entry, | ||
473 | struct file *file, unsigned flags, | ||
474 | umode_t mode, int *opened) | ||
475 | { | ||
476 | int err; | ||
477 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
478 | struct dentry *res = NULL; | ||
479 | |||
480 | if (d_unhashed(entry)) { | ||
481 | res = fuse_lookup(dir, entry, 0); | ||
482 | if (IS_ERR(res)) | ||
483 | return PTR_ERR(res); | ||
484 | |||
485 | if (res) | ||
486 | entry = res; | ||
487 | } | ||
488 | |||
489 | if (!(flags & O_CREAT) || entry->d_inode) | ||
490 | goto no_open; | ||
491 | |||
492 | /* Only creates */ | ||
493 | *opened |= FILE_CREATED; | ||
494 | |||
495 | if (fc->no_create) | ||
496 | goto mknod; | ||
497 | |||
498 | err = fuse_create_open(dir, entry, file, flags, mode, opened); | ||
499 | if (err == -ENOSYS) { | ||
500 | fc->no_create = 1; | ||
501 | goto mknod; | ||
502 | } | ||
503 | out_dput: | ||
504 | dput(res); | ||
472 | return err; | 505 | return err; |
506 | |||
507 | mknod: | ||
508 | err = fuse_mknod(dir, entry, mode, 0); | ||
509 | if (err) | ||
510 | goto out_dput; | ||
511 | no_open: | ||
512 | return finish_no_open(file, res); | ||
473 | } | 513 | } |
474 | 514 | ||
475 | /* | 515 | /* |
@@ -571,14 +611,8 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode, | |||
571 | } | 611 | } |
572 | 612 | ||
573 | static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, | 613 | static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, |
574 | struct nameidata *nd) | 614 | bool excl) |
575 | { | 615 | { |
576 | if (nd) { | ||
577 | int err = fuse_create_open(dir, entry, mode, nd); | ||
578 | if (err != -ENOSYS) | ||
579 | return err; | ||
580 | /* Fall back on mknod */ | ||
581 | } | ||
582 | return fuse_mknod(dir, entry, mode, 0); | 616 | return fuse_mknod(dir, entry, mode, 0); |
583 | } | 617 | } |
584 | 618 | ||
@@ -1646,6 +1680,7 @@ static const struct inode_operations fuse_dir_inode_operations = { | |||
1646 | .link = fuse_link, | 1680 | .link = fuse_link, |
1647 | .setattr = fuse_setattr, | 1681 | .setattr = fuse_setattr, |
1648 | .create = fuse_create, | 1682 | .create = fuse_create, |
1683 | .atomic_open = fuse_atomic_open, | ||
1649 | .mknod = fuse_mknod, | 1684 | .mknod = fuse_mknod, |
1650 | .permission = fuse_permission, | 1685 | .permission = fuse_permission, |
1651 | .getattr = fuse_getattr, | 1686 | .getattr = fuse_getattr, |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2eed3acfb6a6..aba15f1b7ad2 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -947,9 +947,8 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
947 | return err; | 947 | return err; |
948 | 948 | ||
949 | count = ocount; | 949 | count = ocount; |
950 | 950 | sb_start_write(inode->i_sb); | |
951 | mutex_lock(&inode->i_mutex); | 951 | mutex_lock(&inode->i_mutex); |
952 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
953 | 952 | ||
954 | /* We can write back this queue in page reclaim */ | 953 | /* We can write back this queue in page reclaim */ |
955 | current->backing_dev_info = mapping->backing_dev_info; | 954 | current->backing_dev_info = mapping->backing_dev_info; |
@@ -1007,6 +1006,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
1007 | out: | 1006 | out: |
1008 | current->backing_dev_info = NULL; | 1007 | current->backing_dev_info = NULL; |
1009 | mutex_unlock(&inode->i_mutex); | 1008 | mutex_unlock(&inode->i_mutex); |
1009 | sb_end_write(inode->i_sb); | ||
1010 | 1010 | ||
1011 | return written ? written : err; | 1011 | return written ? written : err; |
1012 | } | 1012 | } |