Commit 0ef97dcfce4179a2eba046b855ee2f91d6f1b414

Authored by Miklos Szeredi
Committed by Al Viro
1 parent 16b1c1cd71

nfs: don't open in ->d_revalidate

NFSv4 can't do reliable opens in d_revalidate, since it cannot know whether a
mount needs to be followed or not.  It does check d_mountpoint() on the dentry,
which can result in a weird error if the VFS found that the mount does not in
fact need to be followed, e.g.:

  # mount --bind /mnt/nfs /mnt/nfs-clone
  # echo something > /mnt/nfs/tmp/bar
  # echo x > /tmp/file
  # mount --bind /tmp/file /mnt/nfs-clone/tmp/bar
  # cat  /mnt/nfs/tmp/bar
  cat: /mnt/nfs/tmp/bar: Not a directory

Which should, by any sane filesystem, result in "something" being printed.

So instead do the open in f_op->open() and in the unlikely case that the cached
dentry turned out to be invalid, drop the dentry and return EOPENSTALE to let
the VFS retry.

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>

Showing 2 changed files with 78 additions and 55 deletions Side-by-side Diff

... ... @@ -1354,10 +1354,10 @@
1354 1354 }
1355 1355  
1356 1356 #ifdef CONFIG_NFS_V4
1357   -static int nfs_open_revalidate(struct dentry *, struct nameidata *);
  1357 +static int nfs4_lookup_revalidate(struct dentry *, struct nameidata *);
1358 1358  
1359 1359 const struct dentry_operations nfs4_dentry_operations = {
1360   - .d_revalidate = nfs_open_revalidate,
  1360 + .d_revalidate = nfs4_lookup_revalidate,
1361 1361 .d_delete = nfs_dentry_delete,
1362 1362 .d_iput = nfs_dentry_iput,
1363 1363 .d_automount = nfs_d_automount,
1364 1364  
... ... @@ -1519,13 +1519,11 @@
1519 1519 return nfs_lookup(dir, dentry, nd);
1520 1520 }
1521 1521  
1522   -static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
  1522 +static int nfs4_lookup_revalidate(struct dentry *dentry, struct nameidata *nd)
