18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/9p/error.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Error string handling 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Plan 9 uses error strings, Unix uses error numbers. These functions 88c2ecf20Sopenharmony_ci * try to help manage that and provide for dynamically adding error 98c2ecf20Sopenharmony_ci * mappings. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 128c2ecf20Sopenharmony_ci * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/jhash.h> 208c2ecf20Sopenharmony_ci#include <linux/errno.h> 218c2ecf20Sopenharmony_ci#include <net/9p/9p.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * struct errormap - map string errors from Plan 9 to Linux numeric ids 258c2ecf20Sopenharmony_ci * @name: string sent over 9P 268c2ecf20Sopenharmony_ci * @val: numeric id most closely representing @name 278c2ecf20Sopenharmony_ci * @namelen: length of string 288c2ecf20Sopenharmony_ci * @list: hash-table list for string lookup 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistruct errormap { 318c2ecf20Sopenharmony_ci char *name; 328c2ecf20Sopenharmony_ci int val; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci int namelen; 358c2ecf20Sopenharmony_ci struct hlist_node list; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define ERRHASHSZ 32 398c2ecf20Sopenharmony_cistatic struct hlist_head hash_errmap[ERRHASHSZ]; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* FixMe - reduce to a reasonable size */ 428c2ecf20Sopenharmony_cistatic struct errormap errmap[] = { 438c2ecf20Sopenharmony_ci {"Operation not permitted", EPERM}, 448c2ecf20Sopenharmony_ci {"wstat prohibited", EPERM}, 458c2ecf20Sopenharmony_ci {"No such file or directory", ENOENT}, 468c2ecf20Sopenharmony_ci {"directory entry not found", ENOENT}, 478c2ecf20Sopenharmony_ci {"file not found", ENOENT}, 488c2ecf20Sopenharmony_ci {"Interrupted system call", EINTR}, 498c2ecf20Sopenharmony_ci {"Input/output error", EIO}, 508c2ecf20Sopenharmony_ci {"No such device or address", ENXIO}, 518c2ecf20Sopenharmony_ci {"Argument list too long", E2BIG}, 528c2ecf20Sopenharmony_ci {"Bad file descriptor", EBADF}, 538c2ecf20Sopenharmony_ci {"Resource temporarily unavailable", EAGAIN}, 548c2ecf20Sopenharmony_ci {"Cannot allocate memory", ENOMEM}, 558c2ecf20Sopenharmony_ci {"Permission denied", EACCES}, 568c2ecf20Sopenharmony_ci {"Bad address", EFAULT}, 578c2ecf20Sopenharmony_ci {"Block device required", ENOTBLK}, 588c2ecf20Sopenharmony_ci {"Device or resource busy", EBUSY}, 598c2ecf20Sopenharmony_ci {"File exists", EEXIST}, 608c2ecf20Sopenharmony_ci {"Invalid cross-device link", EXDEV}, 618c2ecf20Sopenharmony_ci {"No such device", ENODEV}, 628c2ecf20Sopenharmony_ci {"Not a directory", ENOTDIR}, 638c2ecf20Sopenharmony_ci {"Is a directory", EISDIR}, 648c2ecf20Sopenharmony_ci {"Invalid argument", EINVAL}, 658c2ecf20Sopenharmony_ci {"Too many open files in system", ENFILE}, 668c2ecf20Sopenharmony_ci {"Too many open files", EMFILE}, 678c2ecf20Sopenharmony_ci {"Text file busy", ETXTBSY}, 688c2ecf20Sopenharmony_ci {"File too large", EFBIG}, 698c2ecf20Sopenharmony_ci {"No space left on device", ENOSPC}, 708c2ecf20Sopenharmony_ci {"Illegal seek", ESPIPE}, 718c2ecf20Sopenharmony_ci {"Read-only file system", EROFS}, 728c2ecf20Sopenharmony_ci {"Too many links", EMLINK}, 738c2ecf20Sopenharmony_ci {"Broken pipe", EPIPE}, 748c2ecf20Sopenharmony_ci {"Numerical argument out of domain", EDOM}, 758c2ecf20Sopenharmony_ci {"Numerical result out of range", ERANGE}, 768c2ecf20Sopenharmony_ci {"Resource deadlock avoided", EDEADLK}, 778c2ecf20Sopenharmony_ci {"File name too long", ENAMETOOLONG}, 788c2ecf20Sopenharmony_ci {"No locks available", ENOLCK}, 798c2ecf20Sopenharmony_ci {"Function not implemented", ENOSYS}, 808c2ecf20Sopenharmony_ci {"Directory not empty", ENOTEMPTY}, 818c2ecf20Sopenharmony_ci {"Too many levels of symbolic links", ELOOP}, 828c2ecf20Sopenharmony_ci {"No message of desired type", ENOMSG}, 838c2ecf20Sopenharmony_ci {"Identifier removed", EIDRM}, 848c2ecf20Sopenharmony_ci {"No data available", ENODATA}, 858c2ecf20Sopenharmony_ci {"Machine is not on the network", ENONET}, 868c2ecf20Sopenharmony_ci {"Package not installed", ENOPKG}, 878c2ecf20Sopenharmony_ci {"Object is remote", EREMOTE}, 888c2ecf20Sopenharmony_ci {"Link has been severed", ENOLINK}, 898c2ecf20Sopenharmony_ci {"Communication error on send", ECOMM}, 908c2ecf20Sopenharmony_ci {"Protocol error", EPROTO}, 918c2ecf20Sopenharmony_ci {"Bad message", EBADMSG}, 928c2ecf20Sopenharmony_ci {"File descriptor in bad state", EBADFD}, 938c2ecf20Sopenharmony_ci {"Streams pipe error", ESTRPIPE}, 948c2ecf20Sopenharmony_ci {"Too many users", EUSERS}, 958c2ecf20Sopenharmony_ci {"Socket operation on non-socket", ENOTSOCK}, 968c2ecf20Sopenharmony_ci {"Message too long", EMSGSIZE}, 978c2ecf20Sopenharmony_ci {"Protocol not available", ENOPROTOOPT}, 988c2ecf20Sopenharmony_ci {"Protocol not supported", EPROTONOSUPPORT}, 998c2ecf20Sopenharmony_ci {"Socket type not supported", ESOCKTNOSUPPORT}, 1008c2ecf20Sopenharmony_ci {"Operation not supported", EOPNOTSUPP}, 1018c2ecf20Sopenharmony_ci {"Protocol family not supported", EPFNOSUPPORT}, 1028c2ecf20Sopenharmony_ci {"Network is down", ENETDOWN}, 1038c2ecf20Sopenharmony_ci {"Network is unreachable", ENETUNREACH}, 1048c2ecf20Sopenharmony_ci {"Network dropped connection on reset", ENETRESET}, 1058c2ecf20Sopenharmony_ci {"Software caused connection abort", ECONNABORTED}, 1068c2ecf20Sopenharmony_ci {"Connection reset by peer", ECONNRESET}, 1078c2ecf20Sopenharmony_ci {"No buffer space available", ENOBUFS}, 1088c2ecf20Sopenharmony_ci {"Transport endpoint is already connected", EISCONN}, 1098c2ecf20Sopenharmony_ci {"Transport endpoint is not connected", ENOTCONN}, 1108c2ecf20Sopenharmony_ci {"Cannot send after transport endpoint shutdown", ESHUTDOWN}, 1118c2ecf20Sopenharmony_ci {"Connection timed out", ETIMEDOUT}, 1128c2ecf20Sopenharmony_ci {"Connection refused", ECONNREFUSED}, 1138c2ecf20Sopenharmony_ci {"Host is down", EHOSTDOWN}, 1148c2ecf20Sopenharmony_ci {"No route to host", EHOSTUNREACH}, 1158c2ecf20Sopenharmony_ci {"Operation already in progress", EALREADY}, 1168c2ecf20Sopenharmony_ci {"Operation now in progress", EINPROGRESS}, 1178c2ecf20Sopenharmony_ci {"Is a named type file", EISNAM}, 1188c2ecf20Sopenharmony_ci {"Remote I/O error", EREMOTEIO}, 1198c2ecf20Sopenharmony_ci {"Disk quota exceeded", EDQUOT}, 1208c2ecf20Sopenharmony_ci/* errors from fossil, vacfs, and u9fs */ 1218c2ecf20Sopenharmony_ci {"fid unknown or out of range", EBADF}, 1228c2ecf20Sopenharmony_ci {"permission denied", EACCES}, 1238c2ecf20Sopenharmony_ci {"file does not exist", ENOENT}, 1248c2ecf20Sopenharmony_ci {"authentication failed", ECONNREFUSED}, 1258c2ecf20Sopenharmony_ci {"bad offset in directory read", ESPIPE}, 1268c2ecf20Sopenharmony_ci {"bad use of fid", EBADF}, 1278c2ecf20Sopenharmony_ci {"wstat can't convert between files and directories", EPERM}, 1288c2ecf20Sopenharmony_ci {"directory is not empty", ENOTEMPTY}, 1298c2ecf20Sopenharmony_ci {"file exists", EEXIST}, 1308c2ecf20Sopenharmony_ci {"file already exists", EEXIST}, 1318c2ecf20Sopenharmony_ci {"file or directory already exists", EEXIST}, 1328c2ecf20Sopenharmony_ci {"fid already in use", EBADF}, 1338c2ecf20Sopenharmony_ci {"file in use", ETXTBSY}, 1348c2ecf20Sopenharmony_ci {"i/o error", EIO}, 1358c2ecf20Sopenharmony_ci {"file already open for I/O", ETXTBSY}, 1368c2ecf20Sopenharmony_ci {"illegal mode", EINVAL}, 1378c2ecf20Sopenharmony_ci {"illegal name", ENAMETOOLONG}, 1388c2ecf20Sopenharmony_ci {"not a directory", ENOTDIR}, 1398c2ecf20Sopenharmony_ci {"not a member of proposed group", EPERM}, 1408c2ecf20Sopenharmony_ci {"not owner", EACCES}, 1418c2ecf20Sopenharmony_ci {"only owner can change group in wstat", EACCES}, 1428c2ecf20Sopenharmony_ci {"read only file system", EROFS}, 1438c2ecf20Sopenharmony_ci {"no access to special file", EPERM}, 1448c2ecf20Sopenharmony_ci {"i/o count too large", EIO}, 1458c2ecf20Sopenharmony_ci {"unknown group", EINVAL}, 1468c2ecf20Sopenharmony_ci {"unknown user", EINVAL}, 1478c2ecf20Sopenharmony_ci {"bogus wstat buffer", EPROTO}, 1488c2ecf20Sopenharmony_ci {"exclusive use file already open", EAGAIN}, 1498c2ecf20Sopenharmony_ci {"corrupted directory entry", EIO}, 1508c2ecf20Sopenharmony_ci {"corrupted file entry", EIO}, 1518c2ecf20Sopenharmony_ci {"corrupted block label", EIO}, 1528c2ecf20Sopenharmony_ci {"corrupted meta data", EIO}, 1538c2ecf20Sopenharmony_ci {"illegal offset", EINVAL}, 1548c2ecf20Sopenharmony_ci {"illegal path element", ENOENT}, 1558c2ecf20Sopenharmony_ci {"root of file system is corrupted", EIO}, 1568c2ecf20Sopenharmony_ci {"corrupted super block", EIO}, 1578c2ecf20Sopenharmony_ci {"protocol botch", EPROTO}, 1588c2ecf20Sopenharmony_ci {"file system is full", ENOSPC}, 1598c2ecf20Sopenharmony_ci {"file is in use", EAGAIN}, 1608c2ecf20Sopenharmony_ci {"directory entry is not allocated", ENOENT}, 1618c2ecf20Sopenharmony_ci {"file is read only", EROFS}, 1628c2ecf20Sopenharmony_ci {"file has been removed", EIDRM}, 1638c2ecf20Sopenharmony_ci {"only support truncation to zero length", EPERM}, 1648c2ecf20Sopenharmony_ci {"cannot remove root", EPERM}, 1658c2ecf20Sopenharmony_ci {"file too big", EFBIG}, 1668c2ecf20Sopenharmony_ci {"venti i/o error", EIO}, 1678c2ecf20Sopenharmony_ci /* these are not errors */ 1688c2ecf20Sopenharmony_ci {"u9fs rhostsauth: no authentication required", 0}, 1698c2ecf20Sopenharmony_ci {"u9fs authnone: no authentication required", 0}, 1708c2ecf20Sopenharmony_ci {NULL, -1} 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * p9_error_init - preload mappings into hash list 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ciint p9_error_init(void) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct errormap *c; 1818c2ecf20Sopenharmony_ci int bucket; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* initialize hash table */ 1848c2ecf20Sopenharmony_ci for (bucket = 0; bucket < ERRHASHSZ; bucket++) 1858c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&hash_errmap[bucket]); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* load initial error map into hash table */ 1888c2ecf20Sopenharmony_ci for (c = errmap; c->name != NULL; c++) { 1898c2ecf20Sopenharmony_ci c->namelen = strlen(c->name); 1908c2ecf20Sopenharmony_ci bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ; 1918c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&c->list); 1928c2ecf20Sopenharmony_ci hlist_add_head(&c->list, &hash_errmap[bucket]); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 1; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_error_init); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * errstr2errno - convert error string to error number 2018c2ecf20Sopenharmony_ci * @errstr: error string 2028c2ecf20Sopenharmony_ci * @len: length of error string 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciint p9_errstr2errno(char *errstr, int len) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int errno; 2098c2ecf20Sopenharmony_ci struct errormap *c; 2108c2ecf20Sopenharmony_ci int bucket; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci errno = 0; 2138c2ecf20Sopenharmony_ci c = NULL; 2148c2ecf20Sopenharmony_ci bucket = jhash(errstr, len, 0) % ERRHASHSZ; 2158c2ecf20Sopenharmony_ci hlist_for_each_entry(c, &hash_errmap[bucket], list) { 2168c2ecf20Sopenharmony_ci if (c->namelen == len && !memcmp(c->name, errstr, len)) { 2178c2ecf20Sopenharmony_ci errno = c->val; 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (errno == 0) { 2238c2ecf20Sopenharmony_ci /* TODO: if error isn't found, add it dynamically */ 2248c2ecf20Sopenharmony_ci errstr[len] = 0; 2258c2ecf20Sopenharmony_ci pr_err("%s: server reported unknown error %s\n", 2268c2ecf20Sopenharmony_ci __func__, errstr); 2278c2ecf20Sopenharmony_ci errno = ESERVERFAULT; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return -errno; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_errstr2errno); 233