162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 9P Protocol Support Code 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Base on code from Anthony Liguori <aliguori@us.ibm.com> 862306a36Sopenharmony_ci * Copyright (C) 2008 by IBM, Corp. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/sched.h> 1762306a36Sopenharmony_ci#include <linux/stddef.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/uio.h> 2062306a36Sopenharmony_ci#include <net/9p/9p.h> 2162306a36Sopenharmony_ci#include <net/9p/client.h> 2262306a36Sopenharmony_ci#include "protocol.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <trace/events/9p.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* len[2] text[len] */ 2762306a36Sopenharmony_ci#define P9_STRLEN(s) \ 2862306a36Sopenharmony_ci (2 + min_t(size_t, s ? strlen(s) : 0, USHRT_MAX)) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * p9_msg_buf_size - Returns a buffer size sufficiently large to hold the 3262306a36Sopenharmony_ci * intended 9p message. 3362306a36Sopenharmony_ci * @c: client 3462306a36Sopenharmony_ci * @type: message type 3562306a36Sopenharmony_ci * @fmt: format template for assembling request message 3662306a36Sopenharmony_ci * (see p9pdu_vwritef) 3762306a36Sopenharmony_ci * @ap: variable arguments to be fed to passed format template 3862306a36Sopenharmony_ci * (see p9pdu_vwritef) 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Note: Even for response types (P9_R*) the format template and variable 4162306a36Sopenharmony_ci * arguments must always be for the originating request type (P9_T*). 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cisize_t p9_msg_buf_size(struct p9_client *c, enum p9_msg_t type, 4462306a36Sopenharmony_ci const char *fmt, va_list ap) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci /* size[4] type[1] tag[2] */ 4762306a36Sopenharmony_ci const int hdr = 4 + 1 + 2; 4862306a36Sopenharmony_ci /* ename[s] errno[4] */ 4962306a36Sopenharmony_ci const int rerror_size = hdr + P9_ERRMAX + 4; 5062306a36Sopenharmony_ci /* ecode[4] */ 5162306a36Sopenharmony_ci const int rlerror_size = hdr + 4; 5262306a36Sopenharmony_ci const int err_size = 5362306a36Sopenharmony_ci c->proto_version == p9_proto_2000L ? rlerror_size : rerror_size; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci static_assert(NAME_MAX <= 4*1024, "p9_msg_buf_size() currently assumes " 5662306a36Sopenharmony_ci "a max. allowed directory entry name length of 4k"); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci switch (type) { 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* message types not used at all */ 6162306a36Sopenharmony_ci case P9_TERROR: 6262306a36Sopenharmony_ci case P9_TLERROR: 6362306a36Sopenharmony_ci case P9_TAUTH: 6462306a36Sopenharmony_ci case P9_RAUTH: 6562306a36Sopenharmony_ci BUG(); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* variable length & potentially large message types */ 6862306a36Sopenharmony_ci case P9_TATTACH: 6962306a36Sopenharmony_ci BUG_ON(strcmp("ddss?u", fmt)); 7062306a36Sopenharmony_ci va_arg(ap, int32_t); 7162306a36Sopenharmony_ci va_arg(ap, int32_t); 7262306a36Sopenharmony_ci { 7362306a36Sopenharmony_ci const char *uname = va_arg(ap, const char *); 7462306a36Sopenharmony_ci const char *aname = va_arg(ap, const char *); 7562306a36Sopenharmony_ci /* fid[4] afid[4] uname[s] aname[s] n_uname[4] */ 7662306a36Sopenharmony_ci return hdr + 4 + 4 + P9_STRLEN(uname) + P9_STRLEN(aname) + 4; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci case P9_TWALK: 7962306a36Sopenharmony_ci BUG_ON(strcmp("ddT", fmt)); 8062306a36Sopenharmony_ci va_arg(ap, int32_t); 8162306a36Sopenharmony_ci va_arg(ap, int32_t); 8262306a36Sopenharmony_ci { 8362306a36Sopenharmony_ci uint i, nwname = va_arg(ap, int); 8462306a36Sopenharmony_ci size_t wname_all; 8562306a36Sopenharmony_ci const char **wnames = va_arg(ap, const char **); 8662306a36Sopenharmony_ci for (i = 0, wname_all = 0; i < nwname; ++i) { 8762306a36Sopenharmony_ci wname_all += P9_STRLEN(wnames[i]); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ 9062306a36Sopenharmony_ci return hdr + 4 + 4 + 2 + wname_all; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci case P9_RWALK: 9362306a36Sopenharmony_ci BUG_ON(strcmp("ddT", fmt)); 9462306a36Sopenharmony_ci va_arg(ap, int32_t); 9562306a36Sopenharmony_ci va_arg(ap, int32_t); 9662306a36Sopenharmony_ci { 9762306a36Sopenharmony_ci uint nwname = va_arg(ap, int); 9862306a36Sopenharmony_ci /* nwqid[2] nwqid*(wqid[13]) */ 9962306a36Sopenharmony_ci return max_t(size_t, hdr + 2 + nwname * 13, err_size); 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci case P9_TCREATE: 10262306a36Sopenharmony_ci BUG_ON(strcmp("dsdb?s", fmt)); 10362306a36Sopenharmony_ci va_arg(ap, int32_t); 10462306a36Sopenharmony_ci { 10562306a36Sopenharmony_ci const char *name = va_arg(ap, const char *); 10662306a36Sopenharmony_ci if (c->proto_version == p9_proto_legacy) { 10762306a36Sopenharmony_ci /* fid[4] name[s] perm[4] mode[1] */ 10862306a36Sopenharmony_ci return hdr + 4 + P9_STRLEN(name) + 4 + 1; 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci va_arg(ap, int32_t); 11162306a36Sopenharmony_ci va_arg(ap, int); 11262306a36Sopenharmony_ci { 11362306a36Sopenharmony_ci const char *ext = va_arg(ap, const char *); 11462306a36Sopenharmony_ci /* fid[4] name[s] perm[4] mode[1] extension[s] */ 11562306a36Sopenharmony_ci return hdr + 4 + P9_STRLEN(name) + 4 + 1 + P9_STRLEN(ext); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci case P9_TLCREATE: 12062306a36Sopenharmony_ci BUG_ON(strcmp("dsddg", fmt)); 12162306a36Sopenharmony_ci va_arg(ap, int32_t); 12262306a36Sopenharmony_ci { 12362306a36Sopenharmony_ci const char *name = va_arg(ap, const char *); 12462306a36Sopenharmony_ci /* fid[4] name[s] flags[4] mode[4] gid[4] */ 12562306a36Sopenharmony_ci return hdr + 4 + P9_STRLEN(name) + 4 + 4 + 4; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci case P9_RREAD: 12862306a36Sopenharmony_ci case P9_RREADDIR: 12962306a36Sopenharmony_ci BUG_ON(strcmp("dqd", fmt)); 13062306a36Sopenharmony_ci va_arg(ap, int32_t); 13162306a36Sopenharmony_ci va_arg(ap, int64_t); 13262306a36Sopenharmony_ci { 13362306a36Sopenharmony_ci const int32_t count = va_arg(ap, int32_t); 13462306a36Sopenharmony_ci /* count[4] data[count] */ 13562306a36Sopenharmony_ci return max_t(size_t, hdr + 4 + count, err_size); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci case P9_TWRITE: 13862306a36Sopenharmony_ci BUG_ON(strcmp("dqV", fmt)); 13962306a36Sopenharmony_ci va_arg(ap, int32_t); 14062306a36Sopenharmony_ci va_arg(ap, int64_t); 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci const int32_t count = va_arg(ap, int32_t); 14362306a36Sopenharmony_ci /* fid[4] offset[8] count[4] data[count] */ 14462306a36Sopenharmony_ci return hdr + 4 + 8 + 4 + count; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci case P9_TRENAMEAT: 14762306a36Sopenharmony_ci BUG_ON(strcmp("dsds", fmt)); 14862306a36Sopenharmony_ci va_arg(ap, int32_t); 14962306a36Sopenharmony_ci { 15062306a36Sopenharmony_ci const char *oldname, *newname; 15162306a36Sopenharmony_ci oldname = va_arg(ap, const char *); 15262306a36Sopenharmony_ci va_arg(ap, int32_t); 15362306a36Sopenharmony_ci newname = va_arg(ap, const char *); 15462306a36Sopenharmony_ci /* olddirfid[4] oldname[s] newdirfid[4] newname[s] */ 15562306a36Sopenharmony_ci return hdr + 4 + P9_STRLEN(oldname) + 4 + P9_STRLEN(newname); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci case P9_TSYMLINK: 15862306a36Sopenharmony_ci BUG_ON(strcmp("dssg", fmt)); 15962306a36Sopenharmony_ci va_arg(ap, int32_t); 16062306a36Sopenharmony_ci { 16162306a36Sopenharmony_ci const char *name = va_arg(ap, const char *); 16262306a36Sopenharmony_ci const char *symtgt = va_arg(ap, const char *); 16362306a36Sopenharmony_ci /* fid[4] name[s] symtgt[s] gid[4] */ 16462306a36Sopenharmony_ci return hdr + 4 + P9_STRLEN(name) + P9_STRLEN(symtgt) + 4; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci case P9_RERROR: 16862306a36Sopenharmony_ci return rerror_size; 16962306a36Sopenharmony_ci case P9_RLERROR: 17062306a36Sopenharmony_ci return rlerror_size; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* small message types */ 17362306a36Sopenharmony_ci case P9_TWSTAT: 17462306a36Sopenharmony_ci case P9_RSTAT: 17562306a36Sopenharmony_ci case P9_RREADLINK: 17662306a36Sopenharmony_ci case P9_TXATTRWALK: 17762306a36Sopenharmony_ci case P9_TXATTRCREATE: 17862306a36Sopenharmony_ci case P9_TLINK: 17962306a36Sopenharmony_ci case P9_TMKDIR: 18062306a36Sopenharmony_ci case P9_TMKNOD: 18162306a36Sopenharmony_ci case P9_TRENAME: 18262306a36Sopenharmony_ci case P9_TUNLINKAT: 18362306a36Sopenharmony_ci case P9_TLOCK: 18462306a36Sopenharmony_ci return 8 * 1024; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* tiny message types */ 18762306a36Sopenharmony_ci default: 18862306a36Sopenharmony_ci return 4 * 1024; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int 19462306a36Sopenharmony_cip9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_civoid p9stat_free(struct p9_wstat *stbuf) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci kfree(stbuf->name); 19962306a36Sopenharmony_ci stbuf->name = NULL; 20062306a36Sopenharmony_ci kfree(stbuf->uid); 20162306a36Sopenharmony_ci stbuf->uid = NULL; 20262306a36Sopenharmony_ci kfree(stbuf->gid); 20362306a36Sopenharmony_ci stbuf->gid = NULL; 20462306a36Sopenharmony_ci kfree(stbuf->muid); 20562306a36Sopenharmony_ci stbuf->muid = NULL; 20662306a36Sopenharmony_ci kfree(stbuf->extension); 20762306a36Sopenharmony_ci stbuf->extension = NULL; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ciEXPORT_SYMBOL(p9stat_free); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cisize_t pdu_read(struct p9_fcall *pdu, void *data, size_t size) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci size_t len = min(pdu->size - pdu->offset, size); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci memcpy(data, &pdu->sdata[pdu->offset], len); 21662306a36Sopenharmony_ci pdu->offset += len; 21762306a36Sopenharmony_ci return size - len; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci size_t len = min(pdu->capacity - pdu->size, size); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci memcpy(&pdu->sdata[pdu->size], data, len); 22562306a36Sopenharmony_ci pdu->size += len; 22662306a36Sopenharmony_ci return size - len; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic size_t 23062306a36Sopenharmony_cipdu_write_u(struct p9_fcall *pdu, struct iov_iter *from, size_t size) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci size_t len = min(pdu->capacity - pdu->size, size); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (!copy_from_iter_full(&pdu->sdata[pdu->size], len, from)) 23562306a36Sopenharmony_ci len = 0; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pdu->size += len; 23862306a36Sopenharmony_ci return size - len; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/* b - int8_t 24262306a36Sopenharmony_ci * w - int16_t 24362306a36Sopenharmony_ci * d - int32_t 24462306a36Sopenharmony_ci * q - int64_t 24562306a36Sopenharmony_ci * s - string 24662306a36Sopenharmony_ci * u - numeric uid 24762306a36Sopenharmony_ci * g - numeric gid 24862306a36Sopenharmony_ci * S - stat 24962306a36Sopenharmony_ci * Q - qid 25062306a36Sopenharmony_ci * D - data blob (int32_t size followed by void *, results are not freed) 25162306a36Sopenharmony_ci * T - array of strings (int16_t count, followed by strings) 25262306a36Sopenharmony_ci * R - array of qids (int16_t count, followed by qids) 25362306a36Sopenharmony_ci * A - stat for 9p2000.L (p9_stat_dotl) 25462306a36Sopenharmony_ci * ? - if optional = 1, continue parsing 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int 25862306a36Sopenharmony_cip9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt, 25962306a36Sopenharmony_ci va_list ap) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci const char *ptr; 26262306a36Sopenharmony_ci int errcode = 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci for (ptr = fmt; *ptr; ptr++) { 26562306a36Sopenharmony_ci switch (*ptr) { 26662306a36Sopenharmony_ci case 'b':{ 26762306a36Sopenharmony_ci int8_t *val = va_arg(ap, int8_t *); 26862306a36Sopenharmony_ci if (pdu_read(pdu, val, sizeof(*val))) { 26962306a36Sopenharmony_ci errcode = -EFAULT; 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci case 'w':{ 27562306a36Sopenharmony_ci int16_t *val = va_arg(ap, int16_t *); 27662306a36Sopenharmony_ci __le16 le_val; 27762306a36Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 27862306a36Sopenharmony_ci errcode = -EFAULT; 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci *val = le16_to_cpu(le_val); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case 'd':{ 28562306a36Sopenharmony_ci int32_t *val = va_arg(ap, int32_t *); 28662306a36Sopenharmony_ci __le32 le_val; 28762306a36Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 28862306a36Sopenharmony_ci errcode = -EFAULT; 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci *val = le32_to_cpu(le_val); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case 'q':{ 29562306a36Sopenharmony_ci int64_t *val = va_arg(ap, int64_t *); 29662306a36Sopenharmony_ci __le64 le_val; 29762306a36Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 29862306a36Sopenharmony_ci errcode = -EFAULT; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci *val = le64_to_cpu(le_val); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci case 's':{ 30562306a36Sopenharmony_ci char **sptr = va_arg(ap, char **); 30662306a36Sopenharmony_ci uint16_t len; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, 30962306a36Sopenharmony_ci "w", &len); 31062306a36Sopenharmony_ci if (errcode) 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci *sptr = kmalloc(len + 1, GFP_NOFS); 31462306a36Sopenharmony_ci if (*sptr == NULL) { 31562306a36Sopenharmony_ci errcode = -ENOMEM; 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci if (pdu_read(pdu, *sptr, len)) { 31962306a36Sopenharmony_ci errcode = -EFAULT; 32062306a36Sopenharmony_ci kfree(*sptr); 32162306a36Sopenharmony_ci *sptr = NULL; 32262306a36Sopenharmony_ci } else 32362306a36Sopenharmony_ci (*sptr)[len] = 0; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci case 'u': { 32762306a36Sopenharmony_ci kuid_t *uid = va_arg(ap, kuid_t *); 32862306a36Sopenharmony_ci __le32 le_val; 32962306a36Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 33062306a36Sopenharmony_ci errcode = -EFAULT; 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci *uid = make_kuid(&init_user_ns, 33462306a36Sopenharmony_ci le32_to_cpu(le_val)); 33562306a36Sopenharmony_ci } break; 33662306a36Sopenharmony_ci case 'g': { 33762306a36Sopenharmony_ci kgid_t *gid = va_arg(ap, kgid_t *); 33862306a36Sopenharmony_ci __le32 le_val; 33962306a36Sopenharmony_ci if (pdu_read(pdu, &le_val, sizeof(le_val))) { 34062306a36Sopenharmony_ci errcode = -EFAULT; 34162306a36Sopenharmony_ci break; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci *gid = make_kgid(&init_user_ns, 34462306a36Sopenharmony_ci le32_to_cpu(le_val)); 34562306a36Sopenharmony_ci } break; 34662306a36Sopenharmony_ci case 'Q':{ 34762306a36Sopenharmony_ci struct p9_qid *qid = 34862306a36Sopenharmony_ci va_arg(ap, struct p9_qid *); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, "bdq", 35162306a36Sopenharmony_ci &qid->type, &qid->version, 35262306a36Sopenharmony_ci &qid->path); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci case 'S':{ 35662306a36Sopenharmony_ci struct p9_wstat *stbuf = 35762306a36Sopenharmony_ci va_arg(ap, struct p9_wstat *); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci memset(stbuf, 0, sizeof(struct p9_wstat)); 36062306a36Sopenharmony_ci stbuf->n_uid = stbuf->n_muid = INVALID_UID; 36162306a36Sopenharmony_ci stbuf->n_gid = INVALID_GID; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci errcode = 36462306a36Sopenharmony_ci p9pdu_readf(pdu, proto_version, 36562306a36Sopenharmony_ci "wwdQdddqssss?sugu", 36662306a36Sopenharmony_ci &stbuf->size, &stbuf->type, 36762306a36Sopenharmony_ci &stbuf->dev, &stbuf->qid, 36862306a36Sopenharmony_ci &stbuf->mode, &stbuf->atime, 36962306a36Sopenharmony_ci &stbuf->mtime, &stbuf->length, 37062306a36Sopenharmony_ci &stbuf->name, &stbuf->uid, 37162306a36Sopenharmony_ci &stbuf->gid, &stbuf->muid, 37262306a36Sopenharmony_ci &stbuf->extension, 37362306a36Sopenharmony_ci &stbuf->n_uid, &stbuf->n_gid, 37462306a36Sopenharmony_ci &stbuf->n_muid); 37562306a36Sopenharmony_ci if (errcode) 37662306a36Sopenharmony_ci p9stat_free(stbuf); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci break; 37962306a36Sopenharmony_ci case 'D':{ 38062306a36Sopenharmony_ci uint32_t *count = va_arg(ap, uint32_t *); 38162306a36Sopenharmony_ci void **data = va_arg(ap, void **); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci errcode = 38462306a36Sopenharmony_ci p9pdu_readf(pdu, proto_version, "d", count); 38562306a36Sopenharmony_ci if (!errcode) { 38662306a36Sopenharmony_ci *count = 38762306a36Sopenharmony_ci min_t(uint32_t, *count, 38862306a36Sopenharmony_ci pdu->size - pdu->offset); 38962306a36Sopenharmony_ci *data = &pdu->sdata[pdu->offset]; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case 'T':{ 39462306a36Sopenharmony_ci uint16_t *nwname = va_arg(ap, uint16_t *); 39562306a36Sopenharmony_ci char ***wnames = va_arg(ap, char ***); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci *wnames = NULL; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci errcode = p9pdu_readf(pdu, proto_version, 40062306a36Sopenharmony_ci "w", nwname); 40162306a36Sopenharmony_ci if (!errcode) { 40262306a36Sopenharmony_ci *wnames = 40362306a36Sopenharmony_ci kmalloc_array(*nwname, 40462306a36Sopenharmony_ci sizeof(char *), 40562306a36Sopenharmony_ci GFP_NOFS); 40662306a36Sopenharmony_ci if (!*wnames) 40762306a36Sopenharmony_ci errcode = -ENOMEM; 40862306a36Sopenharmony_ci else 40962306a36Sopenharmony_ci (*wnames)[0] = NULL; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!errcode) { 41362306a36Sopenharmony_ci int i; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < *nwname; i++) { 41662306a36Sopenharmony_ci errcode = 41762306a36Sopenharmony_ci p9pdu_readf(pdu, 41862306a36Sopenharmony_ci proto_version, 41962306a36Sopenharmony_ci "s", 42062306a36Sopenharmony_ci &(*wnames)[i]); 42162306a36Sopenharmony_ci if (errcode) { 42262306a36Sopenharmony_ci (*wnames)[i] = NULL; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (errcode) { 42962306a36Sopenharmony_ci if (*wnames) { 43062306a36Sopenharmony_ci int i; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci for (i = 0; i < *nwname; i++) { 43362306a36Sopenharmony_ci if (!(*wnames)[i]) 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci kfree((*wnames)[i]); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci kfree(*wnames); 43862306a36Sopenharmony_ci *wnames = NULL; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci case 'R':{ 44462306a36Sopenharmony_ci uint16_t *nwqid = va_arg(ap, uint16_t *); 44562306a36Sopenharmony_ci struct p9_qid **wqids = 44662306a36Sopenharmony_ci va_arg(ap, struct p9_qid **); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci *wqids = NULL; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci errcode = 45162306a36Sopenharmony_ci p9pdu_readf(pdu, proto_version, "w", nwqid); 45262306a36Sopenharmony_ci if (!errcode) { 45362306a36Sopenharmony_ci *wqids = 45462306a36Sopenharmony_ci kmalloc_array(*nwqid, 45562306a36Sopenharmony_ci sizeof(struct p9_qid), 45662306a36Sopenharmony_ci GFP_NOFS); 45762306a36Sopenharmony_ci if (*wqids == NULL) 45862306a36Sopenharmony_ci errcode = -ENOMEM; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (!errcode) { 46262306a36Sopenharmony_ci int i; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci for (i = 0; i < *nwqid; i++) { 46562306a36Sopenharmony_ci errcode = 46662306a36Sopenharmony_ci p9pdu_readf(pdu, 46762306a36Sopenharmony_ci proto_version, 46862306a36Sopenharmony_ci "Q", 46962306a36Sopenharmony_ci &(*wqids)[i]); 47062306a36Sopenharmony_ci if (errcode) 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (errcode) { 47662306a36Sopenharmony_ci kfree(*wqids); 47762306a36Sopenharmony_ci *wqids = NULL; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case 'A': { 48262306a36Sopenharmony_ci struct p9_stat_dotl *stbuf = 48362306a36Sopenharmony_ci va_arg(ap, struct p9_stat_dotl *); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci memset(stbuf, 0, sizeof(struct p9_stat_dotl)); 48662306a36Sopenharmony_ci errcode = 48762306a36Sopenharmony_ci p9pdu_readf(pdu, proto_version, 48862306a36Sopenharmony_ci "qQdugqqqqqqqqqqqqqqq", 48962306a36Sopenharmony_ci &stbuf->st_result_mask, 49062306a36Sopenharmony_ci &stbuf->qid, 49162306a36Sopenharmony_ci &stbuf->st_mode, 49262306a36Sopenharmony_ci &stbuf->st_uid, &stbuf->st_gid, 49362306a36Sopenharmony_ci &stbuf->st_nlink, 49462306a36Sopenharmony_ci &stbuf->st_rdev, &stbuf->st_size, 49562306a36Sopenharmony_ci &stbuf->st_blksize, &stbuf->st_blocks, 49662306a36Sopenharmony_ci &stbuf->st_atime_sec, 49762306a36Sopenharmony_ci &stbuf->st_atime_nsec, 49862306a36Sopenharmony_ci &stbuf->st_mtime_sec, 49962306a36Sopenharmony_ci &stbuf->st_mtime_nsec, 50062306a36Sopenharmony_ci &stbuf->st_ctime_sec, 50162306a36Sopenharmony_ci &stbuf->st_ctime_nsec, 50262306a36Sopenharmony_ci &stbuf->st_btime_sec, 50362306a36Sopenharmony_ci &stbuf->st_btime_nsec, 50462306a36Sopenharmony_ci &stbuf->st_gen, 50562306a36Sopenharmony_ci &stbuf->st_data_version); 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case '?': 50962306a36Sopenharmony_ci if ((proto_version != p9_proto_2000u) && 51062306a36Sopenharmony_ci (proto_version != p9_proto_2000L)) 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci default: 51462306a36Sopenharmony_ci BUG(); 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (errcode) 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return errcode; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciint 52662306a36Sopenharmony_cip9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, 52762306a36Sopenharmony_ci va_list ap) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci const char *ptr; 53062306a36Sopenharmony_ci int errcode = 0; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci for (ptr = fmt; *ptr; ptr++) { 53362306a36Sopenharmony_ci switch (*ptr) { 53462306a36Sopenharmony_ci case 'b':{ 53562306a36Sopenharmony_ci int8_t val = va_arg(ap, int); 53662306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 53762306a36Sopenharmony_ci errcode = -EFAULT; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci break; 54062306a36Sopenharmony_ci case 'w':{ 54162306a36Sopenharmony_ci __le16 val = cpu_to_le16(va_arg(ap, int)); 54262306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 54362306a36Sopenharmony_ci errcode = -EFAULT; 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci case 'd':{ 54762306a36Sopenharmony_ci __le32 val = cpu_to_le32(va_arg(ap, int32_t)); 54862306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 54962306a36Sopenharmony_ci errcode = -EFAULT; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case 'q':{ 55362306a36Sopenharmony_ci __le64 val = cpu_to_le64(va_arg(ap, int64_t)); 55462306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 55562306a36Sopenharmony_ci errcode = -EFAULT; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci break; 55862306a36Sopenharmony_ci case 's':{ 55962306a36Sopenharmony_ci const char *sptr = va_arg(ap, const char *); 56062306a36Sopenharmony_ci uint16_t len = 0; 56162306a36Sopenharmony_ci if (sptr) 56262306a36Sopenharmony_ci len = min_t(size_t, strlen(sptr), 56362306a36Sopenharmony_ci USHRT_MAX); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, 56662306a36Sopenharmony_ci "w", len); 56762306a36Sopenharmony_ci if (!errcode && pdu_write(pdu, sptr, len)) 56862306a36Sopenharmony_ci errcode = -EFAULT; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci break; 57162306a36Sopenharmony_ci case 'u': { 57262306a36Sopenharmony_ci kuid_t uid = va_arg(ap, kuid_t); 57362306a36Sopenharmony_ci __le32 val = cpu_to_le32( 57462306a36Sopenharmony_ci from_kuid(&init_user_ns, uid)); 57562306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 57662306a36Sopenharmony_ci errcode = -EFAULT; 57762306a36Sopenharmony_ci } break; 57862306a36Sopenharmony_ci case 'g': { 57962306a36Sopenharmony_ci kgid_t gid = va_arg(ap, kgid_t); 58062306a36Sopenharmony_ci __le32 val = cpu_to_le32( 58162306a36Sopenharmony_ci from_kgid(&init_user_ns, gid)); 58262306a36Sopenharmony_ci if (pdu_write(pdu, &val, sizeof(val))) 58362306a36Sopenharmony_ci errcode = -EFAULT; 58462306a36Sopenharmony_ci } break; 58562306a36Sopenharmony_ci case 'Q':{ 58662306a36Sopenharmony_ci const struct p9_qid *qid = 58762306a36Sopenharmony_ci va_arg(ap, const struct p9_qid *); 58862306a36Sopenharmony_ci errcode = 58962306a36Sopenharmony_ci p9pdu_writef(pdu, proto_version, "bdq", 59062306a36Sopenharmony_ci qid->type, qid->version, 59162306a36Sopenharmony_ci qid->path); 59262306a36Sopenharmony_ci } break; 59362306a36Sopenharmony_ci case 'S':{ 59462306a36Sopenharmony_ci const struct p9_wstat *stbuf = 59562306a36Sopenharmony_ci va_arg(ap, const struct p9_wstat *); 59662306a36Sopenharmony_ci errcode = 59762306a36Sopenharmony_ci p9pdu_writef(pdu, proto_version, 59862306a36Sopenharmony_ci "wwdQdddqssss?sugu", 59962306a36Sopenharmony_ci stbuf->size, stbuf->type, 60062306a36Sopenharmony_ci stbuf->dev, &stbuf->qid, 60162306a36Sopenharmony_ci stbuf->mode, stbuf->atime, 60262306a36Sopenharmony_ci stbuf->mtime, stbuf->length, 60362306a36Sopenharmony_ci stbuf->name, stbuf->uid, 60462306a36Sopenharmony_ci stbuf->gid, stbuf->muid, 60562306a36Sopenharmony_ci stbuf->extension, stbuf->n_uid, 60662306a36Sopenharmony_ci stbuf->n_gid, stbuf->n_muid); 60762306a36Sopenharmony_ci } break; 60862306a36Sopenharmony_ci case 'V':{ 60962306a36Sopenharmony_ci uint32_t count = va_arg(ap, uint32_t); 61062306a36Sopenharmony_ci struct iov_iter *from = 61162306a36Sopenharmony_ci va_arg(ap, struct iov_iter *); 61262306a36Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "d", 61362306a36Sopenharmony_ci count); 61462306a36Sopenharmony_ci if (!errcode && pdu_write_u(pdu, from, count)) 61562306a36Sopenharmony_ci errcode = -EFAULT; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci break; 61862306a36Sopenharmony_ci case 'T':{ 61962306a36Sopenharmony_ci uint16_t nwname = va_arg(ap, int); 62062306a36Sopenharmony_ci const char **wnames = va_arg(ap, const char **); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "w", 62362306a36Sopenharmony_ci nwname); 62462306a36Sopenharmony_ci if (!errcode) { 62562306a36Sopenharmony_ci int i; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci for (i = 0; i < nwname; i++) { 62862306a36Sopenharmony_ci errcode = 62962306a36Sopenharmony_ci p9pdu_writef(pdu, 63062306a36Sopenharmony_ci proto_version, 63162306a36Sopenharmony_ci "s", 63262306a36Sopenharmony_ci wnames[i]); 63362306a36Sopenharmony_ci if (errcode) 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci break; 63962306a36Sopenharmony_ci case 'R':{ 64062306a36Sopenharmony_ci uint16_t nwqid = va_arg(ap, int); 64162306a36Sopenharmony_ci struct p9_qid *wqids = 64262306a36Sopenharmony_ci va_arg(ap, struct p9_qid *); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, "w", 64562306a36Sopenharmony_ci nwqid); 64662306a36Sopenharmony_ci if (!errcode) { 64762306a36Sopenharmony_ci int i; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci for (i = 0; i < nwqid; i++) { 65062306a36Sopenharmony_ci errcode = 65162306a36Sopenharmony_ci p9pdu_writef(pdu, 65262306a36Sopenharmony_ci proto_version, 65362306a36Sopenharmony_ci "Q", 65462306a36Sopenharmony_ci &wqids[i]); 65562306a36Sopenharmony_ci if (errcode) 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case 'I':{ 66262306a36Sopenharmony_ci struct p9_iattr_dotl *p9attr = va_arg(ap, 66362306a36Sopenharmony_ci struct p9_iattr_dotl *); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci errcode = p9pdu_writef(pdu, proto_version, 66662306a36Sopenharmony_ci "ddugqqqqq", 66762306a36Sopenharmony_ci p9attr->valid, 66862306a36Sopenharmony_ci p9attr->mode, 66962306a36Sopenharmony_ci p9attr->uid, 67062306a36Sopenharmony_ci p9attr->gid, 67162306a36Sopenharmony_ci p9attr->size, 67262306a36Sopenharmony_ci p9attr->atime_sec, 67362306a36Sopenharmony_ci p9attr->atime_nsec, 67462306a36Sopenharmony_ci p9attr->mtime_sec, 67562306a36Sopenharmony_ci p9attr->mtime_nsec); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci case '?': 67962306a36Sopenharmony_ci if ((proto_version != p9_proto_2000u) && 68062306a36Sopenharmony_ci (proto_version != p9_proto_2000L)) 68162306a36Sopenharmony_ci return 0; 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci default: 68462306a36Sopenharmony_ci BUG(); 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci if (errcode) 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return errcode; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ciint p9pdu_readf(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci va_list ap; 69862306a36Sopenharmony_ci int ret; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci va_start(ap, fmt); 70162306a36Sopenharmony_ci ret = p9pdu_vreadf(pdu, proto_version, fmt, ap); 70262306a36Sopenharmony_ci va_end(ap); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return ret; 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic int 70862306a36Sopenharmony_cip9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci va_list ap; 71162306a36Sopenharmony_ci int ret; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci va_start(ap, fmt); 71462306a36Sopenharmony_ci ret = p9pdu_vwritef(pdu, proto_version, fmt, ap); 71562306a36Sopenharmony_ci va_end(ap); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return ret; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ciint p9stat_read(struct p9_client *clnt, char *buf, int len, struct p9_wstat *st) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct p9_fcall fake_pdu; 72362306a36Sopenharmony_ci int ret; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci fake_pdu.size = len; 72662306a36Sopenharmony_ci fake_pdu.capacity = len; 72762306a36Sopenharmony_ci fake_pdu.sdata = buf; 72862306a36Sopenharmony_ci fake_pdu.offset = 0; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "S", st); 73162306a36Sopenharmony_ci if (ret) { 73262306a36Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< p9stat_read failed: %d\n", ret); 73362306a36Sopenharmony_ci trace_9p_protocol_dump(clnt, &fake_pdu); 73462306a36Sopenharmony_ci return ret; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return fake_pdu.offset; 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ciEXPORT_SYMBOL(p9stat_read); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ciint p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci pdu->id = type; 74462306a36Sopenharmony_ci return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ciint p9pdu_finalize(struct p9_client *clnt, struct p9_fcall *pdu) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci int size = pdu->size; 75062306a36Sopenharmony_ci int err; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci pdu->size = 0; 75362306a36Sopenharmony_ci err = p9pdu_writef(pdu, 0, "d", size); 75462306a36Sopenharmony_ci pdu->size = size; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci trace_9p_protocol_dump(clnt, pdu); 75762306a36Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> size=%d type: %d tag: %d\n", 75862306a36Sopenharmony_ci pdu->size, pdu->id, pdu->tag); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return err; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_civoid p9pdu_reset(struct p9_fcall *pdu) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci pdu->offset = 0; 76662306a36Sopenharmony_ci pdu->size = 0; 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ciint p9dirent_read(struct p9_client *clnt, char *buf, int len, 77062306a36Sopenharmony_ci struct p9_dirent *dirent) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct p9_fcall fake_pdu; 77362306a36Sopenharmony_ci int ret; 77462306a36Sopenharmony_ci char *nameptr; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci fake_pdu.size = len; 77762306a36Sopenharmony_ci fake_pdu.capacity = len; 77862306a36Sopenharmony_ci fake_pdu.sdata = buf; 77962306a36Sopenharmony_ci fake_pdu.offset = 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci ret = p9pdu_readf(&fake_pdu, clnt->proto_version, "Qqbs", &dirent->qid, 78262306a36Sopenharmony_ci &dirent->d_off, &dirent->d_type, &nameptr); 78362306a36Sopenharmony_ci if (ret) { 78462306a36Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret); 78562306a36Sopenharmony_ci trace_9p_protocol_dump(clnt, &fake_pdu); 78662306a36Sopenharmony_ci return ret; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ret = strscpy(dirent->d_name, nameptr, sizeof(dirent->d_name)); 79062306a36Sopenharmony_ci if (ret < 0) { 79162306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 79262306a36Sopenharmony_ci "On the wire dirent name too long: %s\n", 79362306a36Sopenharmony_ci nameptr); 79462306a36Sopenharmony_ci kfree(nameptr); 79562306a36Sopenharmony_ci return ret; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci kfree(nameptr); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return fake_pdu.offset; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ciEXPORT_SYMBOL(p9dirent_read); 802