1523 1523 {
1524 1524 struct dentry *parent = NULL;
1525 1525 struct inode *inode;
1526 1526 struct inode *dir;
1527   - struct nfs_open_context *ctx;
1528   - struct iattr attr;
1529 1527 int openflags, ret = 0;
1530 1528  
1531 1529 if (nd->flags & LOOKUP_RCU)
1532 1530  
1533 1531  
1534 1532  
... ... @@ -1554,57 +1552,13 @@
1554 1552 /* We cannot do exclusive creation on a positive dentry */
1555 1553 if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
1556 1554 goto no_open_dput;
1557   - /* We can't create new files here */
1558   - openflags &= ~(O_CREAT|O_EXCL);
1559 1555  
1560   - ctx = create_nfs_open_context(dentry, openflags);
1561   - ret = PTR_ERR(ctx);
1562   - if (IS_ERR(ctx))
1563   - goto out;
  1556 + /* Let f_op->open() actually open (and revalidate) the file */
  1557 + ret = 1;
1564 1558  
1565   - attr.ia_valid = ATTR_OPEN;
1566   - if (openflags & O_TRUNC) {
1567   - attr.ia_valid |= ATTR_SIZE;
1568   - attr.ia_size = 0;
1569   - nfs_wb_all(inode);
1570   - }
1571   -
1572   - /*
1573   - * Note: we're not holding inode->i_mutex and so may be racing with
1574   - * operations that change the directory. We therefore save the
1575   - * change attribute *before* we do the RPC call.
1576   - */
1577   - inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
1578   - if (IS_ERR(inode)) {
1579   - ret = PTR_ERR(inode);
1580   - switch (ret) {
1581   - case -EPERM:
1582   - case -EACCES:
1583   - case -EDQUOT:
1584   - case -ENOSPC:
1585   - case -EROFS:
1586   - goto out_put_ctx;
1587   - default:
1588   - goto out_drop;
1589   - }
1590   - }
1591   - iput(inode);
1592   - if (inode != dentry->d_inode)
1593   - goto out_drop;
1594   -
1595   - nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1596   - ret = nfs_intent_set_file(nd, ctx);
1597   - if (ret >= 0)
1598   - ret = 1;
1599 1559 out:
1600 1560 dput(parent);
1601 1561 return ret;
1602   -out_drop:
1603   - d_drop(dentry);
1604   - ret = 0;
1605   -out_put_ctx:
1606   - put_nfs_open_context(ctx);
1607   - goto out;
1608 1562  
1609 1563 no_open_dput:
1610 1564 dput(parent);
... ... @@ -879,12 +879,81 @@
879 879 static int
880 880 nfs4_file_open(struct inode *inode, struct file *filp)
881 881 {
  882 + struct nfs_open_context *ctx;
  883 + struct dentry *dentry = filp->f_path.dentry;
  884 + struct dentry *parent = NULL;
  885 + struct inode *dir;
  886 + unsigned openflags = filp->f_flags;
  887 + struct iattr attr;
  888 + int err;
  889 +
  890 + BUG_ON(inode != dentry->d_inode);
882 891 /*
883   - * NFSv4 opens are handled in d_lookup and d_revalidate. If we get to
884   - * this point, then something is very wrong
  892 + * If no cached dentry exists or if it's negative, NFSv4 handled the
  893 + * opens in ->lookup() or ->create().
  894 + *
  895 + * We only get this far for a cached positive dentry. We skipped
  896 + * revalidation, so handle it here by dropping the dentry and returning
  897 + * -EOPENSTALE. The VFS will retry the lookup/create/open.
885 898 */
886   - dprintk("NFS: %s called! inode=%p filp=%p\n", __func__, inode, filp);
887   - return -ENOTDIR;
  899 +
  900 + dprintk("NFS: open file(%s/%s)\n",
  901 + dentry->d_parent->d_name.name,
  902 + dentry->d_name.name);
  903 +
  904 + if ((openflags & O_ACCMODE) == 3)
  905 + openflags--;
  906 +
  907 + /* We can't create new files here */
  908 + openflags &= ~(O_CREAT|O_EXCL);
  909 +
  910 + parent = dget_parent(dentry);
  911 + dir = parent->d_inode;
  912 +
  913 + ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
  914 + err = PTR_ERR(ctx);
  915 + if (IS_ERR(ctx))
  916 + goto out;
  917 +
  918 + attr.ia_valid = ATTR_OPEN;
  919 + if (openflags & O_TRUNC) {
  920 + attr.ia_valid |= ATTR_SIZE;
  921 + attr.ia_size = 0;
  922 + nfs_wb_all(inode);
  923 + }
  924 +
  925 + inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr);
  926 + if (IS_ERR(inode)) {
  927 + err = PTR_ERR(inode);
  928 + switch (err) {
  929 + case -EPERM:
  930 + case -EACCES:
  931 + case -EDQUOT:
  932 + case -ENOSPC:
  933 + case -EROFS:
  934 + goto out_put_ctx;
  935 + default:
  936 + goto out_drop;
  937 + }
  938 + }
  939 + iput(inode);
  940 + if (inode != dentry->d_inode)
  941 + goto out_drop;
  942 +
  943 + nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
  944 + nfs_file_set_open_context(filp, ctx);
  945 + err = 0;
  946 +
  947 +out_put_ctx:
  948 + put_nfs_open_context(ctx);
  949 +out:
  950 + dput(parent);
  951 + return err;
  952 +
  953 +out_drop:
  954 + d_drop(dentry);
  955 + err = -EOPENSTALE;
  956 + goto out_put_ctx;
888 957 }
889 958  
890 959 const struct file_operations nfs4_file_operations = {