Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+5 -5
+4 -4
fs/nfsd/nfs4proc.c
··· 235 235 */ 236 236 if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) 237 237 open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | 238 - FATTR4_WORD1_TIME_MODIFY); 238 + FATTR4_WORD1_TIME_MODIFY); 239 239 } else { 240 240 status = nfsd_lookup(rqstp, current_fh, 241 241 open->op_fname.data, open->op_fname.len, resfh); 242 242 fh_unlock(current_fh); 243 - if (status) 244 - goto out; 245 - status = nfsd_check_obj_isreg(resfh); 246 243 } 244 + if (status) 245 + goto out; 246 + status = nfsd_check_obj_isreg(resfh); 247 247 if (status) 248 248 goto out; 249 249
+1 -1
fs/nfsd/vfs.c
··· 1458 1458 switch (createmode) { 1459 1459 case NFS3_CREATE_UNCHECKED: 1460 1460 if (! S_ISREG(dchild->d_inode->i_mode)) 1461 - err = nfserr_exist; 1461 + goto out; 1462 1462 else if (truncp) { 1463 1463 /* in nfsv4, we need to treat this case a little 1464 1464 * differently. we don't want to truncate the