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(&current->sighand->siglock, flags);
7968c2ecf20Sopenharmony_ci		recalc_sigpending();
7978c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&current->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(&current->sighand->siglock, flags);
8788c2ecf20Sopenharmony_ci		recalc_sigpending();
8798c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&current->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