aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2012-06-05 09:10:22 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-14 08:33:14 -0400
commitc8ccbe032feb127a977c66865cb63d72d9a6e08b (patch)
treec8f4ebff9ae19a49634a8ade2cf3d3372091e970 /fs
parenteda72afb9ef9f45941fb09260c0f268ff81ec40d (diff)
fuse: implement i_op->atomic_open()
Add an ->atomic_open implementation which replaces the atomic open+create operation implemented via ->create. No functionality is changed. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dir.c94
1 files changed, 67 insertions, 27 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index f7543f72897e..e42442f1da16 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -369,8 +369,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
369 * If the filesystem doesn't support this, then fall back to separate 369 * If the filesystem doesn't support this, then fall back to separate
370 * 'mknod' + 'open' requests. 370 * 'mknod' + 'open' requests.
371 */ 371 */
372static int fuse_create_open(struct inode *dir, struct dentry *entry, 372static struct file *fuse_create_open(struct inode *dir, struct dentry *entry,
373 umode_t mode, struct nameidata *nd) 373 struct opendata *od, unsigned flags,
374 umode_t mode)
374{ 375{
375 int err; 376 int err;
376 struct inode *inode; 377 struct inode *inode;
@@ -382,14 +383,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
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 struct file *file;
385 int flags = nd->intent.open.flags;
386
387 if (fc->no_create)
388 return -ENOSYS;
389 386
390 forget = fuse_alloc_forget(); 387 forget = fuse_alloc_forget();
388 err = -ENOMEM;
391 if (!forget) 389 if (!forget)
392 return -ENOMEM; 390 goto out_err;
393 391
394 req = fuse_get_req(fc); 392 req = fuse_get_req(fc);
395 err = PTR_ERR(req); 393 err = PTR_ERR(req);
@@ -428,11 +426,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
428 req->out.args[1].value = &outopen; 426 req->out.args[1].value = &outopen;
429 fuse_request_send(fc, req); 427 fuse_request_send(fc, req);
430 err = req->out.h.error; 428 err = req->out.h.error;
431 if (err) { 429 if (err)
432 if (err == -ENOSYS)
433 fc->no_create = 1;
434 goto out_free_ff; 430 goto out_free_ff;
435 }
436 431
437 err = -EIO; 432 err = -EIO;
438 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) 433 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
@@ -448,28 +443,78 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
448 flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 443 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
449 fuse_sync_release(ff, flags); 444 fuse_sync_release(ff, flags);
450 fuse_queue_forget(fc, forget, outentry.nodeid, 1); 445 fuse_queue_forget(fc, forget, outentry.nodeid, 1);
451 return -ENOMEM; 446 err = -ENOMEM;
447 goto out_err;
452 } 448 }
453 kfree(forget); 449 kfree(forget);
454 d_instantiate(entry, inode); 450 d_instantiate(entry, inode);
455 fuse_change_entry_timeout(entry, &outentry); 451 fuse_change_entry_timeout(entry, &outentry);
456 fuse_invalidate_attr(dir); 452 fuse_invalidate_attr(dir);
457 file = lookup_instantiate_filp(nd, entry, generic_file_open); 453 file = finish_open(od, entry, generic_file_open);
458 if (IS_ERR(file)) { 454 if (IS_ERR(file)) {
459 fuse_sync_release(ff, flags); 455 fuse_sync_release(ff, flags);
460 return PTR_ERR(file); 456 } else {
457 file->private_data = fuse_file_get(ff);
458 fuse_finish_open(inode, file);
461 } 459 }
462 file->private_data = fuse_file_get(ff); 460 return file;
463 fuse_finish_open(inode, file);
464 return 0;
465 461
466 out_free_ff: 462out_free_ff:
467 fuse_file_free(ff); 463 fuse_file_free(ff);
468 out_put_request: 464out_put_request:
469 fuse_put_request(fc, req); 465 fuse_put_request(fc, req);
470 out_put_forget_req: 466out_put_forget_req:
471 kfree(forget); 467 kfree(forget);
472 return err; 468out_err:
469 return ERR_PTR(err);
470}
471
472static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
473static struct file *fuse_atomic_open(struct inode *dir, struct dentry *entry,
474 struct opendata *od, unsigned flags,
475 umode_t mode, bool *created)
476{
477 int err;
478 struct fuse_conn *fc = get_fuse_conn(dir);
479 struct file *file;
480 struct dentry *res = NULL;
481
482 if (d_unhashed(entry)) {
483 res = fuse_lookup(dir, entry, NULL);
484 if (IS_ERR(res))
485 return ERR_CAST(res);
486
487 if (res)
488 entry = res;
489 }
490
491 if (!(flags & O_CREAT) || entry->d_inode)
492 goto no_open;
493
494 /* Only creates */
495 *created = true;
496
497 if (fc->no_create)
498 goto mknod;
499
500 file = fuse_create_open(dir, entry, od, flags, mode);
501 if (PTR_ERR(file) == -ENOSYS) {
502 fc->no_create = 1;
503 goto mknod;
504 }
505out_dput:
506 dput(res);
507 return file;
508
509mknod:
510 err = fuse_mknod(dir, entry, mode, 0);
511 if (err) {
512 file = ERR_PTR(err);
513 goto out_dput;
514 }
515no_open:
516 finish_no_open(od, res);
517 return NULL;
473} 518}
474 519
475/* 520/*
@@ -573,12 +618,6 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
573static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode, 618static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
574 struct nameidata *nd) 619 struct nameidata *nd)
575{ 620{
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); 621 return fuse_mknod(dir, entry, mode, 0);
583} 622}
584 623
@@ -1646,6 +1685,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
1646 .link = fuse_link, 1685 .link = fuse_link,
1647 .setattr = fuse_setattr, 1686 .setattr = fuse_setattr,
1648 .create = fuse_create, 1687 .create = fuse_create,
1688 .atomic_open = fuse_atomic_open,
1649 .mknod = fuse_mknod, 1689 .mknod = fuse_mknod,
1650 .permission = fuse_permission, 1690 .permission = fuse_permission,
1651 .getattr = fuse_getattr, 1691 .getattr = fuse_getattr,