| // 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_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); |