xref: /freebsd/sys/fs/p9fs/p9_client.c (revision e97ad33a89a78f55280b0485b3249ee9b907a718)
1*e97ad33aSDoug Rabson /*-
2*e97ad33aSDoug Rabson  * Copyright (c) 2017 Juniper Networks, Inc.
3*e97ad33aSDoug Rabson  * All rights reserved.
4*e97ad33aSDoug Rabson  *
5*e97ad33aSDoug Rabson  * Redistribution and use in source and binary forms, with or without
6*e97ad33aSDoug Rabson  * modification, are permitted provided that the following conditions
7*e97ad33aSDoug Rabson  * are met:
8*e97ad33aSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
9*e97ad33aSDoug Rabson  *	notice, this list of conditions and the following disclaimer.
10*e97ad33aSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
11*e97ad33aSDoug Rabson  *	notice, this list of conditions and the following disclaimer in the
12*e97ad33aSDoug Rabson  *	documentation and/or other materials provided with the distribution.
13*e97ad33aSDoug Rabson  *
14*e97ad33aSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15*e97ad33aSDoug Rabson  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16*e97ad33aSDoug Rabson  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17*e97ad33aSDoug Rabson  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18*e97ad33aSDoug Rabson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19*e97ad33aSDoug Rabson  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20*e97ad33aSDoug Rabson  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21*e97ad33aSDoug Rabson  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22*e97ad33aSDoug Rabson  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23*e97ad33aSDoug Rabson  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24*e97ad33aSDoug Rabson  *
25*e97ad33aSDoug Rabson  */
26*e97ad33aSDoug Rabson 
27*e97ad33aSDoug Rabson /*
28*e97ad33aSDoug Rabson  * This file contains 9P client functions which prepares message to be sent to
29*e97ad33aSDoug Rabson  * the server. Every fileop typically has a function defined here to interact
30*e97ad33aSDoug Rabson  * with the host.
31*e97ad33aSDoug Rabson  */
32*e97ad33aSDoug Rabson 
33*e97ad33aSDoug Rabson #include <vm/uma.h>
34*e97ad33aSDoug Rabson #include <sys/systm.h>
35*e97ad33aSDoug Rabson #include <sys/dirent.h>
36*e97ad33aSDoug Rabson #include <sys/fcntl.h>
37*e97ad33aSDoug Rabson #include <sys/param.h>
38*e97ad33aSDoug Rabson #include <sys/malloc.h>
39*e97ad33aSDoug Rabson #include <sys/mount.h>
40*e97ad33aSDoug Rabson #include <sys/sysctl.h>
41*e97ad33aSDoug Rabson 
42*e97ad33aSDoug Rabson #include <fs/p9fs/p9_client.h>
43*e97ad33aSDoug Rabson #include <fs/p9fs/p9_debug.h>
44*e97ad33aSDoug Rabson #include <fs/p9fs/p9_transport.h>
45*e97ad33aSDoug Rabson 
46*e97ad33aSDoug Rabson #define QEMU_HEADER 7
47*e97ad33aSDoug Rabson #define P9FS_MAX_FID_CNT (1024 * 1024 * 1024)
48*e97ad33aSDoug Rabson #define P9FS_ROOT_FID_NO 2
49*e97ad33aSDoug Rabson #define P9FS_MIN_TAG 1
50*e97ad33aSDoug Rabson #define P9FS_MAX_TAG 65535
51*e97ad33aSDoug Rabson #define WSTAT_SIZE 47
52*e97ad33aSDoug Rabson #define WSTAT_EXTENSION_SIZE 14
53*e97ad33aSDoug Rabson 
54*e97ad33aSDoug Rabson static MALLOC_DEFINE(M_P9CLNT, "p9_client", "p9fs client structure");
55*e97ad33aSDoug Rabson static uma_zone_t p9fs_fid_zone;
56*e97ad33aSDoug Rabson static uma_zone_t p9fs_req_zone;
57*e97ad33aSDoug Rabson static uma_zone_t p9fs_buf_zone;
58*e97ad33aSDoug Rabson 
59*e97ad33aSDoug Rabson SYSCTL_DECL(_vfs_p9fs);
60*e97ad33aSDoug Rabson int p9_debug_level = 0;
61*e97ad33aSDoug Rabson SYSCTL_INT(_vfs_p9fs, OID_AUTO, debug_level, CTLFLAG_RW,
62*e97ad33aSDoug Rabson     &p9_debug_level, 0, "p9fs debug logging");
63*e97ad33aSDoug Rabson 
64*e97ad33aSDoug Rabson static struct p9_req_t *p9_get_request(struct p9_client *c, int *error);
65*e97ad33aSDoug Rabson static struct p9_req_t *p9_client_request(
66*e97ad33aSDoug Rabson     struct p9_client *c, int8_t type, int *error, const char *fmt, ...);
67*e97ad33aSDoug Rabson 
68*e97ad33aSDoug Rabson inline int
69*e97ad33aSDoug Rabson p9_is_proto_dotl(struct p9_client *clnt)
70*e97ad33aSDoug Rabson {
71*e97ad33aSDoug Rabson 
72*e97ad33aSDoug Rabson 	return (clnt->proto_version == p9_proto_2000L);
73*e97ad33aSDoug Rabson }
74*e97ad33aSDoug Rabson 
75*e97ad33aSDoug Rabson inline int
76*e97ad33aSDoug Rabson p9_is_proto_dotu(struct p9_client *clnt)
77*e97ad33aSDoug Rabson {
78*e97ad33aSDoug Rabson 
79*e97ad33aSDoug Rabson 	return (clnt->proto_version == p9_proto_2000u);
80*e97ad33aSDoug Rabson }
81*e97ad33aSDoug Rabson 
82*e97ad33aSDoug Rabson /* Parse mount options into client structure */
83*e97ad33aSDoug Rabson static int
84*e97ad33aSDoug Rabson p9_parse_opts(struct mount  *mp, struct p9_client *clnt)
85*e97ad33aSDoug Rabson {
86*e97ad33aSDoug Rabson 	int error, len;
87*e97ad33aSDoug Rabson 	char *trans;
88*e97ad33aSDoug Rabson 
89*e97ad33aSDoug Rabson 	/*
90*e97ad33aSDoug Rabson 	 * Default to virtio since thats the only transport we have for now.
91*e97ad33aSDoug Rabson 	 */
92*e97ad33aSDoug Rabson 	error = vfs_getopt(mp->mnt_optnew, "trans", (void **)&trans, &len);
93*e97ad33aSDoug Rabson 	if (error == ENOENT)
94*e97ad33aSDoug Rabson 		trans = "virtio";
95*e97ad33aSDoug Rabson 
96*e97ad33aSDoug Rabson 	/* These are defaults for now */
97*e97ad33aSDoug Rabson 	clnt->proto_version = p9_proto_2000L;
98*e97ad33aSDoug Rabson 	clnt->msize = 8192;
99*e97ad33aSDoug Rabson 
100*e97ad33aSDoug Rabson 	/* Get the default trans callback */
101*e97ad33aSDoug Rabson 	clnt->ops = p9_get_trans_by_name(trans);
102*e97ad33aSDoug Rabson 
103*e97ad33aSDoug Rabson 	return (0);
104*e97ad33aSDoug Rabson }
105*e97ad33aSDoug Rabson 
106*e97ad33aSDoug Rabson /* Allocate buffer for sending request and getting responses */
107*e97ad33aSDoug Rabson static struct p9_buffer *
108*e97ad33aSDoug Rabson p9_buffer_alloc(int alloc_msize)
109*e97ad33aSDoug Rabson {
110*e97ad33aSDoug Rabson 	struct p9_buffer *fc;
111*e97ad33aSDoug Rabson 
112*e97ad33aSDoug Rabson 	fc = uma_zalloc(p9fs_buf_zone, M_WAITOK | M_ZERO);
113*e97ad33aSDoug Rabson 	fc->capacity = alloc_msize;
114*e97ad33aSDoug Rabson 	fc->offset = 0;
115*e97ad33aSDoug Rabson 	fc->size = 0;
116*e97ad33aSDoug Rabson 	fc->sdata = (char *)fc + sizeof(struct p9_buffer);
117*e97ad33aSDoug Rabson 
118*e97ad33aSDoug Rabson 	return (fc);
119*e97ad33aSDoug Rabson }
120*e97ad33aSDoug Rabson 
121*e97ad33aSDoug Rabson /* Free memory used by request and response buffers */
122*e97ad33aSDoug Rabson static void
123*e97ad33aSDoug Rabson p9_buffer_free(struct p9_buffer **buf)
124*e97ad33aSDoug Rabson {
125*e97ad33aSDoug Rabson 
126*e97ad33aSDoug Rabson 	/* Free the sdata buffers first, then the whole structure*/
127*e97ad33aSDoug Rabson 	uma_zfree(p9fs_buf_zone, *buf);
128*e97ad33aSDoug Rabson 	*buf = NULL;
129*e97ad33aSDoug Rabson }
130*e97ad33aSDoug Rabson 
131*e97ad33aSDoug Rabson /* Free the request */
132*e97ad33aSDoug Rabson static void
133*e97ad33aSDoug Rabson p9_free_req(struct p9_client *clnt, struct p9_req_t *req)
134*e97ad33aSDoug Rabson {
135*e97ad33aSDoug Rabson 
136*e97ad33aSDoug Rabson 	if (req->tc != NULL) {
137*e97ad33aSDoug Rabson 		if (req->tc->tag != P9_NOTAG)
138*e97ad33aSDoug Rabson 			p9_tag_destroy(clnt, req->tc->tag);
139*e97ad33aSDoug Rabson 		p9_buffer_free(&req->tc);
140*e97ad33aSDoug Rabson 	}
141*e97ad33aSDoug Rabson 
142*e97ad33aSDoug Rabson 	if (req->rc != NULL)
143*e97ad33aSDoug Rabson 		p9_buffer_free(&req->rc);
144*e97ad33aSDoug Rabson 
145*e97ad33aSDoug Rabson 	uma_zfree(p9fs_req_zone, req);
146*e97ad33aSDoug Rabson }
147*e97ad33aSDoug Rabson 
148*e97ad33aSDoug Rabson /* Allocate a request by tag */
149*e97ad33aSDoug Rabson static struct p9_req_t *
150*e97ad33aSDoug Rabson p9_get_request(struct p9_client *clnt, int *error)
151*e97ad33aSDoug Rabson {
152*e97ad33aSDoug Rabson 	struct p9_req_t *req;
153*e97ad33aSDoug Rabson 	int alloc_msize;
154*e97ad33aSDoug Rabson 	uint16_t tag;
155*e97ad33aSDoug Rabson 
156*e97ad33aSDoug Rabson 	alloc_msize = P9FS_MTU;
157*e97ad33aSDoug Rabson 
158*e97ad33aSDoug Rabson 	req = uma_zalloc(p9fs_req_zone, M_WAITOK | M_ZERO);
159*e97ad33aSDoug Rabson 	req->tc = p9_buffer_alloc(alloc_msize);
160*e97ad33aSDoug Rabson 	req->rc = p9_buffer_alloc(alloc_msize);
161*e97ad33aSDoug Rabson 
162*e97ad33aSDoug Rabson 	tag = p9_tag_create(clnt);
163*e97ad33aSDoug Rabson 	if (tag == P9_NOTAG) {
164*e97ad33aSDoug Rabson 		*error = EAGAIN;
165*e97ad33aSDoug Rabson 		req->tc->tag = P9_NOTAG;
166*e97ad33aSDoug Rabson 		p9_free_req(clnt, req);
167*e97ad33aSDoug Rabson 		return (NULL);
168*e97ad33aSDoug Rabson 	}
169*e97ad33aSDoug Rabson 	req->tc->tag = tag;
170*e97ad33aSDoug Rabson 	return (req);
171*e97ad33aSDoug Rabson }
172*e97ad33aSDoug Rabson 
173*e97ad33aSDoug Rabson /* Parse header arguments of the response buffer */
174*e97ad33aSDoug Rabson static int
175*e97ad33aSDoug Rabson p9_parse_receive(struct p9_buffer *buf, struct p9_client *clnt)
176*e97ad33aSDoug Rabson {
177*e97ad33aSDoug Rabson 	int8_t type;
178*e97ad33aSDoug Rabson 	int16_t tag;
179*e97ad33aSDoug Rabson 	int32_t size;
180*e97ad33aSDoug Rabson 	int error;
181*e97ad33aSDoug Rabson 
182*e97ad33aSDoug Rabson 	buf->offset = 0;
183*e97ad33aSDoug Rabson 
184*e97ad33aSDoug Rabson 	/* This value is set by QEMU for the header.*/
185*e97ad33aSDoug Rabson 	if (buf->size == 0)
186*e97ad33aSDoug Rabson 		buf->size = QEMU_HEADER;
187*e97ad33aSDoug Rabson 
188*e97ad33aSDoug Rabson 	/* This is the initial header. Parse size, type, and tag .*/
189*e97ad33aSDoug Rabson 	error = p9_buf_readf(buf, 0, "dbw", &size, &type, &tag);
190*e97ad33aSDoug Rabson 	if (error != 0)
191*e97ad33aSDoug Rabson 		goto out;
192*e97ad33aSDoug Rabson 
193*e97ad33aSDoug Rabson 	buf->size = size;
194*e97ad33aSDoug Rabson 	buf->id = type;
195*e97ad33aSDoug Rabson 	buf->tag = tag;
196*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: size=%d type: %d tag: %d\n",
197*e97ad33aSDoug Rabson 	    __func__, buf->size, buf->id, buf->tag);
198*e97ad33aSDoug Rabson out:
199*e97ad33aSDoug Rabson 	return (error);
200*e97ad33aSDoug Rabson }
201*e97ad33aSDoug Rabson 
202*e97ad33aSDoug Rabson /* Check 9P response for any errors returned and process it */
203*e97ad33aSDoug Rabson static int
204*e97ad33aSDoug Rabson p9_client_check_return(struct p9_client *c, struct p9_req_t *req)
205*e97ad33aSDoug Rabson {
206*e97ad33aSDoug Rabson 	int error;
207*e97ad33aSDoug Rabson 	int ecode;
208*e97ad33aSDoug Rabson 	char *ename;
209*e97ad33aSDoug Rabson 
210*e97ad33aSDoug Rabson 	/* Check what we have in the receive bufer .*/
211*e97ad33aSDoug Rabson 	error = p9_parse_receive(req->rc, c);
212*e97ad33aSDoug Rabson 	if (error != 0)
213*e97ad33aSDoug Rabson 		goto out;
214*e97ad33aSDoug Rabson 
215*e97ad33aSDoug Rabson 	/*
216*e97ad33aSDoug Rabson 	 * No error, We are done with the preprocessing. Return to the caller
217*e97ad33aSDoug Rabson 	 * and process the actual data.
218*e97ad33aSDoug Rabson 	 */
219*e97ad33aSDoug Rabson 	if (req->rc->id != P9PROTO_RERROR && req->rc->id != P9PROTO_RLERROR)
220*e97ad33aSDoug Rabson 		return (0);
221*e97ad33aSDoug Rabson 
222*e97ad33aSDoug Rabson 	/*
223*e97ad33aSDoug Rabson 	 * Interpreting the error is done in different ways for Linux and
224*e97ad33aSDoug Rabson 	 * Unix version. Make sure you interpret it right.
225*e97ad33aSDoug Rabson 	 */
226*e97ad33aSDoug Rabson 	if (req->rc->id == P9PROTO_RERROR) {
227*e97ad33aSDoug Rabson 	        error = p9_buf_readf(req->rc, c->proto_version, "s?d", &ename, &ecode);
228*e97ad33aSDoug Rabson 	} else if (req->rc->id == P9PROTO_RLERROR) {
229*e97ad33aSDoug Rabson 	        error = p9_buf_readf(req->rc, c->proto_version, "d", &ecode);
230*e97ad33aSDoug Rabson 	} else {
231*e97ad33aSDoug Rabson 		goto out;
232*e97ad33aSDoug Rabson 	}
233*e97ad33aSDoug Rabson 	if (error != 0)
234*e97ad33aSDoug Rabson 		goto out;
235*e97ad33aSDoug Rabson 
236*e97ad33aSDoug Rabson 	/* if there was an ecode error make this the err now */
237*e97ad33aSDoug Rabson 	error = ecode;
238*e97ad33aSDoug Rabson 
239*e97ad33aSDoug Rabson 	/*
240*e97ad33aSDoug Rabson 	 * Note this is still not completely an error, as lookups for files
241*e97ad33aSDoug Rabson 	 * not present can hit this and return. Hence it is made a debug print.
242*e97ad33aSDoug Rabson 	 */
243*e97ad33aSDoug Rabson 	if (error != 0) {
244*e97ad33aSDoug Rabson 	        if (req->rc->id == P9PROTO_RERROR) {
245*e97ad33aSDoug Rabson 		        P9_DEBUG(PROTO, "RERROR error %d ename %s\n",
246*e97ad33aSDoug Rabson 			    error, ename);
247*e97ad33aSDoug Rabson 	        } else if (req->rc->id == P9PROTO_RLERROR) {
248*e97ad33aSDoug Rabson 		        P9_DEBUG(PROTO, "RLERROR error %d\n", error);
249*e97ad33aSDoug Rabson 		}
250*e97ad33aSDoug Rabson 	}
251*e97ad33aSDoug Rabson 
252*e97ad33aSDoug Rabson 	if (req->rc->id == P9PROTO_RERROR) {
253*e97ad33aSDoug Rabson 	        free(ename, M_TEMP);
254*e97ad33aSDoug Rabson 	}
255*e97ad33aSDoug Rabson 	return (error);
256*e97ad33aSDoug Rabson 
257*e97ad33aSDoug Rabson out:
258*e97ad33aSDoug Rabson 	P9_DEBUG(ERROR, "couldn't parse receive buffer error%d\n", error);
259*e97ad33aSDoug Rabson 	return (error);
260*e97ad33aSDoug Rabson }
261*e97ad33aSDoug Rabson 
262*e97ad33aSDoug Rabson /* State machine changing helpers */
263*e97ad33aSDoug Rabson void p9_client_disconnect(struct p9_client *clnt)
264*e97ad33aSDoug Rabson {
265*e97ad33aSDoug Rabson 
266*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: clnt %p\n", __func__, clnt);
267*e97ad33aSDoug Rabson 	clnt->trans_status = P9FS_DISCONNECT;
268*e97ad33aSDoug Rabson }
269*e97ad33aSDoug Rabson 
270*e97ad33aSDoug Rabson void p9_client_begin_disconnect(struct p9_client *clnt)
271*e97ad33aSDoug Rabson {
272*e97ad33aSDoug Rabson 
273*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: clnt %p\n", __func__, clnt);
274*e97ad33aSDoug Rabson 	clnt->trans_status = P9FS_BEGIN_DISCONNECT;
275*e97ad33aSDoug Rabson }
276*e97ad33aSDoug Rabson 
277*e97ad33aSDoug Rabson static struct p9_req_t *
278*e97ad33aSDoug Rabson p9_client_prepare_req(struct p9_client *c, int8_t type,
279*e97ad33aSDoug Rabson     int req_size, int *error, const char *fmt, __va_list ap)
280*e97ad33aSDoug Rabson {
281*e97ad33aSDoug Rabson 	struct p9_req_t *req;
282*e97ad33aSDoug Rabson 
283*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: client %p op %d\n", __func__, c, type);
284*e97ad33aSDoug Rabson 
285*e97ad33aSDoug Rabson 	/*
286*e97ad33aSDoug Rabson 	 * Before we start with the request, check if its possible to finish
287*e97ad33aSDoug Rabson 	 * this request. We are allowed to submit the request only if there
288*e97ad33aSDoug Rabson 	 * are no close sessions happening or else there can be race. If the
289*e97ad33aSDoug Rabson 	 * status is Disconnected, we stop any requests coming in after that.
290*e97ad33aSDoug Rabson 	 */
291*e97ad33aSDoug Rabson 	if (c->trans_status == P9FS_DISCONNECT) {
292*e97ad33aSDoug Rabson 		*error = EIO;
293*e97ad33aSDoug Rabson 		return (NULL);
294*e97ad33aSDoug Rabson 	}
295*e97ad33aSDoug Rabson 
296*e97ad33aSDoug Rabson 	/* Allow only cleanup clunk messages once teardown has started. */
297*e97ad33aSDoug Rabson 	if ((c->trans_status == P9FS_BEGIN_DISCONNECT) &&
298*e97ad33aSDoug Rabson 	    (type != P9PROTO_TCLUNK)) {
299*e97ad33aSDoug Rabson 		*error = EIO;
300*e97ad33aSDoug Rabson 		return (NULL);
301*e97ad33aSDoug Rabson 	}
302*e97ad33aSDoug Rabson 
303*e97ad33aSDoug Rabson 	/* Allocate buffer for transferring and receiving data from host */
304*e97ad33aSDoug Rabson 	req = p9_get_request(c, error);
305*e97ad33aSDoug Rabson 	if (*error != 0) {
306*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: request allocation failed.\n", __func__);
307*e97ad33aSDoug Rabson 		return (NULL);
308*e97ad33aSDoug Rabson 	}
309*e97ad33aSDoug Rabson 
310*e97ad33aSDoug Rabson 	/* Marshall the data according to QEMU standards */
311*e97ad33aSDoug Rabson 	*error = p9_buf_prepare(req->tc, type);
312*e97ad33aSDoug Rabson 	if (*error != 0) {
313*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_prepare failed: %d\n",
314*e97ad33aSDoug Rabson 		    __func__, *error);
315*e97ad33aSDoug Rabson 		goto out;
316*e97ad33aSDoug Rabson 	}
317*e97ad33aSDoug Rabson 
318*e97ad33aSDoug Rabson 	*error = p9_buf_vwritef(req->tc, c->proto_version, fmt, ap);
319*e97ad33aSDoug Rabson 	if (*error != 0) {
320*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_vwrite failed: %d\n",
321*e97ad33aSDoug Rabson 		    __func__, *error);
322*e97ad33aSDoug Rabson 		goto out;
323*e97ad33aSDoug Rabson 	}
324*e97ad33aSDoug Rabson 
325*e97ad33aSDoug Rabson 	*error = p9_buf_finalize(c, req->tc);
326*e97ad33aSDoug Rabson 	if (*error != 0) {
327*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_finalize failed: %d \n",
328*e97ad33aSDoug Rabson 		    __func__, *error);
329*e97ad33aSDoug Rabson 		goto out;
330*e97ad33aSDoug Rabson 	}
331*e97ad33aSDoug Rabson 
332*e97ad33aSDoug Rabson 	return (req);
333*e97ad33aSDoug Rabson out:
334*e97ad33aSDoug Rabson 	p9_free_req(c, req);
335*e97ad33aSDoug Rabson 	return (NULL);
336*e97ad33aSDoug Rabson }
337*e97ad33aSDoug Rabson 
338*e97ad33aSDoug Rabson /*
339*e97ad33aSDoug Rabson  * Issue a request and wait for response. The routine takes care of preparing
340*e97ad33aSDoug Rabson  * the 9P request header to be sent, parsing and checking for error conditions
341*e97ad33aSDoug Rabson  * in the received buffer. It returns the request structure.
342*e97ad33aSDoug Rabson  */
343*e97ad33aSDoug Rabson static struct p9_req_t *
344*e97ad33aSDoug Rabson p9_client_request(struct p9_client *c, int8_t type, int *error,
345*e97ad33aSDoug Rabson     const char *fmt, ...)
346*e97ad33aSDoug Rabson {
347*e97ad33aSDoug Rabson 	va_list ap;
348*e97ad33aSDoug Rabson 	struct p9_req_t *req;
349*e97ad33aSDoug Rabson 
350*e97ad33aSDoug Rabson 	va_start(ap, fmt);
351*e97ad33aSDoug Rabson 	req = p9_client_prepare_req(c, type, c->msize, error, fmt, ap);
352*e97ad33aSDoug Rabson 	va_end(ap);
353*e97ad33aSDoug Rabson 
354*e97ad33aSDoug Rabson 	/* Issue with allocation of request buffer */
355*e97ad33aSDoug Rabson 	if (*error != 0)
356*e97ad33aSDoug Rabson 		return (NULL);
357*e97ad33aSDoug Rabson 
358*e97ad33aSDoug Rabson 	/* Call into the transport for submission. */
359*e97ad33aSDoug Rabson 	*error = c->ops->request(c->handle, req);
360*e97ad33aSDoug Rabson 	if (*error != 0) {
361*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: failed: %d\n", __func__, *error);
362*e97ad33aSDoug Rabson 		goto out;
363*e97ad33aSDoug Rabson 	}
364*e97ad33aSDoug Rabson 
365*e97ad33aSDoug Rabson 	/*
366*e97ad33aSDoug Rabson 	 * Before we return, pre process the header and the rc buffer before
367*e97ad33aSDoug Rabson 	 * calling into the protocol infra to analyze the data in rc.
368*e97ad33aSDoug Rabson 	 */
369*e97ad33aSDoug Rabson 	*error = p9_client_check_return(c, req);
370*e97ad33aSDoug Rabson 	if (*error != 0)
371*e97ad33aSDoug Rabson 		goto out;
372*e97ad33aSDoug Rabson 
373*e97ad33aSDoug Rabson 	return (req);
374*e97ad33aSDoug Rabson out:
375*e97ad33aSDoug Rabson 	p9_free_req(c, req);
376*e97ad33aSDoug Rabson 	return (NULL);
377*e97ad33aSDoug Rabson }
378*e97ad33aSDoug Rabson 
379*e97ad33aSDoug Rabson /* Setup tag contents and structure  */
380*e97ad33aSDoug Rabson uint16_t
381*e97ad33aSDoug Rabson p9_tag_create(struct p9_client *clnt)
382*e97ad33aSDoug Rabson {
383*e97ad33aSDoug Rabson         int tag;
384*e97ad33aSDoug Rabson 
385*e97ad33aSDoug Rabson         tag = alloc_unr(&clnt->tagpool);
386*e97ad33aSDoug Rabson         P9_DEBUG(LPROTO, "%s: clnt %p: tag %d\n", __func__, clnt, tag);
387*e97ad33aSDoug Rabson 
388*e97ad33aSDoug Rabson         /* Alloc_unr returning -1 is an error for no units left */
389*e97ad33aSDoug Rabson         if (tag == -1) {
390*e97ad33aSDoug Rabson                 return (P9_NOTAG);
391*e97ad33aSDoug Rabson         }
392*e97ad33aSDoug Rabson         return (tag);
393*e97ad33aSDoug Rabson }
394*e97ad33aSDoug Rabson 
395*e97ad33aSDoug Rabson /* Clean up tag structures */
396*e97ad33aSDoug Rabson void
397*e97ad33aSDoug Rabson p9_tag_destroy(struct p9_client *clnt, uint16_t tag)
398*e97ad33aSDoug Rabson {
399*e97ad33aSDoug Rabson 
400*e97ad33aSDoug Rabson         P9_DEBUG(LPROTO, "%s: clnt %p: tag %d\n", __func__, clnt, tag);
401*e97ad33aSDoug Rabson 
402*e97ad33aSDoug Rabson         /* Release to the pool */
403*e97ad33aSDoug Rabson         free_unr(&clnt->tagpool, tag);
404*e97ad33aSDoug Rabson }
405*e97ad33aSDoug Rabson 
406*e97ad33aSDoug Rabson /* Allocate a new fid from the fidpool */
407*e97ad33aSDoug Rabson struct p9_fid *
408*e97ad33aSDoug Rabson p9_fid_create(struct p9_client *clnt)
409*e97ad33aSDoug Rabson {
410*e97ad33aSDoug Rabson 	struct p9_fid *fid;
411*e97ad33aSDoug Rabson 
412*e97ad33aSDoug Rabson 
413*e97ad33aSDoug Rabson 	fid = uma_zalloc(p9fs_fid_zone, M_WAITOK | M_ZERO);
414*e97ad33aSDoug Rabson 	fid->fid = alloc_unr(&clnt->fidpool);
415*e97ad33aSDoug Rabson 	P9_DEBUG(LPROTO, "%s: fid %d\n", __func__, fid->fid);
416*e97ad33aSDoug Rabson 
417*e97ad33aSDoug Rabson 	/* Alloc_unr returning -1 is an error for no units left */
418*e97ad33aSDoug Rabson 	if (fid->fid == -1) {
419*e97ad33aSDoug Rabson 		uma_zfree(p9fs_fid_zone, fid);
420*e97ad33aSDoug Rabson 		return (NULL);
421*e97ad33aSDoug Rabson 	}
422*e97ad33aSDoug Rabson 	fid->mode = -1;
423*e97ad33aSDoug Rabson 	fid->uid = -1;
424*e97ad33aSDoug Rabson 	fid->clnt = clnt;
425*e97ad33aSDoug Rabson 
426*e97ad33aSDoug Rabson 	return (fid);
427*e97ad33aSDoug Rabson }
428*e97ad33aSDoug Rabson 
429*e97ad33aSDoug Rabson /* Free the fid by releasing it to fidpool */
430*e97ad33aSDoug Rabson void
431*e97ad33aSDoug Rabson p9_fid_destroy(struct p9_fid *fid)
432*e97ad33aSDoug Rabson {
433*e97ad33aSDoug Rabson 	struct p9_client *clnt;
434*e97ad33aSDoug Rabson 
435*e97ad33aSDoug Rabson 	P9_DEBUG(LPROTO, "%s: fid %d\n", __func__, fid->fid);
436*e97ad33aSDoug Rabson 	clnt = fid->clnt;
437*e97ad33aSDoug Rabson 	/* Release to the pool */
438*e97ad33aSDoug Rabson 	free_unr(&clnt->fidpool, fid->fid);
439*e97ad33aSDoug Rabson 	uma_zfree(p9fs_fid_zone, fid);
440*e97ad33aSDoug Rabson }
441*e97ad33aSDoug Rabson 
442*e97ad33aSDoug Rabson /* Request the version of 9P protocol */
443*e97ad33aSDoug Rabson int
444*e97ad33aSDoug Rabson p9_client_version(struct p9_client *c)
445*e97ad33aSDoug Rabson {
446*e97ad33aSDoug Rabson 	int error;
447*e97ad33aSDoug Rabson 	struct p9_req_t *req;
448*e97ad33aSDoug Rabson 	char *version;
449*e97ad33aSDoug Rabson 	int msize;
450*e97ad33aSDoug Rabson 
451*e97ad33aSDoug Rabson 	error = 0;
452*e97ad33aSDoug Rabson 
453*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TVERSION msize %d protocol %d\n",
454*e97ad33aSDoug Rabson 	    c->msize, c->proto_version);
455*e97ad33aSDoug Rabson 
456*e97ad33aSDoug Rabson 	switch (c->proto_version) {
457*e97ad33aSDoug Rabson 	case p9_proto_2000L:
458*e97ad33aSDoug Rabson 		req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
459*e97ad33aSDoug Rabson 		    c->msize, "9P2000.L");
460*e97ad33aSDoug Rabson 		break;
461*e97ad33aSDoug Rabson 	case p9_proto_2000u:
462*e97ad33aSDoug Rabson 		req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
463*e97ad33aSDoug Rabson 		    c->msize, "9P2000.u");
464*e97ad33aSDoug Rabson 		break;
465*e97ad33aSDoug Rabson 	case p9_proto_legacy:
466*e97ad33aSDoug Rabson 		req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
467*e97ad33aSDoug Rabson 		    c->msize, "9P2000");
468*e97ad33aSDoug Rabson 		break;
469*e97ad33aSDoug Rabson 	default:
470*e97ad33aSDoug Rabson 		return (EINVAL);
471*e97ad33aSDoug Rabson 	}
472*e97ad33aSDoug Rabson 
473*e97ad33aSDoug Rabson 	/*  Always return the relevant error code */
474*e97ad33aSDoug Rabson 	if (error != 0)
475*e97ad33aSDoug Rabson 		return (error);
476*e97ad33aSDoug Rabson 
477*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, c->proto_version, "ds", &msize, &version);
478*e97ad33aSDoug Rabson 	if (error != 0) {
479*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: version error: %d\n", __func__, error);
480*e97ad33aSDoug Rabson 		goto out;
481*e97ad33aSDoug Rabson 	}
482*e97ad33aSDoug Rabson 
483*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RVERSION msize %d %s\n", msize, version);
484*e97ad33aSDoug Rabson 
485*e97ad33aSDoug Rabson 	if (!strncmp(version, "9P2000.L", 8))
486*e97ad33aSDoug Rabson 		c->proto_version = p9_proto_2000L;
487*e97ad33aSDoug Rabson 	else if (!strncmp(version, "9P2000.u", 8))
488*e97ad33aSDoug Rabson 		c->proto_version = p9_proto_2000u;
489*e97ad33aSDoug Rabson 	else if (!strncmp(version, "9P2000", 6))
490*e97ad33aSDoug Rabson 		c->proto_version = p9_proto_legacy;
491*e97ad33aSDoug Rabson 	else {
492*e97ad33aSDoug Rabson 		error = ENOMEM;
493*e97ad33aSDoug Rabson 		goto out;
494*e97ad33aSDoug Rabson 	}
495*e97ad33aSDoug Rabson 
496*e97ad33aSDoug Rabson 	/* limit the msize .*/
497*e97ad33aSDoug Rabson 	if (msize < c->msize)
498*e97ad33aSDoug Rabson 		c->msize = msize;
499*e97ad33aSDoug Rabson out:
500*e97ad33aSDoug Rabson 	p9_free_req(c, req);
501*e97ad33aSDoug Rabson 	return (error);
502*e97ad33aSDoug Rabson }
503*e97ad33aSDoug Rabson 
504*e97ad33aSDoug Rabson /*
505*e97ad33aSDoug Rabson  * Initialize zones for different things. This is called from Init module
506*e97ad33aSDoug Rabson  * so that we just have them initalized once.
507*e97ad33aSDoug Rabson  */
508*e97ad33aSDoug Rabson void
509*e97ad33aSDoug Rabson p9_init_zones(void)
510*e97ad33aSDoug Rabson {
511*e97ad33aSDoug Rabson 
512*e97ad33aSDoug Rabson 	/* Create the request and the fid zones */
513*e97ad33aSDoug Rabson 	p9fs_fid_zone = uma_zcreate("p9fs fid zone",
514*e97ad33aSDoug Rabson 	    sizeof(struct p9_fid), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
515*e97ad33aSDoug Rabson 
516*e97ad33aSDoug Rabson 	/* Create the request and the fid zones */
517*e97ad33aSDoug Rabson 	p9fs_req_zone = uma_zcreate("p9fs req zone",
518*e97ad33aSDoug Rabson 	    sizeof(struct p9_req_t), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
519*e97ad33aSDoug Rabson 
520*e97ad33aSDoug Rabson 	/* Create the buffer zone */
521*e97ad33aSDoug Rabson 	p9fs_buf_zone = uma_zcreate("p9fs buf zone",
522*e97ad33aSDoug Rabson 	    sizeof(struct p9_buffer) + P9FS_MTU, NULL, NULL,
523*e97ad33aSDoug Rabson 	    NULL, NULL, UMA_ALIGN_PTR, 0);
524*e97ad33aSDoug Rabson }
525*e97ad33aSDoug Rabson 
526*e97ad33aSDoug Rabson void
527*e97ad33aSDoug Rabson p9_destroy_zones(void)
528*e97ad33aSDoug Rabson {
529*e97ad33aSDoug Rabson 
530*e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_fid_zone);
531*e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_req_zone);
532*e97ad33aSDoug Rabson 	uma_zdestroy(p9fs_buf_zone);
533*e97ad33aSDoug Rabson }
534*e97ad33aSDoug Rabson 
535*e97ad33aSDoug Rabson /* Return the client to the session in the FS to hold it */
536*e97ad33aSDoug Rabson struct p9_client *
537*e97ad33aSDoug Rabson p9_client_create(struct mount *mp, int *error, const char *mount_tag)
538*e97ad33aSDoug Rabson {
539*e97ad33aSDoug Rabson 	struct p9_client *clnt;
540*e97ad33aSDoug Rabson 
541*e97ad33aSDoug Rabson 	clnt = malloc(sizeof(struct p9_client), M_P9CLNT, M_WAITOK | M_ZERO);
542*e97ad33aSDoug Rabson 	mtx_init(&clnt->clnt_mtx, "p9clnt", NULL, MTX_DEF);
543*e97ad33aSDoug Rabson 
544*e97ad33aSDoug Rabson 	/* Parse should have set trans_mod */
545*e97ad33aSDoug Rabson 	*error = p9_parse_opts(mp, clnt);
546*e97ad33aSDoug Rabson 	if (*error != 0)
547*e97ad33aSDoug Rabson 		goto out;
548*e97ad33aSDoug Rabson 
549*e97ad33aSDoug Rabson 	if (clnt->ops == NULL) {
550*e97ad33aSDoug Rabson 		*error = EINVAL;
551*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: no transport\n", __func__);
552*e97ad33aSDoug Rabson 		goto out;
553*e97ad33aSDoug Rabson 	}
554*e97ad33aSDoug Rabson 
555*e97ad33aSDoug Rabson 	/* All the structures from here are protected by the lock clnt_mtx */
556*e97ad33aSDoug Rabson 	init_unrhdr(&clnt->fidpool, P9FS_ROOT_FID_NO, P9FS_MAX_FID_CNT,
557*e97ad33aSDoug Rabson 	    &clnt->clnt_mtx);
558*e97ad33aSDoug Rabson 	init_unrhdr(&clnt->tagpool, P9FS_MIN_TAG, P9FS_MAX_TAG,
559*e97ad33aSDoug Rabson 	    &clnt->clnt_mtx);
560*e97ad33aSDoug Rabson 
561*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: clnt %p trans %p msize %d protocol %d\n",
562*e97ad33aSDoug Rabson 	    __func__, clnt, clnt->ops, clnt->msize, clnt->proto_version);
563*e97ad33aSDoug Rabson 
564*e97ad33aSDoug Rabson 	*error = clnt->ops->create(mount_tag, &clnt->handle);
565*e97ad33aSDoug Rabson 	if (*error != 0) {
566*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: transport create failed .%d \n",
567*e97ad33aSDoug Rabson 		    __func__, *error);
568*e97ad33aSDoug Rabson 		goto out;
569*e97ad33aSDoug Rabson 	}
570*e97ad33aSDoug Rabson 	clnt->trans_status = P9FS_CONNECT;
571*e97ad33aSDoug Rabson 
572*e97ad33aSDoug Rabson 	*error = p9_client_version(clnt);
573*e97ad33aSDoug Rabson 	if (*error != 0)
574*e97ad33aSDoug Rabson 		goto out;
575*e97ad33aSDoug Rabson 
576*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: client creation succeeded.\n", __func__);
577*e97ad33aSDoug Rabson 	return (clnt);
578*e97ad33aSDoug Rabson out:
579*e97ad33aSDoug Rabson 	free(clnt, M_P9CLNT);
580*e97ad33aSDoug Rabson 	return (NULL);
581*e97ad33aSDoug Rabson }
582*e97ad33aSDoug Rabson 
583*e97ad33aSDoug Rabson /* Destroy the client by destroying associated fidpool and tagpool */
584*e97ad33aSDoug Rabson void
585*e97ad33aSDoug Rabson p9_client_destroy(struct p9_client *clnt)
586*e97ad33aSDoug Rabson {
587*e97ad33aSDoug Rabson 
588*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s: client %p\n", __func__, clnt);
589*e97ad33aSDoug Rabson 	clnt->ops->close(clnt->handle);
590*e97ad33aSDoug Rabson 
591*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s : Destroying fidpool\n", __func__);
592*e97ad33aSDoug Rabson 	clear_unrhdr(&clnt->fidpool);
593*e97ad33aSDoug Rabson 
594*e97ad33aSDoug Rabson 	P9_DEBUG(TRANS, "%s : Destroying tagpool\n", __func__);
595*e97ad33aSDoug Rabson 	clear_unrhdr(&clnt->tagpool);
596*e97ad33aSDoug Rabson 
597*e97ad33aSDoug Rabson 	free(clnt, M_P9CLNT);
598*e97ad33aSDoug Rabson }
599*e97ad33aSDoug Rabson 
600*e97ad33aSDoug Rabson /*
601*e97ad33aSDoug Rabson  * Attach a user to the filesystem. Create a fid for that user to access
602*e97ad33aSDoug Rabson  * the root of the filesystem.
603*e97ad33aSDoug Rabson  */
604*e97ad33aSDoug Rabson struct p9_fid *
605*e97ad33aSDoug Rabson p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
606*e97ad33aSDoug Rabson     const char *uname, uid_t n_uname, const char *aname, int *error)
607*e97ad33aSDoug Rabson {
608*e97ad33aSDoug Rabson 	struct p9_req_t *req;
609*e97ad33aSDoug Rabson 	struct p9_fid *fid;
610*e97ad33aSDoug Rabson 	struct p9_qid qid;
611*e97ad33aSDoug Rabson 
612*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TATTACH uname=%s aname=%s, n_uname=%d\n",
613*e97ad33aSDoug Rabson 	    uname, aname, n_uname);
614*e97ad33aSDoug Rabson 	fid = p9_fid_create(clnt);
615*e97ad33aSDoug Rabson 	if (fid == NULL) {
616*e97ad33aSDoug Rabson 		*error = ENOMEM;
617*e97ad33aSDoug Rabson 		return (NULL);
618*e97ad33aSDoug Rabson 	}
619*e97ad33aSDoug Rabson 	fid->uid = n_uname;
620*e97ad33aSDoug Rabson 
621*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TATTACH, error, "ddssd", fid->fid,
622*e97ad33aSDoug Rabson 	    P9PROTO_NOFID, uname, aname, n_uname);
623*e97ad33aSDoug Rabson 	if (*error != 0)
624*e97ad33aSDoug Rabson 		goto out;
625*e97ad33aSDoug Rabson 
626*e97ad33aSDoug Rabson 	*error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
627*e97ad33aSDoug Rabson 	if (*error != 0) {
628*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d \n",
629*e97ad33aSDoug Rabson 		    __func__, *error);
630*e97ad33aSDoug Rabson 		goto out;
631*e97ad33aSDoug Rabson 	}
632*e97ad33aSDoug Rabson 
633*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RATTACH qid %x.%llx.%x\n",
634*e97ad33aSDoug Rabson 	    qid.type, (unsigned long long)qid.path, qid.version);
635*e97ad33aSDoug Rabson 
636*e97ad33aSDoug Rabson 	memmove(&fid->qid, &qid, sizeof(struct p9_qid));
637*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
638*e97ad33aSDoug Rabson 
639*e97ad33aSDoug Rabson 	return (fid);
640*e97ad33aSDoug Rabson out:
641*e97ad33aSDoug Rabson 	if (req != NULL)
642*e97ad33aSDoug Rabson 		p9_free_req(clnt, req);
643*e97ad33aSDoug Rabson 	if (fid != NULL)
644*e97ad33aSDoug Rabson 		p9_fid_destroy(fid);
645*e97ad33aSDoug Rabson 
646*e97ad33aSDoug Rabson 	return (NULL);
647*e97ad33aSDoug Rabson }
648*e97ad33aSDoug Rabson 
649*e97ad33aSDoug Rabson /* Delete a file/directory. Corresponding fid will be cluncked too */
650*e97ad33aSDoug Rabson int
651*e97ad33aSDoug Rabson p9_client_remove(struct p9_fid *fid)
652*e97ad33aSDoug Rabson {
653*e97ad33aSDoug Rabson 	int error;
654*e97ad33aSDoug Rabson 	struct p9_client *clnt;
655*e97ad33aSDoug Rabson 	struct p9_req_t *req;
656*e97ad33aSDoug Rabson 
657*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TREMOVE fid %d\n", fid->fid);
658*e97ad33aSDoug Rabson 
659*e97ad33aSDoug Rabson 	error = 0;
660*e97ad33aSDoug Rabson 	clnt = fid->clnt;
661*e97ad33aSDoug Rabson 
662*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TREMOVE, &error, "d", fid->fid);
663*e97ad33aSDoug Rabson 	if (error != 0) {
664*e97ad33aSDoug Rabson 		P9_DEBUG(PROTO, "RREMOVE fid %d\n", fid->fid);
665*e97ad33aSDoug Rabson 		return (error);
666*e97ad33aSDoug Rabson 	}
667*e97ad33aSDoug Rabson 
668*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
669*e97ad33aSDoug Rabson 	return (error);
670*e97ad33aSDoug Rabson }
671*e97ad33aSDoug Rabson 
672*e97ad33aSDoug Rabson /* Inform the file server that the current file represented by fid is no longer
673*e97ad33aSDoug Rabson  * needed by the client. Any allocated fid on the server needs a clunk to be
674*e97ad33aSDoug Rabson  * destroyed.
675*e97ad33aSDoug Rabson  */
676*e97ad33aSDoug Rabson int
677*e97ad33aSDoug Rabson p9_client_clunk(struct p9_fid *fid)
678*e97ad33aSDoug Rabson {
679*e97ad33aSDoug Rabson 	int error;
680*e97ad33aSDoug Rabson 	struct p9_client *clnt;
681*e97ad33aSDoug Rabson 	struct p9_req_t *req;
682*e97ad33aSDoug Rabson 
683*e97ad33aSDoug Rabson 	error = 0;
684*e97ad33aSDoug Rabson 
685*e97ad33aSDoug Rabson 	if (fid == NULL) {
686*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: clunk with NULL fid is bad\n", __func__);
687*e97ad33aSDoug Rabson 		return (0);
688*e97ad33aSDoug Rabson 	}
689*e97ad33aSDoug Rabson 
690*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TCLUNK fid %d \n", fid->fid);
691*e97ad33aSDoug Rabson 
692*e97ad33aSDoug Rabson 	clnt = fid->clnt;
693*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TCLUNK, &error, "d", fid->fid);
694*e97ad33aSDoug Rabson 	if (req != NULL) {
695*e97ad33aSDoug Rabson 		P9_DEBUG(PROTO, "RCLUNK fid %d\n", fid->fid);
696*e97ad33aSDoug Rabson 		p9_free_req(clnt, req);
697*e97ad33aSDoug Rabson 	}
698*e97ad33aSDoug Rabson 
699*e97ad33aSDoug Rabson 	p9_fid_destroy(fid);
700*e97ad33aSDoug Rabson 	return (error);
701*e97ad33aSDoug Rabson }
702*e97ad33aSDoug Rabson 
703*e97ad33aSDoug Rabson /*
704*e97ad33aSDoug Rabson  * Client_walk is for searching any component name in a directory.
705*e97ad33aSDoug Rabson  * This is usually called on lookups. Also when we need a new open fid
706*e97ad33aSDoug Rabson  * as 9p needs to have an open fid for every file to fileops, we call this
707*e97ad33aSDoug Rabson  * validate the component of the file and return the newfid(openfid) created.
708*e97ad33aSDoug Rabson  */
709*e97ad33aSDoug Rabson struct p9_fid *
710*e97ad33aSDoug Rabson p9_client_walk(struct p9_fid *oldfid, uint16_t nwnames, char **wnames,
711*e97ad33aSDoug Rabson     int clone, int *error)
712*e97ad33aSDoug Rabson {
713*e97ad33aSDoug Rabson 	struct p9_client *clnt;
714*e97ad33aSDoug Rabson 	struct p9_fid *fid;
715*e97ad33aSDoug Rabson 	struct p9_qid *wqids;
716*e97ad33aSDoug Rabson 	struct p9_req_t *req;
717*e97ad33aSDoug Rabson 	uint16_t nwqids, count;
718*e97ad33aSDoug Rabson 
719*e97ad33aSDoug Rabson 	clnt = oldfid->clnt;
720*e97ad33aSDoug Rabson 	wqids = NULL;
721*e97ad33aSDoug Rabson 	nwqids = 0;
722*e97ad33aSDoug Rabson 
723*e97ad33aSDoug Rabson 	/*
724*e97ad33aSDoug Rabson 	 *  Before, we go and create fid, make sure we are not tearing
725*e97ad33aSDoug Rabson 	 *  down. Only then we create.
726*e97ad33aSDoug Rabson 	 *  Allow only cleanup clunk messages once we are starting to teardown.
727*e97ad33aSDoug Rabson 	 */
728*e97ad33aSDoug Rabson 	if (clnt->trans_status != P9FS_CONNECT) {
729*e97ad33aSDoug Rabson 		*error = EIO;
730*e97ad33aSDoug Rabson 		return (NULL);
731*e97ad33aSDoug Rabson 	}
732*e97ad33aSDoug Rabson 
733*e97ad33aSDoug Rabson 	if (clone) {
734*e97ad33aSDoug Rabson 		fid = p9_fid_create(clnt);
735*e97ad33aSDoug Rabson 		if (fid == NULL) {
736*e97ad33aSDoug Rabson 			*error = ENOMEM;
737*e97ad33aSDoug Rabson 			return (NULL);
738*e97ad33aSDoug Rabson 		}
739*e97ad33aSDoug Rabson 		fid->uid = oldfid->uid;
740*e97ad33aSDoug Rabson 	} else
741*e97ad33aSDoug Rabson 		fid = oldfid;
742*e97ad33aSDoug Rabson 
743*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TWALK fids %d,%d nwnames %u wname %s\n",
744*e97ad33aSDoug Rabson 	    oldfid->fid, fid->fid, nwnames,
745*e97ad33aSDoug Rabson 	    wnames != NULL ? wnames[nwnames-1] : NULL);
746*e97ad33aSDoug Rabson 
747*e97ad33aSDoug Rabson 	/*
748*e97ad33aSDoug Rabson 	 * The newfid is for the component in search. We are preallocating as
749*e97ad33aSDoug Rabson 	 * qemu on other side allocates or returns a fid if it sees a match
750*e97ad33aSDoug Rabson 	 */
751*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TWALK, error, "ddT", oldfid->fid,
752*e97ad33aSDoug Rabson 	    fid->fid, wnames, nwnames);
753*e97ad33aSDoug Rabson 	if (*error != 0) {
754*e97ad33aSDoug Rabson 		if (fid != oldfid)
755*e97ad33aSDoug Rabson 			p9_fid_destroy(fid);
756*e97ad33aSDoug Rabson 		return (NULL);
757*e97ad33aSDoug Rabson 	}
758*e97ad33aSDoug Rabson 
759*e97ad33aSDoug Rabson 	*error = p9_buf_readf(req->rc, clnt->proto_version, "R", &nwqids,
760*e97ad33aSDoug Rabson 	    &wqids);
761*e97ad33aSDoug Rabson 	if (*error != 0)
762*e97ad33aSDoug Rabson 		goto out;
763*e97ad33aSDoug Rabson 
764*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RWALK nwqid %d:\n", nwqids);
765*e97ad33aSDoug Rabson 
766*e97ad33aSDoug Rabson 	if (nwqids != nwnames) {
767*e97ad33aSDoug Rabson 		*error = ENOENT;
768*e97ad33aSDoug Rabson 		goto out;
769*e97ad33aSDoug Rabson 	}
770*e97ad33aSDoug Rabson 
771*e97ad33aSDoug Rabson 	for (count = 0; count < nwqids; count++)
772*e97ad33aSDoug Rabson 		P9_DEBUG(TRANS, "%s: [%d] %x.%llx.%x\n",
773*e97ad33aSDoug Rabson 		    __func__, count, wqids[count].type,
774*e97ad33aSDoug Rabson 		    (unsigned long long)wqids[count].path,
775*e97ad33aSDoug Rabson 		    wqids[count].version);
776*e97ad33aSDoug Rabson 
777*e97ad33aSDoug Rabson 	if (nwnames)
778*e97ad33aSDoug Rabson 		memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
779*e97ad33aSDoug Rabson 	else
780*e97ad33aSDoug Rabson 		fid->qid = oldfid->qid;
781*e97ad33aSDoug Rabson 
782*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
783*e97ad33aSDoug Rabson 	free(wqids, M_TEMP);
784*e97ad33aSDoug Rabson 	return (fid);
785*e97ad33aSDoug Rabson 
786*e97ad33aSDoug Rabson out:
787*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
788*e97ad33aSDoug Rabson 	if (wqids)
789*e97ad33aSDoug Rabson 		free(wqids, M_TEMP);
790*e97ad33aSDoug Rabson 	if (fid && fid != oldfid)
791*e97ad33aSDoug Rabson 		p9_client_clunk(fid);
792*e97ad33aSDoug Rabson 	return (NULL);
793*e97ad33aSDoug Rabson }
794*e97ad33aSDoug Rabson 
795*e97ad33aSDoug Rabson /* Open a file with given fid and mode */
796*e97ad33aSDoug Rabson int
797*e97ad33aSDoug Rabson p9_client_open(struct p9_fid *fid, int mode)
798*e97ad33aSDoug Rabson {
799*e97ad33aSDoug Rabson 	int error, mtu;
800*e97ad33aSDoug Rabson 	struct p9_client *clnt;
801*e97ad33aSDoug Rabson 	struct p9_req_t *req;
802*e97ad33aSDoug Rabson 
803*e97ad33aSDoug Rabson 	error = 0;
804*e97ad33aSDoug Rabson 	clnt = fid->clnt;
805*e97ad33aSDoug Rabson 	mtu = 0;
806*e97ad33aSDoug Rabson 
807*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "%s fid %d mode %d\n",
808*e97ad33aSDoug Rabson 	    p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN",
809*e97ad33aSDoug Rabson 	    fid->fid, mode);
810*e97ad33aSDoug Rabson 
811*e97ad33aSDoug Rabson 	if (fid->mode != -1)
812*e97ad33aSDoug Rabson 		return (EINVAL);
813*e97ad33aSDoug Rabson 
814*e97ad33aSDoug Rabson 	if (p9_is_proto_dotl(clnt))
815*e97ad33aSDoug Rabson 		req = p9_client_request(clnt, P9PROTO_TLOPEN, &error, "dd",
816*e97ad33aSDoug Rabson 		    fid->fid, mode);
817*e97ad33aSDoug Rabson 	else
818*e97ad33aSDoug Rabson 		req = p9_client_request(clnt, P9PROTO_TOPEN, &error, "db",
819*e97ad33aSDoug Rabson 		    fid->fid, mode);
820*e97ad33aSDoug Rabson 
821*e97ad33aSDoug Rabson 	if (error != 0)
822*e97ad33aSDoug Rabson 		return (error);
823*e97ad33aSDoug Rabson 
824*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &fid->qid,
825*e97ad33aSDoug Rabson 	    &mtu);
826*e97ad33aSDoug Rabson 	if (error != 0)
827*e97ad33aSDoug Rabson 		goto out;
828*e97ad33aSDoug Rabson 
829*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "%s qid %x.%llx.%x mtu %x\n",
830*e97ad33aSDoug Rabson 	    p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN",
831*e97ad33aSDoug Rabson 	    (fid->qid).type, (unsigned long long)(fid->qid).path,
832*e97ad33aSDoug Rabson 	    (fid->qid).version, mtu);
833*e97ad33aSDoug Rabson 
834*e97ad33aSDoug Rabson 	fid->mode = mode;
835*e97ad33aSDoug Rabson 	fid->mtu = mtu;
836*e97ad33aSDoug Rabson out:
837*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
838*e97ad33aSDoug Rabson 	return (error);
839*e97ad33aSDoug Rabson }
840*e97ad33aSDoug Rabson 
841*e97ad33aSDoug Rabson /* Request to get directory entries */
842*e97ad33aSDoug Rabson int
843*e97ad33aSDoug Rabson p9_client_readdir(struct p9_fid *fid, char *data, uint64_t offset,
844*e97ad33aSDoug Rabson     uint32_t count)
845*e97ad33aSDoug Rabson {
846*e97ad33aSDoug Rabson 	int error;
847*e97ad33aSDoug Rabson 	uint32_t rsize;
848*e97ad33aSDoug Rabson 	struct p9_client *clnt;
849*e97ad33aSDoug Rabson 	struct p9_req_t *req;
850*e97ad33aSDoug Rabson 	char *dataptr;
851*e97ad33aSDoug Rabson 
852*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TREADDIR fid %d offset %llu count %d\n",
853*e97ad33aSDoug Rabson 	    fid->fid, (unsigned long long) offset, count);
854*e97ad33aSDoug Rabson 
855*e97ad33aSDoug Rabson 	error = 0;
856*e97ad33aSDoug Rabson 	rsize = fid->mtu;
857*e97ad33aSDoug Rabson 	clnt = fid->clnt;
858*e97ad33aSDoug Rabson 
859*e97ad33aSDoug Rabson 	if (rsize == 0 || rsize > clnt->msize)
860*e97ad33aSDoug Rabson 		rsize = clnt->msize;
861*e97ad33aSDoug Rabson 
862*e97ad33aSDoug Rabson 	if (count < rsize)
863*e97ad33aSDoug Rabson 		rsize = count;
864*e97ad33aSDoug Rabson 
865*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TREADDIR, &error, "dqd",
866*e97ad33aSDoug Rabson 	    fid->fid, offset, rsize);
867*e97ad33aSDoug Rabson 
868*e97ad33aSDoug Rabson 	if (error != 0) {
869*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: couldn't allocate req in client_readdir\n",
870*e97ad33aSDoug Rabson 			__func__);
871*e97ad33aSDoug Rabson 		return (-error);
872*e97ad33aSDoug Rabson 	}
873*e97ad33aSDoug Rabson 
874*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
875*e97ad33aSDoug Rabson 	    &dataptr);
876*e97ad33aSDoug Rabson 	if (error != 0) {
877*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p0_buf_readf failed: %d\n",
878*e97ad33aSDoug Rabson 		    __func__, error);
879*e97ad33aSDoug Rabson 		p9_free_req(clnt, req);
880*e97ad33aSDoug Rabson 		return (-error);
881*e97ad33aSDoug Rabson 	}
882*e97ad33aSDoug Rabson 
883*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RREADDIR count %u\n", count);
884*e97ad33aSDoug Rabson 
885*e97ad33aSDoug Rabson 	/* Copy back the data into the input buffer. */
886*e97ad33aSDoug Rabson 	memmove(data, dataptr, count);
887*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
888*e97ad33aSDoug Rabson 	return (count);
889*e97ad33aSDoug Rabson }
890*e97ad33aSDoug Rabson 
891*e97ad33aSDoug Rabson /*
892*e97ad33aSDoug Rabson  * Read count bytes from offset for the file fid into the character
893*e97ad33aSDoug Rabson  * buffer data. This buffer is handed over to p9fs to process into user
894*e97ad33aSDoug Rabson  * buffers. Note that this function typically returns the number of bytes read
895*e97ad33aSDoug Rabson  * so in case of an error we return -error so that we can distinguish between
896*e97ad33aSDoug Rabson  * error codes and bytes.
897*e97ad33aSDoug Rabson  */
898*e97ad33aSDoug Rabson int
899*e97ad33aSDoug Rabson p9_client_read(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
900*e97ad33aSDoug Rabson {
901*e97ad33aSDoug Rabson 	struct p9_client *clnt;
902*e97ad33aSDoug Rabson 	struct p9_req_t *req;
903*e97ad33aSDoug Rabson 	char *dataptr;
904*e97ad33aSDoug Rabson 	int error, rsize;
905*e97ad33aSDoug Rabson 
906*e97ad33aSDoug Rabson 	clnt = fid->clnt;
907*e97ad33aSDoug Rabson 	rsize = fid->mtu;
908*e97ad33aSDoug Rabson 	error = 0;
909*e97ad33aSDoug Rabson 
910*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TREAD fid %d offset %llu %u\n",
911*e97ad33aSDoug Rabson 	    fid->fid, (unsigned long long) offset, count);
912*e97ad33aSDoug Rabson 
913*e97ad33aSDoug Rabson 	if (!rsize || rsize > clnt->msize)
914*e97ad33aSDoug Rabson 		rsize = clnt->msize;
915*e97ad33aSDoug Rabson 
916*e97ad33aSDoug Rabson 	if (count < rsize)
917*e97ad33aSDoug Rabson 		rsize = count;
918*e97ad33aSDoug Rabson 
919*e97ad33aSDoug Rabson 	/* At this stage, we only have 8K buffers so only transfer */
920*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TREAD, &error, "dqd", fid->fid,
921*e97ad33aSDoug Rabson 	    offset, rsize);
922*e97ad33aSDoug Rabson 	if (error != 0) {
923*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: failed allocate request\n", __func__);
924*e97ad33aSDoug Rabson 		return (-error);
925*e97ad33aSDoug Rabson 	}
926*e97ad33aSDoug Rabson 
927*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
928*e97ad33aSDoug Rabson 	    &dataptr);
929*e97ad33aSDoug Rabson 	if (error != 0) {
930*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d\n",
931*e97ad33aSDoug Rabson 		    __func__, error);
932*e97ad33aSDoug Rabson 		goto out;
933*e97ad33aSDoug Rabson 	}
934*e97ad33aSDoug Rabson 
935*e97ad33aSDoug Rabson 	if (rsize < count) {
936*e97ad33aSDoug Rabson 		P9_DEBUG(PROTO, "RREAD count (%d > %d)\n", count, rsize);
937*e97ad33aSDoug Rabson 		count = rsize;
938*e97ad33aSDoug Rabson 	}
939*e97ad33aSDoug Rabson 
940*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RREAD count %d\n", count);
941*e97ad33aSDoug Rabson 
942*e97ad33aSDoug Rabson 	if (count == 0) {
943*e97ad33aSDoug Rabson 		error = -EIO;
944*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: EIO error in client_read \n", __func__);
945*e97ad33aSDoug Rabson 		goto out;
946*e97ad33aSDoug Rabson 	}
947*e97ad33aSDoug Rabson 
948*e97ad33aSDoug Rabson 	/* Copy back the data into the input buffer. */
949*e97ad33aSDoug Rabson 	memmove(data, dataptr, count);
950*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
951*e97ad33aSDoug Rabson 	return (count);
952*e97ad33aSDoug Rabson out:
953*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
954*e97ad33aSDoug Rabson 	return (-error);
955*e97ad33aSDoug Rabson }
956*e97ad33aSDoug Rabson 
957*e97ad33aSDoug Rabson /*
958*e97ad33aSDoug Rabson  * Write count bytes from buffer to the offset for the file fid
959*e97ad33aSDoug Rabson  * Note that this function typically returns the number of bytes written
960*e97ad33aSDoug Rabson  * so in case of an error we return -error so that we can distinguish between
961*e97ad33aSDoug Rabson  * error codes and bytes.
962*e97ad33aSDoug Rabson  */
963*e97ad33aSDoug Rabson 
964*e97ad33aSDoug Rabson int
965*e97ad33aSDoug Rabson p9_client_write(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
966*e97ad33aSDoug Rabson {
967*e97ad33aSDoug Rabson 	struct p9_client *clnt;
968*e97ad33aSDoug Rabson 	struct p9_req_t *req;
969*e97ad33aSDoug Rabson 	int ret, error, rsize;
970*e97ad33aSDoug Rabson 
971*e97ad33aSDoug Rabson 	clnt = fid->clnt;
972*e97ad33aSDoug Rabson 	rsize = fid->mtu;
973*e97ad33aSDoug Rabson 	ret = 0;
974*e97ad33aSDoug Rabson 	error = 0;
975*e97ad33aSDoug Rabson 
976*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TWRITE fid %d offset %llu  %u\n",
977*e97ad33aSDoug Rabson 	    fid->fid, (unsigned long long) offset, count);
978*e97ad33aSDoug Rabson 
979*e97ad33aSDoug Rabson 	if (!rsize || rsize > clnt->msize)
980*e97ad33aSDoug Rabson 		rsize = clnt->msize;
981*e97ad33aSDoug Rabson 
982*e97ad33aSDoug Rabson 	/* Limit set by Qemu ,8168 */
983*e97ad33aSDoug Rabson 	if (count > rsize) {
984*e97ad33aSDoug Rabson 		count = rsize;
985*e97ad33aSDoug Rabson 	}
986*e97ad33aSDoug Rabson 
987*e97ad33aSDoug Rabson 	/*
988*e97ad33aSDoug Rabson 	 * Doing the Data blob instead. If at all we add the zerocopy, we can
989*e97ad33aSDoug Rabson 	 * change it to uio direct copy
990*e97ad33aSDoug Rabson 	 */
991*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TWRITE, &error, "dqD", fid->fid,
992*e97ad33aSDoug Rabson 	    offset, count, data);
993*e97ad33aSDoug Rabson 	if (error != 0) {
994*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: failed allocate request: %d\n",
995*e97ad33aSDoug Rabson 		    __func__, error);
996*e97ad33aSDoug Rabson 		return (-error);
997*e97ad33aSDoug Rabson 	}
998*e97ad33aSDoug Rabson 
999*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "d", &ret);
1000*e97ad33aSDoug Rabson 	if (error != 0) {
1001*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: p9_buf_readf error: %d\n",
1002*e97ad33aSDoug Rabson 		    __func__, error);
1003*e97ad33aSDoug Rabson 		goto out;
1004*e97ad33aSDoug Rabson 	}
1005*e97ad33aSDoug Rabson 
1006*e97ad33aSDoug Rabson 	if (count < ret) {
1007*e97ad33aSDoug Rabson 		P9_DEBUG(PROTO, "RWRITE count (%d > %d)\n", count, ret);
1008*e97ad33aSDoug Rabson 		ret = count;
1009*e97ad33aSDoug Rabson 	}
1010*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RWRITE count %d\n", ret);
1011*e97ad33aSDoug Rabson 
1012*e97ad33aSDoug Rabson 	if (count == 0) {
1013*e97ad33aSDoug Rabson 		error = EIO;
1014*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: EIO error\n", __func__);
1015*e97ad33aSDoug Rabson 		goto out;
1016*e97ad33aSDoug Rabson 	}
1017*e97ad33aSDoug Rabson 
1018*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1019*e97ad33aSDoug Rabson 	return (ret);
1020*e97ad33aSDoug Rabson out:
1021*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1022*e97ad33aSDoug Rabson 	return (-error);
1023*e97ad33aSDoug Rabson }
1024*e97ad33aSDoug Rabson 
1025*e97ad33aSDoug Rabson 
1026*e97ad33aSDoug Rabson /* Create file under directory fid, with name, permissions, mode. */
1027*e97ad33aSDoug Rabson int
1028*e97ad33aSDoug Rabson p9_client_file_create(struct p9_fid *fid, char *name, uint32_t perm, int mode,
1029*e97ad33aSDoug Rabson     char *extension)
1030*e97ad33aSDoug Rabson {
1031*e97ad33aSDoug Rabson 	int error;
1032*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1033*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1034*e97ad33aSDoug Rabson 	struct p9_qid qid;
1035*e97ad33aSDoug Rabson 	int mtu;
1036*e97ad33aSDoug Rabson 
1037*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TCREATE fid %d name %s perm %d mode %d\n",
1038*e97ad33aSDoug Rabson 	    fid->fid, name, perm, mode);
1039*e97ad33aSDoug Rabson 
1040*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1041*e97ad33aSDoug Rabson 	error = 0;
1042*e97ad33aSDoug Rabson 
1043*e97ad33aSDoug Rabson 	if (fid->mode != -1)
1044*e97ad33aSDoug Rabson 		return (EINVAL);
1045*e97ad33aSDoug Rabson 
1046*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TCREATE, &error, "dsdb?s",
1047*e97ad33aSDoug Rabson 	    fid->fid, name, perm, mode, extension);
1048*e97ad33aSDoug Rabson 	if (error != 0)
1049*e97ad33aSDoug Rabson 		return (error);
1050*e97ad33aSDoug Rabson 
1051*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &qid, &mtu);
1052*e97ad33aSDoug Rabson 	if (error != 0)
1053*e97ad33aSDoug Rabson 		goto out;
1054*e97ad33aSDoug Rabson 
1055*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RCREATE qid %x.%jx.%x mtu %x\n",
1056*e97ad33aSDoug Rabson 	    qid.type, (uintmax_t)qid.path, qid.version, mtu);
1057*e97ad33aSDoug Rabson 	fid->mode = mode;
1058*e97ad33aSDoug Rabson 	fid->mtu = mtu;
1059*e97ad33aSDoug Rabson 
1060*e97ad33aSDoug Rabson out:
1061*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1062*e97ad33aSDoug Rabson 	return (error);
1063*e97ad33aSDoug Rabson }
1064*e97ad33aSDoug Rabson 
1065*e97ad33aSDoug Rabson /* Request file system information of the file system */
1066*e97ad33aSDoug Rabson int
1067*e97ad33aSDoug Rabson p9_client_statfs(struct p9_fid *fid, struct p9_statfs *stat)
1068*e97ad33aSDoug Rabson {
1069*e97ad33aSDoug Rabson 	int error;
1070*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1071*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1072*e97ad33aSDoug Rabson 
1073*e97ad33aSDoug Rabson 	error = 0;
1074*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1075*e97ad33aSDoug Rabson 
1076*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TSTATFS fid %d\n", fid->fid);
1077*e97ad33aSDoug Rabson 
1078*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TSTATFS, &error, "d", fid->fid);
1079*e97ad33aSDoug Rabson 	if (error != 0) {
1080*e97ad33aSDoug Rabson 		return (error);
1081*e97ad33aSDoug Rabson 	}
1082*e97ad33aSDoug Rabson 
1083*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "ddqqqqqqd",
1084*e97ad33aSDoug Rabson 	    &stat->type, &stat->bsize, &stat->blocks, &stat->bfree,
1085*e97ad33aSDoug Rabson 	    &stat->bavail, &stat->files, &stat->ffree, &stat->fsid,
1086*e97ad33aSDoug Rabson 	    &stat->namelen);
1087*e97ad33aSDoug Rabson 
1088*e97ad33aSDoug Rabson 	if (error != 0)
1089*e97ad33aSDoug Rabson 		goto out;
1090*e97ad33aSDoug Rabson 
1091*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RSTATFS fid %d type 0x%jx bsize %ju "
1092*e97ad33aSDoug Rabson 	    "blocks %ju bfree %ju bavail %ju files %ju ffree %ju "
1093*e97ad33aSDoug Rabson 	    "fsid %ju namelen %ju\n",
1094*e97ad33aSDoug Rabson 	    fid->fid, (uintmax_t)stat->type,
1095*e97ad33aSDoug Rabson 	    (uintmax_t)stat->bsize, (uintmax_t)stat->blocks,
1096*e97ad33aSDoug Rabson 	    (uintmax_t)stat->bfree, (uintmax_t)stat->bavail,
1097*e97ad33aSDoug Rabson 	    (uintmax_t)stat->files, (uintmax_t)stat->ffree,
1098*e97ad33aSDoug Rabson 	    (uintmax_t)stat->fsid, (uintmax_t)stat->namelen);
1099*e97ad33aSDoug Rabson 
1100*e97ad33aSDoug Rabson out:
1101*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1102*e97ad33aSDoug Rabson 	return (error);
1103*e97ad33aSDoug Rabson }
1104*e97ad33aSDoug Rabson 
1105*e97ad33aSDoug Rabson /* Rename file referenced by the fid */
1106*e97ad33aSDoug Rabson int
1107*e97ad33aSDoug Rabson p9_client_renameat(struct p9_fid *oldfid, char *oldname, struct p9_fid *newfid,
1108*e97ad33aSDoug Rabson     char *newname)
1109*e97ad33aSDoug Rabson {
1110*e97ad33aSDoug Rabson 	int error;
1111*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1112*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1113*e97ad33aSDoug Rabson 
1114*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TRENAMEAT oldfid %d oldname %s newfid %d newfid %s",
1115*e97ad33aSDoug Rabson 	    oldfid->fid, oldname, newfid->fid, newname);
1116*e97ad33aSDoug Rabson 
1117*e97ad33aSDoug Rabson 	error = 0;
1118*e97ad33aSDoug Rabson 	clnt = oldfid->clnt;
1119*e97ad33aSDoug Rabson 
1120*e97ad33aSDoug Rabson 	/*
1121*e97ad33aSDoug Rabson 	 * we are calling the request with TRENAMEAT tag and not TRENAME with
1122*e97ad33aSDoug Rabson 	 * the 9p protocol version 9p2000.u as the QEMU version supports this
1123*e97ad33aSDoug Rabson 	 * version of renaming
1124*e97ad33aSDoug Rabson 	 */
1125*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TRENAMEAT, &error, "dsds",
1126*e97ad33aSDoug Rabson 	    oldfid->fid, oldname, newfid->fid, newname);
1127*e97ad33aSDoug Rabson 
1128*e97ad33aSDoug Rabson 	if (error != 0)
1129*e97ad33aSDoug Rabson 		return (error);
1130*e97ad33aSDoug Rabson 
1131*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1132*e97ad33aSDoug Rabson 	return (error);
1133*e97ad33aSDoug Rabson }
1134*e97ad33aSDoug Rabson 
1135*e97ad33aSDoug Rabson /* Request to create symbolic link */
1136*e97ad33aSDoug Rabson int
1137*e97ad33aSDoug Rabson p9_create_symlink(struct p9_fid *fid, char *name, char *symtgt, gid_t gid)
1138*e97ad33aSDoug Rabson {
1139*e97ad33aSDoug Rabson 	int error;
1140*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1141*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1142*e97ad33aSDoug Rabson 	struct p9_qid qid;
1143*e97ad33aSDoug Rabson 
1144*e97ad33aSDoug Rabson 	error = 0;
1145*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1146*e97ad33aSDoug Rabson 
1147*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TSYMLINK fid %d name %s\n", fid->fid, name);
1148*e97ad33aSDoug Rabson 
1149*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TSYMLINK, &error, "dssd",
1150*e97ad33aSDoug Rabson 	    fid->fid, name, symtgt, gid);
1151*e97ad33aSDoug Rabson 
1152*e97ad33aSDoug Rabson 	if (error != 0)
1153*e97ad33aSDoug Rabson 		return (error);
1154*e97ad33aSDoug Rabson 
1155*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
1156*e97ad33aSDoug Rabson 	if (error != 0) {
1157*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
1158*e97ad33aSDoug Rabson 		return (error);
1159*e97ad33aSDoug Rabson 	}
1160*e97ad33aSDoug Rabson 
1161*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RSYMLINK qid %x.%jx.%x\n",
1162*e97ad33aSDoug Rabson 	    qid.type, (uintmax_t)qid.path, qid.version);
1163*e97ad33aSDoug Rabson 
1164*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1165*e97ad33aSDoug Rabson 	return (0);
1166*e97ad33aSDoug Rabson }
1167*e97ad33aSDoug Rabson 
1168*e97ad33aSDoug Rabson /* Request to create hard link */
1169*e97ad33aSDoug Rabson int
1170*e97ad33aSDoug Rabson p9_create_hardlink(struct p9_fid *dfid, struct p9_fid *oldfid, char *name)
1171*e97ad33aSDoug Rabson {
1172*e97ad33aSDoug Rabson 	int error;
1173*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1174*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1175*e97ad33aSDoug Rabson 
1176*e97ad33aSDoug Rabson 	error = 0;
1177*e97ad33aSDoug Rabson 	clnt = dfid->clnt;
1178*e97ad33aSDoug Rabson 
1179*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TLINK dfid %d oldfid %d name %s\n",
1180*e97ad33aSDoug Rabson 	    dfid->fid, oldfid->fid, name);
1181*e97ad33aSDoug Rabson 
1182*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TLINK, &error, "dds", dfid->fid,
1183*e97ad33aSDoug Rabson 	    oldfid->fid, name);
1184*e97ad33aSDoug Rabson 	if (error != 0)
1185*e97ad33aSDoug Rabson 		return (error);
1186*e97ad33aSDoug Rabson 
1187*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1188*e97ad33aSDoug Rabson 	return (0);
1189*e97ad33aSDoug Rabson }
1190*e97ad33aSDoug Rabson 
1191*e97ad33aSDoug Rabson /* Request to read contents of symbolic link */
1192*e97ad33aSDoug Rabson int
1193*e97ad33aSDoug Rabson p9_readlink(struct p9_fid *fid, char **target)
1194*e97ad33aSDoug Rabson {
1195*e97ad33aSDoug Rabson 	int error;
1196*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1197*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1198*e97ad33aSDoug Rabson 
1199*e97ad33aSDoug Rabson 	error = 0;
1200*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1201*e97ad33aSDoug Rabson 
1202*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TREADLINK fid %d\n", fid->fid);
1203*e97ad33aSDoug Rabson 
1204*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TREADLINK, &error, "d", fid->fid);
1205*e97ad33aSDoug Rabson 	if (error != 0)
1206*e97ad33aSDoug Rabson 		return (error);
1207*e97ad33aSDoug Rabson 
1208*e97ad33aSDoug Rabson 	error = p9_buf_readf(req->rc, clnt->proto_version, "s", target);
1209*e97ad33aSDoug Rabson 	if (error != 0) {
1210*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
1211*e97ad33aSDoug Rabson 		return (error);
1212*e97ad33aSDoug Rabson 	}
1213*e97ad33aSDoug Rabson 
1214*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RREADLINK target %s \n", *target);
1215*e97ad33aSDoug Rabson 
1216*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1217*e97ad33aSDoug Rabson 	return (0);
1218*e97ad33aSDoug Rabson }
1219*e97ad33aSDoug Rabson 
1220*e97ad33aSDoug Rabson /* Get file attributes of the file referenced by the fid */
1221*e97ad33aSDoug Rabson int
1222*e97ad33aSDoug Rabson p9_client_getattr(struct p9_fid *fid, struct p9_stat_dotl *stat_dotl,
1223*e97ad33aSDoug Rabson     uint64_t request_mask)
1224*e97ad33aSDoug Rabson {
1225*e97ad33aSDoug Rabson 	int err;
1226*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1227*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1228*e97ad33aSDoug Rabson 
1229*e97ad33aSDoug Rabson 	err = 0;
1230*e97ad33aSDoug Rabson 
1231*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TGETATTR fid %d mask %ju\n",
1232*e97ad33aSDoug Rabson 	    fid->fid, (uintmax_t)request_mask);
1233*e97ad33aSDoug Rabson 
1234*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1235*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TGETATTR, &err, "dq", fid->fid,
1236*e97ad33aSDoug Rabson 	    request_mask);
1237*e97ad33aSDoug Rabson 	if (req == NULL) {
1238*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: allocation failed %d", __func__, err);
1239*e97ad33aSDoug Rabson 		goto error;
1240*e97ad33aSDoug Rabson 	}
1241*e97ad33aSDoug Rabson 
1242*e97ad33aSDoug Rabson 	err = p9_buf_readf(req->rc, clnt->proto_version, "A", stat_dotl);
1243*e97ad33aSDoug Rabson 	if (err != 0) {
1244*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, err);
1245*e97ad33aSDoug Rabson 		goto error;
1246*e97ad33aSDoug Rabson 	}
1247*e97ad33aSDoug Rabson 
1248*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1249*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "RGETATTR fid %d qid %x.%jx.%x st_mode %8.8x "
1250*e97ad33aSDoug Rabson 	    "uid %d gid %d nlink %ju rdev %jx st_size %jx blksize %ju "
1251*e97ad33aSDoug Rabson 	    "blocks %ju st_atime_sec %ju, st_atime_nsec %ju "
1252*e97ad33aSDoug Rabson 	    "st_mtime_sec %ju, st_mtime_nsec %ju st_ctime_sec %ju "
1253*e97ad33aSDoug Rabson 	    "st_ctime_nsec %ju st_btime_sec %ju, st_btime_nsec %ju "
1254*e97ad33aSDoug Rabson 	    "st_stat %ju, st_data_version %ju \n", fid->fid,
1255*e97ad33aSDoug Rabson 	    stat_dotl->qid.type, (uintmax_t)stat_dotl->qid.path,
1256*e97ad33aSDoug Rabson 	    stat_dotl->qid.version, stat_dotl->st_mode, stat_dotl->st_uid,
1257*e97ad33aSDoug Rabson 	    stat_dotl->st_gid, (uintmax_t)stat_dotl->st_nlink,
1258*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_rdev, (uintmax_t)stat_dotl->st_size,
1259*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_blksize,
1260*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_blocks, (uintmax_t)stat_dotl->st_atime_sec,
1261*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_atime_nsec, (uintmax_t)stat_dotl->st_mtime_sec,
1262*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_mtime_nsec, (uintmax_t)stat_dotl->st_ctime_sec,
1263*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_ctime_nsec, (uintmax_t)stat_dotl->st_btime_sec,
1264*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_btime_nsec, (uintmax_t)stat_dotl->st_gen,
1265*e97ad33aSDoug Rabson 	    (uintmax_t)stat_dotl->st_data_version);
1266*e97ad33aSDoug Rabson 
1267*e97ad33aSDoug Rabson 	return (err);
1268*e97ad33aSDoug Rabson 
1269*e97ad33aSDoug Rabson error:
1270*e97ad33aSDoug Rabson 	if (req != NULL)
1271*e97ad33aSDoug Rabson 		p9_free_req(clnt, req);
1272*e97ad33aSDoug Rabson 
1273*e97ad33aSDoug Rabson 	return (err);
1274*e97ad33aSDoug Rabson }
1275*e97ad33aSDoug Rabson 
1276*e97ad33aSDoug Rabson /* Set file attributes of the file referenced by the fid */
1277*e97ad33aSDoug Rabson int
1278*e97ad33aSDoug Rabson p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
1279*e97ad33aSDoug Rabson {
1280*e97ad33aSDoug Rabson 	int err;
1281*e97ad33aSDoug Rabson 	struct p9_req_t *req;
1282*e97ad33aSDoug Rabson 	struct p9_client *clnt;
1283*e97ad33aSDoug Rabson 
1284*e97ad33aSDoug Rabson 	err = 0;
1285*e97ad33aSDoug Rabson 
1286*e97ad33aSDoug Rabson 	P9_DEBUG(PROTO, "TSETATTR fid %d"
1287*e97ad33aSDoug Rabson 	    " valid %x mode %x uid %d gid %d size %ju"
1288*e97ad33aSDoug Rabson 	    " atime_sec %ju atime_nsec %ju"
1289*e97ad33aSDoug Rabson 	    " mtime_sec %ju mtime_nsec %ju\n",
1290*e97ad33aSDoug Rabson 	    fid->fid,
1291*e97ad33aSDoug Rabson 	    p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
1292*e97ad33aSDoug Rabson 	    (uintmax_t)p9attr->size, (uintmax_t)p9attr->atime_sec,
1293*e97ad33aSDoug Rabson 	    (uintmax_t)p9attr->atime_nsec, (uintmax_t)p9attr->mtime_sec,
1294*e97ad33aSDoug Rabson 	    (uintmax_t)p9attr->mtime_nsec);
1295*e97ad33aSDoug Rabson 
1296*e97ad33aSDoug Rabson 	clnt = fid->clnt;
1297*e97ad33aSDoug Rabson 
1298*e97ad33aSDoug Rabson 	/* Any client_request error is converted to req == NULL error*/
1299*e97ad33aSDoug Rabson 	req = p9_client_request(clnt, P9PROTO_TSETATTR, &err, "dA", fid->fid,
1300*e97ad33aSDoug Rabson 	    p9attr);
1301*e97ad33aSDoug Rabson 
1302*e97ad33aSDoug Rabson 	if (req == NULL) {
1303*e97ad33aSDoug Rabson 		P9_DEBUG(ERROR, "%s: allocation failed %d\n", __func__, err);
1304*e97ad33aSDoug Rabson 		goto error;
1305*e97ad33aSDoug Rabson 	}
1306*e97ad33aSDoug Rabson 
1307*e97ad33aSDoug Rabson 	p9_free_req(clnt, req);
1308*e97ad33aSDoug Rabson error:
1309*e97ad33aSDoug Rabson 	return (err);
1310*e97ad33aSDoug Rabson }
1311*e97ad33aSDoug Rabson 
1312