Convert from nfs error values to regular errno's. Although most values of

nfs errors are chosen to be the same as errno, some of them are not and
it is better for portability to do the conversion anyway. Also a server
can return a bad error number that can cause the server to crash, because
it can have the high bits that are used internally set. This was the case
with amd. Finally nfs_request() should return a valid errno, because we
can return a bogus value to userland. Thanks to rpaulo for debugging this.
This commit is contained in:
christos 2005-09-25 00:20:38 +00:00
parent 61f989aeaf
commit a6ce8d7c4d
1 changed files with 118 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_socket.c,v 1.114 2005/05/29 20:58:13 christos Exp $ */
/* $NetBSD: nfs_socket.c,v 1.115 2005/09/25 00:20:38 christos Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1995
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.114 2005/05/29 20:58:13 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: nfs_socket.c,v 1.115 2005/09/25 00:20:38 christos Exp $");
#include "fs_nfs.h"
#include "opt_nfs.h"
@ -1211,22 +1211,122 @@ tryagain:
nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
if (*tl != 0) {
error = fxdr_unsigned(int, *tl);
if (error == NFSERR_ACCES && retry_cred) {
switch (error) {
case NFSERR_PERM:
error = EPERM;
break;
case NFSERR_NOENT:
error = ENOENT;
break;
case NFSERR_NXIO:
error = ENXIO;
break;
case NFSERR_ACCES:
error = EACCES;
if (!retry_cred)
break;
m_freem(mrep);
m_freem(rep->r_mreq);
FREE(rep, M_NFSREQ);
use_opencred = !use_opencred;
if (mrest_backup == NULL)
return ENOMEM; /* m_copym failure */
/* m_copym failure */
return ENOMEM;
mrest = mrest_backup;
mrest_backup = NULL;
cred = origcred;
error = 0;
retry_cred = FALSE;
goto tryagain_cred;
}
if ((nmp->nm_flag & NFSMNT_NFSV3) &&
error == NFSERR_TRYLATER) {
case NFSERR_EXIST:
error = EEXIST;
break;
case NFSERR_XDEV:
error = EXDEV;
break;
case NFSERR_NODEV:
error = ENODEV;
break;
case NFSERR_NOTDIR:
error = ENOTDIR;
break;
case NFSERR_ISDIR:
error = EISDIR;
break;
case NFSERR_INVAL:
error = EINVAL;
break;
case NFSERR_FBIG:
error = EFBIG;
break;
case NFSERR_NOSPC:
error = ENOSPC;
break;
case NFSERR_ROFS:
error = EROFS;
break;
case NFSERR_MLINK:
error = EMLINK;
break;
case NFSERR_NAMETOL:
error = ENAMETOOLONG;
break;
case NFSERR_NOTEMPTY:
error = ENOTEMPTY;
break;
case NFSERR_DQUOT:
error = EDQUOT;
break;
case NFSERR_STALE:
/*
* If the File Handle was stale, invalidate the
* lookup cache, just in case.
*/
error = ESTALE;
cache_purge(NFSTOV(np));
break;
case NFSERR_REMOTE:
error = EREMOTE;
break;
case NFSERR_WFLUSH:
case NFSERR_BADHANDLE:
case NFSERR_NOT_SYNC:
case NFSERR_BAD_COOKIE:
error = EINVAL;
break;
case NFSERR_NOTSUPP:
error = ENOTSUP;
break;
case NFSERR_TOOSMALL:
case NFSERR_SERVERFAULT:
case NFSERR_BADTYPE:
error = EINVAL;
break;
case NFSERR_TRYLATER:
if ((nmp->nm_flag & NFSMNT_NFSV3) == 0)
break;
m_freem(mrep);
error = 0;
waituntil = time.tv_sec + trylater_delay;
@ -1243,14 +1343,19 @@ tryagain:
*/
nfs_renewxid(rep);
goto tryagain;
case NFSERR_STALEWRITEVERF:
error = EINVAL;
break;
default:
#ifdef DIAGNOSTIC
printf("Invalid rpc error code %d\n", error);
#endif
error = EINVAL;
break;
}
/*
* If the File Handle was stale, invalidate the
* lookup cache, just in case.
*/
if (error == ESTALE)
cache_purge(NFSTOV(np));
if (nmp->nm_flag & NFSMNT_NFSV3) {
*mrp = mrep;
*mdp = md;