Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Miklos Szeredi and committed by
Al Viro
0ef97dcf 16b1c1cd

+78 -55
+5 -51
fs/nfs/dir.c
··· 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, ··· 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) ··· 1552 1554 /* We cannot do exclusive creation on a positive dentry */ 1553 1555 if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) 1554 1556 goto no_open_dput; 1555 - /* We can't create new files here */ 1556 - openflags &= ~(O_CREAT|O_EXCL); 1557 1557 1558 - ctx = create_nfs_open_context(dentry, openflags); 1559 - ret = PTR_ERR(ctx); 1560 - if (IS_ERR(ctx)) 1561 - goto out; 1558 + /* Let f_op->open() actually open (and revalidate) the file */ 1559 + ret = 1; 1562 1560 1563 - attr.ia_valid = ATTR_OPEN; 1564 - if (openflags & O_TRUNC) { 1565 - attr.ia_valid |= ATTR_SIZE; 1566 - attr.ia_size = 0; 1567 - nfs_wb_all(inode); 1568 - } 1569 - 1570 - /* 1571 - * Note: we're not holding inode->i_mutex and so may be racing with 1572 - * operations that change the directory. We therefore save the 1573 - * change attribute *before* we do the RPC call. 1574 - */ 1575 - inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); 1576 - if (IS_ERR(inode)) { 1577 - ret = PTR_ERR(inode); 1578 - switch (ret) { 1579 - case -EPERM: 1580 - case -EACCES: 1581 - case -EDQUOT: 1582 - case -ENOSPC: 1583 - case -EROFS: 1584 - goto out_put_ctx; 1585 - default: 1586 - goto out_drop; 1587 - } 1588 - } 1589 - iput(inode); 1590 - if (inode != dentry->d_inode) 1591 - goto out_drop; 1592 - 1593 - nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); 1594 - ret = nfs_intent_set_file(nd, ctx); 1595 - if (ret >= 0) 1596 - ret = 1; 1597 1561 out: 1598 1562 dput(parent); 1599 1563 return ret; 1600 - out_drop: 1601 - d_drop(dentry); 1602 - ret = 0; 1603 - out_put_ctx: 1604 - put_nfs_open_context(ctx); 1605 - goto out; 1606 1564 1607 1565 no_open_dput: 1608 1566 dput(parent);
+73 -4
fs/nfs/file.c
··· 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 = {