11f327613SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bd238fb4SLatchesar Ionkov /*
3bd238fb4SLatchesar Ionkov * 9P Client
4bd238fb4SLatchesar Ionkov *
58a0dc95fSEric Van Hensbergen * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
6bd238fb4SLatchesar Ionkov * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7bd238fb4SLatchesar Ionkov */
8bd238fb4SLatchesar Ionkov
95d385153SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
105d385153SJoe Perches
11bd238fb4SLatchesar Ionkov #include <linux/module.h>
12bd238fb4SLatchesar Ionkov #include <linux/errno.h>
13bd238fb4SLatchesar Ionkov #include <linux/fs.h>
148a0dc95fSEric Van Hensbergen #include <linux/poll.h>
15bd238fb4SLatchesar Ionkov #include <linux/idr.h>
16bd238fb4SLatchesar Ionkov #include <linux/mutex.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
183f07c014SIngo Molnar #include <linux/sched/signal.h>
19bd238fb4SLatchesar Ionkov #include <linux/uaccess.h>
204f3b35c1SAl Viro #include <linux/uio.h>
21bd238fb4SLatchesar Ionkov #include <net/9p/9p.h>
22fb0466c3SEric Van Hensbergen #include <linux/parser.h>
23c4fac910SDavid Howells #include <linux/seq_file.h>
24bd238fb4SLatchesar Ionkov #include <net/9p/client.h>
258b81ef58SEric Van Hensbergen #include <net/9p/transport.h>
2651a87c55SEric Van Hensbergen #include "protocol.h"
27bd238fb4SLatchesar Ionkov
28348b5901SAneesh Kumar K.V #define CREATE_TRACE_POINTS
29348b5901SAneesh Kumar K.V #include <trace/events/9p.h>
30348b5901SAneesh Kumar K.V
312a034722SEric Van Hensbergen /* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ +
322a034722SEric Van Hensbergen * room for write (16 extra) or read (11 extra) operands.
332a034722SEric Van Hensbergen */
342a034722SEric Van Hensbergen
352a034722SEric Van Hensbergen #define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ)
369210fc0aSChristian Schoenebeck
376e195b0fSDominique Martinet /* Client Option Parsing (code inspired by NFS code)
388a0dc95fSEric Van Hensbergen * - a little lazy - parse all client options
398a0dc95fSEric Van Hensbergen */
408a0dc95fSEric Van Hensbergen
418a0dc95fSEric Van Hensbergen enum {
428a0dc95fSEric Van Hensbergen Opt_msize,
438a0dc95fSEric Van Hensbergen Opt_trans,
448a0dc95fSEric Van Hensbergen Opt_legacy,
450fb80abdSSripathi Kodi Opt_version,
468a0dc95fSEric Van Hensbergen Opt_err,
478a0dc95fSEric Van Hensbergen };
488a0dc95fSEric Van Hensbergen
49a447c093SSteven Whitehouse static const match_table_t tokens = {
508a0dc95fSEric Van Hensbergen {Opt_msize, "msize=%u"},
518a0dc95fSEric Van Hensbergen {Opt_legacy, "noextend"},
528a0dc95fSEric Van Hensbergen {Opt_trans, "trans=%s"},
530fb80abdSSripathi Kodi {Opt_version, "version=%s"},
548a0dc95fSEric Van Hensbergen {Opt_err, NULL},
558a0dc95fSEric Van Hensbergen };
568a0dc95fSEric Van Hensbergen
p9_is_proto_dotl(struct p9_client * clnt)57342fee1dSSripathi Kodi inline int p9_is_proto_dotl(struct p9_client *clnt)
58342fee1dSSripathi Kodi {
59a02cec21SEric Dumazet return clnt->proto_version == p9_proto_2000L;
60342fee1dSSripathi Kodi }
61342fee1dSSripathi Kodi EXPORT_SYMBOL(p9_is_proto_dotl);
62342fee1dSSripathi Kodi
p9_is_proto_dotu(struct p9_client * clnt)63342fee1dSSripathi Kodi inline int p9_is_proto_dotu(struct p9_client *clnt)
64342fee1dSSripathi Kodi {
65a02cec21SEric Dumazet return clnt->proto_version == p9_proto_2000u;
66342fee1dSSripathi Kodi }
67342fee1dSSripathi Kodi EXPORT_SYMBOL(p9_is_proto_dotu);
68342fee1dSSripathi Kodi
p9_show_client_options(struct seq_file * m,struct p9_client * clnt)69c4fac910SDavid Howells int p9_show_client_options(struct seq_file *m, struct p9_client *clnt)
70c4fac910SDavid Howells {
719210fc0aSChristian Schoenebeck if (clnt->msize != DEFAULT_MSIZE)
72c4fac910SDavid Howells seq_printf(m, ",msize=%u", clnt->msize);
7361b272c3STuomas Tynkkynen seq_printf(m, ",trans=%s", clnt->trans_mod->name);
74c4fac910SDavid Howells
75c4fac910SDavid Howells switch (clnt->proto_version) {
76c4fac910SDavid Howells case p9_proto_legacy:
77c4fac910SDavid Howells seq_puts(m, ",noextend");
78c4fac910SDavid Howells break;
79c4fac910SDavid Howells case p9_proto_2000u:
80c4fac910SDavid Howells seq_puts(m, ",version=9p2000.u");
81c4fac910SDavid Howells break;
82c4fac910SDavid Howells case p9_proto_2000L:
83c4fac910SDavid Howells /* Default */
84c4fac910SDavid Howells break;
85c4fac910SDavid Howells }
86c4fac910SDavid Howells
87c4fac910SDavid Howells if (clnt->trans_mod->show_options)
88c4fac910SDavid Howells return clnt->trans_mod->show_options(m, clnt);
89c4fac910SDavid Howells return 0;
90c4fac910SDavid Howells }
91c4fac910SDavid Howells EXPORT_SYMBOL(p9_show_client_options);
92c4fac910SDavid Howells
936e195b0fSDominique Martinet /* Some error codes are taken directly from the server replies,
9443def35cSSimon Derr * make sure they are valid.
9543def35cSSimon Derr */
safe_errno(int err)9643def35cSSimon Derr static int safe_errno(int err)
9743def35cSSimon Derr {
986e195b0fSDominique Martinet if (err > 0 || err < -MAX_ERRNO) {
9943def35cSSimon Derr p9_debug(P9_DEBUG_ERROR, "Invalid error code %d\n", err);
10043def35cSSimon Derr return -EPROTO;
10143def35cSSimon Derr }
10243def35cSSimon Derr return err;
10343def35cSSimon Derr }
10443def35cSSimon Derr
1050fb80abdSSripathi Kodi /* Interpret mount option for protocol version */
get_protocol_version(char * s)1064d63055fSPrem Karat static int get_protocol_version(char *s)
1070fb80abdSSripathi Kodi {
1083dc9fef6SDan Carpenter int version = -EINVAL;
1093dc9fef6SDan Carpenter
1104d63055fSPrem Karat if (!strcmp(s, "9p2000")) {
1110fb80abdSSripathi Kodi version = p9_proto_legacy;
1125d385153SJoe Perches p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n");
1134d63055fSPrem Karat } else if (!strcmp(s, "9p2000.u")) {
1140fb80abdSSripathi Kodi version = p9_proto_2000u;
1155d385153SJoe Perches p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
1164d63055fSPrem Karat } else if (!strcmp(s, "9p2000.L")) {
11745bc21edSSripathi Kodi version = p9_proto_2000L;
1185d385153SJoe Perches p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
1196e195b0fSDominique Martinet } else {
1205d385153SJoe Perches pr_info("Unknown protocol version %s\n", s);
1216e195b0fSDominique Martinet }
1224d63055fSPrem Karat
1230fb80abdSSripathi Kodi return version;
1240fb80abdSSripathi Kodi }
1250fb80abdSSripathi Kodi
1268a0dc95fSEric Van Hensbergen /**
12703ff7371SXiongfeng Wang * parse_opts - parse mount options into client structure
1280e15597eSAbhishek Kulkarni * @opts: options string passed from mount
1290e15597eSAbhishek Kulkarni * @clnt: existing v9fs client information
1308a0dc95fSEric Van Hensbergen *
131bb8ffdfcSEric Van Hensbergen * Return 0 upon success, -ERRNO upon failure
1328a0dc95fSEric Van Hensbergen */
1338a0dc95fSEric Van Hensbergen
parse_opts(char * opts,struct p9_client * clnt)134bb8ffdfcSEric Van Hensbergen static int parse_opts(char *opts, struct p9_client *clnt)
1358a0dc95fSEric Van Hensbergen {
136d8c8a9e3SEric Van Hensbergen char *options, *tmp_options;
1378a0dc95fSEric Van Hensbergen char *p;
1388a0dc95fSEric Van Hensbergen substring_t args[MAX_OPT_ARGS];
1398a0dc95fSEric Van Hensbergen int option;
1404d63055fSPrem Karat char *s;
141bb8ffdfcSEric Van Hensbergen int ret = 0;
1428a0dc95fSEric Van Hensbergen
143095e7999SAneesh Kumar K.V clnt->proto_version = p9_proto_2000L;
1449210fc0aSChristian Schoenebeck clnt->msize = DEFAULT_MSIZE;
1458a0dc95fSEric Van Hensbergen
146bb8ffdfcSEric Van Hensbergen if (!opts)
147bb8ffdfcSEric Van Hensbergen return 0;
148bb8ffdfcSEric Van Hensbergen
149d8c8a9e3SEric Van Hensbergen tmp_options = kstrdup(opts, GFP_KERNEL);
1506e195b0fSDominique Martinet if (!tmp_options)
151bb8ffdfcSEric Van Hensbergen return -ENOMEM;
152d8c8a9e3SEric Van Hensbergen options = tmp_options;
1538a0dc95fSEric Van Hensbergen
1548a0dc95fSEric Van Hensbergen while ((p = strsep(&options, ",")) != NULL) {
1554d5077f1SAneesh Kumar K.V int token, r;
1566e195b0fSDominique Martinet
1578a0dc95fSEric Van Hensbergen if (!*p)
1588a0dc95fSEric Van Hensbergen continue;
1598a0dc95fSEric Van Hensbergen token = match_token(p, tokens, args);
1604d5077f1SAneesh Kumar K.V switch (token) {
1614d5077f1SAneesh Kumar K.V case Opt_msize:
1624d5077f1SAneesh Kumar K.V r = match_int(&args[0], &option);
163bb8ffdfcSEric Van Hensbergen if (r < 0) {
1645d385153SJoe Perches p9_debug(P9_DEBUG_ERROR,
1658a0dc95fSEric Van Hensbergen "integer field, but no integer?\n");
166bb8ffdfcSEric Van Hensbergen ret = r;
1678a0dc95fSEric Van Hensbergen continue;
1688a0dc95fSEric Van Hensbergen }
169574d356bSDominique Martinet if (option < 4096) {
170574d356bSDominique Martinet p9_debug(P9_DEBUG_ERROR,
171574d356bSDominique Martinet "msize should be at least 4k\n");
172574d356bSDominique Martinet ret = -EINVAL;
173574d356bSDominique Martinet continue;
174574d356bSDominique Martinet }
1758a0dc95fSEric Van Hensbergen clnt->msize = option;
1768a0dc95fSEric Van Hensbergen break;
1778a0dc95fSEric Van Hensbergen case Opt_trans:
1784d63055fSPrem Karat s = match_strdup(&args[0]);
1794d63055fSPrem Karat if (!s) {
1804d63055fSPrem Karat ret = -ENOMEM;
1815d385153SJoe Perches p9_debug(P9_DEBUG_ERROR,
1824d63055fSPrem Karat "problem allocating copy of trans arg\n");
183349d3bb8SEric Van Hensbergen goto free_and_return;
184349d3bb8SEric Van Hensbergen }
1859421c3e6SChengguang Xu
1869421c3e6SChengguang Xu v9fs_put_trans(clnt->trans_mod);
1874d63055fSPrem Karat clnt->trans_mod = v9fs_get_trans_by_name(s);
1886e195b0fSDominique Martinet if (!clnt->trans_mod) {
1895d385153SJoe Perches pr_info("Could not find request transport: %s\n",
1905d385153SJoe Perches s);
1914d63055fSPrem Karat ret = -EINVAL;
1924d63055fSPrem Karat }
1934d63055fSPrem Karat kfree(s);
1948a0dc95fSEric Van Hensbergen break;
1958a0dc95fSEric Van Hensbergen case Opt_legacy:
196342fee1dSSripathi Kodi clnt->proto_version = p9_proto_legacy;
1978a0dc95fSEric Van Hensbergen break;
1980fb80abdSSripathi Kodi case Opt_version:
1994d63055fSPrem Karat s = match_strdup(&args[0]);
2004d63055fSPrem Karat if (!s) {
2014d63055fSPrem Karat ret = -ENOMEM;
2025d385153SJoe Perches p9_debug(P9_DEBUG_ERROR,
2034d63055fSPrem Karat "problem allocating copy of version arg\n");
2040fb80abdSSripathi Kodi goto free_and_return;
2054d63055fSPrem Karat }
2068d856c72SChengguang Xu r = get_protocol_version(s);
2078d856c72SChengguang Xu if (r < 0)
2088d856c72SChengguang Xu ret = r;
2098d856c72SChengguang Xu else
2108d856c72SChengguang Xu clnt->proto_version = r;
2114d63055fSPrem Karat kfree(s);
2120fb80abdSSripathi Kodi break;
2138a0dc95fSEric Van Hensbergen default:
2148a0dc95fSEric Van Hensbergen continue;
2158a0dc95fSEric Van Hensbergen }
2168a0dc95fSEric Van Hensbergen }
21772029fe8STejun Heo
218349d3bb8SEric Van Hensbergen free_and_return:
219c290fba8Spiaojun if (ret)
2209421c3e6SChengguang Xu v9fs_put_trans(clnt->trans_mod);
221d8c8a9e3SEric Van Hensbergen kfree(tmp_options);
222bb8ffdfcSEric Van Hensbergen return ret;
2238a0dc95fSEric Van Hensbergen }
2248a0dc95fSEric Van Hensbergen
p9_fcall_init(struct p9_client * c,struct p9_fcall * fc,int alloc_msize)22591a76be3SDominique Martinet static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
22691a76be3SDominique Martinet int alloc_msize)
2275387320dSSimon Derr {
22891a76be3SDominique Martinet if (likely(c->fcall_cache) && alloc_msize == c->msize) {
22991a76be3SDominique Martinet fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS);
23091a76be3SDominique Martinet fc->cache = c->fcall_cache;
23191a76be3SDominique Martinet } else {
232523adb6cSDominique Martinet fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
23391a76be3SDominique Martinet fc->cache = NULL;
23491a76be3SDominique Martinet }
235523adb6cSDominique Martinet if (!fc->sdata)
236523adb6cSDominique Martinet return -ENOMEM;
2375387320dSSimon Derr fc->capacity = alloc_msize;
2386c179113SNikita Zhandarovich fc->id = 0;
2396c179113SNikita Zhandarovich fc->tag = P9_NOTAG;
240523adb6cSDominique Martinet return 0;
2415387320dSSimon Derr }
2425387320dSSimon Derr
p9_fcall_fini(struct p9_fcall * fc)243523adb6cSDominique Martinet void p9_fcall_fini(struct p9_fcall *fc)
244523adb6cSDominique Martinet {
24591a76be3SDominique Martinet /* sdata can be NULL for interrupted requests in trans_rdma,
24691a76be3SDominique Martinet * and kmem_cache_free does not do NULL-check for us
24791a76be3SDominique Martinet */
24891a76be3SDominique Martinet if (unlikely(!fc->sdata))
24991a76be3SDominique Martinet return;
25091a76be3SDominique Martinet
25191a76be3SDominique Martinet if (fc->cache)
25291a76be3SDominique Martinet kmem_cache_free(fc->cache, fc->sdata);
25391a76be3SDominique Martinet else
254523adb6cSDominique Martinet kfree(fc->sdata);
255523adb6cSDominique Martinet }
256523adb6cSDominique Martinet EXPORT_SYMBOL(p9_fcall_fini);
257523adb6cSDominique Martinet
258996d5b4dSMatthew Wilcox static struct kmem_cache *p9_req_cache;
259996d5b4dSMatthew Wilcox
260fea511a6SEric Van Hensbergen /**
26103ff7371SXiongfeng Wang * p9_tag_alloc - Allocate a new request.
262996d5b4dSMatthew Wilcox * @c: Client session.
263996d5b4dSMatthew Wilcox * @type: Transaction type.
26460ece083SChristian Schoenebeck * @t_size: Buffer size for holding this request
26560ece083SChristian Schoenebeck * (automatic calculation by format template if 0).
26660ece083SChristian Schoenebeck * @r_size: Buffer size for holding server's reply on this request
26760ece083SChristian Schoenebeck * (automatic calculation by format template if 0).
26860ece083SChristian Schoenebeck * @fmt: Format template for assembling 9p request message
26960ece083SChristian Schoenebeck * (see p9pdu_vwritef).
27060ece083SChristian Schoenebeck * @ap: Variable arguments to be fed to passed format template
27160ece083SChristian Schoenebeck * (see p9pdu_vwritef).
272fea511a6SEric Van Hensbergen *
273996d5b4dSMatthew Wilcox * Context: Process context.
274996d5b4dSMatthew Wilcox * Return: Pointer to new request.
275fea511a6SEric Van Hensbergen */
276ef6b0807SDan Carpenter static struct p9_req_t *
p9_tag_alloc(struct p9_client * c,int8_t type,uint t_size,uint r_size,const char * fmt,va_list ap)27760ece083SChristian Schoenebeck p9_tag_alloc(struct p9_client *c, int8_t type, uint t_size, uint r_size,
27860ece083SChristian Schoenebeck const char *fmt, va_list ap)
279fea511a6SEric Van Hensbergen {
280996d5b4dSMatthew Wilcox struct p9_req_t *req = kmem_cache_alloc(p9_req_cache, GFP_NOFS);
28160ece083SChristian Schoenebeck int alloc_tsize;
28260ece083SChristian Schoenebeck int alloc_rsize;
283996d5b4dSMatthew Wilcox int tag;
28460ece083SChristian Schoenebeck va_list apc;
28560ece083SChristian Schoenebeck
28660ece083SChristian Schoenebeck va_copy(apc, ap);
28760ece083SChristian Schoenebeck alloc_tsize = min_t(size_t, c->msize,
28860ece083SChristian Schoenebeck t_size ?: p9_msg_buf_size(c, type, fmt, apc));
28960ece083SChristian Schoenebeck va_end(apc);
29060ece083SChristian Schoenebeck
29160ece083SChristian Schoenebeck alloc_rsize = min_t(size_t, c->msize,
29260ece083SChristian Schoenebeck r_size ?: p9_msg_buf_size(c, type + 1, fmt, ap));
293fea511a6SEric Van Hensbergen
294996d5b4dSMatthew Wilcox if (!req)
29572ea0321SDan Carpenter return ERR_PTR(-ENOMEM);
296fea511a6SEric Van Hensbergen
297e7c62197SChristian Schoenebeck if (p9_fcall_init(c, &req->tc, alloc_tsize))
298523adb6cSDominique Martinet goto free_req;
299e7c62197SChristian Schoenebeck if (p9_fcall_init(c, &req->rc, alloc_rsize))
300996d5b4dSMatthew Wilcox goto free;
301ea071aa1SSimon Derr
302523adb6cSDominique Martinet p9pdu_reset(&req->tc);
303523adb6cSDominique Martinet p9pdu_reset(&req->rc);
3040ce772feSLu Shuaibing req->t_err = 0;
30551a87c55SEric Van Hensbergen req->status = REQ_STATUS_ALLOC;
30626273adeSSchspa Shi /* refcount needs to be set to 0 before inserting into the idr
30726273adeSSchspa Shi * so p9_tag_lookup does not accept a request that is not fully
30826273adeSSchspa Shi * initialized. refcount_set to 2 below will mark request ready.
30926273adeSSchspa Shi */
31026273adeSSchspa Shi refcount_set(&req->refcount, 0);
311996d5b4dSMatthew Wilcox init_waitqueue_head(&req->wq);
312996d5b4dSMatthew Wilcox INIT_LIST_HEAD(&req->req_list);
313996d5b4dSMatthew Wilcox
314996d5b4dSMatthew Wilcox idr_preload(GFP_NOFS);
315996d5b4dSMatthew Wilcox spin_lock_irq(&c->lock);
316996d5b4dSMatthew Wilcox if (type == P9_TVERSION)
317996d5b4dSMatthew Wilcox tag = idr_alloc(&c->reqs, req, P9_NOTAG, P9_NOTAG + 1,
318996d5b4dSMatthew Wilcox GFP_NOWAIT);
319996d5b4dSMatthew Wilcox else
320996d5b4dSMatthew Wilcox tag = idr_alloc(&c->reqs, req, 0, P9_NOTAG, GFP_NOWAIT);
321523adb6cSDominique Martinet req->tc.tag = tag;
322996d5b4dSMatthew Wilcox spin_unlock_irq(&c->lock);
323996d5b4dSMatthew Wilcox idr_preload_end();
324996d5b4dSMatthew Wilcox if (tag < 0)
325996d5b4dSMatthew Wilcox goto free;
326fea511a6SEric Van Hensbergen
327728356deSTomas Bortoli /* Init ref to two because in the general case there is one ref
328728356deSTomas Bortoli * that is put asynchronously by a writer thread, one ref
329728356deSTomas Bortoli * temporarily given by p9_tag_lookup and put by p9_client_cb
33067dd8e44SDominique Martinet * in the recv thread, and one ref put by p9_req_put in the
331728356deSTomas Bortoli * main thread. The only exception is virtio that does not use
332728356deSTomas Bortoli * p9_tag_lookup but does not have a writer thread either
333728356deSTomas Bortoli * (the write happens synchronously in the request/zc_request
334728356deSTomas Bortoli * callback), so p9_client_cb eats the second ref there
335728356deSTomas Bortoli * as the pointer is duplicated directly by virtqueue_add_sgs()
336728356deSTomas Bortoli */
3376cda1286SKent Overstreet refcount_set(&req->refcount, 2);
338728356deSTomas Bortoli
339ea071aa1SSimon Derr return req;
340ea071aa1SSimon Derr
341996d5b4dSMatthew Wilcox free:
342523adb6cSDominique Martinet p9_fcall_fini(&req->tc);
343523adb6cSDominique Martinet p9_fcall_fini(&req->rc);
344523adb6cSDominique Martinet free_req:
345996d5b4dSMatthew Wilcox kmem_cache_free(p9_req_cache, req);
346ea071aa1SSimon Derr return ERR_PTR(-ENOMEM);
347fea511a6SEric Van Hensbergen }
348fea511a6SEric Van Hensbergen
349fea511a6SEric Van Hensbergen /**
350996d5b4dSMatthew Wilcox * p9_tag_lookup - Look up a request by tag.
351996d5b4dSMatthew Wilcox * @c: Client session.
352996d5b4dSMatthew Wilcox * @tag: Transaction ID.
353fea511a6SEric Van Hensbergen *
354996d5b4dSMatthew Wilcox * Context: Any context.
355996d5b4dSMatthew Wilcox * Return: A request, or %NULL if there is no request with that tag.
356fea511a6SEric Van Hensbergen */
p9_tag_lookup(struct p9_client * c,u16 tag)357fea511a6SEric Van Hensbergen struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
358fea511a6SEric Van Hensbergen {
359996d5b4dSMatthew Wilcox struct p9_req_t *req;
360fea511a6SEric Van Hensbergen
361996d5b4dSMatthew Wilcox rcu_read_lock();
362728356deSTomas Bortoli again:
363996d5b4dSMatthew Wilcox req = idr_find(&c->reqs, tag);
364728356deSTomas Bortoli if (req) {
365728356deSTomas Bortoli /* We have to be careful with the req found under rcu_read_lock
366728356deSTomas Bortoli * Thanks to SLAB_TYPESAFE_BY_RCU we can safely try to get the
367728356deSTomas Bortoli * ref again without corrupting other data, then check again
368728356deSTomas Bortoli * that the tag matches once we have the ref
369996d5b4dSMatthew Wilcox */
370728356deSTomas Bortoli if (!p9_req_try_get(req))
371728356deSTomas Bortoli goto again;
372728356deSTomas Bortoli if (req->tc.tag != tag) {
3738b11ff09SKent Overstreet p9_req_put(c, req);
374728356deSTomas Bortoli goto again;
375728356deSTomas Bortoli }
376728356deSTomas Bortoli }
377996d5b4dSMatthew Wilcox rcu_read_unlock();
378fea511a6SEric Van Hensbergen
379996d5b4dSMatthew Wilcox return req;
380fea511a6SEric Van Hensbergen }
381fea511a6SEric Van Hensbergen EXPORT_SYMBOL(p9_tag_lookup);
382fea511a6SEric Van Hensbergen
383fea511a6SEric Van Hensbergen /**
38443cbcbeeSTomas Bortoli * p9_tag_remove - Remove a tag.
385996d5b4dSMatthew Wilcox * @c: Client session.
38643cbcbeeSTomas Bortoli * @r: Request of reference.
387fea511a6SEric Van Hensbergen *
388996d5b4dSMatthew Wilcox * Context: Any context.
389fea511a6SEric Van Hensbergen */
p9_tag_remove(struct p9_client * c,struct p9_req_t * r)39067dd8e44SDominique Martinet static void p9_tag_remove(struct p9_client *c, struct p9_req_t *r)
391fea511a6SEric Van Hensbergen {
392996d5b4dSMatthew Wilcox unsigned long flags;
393523adb6cSDominique Martinet u16 tag = r->tc.tag;
394fea511a6SEric Van Hensbergen
39567dd8e44SDominique Martinet p9_debug(P9_DEBUG_MUX, "freeing clnt %p req %p tag: %d\n", c, r, tag);
396996d5b4dSMatthew Wilcox spin_lock_irqsave(&c->lock, flags);
397996d5b4dSMatthew Wilcox idr_remove(&c->reqs, tag);
398996d5b4dSMatthew Wilcox spin_unlock_irqrestore(&c->lock, flags);
399728356deSTomas Bortoli }
400728356deSTomas Bortoli
p9_req_put(struct p9_client * c,struct p9_req_t * r)4018b11ff09SKent Overstreet int p9_req_put(struct p9_client *c, struct p9_req_t *r)
402728356deSTomas Bortoli {
4036cda1286SKent Overstreet if (refcount_dec_and_test(&r->refcount)) {
40467dd8e44SDominique Martinet p9_tag_remove(c, r);
4056e195b0fSDominique Martinet
406523adb6cSDominique Martinet p9_fcall_fini(&r->tc);
407523adb6cSDominique Martinet p9_fcall_fini(&r->rc);
408996d5b4dSMatthew Wilcox kmem_cache_free(p9_req_cache, r);
4096cda1286SKent Overstreet return 1;
410fea511a6SEric Van Hensbergen }
4116cda1286SKent Overstreet return 0;
412728356deSTomas Bortoli }
413728356deSTomas Bortoli EXPORT_SYMBOL(p9_req_put);
414728356deSTomas Bortoli
415fea511a6SEric Van Hensbergen /**
416fea511a6SEric Van Hensbergen * p9_tag_cleanup - cleans up tags structure and reclaims resources
4170e15597eSAbhishek Kulkarni * @c: v9fs client struct
418fea511a6SEric Van Hensbergen *
419fea511a6SEric Van Hensbergen * This frees resources associated with the tags structure
420fea511a6SEric Van Hensbergen *
421fea511a6SEric Van Hensbergen */
p9_tag_cleanup(struct p9_client * c)422fea511a6SEric Van Hensbergen static void p9_tag_cleanup(struct p9_client *c)
423fea511a6SEric Van Hensbergen {
424996d5b4dSMatthew Wilcox struct p9_req_t *req;
425996d5b4dSMatthew Wilcox int id;
426fea511a6SEric Van Hensbergen
427996d5b4dSMatthew Wilcox rcu_read_lock();
428996d5b4dSMatthew Wilcox idr_for_each_entry(&c->reqs, req, id) {
429996d5b4dSMatthew Wilcox pr_info("Tag %d still in use\n", id);
43067dd8e44SDominique Martinet if (p9_req_put(c, req) == 0)
431728356deSTomas Bortoli pr_warn("Packet with tag %d has still references",
432728356deSTomas Bortoli req->tc.tag);
433fea511a6SEric Van Hensbergen }
434996d5b4dSMatthew Wilcox rcu_read_unlock();
435673d62cdSEric Van Hensbergen }
436673d62cdSEric Van Hensbergen
43791b8534fSEric Van Hensbergen /**
43891b8534fSEric Van Hensbergen * p9_client_cb - call back from transport to client
439760b3d61SAndrew Lunn * @c: client state
440760b3d61SAndrew Lunn * @req: request received
441760b3d61SAndrew Lunn * @status: request status, one of REQ_STATUS_*
44291b8534fSEric Van Hensbergen *
44391b8534fSEric Van Hensbergen */
p9_client_cb(struct p9_client * c,struct p9_req_t * req,int status)4442b6e72edSDominique Martinet void p9_client_cb(struct p9_client *c, struct p9_req_t *req, int status)
44591b8534fSEric Van Hensbergen {
446523adb6cSDominique Martinet p9_debug(P9_DEBUG_MUX, " tag %d\n", req->tc.tag);
4472b6e72edSDominique Martinet
4486e195b0fSDominique Martinet /* This barrier is needed to make sure any change made to req before
4492d58f63fSMatthew Wilcox * the status change is visible to another thread
4502b6e72edSDominique Martinet */
4512b6e72edSDominique Martinet smp_wmb();
4521a4f69efSDominique Martinet WRITE_ONCE(req->status, status);
4532b6e72edSDominique Martinet
4542557d0c5SMatthew Wilcox wake_up(&req->wq);
455523adb6cSDominique Martinet p9_debug(P9_DEBUG_MUX, "wakeup: %d\n", req->tc.tag);
4568b11ff09SKent Overstreet p9_req_put(c, req);
45791b8534fSEric Van Hensbergen }
45891b8534fSEric Van Hensbergen EXPORT_SYMBOL(p9_client_cb);
45991b8534fSEric Van Hensbergen
46091b8534fSEric Van Hensbergen /**
46151a87c55SEric Van Hensbergen * p9_parse_header - parse header arguments out of a packet
46251a87c55SEric Van Hensbergen * @pdu: packet to parse
46351a87c55SEric Van Hensbergen * @size: size of packet
46451a87c55SEric Van Hensbergen * @type: type of request
46551a87c55SEric Van Hensbergen * @tag: tag of packet
46651a87c55SEric Van Hensbergen * @rewind: set if we need to rewind offset afterwards
46791b8534fSEric Van Hensbergen */
46891b8534fSEric Van Hensbergen
46951a87c55SEric Van Hensbergen int
p9_parse_header(struct p9_fcall * pdu,int32_t * size,int8_t * type,int16_t * tag,int rewind)4706e195b0fSDominique Martinet p9_parse_header(struct p9_fcall *pdu, int32_t *size, int8_t *type,
4716e195b0fSDominique Martinet int16_t *tag, int rewind)
47291b8534fSEric Van Hensbergen {
4736e195b0fSDominique Martinet s8 r_type;
4746e195b0fSDominique Martinet s16 r_tag;
4756e195b0fSDominique Martinet s32 r_size;
47651a87c55SEric Van Hensbergen int offset = pdu->offset;
47751a87c55SEric Van Hensbergen int err;
47851a87c55SEric Van Hensbergen
47951a87c55SEric Van Hensbergen pdu->offset = 0;
48051a87c55SEric Van Hensbergen
48151a87c55SEric Van Hensbergen err = p9pdu_readf(pdu, 0, "dbw", &r_size, &r_type, &r_tag);
48251a87c55SEric Van Hensbergen if (err)
48351a87c55SEric Van Hensbergen goto rewind_and_exit;
48451a87c55SEric Van Hensbergen
48551a87c55SEric Van Hensbergen if (type)
48651a87c55SEric Van Hensbergen *type = r_type;
48751a87c55SEric Van Hensbergen if (tag)
48851a87c55SEric Van Hensbergen *tag = r_tag;
48951a87c55SEric Van Hensbergen if (size)
49051a87c55SEric Van Hensbergen *size = r_size;
49151a87c55SEric Van Hensbergen
492f984579aSTomas Bortoli if (pdu->size != r_size || r_size < 7) {
493f984579aSTomas Bortoli err = -EINVAL;
494f984579aSTomas Bortoli goto rewind_and_exit;
495f984579aSTomas Bortoli }
496f984579aSTomas Bortoli
497f984579aSTomas Bortoli pdu->id = r_type;
498f984579aSTomas Bortoli pdu->tag = r_tag;
499f984579aSTomas Bortoli
500f984579aSTomas Bortoli p9_debug(P9_DEBUG_9P, "<<< size=%d type: %d tag: %d\n",
501f984579aSTomas Bortoli pdu->size, pdu->id, pdu->tag);
50251a87c55SEric Van Hensbergen
50351a87c55SEric Van Hensbergen rewind_and_exit:
50451a87c55SEric Van Hensbergen if (rewind)
50551a87c55SEric Van Hensbergen pdu->offset = offset;
50651a87c55SEric Van Hensbergen return err;
50751a87c55SEric Van Hensbergen }
50851a87c55SEric Van Hensbergen EXPORT_SYMBOL(p9_parse_header);
50951a87c55SEric Van Hensbergen
51051a87c55SEric Van Hensbergen /**
51151a87c55SEric Van Hensbergen * p9_check_errors - check 9p packet for error return and process it
51251a87c55SEric Van Hensbergen * @c: current client instance
51351a87c55SEric Van Hensbergen * @req: request to parse and check for error conditions
51451a87c55SEric Van Hensbergen *
51551a87c55SEric Van Hensbergen * returns error code if one is discovered, otherwise returns 0
51651a87c55SEric Van Hensbergen *
51751a87c55SEric Van Hensbergen * this will have to be more complicated if we have multiple
51851a87c55SEric Van Hensbergen * error packet types
51951a87c55SEric Van Hensbergen */
52051a87c55SEric Van Hensbergen
p9_check_errors(struct p9_client * c,struct p9_req_t * req)52151a87c55SEric Van Hensbergen static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
52251a87c55SEric Van Hensbergen {
5236e195b0fSDominique Martinet s8 type;
52451a87c55SEric Van Hensbergen int err;
525ca41bb3eSVenkateswararao Jujjuri (JV) int ecode;
52651a87c55SEric Van Hensbergen
527523adb6cSDominique Martinet err = p9_parse_header(&req->rc, NULL, &type, NULL, 0);
528a31b3cffSChristian Schoenebeck if (req->rc.size > req->rc.capacity && !req->rc.zc) {
529a31b3cffSChristian Schoenebeck pr_err("requested packet size too big: %d does not fit %zu (type=%d)\n",
530a31b3cffSChristian Schoenebeck req->rc.size, req->rc.capacity, req->rc.id);
531f984579aSTomas Bortoli return -EIO;
532f984579aSTomas Bortoli }
5336e195b0fSDominique Martinet /* dump the response from server
534348b5901SAneesh Kumar K.V * This should be after check errors which poplulate pdu_fcall.
535348b5901SAneesh Kumar K.V */
536523adb6cSDominique Martinet trace_9p_protocol_dump(c, &req->rc);
53751a87c55SEric Van Hensbergen if (err) {
5385d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "couldn't parse header %d\n", err);
53951a87c55SEric Van Hensbergen return err;
54051a87c55SEric Van Hensbergen }
541ca41bb3eSVenkateswararao Jujjuri (JV) if (type != P9_RERROR && type != P9_RLERROR)
542ca41bb3eSVenkateswararao Jujjuri (JV) return 0;
5434f7ebe80SArun R Bharadwaj
5444f7ebe80SArun R Bharadwaj if (!p9_is_proto_dotl(c)) {
545b29b09d5SHangyu Hua char *ename = NULL;
5466e195b0fSDominique Martinet
547523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, c->proto_version, "s?d",
548342fee1dSSripathi Kodi &ename, &ecode);
549b29b09d5SHangyu Hua if (err) {
550b29b09d5SHangyu Hua kfree(ename);
5514f7ebe80SArun R Bharadwaj goto out_err;
552b29b09d5SHangyu Hua }
55351a87c55SEric Van Hensbergen
554287980e4SArnd Bergmann if (p9_is_proto_dotu(c) && ecode < 512)
55551a87c55SEric Van Hensbergen err = -ecode;
55651a87c55SEric Van Hensbergen
557287980e4SArnd Bergmann if (!err) {
55851a87c55SEric Van Hensbergen err = p9_errstr2errno(ename, strlen(ename));
55951a87c55SEric Van Hensbergen
5605d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RERROR (%d) %s\n",
561abfa034eSAneesh Kumar K.V -ecode, ename);
5624f7ebe80SArun R Bharadwaj }
563abfa034eSAneesh Kumar K.V kfree(ename);
5644f7ebe80SArun R Bharadwaj } else {
565523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, c->proto_version, "d", &ecode);
56627eb4c31SDominique Martinet if (err)
56727eb4c31SDominique Martinet goto out_err;
5684f7ebe80SArun R Bharadwaj err = -ecode;
5694f7ebe80SArun R Bharadwaj
5705d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
5714f7ebe80SArun R Bharadwaj }
5724f7ebe80SArun R Bharadwaj
57351a87c55SEric Van Hensbergen return err;
5744f7ebe80SArun R Bharadwaj
5754f7ebe80SArun R Bharadwaj out_err:
5765d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
5774f7ebe80SArun R Bharadwaj
5784f7ebe80SArun R Bharadwaj return err;
57951a87c55SEric Van Hensbergen }
58051a87c55SEric Van Hensbergen
581aca00763SRob Landley static struct p9_req_t *
582aca00763SRob Landley p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...);
583aca00763SRob Landley
58451a87c55SEric Van Hensbergen /**
58551a87c55SEric Van Hensbergen * p9_client_flush - flush (cancel) a request
5860e15597eSAbhishek Kulkarni * @c: client state
5870e15597eSAbhishek Kulkarni * @oldreq: request to cancel
58851a87c55SEric Van Hensbergen *
589aca00763SRob Landley * This sents a flush for a particular request and links
59051a87c55SEric Van Hensbergen * the flush request to the original request. The current
59151a87c55SEric Van Hensbergen * code only supports a single flush request although the protocol
59251a87c55SEric Van Hensbergen * allows for multiple flush requests to be sent for a single request.
59351a87c55SEric Van Hensbergen *
59451a87c55SEric Van Hensbergen */
59551a87c55SEric Van Hensbergen
p9_client_flush(struct p9_client * c,struct p9_req_t * oldreq)59651a87c55SEric Van Hensbergen static int p9_client_flush(struct p9_client *c, struct p9_req_t *oldreq)
59751a87c55SEric Van Hensbergen {
59851a87c55SEric Van Hensbergen struct p9_req_t *req;
5996e195b0fSDominique Martinet s16 oldtag;
60051a87c55SEric Van Hensbergen int err;
60151a87c55SEric Van Hensbergen
602523adb6cSDominique Martinet err = p9_parse_header(&oldreq->tc, NULL, NULL, &oldtag, 1);
60351a87c55SEric Van Hensbergen if (err)
60451a87c55SEric Van Hensbergen return err;
60551a87c55SEric Van Hensbergen
6065d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TFLUSH tag %d\n", oldtag);
60751a87c55SEric Van Hensbergen
60851a87c55SEric Van Hensbergen req = p9_client_rpc(c, P9_TFLUSH, "w", oldtag);
60951a87c55SEric Van Hensbergen if (IS_ERR(req))
61051a87c55SEric Van Hensbergen return PTR_ERR(req);
61151a87c55SEric Van Hensbergen
6126e195b0fSDominique Martinet /* if we haven't received a response for oldreq,
61360ff779cSAndi Shyti * remove it from the list
6141cff3306SSimon Derr */
6151a4f69efSDominique Martinet if (READ_ONCE(oldreq->status) == REQ_STATUS_SENT) {
616afd8d654SSimon Derr if (c->trans_mod->cancelled)
617afd8d654SSimon Derr c->trans_mod->cancelled(c, oldreq);
618728356deSTomas Bortoli }
6191bab88b2SLatchesar Ionkov
62067dd8e44SDominique Martinet p9_req_put(c, req);
62151a87c55SEric Van Hensbergen return 0;
62251a87c55SEric Van Hensbergen }
62351a87c55SEric Van Hensbergen
p9_client_prepare_req(struct p9_client * c,int8_t type,uint t_size,uint r_size,const char * fmt,va_list ap)624abfa034eSAneesh Kumar K.V static struct p9_req_t *p9_client_prepare_req(struct p9_client *c,
625e7c62197SChristian Schoenebeck int8_t type, uint t_size, uint r_size,
626abfa034eSAneesh Kumar K.V const char *fmt, va_list ap)
627abfa034eSAneesh Kumar K.V {
628996d5b4dSMatthew Wilcox int err;
629abfa034eSAneesh Kumar K.V struct p9_req_t *req;
63060ece083SChristian Schoenebeck va_list apc;
631abfa034eSAneesh Kumar K.V
6325d385153SJoe Perches p9_debug(P9_DEBUG_MUX, "client %p op %d\n", c, type);
633abfa034eSAneesh Kumar K.V
634abfa034eSAneesh Kumar K.V /* we allow for any status other than disconnected */
635abfa034eSAneesh Kumar K.V if (c->status == Disconnected)
636abfa034eSAneesh Kumar K.V return ERR_PTR(-EIO);
637abfa034eSAneesh Kumar K.V
638abfa034eSAneesh Kumar K.V /* if status is begin_disconnected we allow only clunk request */
6396e195b0fSDominique Martinet if (c->status == BeginDisconnect && type != P9_TCLUNK)
640abfa034eSAneesh Kumar K.V return ERR_PTR(-EIO);
641abfa034eSAneesh Kumar K.V
64260ece083SChristian Schoenebeck va_copy(apc, ap);
64360ece083SChristian Schoenebeck req = p9_tag_alloc(c, type, t_size, r_size, fmt, apc);
64460ece083SChristian Schoenebeck va_end(apc);
645abfa034eSAneesh Kumar K.V if (IS_ERR(req))
646abfa034eSAneesh Kumar K.V return req;
647abfa034eSAneesh Kumar K.V
648abfa034eSAneesh Kumar K.V /* marshall the data */
649523adb6cSDominique Martinet p9pdu_prepare(&req->tc, req->tc.tag, type);
650523adb6cSDominique Martinet err = p9pdu_vwritef(&req->tc, c->proto_version, fmt, ap);
651abfa034eSAneesh Kumar K.V if (err)
652abfa034eSAneesh Kumar K.V goto reterr;
653523adb6cSDominique Martinet p9pdu_finalize(c, &req->tc);
654523adb6cSDominique Martinet trace_9p_client_req(c, type, req->tc.tag);
655abfa034eSAneesh Kumar K.V return req;
656abfa034eSAneesh Kumar K.V reterr:
65767dd8e44SDominique Martinet p9_req_put(c, req);
658728356deSTomas Bortoli /* We have to put also the 2nd reference as it won't be used */
6598b11ff09SKent Overstreet p9_req_put(c, req);
660abfa034eSAneesh Kumar K.V return ERR_PTR(err);
661abfa034eSAneesh Kumar K.V }
662abfa034eSAneesh Kumar K.V
66351a87c55SEric Van Hensbergen /**
66451a87c55SEric Van Hensbergen * p9_client_rpc - issue a request and wait for a response
66551a87c55SEric Van Hensbergen * @c: client session
66651a87c55SEric Van Hensbergen * @type: type of request
66751a87c55SEric Van Hensbergen * @fmt: protocol format string (see protocol.c)
66851a87c55SEric Van Hensbergen *
66967dd8e44SDominique Martinet * Returns request structure (which client must free using p9_req_put)
67051a87c55SEric Van Hensbergen */
67151a87c55SEric Van Hensbergen
67251a87c55SEric Van Hensbergen static struct p9_req_t *
p9_client_rpc(struct p9_client * c,int8_t type,const char * fmt,...)67351a87c55SEric Van Hensbergen p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
67451a87c55SEric Van Hensbergen {
67551a87c55SEric Van Hensbergen va_list ap;
676abfa034eSAneesh Kumar K.V int sigpending, err;
67791b8534fSEric Van Hensbergen unsigned long flags;
678abfa034eSAneesh Kumar K.V struct p9_req_t *req;
67960ece083SChristian Schoenebeck /* Passing zero for tsize/rsize to p9_client_prepare_req() tells it to
68060ece083SChristian Schoenebeck * auto determine an appropriate (small) request/response size
68160ece083SChristian Schoenebeck * according to actual message data being sent. Currently RDMA
68260ece083SChristian Schoenebeck * transport is excluded from this response message size optimization,
68360ece083SChristian Schoenebeck * as it would not cope with it, due to its pooled response buffers
68460ece083SChristian Schoenebeck * (using an optimized request size for RDMA as well though).
68560ece083SChristian Schoenebeck */
68660ece083SChristian Schoenebeck const uint tsize = 0;
68760ece083SChristian Schoenebeck const uint rsize = c->trans_mod->pooled_rbuffers ? c->msize : 0;
68891b8534fSEric Van Hensbergen
689abfa034eSAneesh Kumar K.V va_start(ap, fmt);
69060ece083SChristian Schoenebeck req = p9_client_prepare_req(c, type, tsize, rsize, fmt, ap);
691abfa034eSAneesh Kumar K.V va_end(ap);
692abfa034eSAneesh Kumar K.V if (IS_ERR(req))
693abfa034eSAneesh Kumar K.V return req;
69491b8534fSEric Van Hensbergen
6958e4c2eeeSChristian Schoenebeck req->tc.zc = false;
6968e4c2eeeSChristian Schoenebeck req->rc.zc = false;
6978e4c2eeeSChristian Schoenebeck
69891b8534fSEric Van Hensbergen if (signal_pending(current)) {
69991b8534fSEric Van Hensbergen sigpending = 1;
70091b8534fSEric Van Hensbergen clear_thread_flag(TIF_SIGPENDING);
7016e195b0fSDominique Martinet } else {
70291b8534fSEric Van Hensbergen sigpending = 0;
7036e195b0fSDominique Martinet }
70491b8534fSEric Van Hensbergen
70591b8534fSEric Van Hensbergen err = c->trans_mod->request(c, req);
70691b8534fSEric Van Hensbergen if (err < 0) {
707728356deSTomas Bortoli /* write won't happen */
7088b11ff09SKent Overstreet p9_req_put(c, req);
7093cd79678SM. Mohan Kumar if (err != -ERESTARTSYS && err != -EFAULT)
71091b8534fSEric Van Hensbergen c->status = Disconnected;
711a8522243SGreg Kurz goto recalc_sigpending;
71291b8534fSEric Van Hensbergen }
713a314f274SJim Garlick again:
714abfa034eSAneesh Kumar K.V /* Wait for the response */
7151a4f69efSDominique Martinet err = wait_event_killable(req->wq,
7161a4f69efSDominique Martinet READ_ONCE(req->status) >= REQ_STATUS_RCVD);
71791b8534fSEric Van Hensbergen
7186e195b0fSDominique Martinet /* Make sure our req is coherent with regard to updates in other
7192b6e72edSDominique Martinet * threads - echoes to wmb() in the callback
7202b6e72edSDominique Martinet */
7212b6e72edSDominique Martinet smp_rmb();
7222b6e72edSDominique Martinet
7236e195b0fSDominique Martinet if (err == -ERESTARTSYS && c->status == Connected &&
7246e195b0fSDominique Martinet type == P9_TFLUSH) {
725a314f274SJim Garlick sigpending = 1;
726a314f274SJim Garlick clear_thread_flag(TIF_SIGPENDING);
727a314f274SJim Garlick goto again;
728a314f274SJim Garlick }
729a314f274SJim Garlick
7301a4f69efSDominique Martinet if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
7315d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
73291b8534fSEric Van Hensbergen err = req->t_err;
73391b8534fSEric Van Hensbergen }
7346e195b0fSDominique Martinet if (err == -ERESTARTSYS && c->status == Connected) {
7355d385153SJoe Perches p9_debug(P9_DEBUG_MUX, "flushing\n");
73691b8534fSEric Van Hensbergen sigpending = 1;
73791b8534fSEric Van Hensbergen clear_thread_flag(TIF_SIGPENDING);
73891b8534fSEric Van Hensbergen
7391bab88b2SLatchesar Ionkov if (c->trans_mod->cancel(c, req))
7401bab88b2SLatchesar Ionkov p9_client_flush(c, req);
7411bab88b2SLatchesar Ionkov
7421bab88b2SLatchesar Ionkov /* if we received the response anyway, don't signal error */
7431a4f69efSDominique Martinet if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
7441bab88b2SLatchesar Ionkov err = 0;
74591b8534fSEric Van Hensbergen }
746a8522243SGreg Kurz recalc_sigpending:
74791b8534fSEric Van Hensbergen if (sigpending) {
74891b8534fSEric Van Hensbergen spin_lock_irqsave(¤t->sighand->siglock, flags);
74991b8534fSEric Van Hensbergen recalc_sigpending();
75091b8534fSEric Van Hensbergen spin_unlock_irqrestore(¤t->sighand->siglock, flags);
75191b8534fSEric Van Hensbergen }
75291b8534fSEric Van Hensbergen if (err < 0)
75391b8534fSEric Van Hensbergen goto reterr;
75491b8534fSEric Van Hensbergen
75551a87c55SEric Van Hensbergen err = p9_check_errors(c, req);
756523adb6cSDominique Martinet trace_9p_client_res(c, type, req->rc.tag, err);
757348b5901SAneesh Kumar K.V if (!err)
75851a87c55SEric Van Hensbergen return req;
759abfa034eSAneesh Kumar K.V reterr:
76067dd8e44SDominique Martinet p9_req_put(c, req);
76143def35cSSimon Derr return ERR_PTR(safe_errno(err));
762abfa034eSAneesh Kumar K.V }
76391b8534fSEric Van Hensbergen
764abfa034eSAneesh Kumar K.V /**
765abfa034eSAneesh Kumar K.V * p9_client_zc_rpc - issue a request and wait for a response
766abfa034eSAneesh Kumar K.V * @c: client session
767abfa034eSAneesh Kumar K.V * @type: type of request
7684f3b35c1SAl Viro * @uidata: destination for zero copy read
7694f3b35c1SAl Viro * @uodata: source for zero copy write
770abfa034eSAneesh Kumar K.V * @inlen: read buffer size
771abfa034eSAneesh Kumar K.V * @olen: write buffer size
77215e522a7SAndrew Lunn * @in_hdrlen: reader header size, This is the size of response protocol data
773abfa034eSAneesh Kumar K.V * @fmt: protocol format string (see protocol.c)
774abfa034eSAneesh Kumar K.V *
77567dd8e44SDominique Martinet * Returns request structure (which client must free using p9_req_put)
776abfa034eSAneesh Kumar K.V */
p9_client_zc_rpc(struct p9_client * c,int8_t type,struct iov_iter * uidata,struct iov_iter * uodata,int inlen,int olen,int in_hdrlen,const char * fmt,...)777abfa034eSAneesh Kumar K.V static struct p9_req_t *p9_client_zc_rpc(struct p9_client *c, int8_t type,
7784f3b35c1SAl Viro struct iov_iter *uidata,
7794f3b35c1SAl Viro struct iov_iter *uodata,
780abfa034eSAneesh Kumar K.V int inlen, int olen, int in_hdrlen,
7814f3b35c1SAl Viro const char *fmt, ...)
782abfa034eSAneesh Kumar K.V {
783abfa034eSAneesh Kumar K.V va_list ap;
784abfa034eSAneesh Kumar K.V int sigpending, err;
785abfa034eSAneesh Kumar K.V unsigned long flags;
786abfa034eSAneesh Kumar K.V struct p9_req_t *req;
787abfa034eSAneesh Kumar K.V
788abfa034eSAneesh Kumar K.V va_start(ap, fmt);
7896e195b0fSDominique Martinet /* We allocate a inline protocol data of only 4k bytes.
790abfa034eSAneesh Kumar K.V * The actual content is passed in zero-copy fashion.
791abfa034eSAneesh Kumar K.V */
792e7c62197SChristian Schoenebeck req = p9_client_prepare_req(c, type, P9_ZC_HDR_SZ, P9_ZC_HDR_SZ, fmt, ap);
793abfa034eSAneesh Kumar K.V va_end(ap);
794abfa034eSAneesh Kumar K.V if (IS_ERR(req))
795abfa034eSAneesh Kumar K.V return req;
796abfa034eSAneesh Kumar K.V
7978e4c2eeeSChristian Schoenebeck req->tc.zc = true;
7988e4c2eeeSChristian Schoenebeck req->rc.zc = true;
7998e4c2eeeSChristian Schoenebeck
800abfa034eSAneesh Kumar K.V if (signal_pending(current)) {
801abfa034eSAneesh Kumar K.V sigpending = 1;
802abfa034eSAneesh Kumar K.V clear_thread_flag(TIF_SIGPENDING);
8036e195b0fSDominique Martinet } else {
804abfa034eSAneesh Kumar K.V sigpending = 0;
8056e195b0fSDominique Martinet }
806abfa034eSAneesh Kumar K.V
807abfa034eSAneesh Kumar K.V err = c->trans_mod->zc_request(c, req, uidata, uodata,
8084f3b35c1SAl Viro inlen, olen, in_hdrlen);
809abfa034eSAneesh Kumar K.V if (err < 0) {
810abfa034eSAneesh Kumar K.V if (err == -EIO)
811abfa034eSAneesh Kumar K.V c->status = Disconnected;
812a84b69cbSAl Viro if (err != -ERESTARTSYS)
813a8522243SGreg Kurz goto recalc_sigpending;
814abfa034eSAneesh Kumar K.V }
8151a4f69efSDominique Martinet if (READ_ONCE(req->status) == REQ_STATUS_ERROR) {
8165d385153SJoe Perches p9_debug(P9_DEBUG_ERROR, "req_status error %d\n", req->t_err);
817abfa034eSAneesh Kumar K.V err = req->t_err;
818abfa034eSAneesh Kumar K.V }
8196e195b0fSDominique Martinet if (err == -ERESTARTSYS && c->status == Connected) {
8205d385153SJoe Perches p9_debug(P9_DEBUG_MUX, "flushing\n");
821abfa034eSAneesh Kumar K.V sigpending = 1;
822abfa034eSAneesh Kumar K.V clear_thread_flag(TIF_SIGPENDING);
823abfa034eSAneesh Kumar K.V
824abfa034eSAneesh Kumar K.V if (c->trans_mod->cancel(c, req))
825abfa034eSAneesh Kumar K.V p9_client_flush(c, req);
826abfa034eSAneesh Kumar K.V
827abfa034eSAneesh Kumar K.V /* if we received the response anyway, don't signal error */
8281a4f69efSDominique Martinet if (READ_ONCE(req->status) == REQ_STATUS_RCVD)
829abfa034eSAneesh Kumar K.V err = 0;
830abfa034eSAneesh Kumar K.V }
831a8522243SGreg Kurz recalc_sigpending:
832abfa034eSAneesh Kumar K.V if (sigpending) {
833abfa034eSAneesh Kumar K.V spin_lock_irqsave(¤t->sighand->siglock, flags);
834abfa034eSAneesh Kumar K.V recalc_sigpending();
835abfa034eSAneesh Kumar K.V spin_unlock_irqrestore(¤t->sighand->siglock, flags);
836abfa034eSAneesh Kumar K.V }
837abfa034eSAneesh Kumar K.V if (err < 0)
838abfa034eSAneesh Kumar K.V goto reterr;
839abfa034eSAneesh Kumar K.V
840f615625aSAl Viro err = p9_check_errors(c, req);
841523adb6cSDominique Martinet trace_9p_client_res(c, type, req->rc.tag, err);
842348b5901SAneesh Kumar K.V if (!err)
843abfa034eSAneesh Kumar K.V return req;
84491b8534fSEric Van Hensbergen reterr:
84567dd8e44SDominique Martinet p9_req_put(c, req);
84643def35cSSimon Derr return ERR_PTR(safe_errno(err));
84791b8534fSEric Van Hensbergen }
84891b8534fSEric Van Hensbergen
p9_fid_create(struct p9_client * clnt)8495503ac56SEric Van Hensbergen static struct p9_fid *p9_fid_create(struct p9_client *clnt)
8505503ac56SEric Van Hensbergen {
8519f3e9bbeSRoel Kluin int ret;
8525503ac56SEric Van Hensbergen struct p9_fid *fid;
8535503ac56SEric Van Hensbergen
8545d385153SJoe Perches p9_debug(P9_DEBUG_FID, "clnt %p\n", clnt);
855aa7aeee1STyler Hicks fid = kzalloc(sizeof(*fid), GFP_KERNEL);
8565503ac56SEric Van Hensbergen if (!fid)
857b5303be2SMatthew Wilcox return NULL;
8585503ac56SEric Van Hensbergen
8595503ac56SEric Van Hensbergen fid->mode = -1;
860f8b9d53aSDavid Howells fid->uid = current_fsuid();
8615503ac56SEric Van Hensbergen fid->clnt = clnt;
862ff5e72ebSDominique Martinet refcount_set(&fid->count, 1);
8635503ac56SEric Van Hensbergen
864f28cdf04SMatthew Wilcox idr_preload(GFP_KERNEL);
865f28cdf04SMatthew Wilcox spin_lock_irq(&clnt->lock);
866f28cdf04SMatthew Wilcox ret = idr_alloc_u32(&clnt->fids, fid, &fid->fid, P9_NOFID - 1,
867f28cdf04SMatthew Wilcox GFP_NOWAIT);
868f28cdf04SMatthew Wilcox spin_unlock_irq(&clnt->lock);
869f28cdf04SMatthew Wilcox idr_preload_end();
870286c171bSDominique Martinet if (!ret) {
871286c171bSDominique Martinet trace_9p_fid_ref(fid, P9_FID_REF_CREATE);
8725503ac56SEric Van Hensbergen return fid;
873286c171bSDominique Martinet }
8745503ac56SEric Van Hensbergen
8755503ac56SEric Van Hensbergen kfree(fid);
876b5303be2SMatthew Wilcox return NULL;
8775503ac56SEric Van Hensbergen }
8785503ac56SEric Van Hensbergen
p9_fid_destroy(struct p9_fid * fid)8795503ac56SEric Van Hensbergen static void p9_fid_destroy(struct p9_fid *fid)
8805503ac56SEric Van Hensbergen {
8815503ac56SEric Van Hensbergen struct p9_client *clnt;
882cac23d65STom Tucker unsigned long flags;
8835503ac56SEric Van Hensbergen
8845d385153SJoe Perches p9_debug(P9_DEBUG_FID, "fid %d\n", fid->fid);
885286c171bSDominique Martinet trace_9p_fid_ref(fid, P9_FID_REF_DESTROY);
8865503ac56SEric Van Hensbergen clnt = fid->clnt;
887cac23d65STom Tucker spin_lock_irqsave(&clnt->lock, flags);
888f28cdf04SMatthew Wilcox idr_remove(&clnt->fids, fid->fid);
889cac23d65STom Tucker spin_unlock_irqrestore(&clnt->lock, flags);
8903e2796a9SEric Van Hensbergen kfree(fid->rdir);
8915503ac56SEric Van Hensbergen kfree(fid);
8925503ac56SEric Van Hensbergen }
8938a0dc95fSEric Van Hensbergen
894286c171bSDominique Martinet /* We also need to export tracepoint symbols for tracepoint_enabled() */
895286c171bSDominique Martinet EXPORT_TRACEPOINT_SYMBOL(9p_fid_ref);
896286c171bSDominique Martinet
do_trace_9p_fid_get(struct p9_fid * fid)897286c171bSDominique Martinet void do_trace_9p_fid_get(struct p9_fid *fid)
898286c171bSDominique Martinet {
899286c171bSDominique Martinet trace_9p_fid_ref(fid, P9_FID_REF_GET);
900286c171bSDominique Martinet }
901286c171bSDominique Martinet EXPORT_SYMBOL(do_trace_9p_fid_get);
902286c171bSDominique Martinet
do_trace_9p_fid_put(struct p9_fid * fid)903286c171bSDominique Martinet void do_trace_9p_fid_put(struct p9_fid *fid)
904286c171bSDominique Martinet {
905286c171bSDominique Martinet trace_9p_fid_ref(fid, P9_FID_REF_PUT);
906286c171bSDominique Martinet }
907286c171bSDominique Martinet EXPORT_SYMBOL(do_trace_9p_fid_put);
908286c171bSDominique Martinet
p9_client_version(struct p9_client * c)90932a875adSstephen hemminger static int p9_client_version(struct p9_client *c)
910bd238fb4SLatchesar Ionkov {
911cf7c33d3SDominique Martinet int err;
91251a87c55SEric Van Hensbergen struct p9_req_t *req;
9137913690dSTomas Bortoli char *version = NULL;
91451a87c55SEric Van Hensbergen int msize;
915bd238fb4SLatchesar Ionkov
9165d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TVERSION msize %d protocol %d\n",
917342fee1dSSripathi Kodi c->msize, c->proto_version);
918c5a7697dSSripathi Kodi
919c5a7697dSSripathi Kodi switch (c->proto_version) {
92045bc21edSSripathi Kodi case p9_proto_2000L:
921c5a7697dSSripathi Kodi req = p9_client_rpc(c, P9_TVERSION, "ds",
92245bc21edSSripathi Kodi c->msize, "9P2000.L");
923c5a7697dSSripathi Kodi break;
924c5a7697dSSripathi Kodi case p9_proto_2000u:
925c5a7697dSSripathi Kodi req = p9_client_rpc(c, P9_TVERSION, "ds",
926c5a7697dSSripathi Kodi c->msize, "9P2000.u");
927c5a7697dSSripathi Kodi break;
928c5a7697dSSripathi Kodi case p9_proto_legacy:
929c5a7697dSSripathi Kodi req = p9_client_rpc(c, P9_TVERSION, "ds",
930c5a7697dSSripathi Kodi c->msize, "9P2000");
931c5a7697dSSripathi Kodi break;
932c5a7697dSSripathi Kodi default:
933c5a7697dSSripathi Kodi return -EINVAL;
934c5a7697dSSripathi Kodi }
935c5a7697dSSripathi Kodi
93651a87c55SEric Van Hensbergen if (IS_ERR(req))
93751a87c55SEric Van Hensbergen return PTR_ERR(req);
9386936bf60SEric Van Hensbergen
939523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, c->proto_version, "ds", &msize, &version);
94051a87c55SEric Van Hensbergen if (err) {
9415d385153SJoe Perches p9_debug(P9_DEBUG_9P, "version error %d\n", err);
942523adb6cSDominique Martinet trace_9p_protocol_dump(c, &req->rc);
9436936bf60SEric Van Hensbergen goto error;
9446936bf60SEric Van Hensbergen }
9456936bf60SEric Van Hensbergen
9465d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RVERSION msize %d %s\n", msize, version);
9476e195b0fSDominique Martinet if (!strncmp(version, "9P2000.L", 8)) {
94845bc21edSSripathi Kodi c->proto_version = p9_proto_2000L;
9496e195b0fSDominique Martinet } else if (!strncmp(version, "9P2000.u", 8)) {
950342fee1dSSripathi Kodi c->proto_version = p9_proto_2000u;
9516e195b0fSDominique Martinet } else if (!strncmp(version, "9P2000", 6)) {
952342fee1dSSripathi Kodi c->proto_version = p9_proto_legacy;
9536e195b0fSDominique Martinet } else {
954574d356bSDominique Martinet p9_debug(P9_DEBUG_ERROR,
955574d356bSDominique Martinet "server returned an unknown version: %s\n", version);
9566936bf60SEric Van Hensbergen err = -EREMOTEIO;
9576936bf60SEric Van Hensbergen goto error;
9586936bf60SEric Van Hensbergen }
9596936bf60SEric Van Hensbergen
960574d356bSDominique Martinet if (msize < 4096) {
961574d356bSDominique Martinet p9_debug(P9_DEBUG_ERROR,
962574d356bSDominique Martinet "server returned a msize < 4096: %d\n", msize);
963574d356bSDominique Martinet err = -EREMOTEIO;
964574d356bSDominique Martinet goto error;
965574d356bSDominique Martinet }
96651a87c55SEric Van Hensbergen if (msize < c->msize)
96751a87c55SEric Van Hensbergen c->msize = msize;
9686936bf60SEric Van Hensbergen
9696936bf60SEric Van Hensbergen error:
97051a87c55SEric Van Hensbergen kfree(version);
97167dd8e44SDominique Martinet p9_req_put(c, req);
9726936bf60SEric Van Hensbergen
9736936bf60SEric Van Hensbergen return err;
9746936bf60SEric Van Hensbergen }
9756936bf60SEric Van Hensbergen
p9_client_create(const char * dev_name,char * options)9766936bf60SEric Van Hensbergen struct p9_client *p9_client_create(const char *dev_name, char *options)
9776936bf60SEric Van Hensbergen {
9786936bf60SEric Van Hensbergen int err;
979*9da3636aSLinus Torvalds static atomic_t seqno = ATOMIC_INIT(0);
9806936bf60SEric Van Hensbergen struct p9_client *clnt;
98150192abeSWill Deacon char *client_id;
9820d6c0b3bSPedro Falcato char *cache_name;
9836936bf60SEric Van Hensbergen
9846e195b0fSDominique Martinet clnt = kmalloc(sizeof(*clnt), GFP_KERNEL);
985bd238fb4SLatchesar Ionkov if (!clnt)
986bd238fb4SLatchesar Ionkov return ERR_PTR(-ENOMEM);
987bd238fb4SLatchesar Ionkov
98872029fe8STejun Heo clnt->trans_mod = NULL;
989bb8ffdfcSEric Van Hensbergen clnt->trans = NULL;
99091a76be3SDominique Martinet clnt->fcall_cache = NULL;
99150192abeSWill Deacon
99250192abeSWill Deacon client_id = utsname()->nodename;
99350192abeSWill Deacon memcpy(clnt->name, client_id, strlen(client_id) + 1);
99450192abeSWill Deacon
995bd238fb4SLatchesar Ionkov spin_lock_init(&clnt->lock);
996f28cdf04SMatthew Wilcox idr_init(&clnt->fids);
997996d5b4dSMatthew Wilcox idr_init(&clnt->reqs);
998fea511a6SEric Van Hensbergen
999bb8ffdfcSEric Van Hensbergen err = parse_opts(options, clnt);
1000bb8ffdfcSEric Van Hensbergen if (err < 0)
1001996d5b4dSMatthew Wilcox goto free_client;
1002bb8ffdfcSEric Van Hensbergen
1003a17d1720SAbhishek Kulkarni if (!clnt->trans_mod)
1004a17d1720SAbhishek Kulkarni clnt->trans_mod = v9fs_get_default_trans();
1005a17d1720SAbhishek Kulkarni
10066e195b0fSDominique Martinet if (!clnt->trans_mod) {
10078a0dc95fSEric Van Hensbergen err = -EPROTONOSUPPORT;
10085d385153SJoe Perches p9_debug(P9_DEBUG_ERROR,
10098a0dc95fSEric Van Hensbergen "No transport defined or default transport\n");
1010996d5b4dSMatthew Wilcox goto free_client;
10118781ff94SEric Van Hensbergen }
10128781ff94SEric Van Hensbergen
10135d385153SJoe Perches p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
1014342fee1dSSripathi Kodi clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
10158a0dc95fSEric Van Hensbergen
10168b81ef58SEric Van Hensbergen err = clnt->trans_mod->create(clnt, dev_name, options);
10178b81ef58SEric Van Hensbergen if (err)
1018f28cdf04SMatthew Wilcox goto put_trans;
10198a0dc95fSEric Van Hensbergen
102015e2721bSChristian Schoenebeck if (clnt->msize > clnt->trans_mod->maxsize) {
1021c9ffb05cSVenkateswararao Jujjuri (JV) clnt->msize = clnt->trans_mod->maxsize;
102215e2721bSChristian Schoenebeck pr_info("Limiting 'msize' to %d as this is the maximum "
102315e2721bSChristian Schoenebeck "supported by transport %s\n",
102415e2721bSChristian Schoenebeck clnt->msize, clnt->trans_mod->name
102515e2721bSChristian Schoenebeck );
102615e2721bSChristian Schoenebeck }
10278a0dc95fSEric Van Hensbergen
1028574d356bSDominique Martinet if (clnt->msize < 4096) {
1029574d356bSDominique Martinet p9_debug(P9_DEBUG_ERROR,
1030574d356bSDominique Martinet "Please specify a msize of at least 4k\n");
1031574d356bSDominique Martinet err = -EINVAL;
1032bb06c388Szhengbin goto close_trans;
1033574d356bSDominique Martinet }
1034574d356bSDominique Martinet
10356936bf60SEric Van Hensbergen err = p9_client_version(clnt);
1036bd238fb4SLatchesar Ionkov if (err)
10378781ff94SEric Van Hensbergen goto close_trans;
1038bd238fb4SLatchesar Ionkov
1039*9da3636aSLinus Torvalds cache_name = kasprintf(GFP_KERNEL,
1040*9da3636aSLinus Torvalds "9p-fcall-cache-%u", atomic_inc_return(&seqno));
10410d6c0b3bSPedro Falcato if (!cache_name) {
10420d6c0b3bSPedro Falcato err = -ENOMEM;
10430d6c0b3bSPedro Falcato goto close_trans;
10440d6c0b3bSPedro Falcato }
10450d6c0b3bSPedro Falcato
104691a76be3SDominique Martinet /* P9_HDRSZ + 4 is the smallest packet header we can have that is
104791a76be3SDominique Martinet * followed by data accessed from userspace by read
104891a76be3SDominique Martinet */
104991a76be3SDominique Martinet clnt->fcall_cache =
10500d6c0b3bSPedro Falcato kmem_cache_create_usercopy(cache_name, clnt->msize,
105191a76be3SDominique Martinet 0, 0, P9_HDRSZ + 4,
105291a76be3SDominique Martinet clnt->msize - (P9_HDRSZ + 4),
105391a76be3SDominique Martinet NULL);
105491a76be3SDominique Martinet
10550d6c0b3bSPedro Falcato kfree(cache_name);
1056bd238fb4SLatchesar Ionkov return clnt;
1057bd238fb4SLatchesar Ionkov
10588781ff94SEric Van Hensbergen close_trans:
10598781ff94SEric Van Hensbergen clnt->trans_mod->close(clnt);
10608781ff94SEric Van Hensbergen put_trans:
10618781ff94SEric Van Hensbergen v9fs_put_trans(clnt->trans_mod);
10628781ff94SEric Van Hensbergen free_client:
10638781ff94SEric Van Hensbergen kfree(clnt);
1064bd238fb4SLatchesar Ionkov return ERR_PTR(err);
1065bd238fb4SLatchesar Ionkov }
1066bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_create);
1067bd238fb4SLatchesar Ionkov
p9_client_destroy(struct p9_client * clnt)1068bd238fb4SLatchesar Ionkov void p9_client_destroy(struct p9_client *clnt)
1069bd238fb4SLatchesar Ionkov {
1070f28cdf04SMatthew Wilcox struct p9_fid *fid;
1071f28cdf04SMatthew Wilcox int id;
1072bd238fb4SLatchesar Ionkov
10735d385153SJoe Perches p9_debug(P9_DEBUG_MUX, "clnt %p\n", clnt);
1074bd238fb4SLatchesar Ionkov
10758b81ef58SEric Van Hensbergen if (clnt->trans_mod)
10768b81ef58SEric Van Hensbergen clnt->trans_mod->close(clnt);
1077bd238fb4SLatchesar Ionkov
107872029fe8STejun Heo v9fs_put_trans(clnt->trans_mod);
107972029fe8STejun Heo
1080f28cdf04SMatthew Wilcox idr_for_each_entry(&clnt->fids, fid, id) {
10815d385153SJoe Perches pr_info("Found fid %d not clunked\n", fid->fid);
1082bd238fb4SLatchesar Ionkov p9_fid_destroy(fid);
10836d96d3abSAneesh Kumar K.V }
1084bd238fb4SLatchesar Ionkov
1085fea511a6SEric Van Hensbergen p9_tag_cleanup(clnt);
1086fea511a6SEric Van Hensbergen
108791a76be3SDominique Martinet kmem_cache_destroy(clnt->fcall_cache);
1088bd238fb4SLatchesar Ionkov kfree(clnt);
1089bd238fb4SLatchesar Ionkov }
1090bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_destroy);
1091bd238fb4SLatchesar Ionkov
p9_client_disconnect(struct p9_client * clnt)1092bd238fb4SLatchesar Ionkov void p9_client_disconnect(struct p9_client *clnt)
1093bd238fb4SLatchesar Ionkov {
10945d385153SJoe Perches p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
10958b81ef58SEric Van Hensbergen clnt->status = Disconnected;
1096bd238fb4SLatchesar Ionkov }
1097bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_disconnect);
1098bd238fb4SLatchesar Ionkov
p9_client_begin_disconnect(struct p9_client * clnt)10996d96d3abSAneesh Kumar K.V void p9_client_begin_disconnect(struct p9_client *clnt)
11006d96d3abSAneesh Kumar K.V {
11015d385153SJoe Perches p9_debug(P9_DEBUG_9P, "clnt %p\n", clnt);
11026d96d3abSAneesh Kumar K.V clnt->status = BeginDisconnect;
11036d96d3abSAneesh Kumar K.V }
11046d96d3abSAneesh Kumar K.V EXPORT_SYMBOL(p9_client_begin_disconnect);
11056d96d3abSAneesh Kumar K.V
p9_client_attach(struct p9_client * clnt,struct p9_fid * afid,const char * uname,kuid_t n_uname,const char * aname)1106bd238fb4SLatchesar Ionkov struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
11076e195b0fSDominique Martinet const char *uname, kuid_t n_uname,
11086e195b0fSDominique Martinet const char *aname)
1109bd238fb4SLatchesar Ionkov {
1110cf7c33d3SDominique Martinet int err;
111151a87c55SEric Van Hensbergen struct p9_req_t *req;
1112bd238fb4SLatchesar Ionkov struct p9_fid *fid;
111351a87c55SEric Van Hensbergen struct p9_qid qid;
1114bd238fb4SLatchesar Ionkov
11155d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TATTACH afid %d uname %s aname %s\n",
111651a87c55SEric Van Hensbergen afid ? afid->fid : -1, uname, aname);
1117bd238fb4SLatchesar Ionkov fid = p9_fid_create(clnt);
1118b5303be2SMatthew Wilcox if (!fid) {
1119b5303be2SMatthew Wilcox err = -ENOMEM;
1120bd238fb4SLatchesar Ionkov goto error;
1121bd238fb4SLatchesar Ionkov }
112221c9f5ccSAl Viro fid->uid = n_uname;
1123bd238fb4SLatchesar Ionkov
1124f791f7c5SEric W. Biederman req = p9_client_rpc(clnt, P9_TATTACH, "ddss?u", fid->fid,
112551a87c55SEric Van Hensbergen afid ? afid->fid : P9_NOFID, uname, aname, n_uname);
112651a87c55SEric Van Hensbergen if (IS_ERR(req)) {
112751a87c55SEric Van Hensbergen err = PTR_ERR(req);
1128bd238fb4SLatchesar Ionkov goto error;
1129bd238fb4SLatchesar Ionkov }
1130bd238fb4SLatchesar Ionkov
1131523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", &qid);
113251a87c55SEric Van Hensbergen if (err) {
1133523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
113467dd8e44SDominique Martinet p9_req_put(clnt, req);
1135bd238fb4SLatchesar Ionkov goto error;
113651a87c55SEric Van Hensbergen }
1137bd238fb4SLatchesar Ionkov
11385d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RATTACH qid %x.%llx.%x\n",
11396e195b0fSDominique Martinet qid.type, qid.path, qid.version);
114051a87c55SEric Van Hensbergen
114151a87c55SEric Van Hensbergen memmove(&fid->qid, &qid, sizeof(struct p9_qid));
114251a87c55SEric Van Hensbergen
114367dd8e44SDominique Martinet p9_req_put(clnt, req);
1144bd238fb4SLatchesar Ionkov return fid;
1145bd238fb4SLatchesar Ionkov
1146bd238fb4SLatchesar Ionkov error:
1147bd238fb4SLatchesar Ionkov if (fid)
1148bd238fb4SLatchesar Ionkov p9_fid_destroy(fid);
1149bd238fb4SLatchesar Ionkov return ERR_PTR(err);
1150bd238fb4SLatchesar Ionkov }
1151bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_attach);
1152bd238fb4SLatchesar Ionkov
p9_client_walk(struct p9_fid * oldfid,uint16_t nwname,const unsigned char * const * wnames,int clone)1153b76225e2SHarsh Prateek Bora struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname,
11547880b43bSAl Viro const unsigned char * const *wnames, int clone)
1155bd238fb4SLatchesar Ionkov {
1156bd238fb4SLatchesar Ionkov int err;
1157bd238fb4SLatchesar Ionkov struct p9_client *clnt;
1158bd238fb4SLatchesar Ionkov struct p9_fid *fid;
115951a87c55SEric Van Hensbergen struct p9_qid *wqids;
116051a87c55SEric Van Hensbergen struct p9_req_t *req;
11616e195b0fSDominique Martinet u16 nwqids, count;
1162bd238fb4SLatchesar Ionkov
116362b2be59SLatchesar Ionkov wqids = NULL;
1164bd238fb4SLatchesar Ionkov clnt = oldfid->clnt;
1165bd238fb4SLatchesar Ionkov if (clone) {
1166bd238fb4SLatchesar Ionkov fid = p9_fid_create(clnt);
1167b5303be2SMatthew Wilcox if (!fid) {
1168b5303be2SMatthew Wilcox err = -ENOMEM;
1169bd238fb4SLatchesar Ionkov goto error;
1170bd238fb4SLatchesar Ionkov }
1171bd238fb4SLatchesar Ionkov
1172bd238fb4SLatchesar Ionkov fid->uid = oldfid->uid;
11736e195b0fSDominique Martinet } else {
1174bd238fb4SLatchesar Ionkov fid = oldfid;
11756e195b0fSDominique Martinet }
117651a87c55SEric Van Hensbergen
11775d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n",
117851a87c55SEric Van Hensbergen oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
117951a87c55SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid,
118051a87c55SEric Van Hensbergen nwname, wnames);
118151a87c55SEric Van Hensbergen if (IS_ERR(req)) {
118251a87c55SEric Van Hensbergen err = PTR_ERR(req);
1183bd238fb4SLatchesar Ionkov goto error;
1184bd238fb4SLatchesar Ionkov }
1185bd238fb4SLatchesar Ionkov
1186523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "R", &nwqids, &wqids);
1187e7f4b8f1SEric Van Hensbergen if (err) {
1188523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
118967dd8e44SDominique Martinet p9_req_put(clnt, req);
1190bd238fb4SLatchesar Ionkov goto clunk_fid;
1191e7f4b8f1SEric Van Hensbergen }
119267dd8e44SDominique Martinet p9_req_put(clnt, req);
1193bd238fb4SLatchesar Ionkov
11945d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RWALK nwqid %d:\n", nwqids);
119551a87c55SEric Van Hensbergen
119651a87c55SEric Van Hensbergen if (nwqids != nwname) {
1197bd238fb4SLatchesar Ionkov err = -ENOENT;
1198bd238fb4SLatchesar Ionkov goto clunk_fid;
1199bd238fb4SLatchesar Ionkov }
1200bd238fb4SLatchesar Ionkov
120151a87c55SEric Van Hensbergen for (count = 0; count < nwqids; count++)
12025d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< [%d] %x.%llx.%x\n",
1203b0d5fdefSRandy Dunlap count, wqids[count].type,
12046e195b0fSDominique Martinet wqids[count].path,
120551a87c55SEric Van Hensbergen wqids[count].version);
120651a87c55SEric Van Hensbergen
1207bd238fb4SLatchesar Ionkov if (nwname)
120851a87c55SEric Van Hensbergen memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
1209bd238fb4SLatchesar Ionkov else
1210154372e6SEric Van Hensbergen memmove(&fid->qid, &oldfid->qid, sizeof(struct p9_qid));
1211bd238fb4SLatchesar Ionkov
121262b2be59SLatchesar Ionkov kfree(wqids);
1213bd238fb4SLatchesar Ionkov return fid;
1214bd238fb4SLatchesar Ionkov
1215bd238fb4SLatchesar Ionkov clunk_fid:
121662b2be59SLatchesar Ionkov kfree(wqids);
1217b48dbb99SDominique Martinet p9_fid_put(fid);
121851a87c55SEric Van Hensbergen fid = NULL;
1219bd238fb4SLatchesar Ionkov
1220bd238fb4SLatchesar Ionkov error:
12216e195b0fSDominique Martinet if (fid && fid != oldfid)
1222bd238fb4SLatchesar Ionkov p9_fid_destroy(fid);
1223bd238fb4SLatchesar Ionkov
1224bd238fb4SLatchesar Ionkov return ERR_PTR(err);
1225bd238fb4SLatchesar Ionkov }
1226bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_walk);
1227bd238fb4SLatchesar Ionkov
p9_client_open(struct p9_fid * fid,int mode)1228bd238fb4SLatchesar Ionkov int p9_client_open(struct p9_fid *fid, int mode)
1229bd238fb4SLatchesar Ionkov {
1230bd238fb4SLatchesar Ionkov int err;
1231bd238fb4SLatchesar Ionkov struct p9_client *clnt;
123251a87c55SEric Van Hensbergen struct p9_req_t *req;
123351a87c55SEric Van Hensbergen struct p9_qid qid;
123451a87c55SEric Van Hensbergen int iounit;
1235bd238fb4SLatchesar Ionkov
1236bd238fb4SLatchesar Ionkov clnt = fid->clnt;
12375d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> %s fid %d mode %d\n",
1238ef56547eSM. Mohan Kumar p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN", fid->fid, mode);
1239bd238fb4SLatchesar Ionkov
1240bd238fb4SLatchesar Ionkov if (fid->mode != -1)
1241bd238fb4SLatchesar Ionkov return -EINVAL;
1242bd238fb4SLatchesar Ionkov
1243ef56547eSM. Mohan Kumar if (p9_is_proto_dotl(clnt))
124446c30cb8SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TLOPEN, "dd", fid->fid, mode & P9L_MODE_MASK);
1245ef56547eSM. Mohan Kumar else
124646c30cb8SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TOPEN, "db", fid->fid, mode & P9L_MODE_MASK);
124751a87c55SEric Van Hensbergen if (IS_ERR(req)) {
124851a87c55SEric Van Hensbergen err = PTR_ERR(req);
124951a87c55SEric Van Hensbergen goto error;
1250bd238fb4SLatchesar Ionkov }
1251bd238fb4SLatchesar Ionkov
1252523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1253e7f4b8f1SEric Van Hensbergen if (err) {
1254523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
1255e7f4b8f1SEric Van Hensbergen goto free_and_error;
1256e7f4b8f1SEric Van Hensbergen }
125751a87c55SEric Van Hensbergen
12585d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< %s qid %x.%llx.%x iounit %x\n",
1259ef56547eSM. Mohan Kumar p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN", qid.type,
12606e195b0fSDominique Martinet qid.path, qid.version, iounit);
1261bd238fb4SLatchesar Ionkov
1262154372e6SEric Van Hensbergen memmove(&fid->qid, &qid, sizeof(struct p9_qid));
1263bd238fb4SLatchesar Ionkov fid->mode = mode;
126451a87c55SEric Van Hensbergen fid->iounit = iounit;
1265bd238fb4SLatchesar Ionkov
1266e7f4b8f1SEric Van Hensbergen free_and_error:
126767dd8e44SDominique Martinet p9_req_put(clnt, req);
126851a87c55SEric Van Hensbergen error:
1269bd238fb4SLatchesar Ionkov return err;
1270bd238fb4SLatchesar Ionkov }
1271bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_open);
1272bd238fb4SLatchesar Ionkov
p9_client_create_dotl(struct p9_fid * ofid,const char * name,u32 flags,u32 mode,kgid_t gid,struct p9_qid * qid)12736e195b0fSDominique Martinet int p9_client_create_dotl(struct p9_fid *ofid, const char *name, u32 flags,
12746e195b0fSDominique Martinet u32 mode, kgid_t gid, struct p9_qid *qid)
12755643135aSVenkateswararao Jujjuri (JV) {
1276cf7c33d3SDominique Martinet int err;
12775643135aSVenkateswararao Jujjuri (JV) struct p9_client *clnt;
12785643135aSVenkateswararao Jujjuri (JV) struct p9_req_t *req;
12795643135aSVenkateswararao Jujjuri (JV) int iounit;
12805643135aSVenkateswararao Jujjuri (JV)
12815d385153SJoe Perches p9_debug(P9_DEBUG_9P,
12825643135aSVenkateswararao Jujjuri (JV) ">>> TLCREATE fid %d name %s flags %d mode %d gid %d\n",
1283f791f7c5SEric W. Biederman ofid->fid, name, flags, mode,
1284f791f7c5SEric W. Biederman from_kgid(&init_user_ns, gid));
12855643135aSVenkateswararao Jujjuri (JV) clnt = ofid->clnt;
12865643135aSVenkateswararao Jujjuri (JV)
12875643135aSVenkateswararao Jujjuri (JV) if (ofid->mode != -1)
12885643135aSVenkateswararao Jujjuri (JV) return -EINVAL;
12895643135aSVenkateswararao Jujjuri (JV)
1290f791f7c5SEric W. Biederman req = p9_client_rpc(clnt, P9_TLCREATE, "dsddg", ofid->fid, name, flags,
129146c30cb8SEric Van Hensbergen mode & P9L_MODE_MASK, gid);
12925643135aSVenkateswararao Jujjuri (JV) if (IS_ERR(req)) {
12935643135aSVenkateswararao Jujjuri (JV) err = PTR_ERR(req);
12945643135aSVenkateswararao Jujjuri (JV) goto error;
12955643135aSVenkateswararao Jujjuri (JV) }
12965643135aSVenkateswararao Jujjuri (JV)
1297523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", qid, &iounit);
12985643135aSVenkateswararao Jujjuri (JV) if (err) {
1299523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
13005643135aSVenkateswararao Jujjuri (JV) goto free_and_error;
13015643135aSVenkateswararao Jujjuri (JV) }
13025643135aSVenkateswararao Jujjuri (JV)
13035d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RLCREATE qid %x.%llx.%x iounit %x\n",
13046e195b0fSDominique Martinet qid->type, qid->path, qid->version, iounit);
13055643135aSVenkateswararao Jujjuri (JV)
1306154372e6SEric Van Hensbergen memmove(&ofid->qid, qid, sizeof(struct p9_qid));
13073866584aSEric Van Hensbergen ofid->mode = flags;
13085643135aSVenkateswararao Jujjuri (JV) ofid->iounit = iounit;
13095643135aSVenkateswararao Jujjuri (JV)
13105643135aSVenkateswararao Jujjuri (JV) free_and_error:
131167dd8e44SDominique Martinet p9_req_put(clnt, req);
13125643135aSVenkateswararao Jujjuri (JV) error:
13135643135aSVenkateswararao Jujjuri (JV) return err;
13145643135aSVenkateswararao Jujjuri (JV) }
13155643135aSVenkateswararao Jujjuri (JV) EXPORT_SYMBOL(p9_client_create_dotl);
13165643135aSVenkateswararao Jujjuri (JV)
p9_client_fcreate(struct p9_fid * fid,const char * name,u32 perm,int mode,char * extension)13177880b43bSAl Viro int p9_client_fcreate(struct p9_fid *fid, const char *name, u32 perm, int mode,
1318bd238fb4SLatchesar Ionkov char *extension)
1319bd238fb4SLatchesar Ionkov {
1320bd238fb4SLatchesar Ionkov int err;
1321bd238fb4SLatchesar Ionkov struct p9_client *clnt;
132251a87c55SEric Van Hensbergen struct p9_req_t *req;
132351a87c55SEric Van Hensbergen struct p9_qid qid;
132451a87c55SEric Van Hensbergen int iounit;
1325bd238fb4SLatchesar Ionkov
13265d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TCREATE fid %d name %s perm %d mode %d\n",
132751a87c55SEric Van Hensbergen fid->fid, name, perm, mode);
1328bd238fb4SLatchesar Ionkov clnt = fid->clnt;
1329bd238fb4SLatchesar Ionkov
1330bd238fb4SLatchesar Ionkov if (fid->mode != -1)
1331bd238fb4SLatchesar Ionkov return -EINVAL;
1332bd238fb4SLatchesar Ionkov
133351a87c55SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TCREATE, "dsdb?s", fid->fid, name, perm,
133446c30cb8SEric Van Hensbergen mode & P9L_MODE_MASK, extension);
133551a87c55SEric Van Hensbergen if (IS_ERR(req)) {
133651a87c55SEric Van Hensbergen err = PTR_ERR(req);
133751a87c55SEric Van Hensbergen goto error;
1338bd238fb4SLatchesar Ionkov }
1339bd238fb4SLatchesar Ionkov
1340523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Qd", &qid, &iounit);
1341e7f4b8f1SEric Van Hensbergen if (err) {
1342523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
1343e7f4b8f1SEric Van Hensbergen goto free_and_error;
1344e7f4b8f1SEric Van Hensbergen }
134551a87c55SEric Van Hensbergen
13465d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RCREATE qid %x.%llx.%x iounit %x\n",
13476e195b0fSDominique Martinet qid.type, qid.path, qid.version, iounit);
1348bd238fb4SLatchesar Ionkov
1349154372e6SEric Van Hensbergen memmove(&fid->qid, &qid, sizeof(struct p9_qid));
1350bd238fb4SLatchesar Ionkov fid->mode = mode;
135151a87c55SEric Van Hensbergen fid->iounit = iounit;
1352bd238fb4SLatchesar Ionkov
1353e7f4b8f1SEric Van Hensbergen free_and_error:
135467dd8e44SDominique Martinet p9_req_put(clnt, req);
135551a87c55SEric Van Hensbergen error:
1356bd238fb4SLatchesar Ionkov return err;
1357bd238fb4SLatchesar Ionkov }
1358bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_fcreate);
1359bd238fb4SLatchesar Ionkov
p9_client_symlink(struct p9_fid * dfid,const char * name,const char * symtgt,kgid_t gid,struct p9_qid * qid)13607880b43bSAl Viro int p9_client_symlink(struct p9_fid *dfid, const char *name,
13617880b43bSAl Viro const char *symtgt, kgid_t gid, struct p9_qid *qid)
136250cc42ffSVenkateswararao Jujjuri (JV) {
1363cf7c33d3SDominique Martinet int err;
136450cc42ffSVenkateswararao Jujjuri (JV) struct p9_client *clnt;
136550cc42ffSVenkateswararao Jujjuri (JV) struct p9_req_t *req;
136650cc42ffSVenkateswararao Jujjuri (JV)
13675d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TSYMLINK dfid %d name %s symtgt %s\n",
136850cc42ffSVenkateswararao Jujjuri (JV) dfid->fid, name, symtgt);
136950cc42ffSVenkateswararao Jujjuri (JV) clnt = dfid->clnt;
137050cc42ffSVenkateswararao Jujjuri (JV)
1371f791f7c5SEric W. Biederman req = p9_client_rpc(clnt, P9_TSYMLINK, "dssg", dfid->fid, name, symtgt,
137250cc42ffSVenkateswararao Jujjuri (JV) gid);
137350cc42ffSVenkateswararao Jujjuri (JV) if (IS_ERR(req)) {
137450cc42ffSVenkateswararao Jujjuri (JV) err = PTR_ERR(req);
137550cc42ffSVenkateswararao Jujjuri (JV) goto error;
137650cc42ffSVenkateswararao Jujjuri (JV) }
137750cc42ffSVenkateswararao Jujjuri (JV)
1378523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
137950cc42ffSVenkateswararao Jujjuri (JV) if (err) {
1380523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
138150cc42ffSVenkateswararao Jujjuri (JV) goto free_and_error;
138250cc42ffSVenkateswararao Jujjuri (JV) }
138350cc42ffSVenkateswararao Jujjuri (JV)
13845d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RSYMLINK qid %x.%llx.%x\n",
13856e195b0fSDominique Martinet qid->type, qid->path, qid->version);
138650cc42ffSVenkateswararao Jujjuri (JV)
138750cc42ffSVenkateswararao Jujjuri (JV) free_and_error:
138867dd8e44SDominique Martinet p9_req_put(clnt, req);
138950cc42ffSVenkateswararao Jujjuri (JV) error:
139050cc42ffSVenkateswararao Jujjuri (JV) return err;
139150cc42ffSVenkateswararao Jujjuri (JV) }
139250cc42ffSVenkateswararao Jujjuri (JV) EXPORT_SYMBOL(p9_client_symlink);
139350cc42ffSVenkateswararao Jujjuri (JV)
p9_client_link(struct p9_fid * dfid,struct p9_fid * oldfid,const char * newname)13947880b43bSAl Viro int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, const char *newname)
1395652df9a7SVenkateswararao Jujjuri (JV) {
1396652df9a7SVenkateswararao Jujjuri (JV) struct p9_client *clnt;
1397652df9a7SVenkateswararao Jujjuri (JV) struct p9_req_t *req;
1398652df9a7SVenkateswararao Jujjuri (JV)
13995d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TLINK dfid %d oldfid %d newname %s\n",
1400652df9a7SVenkateswararao Jujjuri (JV) dfid->fid, oldfid->fid, newname);
1401652df9a7SVenkateswararao Jujjuri (JV) clnt = dfid->clnt;
1402652df9a7SVenkateswararao Jujjuri (JV) req = p9_client_rpc(clnt, P9_TLINK, "dds", dfid->fid, oldfid->fid,
1403652df9a7SVenkateswararao Jujjuri (JV) newname);
1404652df9a7SVenkateswararao Jujjuri (JV) if (IS_ERR(req))
1405652df9a7SVenkateswararao Jujjuri (JV) return PTR_ERR(req);
1406652df9a7SVenkateswararao Jujjuri (JV)
14075d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RLINK\n");
140867dd8e44SDominique Martinet p9_req_put(clnt, req);
1409652df9a7SVenkateswararao Jujjuri (JV) return 0;
1410652df9a7SVenkateswararao Jujjuri (JV) }
1411652df9a7SVenkateswararao Jujjuri (JV) EXPORT_SYMBOL(p9_client_link);
1412652df9a7SVenkateswararao Jujjuri (JV)
p9_client_fsync(struct p9_fid * fid,int datasync)1413b165d601SVenkateswararao Jujjuri (JV) int p9_client_fsync(struct p9_fid *fid, int datasync)
1414920e65dcSVenkateswararao Jujjuri (JV) {
1415cf7c33d3SDominique Martinet int err = 0;
1416920e65dcSVenkateswararao Jujjuri (JV) struct p9_client *clnt;
1417920e65dcSVenkateswararao Jujjuri (JV) struct p9_req_t *req;
1418920e65dcSVenkateswararao Jujjuri (JV)
14195d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
1420b165d601SVenkateswararao Jujjuri (JV) fid->fid, datasync);
1421920e65dcSVenkateswararao Jujjuri (JV) clnt = fid->clnt;
1422920e65dcSVenkateswararao Jujjuri (JV)
1423b165d601SVenkateswararao Jujjuri (JV) req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
1424920e65dcSVenkateswararao Jujjuri (JV) if (IS_ERR(req)) {
1425920e65dcSVenkateswararao Jujjuri (JV) err = PTR_ERR(req);
1426920e65dcSVenkateswararao Jujjuri (JV) goto error;
1427920e65dcSVenkateswararao Jujjuri (JV) }
1428920e65dcSVenkateswararao Jujjuri (JV)
14295d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
1430920e65dcSVenkateswararao Jujjuri (JV)
143167dd8e44SDominique Martinet p9_req_put(clnt, req);
1432920e65dcSVenkateswararao Jujjuri (JV)
1433920e65dcSVenkateswararao Jujjuri (JV) error:
1434920e65dcSVenkateswararao Jujjuri (JV) return err;
1435920e65dcSVenkateswararao Jujjuri (JV) }
1436920e65dcSVenkateswararao Jujjuri (JV) EXPORT_SYMBOL(p9_client_fsync);
1437920e65dcSVenkateswararao Jujjuri (JV)
p9_client_clunk(struct p9_fid * fid)1438bd238fb4SLatchesar Ionkov int p9_client_clunk(struct p9_fid *fid)
1439bd238fb4SLatchesar Ionkov {
1440cf7c33d3SDominique Martinet int err = 0;
1441bd238fb4SLatchesar Ionkov struct p9_client *clnt;
144251a87c55SEric Van Hensbergen struct p9_req_t *req;
1443208f3c28SJim Garlick int retries = 0;
1444bd238fb4SLatchesar Ionkov
1445208f3c28SJim Garlick again:
14466e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, ">>> TCLUNK fid %d (try %d)\n",
14476e195b0fSDominique Martinet fid->fid, retries);
1448bd238fb4SLatchesar Ionkov clnt = fid->clnt;
1449bd238fb4SLatchesar Ionkov
145051a87c55SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TCLUNK, "d", fid->fid);
145151a87c55SEric Van Hensbergen if (IS_ERR(req)) {
145251a87c55SEric Van Hensbergen err = PTR_ERR(req);
145351a87c55SEric Van Hensbergen goto error;
1454bd238fb4SLatchesar Ionkov }
1455bd238fb4SLatchesar Ionkov
14565d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RCLUNK fid %d\n", fid->fid);
1457bd238fb4SLatchesar Ionkov
145867dd8e44SDominique Martinet p9_req_put(clnt, req);
145951a87c55SEric Van Hensbergen error:
14606e195b0fSDominique Martinet /* Fid is not valid even after a failed clunk
1461208f3c28SJim Garlick * If interrupted, retry once then give up and
1462208f3c28SJim Garlick * leak fid until umount.
14635034990eSAneesh Kumar K.V */
1464208f3c28SJim Garlick if (err == -ERESTARTSYS) {
1465208f3c28SJim Garlick if (retries++ == 0)
1466208f3c28SJim Garlick goto again;
14676e195b0fSDominique Martinet } else {
14685034990eSAneesh Kumar K.V p9_fid_destroy(fid);
14696e195b0fSDominique Martinet }
1470bd238fb4SLatchesar Ionkov return err;
1471bd238fb4SLatchesar Ionkov }
1472bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_clunk);
1473bd238fb4SLatchesar Ionkov
p9_client_remove(struct p9_fid * fid)1474bd238fb4SLatchesar Ionkov int p9_client_remove(struct p9_fid *fid)
1475bd238fb4SLatchesar Ionkov {
1476cf7c33d3SDominique Martinet int err = 0;
1477bd238fb4SLatchesar Ionkov struct p9_client *clnt;
147851a87c55SEric Van Hensbergen struct p9_req_t *req;
1479bd238fb4SLatchesar Ionkov
14805d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TREMOVE fid %d\n", fid->fid);
1481bd238fb4SLatchesar Ionkov clnt = fid->clnt;
1482bd238fb4SLatchesar Ionkov
148351a87c55SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TREMOVE, "d", fid->fid);
148451a87c55SEric Van Hensbergen if (IS_ERR(req)) {
148551a87c55SEric Van Hensbergen err = PTR_ERR(req);
148651a87c55SEric Van Hensbergen goto error;
1487bd238fb4SLatchesar Ionkov }
1488bd238fb4SLatchesar Ionkov
14895d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RREMOVE fid %d\n", fid->fid);
1490bd238fb4SLatchesar Ionkov
149167dd8e44SDominique Martinet p9_req_put(clnt, req);
149251a87c55SEric Van Hensbergen error:
1493208f3c28SJim Garlick if (err == -ERESTARTSYS)
1494b48dbb99SDominique Martinet p9_fid_put(fid);
1495208f3c28SJim Garlick else
14960b1208b1SAneesh Kumar K.V p9_fid_destroy(fid);
1497bd238fb4SLatchesar Ionkov return err;
1498bd238fb4SLatchesar Ionkov }
1499bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_remove);
1500bd238fb4SLatchesar Ionkov
p9_client_unlinkat(struct p9_fid * dfid,const char * name,int flags)150148e370ffSAneesh Kumar K.V int p9_client_unlinkat(struct p9_fid *dfid, const char *name, int flags)
150248e370ffSAneesh Kumar K.V {
150348e370ffSAneesh Kumar K.V int err = 0;
150448e370ffSAneesh Kumar K.V struct p9_req_t *req;
150548e370ffSAneesh Kumar K.V struct p9_client *clnt;
150648e370ffSAneesh Kumar K.V
15075d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TUNLINKAT fid %d %s %d\n",
150848e370ffSAneesh Kumar K.V dfid->fid, name, flags);
150948e370ffSAneesh Kumar K.V
151048e370ffSAneesh Kumar K.V clnt = dfid->clnt;
151148e370ffSAneesh Kumar K.V req = p9_client_rpc(clnt, P9_TUNLINKAT, "dsd", dfid->fid, name, flags);
151248e370ffSAneesh Kumar K.V if (IS_ERR(req)) {
151348e370ffSAneesh Kumar K.V err = PTR_ERR(req);
151448e370ffSAneesh Kumar K.V goto error;
151548e370ffSAneesh Kumar K.V }
15165d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RUNLINKAT fid %d %s\n", dfid->fid, name);
151748e370ffSAneesh Kumar K.V
151867dd8e44SDominique Martinet p9_req_put(clnt, req);
151948e370ffSAneesh Kumar K.V error:
152048e370ffSAneesh Kumar K.V return err;
152148e370ffSAneesh Kumar K.V }
152248e370ffSAneesh Kumar K.V EXPORT_SYMBOL(p9_client_unlinkat);
152348e370ffSAneesh Kumar K.V
15240fc9655eSEric Van Hensbergen int
p9_client_read(struct p9_fid * fid,u64 offset,struct iov_iter * to,int * err)1525e1200fe6SAl Viro p9_client_read(struct p9_fid *fid, u64 offset, struct iov_iter *to, int *err)
1526bd238fb4SLatchesar Ionkov {
1527e1200fe6SAl Viro int total = 0;
1528999b8b88SVincent Bernat *err = 0;
1529abfa034eSAneesh Kumar K.V
1530e1200fe6SAl Viro while (iov_iter_count(to)) {
1531388f6966SSergey Alirzaev int count;
1532388f6966SSergey Alirzaev
1533388f6966SSergey Alirzaev count = p9_client_read_once(fid, offset, to, err);
1534388f6966SSergey Alirzaev if (!count || *err)
1535388f6966SSergey Alirzaev break;
1536388f6966SSergey Alirzaev offset += count;
1537388f6966SSergey Alirzaev total += count;
1538388f6966SSergey Alirzaev }
1539388f6966SSergey Alirzaev return total;
1540388f6966SSergey Alirzaev }
1541388f6966SSergey Alirzaev EXPORT_SYMBOL(p9_client_read);
1542388f6966SSergey Alirzaev
1543388f6966SSergey Alirzaev int
p9_client_read_once(struct p9_fid * fid,u64 offset,struct iov_iter * to,int * err)1544388f6966SSergey Alirzaev p9_client_read_once(struct p9_fid *fid, u64 offset, struct iov_iter *to,
1545388f6966SSergey Alirzaev int *err)
1546388f6966SSergey Alirzaev {
1547388f6966SSergey Alirzaev struct p9_client *clnt = fid->clnt;
1548388f6966SSergey Alirzaev struct p9_req_t *req;
1549e1200fe6SAl Viro int count = iov_iter_count(to);
15507f024647SAl Viro int rsize, received, non_zc = 0;
1551e1200fe6SAl Viro char *dataptr;
1552bd238fb4SLatchesar Ionkov
1553388f6966SSergey Alirzaev *err = 0;
15546e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, ">>> TREAD fid %d offset %llu %zu\n",
15556e195b0fSDominique Martinet fid->fid, offset, iov_iter_count(to));
1556388f6966SSergey Alirzaev
1557bd238fb4SLatchesar Ionkov rsize = fid->iounit;
1558bd238fb4SLatchesar Ionkov if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
1559bd238fb4SLatchesar Ionkov rsize = clnt->msize - P9_IOHDRSZ;
1560bd238fb4SLatchesar Ionkov
1561bd238fb4SLatchesar Ionkov if (count < rsize)
1562bd238fb4SLatchesar Ionkov rsize = count;
1563bd238fb4SLatchesar Ionkov
1564aca00763SRob Landley /* Don't bother zerocopy for small IO (< 1024) */
1565abfa034eSAneesh Kumar K.V if (clnt->trans_mod->zc_request && rsize > 1024) {
1566388f6966SSergey Alirzaev /* response header len is 11
1567abfa034eSAneesh Kumar K.V * PDU Header(7) + IO Size (4)
1568abfa034eSAneesh Kumar K.V */
1569e1200fe6SAl Viro req = p9_client_zc_rpc(clnt, P9_TREAD, to, NULL, rsize,
1570e1200fe6SAl Viro 0, 11, "dqd", fid->fid,
1571abfa034eSAneesh Kumar K.V offset, rsize);
1572bb2f8a55SVenkateswararao Jujjuri (JV) } else {
1573abfa034eSAneesh Kumar K.V non_zc = 1;
1574bb2f8a55SVenkateswararao Jujjuri (JV) req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset,
1575bb2f8a55SVenkateswararao Jujjuri (JV) rsize);
1576bb2f8a55SVenkateswararao Jujjuri (JV) }
157751a87c55SEric Van Hensbergen if (IS_ERR(req)) {
1578e1200fe6SAl Viro *err = PTR_ERR(req);
15797f024647SAl Viro if (!non_zc)
15807f024647SAl Viro iov_iter_revert(to, count - iov_iter_count(to));
1581388f6966SSergey Alirzaev return 0;
1582bd238fb4SLatchesar Ionkov }
1583bd238fb4SLatchesar Ionkov
1584523adb6cSDominique Martinet *err = p9pdu_readf(&req->rc, clnt->proto_version,
15857f024647SAl Viro "D", &received, &dataptr);
1586e1200fe6SAl Viro if (*err) {
15877f024647SAl Viro if (!non_zc)
15887f024647SAl Viro iov_iter_revert(to, count - iov_iter_count(to));
1589523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
159067dd8e44SDominique Martinet p9_req_put(clnt, req);
1591388f6966SSergey Alirzaev return 0;
1592e7f4b8f1SEric Van Hensbergen }
15937f024647SAl Viro if (rsize < received) {
15947f024647SAl Viro pr_err("bogus RREAD count (%d > %d)\n", received, rsize);
15957f024647SAl Viro received = rsize;
15960f1db7deSAl Viro }
1597bd238fb4SLatchesar Ionkov
159840613ea1SDominique Martinet p9_debug(P9_DEBUG_9P, "<<< RREAD count %d\n", received);
1599bd238fb4SLatchesar Ionkov
1600e1200fe6SAl Viro if (non_zc) {
16017f024647SAl Viro int n = copy_to_iter(dataptr, received, to);
1602388f6966SSergey Alirzaev
16037f024647SAl Viro if (n != received) {
1604e1200fe6SAl Viro *err = -EFAULT;
160567dd8e44SDominique Martinet p9_req_put(clnt, req);
1606388f6966SSergey Alirzaev return n;
1607e1200fe6SAl Viro }
1608e1200fe6SAl Viro } else {
16097f024647SAl Viro iov_iter_revert(to, count - received - iov_iter_count(to));
16100fc9655eSEric Van Hensbergen }
161167dd8e44SDominique Martinet p9_req_put(clnt, req);
16127f024647SAl Viro return received;
1613e1200fe6SAl Viro }
1614388f6966SSergey Alirzaev EXPORT_SYMBOL(p9_client_read_once);
1615bd238fb4SLatchesar Ionkov
16160fc9655eSEric Van Hensbergen int
p9_client_write(struct p9_fid * fid,u64 offset,struct iov_iter * from,int * err)1617070b3656SAl Viro p9_client_write(struct p9_fid *fid, u64 offset, struct iov_iter *from, int *err)
1618bd238fb4SLatchesar Ionkov {
1619070b3656SAl Viro struct p9_client *clnt = fid->clnt;
162051a87c55SEric Van Hensbergen struct p9_req_t *req;
1621070b3656SAl Viro int total = 0;
1622999b8b88SVincent Bernat *err = 0;
16234f3b35c1SAl Viro
1624070b3656SAl Viro while (iov_iter_count(from)) {
1625070b3656SAl Viro int count = iov_iter_count(from);
1626070b3656SAl Viro int rsize = fid->iounit;
16277f024647SAl Viro int written;
16286e195b0fSDominique Martinet
1629bd238fb4SLatchesar Ionkov if (!rsize || rsize > clnt->msize - P9_IOHDRSZ)
1630bd238fb4SLatchesar Ionkov rsize = clnt->msize - P9_IOHDRSZ;
1631bd238fb4SLatchesar Ionkov
1632bd238fb4SLatchesar Ionkov if (count < rsize)
1633bd238fb4SLatchesar Ionkov rsize = count;
16341fc52481SVenkateswararao Jujjuri (JV)
163540613ea1SDominique Martinet p9_debug(P9_DEBUG_9P, ">>> TWRITE fid %d offset %llu count %d (/%d)\n",
163640613ea1SDominique Martinet fid->fid, offset, rsize, count);
163740613ea1SDominique Martinet
1638abfa034eSAneesh Kumar K.V /* Don't bother zerocopy for small IO (< 1024) */
1639abfa034eSAneesh Kumar K.V if (clnt->trans_mod->zc_request && rsize > 1024) {
1640070b3656SAl Viro req = p9_client_zc_rpc(clnt, P9_TWRITE, NULL, from, 0,
1641070b3656SAl Viro rsize, P9_ZC_HDR_SZ, "dqd",
1642abfa034eSAneesh Kumar K.V fid->fid, offset, rsize);
16431fc52481SVenkateswararao Jujjuri (JV) } else {
16444f3b35c1SAl Viro req = p9_client_rpc(clnt, P9_TWRITE, "dqV", fid->fid,
1645070b3656SAl Viro offset, rsize, from);
16461fc52481SVenkateswararao Jujjuri (JV) }
164751a87c55SEric Van Hensbergen if (IS_ERR(req)) {
16487f024647SAl Viro iov_iter_revert(from, count - iov_iter_count(from));
1649070b3656SAl Viro *err = PTR_ERR(req);
1650070b3656SAl Viro break;
1651bd238fb4SLatchesar Ionkov }
1652bd238fb4SLatchesar Ionkov
16537f024647SAl Viro *err = p9pdu_readf(&req->rc, clnt->proto_version, "d", &written);
1654070b3656SAl Viro if (*err) {
16557f024647SAl Viro iov_iter_revert(from, count - iov_iter_count(from));
1656523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
165767dd8e44SDominique Martinet p9_req_put(clnt, req);
165867e808fbSAl Viro break;
1659e7f4b8f1SEric Van Hensbergen }
16607f024647SAl Viro if (rsize < written) {
16617f024647SAl Viro pr_err("bogus RWRITE count (%d > %d)\n", written, rsize);
16627f024647SAl Viro written = rsize;
16630f1db7deSAl Viro }
1664e7f4b8f1SEric Van Hensbergen
166540613ea1SDominique Martinet p9_debug(P9_DEBUG_9P, "<<< RWRITE count %d\n", written);
1666bd238fb4SLatchesar Ionkov
166767dd8e44SDominique Martinet p9_req_put(clnt, req);
16687f024647SAl Viro iov_iter_revert(from, count - written - iov_iter_count(from));
16697f024647SAl Viro total += written;
16707f024647SAl Viro offset += written;
1671070b3656SAl Viro }
1672070b3656SAl Viro return total;
1673bd238fb4SLatchesar Ionkov }
1674bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_write);
1675bd238fb4SLatchesar Ionkov
p9_client_stat(struct p9_fid * fid)167651a87c55SEric Van Hensbergen struct p9_wstat *p9_client_stat(struct p9_fid *fid)
16775503ac56SEric Van Hensbergen {
167851a87c55SEric Van Hensbergen int err;
167951a87c55SEric Van Hensbergen struct p9_client *clnt;
16806e195b0fSDominique Martinet struct p9_wstat *ret;
168151a87c55SEric Van Hensbergen struct p9_req_t *req;
168251a87c55SEric Van Hensbergen u16 ignored;
16835503ac56SEric Van Hensbergen
16845d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TSTAT fid %d\n", fid->fid);
16855503ac56SEric Van Hensbergen
16866e195b0fSDominique Martinet ret = kmalloc(sizeof(*ret), GFP_KERNEL);
16875503ac56SEric Van Hensbergen if (!ret)
16885503ac56SEric Van Hensbergen return ERR_PTR(-ENOMEM);
16895503ac56SEric Van Hensbergen
1690bd238fb4SLatchesar Ionkov clnt = fid->clnt;
1691bd238fb4SLatchesar Ionkov
169251a87c55SEric Van Hensbergen req = p9_client_rpc(clnt, P9_TSTAT, "d", fid->fid);
169351a87c55SEric Van Hensbergen if (IS_ERR(req)) {
169451a87c55SEric Van Hensbergen err = PTR_ERR(req);
1695bd238fb4SLatchesar Ionkov goto error;
1696bd238fb4SLatchesar Ionkov }
1697bd238fb4SLatchesar Ionkov
1698523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "wS", &ignored, ret);
1699e7f4b8f1SEric Van Hensbergen if (err) {
1700523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
170167dd8e44SDominique Martinet p9_req_put(clnt, req);
1702eedfe1c4SAbhishek Kulkarni goto error;
1703e7f4b8f1SEric Van Hensbergen }
1704bd238fb4SLatchesar Ionkov
17055d385153SJoe Perches p9_debug(P9_DEBUG_9P,
1706e7f4b8f1SEric Van Hensbergen "<<< RSTAT sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1707e7f4b8f1SEric Van Hensbergen "<<< mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1708e7f4b8f1SEric Van Hensbergen "<<< name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1709e7f4b8f1SEric Van Hensbergen "<<< uid=%d gid=%d n_muid=%d\n",
17106e195b0fSDominique Martinet ret->size, ret->type, ret->dev, ret->qid.type, ret->qid.path,
17116e195b0fSDominique Martinet ret->qid.version, ret->mode,
17126e195b0fSDominique Martinet ret->atime, ret->mtime, ret->length,
1713b0d5fdefSRandy Dunlap ret->name, ret->uid, ret->gid, ret->muid, ret->extension,
1714447c5094SEric W. Biederman from_kuid(&init_user_ns, ret->n_uid),
1715447c5094SEric W. Biederman from_kgid(&init_user_ns, ret->n_gid),
1716447c5094SEric W. Biederman from_kuid(&init_user_ns, ret->n_muid));
1717bd238fb4SLatchesar Ionkov
171867dd8e44SDominique Martinet p9_req_put(clnt, req);
1719742b11a7SLatchesar Ionkov return ret;
1720742b11a7SLatchesar Ionkov
1721bd238fb4SLatchesar Ionkov error:
1722742b11a7SLatchesar Ionkov kfree(ret);
1723742b11a7SLatchesar Ionkov return ERR_PTR(err);
1724bd238fb4SLatchesar Ionkov }
1725bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_stat);
1726bd238fb4SLatchesar Ionkov
p9_client_getattr_dotl(struct p9_fid * fid,u64 request_mask)1727f0853122SSripathi Kodi struct p9_stat_dotl *p9_client_getattr_dotl(struct p9_fid *fid,
1728f0853122SSripathi Kodi u64 request_mask)
1729f0853122SSripathi Kodi {
1730f0853122SSripathi Kodi int err;
1731f0853122SSripathi Kodi struct p9_client *clnt;
17326e195b0fSDominique Martinet struct p9_stat_dotl *ret;
1733f0853122SSripathi Kodi struct p9_req_t *req;
1734f0853122SSripathi Kodi
17355d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TGETATTR fid %d, request_mask %lld\n",
1736f0853122SSripathi Kodi fid->fid, request_mask);
1737f0853122SSripathi Kodi
17386e195b0fSDominique Martinet ret = kmalloc(sizeof(*ret), GFP_KERNEL);
1739f0853122SSripathi Kodi if (!ret)
1740f0853122SSripathi Kodi return ERR_PTR(-ENOMEM);
1741f0853122SSripathi Kodi
1742f0853122SSripathi Kodi clnt = fid->clnt;
1743f0853122SSripathi Kodi
1744f0853122SSripathi Kodi req = p9_client_rpc(clnt, P9_TGETATTR, "dq", fid->fid, request_mask);
1745f0853122SSripathi Kodi if (IS_ERR(req)) {
1746f0853122SSripathi Kodi err = PTR_ERR(req);
1747f0853122SSripathi Kodi goto error;
1748f0853122SSripathi Kodi }
1749f0853122SSripathi Kodi
1750523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "A", ret);
1751f0853122SSripathi Kodi if (err) {
1752523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
175367dd8e44SDominique Martinet p9_req_put(clnt, req);
1754f0853122SSripathi Kodi goto error;
1755f0853122SSripathi Kodi }
1756f0853122SSripathi Kodi
17576e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, "<<< RGETATTR st_result_mask=%lld\n"
1758f0853122SSripathi Kodi "<<< qid=%x.%llx.%x\n"
1759f0853122SSripathi Kodi "<<< st_mode=%8.8x st_nlink=%llu\n"
1760f0853122SSripathi Kodi "<<< st_uid=%d st_gid=%d\n"
1761f0853122SSripathi Kodi "<<< st_rdev=%llx st_size=%llx st_blksize=%llu st_blocks=%llu\n"
1762f0853122SSripathi Kodi "<<< st_atime_sec=%lld st_atime_nsec=%lld\n"
1763f0853122SSripathi Kodi "<<< st_mtime_sec=%lld st_mtime_nsec=%lld\n"
1764f0853122SSripathi Kodi "<<< st_ctime_sec=%lld st_ctime_nsec=%lld\n"
1765f0853122SSripathi Kodi "<<< st_btime_sec=%lld st_btime_nsec=%lld\n"
176664ad31f3Spiaojun "<<< st_gen=%lld st_data_version=%lld\n",
17676e195b0fSDominique Martinet ret->st_result_mask,
17686e195b0fSDominique Martinet ret->qid.type, ret->qid.path, ret->qid.version,
17696e195b0fSDominique Martinet ret->st_mode, ret->st_nlink,
1770447c5094SEric W. Biederman from_kuid(&init_user_ns, ret->st_uid),
1771447c5094SEric W. Biederman from_kgid(&init_user_ns, ret->st_gid),
17726e195b0fSDominique Martinet ret->st_rdev, ret->st_size, ret->st_blksize, ret->st_blocks,
17736e195b0fSDominique Martinet ret->st_atime_sec, ret->st_atime_nsec,
17746e195b0fSDominique Martinet ret->st_mtime_sec, ret->st_mtime_nsec,
17756e195b0fSDominique Martinet ret->st_ctime_sec, ret->st_ctime_nsec,
17766e195b0fSDominique Martinet ret->st_btime_sec, ret->st_btime_nsec,
1777f0853122SSripathi Kodi ret->st_gen, ret->st_data_version);
1778f0853122SSripathi Kodi
177967dd8e44SDominique Martinet p9_req_put(clnt, req);
1780f0853122SSripathi Kodi return ret;
1781f0853122SSripathi Kodi
1782f0853122SSripathi Kodi error:
1783f0853122SSripathi Kodi kfree(ret);
1784f0853122SSripathi Kodi return ERR_PTR(err);
1785f0853122SSripathi Kodi }
1786f0853122SSripathi Kodi EXPORT_SYMBOL(p9_client_getattr_dotl);
1787f0853122SSripathi Kodi
p9_client_statsize(struct p9_wstat * wst,int proto_version)1788342fee1dSSripathi Kodi static int p9_client_statsize(struct p9_wstat *wst, int proto_version)
1789453ed90dSLatchesar Ionkov {
1790453ed90dSLatchesar Ionkov int ret;
1791453ed90dSLatchesar Ionkov
17929d6939daSEric Van Hensbergen /* NOTE: size shouldn't include its own length */
1793453ed90dSLatchesar Ionkov /* size[2] type[2] dev[4] qid[13] */
1794453ed90dSLatchesar Ionkov /* mode[4] atime[4] mtime[4] length[8]*/
1795453ed90dSLatchesar Ionkov /* name[s] uid[s] gid[s] muid[s] */
17969d6939daSEric Van Hensbergen ret = 2 + 4 + 13 + 4 + 4 + 4 + 8 + 2 + 2 + 2 + 2;
1797453ed90dSLatchesar Ionkov
1798453ed90dSLatchesar Ionkov if (wst->name)
1799453ed90dSLatchesar Ionkov ret += strlen(wst->name);
1800453ed90dSLatchesar Ionkov if (wst->uid)
1801453ed90dSLatchesar Ionkov ret += strlen(wst->uid);
1802453ed90dSLatchesar Ionkov if (wst->gid)
1803453ed90dSLatchesar Ionkov ret += strlen(wst->gid);
1804453ed90dSLatchesar Ionkov if (wst->muid)
1805453ed90dSLatchesar Ionkov ret += strlen(wst->muid);
1806453ed90dSLatchesar Ionkov
18076e195b0fSDominique Martinet if (proto_version == p9_proto_2000u ||
18086e195b0fSDominique Martinet proto_version == p9_proto_2000L) {
18096e195b0fSDominique Martinet /* extension[s] n_uid[4] n_gid[4] n_muid[4] */
18106e195b0fSDominique Martinet ret += 2 + 4 + 4 + 4;
1811453ed90dSLatchesar Ionkov if (wst->extension)
1812453ed90dSLatchesar Ionkov ret += strlen(wst->extension);
1813453ed90dSLatchesar Ionkov }
1814453ed90dSLatchesar Ionkov
1815453ed90dSLatchesar Ionkov return ret;
1816453ed90dSLatchesar Ionkov }
1817453ed90dSLatchesar Ionkov
p9_client_wstat(struct p9_fid * fid,struct p9_wstat * wst)1818bd238fb4SLatchesar Ionkov int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1819bd238fb4SLatchesar Ionkov {
1820cf7c33d3SDominique Martinet int err = 0;
182151a87c55SEric Van Hensbergen struct p9_req_t *req;
1822bd238fb4SLatchesar Ionkov struct p9_client *clnt;
1823bd238fb4SLatchesar Ionkov
1824453ed90dSLatchesar Ionkov clnt = fid->clnt;
1825342fee1dSSripathi Kodi wst->size = p9_client_statsize(wst, clnt->proto_version);
18266e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, ">>> TWSTAT fid %d\n",
18276e195b0fSDominique Martinet fid->fid);
18285d385153SJoe Perches p9_debug(P9_DEBUG_9P,
1829e7f4b8f1SEric Van Hensbergen " sz=%x type=%x dev=%x qid=%x.%llx.%x\n"
1830e7f4b8f1SEric Van Hensbergen " mode=%8.8x atime=%8.8x mtime=%8.8x length=%llx\n"
1831e7f4b8f1SEric Van Hensbergen " name=%s uid=%s gid=%s muid=%s extension=(%s)\n"
1832e7f4b8f1SEric Van Hensbergen " uid=%d gid=%d n_muid=%d\n",
1833e7f4b8f1SEric Van Hensbergen wst->size, wst->type, wst->dev, wst->qid.type,
18346e195b0fSDominique Martinet wst->qid.path, wst->qid.version,
18356e195b0fSDominique Martinet wst->mode, wst->atime, wst->mtime, wst->length,
1836b0d5fdefSRandy Dunlap wst->name, wst->uid, wst->gid, wst->muid, wst->extension,
1837447c5094SEric W. Biederman from_kuid(&init_user_ns, wst->n_uid),
1838447c5094SEric W. Biederman from_kgid(&init_user_ns, wst->n_gid),
1839447c5094SEric W. Biederman from_kuid(&init_user_ns, wst->n_muid));
1840bd238fb4SLatchesar Ionkov
18416e195b0fSDominique Martinet req = p9_client_rpc(clnt, P9_TWSTAT, "dwS",
18426e195b0fSDominique Martinet fid->fid, wst->size + 2, wst);
184351a87c55SEric Van Hensbergen if (IS_ERR(req)) {
184451a87c55SEric Van Hensbergen err = PTR_ERR(req);
184551a87c55SEric Van Hensbergen goto error;
1846bd238fb4SLatchesar Ionkov }
1847bd238fb4SLatchesar Ionkov
18485d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RWSTAT fid %d\n", fid->fid);
1849bd238fb4SLatchesar Ionkov
185067dd8e44SDominique Martinet p9_req_put(clnt, req);
185151a87c55SEric Van Hensbergen error:
1852bd238fb4SLatchesar Ionkov return err;
1853bd238fb4SLatchesar Ionkov }
1854bd238fb4SLatchesar Ionkov EXPORT_SYMBOL(p9_client_wstat);
1855bda8e775SSripathi Kodi
p9_client_setattr(struct p9_fid * fid,struct p9_iattr_dotl * p9attr)185687d7845aSSripathi Kodi int p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
185787d7845aSSripathi Kodi {
1858cf7c33d3SDominique Martinet int err = 0;
185987d7845aSSripathi Kodi struct p9_req_t *req;
186087d7845aSSripathi Kodi struct p9_client *clnt;
186187d7845aSSripathi Kodi
186287d7845aSSripathi Kodi clnt = fid->clnt;
18635d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TSETATTR fid %d\n", fid->fid);
18646e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, " valid=%x mode=%x uid=%d gid=%d size=%lld\n",
1865447c5094SEric W. Biederman p9attr->valid, p9attr->mode,
1866447c5094SEric W. Biederman from_kuid(&init_user_ns, p9attr->uid),
1867447c5094SEric W. Biederman from_kgid(&init_user_ns, p9attr->gid),
18686e195b0fSDominique Martinet p9attr->size);
18696e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, " atime_sec=%lld atime_nsec=%lld\n",
18706e195b0fSDominique Martinet p9attr->atime_sec, p9attr->atime_nsec);
18716e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, " mtime_sec=%lld mtime_nsec=%lld\n",
187287d7845aSSripathi Kodi p9attr->mtime_sec, p9attr->mtime_nsec);
187387d7845aSSripathi Kodi
187487d7845aSSripathi Kodi req = p9_client_rpc(clnt, P9_TSETATTR, "dI", fid->fid, p9attr);
187587d7845aSSripathi Kodi
187687d7845aSSripathi Kodi if (IS_ERR(req)) {
187787d7845aSSripathi Kodi err = PTR_ERR(req);
187887d7845aSSripathi Kodi goto error;
187987d7845aSSripathi Kodi }
18805d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RSETATTR fid %d\n", fid->fid);
188167dd8e44SDominique Martinet p9_req_put(clnt, req);
188287d7845aSSripathi Kodi error:
188387d7845aSSripathi Kodi return err;
188487d7845aSSripathi Kodi }
188587d7845aSSripathi Kodi EXPORT_SYMBOL(p9_client_setattr);
188687d7845aSSripathi Kodi
p9_client_statfs(struct p9_fid * fid,struct p9_rstatfs * sb)1887bda8e775SSripathi Kodi int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb)
1888bda8e775SSripathi Kodi {
1889bda8e775SSripathi Kodi int err;
1890bda8e775SSripathi Kodi struct p9_req_t *req;
1891bda8e775SSripathi Kodi struct p9_client *clnt;
1892bda8e775SSripathi Kodi
1893bda8e775SSripathi Kodi clnt = fid->clnt;
1894bda8e775SSripathi Kodi
18955d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TSTATFS fid %d\n", fid->fid);
1896bda8e775SSripathi Kodi
1897bda8e775SSripathi Kodi req = p9_client_rpc(clnt, P9_TSTATFS, "d", fid->fid);
1898bda8e775SSripathi Kodi if (IS_ERR(req)) {
1899bda8e775SSripathi Kodi err = PTR_ERR(req);
1900bda8e775SSripathi Kodi goto error;
1901bda8e775SSripathi Kodi }
1902bda8e775SSripathi Kodi
1903523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "ddqqqqqqd", &sb->type,
1904bda8e775SSripathi Kodi &sb->bsize, &sb->blocks, &sb->bfree, &sb->bavail,
1905bda8e775SSripathi Kodi &sb->files, &sb->ffree, &sb->fsid, &sb->namelen);
1906bda8e775SSripathi Kodi if (err) {
1907523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
190867dd8e44SDominique Martinet p9_req_put(clnt, req);
1909bda8e775SSripathi Kodi goto error;
1910bda8e775SSripathi Kodi }
1911bda8e775SSripathi Kodi
19126e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
19136e195b0fSDominique Martinet "<<< RSTATFS fid %d type 0x%x bsize %u blocks %llu bfree %llu bavail %llu files %llu ffree %llu fsid %llu namelen %u\n",
19146e195b0fSDominique Martinet fid->fid, sb->type, sb->bsize, sb->blocks, sb->bfree,
19156e195b0fSDominique Martinet sb->bavail, sb->files, sb->ffree, sb->fsid, sb->namelen);
1916bda8e775SSripathi Kodi
191767dd8e44SDominique Martinet p9_req_put(clnt, req);
1918bda8e775SSripathi Kodi error:
1919bda8e775SSripathi Kodi return err;
1920bda8e775SSripathi Kodi }
1921bda8e775SSripathi Kodi EXPORT_SYMBOL(p9_client_statfs);
19224681dbdaSSripathi Kodi
p9_client_rename(struct p9_fid * fid,struct p9_fid * newdirfid,const char * name)19239e8fb38eSAneesh Kumar K.V int p9_client_rename(struct p9_fid *fid,
19249e8fb38eSAneesh Kumar K.V struct p9_fid *newdirfid, const char *name)
19254681dbdaSSripathi Kodi {
1926cf7c33d3SDominique Martinet int err = 0;
19274681dbdaSSripathi Kodi struct p9_req_t *req;
19284681dbdaSSripathi Kodi struct p9_client *clnt;
19294681dbdaSSripathi Kodi
19304681dbdaSSripathi Kodi clnt = fid->clnt;
19314681dbdaSSripathi Kodi
19325d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TRENAME fid %d newdirfid %d name %s\n",
19334681dbdaSSripathi Kodi fid->fid, newdirfid->fid, name);
19344681dbdaSSripathi Kodi
19354681dbdaSSripathi Kodi req = p9_client_rpc(clnt, P9_TRENAME, "dds", fid->fid,
19364681dbdaSSripathi Kodi newdirfid->fid, name);
19374681dbdaSSripathi Kodi if (IS_ERR(req)) {
19384681dbdaSSripathi Kodi err = PTR_ERR(req);
19394681dbdaSSripathi Kodi goto error;
19404681dbdaSSripathi Kodi }
19414681dbdaSSripathi Kodi
19425d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RRENAME fid %d\n", fid->fid);
19434681dbdaSSripathi Kodi
194467dd8e44SDominique Martinet p9_req_put(clnt, req);
19454681dbdaSSripathi Kodi error:
19464681dbdaSSripathi Kodi return err;
19474681dbdaSSripathi Kodi }
19484681dbdaSSripathi Kodi EXPORT_SYMBOL(p9_client_rename);
19494681dbdaSSripathi Kodi
p9_client_renameat(struct p9_fid * olddirfid,const char * old_name,struct p9_fid * newdirfid,const char * new_name)19509e8fb38eSAneesh Kumar K.V int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
19519e8fb38eSAneesh Kumar K.V struct p9_fid *newdirfid, const char *new_name)
19529e8fb38eSAneesh Kumar K.V {
1953cf7c33d3SDominique Martinet int err = 0;
19549e8fb38eSAneesh Kumar K.V struct p9_req_t *req;
19559e8fb38eSAneesh Kumar K.V struct p9_client *clnt;
19569e8fb38eSAneesh Kumar K.V
19579e8fb38eSAneesh Kumar K.V clnt = olddirfid->clnt;
19589e8fb38eSAneesh Kumar K.V
19596e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
19606e195b0fSDominique Martinet ">>> TRENAMEAT olddirfid %d old name %s newdirfid %d new name %s\n",
19616e195b0fSDominique Martinet olddirfid->fid, old_name, newdirfid->fid, new_name);
19629e8fb38eSAneesh Kumar K.V
19639e8fb38eSAneesh Kumar K.V req = p9_client_rpc(clnt, P9_TRENAMEAT, "dsds", olddirfid->fid,
19649e8fb38eSAneesh Kumar K.V old_name, newdirfid->fid, new_name);
19659e8fb38eSAneesh Kumar K.V if (IS_ERR(req)) {
19669e8fb38eSAneesh Kumar K.V err = PTR_ERR(req);
19679e8fb38eSAneesh Kumar K.V goto error;
19689e8fb38eSAneesh Kumar K.V }
19699e8fb38eSAneesh Kumar K.V
19705d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RRENAMEAT newdirfid %d new name %s\n",
19719e8fb38eSAneesh Kumar K.V newdirfid->fid, new_name);
19729e8fb38eSAneesh Kumar K.V
197367dd8e44SDominique Martinet p9_req_put(clnt, req);
19749e8fb38eSAneesh Kumar K.V error:
19759e8fb38eSAneesh Kumar K.V return err;
19769e8fb38eSAneesh Kumar K.V }
19779e8fb38eSAneesh Kumar K.V EXPORT_SYMBOL(p9_client_renameat);
19789e8fb38eSAneesh Kumar K.V
19796e195b0fSDominique Martinet /* An xattrwalk without @attr_name gives the fid for the lisxattr namespace
19800ef63f34SAneesh Kumar K.V */
p9_client_xattrwalk(struct p9_fid * file_fid,const char * attr_name,u64 * attr_size)19810ef63f34SAneesh Kumar K.V struct p9_fid *p9_client_xattrwalk(struct p9_fid *file_fid,
19820ef63f34SAneesh Kumar K.V const char *attr_name, u64 *attr_size)
19830ef63f34SAneesh Kumar K.V {
19840ef63f34SAneesh Kumar K.V int err;
19850ef63f34SAneesh Kumar K.V struct p9_req_t *req;
19860ef63f34SAneesh Kumar K.V struct p9_client *clnt;
19870ef63f34SAneesh Kumar K.V struct p9_fid *attr_fid;
19880ef63f34SAneesh Kumar K.V
19890ef63f34SAneesh Kumar K.V clnt = file_fid->clnt;
19900ef63f34SAneesh Kumar K.V attr_fid = p9_fid_create(clnt);
1991b5303be2SMatthew Wilcox if (!attr_fid) {
1992b5303be2SMatthew Wilcox err = -ENOMEM;
19930ef63f34SAneesh Kumar K.V goto error;
19940ef63f34SAneesh Kumar K.V }
19955d385153SJoe Perches p9_debug(P9_DEBUG_9P,
199635663b6bSDominique Martinet ">>> TXATTRWALK file_fid %d, attr_fid %d name '%s'\n",
19970ef63f34SAneesh Kumar K.V file_fid->fid, attr_fid->fid, attr_name);
19980ef63f34SAneesh Kumar K.V
19990ef63f34SAneesh Kumar K.V req = p9_client_rpc(clnt, P9_TXATTRWALK, "dds",
20000ef63f34SAneesh Kumar K.V file_fid->fid, attr_fid->fid, attr_name);
20010ef63f34SAneesh Kumar K.V if (IS_ERR(req)) {
20020ef63f34SAneesh Kumar K.V err = PTR_ERR(req);
20030ef63f34SAneesh Kumar K.V goto error;
20040ef63f34SAneesh Kumar K.V }
2005523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "q", attr_size);
20060ef63f34SAneesh Kumar K.V if (err) {
2007523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
200867dd8e44SDominique Martinet p9_req_put(clnt, req);
20090ef63f34SAneesh Kumar K.V goto clunk_fid;
20100ef63f34SAneesh Kumar K.V }
201167dd8e44SDominique Martinet p9_req_put(clnt, req);
20125d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RXATTRWALK fid %d size %llu\n",
20130ef63f34SAneesh Kumar K.V attr_fid->fid, *attr_size);
20140ef63f34SAneesh Kumar K.V return attr_fid;
20150ef63f34SAneesh Kumar K.V clunk_fid:
2016b48dbb99SDominique Martinet p9_fid_put(attr_fid);
20170ef63f34SAneesh Kumar K.V attr_fid = NULL;
20180ef63f34SAneesh Kumar K.V error:
20196e195b0fSDominique Martinet if (attr_fid && attr_fid != file_fid)
20200ef63f34SAneesh Kumar K.V p9_fid_destroy(attr_fid);
20210ef63f34SAneesh Kumar K.V
20220ef63f34SAneesh Kumar K.V return ERR_PTR(err);
20230ef63f34SAneesh Kumar K.V }
20240ef63f34SAneesh Kumar K.V EXPORT_SYMBOL_GPL(p9_client_xattrwalk);
20250ef63f34SAneesh Kumar K.V
p9_client_xattrcreate(struct p9_fid * fid,const char * name,u64 attr_size,int flags)2026eda25e46SAneesh Kumar K.V int p9_client_xattrcreate(struct p9_fid *fid, const char *name,
2027eda25e46SAneesh Kumar K.V u64 attr_size, int flags)
2028eda25e46SAneesh Kumar K.V {
2029cf7c33d3SDominique Martinet int err = 0;
2030eda25e46SAneesh Kumar K.V struct p9_req_t *req;
2031eda25e46SAneesh Kumar K.V struct p9_client *clnt;
2032eda25e46SAneesh Kumar K.V
20335d385153SJoe Perches p9_debug(P9_DEBUG_9P,
20346e195b0fSDominique Martinet ">>> TXATTRCREATE fid %d name %s size %llu flag %d\n",
20356e195b0fSDominique Martinet fid->fid, name, attr_size, flags);
2036eda25e46SAneesh Kumar K.V clnt = fid->clnt;
2037eda25e46SAneesh Kumar K.V req = p9_client_rpc(clnt, P9_TXATTRCREATE, "dsqd",
2038eda25e46SAneesh Kumar K.V fid->fid, name, attr_size, flags);
2039eda25e46SAneesh Kumar K.V if (IS_ERR(req)) {
2040eda25e46SAneesh Kumar K.V err = PTR_ERR(req);
2041eda25e46SAneesh Kumar K.V goto error;
2042eda25e46SAneesh Kumar K.V }
20435d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RXATTRCREATE fid %d\n", fid->fid);
204467dd8e44SDominique Martinet p9_req_put(clnt, req);
2045eda25e46SAneesh Kumar K.V error:
2046eda25e46SAneesh Kumar K.V return err;
2047eda25e46SAneesh Kumar K.V }
2048eda25e46SAneesh Kumar K.V EXPORT_SYMBOL_GPL(p9_client_xattrcreate);
2049eda25e46SAneesh Kumar K.V
p9_client_readdir(struct p9_fid * fid,char * data,u32 count,u64 offset)20507751bdb3SSripathi Kodi int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
20517751bdb3SSripathi Kodi {
2052abfa034eSAneesh Kumar K.V int err, rsize, non_zc = 0;
20537751bdb3SSripathi Kodi struct p9_client *clnt;
20547751bdb3SSripathi Kodi struct p9_req_t *req;
20557751bdb3SSripathi Kodi char *dataptr;
20564f3b35c1SAl Viro struct kvec kv = {.iov_base = data, .iov_len = count};
20574f3b35c1SAl Viro struct iov_iter to;
20584f3b35c1SAl Viro
2059de4eda9dSAl Viro iov_iter_kvec(&to, ITER_DEST, &kv, 1, count);
20607751bdb3SSripathi Kodi
20615d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
20626e195b0fSDominique Martinet fid->fid, offset, count);
20637751bdb3SSripathi Kodi
20647751bdb3SSripathi Kodi clnt = fid->clnt;
20657751bdb3SSripathi Kodi
20667751bdb3SSripathi Kodi rsize = fid->iounit;
20677751bdb3SSripathi Kodi if (!rsize || rsize > clnt->msize - P9_READDIRHDRSZ)
20687751bdb3SSripathi Kodi rsize = clnt->msize - P9_READDIRHDRSZ;
20697751bdb3SSripathi Kodi
20707751bdb3SSripathi Kodi if (count < rsize)
20717751bdb3SSripathi Kodi rsize = count;
20727751bdb3SSripathi Kodi
2073abfa034eSAneesh Kumar K.V /* Don't bother zerocopy for small IO (< 1024) */
2074abfa034eSAneesh Kumar K.V if (clnt->trans_mod->zc_request && rsize > 1024) {
20756e195b0fSDominique Martinet /* response header len is 11
2076abfa034eSAneesh Kumar K.V * PDU Header(7) + IO Size (4)
2077abfa034eSAneesh Kumar K.V */
20784f3b35c1SAl Viro req = p9_client_zc_rpc(clnt, P9_TREADDIR, &to, NULL, rsize, 0,
20794f3b35c1SAl Viro 11, "dqd", fid->fid, offset, rsize);
20802c66523fSVenkateswararao Jujjuri (JV) } else {
2081abfa034eSAneesh Kumar K.V non_zc = 1;
20822c66523fSVenkateswararao Jujjuri (JV) req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid,
20832c66523fSVenkateswararao Jujjuri (JV) offset, rsize);
20842c66523fSVenkateswararao Jujjuri (JV) }
20857751bdb3SSripathi Kodi if (IS_ERR(req)) {
20867751bdb3SSripathi Kodi err = PTR_ERR(req);
20877751bdb3SSripathi Kodi goto error;
20887751bdb3SSripathi Kodi }
20897751bdb3SSripathi Kodi
2090523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "D", &count, &dataptr);
20917751bdb3SSripathi Kodi if (err) {
2092523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
20937751bdb3SSripathi Kodi goto free_and_error;
20947751bdb3SSripathi Kodi }
209571d6ad08SAl Viro if (rsize < count) {
209671d6ad08SAl Viro pr_err("bogus RREADDIR count (%d > %d)\n", count, rsize);
209771d6ad08SAl Viro count = rsize;
209871d6ad08SAl Viro }
20997751bdb3SSripathi Kodi
21005d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
21017751bdb3SSripathi Kodi
2102abfa034eSAneesh Kumar K.V if (non_zc)
21037751bdb3SSripathi Kodi memmove(data, dataptr, count);
21047751bdb3SSripathi Kodi
210567dd8e44SDominique Martinet p9_req_put(clnt, req);
21067751bdb3SSripathi Kodi return count;
21077751bdb3SSripathi Kodi
21087751bdb3SSripathi Kodi free_and_error:
210967dd8e44SDominique Martinet p9_req_put(clnt, req);
21107751bdb3SSripathi Kodi error:
21117751bdb3SSripathi Kodi return err;
21127751bdb3SSripathi Kodi }
21137751bdb3SSripathi Kodi EXPORT_SYMBOL(p9_client_readdir);
21144b43516aSM. Mohan Kumar
p9_client_mknod_dotl(struct p9_fid * fid,const char * name,int mode,dev_t rdev,kgid_t gid,struct p9_qid * qid)21157880b43bSAl Viro int p9_client_mknod_dotl(struct p9_fid *fid, const char *name, int mode,
2116f791f7c5SEric W. Biederman dev_t rdev, kgid_t gid, struct p9_qid *qid)
21174b43516aSM. Mohan Kumar {
21184b43516aSM. Mohan Kumar int err;
21194b43516aSM. Mohan Kumar struct p9_client *clnt;
21204b43516aSM. Mohan Kumar struct p9_req_t *req;
21214b43516aSM. Mohan Kumar
21224b43516aSM. Mohan Kumar clnt = fid->clnt;
21236e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
21246e195b0fSDominique Martinet ">>> TMKNOD fid %d name %s mode %d major %d minor %d\n",
21256e195b0fSDominique Martinet fid->fid, name, mode, MAJOR(rdev), MINOR(rdev));
2126f791f7c5SEric W. Biederman req = p9_client_rpc(clnt, P9_TMKNOD, "dsdddg", fid->fid, name, mode,
21274b43516aSM. Mohan Kumar MAJOR(rdev), MINOR(rdev), gid);
21284b43516aSM. Mohan Kumar if (IS_ERR(req))
21294b43516aSM. Mohan Kumar return PTR_ERR(req);
21304b43516aSM. Mohan Kumar
2131523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
21324b43516aSM. Mohan Kumar if (err) {
2133523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
21344b43516aSM. Mohan Kumar goto error;
21354b43516aSM. Mohan Kumar }
21366e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P, "<<< RMKNOD qid %x.%llx.%x\n",
21376e195b0fSDominique Martinet qid->type, qid->path, qid->version);
21384b43516aSM. Mohan Kumar
21394b43516aSM. Mohan Kumar error:
214067dd8e44SDominique Martinet p9_req_put(clnt, req);
21414b43516aSM. Mohan Kumar return err;
21424b43516aSM. Mohan Kumar }
21434b43516aSM. Mohan Kumar EXPORT_SYMBOL(p9_client_mknod_dotl);
214401a622bdSM. Mohan Kumar
p9_client_mkdir_dotl(struct p9_fid * fid,const char * name,int mode,kgid_t gid,struct p9_qid * qid)21457880b43bSAl Viro int p9_client_mkdir_dotl(struct p9_fid *fid, const char *name, int mode,
2146f791f7c5SEric W. Biederman kgid_t gid, struct p9_qid *qid)
214701a622bdSM. Mohan Kumar {
214801a622bdSM. Mohan Kumar int err;
214901a622bdSM. Mohan Kumar struct p9_client *clnt;
215001a622bdSM. Mohan Kumar struct p9_req_t *req;
215101a622bdSM. Mohan Kumar
215201a622bdSM. Mohan Kumar clnt = fid->clnt;
21535d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TMKDIR fid %d name %s mode %d gid %d\n",
2154f791f7c5SEric W. Biederman fid->fid, name, mode, from_kgid(&init_user_ns, gid));
21556e195b0fSDominique Martinet req = p9_client_rpc(clnt, P9_TMKDIR, "dsdg",
21566e195b0fSDominique Martinet fid->fid, name, mode, gid);
215701a622bdSM. Mohan Kumar if (IS_ERR(req))
215801a622bdSM. Mohan Kumar return PTR_ERR(req);
215901a622bdSM. Mohan Kumar
2160523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "Q", qid);
216101a622bdSM. Mohan Kumar if (err) {
2162523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
216301a622bdSM. Mohan Kumar goto error;
216401a622bdSM. Mohan Kumar }
21655d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RMKDIR qid %x.%llx.%x\n", qid->type,
21666e195b0fSDominique Martinet qid->path, qid->version);
216701a622bdSM. Mohan Kumar
216801a622bdSM. Mohan Kumar error:
216967dd8e44SDominique Martinet p9_req_put(clnt, req);
217001a622bdSM. Mohan Kumar return err;
217101a622bdSM. Mohan Kumar }
217201a622bdSM. Mohan Kumar EXPORT_SYMBOL(p9_client_mkdir_dotl);
2173a099027cSM. Mohan Kumar
p9_client_lock_dotl(struct p9_fid * fid,struct p9_flock * flock,u8 * status)2174a099027cSM. Mohan Kumar int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
2175a099027cSM. Mohan Kumar {
2176a099027cSM. Mohan Kumar int err;
2177a099027cSM. Mohan Kumar struct p9_client *clnt;
2178a099027cSM. Mohan Kumar struct p9_req_t *req;
2179a099027cSM. Mohan Kumar
2180a099027cSM. Mohan Kumar clnt = fid->clnt;
21816e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
21826e195b0fSDominique Martinet ">>> TLOCK fid %d type %i flags %d start %lld length %lld proc_id %d client_id %s\n",
2183a099027cSM. Mohan Kumar fid->fid, flock->type, flock->flags, flock->start,
2184a099027cSM. Mohan Kumar flock->length, flock->proc_id, flock->client_id);
2185a099027cSM. Mohan Kumar
2186a099027cSM. Mohan Kumar req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
2187a099027cSM. Mohan Kumar flock->flags, flock->start, flock->length,
2188a099027cSM. Mohan Kumar flock->proc_id, flock->client_id);
2189a099027cSM. Mohan Kumar
2190a099027cSM. Mohan Kumar if (IS_ERR(req))
2191a099027cSM. Mohan Kumar return PTR_ERR(req);
2192a099027cSM. Mohan Kumar
2193523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "b", status);
2194a099027cSM. Mohan Kumar if (err) {
2195523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
2196a099027cSM. Mohan Kumar goto error;
2197a099027cSM. Mohan Kumar }
21985d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
2199a099027cSM. Mohan Kumar error:
220067dd8e44SDominique Martinet p9_req_put(clnt, req);
2201a099027cSM. Mohan Kumar return err;
2202a099027cSM. Mohan Kumar }
2203a099027cSM. Mohan Kumar EXPORT_SYMBOL(p9_client_lock_dotl);
22041d769cd1SM. Mohan Kumar
p9_client_getlock_dotl(struct p9_fid * fid,struct p9_getlock * glock)22051d769cd1SM. Mohan Kumar int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
22061d769cd1SM. Mohan Kumar {
22071d769cd1SM. Mohan Kumar int err;
22081d769cd1SM. Mohan Kumar struct p9_client *clnt;
22091d769cd1SM. Mohan Kumar struct p9_req_t *req;
22101d769cd1SM. Mohan Kumar
22111d769cd1SM. Mohan Kumar clnt = fid->clnt;
22126e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
22136e195b0fSDominique Martinet ">>> TGETLOCK fid %d, type %i start %lld length %lld proc_id %d client_id %s\n",
22146e195b0fSDominique Martinet fid->fid, glock->type, glock->start, glock->length,
22156e195b0fSDominique Martinet glock->proc_id, glock->client_id);
22161d769cd1SM. Mohan Kumar
22176e195b0fSDominique Martinet req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid,
22186e195b0fSDominique Martinet glock->type, glock->start, glock->length,
22196e195b0fSDominique Martinet glock->proc_id, glock->client_id);
22201d769cd1SM. Mohan Kumar
22211d769cd1SM. Mohan Kumar if (IS_ERR(req))
22221d769cd1SM. Mohan Kumar return PTR_ERR(req);
22231d769cd1SM. Mohan Kumar
2224523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "bqqds", &glock->type,
22251d769cd1SM. Mohan Kumar &glock->start, &glock->length, &glock->proc_id,
22261d769cd1SM. Mohan Kumar &glock->client_id);
22271d769cd1SM. Mohan Kumar if (err) {
2228523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
22291d769cd1SM. Mohan Kumar goto error;
22301d769cd1SM. Mohan Kumar }
22316e195b0fSDominique Martinet p9_debug(P9_DEBUG_9P,
22326e195b0fSDominique Martinet "<<< RGETLOCK type %i start %lld length %lld proc_id %d client_id %s\n",
22336e195b0fSDominique Martinet glock->type, glock->start, glock->length,
22346e195b0fSDominique Martinet glock->proc_id, glock->client_id);
22351d769cd1SM. Mohan Kumar error:
223667dd8e44SDominique Martinet p9_req_put(clnt, req);
22371d769cd1SM. Mohan Kumar return err;
22381d769cd1SM. Mohan Kumar }
22391d769cd1SM. Mohan Kumar EXPORT_SYMBOL(p9_client_getlock_dotl);
2240329176ccSM. Mohan Kumar
p9_client_readlink(struct p9_fid * fid,char ** target)2241329176ccSM. Mohan Kumar int p9_client_readlink(struct p9_fid *fid, char **target)
2242329176ccSM. Mohan Kumar {
2243329176ccSM. Mohan Kumar int err;
2244329176ccSM. Mohan Kumar struct p9_client *clnt;
2245329176ccSM. Mohan Kumar struct p9_req_t *req;
2246329176ccSM. Mohan Kumar
2247329176ccSM. Mohan Kumar clnt = fid->clnt;
22485d385153SJoe Perches p9_debug(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
2249329176ccSM. Mohan Kumar
2250329176ccSM. Mohan Kumar req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
2251329176ccSM. Mohan Kumar if (IS_ERR(req))
2252329176ccSM. Mohan Kumar return PTR_ERR(req);
2253329176ccSM. Mohan Kumar
2254523adb6cSDominique Martinet err = p9pdu_readf(&req->rc, clnt->proto_version, "s", target);
2255329176ccSM. Mohan Kumar if (err) {
2256523adb6cSDominique Martinet trace_9p_protocol_dump(clnt, &req->rc);
2257329176ccSM. Mohan Kumar goto error;
2258329176ccSM. Mohan Kumar }
22595d385153SJoe Perches p9_debug(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
2260329176ccSM. Mohan Kumar error:
226167dd8e44SDominique Martinet p9_req_put(clnt, req);
2262329176ccSM. Mohan Kumar return err;
2263329176ccSM. Mohan Kumar }
2264329176ccSM. Mohan Kumar EXPORT_SYMBOL(p9_client_readlink);
2265996d5b4dSMatthew Wilcox
p9_client_init(void)2266996d5b4dSMatthew Wilcox int __init p9_client_init(void)
2267996d5b4dSMatthew Wilcox {
2268728356deSTomas Bortoli p9_req_cache = KMEM_CACHE(p9_req_t, SLAB_TYPESAFE_BY_RCU);
2269996d5b4dSMatthew Wilcox return p9_req_cache ? 0 : -ENOMEM;
2270996d5b4dSMatthew Wilcox }
2271996d5b4dSMatthew Wilcox
p9_client_exit(void)2272996d5b4dSMatthew Wilcox void __exit p9_client_exit(void)
2273996d5b4dSMatthew Wilcox {
2274996d5b4dSMatthew Wilcox kmem_cache_destroy(p9_req_cache);
2275996d5b4dSMatthew Wilcox }
2276