18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * net/9p/clnt.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * 9P Client 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com> 88c2ecf20Sopenharmony_ci * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/fs.h> 168c2ecf20Sopenharmony_ci#include <linux/poll.h> 178c2ecf20Sopenharmony_ci#include <linux/idr.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 218c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 228c2ecf20Sopenharmony_ci#include <linux/uio.h> 238c2ecf20Sopenharmony_ci#include <net/9p/9p.h> 248c2ecf20Sopenharmony_ci#include <linux/parser.h> 258c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 268c2ecf20Sopenharmony_ci#include <net/9p/client.h> 278c2ecf20Sopenharmony_ci#include <net/9p/transport.h> 288c2ecf20Sopenharmony_ci#include "protocol.h" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include <trace/events/9p.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * Client Option Parsing (code inspired by NFS code) 358c2ecf20Sopenharmony_ci * - a little lazy - parse all client options 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cienum { 398c2ecf20Sopenharmony_ci Opt_msize, 408c2ecf20Sopenharmony_ci Opt_trans, 418c2ecf20Sopenharmony_ci Opt_legacy, 428c2ecf20Sopenharmony_ci Opt_version, 438c2ecf20Sopenharmony_ci Opt_err, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 478c2ecf20Sopenharmony_ci {Opt_msize, "msize=%u"}, 488c2ecf20Sopenharmony_ci {Opt_legacy, "noextend"}, 498c2ecf20Sopenharmony_ci {Opt_trans, "trans=%s"}, 508c2ecf20Sopenharmony_ci {Opt_version, "version=%s"}, 518c2ecf20Sopenharmony_ci {Opt_err, NULL}, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ciinline int p9_is_proto_dotl(struct p9_client *clnt) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return clnt->proto_version == p9_proto_2000L; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_is_proto_dotl); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ciinline int p9_is_proto_dotu(struct p9_client *clnt) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci return clnt->proto_version == p9_proto_2000u; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_is_proto_dotu); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciint p9_show_client_options(struct seq_file *m, struct p9_client *clnt) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci if (clnt->msize != 8192) 698c2ecf20Sopenharmony_ci seq_printf(m, ",msize=%u", clnt->msize); 708c2ecf20Sopenharmony_ci seq_printf(m, ",trans=%s", clnt->trans_mod->name); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci switch (clnt->proto_version) { 738c2ecf20Sopenharmony_ci case p9_proto_legacy: 748c2ecf20Sopenharmony_ci seq_puts(m, ",noextend"); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case p9_proto_2000u: 778c2ecf20Sopenharmony_ci seq_puts(m, ",version=9p2000.u"); 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case p9_proto_2000L: 808c2ecf20Sopenharmony_ci /* Default */ 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (clnt->trans_mod->show_options) 858c2ecf20Sopenharmony_ci return clnt->trans_mod->show_options(m, clnt); 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_show_client_options); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Some error codes are taken directly from the server replies, 928c2ecf20Sopenharmony_ci * make sure they are valid. 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_cistatic int safe_errno(int err) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if ((err > 0) || (err < -MAX_ERRNO)) { 978c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err); 988c2ecf20Sopenharmony_ci return -EPROTO; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci return err; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* Interpret mount option for protocol version */ 1058c2ecf20Sopenharmony_cistatic int get_protocol_version(char *s) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci int version = -EINVAL; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (!strcmp(s, "9p2000")) { 1108c2ecf20Sopenharmony_ci version = p9_proto_legacy; 1118c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n"); 1128c2ecf20Sopenharmony_ci } else if (!strcmp(s, "9p2000.u")) { 1138c2ecf20Sopenharmony_ci version = p9_proto_2000u; 1148c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n"); 1158c2ecf20Sopenharmony_ci } else if (!strcmp(s, "9p2000.L")) { 1168c2ecf20Sopenharmony_ci version = p9_proto_2000L; 1178c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n"); 1188c2ecf20Sopenharmony_ci } else 1198c2ecf20Sopenharmony_ci pr_info("Unknown protocol version %s\n", s); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return version; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * parse_options - parse mount options into client structure 1268c2ecf20Sopenharmony_ci * @opts: options string passed from mount 1278c2ecf20Sopenharmony_ci * @clnt: existing v9fs client information 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Return 0 upon success, -ERRNO upon failure 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int parse_opts(char *opts, struct p9_client *clnt) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci char *options, *tmp_options; 1358c2ecf20Sopenharmony_ci char *p; 1368c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 1378c2ecf20Sopenharmony_ci int option; 1388c2ecf20Sopenharmony_ci char *s; 1398c2ecf20Sopenharmony_ci int ret = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci clnt->proto_version = p9_proto_2000L; 1428c2ecf20Sopenharmony_ci clnt->msize = 8192; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!opts) 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci tmp_options = kstrdup(opts, GFP_KERNEL); 1488c2ecf20Sopenharmony_ci if (!tmp_options) { 1498c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 1508c2ecf20Sopenharmony_ci "failed to allocate copy of option string\n"); 1518c2ecf20Sopenharmony_ci return -ENOMEM; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci options = tmp_options; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 1568c2ecf20Sopenharmony_ci int token, r; 1578c2ecf20Sopenharmony_ci if (!*p) 1588c2ecf20Sopenharmony_ci continue; 1598c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 1608c2ecf20Sopenharmony_ci switch (token) { 1618c2ecf20Sopenharmony_ci case Opt_msize: 1628c2ecf20Sopenharmony_ci r = match_int(&args[0], &option); 1638c2ecf20Sopenharmony_ci if (r < 0) { 1648c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 1658c2ecf20Sopenharmony_ci "integer field, but no integer?\n"); 1668c2ecf20Sopenharmony_ci ret = r; 1678c2ecf20Sopenharmony_ci continue; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (option < 4096) { 1708c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 1718c2ecf20Sopenharmony_ci "msize should be at least 4k\n"); 1728c2ecf20Sopenharmony_ci ret = -EINVAL; 1738c2ecf20Sopenharmony_ci continue; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci clnt->msize = option; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case Opt_trans: 1788c2ecf20Sopenharmony_ci s = match_strdup(&args[0]); 1798c2ecf20Sopenharmony_ci if (!s) { 1808c2ecf20Sopenharmony_ci ret = -ENOMEM; 1818c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 1828c2ecf20Sopenharmony_ci "problem allocating copy of trans arg\n"); 1838c2ecf20Sopenharmony_ci goto free_and_return; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci v9fs_put_trans(clnt->trans_mod); 1878c2ecf20Sopenharmony_ci clnt->trans_mod = v9fs_get_trans_by_name(s); 1888c2ecf20Sopenharmony_ci if (clnt->trans_mod == NULL) { 1898c2ecf20Sopenharmony_ci pr_info("Could not find request transport: %s\n", 1908c2ecf20Sopenharmony_ci s); 1918c2ecf20Sopenharmony_ci ret = -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci kfree(s); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case Opt_legacy: 1968c2ecf20Sopenharmony_ci clnt->proto_version = p9_proto_legacy; 1978c2ecf20Sopenharmony_ci break; 1988c2ecf20Sopenharmony_ci case Opt_version: 1998c2ecf20Sopenharmony_ci s = match_strdup(&args[0]); 2008c2ecf20Sopenharmony_ci if (!s) { 2018c2ecf20Sopenharmony_ci ret = -ENOMEM; 2028c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 2038c2ecf20Sopenharmony_ci "problem allocating copy of version arg\n"); 2048c2ecf20Sopenharmony_ci goto free_and_return; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci r = get_protocol_version(s); 2078c2ecf20Sopenharmony_ci if (r < 0) 2088c2ecf20Sopenharmony_ci ret = r; 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci clnt->proto_version = r; 2118c2ecf20Sopenharmony_ci kfree(s); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci default: 2148c2ecf20Sopenharmony_ci continue; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cifree_and_return: 2198c2ecf20Sopenharmony_ci if (ret) 2208c2ecf20Sopenharmony_ci v9fs_put_trans(clnt->trans_mod); 2218c2ecf20Sopenharmony_ci kfree(tmp_options); 2228c2ecf20Sopenharmony_ci return ret; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc, 2268c2ecf20Sopenharmony_ci int alloc_msize) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci if (likely(c->fcall_cache) && alloc_msize == c->msize) { 2298c2ecf20Sopenharmony_ci fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS); 2308c2ecf20Sopenharmony_ci fc->cache = c->fcall_cache; 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci fc->sdata = kmalloc(alloc_msize, GFP_NOFS); 2338c2ecf20Sopenharmony_ci fc->cache = NULL; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci if (!fc->sdata) 2368c2ecf20Sopenharmony_ci return -ENOMEM; 2378c2ecf20Sopenharmony_ci fc->capacity = alloc_msize; 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid p9_fcall_fini(struct p9_fcall *fc) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci /* sdata can be NULL for interrupted requests in trans_rdma, 2448c2ecf20Sopenharmony_ci * and kmem_cache_free does not do NULL-check for us 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ci if (unlikely(!fc->sdata)) 2478c2ecf20Sopenharmony_ci return; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (fc->cache) 2508c2ecf20Sopenharmony_ci kmem_cache_free(fc->cache, fc->sdata); 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci kfree(fc->sdata); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_fcall_fini); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic struct kmem_cache *p9_req_cache; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * p9_req_alloc - Allocate a new request. 2608c2ecf20Sopenharmony_ci * @c: Client session. 2618c2ecf20Sopenharmony_ci * @type: Transaction type. 2628c2ecf20Sopenharmony_ci * @max_size: Maximum packet size for this request. 2638c2ecf20Sopenharmony_ci * 2648c2ecf20Sopenharmony_ci * Context: Process context. 2658c2ecf20Sopenharmony_ci * Return: Pointer to new request. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_cistatic struct p9_req_t * 2688c2ecf20Sopenharmony_cip9_tag_alloc(struct p9_client *c, int8_t type, unsigned int max_size) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct p9_req_t *req = kmem_cache_alloc(p9_req_cache, GFP_NOFS); 2718c2ecf20Sopenharmony_ci int alloc_msize = min(c->msize, max_size); 2728c2ecf20Sopenharmony_ci int tag; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!req) 2758c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (p9_fcall_init(c, &req->tc, alloc_msize)) 2788c2ecf20Sopenharmony_ci goto free_req; 2798c2ecf20Sopenharmony_ci if (p9_fcall_init(c, &req->rc, alloc_msize)) 2808c2ecf20Sopenharmony_ci goto free; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci p9pdu_reset(&req->tc); 2838c2ecf20Sopenharmony_ci p9pdu_reset(&req->rc); 2848c2ecf20Sopenharmony_ci req->t_err = 0; 2858c2ecf20Sopenharmony_ci req->status = REQ_STATUS_ALLOC; 2868c2ecf20Sopenharmony_ci init_waitqueue_head(&req->wq); 2878c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&req->req_list); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci idr_preload(GFP_NOFS); 2908c2ecf20Sopenharmony_ci spin_lock_irq(&c->lock); 2918c2ecf20Sopenharmony_ci if (type == P9_TVERSION) 2928c2ecf20Sopenharmony_ci tag = idr_alloc(&c->reqs, req, P9_NOTAG, P9_NOTAG + 1, 2938c2ecf20Sopenharmony_ci GFP_NOWAIT); 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci tag = idr_alloc(&c->reqs, req, 0, P9_NOTAG, GFP_NOWAIT); 2968c2ecf20Sopenharmony_ci req->tc.tag = tag; 2978c2ecf20Sopenharmony_ci spin_unlock_irq(&c->lock); 2988c2ecf20Sopenharmony_ci idr_preload_end(); 2998c2ecf20Sopenharmony_ci if (tag < 0) 3008c2ecf20Sopenharmony_ci goto free; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Init ref to two because in the general case there is one ref 3038c2ecf20Sopenharmony_ci * that is put asynchronously by a writer thread, one ref 3048c2ecf20Sopenharmony_ci * temporarily given by p9_tag_lookup and put by p9_client_cb 3058c2ecf20Sopenharmony_ci * in the recv thread, and one ref put by p9_tag_remove in the 3068c2ecf20Sopenharmony_ci * main thread. The only exception is virtio that does not use 3078c2ecf20Sopenharmony_ci * p9_tag_lookup but does not have a writer thread either 3088c2ecf20Sopenharmony_ci * (the write happens synchronously in the request/zc_request 3098c2ecf20Sopenharmony_ci * callback), so p9_client_cb eats the second ref there 3108c2ecf20Sopenharmony_ci * as the pointer is duplicated directly by virtqueue_add_sgs() 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci refcount_set(&req->refcount.refcount, 2); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return req; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cifree: 3178c2ecf20Sopenharmony_ci p9_fcall_fini(&req->tc); 3188c2ecf20Sopenharmony_ci p9_fcall_fini(&req->rc); 3198c2ecf20Sopenharmony_cifree_req: 3208c2ecf20Sopenharmony_ci kmem_cache_free(p9_req_cache, req); 3218c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/** 3258c2ecf20Sopenharmony_ci * p9_tag_lookup - Look up a request by tag. 3268c2ecf20Sopenharmony_ci * @c: Client session. 3278c2ecf20Sopenharmony_ci * @tag: Transaction ID. 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * Context: Any context. 3308c2ecf20Sopenharmony_ci * Return: A request, or %NULL if there is no request with that tag. 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_cistruct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct p9_req_t *req; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci rcu_read_lock(); 3378c2ecf20Sopenharmony_ciagain: 3388c2ecf20Sopenharmony_ci req = idr_find(&c->reqs, tag); 3398c2ecf20Sopenharmony_ci if (req) { 3408c2ecf20Sopenharmony_ci /* We have to be careful with the req found under rcu_read_lock 3418c2ecf20Sopenharmony_ci * Thanks to SLAB_TYPESAFE_BY_RCU we can safely try to get the 3428c2ecf20Sopenharmony_ci * ref again without corrupting other data, then check again 3438c2ecf20Sopenharmony_ci * that the tag matches once we have the ref 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (!p9_req_try_get(req)) 3468c2ecf20Sopenharmony_ci goto again; 3478c2ecf20Sopenharmony_ci if (req->tc.tag != tag) { 3488c2ecf20Sopenharmony_ci p9_req_put(req); 3498c2ecf20Sopenharmony_ci goto again; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci rcu_read_unlock(); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return req; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_tag_lookup); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/** 3598c2ecf20Sopenharmony_ci * p9_tag_remove - Remove a tag. 3608c2ecf20Sopenharmony_ci * @c: Client session. 3618c2ecf20Sopenharmony_ci * @r: Request of reference. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * Context: Any context. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_cistatic int p9_tag_remove(struct p9_client *c, struct p9_req_t *r) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci unsigned long flags; 3688c2ecf20Sopenharmony_ci u16 tag = r->tc.tag; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "clnt %p req %p tag: %d\n", c, r, tag); 3718c2ecf20Sopenharmony_ci spin_lock_irqsave(&c->lock, flags); 3728c2ecf20Sopenharmony_ci idr_remove(&c->reqs, tag); 3738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&c->lock, flags); 3748c2ecf20Sopenharmony_ci return p9_req_put(r); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void p9_req_free(struct kref *ref) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct p9_req_t *r = container_of(ref, struct p9_req_t, refcount); 3808c2ecf20Sopenharmony_ci p9_fcall_fini(&r->tc); 3818c2ecf20Sopenharmony_ci p9_fcall_fini(&r->rc); 3828c2ecf20Sopenharmony_ci kmem_cache_free(p9_req_cache, r); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ciint p9_req_put(struct p9_req_t *r) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci return kref_put(&r->refcount, p9_req_free); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_req_put); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * p9_tag_cleanup - cleans up tags structure and reclaims resources 3938c2ecf20Sopenharmony_ci * @c: v9fs client struct 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * This frees resources associated with the tags structure 3968c2ecf20Sopenharmony_ci * 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_cistatic void p9_tag_cleanup(struct p9_client *c) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct p9_req_t *req; 4018c2ecf20Sopenharmony_ci int id; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci rcu_read_lock(); 4048c2ecf20Sopenharmony_ci idr_for_each_entry(&c->reqs, req, id) { 4058c2ecf20Sopenharmony_ci pr_info("Tag %d still in use\n", id); 4068c2ecf20Sopenharmony_ci if (p9_tag_remove(c, req) == 0) 4078c2ecf20Sopenharmony_ci pr_warn("Packet with tag %d has still references", 4088c2ecf20Sopenharmony_ci req->tc.tag); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci rcu_read_unlock(); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/** 4148c2ecf20Sopenharmony_ci * p9_client_cb - call back from transport to client 4158c2ecf20Sopenharmony_ci * c: client state 4168c2ecf20Sopenharmony_ci * req: request received 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_civoid p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc.tag); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * This barrier is needed to make sure any change made to req before 4258c2ecf20Sopenharmony_ci * the status change is visible to another thread 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ci smp_wmb(); 4288c2ecf20Sopenharmony_ci req->status = status; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci wake_up(&req->wq); 4318c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag); 4328c2ecf20Sopenharmony_ci p9_req_put(req); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_cb); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/** 4378c2ecf20Sopenharmony_ci * p9_parse_header - parse header arguments out of a packet 4388c2ecf20Sopenharmony_ci * @pdu: packet to parse 4398c2ecf20Sopenharmony_ci * @size: size of packet 4408c2ecf20Sopenharmony_ci * @type: type of request 4418c2ecf20Sopenharmony_ci * @tag: tag of packet 4428c2ecf20Sopenharmony_ci * @rewind: set if we need to rewind offset afterwards 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciint 4468c2ecf20Sopenharmony_cip9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type, int16_t *tag, 4478c2ecf20Sopenharmony_ci int rewind) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int8_t r_type; 4508c2ecf20Sopenharmony_ci int16_t r_tag; 4518c2ecf20Sopenharmony_ci int32_t r_size; 4528c2ecf20Sopenharmony_ci int offset = pdu->offset; 4538c2ecf20Sopenharmony_ci int err; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci pdu->offset = 0; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag); 4588c2ecf20Sopenharmony_ci if (err) 4598c2ecf20Sopenharmony_ci goto rewind_and_exit; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (type) 4628c2ecf20Sopenharmony_ci *type = r_type; 4638c2ecf20Sopenharmony_ci if (tag) 4648c2ecf20Sopenharmony_ci *tag = r_tag; 4658c2ecf20Sopenharmony_ci if (size) 4668c2ecf20Sopenharmony_ci *size = r_size; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (pdu->size != r_size || r_size < 7) { 4698c2ecf20Sopenharmony_ci err = -EINVAL; 4708c2ecf20Sopenharmony_ci goto rewind_and_exit; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci pdu->id = r_type; 4748c2ecf20Sopenharmony_ci pdu->tag = r_tag; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n", 4778c2ecf20Sopenharmony_ci pdu->size, pdu->id, pdu->tag); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cirewind_and_exit: 4808c2ecf20Sopenharmony_ci if (rewind) 4818c2ecf20Sopenharmony_ci pdu->offset = offset; 4828c2ecf20Sopenharmony_ci return err; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_parse_header); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * p9_check_errors - check 9p packet for error return and process it 4888c2ecf20Sopenharmony_ci * @c: current client instance 4898c2ecf20Sopenharmony_ci * @req: request to parse and check for error conditions 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci * returns error code if one is discovered, otherwise returns 0 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * this will have to be more complicated if we have multiple 4948c2ecf20Sopenharmony_ci * error packet types 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int p9_check_errors(struct p9_client *c, struct p9_req_t *req) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci int8_t type; 5008c2ecf20Sopenharmony_ci int err; 5018c2ecf20Sopenharmony_ci int ecode; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); 5048c2ecf20Sopenharmony_ci if (req->rc.size >= c->msize) { 5058c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 5068c2ecf20Sopenharmony_ci "requested packet size too big: %d\n", 5078c2ecf20Sopenharmony_ci req->rc.size); 5088c2ecf20Sopenharmony_ci return -EIO; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci /* 5118c2ecf20Sopenharmony_ci * dump the response from server 5128c2ecf20Sopenharmony_ci * This should be after check errors which poplulate pdu_fcall. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci trace_9p_protocol_dump(c, &req->rc); 5158c2ecf20Sopenharmony_ci if (err) { 5168c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); 5178c2ecf20Sopenharmony_ci return err; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci if (type != P9_RERROR && type != P9_RLERROR) 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (!p9_is_proto_dotl(c)) { 5238c2ecf20Sopenharmony_ci char *ename = NULL; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, c->proto_version, "s?d", 5268c2ecf20Sopenharmony_ci &ename, &ecode); 5278c2ecf20Sopenharmony_ci if (err) { 5288c2ecf20Sopenharmony_ci kfree(ename); 5298c2ecf20Sopenharmony_ci goto out_err; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (p9_is_proto_dotu(c) && ecode < 512) 5338c2ecf20Sopenharmony_ci err = -ecode; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!err) { 5368c2ecf20Sopenharmony_ci err = p9_errstr2errno(ename, strlen(ename)); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", 5398c2ecf20Sopenharmony_ci -ecode, ename); 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci kfree(ename); 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode); 5448c2ecf20Sopenharmony_ci if (err) 5458c2ecf20Sopenharmony_ci goto out_err; 5468c2ecf20Sopenharmony_ci err = -ecode; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return err; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciout_err: 5548c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return err; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci/** 5608c2ecf20Sopenharmony_ci * p9_check_zc_errors - check 9p packet for error return and process it 5618c2ecf20Sopenharmony_ci * @c: current client instance 5628c2ecf20Sopenharmony_ci * @req: request to parse and check for error conditions 5638c2ecf20Sopenharmony_ci * @in_hdrlen: Size of response protocol buffer. 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * returns error code if one is discovered, otherwise returns 0 5668c2ecf20Sopenharmony_ci * 5678c2ecf20Sopenharmony_ci * this will have to be more complicated if we have multiple 5688c2ecf20Sopenharmony_ci * error packet types 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int p9_check_zc_errors(struct p9_client *c, struct p9_req_t *req, 5728c2ecf20Sopenharmony_ci struct iov_iter *uidata, int in_hdrlen) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci int err; 5758c2ecf20Sopenharmony_ci int ecode; 5768c2ecf20Sopenharmony_ci int8_t type; 5778c2ecf20Sopenharmony_ci char *ename = NULL; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = p9_parse_header(&req->rc, NULL, &type, NULL, 0); 5808c2ecf20Sopenharmony_ci /* 5818c2ecf20Sopenharmony_ci * dump the response from server 5828c2ecf20Sopenharmony_ci * This should be after parse_header which poplulate pdu_fcall. 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci trace_9p_protocol_dump(c, &req->rc); 5858c2ecf20Sopenharmony_ci if (err) { 5868c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err); 5878c2ecf20Sopenharmony_ci return err; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (type != P9_RERROR && type != P9_RLERROR) 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!p9_is_proto_dotl(c)) { 5948c2ecf20Sopenharmony_ci /* Error is reported in string format */ 5958c2ecf20Sopenharmony_ci int len; 5968c2ecf20Sopenharmony_ci /* 7 = header size for RERROR; */ 5978c2ecf20Sopenharmony_ci int inline_len = in_hdrlen - 7; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci len = req->rc.size - req->rc.offset; 6008c2ecf20Sopenharmony_ci if (len > (P9_ZC_HDR_SZ - 7)) { 6018c2ecf20Sopenharmony_ci err = -EFAULT; 6028c2ecf20Sopenharmony_ci goto out_err; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci ename = &req->rc.sdata[req->rc.offset]; 6068c2ecf20Sopenharmony_ci if (len > inline_len) { 6078c2ecf20Sopenharmony_ci /* We have error in external buffer */ 6088c2ecf20Sopenharmony_ci if (!copy_from_iter_full(ename + inline_len, 6098c2ecf20Sopenharmony_ci len - inline_len, uidata)) { 6108c2ecf20Sopenharmony_ci err = -EFAULT; 6118c2ecf20Sopenharmony_ci goto out_err; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci ename = NULL; 6158c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, c->proto_version, "s?d", 6168c2ecf20Sopenharmony_ci &ename, &ecode); 6178c2ecf20Sopenharmony_ci if (err) 6188c2ecf20Sopenharmony_ci goto out_err; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (p9_is_proto_dotu(c) && ecode < 512) 6218c2ecf20Sopenharmony_ci err = -ecode; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (!err) { 6248c2ecf20Sopenharmony_ci err = p9_errstr2errno(ename, strlen(ename)); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", 6278c2ecf20Sopenharmony_ci -ecode, ename); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci kfree(ename); 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode); 6328c2ecf20Sopenharmony_ci err = -ecode; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci return err; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ciout_err: 6398c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); 6408c2ecf20Sopenharmony_ci return err; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic struct p9_req_t * 6448c2ecf20Sopenharmony_cip9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/** 6478c2ecf20Sopenharmony_ci * p9_client_flush - flush (cancel) a request 6488c2ecf20Sopenharmony_ci * @c: client state 6498c2ecf20Sopenharmony_ci * @oldreq: request to cancel 6508c2ecf20Sopenharmony_ci * 6518c2ecf20Sopenharmony_ci * This sents a flush for a particular request and links 6528c2ecf20Sopenharmony_ci * the flush request to the original request. The current 6538c2ecf20Sopenharmony_ci * code only supports a single flush request although the protocol 6548c2ecf20Sopenharmony_ci * allows for multiple flush requests to be sent for a single request. 6558c2ecf20Sopenharmony_ci * 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct p9_req_t *req; 6618c2ecf20Sopenharmony_ci int16_t oldtag; 6628c2ecf20Sopenharmony_ci int err; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci err = p9_parse_header(&oldreq->tc, NULL, NULL, &oldtag, 1); 6658c2ecf20Sopenharmony_ci if (err) 6668c2ecf20Sopenharmony_ci return err; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag); 6718c2ecf20Sopenharmony_ci if (IS_ERR(req)) 6728c2ecf20Sopenharmony_ci return PTR_ERR(req); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * if we haven't received a response for oldreq, 6768c2ecf20Sopenharmony_ci * remove it from the list 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci if (oldreq->status == REQ_STATUS_SENT) { 6798c2ecf20Sopenharmony_ci if (c->trans_mod->cancelled) 6808c2ecf20Sopenharmony_ci c->trans_mod->cancelled(c, oldreq); 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci p9_tag_remove(c, req); 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_cistatic struct p9_req_t *p9_client_prepare_req(struct p9_client *c, 6888c2ecf20Sopenharmony_ci int8_t type, int req_size, 6898c2ecf20Sopenharmony_ci const char *fmt, va_list ap) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci int err; 6928c2ecf20Sopenharmony_ci struct p9_req_t *req; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "client %p op %d\n", c, type); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* we allow for any status other than disconnected */ 6978c2ecf20Sopenharmony_ci if (c->status == Disconnected) 6988c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* if status is begin_disconnected we allow only clunk request */ 7018c2ecf20Sopenharmony_ci if ((c->status == BeginDisconnect) && (type != P9_TCLUNK)) 7028c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci req = p9_tag_alloc(c, type, req_size); 7058c2ecf20Sopenharmony_ci if (IS_ERR(req)) 7068c2ecf20Sopenharmony_ci return req; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* marshall the data */ 7098c2ecf20Sopenharmony_ci p9pdu_prepare(&req->tc, req->tc.tag, type); 7108c2ecf20Sopenharmony_ci err = p9pdu_vwritef(&req->tc, c->proto_version, fmt, ap); 7118c2ecf20Sopenharmony_ci if (err) 7128c2ecf20Sopenharmony_ci goto reterr; 7138c2ecf20Sopenharmony_ci p9pdu_finalize(c, &req->tc); 7148c2ecf20Sopenharmony_ci trace_9p_client_req(c, type, req->tc.tag); 7158c2ecf20Sopenharmony_ci return req; 7168c2ecf20Sopenharmony_cireterr: 7178c2ecf20Sopenharmony_ci p9_tag_remove(c, req); 7188c2ecf20Sopenharmony_ci /* We have to put also the 2nd reference as it won't be used */ 7198c2ecf20Sopenharmony_ci p9_req_put(req); 7208c2ecf20Sopenharmony_ci return ERR_PTR(err); 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/** 7248c2ecf20Sopenharmony_ci * p9_client_rpc - issue a request and wait for a response 7258c2ecf20Sopenharmony_ci * @c: client session 7268c2ecf20Sopenharmony_ci * @type: type of request 7278c2ecf20Sopenharmony_ci * @fmt: protocol format string (see protocol.c) 7288c2ecf20Sopenharmony_ci * 7298c2ecf20Sopenharmony_ci * Returns request structure (which client must free using p9_tag_remove) 7308c2ecf20Sopenharmony_ci */ 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic struct p9_req_t * 7338c2ecf20Sopenharmony_cip9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci va_list ap; 7368c2ecf20Sopenharmony_ci int sigpending, err; 7378c2ecf20Sopenharmony_ci unsigned long flags; 7388c2ecf20Sopenharmony_ci struct p9_req_t *req; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci va_start(ap, fmt); 7418c2ecf20Sopenharmony_ci req = p9_client_prepare_req(c, type, c->msize, fmt, ap); 7428c2ecf20Sopenharmony_ci va_end(ap); 7438c2ecf20Sopenharmony_ci if (IS_ERR(req)) 7448c2ecf20Sopenharmony_ci return req; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (signal_pending(current)) { 7478c2ecf20Sopenharmony_ci sigpending = 1; 7488c2ecf20Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 7498c2ecf20Sopenharmony_ci } else 7508c2ecf20Sopenharmony_ci sigpending = 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci err = c->trans_mod->request(c, req); 7538c2ecf20Sopenharmony_ci if (err < 0) { 7548c2ecf20Sopenharmony_ci /* write won't happen */ 7558c2ecf20Sopenharmony_ci p9_req_put(req); 7568c2ecf20Sopenharmony_ci if (err != -ERESTARTSYS && err != -EFAULT) 7578c2ecf20Sopenharmony_ci c->status = Disconnected; 7588c2ecf20Sopenharmony_ci goto recalc_sigpending; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ciagain: 7618c2ecf20Sopenharmony_ci /* Wait for the response */ 7628c2ecf20Sopenharmony_ci err = wait_event_killable(req->wq, req->status >= REQ_STATUS_RCVD); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci * Make sure our req is coherent with regard to updates in other 7668c2ecf20Sopenharmony_ci * threads - echoes to wmb() in the callback 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_ci smp_rmb(); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if ((err == -ERESTARTSYS) && (c->status == Connected) 7718c2ecf20Sopenharmony_ci && (type == P9_TFLUSH)) { 7728c2ecf20Sopenharmony_ci sigpending = 1; 7738c2ecf20Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 7748c2ecf20Sopenharmony_ci goto again; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (req->status == REQ_STATUS_ERROR) { 7788c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 7798c2ecf20Sopenharmony_ci err = req->t_err; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci if ((err == -ERESTARTSYS) && (c->status == Connected)) { 7828c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "flushing\n"); 7838c2ecf20Sopenharmony_ci sigpending = 1; 7848c2ecf20Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (c->trans_mod->cancel(c, req)) 7878c2ecf20Sopenharmony_ci p9_client_flush(c, req); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci /* if we received the response anyway, don't signal error */ 7908c2ecf20Sopenharmony_ci if (req->status == REQ_STATUS_RCVD) 7918c2ecf20Sopenharmony_ci err = 0; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_cirecalc_sigpending: 7948c2ecf20Sopenharmony_ci if (sigpending) { 7958c2ecf20Sopenharmony_ci spin_lock_irqsave(¤t->sighand->siglock, flags); 7968c2ecf20Sopenharmony_ci recalc_sigpending(); 7978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(¤t->sighand->siglock, flags); 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci if (err < 0) 8008c2ecf20Sopenharmony_ci goto reterr; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci err = p9_check_errors(c, req); 8038c2ecf20Sopenharmony_ci trace_9p_client_res(c, type, req->rc.tag, err); 8048c2ecf20Sopenharmony_ci if (!err) 8058c2ecf20Sopenharmony_ci return req; 8068c2ecf20Sopenharmony_cireterr: 8078c2ecf20Sopenharmony_ci p9_tag_remove(c, req); 8088c2ecf20Sopenharmony_ci return ERR_PTR(safe_errno(err)); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/** 8128c2ecf20Sopenharmony_ci * p9_client_zc_rpc - issue a request and wait for a response 8138c2ecf20Sopenharmony_ci * @c: client session 8148c2ecf20Sopenharmony_ci * @type: type of request 8158c2ecf20Sopenharmony_ci * @uidata: destination for zero copy read 8168c2ecf20Sopenharmony_ci * @uodata: source for zero copy write 8178c2ecf20Sopenharmony_ci * @inlen: read buffer size 8188c2ecf20Sopenharmony_ci * @olen: write buffer size 8198c2ecf20Sopenharmony_ci * @in_hdrlen: reader header size, This is the size of response protocol data 8208c2ecf20Sopenharmony_ci * @fmt: protocol format string (see protocol.c) 8218c2ecf20Sopenharmony_ci * 8228c2ecf20Sopenharmony_ci * Returns request structure (which client must free using p9_tag_remove) 8238c2ecf20Sopenharmony_ci */ 8248c2ecf20Sopenharmony_cistatic struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type, 8258c2ecf20Sopenharmony_ci struct iov_iter *uidata, 8268c2ecf20Sopenharmony_ci struct iov_iter *uodata, 8278c2ecf20Sopenharmony_ci int inlen, int olen, int in_hdrlen, 8288c2ecf20Sopenharmony_ci const char *fmt, ...) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci va_list ap; 8318c2ecf20Sopenharmony_ci int sigpending, err; 8328c2ecf20Sopenharmony_ci unsigned long flags; 8338c2ecf20Sopenharmony_ci struct p9_req_t *req; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci va_start(ap, fmt); 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * We allocate a inline protocol data of only 4k bytes. 8388c2ecf20Sopenharmony_ci * The actual content is passed in zero-copy fashion. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci req = p9_client_prepare_req(c, type, P9_ZC_HDR_SZ, fmt, ap); 8418c2ecf20Sopenharmony_ci va_end(ap); 8428c2ecf20Sopenharmony_ci if (IS_ERR(req)) 8438c2ecf20Sopenharmony_ci return req; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (signal_pending(current)) { 8468c2ecf20Sopenharmony_ci sigpending = 1; 8478c2ecf20Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 8488c2ecf20Sopenharmony_ci } else 8498c2ecf20Sopenharmony_ci sigpending = 0; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci err = c->trans_mod->zc_request(c, req, uidata, uodata, 8528c2ecf20Sopenharmony_ci inlen, olen, in_hdrlen); 8538c2ecf20Sopenharmony_ci if (err < 0) { 8548c2ecf20Sopenharmony_ci if (err == -EIO) 8558c2ecf20Sopenharmony_ci c->status = Disconnected; 8568c2ecf20Sopenharmony_ci if (err != -ERESTARTSYS) 8578c2ecf20Sopenharmony_ci goto recalc_sigpending; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci if (req->status == REQ_STATUS_ERROR) { 8608c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err); 8618c2ecf20Sopenharmony_ci err = req->t_err; 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci if ((err == -ERESTARTSYS) && (c->status == Connected)) { 8648c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "flushing\n"); 8658c2ecf20Sopenharmony_ci sigpending = 1; 8668c2ecf20Sopenharmony_ci clear_thread_flag(TIF_SIGPENDING); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (c->trans_mod->cancel(c, req)) 8698c2ecf20Sopenharmony_ci p9_client_flush(c, req); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* if we received the response anyway, don't signal error */ 8728c2ecf20Sopenharmony_ci if (req->status == REQ_STATUS_RCVD) 8738c2ecf20Sopenharmony_ci err = 0; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_cirecalc_sigpending: 8768c2ecf20Sopenharmony_ci if (sigpending) { 8778c2ecf20Sopenharmony_ci spin_lock_irqsave(¤t->sighand->siglock, flags); 8788c2ecf20Sopenharmony_ci recalc_sigpending(); 8798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(¤t->sighand->siglock, flags); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci if (err < 0) 8828c2ecf20Sopenharmony_ci goto reterr; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci err = p9_check_zc_errors(c, req, uidata, in_hdrlen); 8858c2ecf20Sopenharmony_ci trace_9p_client_res(c, type, req->rc.tag, err); 8868c2ecf20Sopenharmony_ci if (!err) 8878c2ecf20Sopenharmony_ci return req; 8888c2ecf20Sopenharmony_cireterr: 8898c2ecf20Sopenharmony_ci p9_tag_remove(c, req); 8908c2ecf20Sopenharmony_ci return ERR_PTR(safe_errno(err)); 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic struct p9_fid *p9_fid_create(struct p9_client *clnt) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci int ret; 8968c2ecf20Sopenharmony_ci struct p9_fid *fid; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_FID, "clnt %p\n", clnt); 8998c2ecf20Sopenharmony_ci fid = kzalloc(sizeof(struct p9_fid), GFP_KERNEL); 9008c2ecf20Sopenharmony_ci if (!fid) 9018c2ecf20Sopenharmony_ci return NULL; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci fid->mode = -1; 9048c2ecf20Sopenharmony_ci fid->uid = current_fsuid(); 9058c2ecf20Sopenharmony_ci fid->clnt = clnt; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci idr_preload(GFP_KERNEL); 9088c2ecf20Sopenharmony_ci spin_lock_irq(&clnt->lock); 9098c2ecf20Sopenharmony_ci ret = idr_alloc_u32(&clnt->fids, fid, &fid->fid, P9_NOFID - 1, 9108c2ecf20Sopenharmony_ci GFP_NOWAIT); 9118c2ecf20Sopenharmony_ci spin_unlock_irq(&clnt->lock); 9128c2ecf20Sopenharmony_ci idr_preload_end(); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (!ret) 9158c2ecf20Sopenharmony_ci return fid; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci kfree(fid); 9188c2ecf20Sopenharmony_ci return NULL; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_cistatic void p9_fid_destroy(struct p9_fid *fid) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci struct p9_client *clnt; 9248c2ecf20Sopenharmony_ci unsigned long flags; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid); 9278c2ecf20Sopenharmony_ci clnt = fid->clnt; 9288c2ecf20Sopenharmony_ci spin_lock_irqsave(&clnt->lock, flags); 9298c2ecf20Sopenharmony_ci idr_remove(&clnt->fids, fid->fid); 9308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clnt->lock, flags); 9318c2ecf20Sopenharmony_ci kfree(fid->rdir); 9328c2ecf20Sopenharmony_ci kfree(fid); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int p9_client_version(struct p9_client *c) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci int err = 0; 9388c2ecf20Sopenharmony_ci struct p9_req_t *req; 9398c2ecf20Sopenharmony_ci char *version = NULL; 9408c2ecf20Sopenharmony_ci int msize; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n", 9438c2ecf20Sopenharmony_ci c->msize, c->proto_version); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci switch (c->proto_version) { 9468c2ecf20Sopenharmony_ci case p9_proto_2000L: 9478c2ecf20Sopenharmony_ci req = p9_client_rpc(c, P9_TVERSION, "ds", 9488c2ecf20Sopenharmony_ci c->msize, "9P2000.L"); 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci case p9_proto_2000u: 9518c2ecf20Sopenharmony_ci req = p9_client_rpc(c, P9_TVERSION, "ds", 9528c2ecf20Sopenharmony_ci c->msize, "9P2000.u"); 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci case p9_proto_legacy: 9558c2ecf20Sopenharmony_ci req = p9_client_rpc(c, P9_TVERSION, "ds", 9568c2ecf20Sopenharmony_ci c->msize, "9P2000"); 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci default: 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (IS_ERR(req)) 9638c2ecf20Sopenharmony_ci return PTR_ERR(req); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, c->proto_version, "ds", &msize, &version); 9668c2ecf20Sopenharmony_ci if (err) { 9678c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "version error %d\n", err); 9688c2ecf20Sopenharmony_ci trace_9p_protocol_dump(c, &req->rc); 9698c2ecf20Sopenharmony_ci goto error; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version); 9738c2ecf20Sopenharmony_ci if (!strncmp(version, "9P2000.L", 8)) 9748c2ecf20Sopenharmony_ci c->proto_version = p9_proto_2000L; 9758c2ecf20Sopenharmony_ci else if (!strncmp(version, "9P2000.u", 8)) 9768c2ecf20Sopenharmony_ci c->proto_version = p9_proto_2000u; 9778c2ecf20Sopenharmony_ci else if (!strncmp(version, "9P2000", 6)) 9788c2ecf20Sopenharmony_ci c->proto_version = p9_proto_legacy; 9798c2ecf20Sopenharmony_ci else { 9808c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 9818c2ecf20Sopenharmony_ci "server returned an unknown version: %s\n", version); 9828c2ecf20Sopenharmony_ci err = -EREMOTEIO; 9838c2ecf20Sopenharmony_ci goto error; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (msize < 4096) { 9878c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 9888c2ecf20Sopenharmony_ci "server returned a msize < 4096: %d\n", msize); 9898c2ecf20Sopenharmony_ci err = -EREMOTEIO; 9908c2ecf20Sopenharmony_ci goto error; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci if (msize < c->msize) 9938c2ecf20Sopenharmony_ci c->msize = msize; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cierror: 9968c2ecf20Sopenharmony_ci kfree(version); 9978c2ecf20Sopenharmony_ci p9_tag_remove(c, req); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci return err; 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistruct p9_client *p9_client_create(const char *dev_name, char *options) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci int err; 10058c2ecf20Sopenharmony_ci struct p9_client *clnt; 10068c2ecf20Sopenharmony_ci char *client_id; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci err = 0; 10098c2ecf20Sopenharmony_ci clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL); 10108c2ecf20Sopenharmony_ci if (!clnt) 10118c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci clnt->trans_mod = NULL; 10148c2ecf20Sopenharmony_ci clnt->trans = NULL; 10158c2ecf20Sopenharmony_ci clnt->fcall_cache = NULL; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci client_id = utsname()->nodename; 10188c2ecf20Sopenharmony_ci memcpy(clnt->name, client_id, strlen(client_id) + 1); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci spin_lock_init(&clnt->lock); 10218c2ecf20Sopenharmony_ci idr_init(&clnt->fids); 10228c2ecf20Sopenharmony_ci idr_init(&clnt->reqs); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci err = parse_opts(options, clnt); 10258c2ecf20Sopenharmony_ci if (err < 0) 10268c2ecf20Sopenharmony_ci goto free_client; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (!clnt->trans_mod) 10298c2ecf20Sopenharmony_ci clnt->trans_mod = v9fs_get_default_trans(); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (clnt->trans_mod == NULL) { 10328c2ecf20Sopenharmony_ci err = -EPROTONOSUPPORT; 10338c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 10348c2ecf20Sopenharmony_ci "No transport defined or default transport\n"); 10358c2ecf20Sopenharmony_ci goto free_client; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n", 10398c2ecf20Sopenharmony_ci clnt, clnt->trans_mod, clnt->msize, clnt->proto_version); 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci err = clnt->trans_mod->create(clnt, dev_name, options); 10428c2ecf20Sopenharmony_ci if (err) 10438c2ecf20Sopenharmony_ci goto put_trans; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (clnt->msize > clnt->trans_mod->maxsize) 10468c2ecf20Sopenharmony_ci clnt->msize = clnt->trans_mod->maxsize; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (clnt->msize < 4096) { 10498c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 10508c2ecf20Sopenharmony_ci "Please specify a msize of at least 4k\n"); 10518c2ecf20Sopenharmony_ci err = -EINVAL; 10528c2ecf20Sopenharmony_ci goto close_trans; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci err = p9_client_version(clnt); 10568c2ecf20Sopenharmony_ci if (err) 10578c2ecf20Sopenharmony_ci goto close_trans; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* P9_HDRSZ + 4 is the smallest packet header we can have that is 10608c2ecf20Sopenharmony_ci * followed by data accessed from userspace by read 10618c2ecf20Sopenharmony_ci */ 10628c2ecf20Sopenharmony_ci clnt->fcall_cache = 10638c2ecf20Sopenharmony_ci kmem_cache_create_usercopy("9p-fcall-cache", clnt->msize, 10648c2ecf20Sopenharmony_ci 0, 0, P9_HDRSZ + 4, 10658c2ecf20Sopenharmony_ci clnt->msize - (P9_HDRSZ + 4), 10668c2ecf20Sopenharmony_ci NULL); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return clnt; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ciclose_trans: 10718c2ecf20Sopenharmony_ci clnt->trans_mod->close(clnt); 10728c2ecf20Sopenharmony_ciput_trans: 10738c2ecf20Sopenharmony_ci v9fs_put_trans(clnt->trans_mod); 10748c2ecf20Sopenharmony_cifree_client: 10758c2ecf20Sopenharmony_ci kfree(clnt); 10768c2ecf20Sopenharmony_ci return ERR_PTR(err); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_create); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_civoid p9_client_destroy(struct p9_client *clnt) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct p9_fid *fid; 10838c2ecf20Sopenharmony_ci int id; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (clnt->trans_mod) 10888c2ecf20Sopenharmony_ci clnt->trans_mod->close(clnt); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci v9fs_put_trans(clnt->trans_mod); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci idr_for_each_entry(&clnt->fids, fid, id) { 10938c2ecf20Sopenharmony_ci pr_info("Found fid %d not clunked\n", fid->fid); 10948c2ecf20Sopenharmony_ci p9_fid_destroy(fid); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci p9_tag_cleanup(clnt); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci kmem_cache_destroy(clnt->fcall_cache); 11008c2ecf20Sopenharmony_ci kfree(clnt); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_destroy); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_civoid p9_client_disconnect(struct p9_client *clnt) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt); 11078c2ecf20Sopenharmony_ci clnt->status = Disconnected; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_disconnect); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_civoid p9_client_begin_disconnect(struct p9_client *clnt) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt); 11148c2ecf20Sopenharmony_ci clnt->status = BeginDisconnect; 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_begin_disconnect); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistruct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid, 11198c2ecf20Sopenharmony_ci const char *uname, kuid_t n_uname, const char *aname) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci int err = 0; 11228c2ecf20Sopenharmony_ci struct p9_req_t *req; 11238c2ecf20Sopenharmony_ci struct p9_fid *fid; 11248c2ecf20Sopenharmony_ci struct p9_qid qid; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n", 11288c2ecf20Sopenharmony_ci afid ? afid->fid : -1, uname, aname); 11298c2ecf20Sopenharmony_ci fid = p9_fid_create(clnt); 11308c2ecf20Sopenharmony_ci if (!fid) { 11318c2ecf20Sopenharmony_ci err = -ENOMEM; 11328c2ecf20Sopenharmony_ci goto error; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci fid->uid = n_uname; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid, 11378c2ecf20Sopenharmony_ci afid ? afid->fid : P9_NOFID, uname, aname, n_uname); 11388c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 11398c2ecf20Sopenharmony_ci err = PTR_ERR(req); 11408c2ecf20Sopenharmony_ci goto error; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", &qid); 11448c2ecf20Sopenharmony_ci if (err) { 11458c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 11468c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 11478c2ecf20Sopenharmony_ci goto error; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n", 11518c2ecf20Sopenharmony_ci qid.type, (unsigned long long)qid.path, qid.version); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci memmove(&fid->qid, &qid, sizeof(struct p9_qid)); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 11568c2ecf20Sopenharmony_ci return fid; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cierror: 11598c2ecf20Sopenharmony_ci if (fid) 11608c2ecf20Sopenharmony_ci p9_fid_destroy(fid); 11618c2ecf20Sopenharmony_ci return ERR_PTR(err); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_attach); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistruct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, 11668c2ecf20Sopenharmony_ci const unsigned char * const *wnames, int clone) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci int err; 11698c2ecf20Sopenharmony_ci struct p9_client *clnt; 11708c2ecf20Sopenharmony_ci struct p9_fid *fid; 11718c2ecf20Sopenharmony_ci struct p9_qid *wqids; 11728c2ecf20Sopenharmony_ci struct p9_req_t *req; 11738c2ecf20Sopenharmony_ci uint16_t nwqids, count; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci err = 0; 11768c2ecf20Sopenharmony_ci wqids = NULL; 11778c2ecf20Sopenharmony_ci clnt = oldfid->clnt; 11788c2ecf20Sopenharmony_ci if (clone) { 11798c2ecf20Sopenharmony_ci fid = p9_fid_create(clnt); 11808c2ecf20Sopenharmony_ci if (!fid) { 11818c2ecf20Sopenharmony_ci err = -ENOMEM; 11828c2ecf20Sopenharmony_ci goto error; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci fid->uid = oldfid->uid; 11868c2ecf20Sopenharmony_ci } else 11878c2ecf20Sopenharmony_ci fid = oldfid; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n", 11918c2ecf20Sopenharmony_ci oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, 11948c2ecf20Sopenharmony_ci nwname, wnames); 11958c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 11968c2ecf20Sopenharmony_ci err = PTR_ERR(req); 11978c2ecf20Sopenharmony_ci goto error; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "R", &nwqids, &wqids); 12018c2ecf20Sopenharmony_ci if (err) { 12028c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 12038c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 12048c2ecf20Sopenharmony_ci goto clunk_fid; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (nwqids != nwname) { 12118c2ecf20Sopenharmony_ci err = -ENOENT; 12128c2ecf20Sopenharmony_ci goto clunk_fid; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci for (count = 0; count < nwqids; count++) 12168c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n", 12178c2ecf20Sopenharmony_ci count, wqids[count].type, 12188c2ecf20Sopenharmony_ci (unsigned long long)wqids[count].path, 12198c2ecf20Sopenharmony_ci wqids[count].version); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (nwname) 12228c2ecf20Sopenharmony_ci memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid)); 12238c2ecf20Sopenharmony_ci else 12248c2ecf20Sopenharmony_ci fid->qid = oldfid->qid; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci kfree(wqids); 12278c2ecf20Sopenharmony_ci return fid; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ciclunk_fid: 12308c2ecf20Sopenharmony_ci kfree(wqids); 12318c2ecf20Sopenharmony_ci p9_client_clunk(fid); 12328c2ecf20Sopenharmony_ci fid = NULL; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_cierror: 12358c2ecf20Sopenharmony_ci if (fid && (fid != oldfid)) 12368c2ecf20Sopenharmony_ci p9_fid_destroy(fid); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci return ERR_PTR(err); 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_walk); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ciint p9_client_open(struct p9_fid *fid, int mode) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci int err; 12458c2ecf20Sopenharmony_ci struct p9_client *clnt; 12468c2ecf20Sopenharmony_ci struct p9_req_t *req; 12478c2ecf20Sopenharmony_ci struct p9_qid qid; 12488c2ecf20Sopenharmony_ci int iounit; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci clnt = fid->clnt; 12518c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> %s fid %d mode %d\n", 12528c2ecf20Sopenharmony_ci p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode); 12538c2ecf20Sopenharmony_ci err = 0; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (fid->mode != -1) 12568c2ecf20Sopenharmony_ci return -EINVAL; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (p9_is_proto_dotl(clnt)) 12598c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode); 12608c2ecf20Sopenharmony_ci else 12618c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode); 12628c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 12638c2ecf20Sopenharmony_ci err = PTR_ERR(req); 12648c2ecf20Sopenharmony_ci goto error; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit); 12688c2ecf20Sopenharmony_ci if (err) { 12698c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 12708c2ecf20Sopenharmony_ci goto free_and_error; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n", 12748c2ecf20Sopenharmony_ci p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type, 12758c2ecf20Sopenharmony_ci (unsigned long long)qid.path, qid.version, iounit); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci fid->mode = mode; 12788c2ecf20Sopenharmony_ci fid->iounit = iounit; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cifree_and_error: 12818c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 12828c2ecf20Sopenharmony_cierror: 12838c2ecf20Sopenharmony_ci return err; 12848c2ecf20Sopenharmony_ci} 12858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_open); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ciint p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags, u32 mode, 12888c2ecf20Sopenharmony_ci kgid_t gid, struct p9_qid *qid) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci int err = 0; 12918c2ecf20Sopenharmony_ci struct p9_client *clnt; 12928c2ecf20Sopenharmony_ci struct p9_req_t *req; 12938c2ecf20Sopenharmony_ci int iounit; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 12968c2ecf20Sopenharmony_ci ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n", 12978c2ecf20Sopenharmony_ci ofid->fid, name, flags, mode, 12988c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, gid)); 12998c2ecf20Sopenharmony_ci clnt = ofid->clnt; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (ofid->mode != -1) 13028c2ecf20Sopenharmony_ci return -EINVAL; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TLCREATE, "dsddg", ofid->fid, name, flags, 13058c2ecf20Sopenharmony_ci mode, gid); 13068c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 13078c2ecf20Sopenharmony_ci err = PTR_ERR(req); 13088c2ecf20Sopenharmony_ci goto error; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", qid, &iounit); 13128c2ecf20Sopenharmony_ci if (err) { 13138c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 13148c2ecf20Sopenharmony_ci goto free_and_error; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n", 13188c2ecf20Sopenharmony_ci qid->type, 13198c2ecf20Sopenharmony_ci (unsigned long long)qid->path, 13208c2ecf20Sopenharmony_ci qid->version, iounit); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci ofid->mode = mode; 13238c2ecf20Sopenharmony_ci ofid->iounit = iounit; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cifree_and_error: 13268c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 13278c2ecf20Sopenharmony_cierror: 13288c2ecf20Sopenharmony_ci return err; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_create_dotl); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ciint p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode, 13338c2ecf20Sopenharmony_ci char *extension) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci int err; 13368c2ecf20Sopenharmony_ci struct p9_client *clnt; 13378c2ecf20Sopenharmony_ci struct p9_req_t *req; 13388c2ecf20Sopenharmony_ci struct p9_qid qid; 13398c2ecf20Sopenharmony_ci int iounit; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n", 13428c2ecf20Sopenharmony_ci fid->fid, name, perm, mode); 13438c2ecf20Sopenharmony_ci err = 0; 13448c2ecf20Sopenharmony_ci clnt = fid->clnt; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (fid->mode != -1) 13478c2ecf20Sopenharmony_ci return -EINVAL; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm, 13508c2ecf20Sopenharmony_ci mode, extension); 13518c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 13528c2ecf20Sopenharmony_ci err = PTR_ERR(req); 13538c2ecf20Sopenharmony_ci goto error; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit); 13578c2ecf20Sopenharmony_ci if (err) { 13588c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 13598c2ecf20Sopenharmony_ci goto free_and_error; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n", 13638c2ecf20Sopenharmony_ci qid.type, 13648c2ecf20Sopenharmony_ci (unsigned long long)qid.path, 13658c2ecf20Sopenharmony_ci qid.version, iounit); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci fid->mode = mode; 13688c2ecf20Sopenharmony_ci fid->iounit = iounit; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cifree_and_error: 13718c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 13728c2ecf20Sopenharmony_cierror: 13738c2ecf20Sopenharmony_ci return err; 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_fcreate); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ciint p9_client_symlink(struct p9_fid *dfid, const char *name, 13788c2ecf20Sopenharmony_ci const char *symtgt, kgid_t gid, struct p9_qid *qid) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci int err = 0; 13818c2ecf20Sopenharmony_ci struct p9_client *clnt; 13828c2ecf20Sopenharmony_ci struct p9_req_t *req; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n", 13858c2ecf20Sopenharmony_ci dfid->fid, name, symtgt); 13868c2ecf20Sopenharmony_ci clnt = dfid->clnt; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TSYMLINK, "dssg", dfid->fid, name, symtgt, 13898c2ecf20Sopenharmony_ci gid); 13908c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 13918c2ecf20Sopenharmony_ci err = PTR_ERR(req); 13928c2ecf20Sopenharmony_ci goto error; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid); 13968c2ecf20Sopenharmony_ci if (err) { 13978c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 13988c2ecf20Sopenharmony_ci goto free_and_error; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n", 14028c2ecf20Sopenharmony_ci qid->type, (unsigned long long)qid->path, qid->version); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cifree_and_error: 14058c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 14068c2ecf20Sopenharmony_cierror: 14078c2ecf20Sopenharmony_ci return err; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_symlink); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ciint p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, const char *newname) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci struct p9_client *clnt; 14148c2ecf20Sopenharmony_ci struct p9_req_t *req; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n", 14178c2ecf20Sopenharmony_ci dfid->fid, oldfid->fid, newname); 14188c2ecf20Sopenharmony_ci clnt = dfid->clnt; 14198c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid, 14208c2ecf20Sopenharmony_ci newname); 14218c2ecf20Sopenharmony_ci if (IS_ERR(req)) 14228c2ecf20Sopenharmony_ci return PTR_ERR(req); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RLINK\n"); 14258c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 14268c2ecf20Sopenharmony_ci return 0; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_link); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ciint p9_client_fsync(struct p9_fid *fid, int datasync) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci int err; 14338c2ecf20Sopenharmony_ci struct p9_client *clnt; 14348c2ecf20Sopenharmony_ci struct p9_req_t *req; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n", 14378c2ecf20Sopenharmony_ci fid->fid, datasync); 14388c2ecf20Sopenharmony_ci err = 0; 14398c2ecf20Sopenharmony_ci clnt = fid->clnt; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync); 14428c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 14438c2ecf20Sopenharmony_ci err = PTR_ERR(req); 14448c2ecf20Sopenharmony_ci goto error; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_cierror: 14528c2ecf20Sopenharmony_ci return err; 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_fsync); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ciint p9_client_clunk(struct p9_fid *fid) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci int err; 14598c2ecf20Sopenharmony_ci struct p9_client *clnt; 14608c2ecf20Sopenharmony_ci struct p9_req_t *req; 14618c2ecf20Sopenharmony_ci int retries = 0; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (!fid) { 14648c2ecf20Sopenharmony_ci pr_warn("%s (%d): Trying to clunk with NULL fid\n", 14658c2ecf20Sopenharmony_ci __func__, task_pid_nr(current)); 14668c2ecf20Sopenharmony_ci dump_stack(); 14678c2ecf20Sopenharmony_ci return 0; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ciagain: 14718c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n", fid->fid, 14728c2ecf20Sopenharmony_ci retries); 14738c2ecf20Sopenharmony_ci err = 0; 14748c2ecf20Sopenharmony_ci clnt = fid->clnt; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid); 14778c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 14788c2ecf20Sopenharmony_ci err = PTR_ERR(req); 14798c2ecf20Sopenharmony_ci goto error; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 14858c2ecf20Sopenharmony_cierror: 14868c2ecf20Sopenharmony_ci /* 14878c2ecf20Sopenharmony_ci * Fid is not valid even after a failed clunk 14888c2ecf20Sopenharmony_ci * If interrupted, retry once then give up and 14898c2ecf20Sopenharmony_ci * leak fid until umount. 14908c2ecf20Sopenharmony_ci */ 14918c2ecf20Sopenharmony_ci if (err == -ERESTARTSYS) { 14928c2ecf20Sopenharmony_ci if (retries++ == 0) 14938c2ecf20Sopenharmony_ci goto again; 14948c2ecf20Sopenharmony_ci } else 14958c2ecf20Sopenharmony_ci p9_fid_destroy(fid); 14968c2ecf20Sopenharmony_ci return err; 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_clunk); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ciint p9_client_remove(struct p9_fid *fid) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci int err; 15038c2ecf20Sopenharmony_ci struct p9_client *clnt; 15048c2ecf20Sopenharmony_ci struct p9_req_t *req; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid); 15078c2ecf20Sopenharmony_ci err = 0; 15088c2ecf20Sopenharmony_ci clnt = fid->clnt; 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid); 15118c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 15128c2ecf20Sopenharmony_ci err = PTR_ERR(req); 15138c2ecf20Sopenharmony_ci goto error; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 15198c2ecf20Sopenharmony_cierror: 15208c2ecf20Sopenharmony_ci if (err == -ERESTARTSYS) 15218c2ecf20Sopenharmony_ci p9_client_clunk(fid); 15228c2ecf20Sopenharmony_ci else 15238c2ecf20Sopenharmony_ci p9_fid_destroy(fid); 15248c2ecf20Sopenharmony_ci return err; 15258c2ecf20Sopenharmony_ci} 15268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_remove); 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ciint p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags) 15298c2ecf20Sopenharmony_ci{ 15308c2ecf20Sopenharmony_ci int err = 0; 15318c2ecf20Sopenharmony_ci struct p9_req_t *req; 15328c2ecf20Sopenharmony_ci struct p9_client *clnt; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n", 15358c2ecf20Sopenharmony_ci dfid->fid, name, flags); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci clnt = dfid->clnt; 15388c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags); 15398c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 15408c2ecf20Sopenharmony_ci err = PTR_ERR(req); 15418c2ecf20Sopenharmony_ci goto error; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 15468c2ecf20Sopenharmony_cierror: 15478c2ecf20Sopenharmony_ci return err; 15488c2ecf20Sopenharmony_ci} 15498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_unlinkat); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ciint 15528c2ecf20Sopenharmony_cip9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci int total = 0; 15558c2ecf20Sopenharmony_ci *err = 0; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci while (iov_iter_count(to)) { 15588c2ecf20Sopenharmony_ci int count; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci count = p9_client_read_once(fid, offset, to, err); 15618c2ecf20Sopenharmony_ci if (!count || *err) 15628c2ecf20Sopenharmony_ci break; 15638c2ecf20Sopenharmony_ci offset += count; 15648c2ecf20Sopenharmony_ci total += count; 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci return total; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_read); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ciint 15718c2ecf20Sopenharmony_cip9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to, 15728c2ecf20Sopenharmony_ci int *err) 15738c2ecf20Sopenharmony_ci{ 15748c2ecf20Sopenharmony_ci struct p9_client *clnt = fid->clnt; 15758c2ecf20Sopenharmony_ci struct p9_req_t *req; 15768c2ecf20Sopenharmony_ci int count = iov_iter_count(to); 15778c2ecf20Sopenharmony_ci int rsize, non_zc = 0; 15788c2ecf20Sopenharmony_ci char *dataptr; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci *err = 0; 15818c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %d\n", 15828c2ecf20Sopenharmony_ci fid->fid, (unsigned long long) offset, (int)iov_iter_count(to)); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci rsize = fid->iounit; 15858c2ecf20Sopenharmony_ci if (!rsize || rsize > clnt->msize - P9_IOHDRSZ) 15868c2ecf20Sopenharmony_ci rsize = clnt->msize - P9_IOHDRSZ; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (count < rsize) 15898c2ecf20Sopenharmony_ci rsize = count; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci /* Don't bother zerocopy for small IO (< 1024) */ 15928c2ecf20Sopenharmony_ci if (clnt->trans_mod->zc_request && rsize > 1024) { 15938c2ecf20Sopenharmony_ci /* response header len is 11 15948c2ecf20Sopenharmony_ci * PDU Header(7) + IO Size (4) 15958c2ecf20Sopenharmony_ci */ 15968c2ecf20Sopenharmony_ci req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize, 15978c2ecf20Sopenharmony_ci 0, 11, "dqd", fid->fid, 15988c2ecf20Sopenharmony_ci offset, rsize); 15998c2ecf20Sopenharmony_ci } else { 16008c2ecf20Sopenharmony_ci non_zc = 1; 16018c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, 16028c2ecf20Sopenharmony_ci rsize); 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 16058c2ecf20Sopenharmony_ci *err = PTR_ERR(req); 16068c2ecf20Sopenharmony_ci return 0; 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci *err = p9pdu_readf(&req->rc, clnt->proto_version, 16108c2ecf20Sopenharmony_ci "D", &count, &dataptr); 16118c2ecf20Sopenharmony_ci if (*err) { 16128c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 16138c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci if (rsize < count) { 16178c2ecf20Sopenharmony_ci pr_err("bogus RREAD count (%d > %d)\n", count, rsize); 16188c2ecf20Sopenharmony_ci count = rsize; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (non_zc) { 16248c2ecf20Sopenharmony_ci int n = copy_to_iter(dataptr, count, to); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (n != count) { 16278c2ecf20Sopenharmony_ci *err = -EFAULT; 16288c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 16298c2ecf20Sopenharmony_ci return n; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci } else { 16328c2ecf20Sopenharmony_ci iov_iter_advance(to, count); 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 16358c2ecf20Sopenharmony_ci return count; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_read_once); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ciint 16408c2ecf20Sopenharmony_cip9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci struct p9_client *clnt = fid->clnt; 16438c2ecf20Sopenharmony_ci struct p9_req_t *req; 16448c2ecf20Sopenharmony_ci int total = 0; 16458c2ecf20Sopenharmony_ci *err = 0; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n", 16488c2ecf20Sopenharmony_ci fid->fid, (unsigned long long) offset, 16498c2ecf20Sopenharmony_ci iov_iter_count(from)); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci while (iov_iter_count(from)) { 16528c2ecf20Sopenharmony_ci int count = iov_iter_count(from); 16538c2ecf20Sopenharmony_ci int rsize = fid->iounit; 16548c2ecf20Sopenharmony_ci if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) 16558c2ecf20Sopenharmony_ci rsize = clnt->msize - P9_IOHDRSZ; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (count < rsize) 16588c2ecf20Sopenharmony_ci rsize = count; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci /* Don't bother zerocopy for small IO (< 1024) */ 16618c2ecf20Sopenharmony_ci if (clnt->trans_mod->zc_request && rsize > 1024) { 16628c2ecf20Sopenharmony_ci req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0, 16638c2ecf20Sopenharmony_ci rsize, P9_ZC_HDR_SZ, "dqd", 16648c2ecf20Sopenharmony_ci fid->fid, offset, rsize); 16658c2ecf20Sopenharmony_ci } else { 16668c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid, 16678c2ecf20Sopenharmony_ci offset, rsize, from); 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 16708c2ecf20Sopenharmony_ci *err = PTR_ERR(req); 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &count); 16758c2ecf20Sopenharmony_ci if (*err) { 16768c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 16778c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci if (rsize < count) { 16818c2ecf20Sopenharmony_ci pr_err("bogus RWRITE count (%d > %d)\n", count, rsize); 16828c2ecf20Sopenharmony_ci count = rsize; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count); 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 16888c2ecf20Sopenharmony_ci iov_iter_advance(from, count); 16898c2ecf20Sopenharmony_ci total += count; 16908c2ecf20Sopenharmony_ci offset += count; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci return total; 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_write); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cistruct p9_wstat *p9_client_stat(struct p9_fid *fid) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci int err; 16998c2ecf20Sopenharmony_ci struct p9_client *clnt; 17008c2ecf20Sopenharmony_ci struct p9_wstat *ret = kmalloc(sizeof(struct p9_wstat), GFP_KERNEL); 17018c2ecf20Sopenharmony_ci struct p9_req_t *req; 17028c2ecf20Sopenharmony_ci u16 ignored; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci if (!ret) 17078c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci err = 0; 17108c2ecf20Sopenharmony_ci clnt = fid->clnt; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid); 17138c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 17148c2ecf20Sopenharmony_ci err = PTR_ERR(req); 17158c2ecf20Sopenharmony_ci goto error; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "wS", &ignored, ret); 17198c2ecf20Sopenharmony_ci if (err) { 17208c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 17218c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 17228c2ecf20Sopenharmony_ci goto error; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 17268c2ecf20Sopenharmony_ci "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 17278c2ecf20Sopenharmony_ci "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" 17288c2ecf20Sopenharmony_ci "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n" 17298c2ecf20Sopenharmony_ci "<<< uid=%d gid=%d n_muid=%d\n", 17308c2ecf20Sopenharmony_ci ret->size, ret->type, ret->dev, ret->qid.type, 17318c2ecf20Sopenharmony_ci (unsigned long long)ret->qid.path, ret->qid.version, ret->mode, 17328c2ecf20Sopenharmony_ci ret->atime, ret->mtime, (unsigned long long)ret->length, 17338c2ecf20Sopenharmony_ci ret->name, ret->uid, ret->gid, ret->muid, ret->extension, 17348c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, ret->n_uid), 17358c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, ret->n_gid), 17368c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, ret->n_muid)); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 17398c2ecf20Sopenharmony_ci return ret; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cierror: 17428c2ecf20Sopenharmony_ci kfree(ret); 17438c2ecf20Sopenharmony_ci return ERR_PTR(err); 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_stat); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistruct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid, 17488c2ecf20Sopenharmony_ci u64 request_mask) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci int err; 17518c2ecf20Sopenharmony_ci struct p9_client *clnt; 17528c2ecf20Sopenharmony_ci struct p9_stat_dotl *ret = kmalloc(sizeof(struct p9_stat_dotl), 17538c2ecf20Sopenharmony_ci GFP_KERNEL); 17548c2ecf20Sopenharmony_ci struct p9_req_t *req; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n", 17578c2ecf20Sopenharmony_ci fid->fid, request_mask); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci if (!ret) 17608c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci err = 0; 17638c2ecf20Sopenharmony_ci clnt = fid->clnt; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask); 17668c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 17678c2ecf20Sopenharmony_ci err = PTR_ERR(req); 17688c2ecf20Sopenharmony_ci goto error; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "A", ret); 17728c2ecf20Sopenharmony_ci if (err) { 17738c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 17748c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 17758c2ecf20Sopenharmony_ci goto error; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 17798c2ecf20Sopenharmony_ci "<<< RGETATTR st_result_mask=%lld\n" 17808c2ecf20Sopenharmony_ci "<<< qid=%x.%llx.%x\n" 17818c2ecf20Sopenharmony_ci "<<< st_mode=%8.8x st_nlink=%llu\n" 17828c2ecf20Sopenharmony_ci "<<< st_uid=%d st_gid=%d\n" 17838c2ecf20Sopenharmony_ci "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n" 17848c2ecf20Sopenharmony_ci "<<< st_atime_sec=%lld st_atime_nsec=%lld\n" 17858c2ecf20Sopenharmony_ci "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n" 17868c2ecf20Sopenharmony_ci "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n" 17878c2ecf20Sopenharmony_ci "<<< st_btime_sec=%lld st_btime_nsec=%lld\n" 17888c2ecf20Sopenharmony_ci "<<< st_gen=%lld st_data_version=%lld\n", 17898c2ecf20Sopenharmony_ci ret->st_result_mask, ret->qid.type, ret->qid.path, 17908c2ecf20Sopenharmony_ci ret->qid.version, ret->st_mode, ret->st_nlink, 17918c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, ret->st_uid), 17928c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, ret->st_gid), 17938c2ecf20Sopenharmony_ci ret->st_rdev, ret->st_size, ret->st_blksize, 17948c2ecf20Sopenharmony_ci ret->st_blocks, ret->st_atime_sec, ret->st_atime_nsec, 17958c2ecf20Sopenharmony_ci ret->st_mtime_sec, ret->st_mtime_nsec, ret->st_ctime_sec, 17968c2ecf20Sopenharmony_ci ret->st_ctime_nsec, ret->st_btime_sec, ret->st_btime_nsec, 17978c2ecf20Sopenharmony_ci ret->st_gen, ret->st_data_version); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 18008c2ecf20Sopenharmony_ci return ret; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_cierror: 18038c2ecf20Sopenharmony_ci kfree(ret); 18048c2ecf20Sopenharmony_ci return ERR_PTR(err); 18058c2ecf20Sopenharmony_ci} 18068c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_getattr_dotl); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cistatic int p9_client_statsize(struct p9_wstat *wst, int proto_version) 18098c2ecf20Sopenharmony_ci{ 18108c2ecf20Sopenharmony_ci int ret; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci /* NOTE: size shouldn't include its own length */ 18138c2ecf20Sopenharmony_ci /* size[2] type[2] dev[4] qid[13] */ 18148c2ecf20Sopenharmony_ci /* mode[4] atime[4] mtime[4] length[8]*/ 18158c2ecf20Sopenharmony_ci /* name[s] uid[s] gid[s] muid[s] */ 18168c2ecf20Sopenharmony_ci ret = 2+4+13+4+4+4+8+2+2+2+2; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (wst->name) 18198c2ecf20Sopenharmony_ci ret += strlen(wst->name); 18208c2ecf20Sopenharmony_ci if (wst->uid) 18218c2ecf20Sopenharmony_ci ret += strlen(wst->uid); 18228c2ecf20Sopenharmony_ci if (wst->gid) 18238c2ecf20Sopenharmony_ci ret += strlen(wst->gid); 18248c2ecf20Sopenharmony_ci if (wst->muid) 18258c2ecf20Sopenharmony_ci ret += strlen(wst->muid); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if ((proto_version == p9_proto_2000u) || 18288c2ecf20Sopenharmony_ci (proto_version == p9_proto_2000L)) { 18298c2ecf20Sopenharmony_ci ret += 2+4+4+4; /* extension[s] n_uid[4] n_gid[4] n_muid[4] */ 18308c2ecf20Sopenharmony_ci if (wst->extension) 18318c2ecf20Sopenharmony_ci ret += strlen(wst->extension); 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci return ret; 18358c2ecf20Sopenharmony_ci} 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ciint p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst) 18388c2ecf20Sopenharmony_ci{ 18398c2ecf20Sopenharmony_ci int err; 18408c2ecf20Sopenharmony_ci struct p9_req_t *req; 18418c2ecf20Sopenharmony_ci struct p9_client *clnt; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci err = 0; 18448c2ecf20Sopenharmony_ci clnt = fid->clnt; 18458c2ecf20Sopenharmony_ci wst->size = p9_client_statsize(wst, clnt->proto_version); 18468c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TWSTAT fid %d\n", fid->fid); 18478c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 18488c2ecf20Sopenharmony_ci " sz=%x type=%x dev=%x qid=%x.%llx.%x\n" 18498c2ecf20Sopenharmony_ci " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n" 18508c2ecf20Sopenharmony_ci " name=%s uid=%s gid=%s muid=%s extension=(%s)\n" 18518c2ecf20Sopenharmony_ci " uid=%d gid=%d n_muid=%d\n", 18528c2ecf20Sopenharmony_ci wst->size, wst->type, wst->dev, wst->qid.type, 18538c2ecf20Sopenharmony_ci (unsigned long long)wst->qid.path, wst->qid.version, wst->mode, 18548c2ecf20Sopenharmony_ci wst->atime, wst->mtime, (unsigned long long)wst->length, 18558c2ecf20Sopenharmony_ci wst->name, wst->uid, wst->gid, wst->muid, wst->extension, 18568c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, wst->n_uid), 18578c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, wst->n_gid), 18588c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, wst->n_muid)); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TWSTAT, "dwS", fid->fid, wst->size+2, wst); 18618c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 18628c2ecf20Sopenharmony_ci err = PTR_ERR(req); 18638c2ecf20Sopenharmony_ci goto error; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 18698c2ecf20Sopenharmony_cierror: 18708c2ecf20Sopenharmony_ci return err; 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_wstat); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ciint p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci int err; 18778c2ecf20Sopenharmony_ci struct p9_req_t *req; 18788c2ecf20Sopenharmony_ci struct p9_client *clnt; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci err = 0; 18818c2ecf20Sopenharmony_ci clnt = fid->clnt; 18828c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid); 18838c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 18848c2ecf20Sopenharmony_ci " valid=%x mode=%x uid=%d gid=%d size=%lld\n" 18858c2ecf20Sopenharmony_ci " atime_sec=%lld atime_nsec=%lld\n" 18868c2ecf20Sopenharmony_ci " mtime_sec=%lld mtime_nsec=%lld\n", 18878c2ecf20Sopenharmony_ci p9attr->valid, p9attr->mode, 18888c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, p9attr->uid), 18898c2ecf20Sopenharmony_ci from_kgid(&init_user_ns, p9attr->gid), 18908c2ecf20Sopenharmony_ci p9attr->size, p9attr->atime_sec, p9attr->atime_nsec, 18918c2ecf20Sopenharmony_ci p9attr->mtime_sec, p9attr->mtime_nsec); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 18968c2ecf20Sopenharmony_ci err = PTR_ERR(req); 18978c2ecf20Sopenharmony_ci goto error; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid); 19008c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 19018c2ecf20Sopenharmony_cierror: 19028c2ecf20Sopenharmony_ci return err; 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_setattr); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ciint p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci int err; 19098c2ecf20Sopenharmony_ci struct p9_req_t *req; 19108c2ecf20Sopenharmony_ci struct p9_client *clnt; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci err = 0; 19138c2ecf20Sopenharmony_ci clnt = fid->clnt; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid); 19188c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 19198c2ecf20Sopenharmony_ci err = PTR_ERR(req); 19208c2ecf20Sopenharmony_ci goto error; 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type, 19248c2ecf20Sopenharmony_ci &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail, 19258c2ecf20Sopenharmony_ci &sb->files, &sb->ffree, &sb->fsid, &sb->namelen); 19268c2ecf20Sopenharmony_ci if (err) { 19278c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 19288c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 19298c2ecf20Sopenharmony_ci goto error; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RSTATFS fid %d type 0x%lx bsize %ld " 19338c2ecf20Sopenharmony_ci "blocks %llu bfree %llu bavail %llu files %llu ffree %llu " 19348c2ecf20Sopenharmony_ci "fsid %llu namelen %ld\n", 19358c2ecf20Sopenharmony_ci fid->fid, (long unsigned int)sb->type, (long int)sb->bsize, 19368c2ecf20Sopenharmony_ci sb->blocks, sb->bfree, sb->bavail, sb->files, sb->ffree, 19378c2ecf20Sopenharmony_ci sb->fsid, (long int)sb->namelen); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 19408c2ecf20Sopenharmony_cierror: 19418c2ecf20Sopenharmony_ci return err; 19428c2ecf20Sopenharmony_ci} 19438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_statfs); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ciint p9_client_rename(struct p9_fid *fid, 19468c2ecf20Sopenharmony_ci struct p9_fid *newdirfid, const char *name) 19478c2ecf20Sopenharmony_ci{ 19488c2ecf20Sopenharmony_ci int err; 19498c2ecf20Sopenharmony_ci struct p9_req_t *req; 19508c2ecf20Sopenharmony_ci struct p9_client *clnt; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci err = 0; 19538c2ecf20Sopenharmony_ci clnt = fid->clnt; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n", 19568c2ecf20Sopenharmony_ci fid->fid, newdirfid->fid, name); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid, 19598c2ecf20Sopenharmony_ci newdirfid->fid, name); 19608c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 19618c2ecf20Sopenharmony_ci err = PTR_ERR(req); 19628c2ecf20Sopenharmony_ci goto error; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid); 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 19688c2ecf20Sopenharmony_cierror: 19698c2ecf20Sopenharmony_ci return err; 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_rename); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ciint p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, 19748c2ecf20Sopenharmony_ci struct p9_fid *newdirfid, const char *new_name) 19758c2ecf20Sopenharmony_ci{ 19768c2ecf20Sopenharmony_ci int err; 19778c2ecf20Sopenharmony_ci struct p9_req_t *req; 19788c2ecf20Sopenharmony_ci struct p9_client *clnt; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci err = 0; 19818c2ecf20Sopenharmony_ci clnt = olddirfid->clnt; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TRENAMEAT olddirfid %d old name %s" 19848c2ecf20Sopenharmony_ci " newdirfid %d new name %s\n", olddirfid->fid, old_name, 19858c2ecf20Sopenharmony_ci newdirfid->fid, new_name); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid, 19888c2ecf20Sopenharmony_ci old_name, newdirfid->fid, new_name); 19898c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 19908c2ecf20Sopenharmony_ci err = PTR_ERR(req); 19918c2ecf20Sopenharmony_ci goto error; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n", 19958c2ecf20Sopenharmony_ci newdirfid->fid, new_name); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 19988c2ecf20Sopenharmony_cierror: 19998c2ecf20Sopenharmony_ci return err; 20008c2ecf20Sopenharmony_ci} 20018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_renameat); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci/* 20048c2ecf20Sopenharmony_ci * An xattrwalk without @attr_name gives the fid for the lisxattr namespace 20058c2ecf20Sopenharmony_ci */ 20068c2ecf20Sopenharmony_cistruct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid, 20078c2ecf20Sopenharmony_ci const char *attr_name, u64 *attr_size) 20088c2ecf20Sopenharmony_ci{ 20098c2ecf20Sopenharmony_ci int err; 20108c2ecf20Sopenharmony_ci struct p9_req_t *req; 20118c2ecf20Sopenharmony_ci struct p9_client *clnt; 20128c2ecf20Sopenharmony_ci struct p9_fid *attr_fid; 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci err = 0; 20158c2ecf20Sopenharmony_ci clnt = file_fid->clnt; 20168c2ecf20Sopenharmony_ci attr_fid = p9_fid_create(clnt); 20178c2ecf20Sopenharmony_ci if (!attr_fid) { 20188c2ecf20Sopenharmony_ci err = -ENOMEM; 20198c2ecf20Sopenharmony_ci goto error; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 20228c2ecf20Sopenharmony_ci ">>> TXATTRWALK file_fid %d, attr_fid %d name %s\n", 20238c2ecf20Sopenharmony_ci file_fid->fid, attr_fid->fid, attr_name); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds", 20268c2ecf20Sopenharmony_ci file_fid->fid, attr_fid->fid, attr_name); 20278c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 20288c2ecf20Sopenharmony_ci err = PTR_ERR(req); 20298c2ecf20Sopenharmony_ci goto error; 20308c2ecf20Sopenharmony_ci } 20318c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "q", attr_size); 20328c2ecf20Sopenharmony_ci if (err) { 20338c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 20348c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 20358c2ecf20Sopenharmony_ci goto clunk_fid; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 20388c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n", 20398c2ecf20Sopenharmony_ci attr_fid->fid, *attr_size); 20408c2ecf20Sopenharmony_ci return attr_fid; 20418c2ecf20Sopenharmony_ciclunk_fid: 20428c2ecf20Sopenharmony_ci p9_client_clunk(attr_fid); 20438c2ecf20Sopenharmony_ci attr_fid = NULL; 20448c2ecf20Sopenharmony_cierror: 20458c2ecf20Sopenharmony_ci if (attr_fid && (attr_fid != file_fid)) 20468c2ecf20Sopenharmony_ci p9_fid_destroy(attr_fid); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return ERR_PTR(err); 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(p9_client_xattrwalk); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ciint p9_client_xattrcreate(struct p9_fid *fid, const char *name, 20538c2ecf20Sopenharmony_ci u64 attr_size, int flags) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci int err; 20568c2ecf20Sopenharmony_ci struct p9_req_t *req; 20578c2ecf20Sopenharmony_ci struct p9_client *clnt; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, 20608c2ecf20Sopenharmony_ci ">>> TXATTRCREATE fid %d name %s size %lld flag %d\n", 20618c2ecf20Sopenharmony_ci fid->fid, name, (long long)attr_size, flags); 20628c2ecf20Sopenharmony_ci err = 0; 20638c2ecf20Sopenharmony_ci clnt = fid->clnt; 20648c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd", 20658c2ecf20Sopenharmony_ci fid->fid, name, attr_size, flags); 20668c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 20678c2ecf20Sopenharmony_ci err = PTR_ERR(req); 20688c2ecf20Sopenharmony_ci goto error; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid); 20718c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 20728c2ecf20Sopenharmony_cierror: 20738c2ecf20Sopenharmony_ci return err; 20748c2ecf20Sopenharmony_ci} 20758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(p9_client_xattrcreate); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ciint p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci int err, rsize, non_zc = 0; 20808c2ecf20Sopenharmony_ci struct p9_client *clnt; 20818c2ecf20Sopenharmony_ci struct p9_req_t *req; 20828c2ecf20Sopenharmony_ci char *dataptr; 20838c2ecf20Sopenharmony_ci struct kvec kv = {.iov_base = data, .iov_len = count}; 20848c2ecf20Sopenharmony_ci struct iov_iter to; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci iov_iter_kvec(&to, READ, &kv, 1, count); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n", 20898c2ecf20Sopenharmony_ci fid->fid, (unsigned long long) offset, count); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci err = 0; 20928c2ecf20Sopenharmony_ci clnt = fid->clnt; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci rsize = fid->iounit; 20958c2ecf20Sopenharmony_ci if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) 20968c2ecf20Sopenharmony_ci rsize = clnt->msize - P9_READDIRHDRSZ; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (count < rsize) 20998c2ecf20Sopenharmony_ci rsize = count; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci /* Don't bother zerocopy for small IO (< 1024) */ 21028c2ecf20Sopenharmony_ci if (clnt->trans_mod->zc_request && rsize > 1024) { 21038c2ecf20Sopenharmony_ci /* 21048c2ecf20Sopenharmony_ci * response header len is 11 21058c2ecf20Sopenharmony_ci * PDU Header(7) + IO Size (4) 21068c2ecf20Sopenharmony_ci */ 21078c2ecf20Sopenharmony_ci req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0, 21088c2ecf20Sopenharmony_ci 11, "dqd", fid->fid, offset, rsize); 21098c2ecf20Sopenharmony_ci } else { 21108c2ecf20Sopenharmony_ci non_zc = 1; 21118c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, 21128c2ecf20Sopenharmony_ci offset, rsize); 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci if (IS_ERR(req)) { 21158c2ecf20Sopenharmony_ci err = PTR_ERR(req); 21168c2ecf20Sopenharmony_ci goto error; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "D", &count, &dataptr); 21208c2ecf20Sopenharmony_ci if (err) { 21218c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 21228c2ecf20Sopenharmony_ci goto free_and_error; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci if (rsize < count) { 21258c2ecf20Sopenharmony_ci pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize); 21268c2ecf20Sopenharmony_ci count = rsize; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (non_zc) 21328c2ecf20Sopenharmony_ci memmove(data, dataptr, count); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 21358c2ecf20Sopenharmony_ci return count; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_cifree_and_error: 21388c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 21398c2ecf20Sopenharmony_cierror: 21408c2ecf20Sopenharmony_ci return err; 21418c2ecf20Sopenharmony_ci} 21428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_readdir); 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ciint p9_client_mknod_dotl(struct p9_fid *fid, const char *name, int mode, 21458c2ecf20Sopenharmony_ci dev_t rdev, kgid_t gid, struct p9_qid *qid) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci int err; 21488c2ecf20Sopenharmony_ci struct p9_client *clnt; 21498c2ecf20Sopenharmony_ci struct p9_req_t *req; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci err = 0; 21528c2ecf20Sopenharmony_ci clnt = fid->clnt; 21538c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TMKNOD fid %d name %s mode %d major %d " 21548c2ecf20Sopenharmony_ci "minor %d\n", fid->fid, name, mode, MAJOR(rdev), MINOR(rdev)); 21558c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddg", fid->fid, name, mode, 21568c2ecf20Sopenharmony_ci MAJOR(rdev), MINOR(rdev), gid); 21578c2ecf20Sopenharmony_ci if (IS_ERR(req)) 21588c2ecf20Sopenharmony_ci return PTR_ERR(req); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid); 21618c2ecf20Sopenharmony_ci if (err) { 21628c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 21638c2ecf20Sopenharmony_ci goto error; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n", qid->type, 21668c2ecf20Sopenharmony_ci (unsigned long long)qid->path, qid->version); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_cierror: 21698c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 21708c2ecf20Sopenharmony_ci return err; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_mknod_dotl); 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ciint p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode, 21768c2ecf20Sopenharmony_ci kgid_t gid, struct p9_qid *qid) 21778c2ecf20Sopenharmony_ci{ 21788c2ecf20Sopenharmony_ci int err; 21798c2ecf20Sopenharmony_ci struct p9_client *clnt; 21808c2ecf20Sopenharmony_ci struct p9_req_t *req; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci err = 0; 21838c2ecf20Sopenharmony_ci clnt = fid->clnt; 21848c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n", 21858c2ecf20Sopenharmony_ci fid->fid, name, mode, from_kgid(&init_user_ns, gid)); 21868c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TMKDIR, "dsdg", fid->fid, name, mode, 21878c2ecf20Sopenharmony_ci gid); 21888c2ecf20Sopenharmony_ci if (IS_ERR(req)) 21898c2ecf20Sopenharmony_ci return PTR_ERR(req); 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid); 21928c2ecf20Sopenharmony_ci if (err) { 21938c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 21948c2ecf20Sopenharmony_ci goto error; 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type, 21978c2ecf20Sopenharmony_ci (unsigned long long)qid->path, qid->version); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_cierror: 22008c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 22018c2ecf20Sopenharmony_ci return err; 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_mkdir_dotl); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ciint p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci int err; 22098c2ecf20Sopenharmony_ci struct p9_client *clnt; 22108c2ecf20Sopenharmony_ci struct p9_req_t *req; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci err = 0; 22138c2ecf20Sopenharmony_ci clnt = fid->clnt; 22148c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d " 22158c2ecf20Sopenharmony_ci "start %lld length %lld proc_id %d client_id %s\n", 22168c2ecf20Sopenharmony_ci fid->fid, flock->type, flock->flags, flock->start, 22178c2ecf20Sopenharmony_ci flock->length, flock->proc_id, flock->client_id); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type, 22208c2ecf20Sopenharmony_ci flock->flags, flock->start, flock->length, 22218c2ecf20Sopenharmony_ci flock->proc_id, flock->client_id); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci if (IS_ERR(req)) 22248c2ecf20Sopenharmony_ci return PTR_ERR(req); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "b", status); 22278c2ecf20Sopenharmony_ci if (err) { 22288c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 22298c2ecf20Sopenharmony_ci goto error; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); 22328c2ecf20Sopenharmony_cierror: 22338c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 22348c2ecf20Sopenharmony_ci return err; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_lock_dotl); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ciint p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci int err; 22428c2ecf20Sopenharmony_ci struct p9_client *clnt; 22438c2ecf20Sopenharmony_ci struct p9_req_t *req; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci err = 0; 22468c2ecf20Sopenharmony_ci clnt = fid->clnt; 22478c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld " 22488c2ecf20Sopenharmony_ci "length %lld proc_id %d client_id %s\n", fid->fid, glock->type, 22498c2ecf20Sopenharmony_ci glock->start, glock->length, glock->proc_id, glock->client_id); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type, 22528c2ecf20Sopenharmony_ci glock->start, glock->length, glock->proc_id, glock->client_id); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if (IS_ERR(req)) 22558c2ecf20Sopenharmony_ci return PTR_ERR(req); 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "bqqds", &glock->type, 22588c2ecf20Sopenharmony_ci &glock->start, &glock->length, &glock->proc_id, 22598c2ecf20Sopenharmony_ci &glock->client_id); 22608c2ecf20Sopenharmony_ci if (err) { 22618c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 22628c2ecf20Sopenharmony_ci goto error; 22638c2ecf20Sopenharmony_ci } 22648c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " 22658c2ecf20Sopenharmony_ci "proc_id %d client_id %s\n", glock->type, glock->start, 22668c2ecf20Sopenharmony_ci glock->length, glock->proc_id, glock->client_id); 22678c2ecf20Sopenharmony_cierror: 22688c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 22698c2ecf20Sopenharmony_ci return err; 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_getlock_dotl); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ciint p9_client_readlink(struct p9_fid *fid, char **target) 22748c2ecf20Sopenharmony_ci{ 22758c2ecf20Sopenharmony_ci int err; 22768c2ecf20Sopenharmony_ci struct p9_client *clnt; 22778c2ecf20Sopenharmony_ci struct p9_req_t *req; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci err = 0; 22808c2ecf20Sopenharmony_ci clnt = fid->clnt; 22818c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid); 22848c2ecf20Sopenharmony_ci if (IS_ERR(req)) 22858c2ecf20Sopenharmony_ci return PTR_ERR(req); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci err = p9pdu_readf(&req->rc, clnt->proto_version, "s", target); 22888c2ecf20Sopenharmony_ci if (err) { 22898c2ecf20Sopenharmony_ci trace_9p_protocol_dump(clnt, &req->rc); 22908c2ecf20Sopenharmony_ci goto error; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci p9_debug(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); 22938c2ecf20Sopenharmony_cierror: 22948c2ecf20Sopenharmony_ci p9_tag_remove(clnt, req); 22958c2ecf20Sopenharmony_ci return err; 22968c2ecf20Sopenharmony_ci} 22978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(p9_client_readlink); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ciint __init p9_client_init(void) 23008c2ecf20Sopenharmony_ci{ 23018c2ecf20Sopenharmony_ci p9_req_cache = KMEM_CACHE(p9_req_t, SLAB_TYPESAFE_BY_RCU); 23028c2ecf20Sopenharmony_ci return p9_req_cache ? 0 : -ENOMEM; 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_civoid __exit p9_client_exit(void) 23068c2ecf20Sopenharmony_ci{ 23078c2ecf20Sopenharmony_ci kmem_cache_destroy(p9_req_cache); 23088c2ecf20Sopenharmony_ci} 2309