diff options
author | Miklos Szeredi <mszeredi@suse.cz> | 2012-06-05 09:10:18 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 08:33:06 -0400 |
commit | 0dd2b474d0b69d58859399b1df7fdc699ea005d4 (patch) | |
tree | 637db7456112c7d52193fc5ec743b8f9e8e20fb2 /fs/nfs | |
parent | d18e9008c377dc6a6d2166a6840bf3a23a5867fd (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/nfs')
-rw-r--r-- | fs/nfs/dir.c | 183 |
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 | ||
114 | static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); | 114 | static struct file *nfs_atomic_open(struct inode *, struct dentry *, |
115 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd); | 115 | struct opendata *, unsigned, umode_t, |
116 | bool *); | ||
117 | static int nfs4_create(struct inode *dir, struct dentry *dentry, | ||
118 | umode_t mode, struct nameidata *nd); | ||
116 | const struct inode_operations nfs4_dir_inode_operations = { | 119 | const 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 | ||
1406 | static int nfs_intent_set_file(struct nameidata *nd, struct nfs_open_context *ctx) | 1410 | static 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 | |||
1424 | out: | 1435 | out: |
1425 | put_nfs_open_context(ctx); | 1436 | put_nfs_open_context(ctx); |
1426 | return ret; | 1437 | return filp; |
1427 | } | 1438 | } |
1428 | 1439 | ||
1429 | static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1440 | static 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 | } | ||
1515 | out: | ||
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 | |||
1525 | out_err: | ||
1526 | return ERR_PTR(err); | ||
1527 | |||
1518 | no_open: | 1528 | no_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 | ||
1522 | static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | 1538 | static 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 | ||
1569 | static int nfs_open_create(struct inode *dir, struct dentry *dentry, | 1585 | static 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; |
1602 | out_put_ctx: | 1614 | out_put_ctx: |
1603 | put_nfs_open_context(ctx); | 1615 | put_nfs_open_context(ctx); |
1604 | out_err_drop: | 1616 | out_err_drop: |
1605 | d_drop(dentry); | 1617 | d_drop(dentry); |
1606 | out_err: | ||
1607 | return error; | 1618 | return error; |
1608 | } | 1619 | } |
1609 | 1620 | ||