aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2012-06-05 09:10:18 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-14 08:33:06 -0400
commit0dd2b474d0b69d58859399b1df7fdc699ea005d4 (patch)
tree637db7456112c7d52193fc5ec743b8f9e8e20fb2 /fs
parentd18e9008c377dc6a6d2166a6840bf3a23a5867fd (diff)
nfs: implement i_op->atomic_open()
Replace NFS4 specific ->lookup implementation with ->atomic_open impelementation and use the generic nfs_lookup for other lookups. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> CC: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/dir.c183
1 files changed, 97 insertions, 86 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f430057ff3b3..0d8c71271d1a 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -111,11 +111,15 @@ const struct inode_operations nfs3_dir_inode_operations = {
111 111
112#ifdef CONFIG_NFS_V4 112#ifdef CONFIG_NFS_V4
113 113
114static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); 114static struct file *nfs_atomic_open(struct inode *, struct dentry *,
115static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd); 115 struct opendata *, unsigned, umode_t,
116 bool *);
117static int nfs4_create(struct inode *dir, struct dentry *dentry,
118 umode_t mode, struct nameidata *nd);
116const struct inode_operations nfs4_dir_inode_operations = { 119const struct inode_operations nfs4_dir_inode_operations = {
117 .create = nfs_open_create, 120 .create = nfs4_create,
118 .lookup = nfs_atomic_lookup, 121 .lookup = nfs_lookup,
122 .atomic_open = nfs_atomic_open,
119 .link = nfs_link, 123 .link = nfs_link,
120 .unlink = nfs_unlink, 124 .unlink = nfs_unlink,
121 .symlink = nfs_symlink, 125 .symlink = nfs_symlink,
@@ -1403,120 +1407,132 @@ static int do_open(struct inode *inode, struct file *filp)
1403 return 0; 1407 return 0;
1404} 1408}
1405 1409
1406static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx) 1410static struct file *nfs_finish_open(struct nfs_open_context *ctx,
1411 struct dentry *dentry,
1412 struct opendata *od, unsigned open_flags)
1407{ 1413{
1408 struct file *filp; 1414 struct file *filp;
1409 int ret = 0; 1415 int err;
1416
1417 if (ctx->dentry != dentry) {
1418 dput(ctx->dentry);
1419 ctx->dentry = dget(dentry);
1420 }
1410 1421
1411 /* If the open_intent is for execute, we have an extra check to make */ 1422 /* If the open_intent is for execute, we have an extra check to make */
1412 if (ctx->mode & FMODE_EXEC) { 1423 if (ctx->mode & FMODE_EXEC) {
1413 ret = nfs_may_open(ctx->dentry->d_inode, 1424 err = nfs_may_open(dentry->d_inode, ctx->cred, open_flags);
1414 ctx->cred, 1425 if (err < 0) {
1415 nd->intent.open.flags); 1426 filp = ERR_PTR(err);
1416 if (ret < 0)
1417 goto out; 1427 goto out;
1428 }
1418 } 1429 }
1419 filp = lookup_instantiate_filp(nd, ctx->dentry, do_open); 1430
1420 if (IS_ERR(filp)) 1431 filp = finish_open(od, dentry, do_open);
1421 ret = PTR_ERR(filp); 1432 if (!IS_ERR(filp))
1422 else
1423 nfs_file_set_open_context(filp, ctx); 1433 nfs_file_set_open_context(filp, ctx);
1434
1424out: 1435out:
1425 put_nfs_open_context(ctx); 1436 put_nfs_open_context(ctx);
1426 return ret; 1437 return filp;
1427} 1438}
1428 1439
1429static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 1440static struct file *nfs_atomic_open(struct inode *dir, struct dentry *dentry,
1441 struct opendata *od, unsigned open_flags,
1442 umode_t mode, bool *created)
1430{ 1443{
1431 struct nfs_open_context *ctx; 1444 struct nfs_open_context *ctx;
1432 struct iattr attr; 1445 struct dentry *res;
1433 struct dentry *res = NULL; 1446 struct iattr attr = { .ia_valid = ATTR_OPEN };
1434 struct inode *inode; 1447 struct inode *inode;
1435 int open_flags; 1448 struct file *filp;
1436 int err; 1449 int err;
1437 1450
1438 dfprintk(VFS, "NFS: atomic_lookup(%s/%ld), %s\n", 1451 /* Expect a negative dentry */
1452 BUG_ON(dentry->d_inode);
1453
1454 dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
1439 dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); 1455 dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
1440 1456
1441 /* Check that we are indeed trying to open this file */ 1457 /* NFS only supports OPEN on regular files */
1442 if (!is_atomic_open(nd)) 1458 if ((open_flags & O_DIRECTORY)) {
1459 err = -ENOENT;
1460 if (!d_unhashed(dentry)) {
1461 /*
1462 * Hashed negative dentry with O_DIRECTORY: dentry was
1463 * revalidated and is fine, no need to perform lookup
1464 * again
1465 */
1466 goto out_err;
1467 }
1443 goto no_open; 1468 goto no_open;
1444
1445 if (dentry->d_name.len > NFS_SERVER(dir)->namelen) {
1446 res = ERR_PTR(-ENAMETOOLONG);
1447 goto out;
1448 } 1469 }
1449 1470
1450 /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash 1471 err = -ENAMETOOLONG;
1451 * the dentry. */ 1472 if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
1452 if (nd->flags & LOOKUP_EXCL) { 1473 goto out_err;
1453 d_instantiate(dentry, NULL);
1454 goto out;
1455 }
1456
1457 open_flags = nd->intent.open.flags;
1458 attr.ia_valid = ATTR_OPEN;
1459
1460 ctx = create_nfs_open_context(dentry, open_flags);
1461 res = ERR_CAST(ctx);
1462 if (IS_ERR(ctx))
1463 goto out;
1464 1474
1465 if (nd->flags & LOOKUP_CREATE) { 1475 if (open_flags & O_CREAT) {
1466 attr.ia_mode = nd->intent.open.create_mode;
1467 attr.ia_valid |= ATTR_MODE; 1476 attr.ia_valid |= ATTR_MODE;
1468 attr.ia_mode &= ~current_umask(); 1477 attr.ia_mode = mode & ~current_umask();
1469 } else 1478 }
1470 open_flags &= ~(O_EXCL | O_CREAT);
1471
1472 if (open_flags & O_TRUNC) { 1479 if (open_flags & O_TRUNC) {
1473 attr.ia_valid |= ATTR_SIZE; 1480 attr.ia_valid |= ATTR_SIZE;
1474 attr.ia_size = 0; 1481 attr.ia_size = 0;
1475 } 1482 }
1476 1483
1477 /* Open the file on the server */ 1484 ctx = create_nfs_open_context(dentry, open_flags);
1485 err = PTR_ERR(ctx);
1486 if (IS_ERR(ctx))
1487 goto out_err;
1488
1478 nfs_block_sillyrename(dentry->d_parent); 1489 nfs_block_sillyrename(dentry->d_parent);
1479 inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr); 1490 inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
1491 d_drop(dentry);
1480 if (IS_ERR(inode)) { 1492 if (IS_ERR(inode)) {
1481 nfs_unblock_sillyrename(dentry->d_parent); 1493 nfs_unblock_sillyrename(dentry->d_parent);
1482 put_nfs_open_context(ctx); 1494 put_nfs_open_context(ctx);
1483 switch (PTR_ERR(inode)) { 1495 err = PTR_ERR(inode);
1484 /* Make a negative dentry */ 1496 switch (err) {
1485 case -ENOENT: 1497 case -ENOENT:
1486 d_add(dentry, NULL); 1498 d_add(dentry, NULL);
1487 res = NULL; 1499 break;
1488 goto out; 1500 case -EISDIR:
1489 /* This turned out not to be a regular file */ 1501 case -ENOTDIR:
1490 case -EISDIR: 1502 goto no_open;
1491 case -ENOTDIR: 1503 case -ELOOP:
1504 if (!(open_flags & O_NOFOLLOW))
1492 goto no_open; 1505 goto no_open;
1493 case -ELOOP: 1506 break;
1494 if (!(nd->intent.open.flags & O_NOFOLLOW))
1495 goto no_open;
1496 /* case -EINVAL: */ 1507 /* case -EINVAL: */
1497 default: 1508 default:
1498 res = ERR_CAST(inode); 1509 break;
1499 goto out;
1500 } 1510 }
1511 goto out_err;
1501 } 1512 }
1502 res = d_add_unique(dentry, inode); 1513 res = d_add_unique(dentry, inode);
1503 nfs_unblock_sillyrename(dentry->d_parent); 1514 if (res != NULL)
1504 if (res != NULL) {
1505 dput(ctx->dentry);
1506 ctx->dentry = dget(res);
1507 dentry = res; 1515 dentry = res;
1508 } 1516
1509 err = nfs_intent_set_file(nd, ctx); 1517 nfs_unblock_sillyrename(dentry->d_parent);
1510 if (err < 0) {
1511 if (res != NULL)
1512 dput(res);
1513 return ERR_PTR(err);
1514 }
1515out:
1516 nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1518 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1517 return res; 1519
1520 filp = nfs_finish_open(ctx, dentry, od, open_flags);
1521
1522 dput(res);
1523 return filp;
1524
1525out_err:
1526 return ERR_PTR(err);
1527
1518no_open: 1528no_open:
1519 return nfs_lookup(dir, dentry, nd); 1529 res = nfs_lookup(dir, dentry, NULL);
1530 err = PTR_ERR(res);
1531 if (IS_ERR(res))
1532 goto out_err;
1533
1534 finish_no_open(od, res);
1535 return NULL;
1520} 1536}
1521 1537
1522static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) 1538static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -1566,8 +1582,8 @@ no_open:
1566 return nfs_lookup_revalidate(dentry, nd); 1582 return nfs_lookup_revalidate(dentry, nd);
1567} 1583}
1568 1584
1569static int nfs_open_create(struct inode *dir, struct dentry *dentry, 1585static int nfs4_create(struct inode *dir, struct dentry *dentry,
1570 umode_t mode, struct nameidata *nd) 1586 umode_t mode, struct nameidata *nd)
1571{ 1587{
1572 struct nfs_open_context *ctx = NULL; 1588 struct nfs_open_context *ctx = NULL;
1573 struct iattr attr; 1589 struct iattr attr;
@@ -1591,19 +1607,14 @@ static int nfs_open_create(struct inode *dir, struct dentry *dentry,
1591 error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx); 1607 error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags, ctx);
1592 if (error != 0) 1608 if (error != 0)
1593 goto out_put_ctx; 1609 goto out_put_ctx;
1594 if (nd) { 1610
1595 error = nfs_intent_set_file(nd, ctx); 1611 put_nfs_open_context(ctx);
1596 if (error < 0) 1612
1597 goto out_err;
1598 } else {
1599 put_nfs_open_context(ctx);
1600 }
1601 return 0; 1613 return 0;
1602out_put_ctx: 1614out_put_ctx:
1603 put_nfs_open_context(ctx); 1615 put_nfs_open_context(ctx);
1604out_err_drop: 1616out_err_drop:
1605 d_drop(dentry); 1617 d_drop(dentry);
1606out_err:
1607 return error; 1618 return error;
1608} 1619}
1609 1620