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