diff options
Diffstat (limited to 'fs/fuse/dir.c')
| -rw-r--r-- | fs/fuse/dir.c | 99 |
1 files changed, 67 insertions, 32 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, |
