Commit 1788ea6e3b2a58cf4fb00206e362d9caff8d86a7
Committed by
Trond Myklebust
1 parent
1583171492
Exists in
master
and in
6 other branches
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
fs/nfs/dir.c
... | ... | @@ -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); |
fs/nfs/file.c
... | ... | @@ -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 */ |
fs/nfs/inode.c
... | ... | @@ -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)) { |
fs/nfs/nfs3proc.c
... | ... | @@ -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, |
fs/nfs/nfs4proc.c
... | ... | @@ -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, |
fs/nfs/proc.c
... | ... | @@ -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 *); |