Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/p9fs/p9_client.c
39536 views
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
69
p9_is_proto_dotl(struct p9_client *clnt)
70
{
71
72
return (clnt->proto_version == p9_proto_2000L);
73
}
74
75
inline int
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
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 *
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
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
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 *
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
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
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 */
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
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 *
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 *
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
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
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 *
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
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
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
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
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 *
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
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 *
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
1334