diff options
author | J. Bruce Fields <bfields@redhat.com> | 2012-04-09 18:06:49 -0400 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2012-05-11 13:14:16 +0100 |
commit | 4ce56133a793c97f5995181504ca9a16146a521f (patch) | |
tree | ef014e0dd847df4e38efafbe962c2d970bad2976 | |
parent | 205648388f15b1ccf92b09ba0cf141cdd62bf711 (diff) |
nfsd: don't fail unchecked creates of non-special files
commit 9dc4e6c4d1182d34604ea40fef641775f5b15456 upstream.
Allow a v3 unchecked open of a non-regular file succeed as if it were a
lookup; typically a client in such a case will want to fall back on a
local open, so succeeding and giving it the filehandle is more useful
than failing with nfserr_exist, which makes it appear that nothing at
all exists by that name.
Similarly for v4, on an open-create, return the same errors we would on
an attempt to open a non-regular file, instead of returning
nfserr_exist.
This fixes a problem found doing a v4 open of a symlink with
O_RDONLY|O_CREAT, which resulted in the current client returning EEXIST.
Thanks also to Trond for analysis.
Reported-by: Orion Poplawski <orion@cora.nwra.com>
Tested-by: Orion Poplawski <orion@cora.nwra.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
[bwh: Backported to 3.2: use &resfh, not resfh]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | fs/nfsd/nfs4proc.c | 8 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 2 |
2 files changed, 5 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 35840aa6308..b8c5538fe45 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -231,17 +231,17 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o */ if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | - FATTR4_WORD1_TIME_MODIFY); + FATTR4_WORD1_TIME_MODIFY); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); fh_unlock(current_fh); - if (status) - goto out; - status = nfsd_check_obj_isreg(&resfh); } if (status) goto out; + status = nfsd_check_obj_isreg(&resfh); + if (status) + goto out; if (is_create_with_attrs(open) && open->op_acl != NULL) do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7a2e442623c..5c3cd820a8a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1439,7 +1439,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, switch (createmode) { case NFS3_CREATE_UNCHECKED: if (! S_ISREG(dchild->d_inode->i_mode)) - err = nfserr_exist; + goto out; else if (truncp) { /* in nfsv4, we need to treat this case a little * differently. we don't want to truncate the |