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