diff options
author | Jeff Layton <jlayton@redhat.com> | 2011-11-04 13:31:21 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-11-04 16:39:04 -0400 |
commit | 1788ea6e3b2a58cf4fb00206e362d9caff8d86a7 (patch) | |
tree | 24846fddf8b55f516f365a735defd79b6ea6d28a /fs | |
parent | 1583171492eb514e267c7b51e96846b38de0f544 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/dir.c | 2 | ||||
-rw-r--r-- | fs/nfs/file.c | 32 | ||||
-rw-r--r-- | fs/nfs/inode.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs3proc.c | 1 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 1 | ||||
-rw-r--r-- | fs/nfs/proc.c | 1 |
6 files changed, 37 insertions, 2 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index b238d95ac48c..ac2899098147 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1468,12 +1468,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1468 | res = NULL; | 1468 | res = NULL; |
1469 | goto out; | 1469 | goto out; |
1470 | /* This turned out not to be a regular file */ | 1470 | /* This turned out not to be a regular file */ |
1471 | case -EISDIR: | ||
1471 | case -ENOTDIR: | 1472 | case -ENOTDIR: |
1472 | goto no_open; | 1473 | goto no_open; |
1473 | case -ELOOP: | 1474 | case -ELOOP: |
1474 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1475 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1475 | goto no_open; | 1476 | goto no_open; |
1476 | /* case -EISDIR: */ | ||
1477 | /* case -EINVAL: */ | 1477 | /* case -EINVAL: */ |
1478 | default: | 1478 | default: |
1479 | res = ERR_CAST(inode); | 1479 | res = ERR_CAST(inode); |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0a1f8312b4dc..6d93e0754b5e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -886,3 +886,35 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) | |||
886 | file->f_path.dentry->d_name.name, arg); | 886 | file->f_path.dentry->d_name.name, arg); |
887 | return -EINVAL; | 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 */ | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index c07a55aec838..50a15fa8cf98 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -291,7 +291,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
291 | */ | 291 | */ |
292 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; | 292 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; |
293 | if (S_ISREG(inode->i_mode)) { | 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 | inode->i_data.a_ops = &nfs_file_aops; | 295 | inode->i_data.a_ops = &nfs_file_aops; |
296 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; | 296 | inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; |
297 | } else if (S_ISDIR(inode->i_mode)) { | 297 | } else if (S_ISDIR(inode->i_mode)) { |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 85f1690ca08c..d4bc9ed91748 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -853,6 +853,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { | |||
853 | .dentry_ops = &nfs_dentry_operations, | 853 | .dentry_ops = &nfs_dentry_operations, |
854 | .dir_inode_ops = &nfs3_dir_inode_operations, | 854 | .dir_inode_ops = &nfs3_dir_inode_operations, |
855 | .file_inode_ops = &nfs3_file_inode_operations, | 855 | .file_inode_ops = &nfs3_file_inode_operations, |
856 | .file_ops = &nfs_file_operations, | ||
856 | .getroot = nfs3_proc_get_root, | 857 | .getroot = nfs3_proc_get_root, |
857 | .getattr = nfs3_proc_getattr, | 858 | .getattr = nfs3_proc_getattr, |
858 | .setattr = nfs3_proc_setattr, | 859 | .setattr = nfs3_proc_setattr, |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b60fddf606f7..069cb8094d43 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -6253,6 +6253,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { | |||
6253 | .dentry_ops = &nfs4_dentry_operations, | 6253 | .dentry_ops = &nfs4_dentry_operations, |
6254 | .dir_inode_ops = &nfs4_dir_inode_operations, | 6254 | .dir_inode_ops = &nfs4_dir_inode_operations, |
6255 | .file_inode_ops = &nfs4_file_inode_operations, | 6255 | .file_inode_ops = &nfs4_file_inode_operations, |
6256 | .file_ops = &nfs4_file_operations, | ||
6256 | .getroot = nfs4_proc_get_root, | 6257 | .getroot = nfs4_proc_get_root, |
6257 | .getattr = nfs4_proc_getattr, | 6258 | .getattr = nfs4_proc_getattr, |
6258 | .setattr = nfs4_proc_setattr, | 6259 | .setattr = nfs4_proc_setattr, |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ac40b8535d7e..f48125da198a 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -710,6 +710,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { | |||
710 | .dentry_ops = &nfs_dentry_operations, | 710 | .dentry_ops = &nfs_dentry_operations, |
711 | .dir_inode_ops = &nfs_dir_inode_operations, | 711 | .dir_inode_ops = &nfs_dir_inode_operations, |
712 | .file_inode_ops = &nfs_file_inode_operations, | 712 | .file_inode_ops = &nfs_file_inode_operations, |
713 | .file_ops = &nfs_file_operations, | ||
713 | .getroot = nfs_proc_get_root, | 714 | .getroot = nfs_proc_get_root, |
714 | .getattr = nfs_proc_getattr, | 715 | .getattr = nfs_proc_getattr, |
715 | .setattr = nfs_proc_setattr, | 716 | .setattr = nfs_proc_setattr, |