nfsd: don't fail unchecked creates of non-special files
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. Cc: stable@kernel.org 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>
This commit is contained in:
parent
0034102808
commit
9dc4e6c4d1
|
@ -235,15 +235,15 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
|
||||||
*/
|
*/
|
||||||
if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
|
if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
|
||||||
open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
|
open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
|
||||||
FATTR4_WORD1_TIME_MODIFY);
|
FATTR4_WORD1_TIME_MODIFY);
|
||||||
} else {
|
} else {
|
||||||
status = nfsd_lookup(rqstp, current_fh,
|
status = nfsd_lookup(rqstp, current_fh,
|
||||||
open->op_fname.data, open->op_fname.len, resfh);
|
open->op_fname.data, open->op_fname.len, resfh);
|
||||||
fh_unlock(current_fh);
|
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)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
@ -1458,7 +1458,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||||
switch (createmode) {
|
switch (createmode) {
|
||||||
case NFS3_CREATE_UNCHECKED:
|
case NFS3_CREATE_UNCHECKED:
|
||||||
if (! S_ISREG(dchild->d_inode->i_mode))
|
if (! S_ISREG(dchild->d_inode->i_mode))
|
||||||
err = nfserr_exist;
|
goto out;
|
||||||
else if (truncp) {
|
else if (truncp) {
|
||||||
/* in nfsv4, we need to treat this case a little
|
/* in nfsv4, we need to treat this case a little
|
||||||
* differently. we don't want to truncate the
|
* differently. we don't want to truncate the
|
||||||
|
|
Loading…
Reference in New Issue