162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Error string handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Plan 9 uses error strings, Unix uses error numbers. These functions 662306a36Sopenharmony_ci * try to help manage that and provide for dynamically adding error 762306a36Sopenharmony_ci * mappings. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 1062306a36Sopenharmony_ci * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/list.h> 1762306a36Sopenharmony_ci#include <linux/jhash.h> 1862306a36Sopenharmony_ci#include <linux/errno.h> 1962306a36Sopenharmony_ci#include <net/9p/9p.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/** 2262306a36Sopenharmony_ci * struct errormap - map string errors from Plan 9 to Linux numeric ids 2362306a36Sopenharmony_ci * @name: string sent over 9P 2462306a36Sopenharmony_ci * @val: numeric id most closely representing @name 2562306a36Sopenharmony_ci * @namelen: length of string 2662306a36Sopenharmony_ci * @list: hash-table list for string lookup 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistruct errormap { 2962306a36Sopenharmony_ci char *name; 3062306a36Sopenharmony_ci int val; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci int namelen; 3362306a36Sopenharmony_ci struct hlist_node list; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define ERRHASHSZ 32 3762306a36Sopenharmony_cistatic struct hlist_head hash_errmap[ERRHASHSZ]; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* FixMe - reduce to a reasonable size */ 4062306a36Sopenharmony_cistatic struct errormap errmap[] = { 4162306a36Sopenharmony_ci {"Operation not permitted", EPERM}, 4262306a36Sopenharmony_ci {"wstat prohibited", EPERM}, 4362306a36Sopenharmony_ci {"No such file or directory", ENOENT}, 4462306a36Sopenharmony_ci {"directory entry not found", ENOENT}, 4562306a36Sopenharmony_ci {"file not found", ENOENT}, 4662306a36Sopenharmony_ci {"Interrupted system call", EINTR}, 4762306a36Sopenharmony_ci {"Input/output error", EIO}, 4862306a36Sopenharmony_ci {"No such device or address", ENXIO}, 4962306a36Sopenharmony_ci {"Argument list too long", E2BIG}, 5062306a36Sopenharmony_ci {"Bad file descriptor", EBADF}, 5162306a36Sopenharmony_ci {"Resource temporarily unavailable", EAGAIN}, 5262306a36Sopenharmony_ci {"Cannot allocate memory", ENOMEM}, 5362306a36Sopenharmony_ci {"Permission denied", EACCES}, 5462306a36Sopenharmony_ci {"Bad address", EFAULT}, 5562306a36Sopenharmony_ci {"Block device required", ENOTBLK}, 5662306a36Sopenharmony_ci {"Device or resource busy", EBUSY}, 5762306a36Sopenharmony_ci {"File exists", EEXIST}, 5862306a36Sopenharmony_ci {"Invalid cross-device link", EXDEV}, 5962306a36Sopenharmony_ci {"No such device", ENODEV}, 6062306a36Sopenharmony_ci {"Not a directory", ENOTDIR}, 6162306a36Sopenharmony_ci {"Is a directory", EISDIR}, 6262306a36Sopenharmony_ci {"Invalid argument", EINVAL}, 6362306a36Sopenharmony_ci {"Too many open files in system", ENFILE}, 6462306a36Sopenharmony_ci {"Too many open files", EMFILE}, 6562306a36Sopenharmony_ci {"Text file busy", ETXTBSY}, 6662306a36Sopenharmony_ci {"File too large", EFBIG}, 6762306a36Sopenharmony_ci {"No space left on device", ENOSPC}, 6862306a36Sopenharmony_ci {"Illegal seek", ESPIPE}, 6962306a36Sopenharmony_ci {"Read-only file system", EROFS}, 7062306a36Sopenharmony_ci {"Too many links", EMLINK}, 7162306a36Sopenharmony_ci {"Broken pipe", EPIPE}, 7262306a36Sopenharmony_ci {"Numerical argument out of domain", EDOM}, 7362306a36Sopenharmony_ci {"Numerical result out of range", ERANGE}, 7462306a36Sopenharmony_ci {"Resource deadlock avoided", EDEADLK}, 7562306a36Sopenharmony_ci {"File name too long", ENAMETOOLONG}, 7662306a36Sopenharmony_ci {"No locks available", ENOLCK}, 7762306a36Sopenharmony_ci {"Function not implemented", ENOSYS}, 7862306a36Sopenharmony_ci {"Directory not empty", ENOTEMPTY}, 7962306a36Sopenharmony_ci {"Too many levels of symbolic links", ELOOP}, 8062306a36Sopenharmony_ci {"No message of desired type", ENOMSG}, 8162306a36Sopenharmony_ci {"Identifier removed", EIDRM}, 8262306a36Sopenharmony_ci {"No data available", ENODATA}, 8362306a36Sopenharmony_ci {"Machine is not on the network", ENONET}, 8462306a36Sopenharmony_ci {"Package not installed", ENOPKG}, 8562306a36Sopenharmony_ci {"Object is remote", EREMOTE}, 8662306a36Sopenharmony_ci {"Link has been severed", ENOLINK}, 8762306a36Sopenharmony_ci {"Communication error on send", ECOMM}, 8862306a36Sopenharmony_ci {"Protocol error", EPROTO}, 8962306a36Sopenharmony_ci {"Bad message", EBADMSG}, 9062306a36Sopenharmony_ci {"File descriptor in bad state", EBADFD}, 9162306a36Sopenharmony_ci {"Streams pipe error", ESTRPIPE}, 9262306a36Sopenharmony_ci {"Too many users", EUSERS}, 9362306a36Sopenharmony_ci {"Socket operation on non-socket", ENOTSOCK}, 9462306a36Sopenharmony_ci {"Message too long", EMSGSIZE}, 9562306a36Sopenharmony_ci {"Protocol not available", ENOPROTOOPT}, 9662306a36Sopenharmony_ci {"Protocol not supported", EPROTONOSUPPORT}, 9762306a36Sopenharmony_ci {"Socket type not supported", ESOCKTNOSUPPORT}, 9862306a36Sopenharmony_ci {"Operation not supported", EOPNOTSUPP}, 9962306a36Sopenharmony_ci {"Protocol family not supported", EPFNOSUPPORT}, 10062306a36Sopenharmony_ci {"Network is down", ENETDOWN}, 10162306a36Sopenharmony_ci {"Network is unreachable", ENETUNREACH}, 10262306a36Sopenharmony_ci {"Network dropped connection on reset", ENETRESET}, 10362306a36Sopenharmony_ci {"Software caused connection abort", ECONNABORTED}, 10462306a36Sopenharmony_ci {"Connection reset by peer", ECONNRESET}, 10562306a36Sopenharmony_ci {"No buffer space available", ENOBUFS}, 10662306a36Sopenharmony_ci {"Transport endpoint is already connected", EISCONN}, 10762306a36Sopenharmony_ci {"Transport endpoint is not connected", ENOTCONN}, 10862306a36Sopenharmony_ci {"Cannot send after transport endpoint shutdown", ESHUTDOWN}, 10962306a36Sopenharmony_ci {"Connection timed out", ETIMEDOUT}, 11062306a36Sopenharmony_ci {"Connection refused", ECONNREFUSED}, 11162306a36Sopenharmony_ci {"Host is down", EHOSTDOWN}, 11262306a36Sopenharmony_ci {"No route to host", EHOSTUNREACH}, 11362306a36Sopenharmony_ci {"Operation already in progress", EALREADY}, 11462306a36Sopenharmony_ci {"Operation now in progress", EINPROGRESS}, 11562306a36Sopenharmony_ci {"Is a named type file", EISNAM}, 11662306a36Sopenharmony_ci {"Remote I/O error", EREMOTEIO}, 11762306a36Sopenharmony_ci {"Disk quota exceeded", EDQUOT}, 11862306a36Sopenharmony_ci/* errors from fossil, vacfs, and u9fs */ 11962306a36Sopenharmony_ci {"fid unknown or out of range", EBADF}, 12062306a36Sopenharmony_ci {"permission denied", EACCES}, 12162306a36Sopenharmony_ci {"file does not exist", ENOENT}, 12262306a36Sopenharmony_ci {"authentication failed", ECONNREFUSED}, 12362306a36Sopenharmony_ci {"bad offset in directory read", ESPIPE}, 12462306a36Sopenharmony_ci {"bad use of fid", EBADF}, 12562306a36Sopenharmony_ci {"wstat can't convert between files and directories", EPERM}, 12662306a36Sopenharmony_ci {"directory is not empty", ENOTEMPTY}, 12762306a36Sopenharmony_ci {"file exists", EEXIST}, 12862306a36Sopenharmony_ci {"file already exists", EEXIST}, 12962306a36Sopenharmony_ci {"file or directory already exists", EEXIST}, 13062306a36Sopenharmony_ci {"fid already in use", EBADF}, 13162306a36Sopenharmony_ci {"file in use", ETXTBSY}, 13262306a36Sopenharmony_ci {"i/o error", EIO}, 13362306a36Sopenharmony_ci {"file already open for I/O", ETXTBSY}, 13462306a36Sopenharmony_ci {"illegal mode", EINVAL}, 13562306a36Sopenharmony_ci {"illegal name", ENAMETOOLONG}, 13662306a36Sopenharmony_ci {"not a directory", ENOTDIR}, 13762306a36Sopenharmony_ci {"not a member of proposed group", EPERM}, 13862306a36Sopenharmony_ci {"not owner", EACCES}, 13962306a36Sopenharmony_ci {"only owner can change group in wstat", EACCES}, 14062306a36Sopenharmony_ci {"read only file system", EROFS}, 14162306a36Sopenharmony_ci {"no access to special file", EPERM}, 14262306a36Sopenharmony_ci {"i/o count too large", EIO}, 14362306a36Sopenharmony_ci {"unknown group", EINVAL}, 14462306a36Sopenharmony_ci {"unknown user", EINVAL}, 14562306a36Sopenharmony_ci {"bogus wstat buffer", EPROTO}, 14662306a36Sopenharmony_ci {"exclusive use file already open", EAGAIN}, 14762306a36Sopenharmony_ci {"corrupted directory entry", EIO}, 14862306a36Sopenharmony_ci {"corrupted file entry", EIO}, 14962306a36Sopenharmony_ci {"corrupted block label", EIO}, 15062306a36Sopenharmony_ci {"corrupted meta data", EIO}, 15162306a36Sopenharmony_ci {"illegal offset", EINVAL}, 15262306a36Sopenharmony_ci {"illegal path element", ENOENT}, 15362306a36Sopenharmony_ci {"root of file system is corrupted", EIO}, 15462306a36Sopenharmony_ci {"corrupted super block", EIO}, 15562306a36Sopenharmony_ci {"protocol botch", EPROTO}, 15662306a36Sopenharmony_ci {"file system is full", ENOSPC}, 15762306a36Sopenharmony_ci {"file is in use", EAGAIN}, 15862306a36Sopenharmony_ci {"directory entry is not allocated", ENOENT}, 15962306a36Sopenharmony_ci {"file is read only", EROFS}, 16062306a36Sopenharmony_ci {"file has been removed", EIDRM}, 16162306a36Sopenharmony_ci {"only support truncation to zero length", EPERM}, 16262306a36Sopenharmony_ci {"cannot remove root", EPERM}, 16362306a36Sopenharmony_ci {"file too big", EFBIG}, 16462306a36Sopenharmony_ci {"venti i/o error", EIO}, 16562306a36Sopenharmony_ci /* these are not errors */ 16662306a36Sopenharmony_ci {"u9fs rhostsauth: no authentication required", 0}, 16762306a36Sopenharmony_ci {"u9fs authnone: no authentication required", 0}, 16862306a36Sopenharmony_ci {NULL, -1} 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * p9_error_init - preload mappings into hash list 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciint p9_error_init(void) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct errormap *c; 17962306a36Sopenharmony_ci int bucket; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* initialize hash table */ 18262306a36Sopenharmony_ci for (bucket = 0; bucket < ERRHASHSZ; bucket++) 18362306a36Sopenharmony_ci INIT_HLIST_HEAD(&hash_errmap[bucket]); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* load initial error map into hash table */ 18662306a36Sopenharmony_ci for (c = errmap; c->name; c++) { 18762306a36Sopenharmony_ci c->namelen = strlen(c->name); 18862306a36Sopenharmony_ci bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ; 18962306a36Sopenharmony_ci INIT_HLIST_NODE(&c->list); 19062306a36Sopenharmony_ci hlist_add_head(&c->list, &hash_errmap[bucket]); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 1; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ciEXPORT_SYMBOL(p9_error_init); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * p9_errstr2errno - convert error string to error number 19962306a36Sopenharmony_ci * @errstr: error string 20062306a36Sopenharmony_ci * @len: length of error string 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ciint p9_errstr2errno(char *errstr, int len) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int errno; 20762306a36Sopenharmony_ci struct errormap *c; 20862306a36Sopenharmony_ci int bucket; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci errno = 0; 21162306a36Sopenharmony_ci c = NULL; 21262306a36Sopenharmony_ci bucket = jhash(errstr, len, 0) % ERRHASHSZ; 21362306a36Sopenharmony_ci hlist_for_each_entry(c, &hash_errmap[bucket], list) { 21462306a36Sopenharmony_ci if (c->namelen == len && !memcmp(c->name, errstr, len)) { 21562306a36Sopenharmony_ci errno = c->val; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (errno == 0) { 22162306a36Sopenharmony_ci /* TODO: if error isn't found, add it dynamically */ 22262306a36Sopenharmony_ci errstr[len] = 0; 22362306a36Sopenharmony_ci pr_err("%s: server reported unknown error %s\n", 22462306a36Sopenharmony_ci __func__, errstr); 22562306a36Sopenharmony_ci errno = ESERVERFAULT; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return -errno; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ciEXPORT_SYMBOL(p9_errstr2errno); 231