18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/9p/protocol.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * 9P Protocol Support Code 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Base on code from Anthony Liguori <aliguori@us.ibm.com> 108c2ecf20Sopenharmony_ci * Copyright (C) 2008 by IBM, Corp. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/sched.h> 198c2ecf20Sopenharmony_ci#include <linux/stddef.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/uio.h> 228c2ecf20Sopenharmony_ci#include <net/9p/9p.h> 238c2ecf20Sopenharmony_ci#include <net/9p/client.h> 248c2ecf20Sopenharmony_ci#include "protocol.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <trace/events/9p.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int 298c2ecf20Sopenharmony_cip9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_civoid p9stat_free(struct p9_wstat *stbuf) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci kfree(stbuf->name); 348c2ecf20Sopenharmony_ci stbuf->name = NULL; 358c2ecf20Sopenharmony_ci kfree(stbuf->uid); 368c2ecf20Sopenharmony_ci stbuf->uid = NULL; 378c2ecf20Sopenharmony_ci kfree(stbuf->gid); 388c2ecf20Sopenharmony_ci stbuf->gid = NULL; 398c2ecf20Sopenharmony_ci kfree(stbuf->muid); 408c2ecf20Sopenharmony_ci stbuf->muid = NULL; 418c2ecf20Sopenharmony_ci kfree(stbuf->extension); 428c2ecf20Sopenharmony_ci stbuf->extension = NULL; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9stat_free); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cisize_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci size_t len = min(pdu->size - pdu->offset, size); 498c2ecf20Sopenharmony_ci memcpy(data, &pdu->sdata[pdu->offset], len); 508c2ecf20Sopenharmony_ci pdu->offset += len; 518c2ecf20Sopenharmony_ci return size - len; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci size_t len = min(pdu->capacity - pdu->size, size); 578c2ecf20Sopenharmony_ci memcpy(&pdu->sdata[pdu->size], data, len); 588c2ecf20Sopenharmony_ci pdu->size += len; 598c2ecf20Sopenharmony_ci return size - len; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic size_t 638c2ecf20Sopenharmony_cipdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci size_t len = min(pdu->capacity - pdu->size, size); 668c2ecf20Sopenharmony_ci struct iov_iter i = *from; 678c2ecf20Sopenharmony_ci if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, &i)) 688c2ecf20Sopenharmony_ci len = 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci pdu->size += len; 718c2ecf20Sopenharmony_ci return size - len; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci b - int8_t 768c2ecf20Sopenharmony_ci w - int16_t 778c2ecf20Sopenharmony_ci d - int32_t 788c2ecf20Sopenharmony_ci q - int64_t 798c2ecf20Sopenharmony_ci s - string 808c2ecf20Sopenharmony_ci u - numeric uid 818c2ecf20Sopenharmony_ci g - numeric gid 828c2ecf20Sopenharmony_ci S - stat 838c2ecf20Sopenharmony_ci Q - qid 848c2ecf20Sopenharmony_ci D - data blob (int32_t size followed by void *, results are not freed) 858c2ecf20Sopenharmony_ci T - array of strings (int16_t count, followed by strings) 868c2ecf20Sopenharmony_ci R - array of qids (int16_t count, followed by qids) 878c2ecf20Sopenharmony_ci A - stat for 9p2000.L (p9_stat_dotl) 888c2ecf20Sopenharmony_ci ? - if optional = 1, continue parsing 898c2ecf20Sopenharmony_ci*/ 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int 928c2ecf20Sopenharmony_cip9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, 938c2ecf20Sopenharmony_ci va_list ap) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci const char *ptr; 968c2ecf20Sopenharmony_ci int errcode = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci for (ptr = fmt; *ptr; ptr++) { 998c2ecf20Sopenharmony_ci switch (*ptr) { 1008c2ecf20Sopenharmony_ci case 'b':{ 1018c2ecf20Sopenharmony_ci int8_t *val = va_arg(ap, int8_t *); 1028c2ecf20Sopenharmony_ci if (pdu_read(pdu, val, sizeof(*val))) { 1038c2ecf20Sopenharmony_ci errcode = -EFAULT; 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case 'w':{ 1098c2ecf20Sopenharmony_ci int16_t *val = va_arg(ap, int16_t *); 1108c2ecf20Sopenharmony_ci __le16 le_val; 1118c2ecf20Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 1128c2ecf20Sopenharmony_ci errcode = -EFAULT; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci *val = le16_to_cpu(le_val); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case 'd':{ 1198c2ecf20Sopenharmony_ci int32_t *val = va_arg(ap, int32_t *); 1208c2ecf20Sopenharmony_ci __le32 le_val; 1218c2ecf20Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 1228c2ecf20Sopenharmony_ci errcode = -EFAULT; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci *val = le32_to_cpu(le_val); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case 'q':{ 1298c2ecf20Sopenharmony_ci int64_t *val = va_arg(ap, int64_t *); 1308c2ecf20Sopenharmony_ci __le64 le_val; 1318c2ecf20Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 1328c2ecf20Sopenharmony_ci errcode = -EFAULT; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci *val = le64_to_cpu(le_val); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci case 's':{ 1398c2ecf20Sopenharmony_ci char **sptr = va_arg(ap, char **); 1408c2ecf20Sopenharmony_ci uint16_t len; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, 1438c2ecf20Sopenharmony_ci "w", &len); 1448c2ecf20Sopenharmony_ci if (errcode) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci *sptr = kmalloc(len + 1, GFP_NOFS); 1488c2ecf20Sopenharmony_ci if (*sptr == NULL) { 1498c2ecf20Sopenharmony_ci errcode = -ENOMEM; 1508c2ecf20Sopenharmony_ci break; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci if (pdu_read(pdu, *sptr, len)) { 1538c2ecf20Sopenharmony_ci errcode = -EFAULT; 1548c2ecf20Sopenharmony_ci kfree(*sptr); 1558c2ecf20Sopenharmony_ci *sptr = NULL; 1568c2ecf20Sopenharmony_ci } else 1578c2ecf20Sopenharmony_ci (*sptr)[len] = 0; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci case 'u': { 1618c2ecf20Sopenharmony_ci kuid_t *uid = va_arg(ap, kuid_t *); 1628c2ecf20Sopenharmony_ci __le32 le_val; 1638c2ecf20Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 1648c2ecf20Sopenharmony_ci errcode = -EFAULT; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci *uid = make_kuid(&init_user_ns, 1688c2ecf20Sopenharmony_ci le32_to_cpu(le_val)); 1698c2ecf20Sopenharmony_ci } break; 1708c2ecf20Sopenharmony_ci case 'g': { 1718c2ecf20Sopenharmony_ci kgid_t *gid = va_arg(ap, kgid_t *); 1728c2ecf20Sopenharmony_ci __le32 le_val; 1738c2ecf20Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 1748c2ecf20Sopenharmony_ci errcode = -EFAULT; 1758c2ecf20Sopenharmony_ci break; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci *gid = make_kgid(&init_user_ns, 1788c2ecf20Sopenharmony_ci le32_to_cpu(le_val)); 1798c2ecf20Sopenharmony_ci } break; 1808c2ecf20Sopenharmony_ci case 'Q':{ 1818c2ecf20Sopenharmony_ci struct p9_qid *qid = 1828c2ecf20Sopenharmony_ci va_arg(ap, struct p9_qid *); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, "bdq", 1858c2ecf20Sopenharmony_ci &qid->type, &qid->version, 1868c2ecf20Sopenharmony_ci &qid->path); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case 'S':{ 1908c2ecf20Sopenharmony_ci struct p9_wstat *stbuf = 1918c2ecf20Sopenharmony_ci va_arg(ap, struct p9_wstat *); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci memset(stbuf, 0, sizeof(struct p9_wstat)); 1948c2ecf20Sopenharmony_ci stbuf->n_uid = stbuf->n_muid = INVALID_UID; 1958c2ecf20Sopenharmony_ci stbuf->n_gid = INVALID_GID; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci errcode = 1988c2ecf20Sopenharmony_ci p9pdu_readf(pdu, proto_version, 1998c2ecf20Sopenharmony_ci "wwdQdddqssss?sugu", 2008c2ecf20Sopenharmony_ci &stbuf->size, &stbuf->type, 2018c2ecf20Sopenharmony_ci &stbuf->dev, &stbuf->qid, 2028c2ecf20Sopenharmony_ci &stbuf->mode, &stbuf->atime, 2038c2ecf20Sopenharmony_ci &stbuf->mtime, &stbuf->length, 2048c2ecf20Sopenharmony_ci &stbuf->name, &stbuf->uid, 2058c2ecf20Sopenharmony_ci &stbuf->gid, &stbuf->muid, 2068c2ecf20Sopenharmony_ci &stbuf->extension, 2078c2ecf20Sopenharmony_ci &stbuf->n_uid, &stbuf->n_gid, 2088c2ecf20Sopenharmony_ci &stbuf->n_muid); 2098c2ecf20Sopenharmony_ci if (errcode) 2108c2ecf20Sopenharmony_ci p9stat_free(stbuf); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case 'D':{ 2148c2ecf20Sopenharmony_ci uint32_t *count = va_arg(ap, uint32_t *); 2158c2ecf20Sopenharmony_ci void **data = va_arg(ap, void **); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci errcode = 2188c2ecf20Sopenharmony_ci p9pdu_readf(pdu, proto_version, "d", count); 2198c2ecf20Sopenharmony_ci if (!errcode) { 2208c2ecf20Sopenharmony_ci *count = 2218c2ecf20Sopenharmony_ci min_t(uint32_t, *count, 2228c2ecf20Sopenharmony_ci pdu->size - pdu->offset); 2238c2ecf20Sopenharmony_ci *data = &pdu->sdata[pdu->offset]; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case 'T':{ 2288c2ecf20Sopenharmony_ci uint16_t *nwname = va_arg(ap, uint16_t *); 2298c2ecf20Sopenharmony_ci char ***wnames = va_arg(ap, char ***); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci *wnames = NULL; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, 2348c2ecf20Sopenharmony_ci "w", nwname); 2358c2ecf20Sopenharmony_ci if (!errcode) { 2368c2ecf20Sopenharmony_ci *wnames = 2378c2ecf20Sopenharmony_ci kmalloc_array(*nwname, 2388c2ecf20Sopenharmony_ci sizeof(char *), 2398c2ecf20Sopenharmony_ci GFP_NOFS); 2408c2ecf20Sopenharmony_ci if (!*wnames) 2418c2ecf20Sopenharmony_ci errcode = -ENOMEM; 2428c2ecf20Sopenharmony_ci else 2438c2ecf20Sopenharmony_ci (*wnames)[0] = NULL; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!errcode) { 2478c2ecf20Sopenharmony_ci int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (i = 0; i < *nwname; i++) { 2508c2ecf20Sopenharmony_ci errcode = 2518c2ecf20Sopenharmony_ci p9pdu_readf(pdu, 2528c2ecf20Sopenharmony_ci proto_version, 2538c2ecf20Sopenharmony_ci "s", 2548c2ecf20Sopenharmony_ci &(*wnames)[i]); 2558c2ecf20Sopenharmony_ci if (errcode) { 2568c2ecf20Sopenharmony_ci (*wnames)[i] = NULL; 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (errcode) { 2638c2ecf20Sopenharmony_ci if (*wnames) { 2648c2ecf20Sopenharmony_ci int i; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci for (i = 0; i < *nwname; i++) { 2678c2ecf20Sopenharmony_ci if (!(*wnames)[i]) 2688c2ecf20Sopenharmony_ci break; 2698c2ecf20Sopenharmony_ci kfree((*wnames)[i]); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci kfree(*wnames); 2728c2ecf20Sopenharmony_ci *wnames = NULL; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci case 'R':{ 2788c2ecf20Sopenharmony_ci uint16_t *nwqid = va_arg(ap, uint16_t *); 2798c2ecf20Sopenharmony_ci struct p9_qid **wqids = 2808c2ecf20Sopenharmony_ci va_arg(ap, struct p9_qid **); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci *wqids = NULL; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci errcode = 2858c2ecf20Sopenharmony_ci p9pdu_readf(pdu, proto_version, "w", nwqid); 2868c2ecf20Sopenharmony_ci if (!errcode) { 2878c2ecf20Sopenharmony_ci *wqids = 2888c2ecf20Sopenharmony_ci kmalloc_array(*nwqid, 2898c2ecf20Sopenharmony_ci sizeof(struct p9_qid), 2908c2ecf20Sopenharmony_ci GFP_NOFS); 2918c2ecf20Sopenharmony_ci if (*wqids == NULL) 2928c2ecf20Sopenharmony_ci errcode = -ENOMEM; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (!errcode) { 2968c2ecf20Sopenharmony_ci int i; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci for (i = 0; i < *nwqid; i++) { 2998c2ecf20Sopenharmony_ci errcode = 3008c2ecf20Sopenharmony_ci p9pdu_readf(pdu, 3018c2ecf20Sopenharmony_ci proto_version, 3028c2ecf20Sopenharmony_ci "Q", 3038c2ecf20Sopenharmony_ci &(*wqids)[i]); 3048c2ecf20Sopenharmony_ci if (errcode) 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (errcode) { 3108c2ecf20Sopenharmony_ci kfree(*wqids); 3118c2ecf20Sopenharmony_ci *wqids = NULL; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci case 'A': { 3168c2ecf20Sopenharmony_ci struct p9_stat_dotl *stbuf = 3178c2ecf20Sopenharmony_ci va_arg(ap, struct p9_stat_dotl *); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci memset(stbuf, 0, sizeof(struct p9_stat_dotl)); 3208c2ecf20Sopenharmony_ci errcode = 3218c2ecf20Sopenharmony_ci p9pdu_readf(pdu, proto_version, 3228c2ecf20Sopenharmony_ci "qQdugqqqqqqqqqqqqqqq", 3238c2ecf20Sopenharmony_ci &stbuf->st_result_mask, 3248c2ecf20Sopenharmony_ci &stbuf->qid, 3258c2ecf20Sopenharmony_ci &stbuf->st_mode, 3268c2ecf20Sopenharmony_ci &stbuf->st_uid, &stbuf->st_gid, 3278c2ecf20Sopenharmony_ci &stbuf->st_nlink, 3288c2ecf20Sopenharmony_ci &stbuf->st_rdev, &stbuf->st_size, 3298c2ecf20Sopenharmony_ci &stbuf->st_blksize, &stbuf->st_blocks, 3308c2ecf20Sopenharmony_ci &stbuf->st_atime_sec, 3318c2ecf20Sopenharmony_ci &stbuf->st_atime_nsec, 3328c2ecf20Sopenharmony_ci &stbuf->st_mtime_sec, 3338c2ecf20Sopenharmony_ci &stbuf->st_mtime_nsec, 3348c2ecf20Sopenharmony_ci &stbuf->st_ctime_sec, 3358c2ecf20Sopenharmony_ci &stbuf->st_ctime_nsec, 3368c2ecf20Sopenharmony_ci &stbuf->st_btime_sec, 3378c2ecf20Sopenharmony_ci &stbuf->st_btime_nsec, 3388c2ecf20Sopenharmony_ci &stbuf->st_gen, 3398c2ecf20Sopenharmony_ci &stbuf->st_data_version); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci case '?': 3438c2ecf20Sopenharmony_ci if ((proto_version != p9_proto_2000u) && 3448c2ecf20Sopenharmony_ci (proto_version != p9_proto_2000L)) 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci default: 3488c2ecf20Sopenharmony_ci BUG(); 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (errcode) 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return errcode; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ciint 3608c2ecf20Sopenharmony_cip9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, 3618c2ecf20Sopenharmony_ci va_list ap) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci const char *ptr; 3648c2ecf20Sopenharmony_ci int errcode = 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci for (ptr = fmt; *ptr; ptr++) { 3678c2ecf20Sopenharmony_ci switch (*ptr) { 3688c2ecf20Sopenharmony_ci case 'b':{ 3698c2ecf20Sopenharmony_ci int8_t val = va_arg(ap, int); 3708c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 3718c2ecf20Sopenharmony_ci errcode = -EFAULT; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci case 'w':{ 3758c2ecf20Sopenharmony_ci __le16 val = cpu_to_le16(va_arg(ap, int)); 3768c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 3778c2ecf20Sopenharmony_ci errcode = -EFAULT; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci case 'd':{ 3818c2ecf20Sopenharmony_ci __le32 val = cpu_to_le32(va_arg(ap, int32_t)); 3828c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 3838c2ecf20Sopenharmony_ci errcode = -EFAULT; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case 'q':{ 3878c2ecf20Sopenharmony_ci __le64 val = cpu_to_le64(va_arg(ap, int64_t)); 3888c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 3898c2ecf20Sopenharmony_ci errcode = -EFAULT; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case 's':{ 3938c2ecf20Sopenharmony_ci const char *sptr = va_arg(ap, const char *); 3948c2ecf20Sopenharmony_ci uint16_t len = 0; 3958c2ecf20Sopenharmony_ci if (sptr) 3968c2ecf20Sopenharmony_ci len = min_t(size_t, strlen(sptr), 3978c2ecf20Sopenharmony_ci USHRT_MAX); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, 4008c2ecf20Sopenharmony_ci "w", len); 4018c2ecf20Sopenharmony_ci if (!errcode && pdu_write(pdu, sptr, len)) 4028c2ecf20Sopenharmony_ci errcode = -EFAULT; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci case 'u': { 4068c2ecf20Sopenharmony_ci kuid_t uid = va_arg(ap, kuid_t); 4078c2ecf20Sopenharmony_ci __le32 val = cpu_to_le32( 4088c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, uid)); 4098c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 4108c2ecf20Sopenharmony_ci errcode = -EFAULT; 4118c2ecf20Sopenharmony_ci } break; 4128c2ecf20Sopenharmony_ci case 'g': { 4138c2ecf20Sopenharmony_ci kgid_t gid = va_arg(ap, kgid_t); 4148c2ecf20Sopenharmony_ci __le32 val = cpu_to_le32( 4158c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, gid)); 4168c2ecf20Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 4178c2ecf20Sopenharmony_ci errcode = -EFAULT; 4188c2ecf20Sopenharmony_ci } break; 4198c2ecf20Sopenharmony_ci case 'Q':{ 4208c2ecf20Sopenharmony_ci const struct p9_qid *qid = 4218c2ecf20Sopenharmony_ci va_arg(ap, const struct p9_qid *); 4228c2ecf20Sopenharmony_ci errcode = 4238c2ecf20Sopenharmony_ci p9pdu_writef(pdu, proto_version, "bdq", 4248c2ecf20Sopenharmony_ci qid->type, qid->version, 4258c2ecf20Sopenharmony_ci qid->path); 4268c2ecf20Sopenharmony_ci } break; 4278c2ecf20Sopenharmony_ci case 'S':{ 4288c2ecf20Sopenharmony_ci const struct p9_wstat *stbuf = 4298c2ecf20Sopenharmony_ci va_arg(ap, const struct p9_wstat *); 4308c2ecf20Sopenharmony_ci errcode = 4318c2ecf20Sopenharmony_ci p9pdu_writef(pdu, proto_version, 4328c2ecf20Sopenharmony_ci "wwdQdddqssss?sugu", 4338c2ecf20Sopenharmony_ci stbuf->size, stbuf->type, 4348c2ecf20Sopenharmony_ci stbuf->dev, &stbuf->qid, 4358c2ecf20Sopenharmony_ci stbuf->mode, stbuf->atime, 4368c2ecf20Sopenharmony_ci stbuf->mtime, stbuf->length, 4378c2ecf20Sopenharmony_ci stbuf->name, stbuf->uid, 4388c2ecf20Sopenharmony_ci stbuf->gid, stbuf->muid, 4398c2ecf20Sopenharmony_ci stbuf->extension, stbuf->n_uid, 4408c2ecf20Sopenharmony_ci stbuf->n_gid, stbuf->n_muid); 4418c2ecf20Sopenharmony_ci } break; 4428c2ecf20Sopenharmony_ci case 'V':{ 4438c2ecf20Sopenharmony_ci uint32_t count = va_arg(ap, uint32_t); 4448c2ecf20Sopenharmony_ci struct iov_iter *from = 4458c2ecf20Sopenharmony_ci va_arg(ap, struct iov_iter *); 4468c2ecf20Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "d", 4478c2ecf20Sopenharmony_ci count); 4488c2ecf20Sopenharmony_ci if (!errcode && pdu_write_u(pdu, from, count)) 4498c2ecf20Sopenharmony_ci errcode = -EFAULT; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci break; 4528c2ecf20Sopenharmony_ci case 'T':{ 4538c2ecf20Sopenharmony_ci uint16_t nwname = va_arg(ap, int); 4548c2ecf20Sopenharmony_ci const char **wnames = va_arg(ap, const char **); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "w", 4578c2ecf20Sopenharmony_ci nwname); 4588c2ecf20Sopenharmony_ci if (!errcode) { 4598c2ecf20Sopenharmony_ci int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (i = 0; i < nwname; i++) { 4628c2ecf20Sopenharmony_ci errcode = 4638c2ecf20Sopenharmony_ci p9pdu_writef(pdu, 4648c2ecf20Sopenharmony_ci proto_version, 4658c2ecf20Sopenharmony_ci "s", 4668c2ecf20Sopenharmony_ci wnames[i]); 4678c2ecf20Sopenharmony_ci if (errcode) 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case 'R':{ 4748c2ecf20Sopenharmony_ci uint16_t nwqid = va_arg(ap, int); 4758c2ecf20Sopenharmony_ci struct p9_qid *wqids = 4768c2ecf20Sopenharmony_ci va_arg(ap, struct p9_qid *); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "w", 4798c2ecf20Sopenharmony_ci nwqid); 4808c2ecf20Sopenharmony_ci if (!errcode) { 4818c2ecf20Sopenharmony_ci int i; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci for (i = 0; i < nwqid; i++) { 4848c2ecf20Sopenharmony_ci errcode = 4858c2ecf20Sopenharmony_ci p9pdu_writef(pdu, 4868c2ecf20Sopenharmony_ci proto_version, 4878c2ecf20Sopenharmony_ci "Q", 4888c2ecf20Sopenharmony_ci &wqids[i]); 4898c2ecf20Sopenharmony_ci if (errcode) 4908c2ecf20Sopenharmony_ci break; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case 'I':{ 4968c2ecf20Sopenharmony_ci struct p9_iattr_dotl *p9attr = va_arg(ap, 4978c2ecf20Sopenharmony_ci struct p9_iattr_dotl *); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, 5008c2ecf20Sopenharmony_ci "ddugqqqqq", 5018c2ecf20Sopenharmony_ci p9attr->valid, 5028c2ecf20Sopenharmony_ci p9attr->mode, 5038c2ecf20Sopenharmony_ci p9attr->uid, 5048c2ecf20Sopenharmony_ci p9attr->gid, 5058c2ecf20Sopenharmony_ci p9attr->size, 5068c2ecf20Sopenharmony_ci p9attr->atime_sec, 5078c2ecf20Sopenharmony_ci p9attr->atime_nsec, 5088c2ecf20Sopenharmony_ci p9attr->mtime_sec, 5098c2ecf20Sopenharmony_ci p9attr->mtime_nsec); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case '?': 5138c2ecf20Sopenharmony_ci if ((proto_version != p9_proto_2000u) && 5148c2ecf20Sopenharmony_ci (proto_version != p9_proto_2000L)) 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci default: 5188c2ecf20Sopenharmony_ci BUG(); 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (errcode) 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return errcode; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ciint p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci va_list ap; 5328c2ecf20Sopenharmony_ci int ret; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci va_start(ap, fmt); 5358c2ecf20Sopenharmony_ci ret = p9pdu_vreadf(pdu, proto_version, fmt, ap); 5368c2ecf20Sopenharmony_ci va_end(ap); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int 5428c2ecf20Sopenharmony_cip9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci va_list ap; 5458c2ecf20Sopenharmony_ci int ret; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci va_start(ap, fmt); 5488c2ecf20Sopenharmony_ci ret = p9pdu_vwritef(pdu, proto_version, fmt, ap); 5498c2ecf20Sopenharmony_ci va_end(ap); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return ret; 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ciint p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct p9_fcall fake_pdu; 5578c2ecf20Sopenharmony_ci int ret; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci fake_pdu.size = len; 5608c2ecf20Sopenharmony_ci fake_pdu.capacity = len; 5618c2ecf20Sopenharmony_ci fake_pdu.sdata = buf; 5628c2ecf20Sopenharmony_ci fake_pdu.offset = 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st); 5658c2ecf20Sopenharmony_ci if (ret) { 5668c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); 5678c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &fake_pdu); 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return fake_pdu.offset; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9stat_read); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ciint p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci pdu->id = type; 5788c2ecf20Sopenharmony_ci return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ciint p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci int size = pdu->size; 5848c2ecf20Sopenharmony_ci int err; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci pdu->size = 0; 5878c2ecf20Sopenharmony_ci err = p9pdu_writef(pdu, 0, "d", size); 5888c2ecf20Sopenharmony_ci pdu->size = size; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, pdu); 5918c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", 5928c2ecf20Sopenharmony_ci pdu->size, pdu->id, pdu->tag); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return err; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_civoid p9pdu_reset(struct p9_fcall *pdu) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci pdu->offset = 0; 6008c2ecf20Sopenharmony_ci pdu->size = 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ciint p9dirent_read(struct p9_client *clnt, char *buf, int len, 6048c2ecf20Sopenharmony_ci struct p9_dirent *dirent) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct p9_fcall fake_pdu; 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci char *nameptr; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci fake_pdu.size = len; 6118c2ecf20Sopenharmony_ci fake_pdu.capacity = len; 6128c2ecf20Sopenharmony_ci fake_pdu.sdata = buf; 6138c2ecf20Sopenharmony_ci fake_pdu.offset = 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid, 6168c2ecf20Sopenharmony_ci &dirent->d_off, &dirent->d_type, &nameptr); 6178c2ecf20Sopenharmony_ci if (ret) { 6188c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); 6198c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &fake_pdu); 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name)); 6248c2ecf20Sopenharmony_ci if (ret < 0) { 6258c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 6268c2ecf20Sopenharmony_ci "On the wire dirent name too long: %s\n", 6278c2ecf20Sopenharmony_ci nameptr); 6288c2ecf20Sopenharmony_ci kfree(nameptr); 6298c2ecf20Sopenharmony_ci return ret; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci kfree(nameptr); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return fake_pdu.offset; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9dirent_read); 636