Commit 1788ea6e3b2a58cf4fb00206e362d9caff8d86a7

Authored by Jeff Layton
Committed by Trond Myklebust
1 parent 1583171492

nfs: when attempting to open a directory, fall back on normal lookup (try #5)

commit d953126 changed how nfs_atomic_lookup handles an -EISDIR return
from an OPEN call. Prior to that patch, that caused the client to fall
back to doing a normal lookup. When that patch went in, the code began
returning that error to userspace. The d_revalidate codepath however
never had the corresponding change, so it was still possible to end up
with a NULL ctx->state pointer after that.

That patch caused a regression. When we attempt to open a directory that
does not have a cached dentry, that open now errors out with EISDIR. If
you attempt the same open with a cached dentry, it will succeed.

Fix this by reverting the change in nfs_atomic_lookup and allowing
attempts to open directories to fall back to a normal lookup

Also, add a NFSv4-specific f_ops->open routine that just returns
-ENOTDIR. This should never be called if things are working properly,
but if it ever is, then the dprintk may help in debugging.

To facilitate this, a new file_operations field is also added to the
nfs_rpc_ops struct.

Cc: stable@kernel.org
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 8 changed files with 41 additions and 2 deletions Side-by-side Diff

... ... @@ -1468,12 +1468,12 @@
1468 1468 res = NULL;
1469 1469 goto out;
1470 1470 /* This turned out not to be a regular file */
  1471 + case -EISDIR:
1471 1472 case -ENOTDIR:
1472 1473 goto no_open;
1473 1474 case -ELOOP:
1474 1475 if (!(nd->intent.open.flags & O_NOFOLLOW))
1475 1476 goto no_open;
1476   - /* case -EISDIR: */
1477 1477 /* case -EINVAL: */
1478 1478 default:
1479 1479 res = ERR_CAST(inode);
... ... @@ -886,4 +886,36 @@
886 886 file->f_path.dentry->d_name.name, arg);
887 887 return -EINVAL;
888 888 }
  889 +
  890 +#ifdef CONFIG_NFS_V4
  891 +static int
  892 +nfs4_file_open(struct inode *inode, struct file *filp)
  893 +{
  894 + /*
  895 + * NFSv4 opens are handled in d_lookup and d_revalidate. If we get to
  896 + * this point, then something is very wrong
  897 + */
  898 + dprintk("NFS: %s called! inode=%p filp=%p\n", __func__, inode, filp);
  899 + return -ENOTDIR;
  900 +}
  901 +
  902 +const struct file_operations nfs4_file_operations = {
  903 + .llseek = nfs_file_llseek,
  904 + .read = do_sync_read,
  905 + .write = do_sync_write,
  906 + .aio_read = nfs_file_read,
  907 + .aio_write = nfs_file_write,
  908 + .mmap = nfs_file_mmap,
  909 + .open = nfs4_file_open,
  910 + .flush = nfs_file_flush,
  911 + .release = nfs_file_release,
  912 + .fsync = nfs_file_fsync,
  913 + .lock = nfs_lock,
  914 + .flock = nfs_flock,
  915 + .splice_read = nfs_file_splice_read,
  916 + .splice_write = nfs_file_splice_write,
  917 + .check_flags = nfs_check_flags,
  918 + .setlease = nfs_setlease,
  919 +};
  920 +#endif /* CONFIG_NFS_V4 */
... ... @@ -291,7 +291,7 @@
291 291 */
292 292 inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops;
293 293 if (S_ISREG(inode->i_mode)) {
294   - inode->i_fop = &nfs_file_operations;
  294 + inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops;
295 295 inode->i_data.a_ops = &nfs_file_aops;
296 296 inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
297 297 } else if (S_ISDIR(inode->i_mode)) {
... ... @@ -853,6 +853,7 @@
853 853 .dentry_ops = &nfs_dentry_operations,
854 854 .dir_inode_ops = &nfs3_dir_inode_operations,
855 855 .file_inode_ops = &nfs3_file_inode_operations,
  856 + .file_ops = &nfs_file_operations,
856 857 .getroot = nfs3_proc_get_root,
857 858 .getattr = nfs3_proc_getattr,
858 859 .setattr = nfs3_proc_setattr,
... ... @@ -6253,6 +6253,7 @@
6253 6253 .dentry_ops = &nfs4_dentry_operations,
6254 6254 .dir_inode_ops = &nfs4_dir_inode_operations,
6255 6255 .file_inode_ops = &nfs4_file_inode_operations,
  6256 + .file_ops = &nfs4_file_operations,
6256 6257 .getroot = nfs4_proc_get_root,
6257 6258 .getattr = nfs4_proc_getattr,
6258 6259 .setattr = nfs4_proc_setattr,
... ... @@ -710,6 +710,7 @@
710 710 .dentry_ops = &nfs_dentry_operations,
711 711 .dir_inode_ops = &nfs_dir_inode_operations,
712 712 .file_inode_ops = &nfs_file_inode_operations,
  713 + .file_ops = &nfs_file_operations,
713 714 .getroot = nfs_proc_get_root,
714 715 .getattr = nfs_proc_getattr,
715 716 .setattr = nfs_proc_setattr,
include/linux/nfs_fs.h
... ... @@ -410,6 +410,9 @@
410 410 extern const struct inode_operations nfs3_file_inode_operations;
411 411 #endif /* CONFIG_NFS_V3 */
412 412 extern const struct file_operations nfs_file_operations;
  413 +#ifdef CONFIG_NFS_V4
  414 +extern const struct file_operations nfs4_file_operations;
  415 +#endif /* CONFIG_NFS_V4 */
413 416 extern const struct address_space_operations nfs_file_aops;
414 417 extern const struct address_space_operations nfs_dir_aops;
415 418  
include/linux/nfs_xdr.h
... ... @@ -1192,6 +1192,7 @@
1192 1192 const struct dentry_operations *dentry_ops;
1193 1193 const struct inode_operations *dir_inode_ops;
1194 1194 const struct inode_operations *file_inode_ops;
  1195 + const struct file_operations *file_ops;
1195 1196  
1196 1197 int (*getroot) (struct nfs_server *, struct nfs_fh *,
1197 1198 struct nfs_fsinfo *);