162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * 9P Client
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
662306a36Sopenharmony_ci *  Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/errno.h>
1362306a36Sopenharmony_ci#include <linux/fs.h>
1462306a36Sopenharmony_ci#include <linux/poll.h>
1562306a36Sopenharmony_ci#include <linux/idr.h>
1662306a36Sopenharmony_ci#include <linux/mutex.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/sched/signal.h>
1962306a36Sopenharmony_ci#include <linux/uaccess.h>
2062306a36Sopenharmony_ci#include <linux/uio.h>
2162306a36Sopenharmony_ci#include <net/9p/9p.h>
2262306a36Sopenharmony_ci#include <linux/parser.h>
2362306a36Sopenharmony_ci#include <linux/seq_file.h>
2462306a36Sopenharmony_ci#include <net/9p/client.h>
2562306a36Sopenharmony_ci#include <net/9p/transport.h>
2662306a36Sopenharmony_ci#include "protocol.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
2962306a36Sopenharmony_ci#include <trace/events/9p.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ +
3262306a36Sopenharmony_ci * room for write (16 extra) or read (11 extra) operands.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Client Option Parsing (code inspired by NFS code)
3862306a36Sopenharmony_ci *  - a little lazy - parse all client options
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cienum {
4262306a36Sopenharmony_ci	Opt_msize,
4362306a36Sopenharmony_ci	Opt_trans,
4462306a36Sopenharmony_ci	Opt_legacy,
4562306a36Sopenharmony_ci	Opt_version,
4662306a36Sopenharmony_ci	Opt_err,
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic const match_table_t tokens = {
5062306a36Sopenharmony_ci	{Opt_msize, "msize=%u"},
5162306a36Sopenharmony_ci	{Opt_legacy, "noextend"},
5262306a36Sopenharmony_ci	{Opt_trans, "trans=%s"},
5362306a36Sopenharmony_ci	{Opt_version, "version=%s"},
5462306a36Sopenharmony_ci	{Opt_err, NULL},
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciinline int p9_is_proto_dotl(struct p9_client *clnt)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return clnt->proto_version == p9_proto_2000L;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_is_proto_dotl);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ciinline int p9_is_proto_dotu(struct p9_client *clnt)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return clnt->proto_version == p9_proto_2000u;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ciEXPORT_SYMBOL(p9_is_proto_dotu);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ciint p9_show_client_options(struct seq_file *m, struct p9_client *clnt)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (clnt->msize != DEFAULT_MSIZE)
7262306a36Sopenharmony_ci		seq_printf(m, ",msize=%u", clnt->msize);
7362306a36Sopenharmony_ci	seq_printf(m, ",trans=%s", clnt->trans_mod->name);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	switch (clnt->proto_version) {
7662306a36Sopenharmony_ci	case p9_proto_legacy:
7762306a36Sopenharmony_ci		seq_puts(m, ",noextend");
7862306a36Sopenharmony_ci		break;
7962306a36Sopenharmony_ci	case p9_proto_2000u:
8062306a36Sopenharmony_ci		seq_puts(m, ",version=9p2000.u");
8162306a36Sopenharmony_ci		break;
8262306a36Sopenharmony_ci	case p9_proto_2000L:
8362306a36Sopenharmony_ci		/* Default */
8462306a36Sopenharmony_ci		break;
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (clnt->trans_mod->show_options)
8862306a36Sopenharmony_ci		return clnt->trans_mod->show_options(m, clnt);
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_show_client_options);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci/* Some error codes are taken directly from the server replies,
9462306a36Sopenharmony_ci * make sure they are valid.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic int safe_errno(int err)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (err > 0 || err < -MAX_ERRNO) {
9962306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err);
10062306a36Sopenharmony_ci		return -EPROTO;
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci	return err;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* Interpret mount option for protocol version */
10662306a36Sopenharmony_cistatic int get_protocol_version(char *s)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	int version = -EINVAL;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (!strcmp(s, "9p2000")) {
11162306a36Sopenharmony_ci		version = p9_proto_legacy;
11262306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n");
11362306a36Sopenharmony_ci	} else if (!strcmp(s, "9p2000.u")) {
11462306a36Sopenharmony_ci		version = p9_proto_2000u;
11562306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
11662306a36Sopenharmony_ci	} else if (!strcmp(s, "9p2000.L")) {
11762306a36Sopenharmony_ci		version = p9_proto_2000L;
11862306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
11962306a36Sopenharmony_ci	} else {
12062306a36Sopenharmony_ci		pr_info("Unknown protocol version %s\n", s);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	return version;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/**
12762306a36Sopenharmony_ci * parse_opts - parse mount options into client structure
12862306a36Sopenharmony_ci * @opts: options string passed from mount
12962306a36Sopenharmony_ci * @clnt: existing v9fs client information
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Return 0 upon success, -ERRNO upon failure
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int parse_opts(char *opts, struct p9_client *clnt)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	char *options, *tmp_options;
13762306a36Sopenharmony_ci	char *p;
13862306a36Sopenharmony_ci	substring_t args[MAX_OPT_ARGS];
13962306a36Sopenharmony_ci	int option;
14062306a36Sopenharmony_ci	char *s;
14162306a36Sopenharmony_ci	int ret = 0;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	clnt->proto_version = p9_proto_2000L;
14462306a36Sopenharmony_ci	clnt->msize = DEFAULT_MSIZE;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (!opts)
14762306a36Sopenharmony_ci		return 0;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	tmp_options = kstrdup(opts, GFP_KERNEL);
15062306a36Sopenharmony_ci	if (!tmp_options)
15162306a36Sopenharmony_ci		return -ENOMEM;
15262306a36Sopenharmony_ci	options = tmp_options;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	while ((p = strsep(&options, ",")) != NULL) {
15562306a36Sopenharmony_ci		int token, r;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		if (!*p)
15862306a36Sopenharmony_ci			continue;
15962306a36Sopenharmony_ci		token = match_token(p, tokens, args);
16062306a36Sopenharmony_ci		switch (token) {
16162306a36Sopenharmony_ci		case Opt_msize:
16262306a36Sopenharmony_ci			r = match_int(&args[0], &option);
16362306a36Sopenharmony_ci			if (r < 0) {
16462306a36Sopenharmony_ci				p9_debug(P9_DEBUG_ERROR,
16562306a36Sopenharmony_ci					 "integer field, but no integer?\n");
16662306a36Sopenharmony_ci				ret = r;
16762306a36Sopenharmony_ci				continue;
16862306a36Sopenharmony_ci			}
16962306a36Sopenharmony_ci			if (option < 4096) {
17062306a36Sopenharmony_ci				p9_debug(P9_DEBUG_ERROR,
17162306a36Sopenharmony_ci					 "msize should be at least 4k\n");
17262306a36Sopenharmony_ci				ret = -EINVAL;
17362306a36Sopenharmony_ci				continue;
17462306a36Sopenharmony_ci			}
17562306a36Sopenharmony_ci			clnt->msize = option;
17662306a36Sopenharmony_ci			break;
17762306a36Sopenharmony_ci		case Opt_trans:
17862306a36Sopenharmony_ci			s = match_strdup(&args[0]);
17962306a36Sopenharmony_ci			if (!s) {
18062306a36Sopenharmony_ci				ret = -ENOMEM;
18162306a36Sopenharmony_ci				p9_debug(P9_DEBUG_ERROR,
18262306a36Sopenharmony_ci					 "problem allocating copy of trans arg\n");
18362306a36Sopenharmony_ci				goto free_and_return;
18462306a36Sopenharmony_ci			}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci			v9fs_put_trans(clnt->trans_mod);
18762306a36Sopenharmony_ci			clnt->trans_mod = v9fs_get_trans_by_name(s);
18862306a36Sopenharmony_ci			if (!clnt->trans_mod) {
18962306a36Sopenharmony_ci				pr_info("Could not find request transport: %s\n",
19062306a36Sopenharmony_ci					s);
19162306a36Sopenharmony_ci				ret = -EINVAL;
19262306a36Sopenharmony_ci			}
19362306a36Sopenharmony_ci			kfree(s);
19462306a36Sopenharmony_ci			break;
19562306a36Sopenharmony_ci		case Opt_legacy:
19662306a36Sopenharmony_ci			clnt->proto_version = p9_proto_legacy;
19762306a36Sopenharmony_ci			break;
19862306a36Sopenharmony_ci		case Opt_version:
19962306a36Sopenharmony_ci			s = match_strdup(&args[0]);
20062306a36Sopenharmony_ci			if (!s) {
20162306a36Sopenharmony_ci				ret = -ENOMEM;
20262306a36Sopenharmony_ci				p9_debug(P9_DEBUG_ERROR,
20362306a36Sopenharmony_ci					 "problem allocating copy of version arg\n");
20462306a36Sopenharmony_ci				goto free_and_return;
20562306a36Sopenharmony_ci			}
20662306a36Sopenharmony_ci			r = get_protocol_version(s);
20762306a36Sopenharmony_ci			if (r < 0)
20862306a36Sopenharmony_ci				ret = r;
20962306a36Sopenharmony_ci			else
21062306a36Sopenharmony_ci				clnt->proto_version = r;
21162306a36Sopenharmony_ci			kfree(s);
21262306a36Sopenharmony_ci			break;
21362306a36Sopenharmony_ci		default:
21462306a36Sopenharmony_ci			continue;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cifree_and_return:
21962306a36Sopenharmony_ci	if (ret)
22062306a36Sopenharmony_ci		v9fs_put_trans(clnt->trans_mod);
22162306a36Sopenharmony_ci	kfree(tmp_options);
22262306a36Sopenharmony_ci	return ret;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
22662306a36Sopenharmony_ci			 int alloc_msize)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	if (likely(c->fcall_cache) && alloc_msize == c->msize) {
22962306a36Sopenharmony_ci		fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS);
23062306a36Sopenharmony_ci		fc->cache = c->fcall_cache;
23162306a36Sopenharmony_ci	} else {
23262306a36Sopenharmony_ci		fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
23362306a36Sopenharmony_ci		fc->cache = NULL;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	if (!fc->sdata)
23662306a36Sopenharmony_ci		return -ENOMEM;
23762306a36Sopenharmony_ci	fc->capacity = alloc_msize;
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_civoid p9_fcall_fini(struct p9_fcall *fc)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	/* sdata can be NULL for interrupted requests in trans_rdma,
24462306a36Sopenharmony_ci	 * and kmem_cache_free does not do NULL-check for us
24562306a36Sopenharmony_ci	 */
24662306a36Sopenharmony_ci	if (unlikely(!fc->sdata))
24762306a36Sopenharmony_ci		return;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (fc->cache)
25062306a36Sopenharmony_ci		kmem_cache_free(fc->cache, fc->sdata);
25162306a36Sopenharmony_ci	else
25262306a36Sopenharmony_ci		kfree(fc->sdata);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ciEXPORT_SYMBOL(p9_fcall_fini);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic struct kmem_cache *p9_req_cache;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/**
25962306a36Sopenharmony_ci * p9_tag_alloc - Allocate a new request.
26062306a36Sopenharmony_ci * @c: Client session.
26162306a36Sopenharmony_ci * @type: Transaction type.
26262306a36Sopenharmony_ci * @t_size: Buffer size for holding this request
26362306a36Sopenharmony_ci * (automatic calculation by format template if 0).
26462306a36Sopenharmony_ci * @r_size: Buffer size for holding server's reply on this request
26562306a36Sopenharmony_ci * (automatic calculation by format template if 0).
26662306a36Sopenharmony_ci * @fmt: Format template for assembling 9p request message
26762306a36Sopenharmony_ci * (see p9pdu_vwritef).
26862306a36Sopenharmony_ci * @ap: Variable arguments to be fed to passed format template
26962306a36Sopenharmony_ci * (see p9pdu_vwritef).
27062306a36Sopenharmony_ci *
27162306a36Sopenharmony_ci * Context: Process context.
27262306a36Sopenharmony_ci * Return: Pointer to new request.
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic struct p9_req_t *
27562306a36Sopenharmony_cip9_tag_alloc(struct p9_client *c, int8_t type, uint t_size, uint r_size,
27662306a36Sopenharmony_ci	      const char *fmt, va_list ap)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct p9_req_t *req = kmem_cache_alloc(p9_req_cache, GFP_NOFS);
27962306a36Sopenharmony_ci	int alloc_tsize;
28062306a36Sopenharmony_ci	int alloc_rsize;
28162306a36Sopenharmony_ci	int tag;
28262306a36Sopenharmony_ci	va_list apc;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	va_copy(apc, ap);
28562306a36Sopenharmony_ci	alloc_tsize = min_t(size_t, c->msize,
28662306a36Sopenharmony_ci			    t_size ?: p9_msg_buf_size(c, type, fmt, apc));
28762306a36Sopenharmony_ci	va_end(apc);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	alloc_rsize = min_t(size_t, c->msize,
29062306a36Sopenharmony_ci			    r_size ?: p9_msg_buf_size(c, type + 1, fmt, ap));
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (!req)
29362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (p9_fcall_init(c, &req->tc, alloc_tsize))
29662306a36Sopenharmony_ci		goto free_req;
29762306a36Sopenharmony_ci	if (p9_fcall_init(c, &req->rc, alloc_rsize))
29862306a36Sopenharmony_ci		goto free;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	p9pdu_reset(&req->tc);
30162306a36Sopenharmony_ci	p9pdu_reset(&req->rc);
30262306a36Sopenharmony_ci	req->t_err = 0;
30362306a36Sopenharmony_ci	req->status = REQ_STATUS_ALLOC;
30462306a36Sopenharmony_ci	/* refcount needs to be set to 0 before inserting into the idr
30562306a36Sopenharmony_ci	 * so p9_tag_lookup does not accept a request that is not fully
30662306a36Sopenharmony_ci	 * initialized. refcount_set to 2 below will mark request ready.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	refcount_set(&req->refcount, 0);
30962306a36Sopenharmony_ci	init_waitqueue_head(&req->wq);
31062306a36Sopenharmony_ci	INIT_LIST_HEAD(&req->req_list);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	idr_preload(GFP_NOFS);
31362306a36Sopenharmony_ci	spin_lock_irq(&c->lock);
31462306a36Sopenharmony_ci	if (type == P9_TVERSION)
31562306a36Sopenharmony_ci		tag = idr_alloc(&c->reqs, req, P9_NOTAG, P9_NOTAG + 1,
31662306a36Sopenharmony_ci				GFP_NOWAIT);
31762306a36Sopenharmony_ci	else
31862306a36Sopenharmony_ci		tag = idr_alloc(&c->reqs, req, 0, P9_NOTAG, GFP_NOWAIT);
31962306a36Sopenharmony_ci	req->tc.tag = tag;
32062306a36Sopenharmony_ci	spin_unlock_irq(&c->lock);
32162306a36Sopenharmony_ci	idr_preload_end();
32262306a36Sopenharmony_ci	if (tag < 0)
32362306a36Sopenharmony_ci		goto free;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* Init ref to two because in the general case there is one ref
32662306a36Sopenharmony_ci	 * that is put asynchronously by a writer thread, one ref
32762306a36Sopenharmony_ci	 * temporarily given by p9_tag_lookup and put by p9_client_cb
32862306a36Sopenharmony_ci	 * in the recv thread, and one ref put by p9_req_put in the
32962306a36Sopenharmony_ci	 * main thread. The only exception is virtio that does not use
33062306a36Sopenharmony_ci	 * p9_tag_lookup but does not have a writer thread either
33162306a36Sopenharmony_ci	 * (the write happens synchronously in the request/zc_request
33262306a36Sopenharmony_ci	 * callback), so p9_client_cb eats the second ref there
33362306a36Sopenharmony_ci	 * as the pointer is duplicated directly by virtqueue_add_sgs()
33462306a36Sopenharmony_ci	 */
33562306a36Sopenharmony_ci	refcount_set(&req->refcount, 2);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return req;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cifree:
34062306a36Sopenharmony_ci	p9_fcall_fini(&req->tc);
34162306a36Sopenharmony_ci	p9_fcall_fini(&req->rc);
34262306a36Sopenharmony_cifree_req:
34362306a36Sopenharmony_ci	kmem_cache_free(p9_req_cache, req);
34462306a36Sopenharmony_ci	return ERR_PTR(-ENOMEM);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/**
34862306a36Sopenharmony_ci * p9_tag_lookup - Look up a request by tag.
34962306a36Sopenharmony_ci * @c: Client session.
35062306a36Sopenharmony_ci * @tag: Transaction ID.
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * Context: Any context.
35362306a36Sopenharmony_ci * Return: A request, or %NULL if there is no request with that tag.
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cistruct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct p9_req_t *req;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	rcu_read_lock();
36062306a36Sopenharmony_ciagain:
36162306a36Sopenharmony_ci	req = idr_find(&c->reqs, tag);
36262306a36Sopenharmony_ci	if (req) {
36362306a36Sopenharmony_ci		/* We have to be careful with the req found under rcu_read_lock
36462306a36Sopenharmony_ci		 * Thanks to SLAB_TYPESAFE_BY_RCU we can safely try to get the
36562306a36Sopenharmony_ci		 * ref again without corrupting other data, then check again
36662306a36Sopenharmony_ci		 * that the tag matches once we have the ref
36762306a36Sopenharmony_ci		 */
36862306a36Sopenharmony_ci		if (!p9_req_try_get(req))
36962306a36Sopenharmony_ci			goto again;
37062306a36Sopenharmony_ci		if (req->tc.tag != tag) {
37162306a36Sopenharmony_ci			p9_req_put(c, req);
37262306a36Sopenharmony_ci			goto again;
37362306a36Sopenharmony_ci		}
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci	rcu_read_unlock();
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return req;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_tag_lookup);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci/**
38262306a36Sopenharmony_ci * p9_tag_remove - Remove a tag.
38362306a36Sopenharmony_ci * @c: Client session.
38462306a36Sopenharmony_ci * @r: Request of reference.
38562306a36Sopenharmony_ci *
38662306a36Sopenharmony_ci * Context: Any context.
38762306a36Sopenharmony_ci */
38862306a36Sopenharmony_cistatic void p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	unsigned long flags;
39162306a36Sopenharmony_ci	u16 tag = r->tc.tag;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, "freeing clnt %p req %p tag: %d\n", c, r, tag);
39462306a36Sopenharmony_ci	spin_lock_irqsave(&c->lock, flags);
39562306a36Sopenharmony_ci	idr_remove(&c->reqs, tag);
39662306a36Sopenharmony_ci	spin_unlock_irqrestore(&c->lock, flags);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ciint p9_req_put(struct p9_client *c, struct p9_req_t *r)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	if (refcount_dec_and_test(&r->refcount)) {
40262306a36Sopenharmony_ci		p9_tag_remove(c, r);
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci		p9_fcall_fini(&r->tc);
40562306a36Sopenharmony_ci		p9_fcall_fini(&r->rc);
40662306a36Sopenharmony_ci		kmem_cache_free(p9_req_cache, r);
40762306a36Sopenharmony_ci		return 1;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	return 0;
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_req_put);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/**
41462306a36Sopenharmony_ci * p9_tag_cleanup - cleans up tags structure and reclaims resources
41562306a36Sopenharmony_ci * @c:  v9fs client struct
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * This frees resources associated with the tags structure
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_cistatic void p9_tag_cleanup(struct p9_client *c)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct p9_req_t *req;
42362306a36Sopenharmony_ci	int id;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	rcu_read_lock();
42662306a36Sopenharmony_ci	idr_for_each_entry(&c->reqs, req, id) {
42762306a36Sopenharmony_ci		pr_info("Tag %d still in use\n", id);
42862306a36Sopenharmony_ci		if (p9_req_put(c, req) == 0)
42962306a36Sopenharmony_ci			pr_warn("Packet with tag %d has still references",
43062306a36Sopenharmony_ci				req->tc.tag);
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	rcu_read_unlock();
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/**
43662306a36Sopenharmony_ci * p9_client_cb - call back from transport to client
43762306a36Sopenharmony_ci * @c: client state
43862306a36Sopenharmony_ci * @req: request received
43962306a36Sopenharmony_ci * @status: request status, one of REQ_STATUS_*
44062306a36Sopenharmony_ci *
44162306a36Sopenharmony_ci */
44262306a36Sopenharmony_civoid p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc.tag);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* This barrier is needed to make sure any change made to req before
44762306a36Sopenharmony_ci	 * the status change is visible to another thread
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	smp_wmb();
45062306a36Sopenharmony_ci	WRITE_ONCE(req->status, status);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	wake_up(&req->wq);
45362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag);
45462306a36Sopenharmony_ci	p9_req_put(c, req);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_cb);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci/**
45962306a36Sopenharmony_ci * p9_parse_header - parse header arguments out of a packet
46062306a36Sopenharmony_ci * @pdu: packet to parse
46162306a36Sopenharmony_ci * @size: size of packet
46262306a36Sopenharmony_ci * @type: type of request
46362306a36Sopenharmony_ci * @tag: tag of packet
46462306a36Sopenharmony_ci * @rewind: set if we need to rewind offset afterwards
46562306a36Sopenharmony_ci */
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ciint
46862306a36Sopenharmony_cip9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type,
46962306a36Sopenharmony_ci		int16_t *tag, int rewind)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	s8 r_type;
47262306a36Sopenharmony_ci	s16 r_tag;
47362306a36Sopenharmony_ci	s32 r_size;
47462306a36Sopenharmony_ci	int offset = pdu->offset;
47562306a36Sopenharmony_ci	int err;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	pdu->offset = 0;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
48062306a36Sopenharmony_ci	if (err)
48162306a36Sopenharmony_ci		goto rewind_and_exit;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (type)
48462306a36Sopenharmony_ci		*type = r_type;
48562306a36Sopenharmony_ci	if (tag)
48662306a36Sopenharmony_ci		*tag = r_tag;
48762306a36Sopenharmony_ci	if (size)
48862306a36Sopenharmony_ci		*size = r_size;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (pdu->size != r_size || r_size < 7) {
49162306a36Sopenharmony_ci		err = -EINVAL;
49262306a36Sopenharmony_ci		goto rewind_and_exit;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	pdu->id = r_type;
49662306a36Sopenharmony_ci	pdu->tag = r_tag;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n",
49962306a36Sopenharmony_ci		 pdu->size, pdu->id, pdu->tag);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cirewind_and_exit:
50262306a36Sopenharmony_ci	if (rewind)
50362306a36Sopenharmony_ci		pdu->offset = offset;
50462306a36Sopenharmony_ci	return err;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ciEXPORT_SYMBOL(p9_parse_header);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci/**
50962306a36Sopenharmony_ci * p9_check_errors - check 9p packet for error return and process it
51062306a36Sopenharmony_ci * @c: current client instance
51162306a36Sopenharmony_ci * @req: request to parse and check for error conditions
51262306a36Sopenharmony_ci *
51362306a36Sopenharmony_ci * returns error code if one is discovered, otherwise returns 0
51462306a36Sopenharmony_ci *
51562306a36Sopenharmony_ci * this will have to be more complicated if we have multiple
51662306a36Sopenharmony_ci * error packet types
51762306a36Sopenharmony_ci */
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	s8 type;
52262306a36Sopenharmony_ci	int err;
52362306a36Sopenharmony_ci	int ecode;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
52662306a36Sopenharmony_ci	if (req->rc.size > req->rc.capacity && !req->rc.zc) {
52762306a36Sopenharmony_ci		pr_err("requested packet size too big: %d does not fit %zu (type=%d)\n",
52862306a36Sopenharmony_ci		       req->rc.size, req->rc.capacity, req->rc.id);
52962306a36Sopenharmony_ci		return -EIO;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci	/* dump the response from server
53262306a36Sopenharmony_ci	 * This should be after check errors which poplulate pdu_fcall.
53362306a36Sopenharmony_ci	 */
53462306a36Sopenharmony_ci	trace_9p_protocol_dump(c, &req->rc);
53562306a36Sopenharmony_ci	if (err) {
53662306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
53762306a36Sopenharmony_ci		return err;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci	if (type != P9_RERROR && type != P9_RLERROR)
54062306a36Sopenharmony_ci		return 0;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!p9_is_proto_dotl(c)) {
54362306a36Sopenharmony_ci		char *ename = NULL;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		err = p9pdu_readf(&req->rc, c->proto_version, "s?d",
54662306a36Sopenharmony_ci				  &ename, &ecode);
54762306a36Sopenharmony_ci		if (err) {
54862306a36Sopenharmony_ci			kfree(ename);
54962306a36Sopenharmony_ci			goto out_err;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		if (p9_is_proto_dotu(c) && ecode < 512)
55362306a36Sopenharmony_ci			err = -ecode;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci		if (!err) {
55662306a36Sopenharmony_ci			err = p9_errstr2errno(ename, strlen(ename));
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci			p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
55962306a36Sopenharmony_ci				 -ecode, ename);
56062306a36Sopenharmony_ci		}
56162306a36Sopenharmony_ci		kfree(ename);
56262306a36Sopenharmony_ci	} else {
56362306a36Sopenharmony_ci		err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode);
56462306a36Sopenharmony_ci		if (err)
56562306a36Sopenharmony_ci			goto out_err;
56662306a36Sopenharmony_ci		err = -ecode;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
56962306a36Sopenharmony_ci	}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	return err;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ciout_err:
57462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	return err;
57762306a36Sopenharmony_ci}
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_cistatic struct p9_req_t *
58062306a36Sopenharmony_cip9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci/**
58362306a36Sopenharmony_ci * p9_client_flush - flush (cancel) a request
58462306a36Sopenharmony_ci * @c: client state
58562306a36Sopenharmony_ci * @oldreq: request to cancel
58662306a36Sopenharmony_ci *
58762306a36Sopenharmony_ci * This sents a flush for a particular request and links
58862306a36Sopenharmony_ci * the flush request to the original request.  The current
58962306a36Sopenharmony_ci * code only supports a single flush request although the protocol
59062306a36Sopenharmony_ci * allows for multiple flush requests to be sent for a single request.
59162306a36Sopenharmony_ci *
59262306a36Sopenharmony_ci */
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct p9_req_t *req;
59762306a36Sopenharmony_ci	s16 oldtag;
59862306a36Sopenharmony_ci	int err;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	err = p9_parse_header(&oldreq->tc, NULL, NULL, &oldtag, 1);
60162306a36Sopenharmony_ci	if (err)
60262306a36Sopenharmony_ci		return err;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
60762306a36Sopenharmony_ci	if (IS_ERR(req))
60862306a36Sopenharmony_ci		return PTR_ERR(req);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/* if we haven't received a response for oldreq,
61162306a36Sopenharmony_ci	 * remove it from the list
61262306a36Sopenharmony_ci	 */
61362306a36Sopenharmony_ci	if (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) {
61462306a36Sopenharmony_ci		if (c->trans_mod->cancelled)
61562306a36Sopenharmony_ci			c->trans_mod->cancelled(c, oldreq);
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	p9_req_put(c, req);
61962306a36Sopenharmony_ci	return 0;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
62362306a36Sopenharmony_ci					      int8_t type, uint t_size, uint r_size,
62462306a36Sopenharmony_ci					      const char *fmt, va_list ap)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	int err;
62762306a36Sopenharmony_ci	struct p9_req_t *req;
62862306a36Sopenharmony_ci	va_list apc;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, "client %p op %d\n", c, type);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* we allow for any status other than disconnected */
63362306a36Sopenharmony_ci	if (c->status == Disconnected)
63462306a36Sopenharmony_ci		return ERR_PTR(-EIO);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* if status is begin_disconnected we allow only clunk request */
63762306a36Sopenharmony_ci	if (c->status == BeginDisconnect && type != P9_TCLUNK)
63862306a36Sopenharmony_ci		return ERR_PTR(-EIO);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	va_copy(apc, ap);
64162306a36Sopenharmony_ci	req = p9_tag_alloc(c, type, t_size, r_size, fmt, apc);
64262306a36Sopenharmony_ci	va_end(apc);
64362306a36Sopenharmony_ci	if (IS_ERR(req))
64462306a36Sopenharmony_ci		return req;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* marshall the data */
64762306a36Sopenharmony_ci	p9pdu_prepare(&req->tc, req->tc.tag, type);
64862306a36Sopenharmony_ci	err = p9pdu_vwritef(&req->tc, c->proto_version, fmt, ap);
64962306a36Sopenharmony_ci	if (err)
65062306a36Sopenharmony_ci		goto reterr;
65162306a36Sopenharmony_ci	p9pdu_finalize(c, &req->tc);
65262306a36Sopenharmony_ci	trace_9p_client_req(c, type, req->tc.tag);
65362306a36Sopenharmony_ci	return req;
65462306a36Sopenharmony_cireterr:
65562306a36Sopenharmony_ci	p9_req_put(c, req);
65662306a36Sopenharmony_ci	/* We have to put also the 2nd reference as it won't be used */
65762306a36Sopenharmony_ci	p9_req_put(c, req);
65862306a36Sopenharmony_ci	return ERR_PTR(err);
65962306a36Sopenharmony_ci}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/**
66262306a36Sopenharmony_ci * p9_client_rpc - issue a request and wait for a response
66362306a36Sopenharmony_ci * @c: client session
66462306a36Sopenharmony_ci * @type: type of request
66562306a36Sopenharmony_ci * @fmt: protocol format string (see protocol.c)
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * Returns request structure (which client must free using p9_req_put)
66862306a36Sopenharmony_ci */
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic struct p9_req_t *
67162306a36Sopenharmony_cip9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	va_list ap;
67462306a36Sopenharmony_ci	int sigpending, err;
67562306a36Sopenharmony_ci	unsigned long flags;
67662306a36Sopenharmony_ci	struct p9_req_t *req;
67762306a36Sopenharmony_ci	/* Passing zero for tsize/rsize to p9_client_prepare_req() tells it to
67862306a36Sopenharmony_ci	 * auto determine an appropriate (small) request/response size
67962306a36Sopenharmony_ci	 * according to actual message data being sent. Currently RDMA
68062306a36Sopenharmony_ci	 * transport is excluded from this response message size optimization,
68162306a36Sopenharmony_ci	 * as it would not cope with it, due to its pooled response buffers
68262306a36Sopenharmony_ci	 * (using an optimized request size for RDMA as well though).
68362306a36Sopenharmony_ci	 */
68462306a36Sopenharmony_ci	const uint tsize = 0;
68562306a36Sopenharmony_ci	const uint rsize = c->trans_mod->pooled_rbuffers ? c->msize : 0;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	va_start(ap, fmt);
68862306a36Sopenharmony_ci	req = p9_client_prepare_req(c, type, tsize, rsize, fmt, ap);
68962306a36Sopenharmony_ci	va_end(ap);
69062306a36Sopenharmony_ci	if (IS_ERR(req))
69162306a36Sopenharmony_ci		return req;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	req->tc.zc = false;
69462306a36Sopenharmony_ci	req->rc.zc = false;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	if (signal_pending(current)) {
69762306a36Sopenharmony_ci		sigpending = 1;
69862306a36Sopenharmony_ci		clear_thread_flag(TIF_SIGPENDING);
69962306a36Sopenharmony_ci	} else {
70062306a36Sopenharmony_ci		sigpending = 0;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	err = c->trans_mod->request(c, req);
70462306a36Sopenharmony_ci	if (err < 0) {
70562306a36Sopenharmony_ci		/* write won't happen */
70662306a36Sopenharmony_ci		p9_req_put(c, req);
70762306a36Sopenharmony_ci		if (err != -ERESTARTSYS && err != -EFAULT)
70862306a36Sopenharmony_ci			c->status = Disconnected;
70962306a36Sopenharmony_ci		goto recalc_sigpending;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ciagain:
71262306a36Sopenharmony_ci	/* Wait for the response */
71362306a36Sopenharmony_ci	err = wait_event_killable(req->wq,
71462306a36Sopenharmony_ci				  READ_ONCE(req->status) >= REQ_STATUS_RCVD);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* Make sure our req is coherent with regard to updates in other
71762306a36Sopenharmony_ci	 * threads - echoes to wmb() in the callback
71862306a36Sopenharmony_ci	 */
71962306a36Sopenharmony_ci	smp_rmb();
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (err == -ERESTARTSYS && c->status == Connected &&
72262306a36Sopenharmony_ci	    type == P9_TFLUSH) {
72362306a36Sopenharmony_ci		sigpending = 1;
72462306a36Sopenharmony_ci		clear_thread_flag(TIF_SIGPENDING);
72562306a36Sopenharmony_ci		goto again;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
72962306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
73062306a36Sopenharmony_ci		err = req->t_err;
73162306a36Sopenharmony_ci	}
73262306a36Sopenharmony_ci	if (err == -ERESTARTSYS && c->status == Connected) {
73362306a36Sopenharmony_ci		p9_debug(P9_DEBUG_MUX, "flushing\n");
73462306a36Sopenharmony_ci		sigpending = 1;
73562306a36Sopenharmony_ci		clear_thread_flag(TIF_SIGPENDING);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		if (c->trans_mod->cancel(c, req))
73862306a36Sopenharmony_ci			p9_client_flush(c, req);
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci		/* if we received the response anyway, don't signal error */
74162306a36Sopenharmony_ci		if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
74262306a36Sopenharmony_ci			err = 0;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_cirecalc_sigpending:
74562306a36Sopenharmony_ci	if (sigpending) {
74662306a36Sopenharmony_ci		spin_lock_irqsave(&current->sighand->siglock, flags);
74762306a36Sopenharmony_ci		recalc_sigpending();
74862306a36Sopenharmony_ci		spin_unlock_irqrestore(&current->sighand->siglock, flags);
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci	if (err < 0)
75162306a36Sopenharmony_ci		goto reterr;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	err = p9_check_errors(c, req);
75462306a36Sopenharmony_ci	trace_9p_client_res(c, type, req->rc.tag, err);
75562306a36Sopenharmony_ci	if (!err)
75662306a36Sopenharmony_ci		return req;
75762306a36Sopenharmony_cireterr:
75862306a36Sopenharmony_ci	p9_req_put(c, req);
75962306a36Sopenharmony_ci	return ERR_PTR(safe_errno(err));
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci/**
76362306a36Sopenharmony_ci * p9_client_zc_rpc - issue a request and wait for a response
76462306a36Sopenharmony_ci * @c: client session
76562306a36Sopenharmony_ci * @type: type of request
76662306a36Sopenharmony_ci * @uidata: destination for zero copy read
76762306a36Sopenharmony_ci * @uodata: source for zero copy write
76862306a36Sopenharmony_ci * @inlen: read buffer size
76962306a36Sopenharmony_ci * @olen: write buffer size
77062306a36Sopenharmony_ci * @in_hdrlen: reader header size, This is the size of response protocol data
77162306a36Sopenharmony_ci * @fmt: protocol format string (see protocol.c)
77262306a36Sopenharmony_ci *
77362306a36Sopenharmony_ci * Returns request structure (which client must free using p9_req_put)
77462306a36Sopenharmony_ci */
77562306a36Sopenharmony_cistatic struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
77662306a36Sopenharmony_ci					 struct iov_iter *uidata,
77762306a36Sopenharmony_ci					 struct iov_iter *uodata,
77862306a36Sopenharmony_ci					 int inlen, int olen, int in_hdrlen,
77962306a36Sopenharmony_ci					 const char *fmt, ...)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	va_list ap;
78262306a36Sopenharmony_ci	int sigpending, err;
78362306a36Sopenharmony_ci	unsigned long flags;
78462306a36Sopenharmony_ci	struct p9_req_t *req;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	va_start(ap, fmt);
78762306a36Sopenharmony_ci	/* We allocate a inline protocol data of only 4k bytes.
78862306a36Sopenharmony_ci	 * The actual content is passed in zero-copy fashion.
78962306a36Sopenharmony_ci	 */
79062306a36Sopenharmony_ci	req = p9_client_prepare_req(c, type, P9_ZC_HDR_SZ, P9_ZC_HDR_SZ, fmt, ap);
79162306a36Sopenharmony_ci	va_end(ap);
79262306a36Sopenharmony_ci	if (IS_ERR(req))
79362306a36Sopenharmony_ci		return req;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	req->tc.zc = true;
79662306a36Sopenharmony_ci	req->rc.zc = true;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (signal_pending(current)) {
79962306a36Sopenharmony_ci		sigpending = 1;
80062306a36Sopenharmony_ci		clear_thread_flag(TIF_SIGPENDING);
80162306a36Sopenharmony_ci	} else {
80262306a36Sopenharmony_ci		sigpending = 0;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	err = c->trans_mod->zc_request(c, req, uidata, uodata,
80662306a36Sopenharmony_ci				       inlen, olen, in_hdrlen);
80762306a36Sopenharmony_ci	if (err < 0) {
80862306a36Sopenharmony_ci		if (err == -EIO)
80962306a36Sopenharmony_ci			c->status = Disconnected;
81062306a36Sopenharmony_ci		if (err != -ERESTARTSYS)
81162306a36Sopenharmony_ci			goto recalc_sigpending;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
81462306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
81562306a36Sopenharmony_ci		err = req->t_err;
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci	if (err == -ERESTARTSYS && c->status == Connected) {
81862306a36Sopenharmony_ci		p9_debug(P9_DEBUG_MUX, "flushing\n");
81962306a36Sopenharmony_ci		sigpending = 1;
82062306a36Sopenharmony_ci		clear_thread_flag(TIF_SIGPENDING);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		if (c->trans_mod->cancel(c, req))
82362306a36Sopenharmony_ci			p9_client_flush(c, req);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci		/* if we received the response anyway, don't signal error */
82662306a36Sopenharmony_ci		if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
82762306a36Sopenharmony_ci			err = 0;
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_cirecalc_sigpending:
83062306a36Sopenharmony_ci	if (sigpending) {
83162306a36Sopenharmony_ci		spin_lock_irqsave(&current->sighand->siglock, flags);
83262306a36Sopenharmony_ci		recalc_sigpending();
83362306a36Sopenharmony_ci		spin_unlock_irqrestore(&current->sighand->siglock, flags);
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci	if (err < 0)
83662306a36Sopenharmony_ci		goto reterr;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	err = p9_check_errors(c, req);
83962306a36Sopenharmony_ci	trace_9p_client_res(c, type, req->rc.tag, err);
84062306a36Sopenharmony_ci	if (!err)
84162306a36Sopenharmony_ci		return req;
84262306a36Sopenharmony_cireterr:
84362306a36Sopenharmony_ci	p9_req_put(c, req);
84462306a36Sopenharmony_ci	return ERR_PTR(safe_errno(err));
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic struct p9_fid *p9_fid_create(struct p9_client *clnt)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	int ret;
85062306a36Sopenharmony_ci	struct p9_fid *fid;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_FID, "clnt %p\n", clnt);
85362306a36Sopenharmony_ci	fid = kzalloc(sizeof(*fid), GFP_KERNEL);
85462306a36Sopenharmony_ci	if (!fid)
85562306a36Sopenharmony_ci		return NULL;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	fid->mode = -1;
85862306a36Sopenharmony_ci	fid->uid = current_fsuid();
85962306a36Sopenharmony_ci	fid->clnt = clnt;
86062306a36Sopenharmony_ci	refcount_set(&fid->count, 1);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	idr_preload(GFP_KERNEL);
86362306a36Sopenharmony_ci	spin_lock_irq(&clnt->lock);
86462306a36Sopenharmony_ci	ret = idr_alloc_u32(&clnt->fids, fid, &fid->fid, P9_NOFID - 1,
86562306a36Sopenharmony_ci			    GFP_NOWAIT);
86662306a36Sopenharmony_ci	spin_unlock_irq(&clnt->lock);
86762306a36Sopenharmony_ci	idr_preload_end();
86862306a36Sopenharmony_ci	if (!ret) {
86962306a36Sopenharmony_ci		trace_9p_fid_ref(fid, P9_FID_REF_CREATE);
87062306a36Sopenharmony_ci		return fid;
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	kfree(fid);
87462306a36Sopenharmony_ci	return NULL;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic void p9_fid_destroy(struct p9_fid *fid)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct p9_client *clnt;
88062306a36Sopenharmony_ci	unsigned long flags;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
88362306a36Sopenharmony_ci	trace_9p_fid_ref(fid, P9_FID_REF_DESTROY);
88462306a36Sopenharmony_ci	clnt = fid->clnt;
88562306a36Sopenharmony_ci	spin_lock_irqsave(&clnt->lock, flags);
88662306a36Sopenharmony_ci	idr_remove(&clnt->fids, fid->fid);
88762306a36Sopenharmony_ci	spin_unlock_irqrestore(&clnt->lock, flags);
88862306a36Sopenharmony_ci	kfree(fid->rdir);
88962306a36Sopenharmony_ci	kfree(fid);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci/* We also need to export tracepoint symbols for tracepoint_enabled() */
89362306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL(9p_fid_ref);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_civoid do_trace_9p_fid_get(struct p9_fid *fid)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	trace_9p_fid_ref(fid, P9_FID_REF_GET);
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ciEXPORT_SYMBOL(do_trace_9p_fid_get);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_civoid do_trace_9p_fid_put(struct p9_fid *fid)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	trace_9p_fid_ref(fid, P9_FID_REF_PUT);
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ciEXPORT_SYMBOL(do_trace_9p_fid_put);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int p9_client_version(struct p9_client *c)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	int err;
91062306a36Sopenharmony_ci	struct p9_req_t *req;
91162306a36Sopenharmony_ci	char *version = NULL;
91262306a36Sopenharmony_ci	int msize;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
91562306a36Sopenharmony_ci		 c->msize, c->proto_version);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	switch (c->proto_version) {
91862306a36Sopenharmony_ci	case p9_proto_2000L:
91962306a36Sopenharmony_ci		req = p9_client_rpc(c, P9_TVERSION, "ds",
92062306a36Sopenharmony_ci				    c->msize, "9P2000.L");
92162306a36Sopenharmony_ci		break;
92262306a36Sopenharmony_ci	case p9_proto_2000u:
92362306a36Sopenharmony_ci		req = p9_client_rpc(c, P9_TVERSION, "ds",
92462306a36Sopenharmony_ci				    c->msize, "9P2000.u");
92562306a36Sopenharmony_ci		break;
92662306a36Sopenharmony_ci	case p9_proto_legacy:
92762306a36Sopenharmony_ci		req = p9_client_rpc(c, P9_TVERSION, "ds",
92862306a36Sopenharmony_ci				    c->msize, "9P2000");
92962306a36Sopenharmony_ci		break;
93062306a36Sopenharmony_ci	default:
93162306a36Sopenharmony_ci		return -EINVAL;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (IS_ERR(req))
93562306a36Sopenharmony_ci		return PTR_ERR(req);
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, c->proto_version, "ds", &msize, &version);
93862306a36Sopenharmony_ci	if (err) {
93962306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "version error %d\n", err);
94062306a36Sopenharmony_ci		trace_9p_protocol_dump(c, &req->rc);
94162306a36Sopenharmony_ci		goto error;
94262306a36Sopenharmony_ci	}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
94562306a36Sopenharmony_ci	if (!strncmp(version, "9P2000.L", 8)) {
94662306a36Sopenharmony_ci		c->proto_version = p9_proto_2000L;
94762306a36Sopenharmony_ci	} else if (!strncmp(version, "9P2000.u", 8)) {
94862306a36Sopenharmony_ci		c->proto_version = p9_proto_2000u;
94962306a36Sopenharmony_ci	} else if (!strncmp(version, "9P2000", 6)) {
95062306a36Sopenharmony_ci		c->proto_version = p9_proto_legacy;
95162306a36Sopenharmony_ci	} else {
95262306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR,
95362306a36Sopenharmony_ci			 "server returned an unknown version: %s\n", version);
95462306a36Sopenharmony_ci		err = -EREMOTEIO;
95562306a36Sopenharmony_ci		goto error;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (msize < 4096) {
95962306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR,
96062306a36Sopenharmony_ci			 "server returned a msize < 4096: %d\n", msize);
96162306a36Sopenharmony_ci		err = -EREMOTEIO;
96262306a36Sopenharmony_ci		goto error;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci	if (msize < c->msize)
96562306a36Sopenharmony_ci		c->msize = msize;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cierror:
96862306a36Sopenharmony_ci	kfree(version);
96962306a36Sopenharmony_ci	p9_req_put(c, req);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return err;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistruct p9_client *p9_client_create(const char *dev_name, char *options)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	int err;
97762306a36Sopenharmony_ci	struct p9_client *clnt;
97862306a36Sopenharmony_ci	char *client_id;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	clnt = kmalloc(sizeof(*clnt), GFP_KERNEL);
98162306a36Sopenharmony_ci	if (!clnt)
98262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	clnt->trans_mod = NULL;
98562306a36Sopenharmony_ci	clnt->trans = NULL;
98662306a36Sopenharmony_ci	clnt->fcall_cache = NULL;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	client_id = utsname()->nodename;
98962306a36Sopenharmony_ci	memcpy(clnt->name, client_id, strlen(client_id) + 1);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	spin_lock_init(&clnt->lock);
99262306a36Sopenharmony_ci	idr_init(&clnt->fids);
99362306a36Sopenharmony_ci	idr_init(&clnt->reqs);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	err = parse_opts(options, clnt);
99662306a36Sopenharmony_ci	if (err < 0)
99762306a36Sopenharmony_ci		goto free_client;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (!clnt->trans_mod)
100062306a36Sopenharmony_ci		clnt->trans_mod = v9fs_get_default_trans();
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (!clnt->trans_mod) {
100362306a36Sopenharmony_ci		err = -EPROTONOSUPPORT;
100462306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR,
100562306a36Sopenharmony_ci			 "No transport defined or default transport\n");
100662306a36Sopenharmony_ci		goto free_client;
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
101062306a36Sopenharmony_ci		 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	err = clnt->trans_mod->create(clnt, dev_name, options);
101362306a36Sopenharmony_ci	if (err)
101462306a36Sopenharmony_ci		goto put_trans;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (clnt->msize > clnt->trans_mod->maxsize) {
101762306a36Sopenharmony_ci		clnt->msize = clnt->trans_mod->maxsize;
101862306a36Sopenharmony_ci		pr_info("Limiting 'msize' to %d as this is the maximum "
101962306a36Sopenharmony_ci			"supported by transport %s\n",
102062306a36Sopenharmony_ci			clnt->msize, clnt->trans_mod->name
102162306a36Sopenharmony_ci		);
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (clnt->msize < 4096) {
102562306a36Sopenharmony_ci		p9_debug(P9_DEBUG_ERROR,
102662306a36Sopenharmony_ci			 "Please specify a msize of at least 4k\n");
102762306a36Sopenharmony_ci		err = -EINVAL;
102862306a36Sopenharmony_ci		goto close_trans;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	err = p9_client_version(clnt);
103262306a36Sopenharmony_ci	if (err)
103362306a36Sopenharmony_ci		goto close_trans;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* P9_HDRSZ + 4 is the smallest packet header we can have that is
103662306a36Sopenharmony_ci	 * followed by data accessed from userspace by read
103762306a36Sopenharmony_ci	 */
103862306a36Sopenharmony_ci	clnt->fcall_cache =
103962306a36Sopenharmony_ci		kmem_cache_create_usercopy("9p-fcall-cache", clnt->msize,
104062306a36Sopenharmony_ci					   0, 0, P9_HDRSZ + 4,
104162306a36Sopenharmony_ci					   clnt->msize - (P9_HDRSZ + 4),
104262306a36Sopenharmony_ci					   NULL);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	return clnt;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ciclose_trans:
104762306a36Sopenharmony_ci	clnt->trans_mod->close(clnt);
104862306a36Sopenharmony_ciput_trans:
104962306a36Sopenharmony_ci	v9fs_put_trans(clnt->trans_mod);
105062306a36Sopenharmony_cifree_client:
105162306a36Sopenharmony_ci	kfree(clnt);
105262306a36Sopenharmony_ci	return ERR_PTR(err);
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_create);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_civoid p9_client_destroy(struct p9_client *clnt)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	struct p9_fid *fid;
105962306a36Sopenharmony_ci	int id;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	if (clnt->trans_mod)
106462306a36Sopenharmony_ci		clnt->trans_mod->close(clnt);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	v9fs_put_trans(clnt->trans_mod);
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	idr_for_each_entry(&clnt->fids, fid, id) {
106962306a36Sopenharmony_ci		pr_info("Found fid %d not clunked\n", fid->fid);
107062306a36Sopenharmony_ci		p9_fid_destroy(fid);
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	p9_tag_cleanup(clnt);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	kmem_cache_destroy(clnt->fcall_cache);
107662306a36Sopenharmony_ci	kfree(clnt);
107762306a36Sopenharmony_ci}
107862306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_destroy);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_civoid p9_client_disconnect(struct p9_client *clnt)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
108362306a36Sopenharmony_ci	clnt->status = Disconnected;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_disconnect);
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_civoid p9_client_begin_disconnect(struct p9_client *clnt)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
109062306a36Sopenharmony_ci	clnt->status = BeginDisconnect;
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_begin_disconnect);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistruct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
109562306a36Sopenharmony_ci				const char *uname, kuid_t n_uname,
109662306a36Sopenharmony_ci				const char *aname)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	int err;
109962306a36Sopenharmony_ci	struct p9_req_t *req;
110062306a36Sopenharmony_ci	struct p9_fid *fid;
110162306a36Sopenharmony_ci	struct p9_qid qid;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
110462306a36Sopenharmony_ci		 afid ? afid->fid : -1, uname, aname);
110562306a36Sopenharmony_ci	fid = p9_fid_create(clnt);
110662306a36Sopenharmony_ci	if (!fid) {
110762306a36Sopenharmony_ci		err = -ENOMEM;
110862306a36Sopenharmony_ci		goto error;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci	fid->uid = n_uname;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid,
111362306a36Sopenharmony_ci			    afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
111462306a36Sopenharmony_ci	if (IS_ERR(req)) {
111562306a36Sopenharmony_ci		err = PTR_ERR(req);
111662306a36Sopenharmony_ci		goto error;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", &qid);
112062306a36Sopenharmony_ci	if (err) {
112162306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
112262306a36Sopenharmony_ci		p9_req_put(clnt, req);
112362306a36Sopenharmony_ci		goto error;
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
112762306a36Sopenharmony_ci		 qid.type, qid.path, qid.version);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	memmove(&fid->qid, &qid, sizeof(struct p9_qid));
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	p9_req_put(clnt, req);
113262306a36Sopenharmony_ci	return fid;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_cierror:
113562306a36Sopenharmony_ci	if (fid)
113662306a36Sopenharmony_ci		p9_fid_destroy(fid);
113762306a36Sopenharmony_ci	return ERR_PTR(err);
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_attach);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistruct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
114262306a36Sopenharmony_ci			      const unsigned char * const *wnames, int clone)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	int err;
114562306a36Sopenharmony_ci	struct p9_client *clnt;
114662306a36Sopenharmony_ci	struct p9_fid *fid;
114762306a36Sopenharmony_ci	struct p9_qid *wqids;
114862306a36Sopenharmony_ci	struct p9_req_t *req;
114962306a36Sopenharmony_ci	u16 nwqids, count;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci	wqids = NULL;
115262306a36Sopenharmony_ci	clnt = oldfid->clnt;
115362306a36Sopenharmony_ci	if (clone) {
115462306a36Sopenharmony_ci		fid = p9_fid_create(clnt);
115562306a36Sopenharmony_ci		if (!fid) {
115662306a36Sopenharmony_ci			err = -ENOMEM;
115762306a36Sopenharmony_ci			goto error;
115862306a36Sopenharmony_ci		}
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci		fid->uid = oldfid->uid;
116162306a36Sopenharmony_ci	} else {
116262306a36Sopenharmony_ci		fid = oldfid;
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
116662306a36Sopenharmony_ci		 oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
116762306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
116862306a36Sopenharmony_ci			    nwname, wnames);
116962306a36Sopenharmony_ci	if (IS_ERR(req)) {
117062306a36Sopenharmony_ci		err = PTR_ERR(req);
117162306a36Sopenharmony_ci		goto error;
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "R", &nwqids, &wqids);
117562306a36Sopenharmony_ci	if (err) {
117662306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
117762306a36Sopenharmony_ci		p9_req_put(clnt, req);
117862306a36Sopenharmony_ci		goto clunk_fid;
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci	p9_req_put(clnt, req);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	if (nwqids != nwname) {
118562306a36Sopenharmony_ci		err = -ENOENT;
118662306a36Sopenharmony_ci		goto clunk_fid;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	for (count = 0; count < nwqids; count++)
119062306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "<<<     [%d] %x.%llx.%x\n",
119162306a36Sopenharmony_ci			 count, wqids[count].type,
119262306a36Sopenharmony_ci			 wqids[count].path,
119362306a36Sopenharmony_ci			 wqids[count].version);
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	if (nwname)
119662306a36Sopenharmony_ci		memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
119762306a36Sopenharmony_ci	else
119862306a36Sopenharmony_ci		memmove(&fid->qid, &oldfid->qid, sizeof(struct p9_qid));
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	kfree(wqids);
120162306a36Sopenharmony_ci	return fid;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ciclunk_fid:
120462306a36Sopenharmony_ci	kfree(wqids);
120562306a36Sopenharmony_ci	p9_fid_put(fid);
120662306a36Sopenharmony_ci	fid = NULL;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cierror:
120962306a36Sopenharmony_ci	if (fid && fid != oldfid)
121062306a36Sopenharmony_ci		p9_fid_destroy(fid);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	return ERR_PTR(err);
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_walk);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ciint p9_client_open(struct p9_fid *fid, int mode)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	int err;
121962306a36Sopenharmony_ci	struct p9_client *clnt;
122062306a36Sopenharmony_ci	struct p9_req_t *req;
122162306a36Sopenharmony_ci	struct p9_qid qid;
122262306a36Sopenharmony_ci	int iounit;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	clnt = fid->clnt;
122562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
122662306a36Sopenharmony_ci		 p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	if (fid->mode != -1)
122962306a36Sopenharmony_ci		return -EINVAL;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (p9_is_proto_dotl(clnt))
123262306a36Sopenharmony_ci		req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode & P9L_MODE_MASK);
123362306a36Sopenharmony_ci	else
123462306a36Sopenharmony_ci		req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode & P9L_MODE_MASK);
123562306a36Sopenharmony_ci	if (IS_ERR(req)) {
123662306a36Sopenharmony_ci		err = PTR_ERR(req);
123762306a36Sopenharmony_ci		goto error;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
124162306a36Sopenharmony_ci	if (err) {
124262306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
124362306a36Sopenharmony_ci		goto free_and_error;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
124762306a36Sopenharmony_ci		 p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN",  qid.type,
124862306a36Sopenharmony_ci		 qid.path, qid.version, iounit);
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	memmove(&fid->qid, &qid, sizeof(struct p9_qid));
125162306a36Sopenharmony_ci	fid->mode = mode;
125262306a36Sopenharmony_ci	fid->iounit = iounit;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cifree_and_error:
125562306a36Sopenharmony_ci	p9_req_put(clnt, req);
125662306a36Sopenharmony_cierror:
125762306a36Sopenharmony_ci	return err;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_open);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ciint p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags,
126262306a36Sopenharmony_ci			  u32 mode, kgid_t gid, struct p9_qid *qid)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	int err;
126562306a36Sopenharmony_ci	struct p9_client *clnt;
126662306a36Sopenharmony_ci	struct p9_req_t *req;
126762306a36Sopenharmony_ci	int iounit;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
127062306a36Sopenharmony_ci		 ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
127162306a36Sopenharmony_ci		 ofid->fid, name, flags, mode,
127262306a36Sopenharmony_ci		 from_kgid(&init_user_ns, gid));
127362306a36Sopenharmony_ci	clnt = ofid->clnt;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	if (ofid->mode != -1)
127662306a36Sopenharmony_ci		return -EINVAL;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TLCREATE, "dsddg", ofid->fid, name, flags,
127962306a36Sopenharmony_ci			    mode & P9L_MODE_MASK, gid);
128062306a36Sopenharmony_ci	if (IS_ERR(req)) {
128162306a36Sopenharmony_ci		err = PTR_ERR(req);
128262306a36Sopenharmony_ci		goto error;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", qid, &iounit);
128662306a36Sopenharmony_ci	if (err) {
128762306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
128862306a36Sopenharmony_ci		goto free_and_error;
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
129262306a36Sopenharmony_ci		 qid->type, qid->path, qid->version, iounit);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	memmove(&ofid->qid, qid, sizeof(struct p9_qid));
129562306a36Sopenharmony_ci	ofid->mode = flags;
129662306a36Sopenharmony_ci	ofid->iounit = iounit;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cifree_and_error:
129962306a36Sopenharmony_ci	p9_req_put(clnt, req);
130062306a36Sopenharmony_cierror:
130162306a36Sopenharmony_ci	return err;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_create_dotl);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ciint p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode,
130662306a36Sopenharmony_ci		     char *extension)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	int err;
130962306a36Sopenharmony_ci	struct p9_client *clnt;
131062306a36Sopenharmony_ci	struct p9_req_t *req;
131162306a36Sopenharmony_ci	struct p9_qid qid;
131262306a36Sopenharmony_ci	int iounit;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
131562306a36Sopenharmony_ci		 fid->fid, name, perm, mode);
131662306a36Sopenharmony_ci	clnt = fid->clnt;
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	if (fid->mode != -1)
131962306a36Sopenharmony_ci		return -EINVAL;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm,
132262306a36Sopenharmony_ci			    mode & P9L_MODE_MASK, extension);
132362306a36Sopenharmony_ci	if (IS_ERR(req)) {
132462306a36Sopenharmony_ci		err = PTR_ERR(req);
132562306a36Sopenharmony_ci		goto error;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
132962306a36Sopenharmony_ci	if (err) {
133062306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
133162306a36Sopenharmony_ci		goto free_and_error;
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
133562306a36Sopenharmony_ci		 qid.type, qid.path, qid.version, iounit);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	memmove(&fid->qid, &qid, sizeof(struct p9_qid));
133862306a36Sopenharmony_ci	fid->mode = mode;
133962306a36Sopenharmony_ci	fid->iounit = iounit;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cifree_and_error:
134262306a36Sopenharmony_ci	p9_req_put(clnt, req);
134362306a36Sopenharmony_cierror:
134462306a36Sopenharmony_ci	return err;
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_fcreate);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ciint p9_client_symlink(struct p9_fid *dfid, const char *name,
134962306a36Sopenharmony_ci		      const char *symtgt, kgid_t gid, struct p9_qid *qid)
135062306a36Sopenharmony_ci{
135162306a36Sopenharmony_ci	int err;
135262306a36Sopenharmony_ci	struct p9_client *clnt;
135362306a36Sopenharmony_ci	struct p9_req_t *req;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s  symtgt %s\n",
135662306a36Sopenharmony_ci		 dfid->fid, name, symtgt);
135762306a36Sopenharmony_ci	clnt = dfid->clnt;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TSYMLINK, "dssg", dfid->fid, name, symtgt,
136062306a36Sopenharmony_ci			    gid);
136162306a36Sopenharmony_ci	if (IS_ERR(req)) {
136262306a36Sopenharmony_ci		err = PTR_ERR(req);
136362306a36Sopenharmony_ci		goto error;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
136762306a36Sopenharmony_ci	if (err) {
136862306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
136962306a36Sopenharmony_ci		goto free_and_error;
137062306a36Sopenharmony_ci	}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
137362306a36Sopenharmony_ci		 qid->type, qid->path, qid->version);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cifree_and_error:
137662306a36Sopenharmony_ci	p9_req_put(clnt, req);
137762306a36Sopenharmony_cierror:
137862306a36Sopenharmony_ci	return err;
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_symlink);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ciint p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, const char *newname)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct p9_client *clnt;
138562306a36Sopenharmony_ci	struct p9_req_t *req;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
138862306a36Sopenharmony_ci		 dfid->fid, oldfid->fid, newname);
138962306a36Sopenharmony_ci	clnt = dfid->clnt;
139062306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
139162306a36Sopenharmony_ci			    newname);
139262306a36Sopenharmony_ci	if (IS_ERR(req))
139362306a36Sopenharmony_ci		return PTR_ERR(req);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RLINK\n");
139662306a36Sopenharmony_ci	p9_req_put(clnt, req);
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_link);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ciint p9_client_fsync(struct p9_fid *fid, int datasync)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	int err = 0;
140462306a36Sopenharmony_ci	struct p9_client *clnt;
140562306a36Sopenharmony_ci	struct p9_req_t *req;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
140862306a36Sopenharmony_ci		 fid->fid, datasync);
140962306a36Sopenharmony_ci	clnt = fid->clnt;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
141262306a36Sopenharmony_ci	if (IS_ERR(req)) {
141362306a36Sopenharmony_ci		err = PTR_ERR(req);
141462306a36Sopenharmony_ci		goto error;
141562306a36Sopenharmony_ci	}
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	p9_req_put(clnt, req);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cierror:
142262306a36Sopenharmony_ci	return err;
142362306a36Sopenharmony_ci}
142462306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_fsync);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ciint p9_client_clunk(struct p9_fid *fid)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	int err = 0;
142962306a36Sopenharmony_ci	struct p9_client *clnt;
143062306a36Sopenharmony_ci	struct p9_req_t *req;
143162306a36Sopenharmony_ci	int retries = 0;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ciagain:
143462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n",
143562306a36Sopenharmony_ci		 fid->fid, retries);
143662306a36Sopenharmony_ci	clnt = fid->clnt;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid);
143962306a36Sopenharmony_ci	if (IS_ERR(req)) {
144062306a36Sopenharmony_ci		err = PTR_ERR(req);
144162306a36Sopenharmony_ci		goto error;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	p9_req_put(clnt, req);
144762306a36Sopenharmony_cierror:
144862306a36Sopenharmony_ci	/* Fid is not valid even after a failed clunk
144962306a36Sopenharmony_ci	 * If interrupted, retry once then give up and
145062306a36Sopenharmony_ci	 * leak fid until umount.
145162306a36Sopenharmony_ci	 */
145262306a36Sopenharmony_ci	if (err == -ERESTARTSYS) {
145362306a36Sopenharmony_ci		if (retries++ == 0)
145462306a36Sopenharmony_ci			goto again;
145562306a36Sopenharmony_ci	} else {
145662306a36Sopenharmony_ci		p9_fid_destroy(fid);
145762306a36Sopenharmony_ci	}
145862306a36Sopenharmony_ci	return err;
145962306a36Sopenharmony_ci}
146062306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_clunk);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ciint p9_client_remove(struct p9_fid *fid)
146362306a36Sopenharmony_ci{
146462306a36Sopenharmony_ci	int err = 0;
146562306a36Sopenharmony_ci	struct p9_client *clnt;
146662306a36Sopenharmony_ci	struct p9_req_t *req;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
146962306a36Sopenharmony_ci	clnt = fid->clnt;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid);
147262306a36Sopenharmony_ci	if (IS_ERR(req)) {
147362306a36Sopenharmony_ci		err = PTR_ERR(req);
147462306a36Sopenharmony_ci		goto error;
147562306a36Sopenharmony_ci	}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	p9_req_put(clnt, req);
148062306a36Sopenharmony_cierror:
148162306a36Sopenharmony_ci	if (err == -ERESTARTSYS)
148262306a36Sopenharmony_ci		p9_fid_put(fid);
148362306a36Sopenharmony_ci	else
148462306a36Sopenharmony_ci		p9_fid_destroy(fid);
148562306a36Sopenharmony_ci	return err;
148662306a36Sopenharmony_ci}
148762306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_remove);
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ciint p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
149062306a36Sopenharmony_ci{
149162306a36Sopenharmony_ci	int err = 0;
149262306a36Sopenharmony_ci	struct p9_req_t *req;
149362306a36Sopenharmony_ci	struct p9_client *clnt;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n",
149662306a36Sopenharmony_ci		 dfid->fid, name, flags);
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	clnt = dfid->clnt;
149962306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags);
150062306a36Sopenharmony_ci	if (IS_ERR(req)) {
150162306a36Sopenharmony_ci		err = PTR_ERR(req);
150262306a36Sopenharmony_ci		goto error;
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	p9_req_put(clnt, req);
150762306a36Sopenharmony_cierror:
150862306a36Sopenharmony_ci	return err;
150962306a36Sopenharmony_ci}
151062306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_unlinkat);
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ciint
151362306a36Sopenharmony_cip9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
151462306a36Sopenharmony_ci{
151562306a36Sopenharmony_ci	int total = 0;
151662306a36Sopenharmony_ci	*err = 0;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	while (iov_iter_count(to)) {
151962306a36Sopenharmony_ci		int count;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		count = p9_client_read_once(fid, offset, to, err);
152262306a36Sopenharmony_ci		if (!count || *err)
152362306a36Sopenharmony_ci			break;
152462306a36Sopenharmony_ci		offset += count;
152562306a36Sopenharmony_ci		total += count;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci	return total;
152862306a36Sopenharmony_ci}
152962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_read);
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ciint
153262306a36Sopenharmony_cip9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
153362306a36Sopenharmony_ci		    int *err)
153462306a36Sopenharmony_ci{
153562306a36Sopenharmony_ci	struct p9_client *clnt = fid->clnt;
153662306a36Sopenharmony_ci	struct p9_req_t *req;
153762306a36Sopenharmony_ci	int count = iov_iter_count(to);
153862306a36Sopenharmony_ci	int rsize, received, non_zc = 0;
153962306a36Sopenharmony_ci	char *dataptr;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	*err = 0;
154262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %zu\n",
154362306a36Sopenharmony_ci		 fid->fid, offset, iov_iter_count(to));
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	rsize = fid->iounit;
154662306a36Sopenharmony_ci	if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
154762306a36Sopenharmony_ci		rsize = clnt->msize - P9_IOHDRSZ;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	if (count < rsize)
155062306a36Sopenharmony_ci		rsize = count;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	/* Don't bother zerocopy for small IO (< 1024) */
155362306a36Sopenharmony_ci	if (clnt->trans_mod->zc_request && rsize > 1024) {
155462306a36Sopenharmony_ci		/* response header len is 11
155562306a36Sopenharmony_ci		 * PDU Header(7) + IO Size (4)
155662306a36Sopenharmony_ci		 */
155762306a36Sopenharmony_ci		req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
155862306a36Sopenharmony_ci				       0, 11, "dqd", fid->fid,
155962306a36Sopenharmony_ci				       offset, rsize);
156062306a36Sopenharmony_ci	} else {
156162306a36Sopenharmony_ci		non_zc = 1;
156262306a36Sopenharmony_ci		req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
156362306a36Sopenharmony_ci				    rsize);
156462306a36Sopenharmony_ci	}
156562306a36Sopenharmony_ci	if (IS_ERR(req)) {
156662306a36Sopenharmony_ci		*err = PTR_ERR(req);
156762306a36Sopenharmony_ci		if (!non_zc)
156862306a36Sopenharmony_ci			iov_iter_revert(to, count - iov_iter_count(to));
156962306a36Sopenharmony_ci		return 0;
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	*err = p9pdu_readf(&req->rc, clnt->proto_version,
157362306a36Sopenharmony_ci			   "D", &received, &dataptr);
157462306a36Sopenharmony_ci	if (*err) {
157562306a36Sopenharmony_ci		if (!non_zc)
157662306a36Sopenharmony_ci			iov_iter_revert(to, count - iov_iter_count(to));
157762306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
157862306a36Sopenharmony_ci		p9_req_put(clnt, req);
157962306a36Sopenharmony_ci		return 0;
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci	if (rsize < received) {
158262306a36Sopenharmony_ci		pr_err("bogus RREAD count (%d > %d)\n", received, rsize);
158362306a36Sopenharmony_ci		received = rsize;
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", count);
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (non_zc) {
158962306a36Sopenharmony_ci		int n = copy_to_iter(dataptr, received, to);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		if (n != received) {
159262306a36Sopenharmony_ci			*err = -EFAULT;
159362306a36Sopenharmony_ci			p9_req_put(clnt, req);
159462306a36Sopenharmony_ci			return n;
159562306a36Sopenharmony_ci		}
159662306a36Sopenharmony_ci	} else {
159762306a36Sopenharmony_ci		iov_iter_revert(to, count - received - iov_iter_count(to));
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci	p9_req_put(clnt, req);
160062306a36Sopenharmony_ci	return received;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_read_once);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ciint
160562306a36Sopenharmony_cip9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	struct p9_client *clnt = fid->clnt;
160862306a36Sopenharmony_ci	struct p9_req_t *req;
160962306a36Sopenharmony_ci	int total = 0;
161062306a36Sopenharmony_ci	*err = 0;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %zd\n",
161362306a36Sopenharmony_ci		 fid->fid, offset, iov_iter_count(from));
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	while (iov_iter_count(from)) {
161662306a36Sopenharmony_ci		int count = iov_iter_count(from);
161762306a36Sopenharmony_ci		int rsize = fid->iounit;
161862306a36Sopenharmony_ci		int written;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci		if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
162162306a36Sopenharmony_ci			rsize = clnt->msize - P9_IOHDRSZ;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci		if (count < rsize)
162462306a36Sopenharmony_ci			rsize = count;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci		/* Don't bother zerocopy for small IO (< 1024) */
162762306a36Sopenharmony_ci		if (clnt->trans_mod->zc_request && rsize > 1024) {
162862306a36Sopenharmony_ci			req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0,
162962306a36Sopenharmony_ci					       rsize, P9_ZC_HDR_SZ, "dqd",
163062306a36Sopenharmony_ci					       fid->fid, offset, rsize);
163162306a36Sopenharmony_ci		} else {
163262306a36Sopenharmony_ci			req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid,
163362306a36Sopenharmony_ci					    offset, rsize, from);
163462306a36Sopenharmony_ci		}
163562306a36Sopenharmony_ci		if (IS_ERR(req)) {
163662306a36Sopenharmony_ci			iov_iter_revert(from, count - iov_iter_count(from));
163762306a36Sopenharmony_ci			*err = PTR_ERR(req);
163862306a36Sopenharmony_ci			break;
163962306a36Sopenharmony_ci		}
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		*err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &written);
164262306a36Sopenharmony_ci		if (*err) {
164362306a36Sopenharmony_ci			iov_iter_revert(from, count - iov_iter_count(from));
164462306a36Sopenharmony_ci			trace_9p_protocol_dump(clnt, &req->rc);
164562306a36Sopenharmony_ci			p9_req_put(clnt, req);
164662306a36Sopenharmony_ci			break;
164762306a36Sopenharmony_ci		}
164862306a36Sopenharmony_ci		if (rsize < written) {
164962306a36Sopenharmony_ci			pr_err("bogus RWRITE count (%d > %d)\n", written, rsize);
165062306a36Sopenharmony_ci			written = rsize;
165162306a36Sopenharmony_ci		}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci		p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", count);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci		p9_req_put(clnt, req);
165662306a36Sopenharmony_ci		iov_iter_revert(from, count - written - iov_iter_count(from));
165762306a36Sopenharmony_ci		total += written;
165862306a36Sopenharmony_ci		offset += written;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci	return total;
166162306a36Sopenharmony_ci}
166262306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_write);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_cistruct p9_wstat *p9_client_stat(struct p9_fid *fid)
166562306a36Sopenharmony_ci{
166662306a36Sopenharmony_ci	int err;
166762306a36Sopenharmony_ci	struct p9_client *clnt;
166862306a36Sopenharmony_ci	struct p9_wstat *ret;
166962306a36Sopenharmony_ci	struct p9_req_t *req;
167062306a36Sopenharmony_ci	u16 ignored;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	ret = kmalloc(sizeof(*ret), GFP_KERNEL);
167562306a36Sopenharmony_ci	if (!ret)
167662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	clnt = fid->clnt;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid);
168162306a36Sopenharmony_ci	if (IS_ERR(req)) {
168262306a36Sopenharmony_ci		err = PTR_ERR(req);
168362306a36Sopenharmony_ci		goto error;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "wS", &ignored, ret);
168762306a36Sopenharmony_ci	if (err) {
168862306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
168962306a36Sopenharmony_ci		p9_req_put(clnt, req);
169062306a36Sopenharmony_ci		goto error;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
169462306a36Sopenharmony_ci		 "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
169562306a36Sopenharmony_ci		 "<<<    mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
169662306a36Sopenharmony_ci		 "<<<    name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
169762306a36Sopenharmony_ci		 "<<<    uid=%d gid=%d n_muid=%d\n",
169862306a36Sopenharmony_ci		 ret->size, ret->type, ret->dev, ret->qid.type, ret->qid.path,
169962306a36Sopenharmony_ci		 ret->qid.version, ret->mode,
170062306a36Sopenharmony_ci		 ret->atime, ret->mtime, ret->length,
170162306a36Sopenharmony_ci		 ret->name, ret->uid, ret->gid, ret->muid, ret->extension,
170262306a36Sopenharmony_ci		 from_kuid(&init_user_ns, ret->n_uid),
170362306a36Sopenharmony_ci		 from_kgid(&init_user_ns, ret->n_gid),
170462306a36Sopenharmony_ci		 from_kuid(&init_user_ns, ret->n_muid));
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	p9_req_put(clnt, req);
170762306a36Sopenharmony_ci	return ret;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_cierror:
171062306a36Sopenharmony_ci	kfree(ret);
171162306a36Sopenharmony_ci	return ERR_PTR(err);
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_stat);
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_cistruct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
171662306a36Sopenharmony_ci					    u64 request_mask)
171762306a36Sopenharmony_ci{
171862306a36Sopenharmony_ci	int err;
171962306a36Sopenharmony_ci	struct p9_client *clnt;
172062306a36Sopenharmony_ci	struct p9_stat_dotl *ret;
172162306a36Sopenharmony_ci	struct p9_req_t *req;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
172462306a36Sopenharmony_ci		 fid->fid, request_mask);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	ret = kmalloc(sizeof(*ret), GFP_KERNEL);
172762306a36Sopenharmony_ci	if (!ret)
172862306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	clnt = fid->clnt;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
173362306a36Sopenharmony_ci	if (IS_ERR(req)) {
173462306a36Sopenharmony_ci		err = PTR_ERR(req);
173562306a36Sopenharmony_ci		goto error;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "A", ret);
173962306a36Sopenharmony_ci	if (err) {
174062306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
174162306a36Sopenharmony_ci		p9_req_put(clnt, req);
174262306a36Sopenharmony_ci		goto error;
174362306a36Sopenharmony_ci	}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RGETATTR st_result_mask=%lld\n"
174662306a36Sopenharmony_ci		 "<<< qid=%x.%llx.%x\n"
174762306a36Sopenharmony_ci		 "<<< st_mode=%8.8x st_nlink=%llu\n"
174862306a36Sopenharmony_ci		 "<<< st_uid=%d st_gid=%d\n"
174962306a36Sopenharmony_ci		 "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
175062306a36Sopenharmony_ci		 "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
175162306a36Sopenharmony_ci		 "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
175262306a36Sopenharmony_ci		 "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
175362306a36Sopenharmony_ci		 "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
175462306a36Sopenharmony_ci		 "<<< st_gen=%lld st_data_version=%lld\n",
175562306a36Sopenharmony_ci		 ret->st_result_mask,
175662306a36Sopenharmony_ci		 ret->qid.type, ret->qid.path, ret->qid.version,
175762306a36Sopenharmony_ci		 ret->st_mode, ret->st_nlink,
175862306a36Sopenharmony_ci		 from_kuid(&init_user_ns, ret->st_uid),
175962306a36Sopenharmony_ci		 from_kgid(&init_user_ns, ret->st_gid),
176062306a36Sopenharmony_ci		 ret->st_rdev, ret->st_size, ret->st_blksize, ret->st_blocks,
176162306a36Sopenharmony_ci		 ret->st_atime_sec, ret->st_atime_nsec,
176262306a36Sopenharmony_ci		 ret->st_mtime_sec, ret->st_mtime_nsec,
176362306a36Sopenharmony_ci		 ret->st_ctime_sec, ret->st_ctime_nsec,
176462306a36Sopenharmony_ci		 ret->st_btime_sec, ret->st_btime_nsec,
176562306a36Sopenharmony_ci		 ret->st_gen, ret->st_data_version);
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	p9_req_put(clnt, req);
176862306a36Sopenharmony_ci	return ret;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_cierror:
177162306a36Sopenharmony_ci	kfree(ret);
177262306a36Sopenharmony_ci	return ERR_PTR(err);
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_getattr_dotl);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cistatic int p9_client_statsize(struct p9_wstat *wst, int proto_version)
177762306a36Sopenharmony_ci{
177862306a36Sopenharmony_ci	int ret;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	/* NOTE: size shouldn't include its own length */
178162306a36Sopenharmony_ci	/* size[2] type[2] dev[4] qid[13] */
178262306a36Sopenharmony_ci	/* mode[4] atime[4] mtime[4] length[8]*/
178362306a36Sopenharmony_ci	/* name[s] uid[s] gid[s] muid[s] */
178462306a36Sopenharmony_ci	ret = 2 + 4 + 13 + 4 + 4 + 4 + 8 + 2 + 2 + 2 + 2;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	if (wst->name)
178762306a36Sopenharmony_ci		ret += strlen(wst->name);
178862306a36Sopenharmony_ci	if (wst->uid)
178962306a36Sopenharmony_ci		ret += strlen(wst->uid);
179062306a36Sopenharmony_ci	if (wst->gid)
179162306a36Sopenharmony_ci		ret += strlen(wst->gid);
179262306a36Sopenharmony_ci	if (wst->muid)
179362306a36Sopenharmony_ci		ret += strlen(wst->muid);
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	if (proto_version == p9_proto_2000u ||
179662306a36Sopenharmony_ci	    proto_version == p9_proto_2000L) {
179762306a36Sopenharmony_ci		/* extension[s] n_uid[4] n_gid[4] n_muid[4] */
179862306a36Sopenharmony_ci		ret += 2 + 4 + 4 + 4;
179962306a36Sopenharmony_ci		if (wst->extension)
180062306a36Sopenharmony_ci			ret += strlen(wst->extension);
180162306a36Sopenharmony_ci	}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci	return ret;
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ciint p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci	int err = 0;
180962306a36Sopenharmony_ci	struct p9_req_t *req;
181062306a36Sopenharmony_ci	struct p9_client *clnt;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	clnt = fid->clnt;
181362306a36Sopenharmony_ci	wst->size = p9_client_statsize(wst, clnt->proto_version);
181462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TWSTAT fid %d\n",
181562306a36Sopenharmony_ci		 fid->fid);
181662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
181762306a36Sopenharmony_ci		 "     sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
181862306a36Sopenharmony_ci		 "     mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
181962306a36Sopenharmony_ci		 "     name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
182062306a36Sopenharmony_ci		 "     uid=%d gid=%d n_muid=%d\n",
182162306a36Sopenharmony_ci		 wst->size, wst->type, wst->dev, wst->qid.type,
182262306a36Sopenharmony_ci		 wst->qid.path, wst->qid.version,
182362306a36Sopenharmony_ci		 wst->mode, wst->atime, wst->mtime, wst->length,
182462306a36Sopenharmony_ci		 wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
182562306a36Sopenharmony_ci		 from_kuid(&init_user_ns, wst->n_uid),
182662306a36Sopenharmony_ci		 from_kgid(&init_user_ns, wst->n_gid),
182762306a36Sopenharmony_ci		 from_kuid(&init_user_ns, wst->n_muid));
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TWSTAT, "dwS",
183062306a36Sopenharmony_ci			    fid->fid, wst->size + 2, wst);
183162306a36Sopenharmony_ci	if (IS_ERR(req)) {
183262306a36Sopenharmony_ci		err = PTR_ERR(req);
183362306a36Sopenharmony_ci		goto error;
183462306a36Sopenharmony_ci	}
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	p9_req_put(clnt, req);
183962306a36Sopenharmony_cierror:
184062306a36Sopenharmony_ci	return err;
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_wstat);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ciint p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
184562306a36Sopenharmony_ci{
184662306a36Sopenharmony_ci	int err = 0;
184762306a36Sopenharmony_ci	struct p9_req_t *req;
184862306a36Sopenharmony_ci	struct p9_client *clnt;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	clnt = fid->clnt;
185162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
185262306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "    valid=%x mode=%x uid=%d gid=%d size=%lld\n",
185362306a36Sopenharmony_ci		 p9attr->valid, p9attr->mode,
185462306a36Sopenharmony_ci		 from_kuid(&init_user_ns, p9attr->uid),
185562306a36Sopenharmony_ci		 from_kgid(&init_user_ns, p9attr->gid),
185662306a36Sopenharmony_ci		 p9attr->size);
185762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "    atime_sec=%lld atime_nsec=%lld\n",
185862306a36Sopenharmony_ci		 p9attr->atime_sec, p9attr->atime_nsec);
185962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "    mtime_sec=%lld mtime_nsec=%lld\n",
186062306a36Sopenharmony_ci		 p9attr->mtime_sec, p9attr->mtime_nsec);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (IS_ERR(req)) {
186562306a36Sopenharmony_ci		err = PTR_ERR(req);
186662306a36Sopenharmony_ci		goto error;
186762306a36Sopenharmony_ci	}
186862306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
186962306a36Sopenharmony_ci	p9_req_put(clnt, req);
187062306a36Sopenharmony_cierror:
187162306a36Sopenharmony_ci	return err;
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_setattr);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ciint p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
187662306a36Sopenharmony_ci{
187762306a36Sopenharmony_ci	int err;
187862306a36Sopenharmony_ci	struct p9_req_t *req;
187962306a36Sopenharmony_ci	struct p9_client *clnt;
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	clnt = fid->clnt;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
188662306a36Sopenharmony_ci	if (IS_ERR(req)) {
188762306a36Sopenharmony_ci		err = PTR_ERR(req);
188862306a36Sopenharmony_ci		goto error;
188962306a36Sopenharmony_ci	}
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
189262306a36Sopenharmony_ci			  &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
189362306a36Sopenharmony_ci			  &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
189462306a36Sopenharmony_ci	if (err) {
189562306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
189662306a36Sopenharmony_ci		p9_req_put(clnt, req);
189762306a36Sopenharmony_ci		goto error;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
190162306a36Sopenharmony_ci		 "<<< RSTATFS fid %d type 0x%x bsize %u blocks %llu bfree %llu bavail %llu files %llu ffree %llu fsid %llu namelen %u\n",
190262306a36Sopenharmony_ci		 fid->fid, sb->type, sb->bsize, sb->blocks, sb->bfree,
190362306a36Sopenharmony_ci		 sb->bavail, sb->files, sb->ffree, sb->fsid, sb->namelen);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	p9_req_put(clnt, req);
190662306a36Sopenharmony_cierror:
190762306a36Sopenharmony_ci	return err;
190862306a36Sopenharmony_ci}
190962306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_statfs);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ciint p9_client_rename(struct p9_fid *fid,
191262306a36Sopenharmony_ci		     struct p9_fid *newdirfid, const char *name)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	int err = 0;
191562306a36Sopenharmony_ci	struct p9_req_t *req;
191662306a36Sopenharmony_ci	struct p9_client *clnt;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	clnt = fid->clnt;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
192162306a36Sopenharmony_ci		 fid->fid, newdirfid->fid, name);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
192462306a36Sopenharmony_ci			    newdirfid->fid, name);
192562306a36Sopenharmony_ci	if (IS_ERR(req)) {
192662306a36Sopenharmony_ci		err = PTR_ERR(req);
192762306a36Sopenharmony_ci		goto error;
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	p9_req_put(clnt, req);
193362306a36Sopenharmony_cierror:
193462306a36Sopenharmony_ci	return err;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_rename);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ciint p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
193962306a36Sopenharmony_ci		       struct p9_fid *newdirfid, const char *new_name)
194062306a36Sopenharmony_ci{
194162306a36Sopenharmony_ci	int err = 0;
194262306a36Sopenharmony_ci	struct p9_req_t *req;
194362306a36Sopenharmony_ci	struct p9_client *clnt;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	clnt = olddirfid->clnt;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
194862306a36Sopenharmony_ci		 ">>> TRENAMEAT olddirfid %d old name %s newdirfid %d new name %s\n",
194962306a36Sopenharmony_ci		 olddirfid->fid, old_name, newdirfid->fid, new_name);
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid,
195262306a36Sopenharmony_ci			    old_name, newdirfid->fid, new_name);
195362306a36Sopenharmony_ci	if (IS_ERR(req)) {
195462306a36Sopenharmony_ci		err = PTR_ERR(req);
195562306a36Sopenharmony_ci		goto error;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
195962306a36Sopenharmony_ci		 newdirfid->fid, new_name);
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	p9_req_put(clnt, req);
196262306a36Sopenharmony_cierror:
196362306a36Sopenharmony_ci	return err;
196462306a36Sopenharmony_ci}
196562306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_renameat);
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci/* An xattrwalk without @attr_name gives the fid for the lisxattr namespace
196862306a36Sopenharmony_ci */
196962306a36Sopenharmony_cistruct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
197062306a36Sopenharmony_ci				   const char *attr_name, u64 *attr_size)
197162306a36Sopenharmony_ci{
197262306a36Sopenharmony_ci	int err;
197362306a36Sopenharmony_ci	struct p9_req_t *req;
197462306a36Sopenharmony_ci	struct p9_client *clnt;
197562306a36Sopenharmony_ci	struct p9_fid *attr_fid;
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	clnt = file_fid->clnt;
197862306a36Sopenharmony_ci	attr_fid = p9_fid_create(clnt);
197962306a36Sopenharmony_ci	if (!attr_fid) {
198062306a36Sopenharmony_ci		err = -ENOMEM;
198162306a36Sopenharmony_ci		goto error;
198262306a36Sopenharmony_ci	}
198362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
198462306a36Sopenharmony_ci		 ">>> TXATTRWALK file_fid %d, attr_fid %d name '%s'\n",
198562306a36Sopenharmony_ci		 file_fid->fid, attr_fid->fid, attr_name);
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
198862306a36Sopenharmony_ci			    file_fid->fid, attr_fid->fid, attr_name);
198962306a36Sopenharmony_ci	if (IS_ERR(req)) {
199062306a36Sopenharmony_ci		err = PTR_ERR(req);
199162306a36Sopenharmony_ci		goto error;
199262306a36Sopenharmony_ci	}
199362306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "q", attr_size);
199462306a36Sopenharmony_ci	if (err) {
199562306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
199662306a36Sopenharmony_ci		p9_req_put(clnt, req);
199762306a36Sopenharmony_ci		goto clunk_fid;
199862306a36Sopenharmony_ci	}
199962306a36Sopenharmony_ci	p9_req_put(clnt, req);
200062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<<  RXATTRWALK fid %d size %llu\n",
200162306a36Sopenharmony_ci		 attr_fid->fid, *attr_size);
200262306a36Sopenharmony_ci	return attr_fid;
200362306a36Sopenharmony_ciclunk_fid:
200462306a36Sopenharmony_ci	p9_fid_put(attr_fid);
200562306a36Sopenharmony_ci	attr_fid = NULL;
200662306a36Sopenharmony_cierror:
200762306a36Sopenharmony_ci	if (attr_fid && attr_fid != file_fid)
200862306a36Sopenharmony_ci		p9_fid_destroy(attr_fid);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	return ERR_PTR(err);
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(p9_client_xattrwalk);
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ciint p9_client_xattrcreate(struct p9_fid *fid, const char *name,
201562306a36Sopenharmony_ci			  u64 attr_size, int flags)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	int err = 0;
201862306a36Sopenharmony_ci	struct p9_req_t *req;
201962306a36Sopenharmony_ci	struct p9_client *clnt;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
202262306a36Sopenharmony_ci		 ">>> TXATTRCREATE fid %d name  %s size %llu flag %d\n",
202362306a36Sopenharmony_ci		 fid->fid, name, attr_size, flags);
202462306a36Sopenharmony_ci	clnt = fid->clnt;
202562306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
202662306a36Sopenharmony_ci			    fid->fid, name, attr_size, flags);
202762306a36Sopenharmony_ci	if (IS_ERR(req)) {
202862306a36Sopenharmony_ci		err = PTR_ERR(req);
202962306a36Sopenharmony_ci		goto error;
203062306a36Sopenharmony_ci	}
203162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
203262306a36Sopenharmony_ci	p9_req_put(clnt, req);
203362306a36Sopenharmony_cierror:
203462306a36Sopenharmony_ci	return err;
203562306a36Sopenharmony_ci}
203662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(p9_client_xattrcreate);
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ciint p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
203962306a36Sopenharmony_ci{
204062306a36Sopenharmony_ci	int err, rsize, non_zc = 0;
204162306a36Sopenharmony_ci	struct p9_client *clnt;
204262306a36Sopenharmony_ci	struct p9_req_t *req;
204362306a36Sopenharmony_ci	char *dataptr;
204462306a36Sopenharmony_ci	struct kvec kv = {.iov_base = data, .iov_len = count};
204562306a36Sopenharmony_ci	struct iov_iter to;
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci	iov_iter_kvec(&to, ITER_DEST, &kv, 1, count);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
205062306a36Sopenharmony_ci		 fid->fid, offset, count);
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	clnt = fid->clnt;
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_ci	rsize = fid->iounit;
205562306a36Sopenharmony_ci	if (!rsize || rsize > clnt->msize - P9_READDIRHDRSZ)
205662306a36Sopenharmony_ci		rsize = clnt->msize - P9_READDIRHDRSZ;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	if (count < rsize)
205962306a36Sopenharmony_ci		rsize = count;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci	/* Don't bother zerocopy for small IO (< 1024) */
206262306a36Sopenharmony_ci	if (clnt->trans_mod->zc_request && rsize > 1024) {
206362306a36Sopenharmony_ci		/* response header len is 11
206462306a36Sopenharmony_ci		 * PDU Header(7) + IO Size (4)
206562306a36Sopenharmony_ci		 */
206662306a36Sopenharmony_ci		req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0,
206762306a36Sopenharmony_ci				       11, "dqd", fid->fid, offset, rsize);
206862306a36Sopenharmony_ci	} else {
206962306a36Sopenharmony_ci		non_zc = 1;
207062306a36Sopenharmony_ci		req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid,
207162306a36Sopenharmony_ci				    offset, rsize);
207262306a36Sopenharmony_ci	}
207362306a36Sopenharmony_ci	if (IS_ERR(req)) {
207462306a36Sopenharmony_ci		err = PTR_ERR(req);
207562306a36Sopenharmony_ci		goto error;
207662306a36Sopenharmony_ci	}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "D", &count, &dataptr);
207962306a36Sopenharmony_ci	if (err) {
208062306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
208162306a36Sopenharmony_ci		goto free_and_error;
208262306a36Sopenharmony_ci	}
208362306a36Sopenharmony_ci	if (rsize < count) {
208462306a36Sopenharmony_ci		pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize);
208562306a36Sopenharmony_ci		count = rsize;
208662306a36Sopenharmony_ci	}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	if (non_zc)
209162306a36Sopenharmony_ci		memmove(data, dataptr, count);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	p9_req_put(clnt, req);
209462306a36Sopenharmony_ci	return count;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_cifree_and_error:
209762306a36Sopenharmony_ci	p9_req_put(clnt, req);
209862306a36Sopenharmony_cierror:
209962306a36Sopenharmony_ci	return err;
210062306a36Sopenharmony_ci}
210162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_readdir);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ciint p9_client_mknod_dotl(struct p9_fid *fid, const char *name, int mode,
210462306a36Sopenharmony_ci			 dev_t rdev, kgid_t gid, struct p9_qid *qid)
210562306a36Sopenharmony_ci{
210662306a36Sopenharmony_ci	int err;
210762306a36Sopenharmony_ci	struct p9_client *clnt;
210862306a36Sopenharmony_ci	struct p9_req_t *req;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	clnt = fid->clnt;
211162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
211262306a36Sopenharmony_ci		 ">>> TMKNOD fid %d name %s mode %d major %d minor %d\n",
211362306a36Sopenharmony_ci		 fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
211462306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddg", fid->fid, name, mode,
211562306a36Sopenharmony_ci			    MAJOR(rdev), MINOR(rdev), gid);
211662306a36Sopenharmony_ci	if (IS_ERR(req))
211762306a36Sopenharmony_ci		return PTR_ERR(req);
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
212062306a36Sopenharmony_ci	if (err) {
212162306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
212262306a36Sopenharmony_ci		goto error;
212362306a36Sopenharmony_ci	}
212462306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n",
212562306a36Sopenharmony_ci		 qid->type, qid->path, qid->version);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_cierror:
212862306a36Sopenharmony_ci	p9_req_put(clnt, req);
212962306a36Sopenharmony_ci	return err;
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_mknod_dotl);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ciint p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
213462306a36Sopenharmony_ci			 kgid_t gid, struct p9_qid *qid)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	int err;
213762306a36Sopenharmony_ci	struct p9_client *clnt;
213862306a36Sopenharmony_ci	struct p9_req_t *req;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	clnt = fid->clnt;
214162306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
214262306a36Sopenharmony_ci		 fid->fid, name, mode, from_kgid(&init_user_ns, gid));
214362306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TMKDIR, "dsdg",
214462306a36Sopenharmony_ci			    fid->fid, name, mode, gid);
214562306a36Sopenharmony_ci	if (IS_ERR(req))
214662306a36Sopenharmony_ci		return PTR_ERR(req);
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
214962306a36Sopenharmony_ci	if (err) {
215062306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
215162306a36Sopenharmony_ci		goto error;
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
215462306a36Sopenharmony_ci		 qid->path, qid->version);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_cierror:
215762306a36Sopenharmony_ci	p9_req_put(clnt, req);
215862306a36Sopenharmony_ci	return err;
215962306a36Sopenharmony_ci}
216062306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_mkdir_dotl);
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ciint p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
216362306a36Sopenharmony_ci{
216462306a36Sopenharmony_ci	int err;
216562306a36Sopenharmony_ci	struct p9_client *clnt;
216662306a36Sopenharmony_ci	struct p9_req_t *req;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	clnt = fid->clnt;
216962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
217062306a36Sopenharmony_ci		 ">>> TLOCK fid %d type %i flags %d start %lld length %lld proc_id %d client_id %s\n",
217162306a36Sopenharmony_ci		 fid->fid, flock->type, flock->flags, flock->start,
217262306a36Sopenharmony_ci		 flock->length, flock->proc_id, flock->client_id);
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
217562306a36Sopenharmony_ci			    flock->flags, flock->start, flock->length,
217662306a36Sopenharmony_ci			    flock->proc_id, flock->client_id);
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci	if (IS_ERR(req))
217962306a36Sopenharmony_ci		return PTR_ERR(req);
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "b", status);
218262306a36Sopenharmony_ci	if (err) {
218362306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
218462306a36Sopenharmony_ci		goto error;
218562306a36Sopenharmony_ci	}
218662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
218762306a36Sopenharmony_cierror:
218862306a36Sopenharmony_ci	p9_req_put(clnt, req);
218962306a36Sopenharmony_ci	return err;
219062306a36Sopenharmony_ci}
219162306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_lock_dotl);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ciint p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
219462306a36Sopenharmony_ci{
219562306a36Sopenharmony_ci	int err;
219662306a36Sopenharmony_ci	struct p9_client *clnt;
219762306a36Sopenharmony_ci	struct p9_req_t *req;
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	clnt = fid->clnt;
220062306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
220162306a36Sopenharmony_ci		 ">>> TGETLOCK fid %d, type %i start %lld length %lld proc_id %d client_id %s\n",
220262306a36Sopenharmony_ci		 fid->fid, glock->type, glock->start, glock->length,
220362306a36Sopenharmony_ci		 glock->proc_id, glock->client_id);
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid,
220662306a36Sopenharmony_ci			    glock->type, glock->start, glock->length,
220762306a36Sopenharmony_ci			    glock->proc_id, glock->client_id);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	if (IS_ERR(req))
221062306a36Sopenharmony_ci		return PTR_ERR(req);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "bqqds", &glock->type,
221362306a36Sopenharmony_ci			  &glock->start, &glock->length, &glock->proc_id,
221462306a36Sopenharmony_ci			  &glock->client_id);
221562306a36Sopenharmony_ci	if (err) {
221662306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
221762306a36Sopenharmony_ci		goto error;
221862306a36Sopenharmony_ci	}
221962306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P,
222062306a36Sopenharmony_ci		 "<<< RGETLOCK type %i start %lld length %lld proc_id %d client_id %s\n",
222162306a36Sopenharmony_ci		 glock->type, glock->start, glock->length,
222262306a36Sopenharmony_ci		 glock->proc_id, glock->client_id);
222362306a36Sopenharmony_cierror:
222462306a36Sopenharmony_ci	p9_req_put(clnt, req);
222562306a36Sopenharmony_ci	return err;
222662306a36Sopenharmony_ci}
222762306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_getlock_dotl);
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ciint p9_client_readlink(struct p9_fid *fid, char **target)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	int err;
223262306a36Sopenharmony_ci	struct p9_client *clnt;
223362306a36Sopenharmony_ci	struct p9_req_t *req;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	clnt = fid->clnt;
223662306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
223962306a36Sopenharmony_ci	if (IS_ERR(req))
224062306a36Sopenharmony_ci		return PTR_ERR(req);
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	err = p9pdu_readf(&req->rc, clnt->proto_version, "s", target);
224362306a36Sopenharmony_ci	if (err) {
224462306a36Sopenharmony_ci		trace_9p_protocol_dump(clnt, &req->rc);
224562306a36Sopenharmony_ci		goto error;
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci	p9_debug(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
224862306a36Sopenharmony_cierror:
224962306a36Sopenharmony_ci	p9_req_put(clnt, req);
225062306a36Sopenharmony_ci	return err;
225162306a36Sopenharmony_ci}
225262306a36Sopenharmony_ciEXPORT_SYMBOL(p9_client_readlink);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ciint __init p9_client_init(void)
225562306a36Sopenharmony_ci{
225662306a36Sopenharmony_ci	p9_req_cache = KMEM_CACHE(p9_req_t, SLAB_TYPESAFE_BY_RCU);
225762306a36Sopenharmony_ci	return p9_req_cache ? 0 : -ENOMEM;
225862306a36Sopenharmony_ci}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_civoid __exit p9_client_exit(void)
226162306a36Sopenharmony_ci{
226262306a36Sopenharmony_ci	kmem_cache_destroy(p9_req_cache);
226362306a36Sopenharmony_ci}
2264