|  | // SPDX-License-Identifier: GPL-2.0-only | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/nfs_common.h> | 
|  | #include <linux/nfs4.h> | 
|  |  | 
|  | /* | 
|  | * We need to translate between nfs status return values and | 
|  | * the local errno values which may not be the same. | 
|  | */ | 
|  | static const struct { | 
|  | int stat; | 
|  | int errno; | 
|  | } nfs_errtbl[] = { | 
|  | { NFS_OK,		0		}, | 
|  | { NFSERR_PERM,		-EPERM		}, | 
|  | { NFSERR_NOENT,		-ENOENT		}, | 
|  | { NFSERR_IO,		-EIO		}, | 
|  | { NFSERR_NXIO,		-ENXIO		}, | 
|  | /*	{ NFSERR_EAGAIN,	-EAGAIN		}, */ | 
|  | { NFSERR_ACCES,		-EACCES		}, | 
|  | { NFSERR_EXIST,		-EEXIST		}, | 
|  | { NFSERR_XDEV,		-EXDEV		}, | 
|  | { NFSERR_NODEV,		-ENODEV		}, | 
|  | { NFSERR_NOTDIR,	-ENOTDIR	}, | 
|  | { NFSERR_ISDIR,		-EISDIR		}, | 
|  | { NFSERR_INVAL,		-EINVAL		}, | 
|  | { NFSERR_FBIG,		-EFBIG		}, | 
|  | { NFSERR_NOSPC,		-ENOSPC		}, | 
|  | { NFSERR_ROFS,		-EROFS		}, | 
|  | { NFSERR_MLINK,		-EMLINK		}, | 
|  | { NFSERR_NAMETOOLONG,	-ENAMETOOLONG	}, | 
|  | { NFSERR_NOTEMPTY,	-ENOTEMPTY	}, | 
|  | { NFSERR_DQUOT,		-EDQUOT		}, | 
|  | { NFSERR_STALE,		-ESTALE		}, | 
|  | { NFSERR_REMOTE,	-EREMOTE	}, | 
|  | #ifdef EWFLUSH | 
|  | { NFSERR_WFLUSH,	-EWFLUSH	}, | 
|  | #endif | 
|  | { NFSERR_BADHANDLE,	-EBADHANDLE	}, | 
|  | { NFSERR_NOT_SYNC,	-ENOTSYNC	}, | 
|  | { NFSERR_BAD_COOKIE,	-EBADCOOKIE	}, | 
|  | { NFSERR_NOTSUPP,	-ENOTSUPP	}, | 
|  | { NFSERR_TOOSMALL,	-ETOOSMALL	}, | 
|  | { NFSERR_SERVERFAULT,	-EREMOTEIO	}, | 
|  | { NFSERR_BADTYPE,	-EBADTYPE	}, | 
|  | { NFSERR_JUKEBOX,	-EJUKEBOX	}, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * nfs_stat_to_errno - convert an NFS status code to a local errno | 
|  | * @status: NFS status code to convert | 
|  | * | 
|  | * Returns a local errno value, or -EIO if the NFS status code is | 
|  | * not recognized.  This function is used jointly by NFSv2 and NFSv3. | 
|  | */ | 
|  | int nfs_stat_to_errno(enum nfs_stat status) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { | 
|  | if (nfs_errtbl[i].stat == (int)status) | 
|  | return nfs_errtbl[i].errno; | 
|  | } | 
|  | return -EIO; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(nfs_stat_to_errno); | 
|  |  | 
|  | /* | 
|  | * We need to translate between nfs v4 status return values and | 
|  | * the local errno values which may not be the same. | 
|  | * | 
|  | * nfs4_errtbl_common[] is used before more specialized mappings | 
|  | * available in nfs4_errtbl[] or nfs4_errtbl_localio[]. | 
|  | */ | 
|  | static const struct { | 
|  | int stat; | 
|  | int errno; | 
|  | } nfs4_errtbl_common[] = { | 
|  | { NFS4_OK,		0		}, | 
|  | { NFS4ERR_PERM,		-EPERM		}, | 
|  | { NFS4ERR_NOENT,	-ENOENT		}, | 
|  | { NFS4ERR_IO,		-EIO		}, | 
|  | { NFS4ERR_NXIO,		-ENXIO		}, | 
|  | { NFS4ERR_ACCESS,	-EACCES		}, | 
|  | { NFS4ERR_EXIST,	-EEXIST		}, | 
|  | { NFS4ERR_XDEV,		-EXDEV		}, | 
|  | { NFS4ERR_NOTDIR,	-ENOTDIR	}, | 
|  | { NFS4ERR_ISDIR,	-EISDIR		}, | 
|  | { NFS4ERR_INVAL,	-EINVAL		}, | 
|  | { NFS4ERR_FBIG,		-EFBIG		}, | 
|  | { NFS4ERR_NOSPC,	-ENOSPC		}, | 
|  | { NFS4ERR_ROFS,		-EROFS		}, | 
|  | { NFS4ERR_MLINK,	-EMLINK		}, | 
|  | { NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	}, | 
|  | { NFS4ERR_NOTEMPTY,	-ENOTEMPTY	}, | 
|  | { NFS4ERR_DQUOT,	-EDQUOT		}, | 
|  | { NFS4ERR_STALE,	-ESTALE		}, | 
|  | { NFS4ERR_BADHANDLE,	-EBADHANDLE	}, | 
|  | { NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	}, | 
|  | { NFS4ERR_NOTSUPP,	-ENOTSUPP	}, | 
|  | { NFS4ERR_TOOSMALL,	-ETOOSMALL	}, | 
|  | { NFS4ERR_BADTYPE,	-EBADTYPE	}, | 
|  | { NFS4ERR_SYMLINK,	-ELOOP		}, | 
|  | { NFS4ERR_DEADLOCK,	-EDEADLK	}, | 
|  | }; | 
|  |  | 
|  | static const struct { | 
|  | int stat; | 
|  | int errno; | 
|  | } nfs4_errtbl[] = { | 
|  | { NFS4ERR_SERVERFAULT,	-EREMOTEIO	}, | 
|  | { NFS4ERR_LOCKED,	-EAGAIN		}, | 
|  | { NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	}, | 
|  | { NFS4ERR_NOXATTR,	-ENODATA	}, | 
|  | { NFS4ERR_XATTR2BIG,	-E2BIG		}, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Convert an NFS error code to a local one. | 
|  | * This one is used by NFSv4. | 
|  | */ | 
|  | int nfs4_stat_to_errno(int stat) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* First check nfs4_errtbl_common */ | 
|  | for (i = 0; i < ARRAY_SIZE(nfs4_errtbl_common); i++) { | 
|  | if (nfs4_errtbl_common[i].stat == stat) | 
|  | return nfs4_errtbl_common[i].errno; | 
|  | } | 
|  | /* Then check nfs4_errtbl */ | 
|  | for (i = 0; i < ARRAY_SIZE(nfs4_errtbl); i++) { | 
|  | if (nfs4_errtbl[i].stat == stat) | 
|  | return nfs4_errtbl[i].errno; | 
|  | } | 
|  | if (stat <= 10000 || stat > 10100) { | 
|  | /* The server is looney tunes. */ | 
|  | return -EREMOTEIO; | 
|  | } | 
|  | /* If we cannot translate the error, the recovery routines should | 
|  | * handle it. | 
|  | * Note: remaining NFSv4 error codes have values > 10000, so should | 
|  | * not conflict with native Linux error codes. | 
|  | */ | 
|  | return -stat; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(nfs4_stat_to_errno); | 
|  |  | 
|  | /* | 
|  | * This table is useful for conversion from local errno to NFS error. | 
|  | * It provides more logically correct mappings for use with LOCALIO | 
|  | * (which is focused on converting from errno to NFS status). | 
|  | */ | 
|  | static const struct { | 
|  | int stat; | 
|  | int errno; | 
|  | } nfs4_errtbl_localio[] = { | 
|  | /* Map errors differently than nfs4_errtbl */ | 
|  | { NFS4ERR_IO,		-EREMOTEIO	}, | 
|  | { NFS4ERR_DELAY,	-EAGAIN		}, | 
|  | { NFS4ERR_FBIG,		-E2BIG		}, | 
|  | /* Map errors not handled by nfs4_errtbl */ | 
|  | { NFS4ERR_STALE,	-EBADF		}, | 
|  | { NFS4ERR_STALE,	-EOPENSTALE	}, | 
|  | { NFS4ERR_DELAY,	-ETIMEDOUT	}, | 
|  | { NFS4ERR_DELAY,	-ERESTARTSYS	}, | 
|  | { NFS4ERR_DELAY,	-ENOMEM		}, | 
|  | { NFS4ERR_IO,		-ETXTBSY	}, | 
|  | { NFS4ERR_IO,		-EBUSY		}, | 
|  | { NFS4ERR_SERVERFAULT,	-ESERVERFAULT	}, | 
|  | { NFS4ERR_SERVERFAULT,	-ENFILE		}, | 
|  | { NFS4ERR_IO,		-EUCLEAN	}, | 
|  | { NFS4ERR_PERM,		-ENOKEY		}, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * Convert an errno to an NFS error code for LOCALIO. | 
|  | */ | 
|  | __u32 nfs_localio_errno_to_nfs4_stat(int errno) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* First check nfs4_errtbl_common */ | 
|  | for (i = 0; i < ARRAY_SIZE(nfs4_errtbl_common); i++) { | 
|  | if (nfs4_errtbl_common[i].errno == errno) | 
|  | return nfs4_errtbl_common[i].stat; | 
|  | } | 
|  | /* Then check nfs4_errtbl_localio */ | 
|  | for (i = 0; i < ARRAY_SIZE(nfs4_errtbl_localio); i++) { | 
|  | if (nfs4_errtbl_localio[i].errno == errno) | 
|  | return nfs4_errtbl_localio[i].stat; | 
|  | } | 
|  | /* If we cannot translate the error, the recovery routines should | 
|  | * handle it. | 
|  | * Note: remaining NFSv4 error codes have values > 10000, so should | 
|  | * not conflict with native Linux error codes. | 
|  | */ | 
|  | return NFS4ERR_SERVERFAULT; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(nfs_localio_errno_to_nfs4_stat); |