xref: /qemu/tests/qtest/libqos/virtio-9p-client.h (revision a9e0c9c0f14e19d23443ac24c8080b4708d2eab8)
1 /*
2  * 9P network client for VirtIO 9P test cases (based on QTest)
3  *
4  * Copyright (c) 2014 SUSE LINUX Products GmbH
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  */
9 
10 /*
11  * Not so fast! You might want to read the 9p developer docs first:
12  * https://wiki.qemu.org/Documentation/9p
13  */
14 
15 #ifndef TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
16 #define TESTS_LIBQOS_VIRTIO_9P_CLIENT_H
17 
18 #include "hw/9pfs/9p.h"
19 #include "hw/9pfs/9p-synth.h"
20 #include "virtio-9p.h"
21 #include "qgraph.h"
22 #include "tests/qtest/libqtest-single.h"
23 
24 #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */
25 
26 typedef struct {
27     QTestState *qts;
28     QVirtio9P *v9p;
29     uint16_t tag;
30     uint64_t t_msg;
31     uint32_t t_size;
32     uint64_t r_msg;
33     /* No r_size, it is hardcoded to P9_MAX_SIZE */
34     size_t t_off;
35     size_t r_off;
36     uint32_t free_head;
37 } P9Req;
38 
39 /* type[1] version[4] path[8] */
40 typedef char v9fs_qid[13];
41 
42 typedef struct v9fs_attr {
43     uint64_t valid;
44     v9fs_qid qid;
45     uint32_t mode;
46     uint32_t uid;
47     uint32_t gid;
48     uint64_t nlink;
49     uint64_t rdev;
50     uint64_t size;
51     uint64_t blksize;
52     uint64_t blocks;
53     uint64_t atime_sec;
54     uint64_t atime_nsec;
55     uint64_t mtime_sec;
56     uint64_t mtime_nsec;
57     uint64_t ctime_sec;
58     uint64_t ctime_nsec;
59     uint64_t btime_sec;
60     uint64_t btime_nsec;
61     uint64_t gen;
62     uint64_t data_version;
63 } v9fs_attr;
64 
65 #define P9_GETATTR_BASIC    0x000007ffULL /* Mask for fields up to BLOCKS */
66 #define P9_GETATTR_ALL      0x00003fffULL /* Mask for ALL fields */
67 
68 #define P9_SETATTR_MODE         0x00000001UL
69 #define P9_SETATTR_UID          0x00000002UL
70 #define P9_SETATTR_GID          0x00000004UL
71 #define P9_SETATTR_SIZE         0x00000008UL
72 #define P9_SETATTR_ATIME        0x00000010UL
73 #define P9_SETATTR_MTIME        0x00000020UL
74 #define P9_SETATTR_CTIME        0x00000040UL
75 #define P9_SETATTR_ATIME_SET    0x00000080UL
76 #define P9_SETATTR_MTIME_SET    0x00000100UL
77 
78 struct V9fsDirent {
79     v9fs_qid qid;
80     uint64_t offset;
81     uint8_t type;
82     char *name;
83     struct V9fsDirent *next;
84 };
85 
86 /* options for 'Twalk' 9p request */
87 typedef struct TWalkOpt {
88     /* 9P client being used (mandatory) */
89     QVirtio9P *client;
90     /* user supplied tag number being returned with response (optional) */
91     uint16_t tag;
92     /* file ID of directory from where walk should start (optional) */
93     uint32_t fid;
94     /* file ID for target directory being walked to (optional) */
95     uint32_t newfid;
96     /* low level variant of path to walk to (optional) */
97     uint16_t nwname;
98     char **wnames;
99     /* high level variant of path to walk to (optional) */
100     const char *path;
101     /* data being received from 9p server as 'Rwalk' response (optional) */
102     struct {
103         uint16_t *nwqid;
104         v9fs_qid **wqid;
105     } rwalk;
106     /* only send Twalk request but not wait for a reply? (optional) */
107     bool requestOnly;
108     /* do we expect an Rlerror response, if yes which error code? (optional) */
109     uint32_t expectErr;
110 } TWalkOpt;
111 
112 /* result of 'Twalk' 9p request */
113 typedef struct TWalkRes {
114     /* file ID of target directory been walked to */
115     uint32_t newfid;
116     /* if requestOnly was set: request object for further processing */
117     P9Req *req;
118 } TWalkRes;
119 
120 /* options for 'Tversion' 9p request */
121 typedef struct TVersionOpt {
122     /* 9P client being used (mandatory) */
123     QVirtio9P *client;
124     /* user supplied tag number being returned with response (optional) */
125     uint16_t tag;
126     /* maximum message size that can be handled by client (optional) */
127     uint32_t msize;
128     /* protocol version (optional) */
129     const char *version;
130     /* only send Tversion request but not wait for a reply? (optional) */
131     bool requestOnly;
132     /* do we expect an Rlerror response, if yes which error code? (optional) */
133     uint32_t expectErr;
134 } TVersionOpt;
135 
136 /* result of 'Tversion' 9p request */
137 typedef struct TVersionRes {
138     /* if requestOnly was set: request object for further processing */
139     P9Req *req;
140 } TVersionRes;
141 
142 /* options for 'Tattach' 9p request */
143 typedef struct TAttachOpt {
144     /* 9P client being used (mandatory) */
145     QVirtio9P *client;
146     /* user supplied tag number being returned with response (optional) */
147     uint16_t tag;
148     /* file ID to be associated with root of file tree (optional) */
149     uint32_t fid;
150     /* numerical uid of user being introduced to server (optional) */
151     uint32_t n_uname;
152     /* data being received from 9p server as 'Rattach' response (optional) */
153     struct {
154         /* server's idea of the root of the file tree */
155         v9fs_qid *qid;
156     } rattach;
157     /* only send Tattach request but not wait for a reply? (optional) */
158     bool requestOnly;
159     /* do we expect an Rlerror response, if yes which error code? (optional) */
160     uint32_t expectErr;
161 } TAttachOpt;
162 
163 /* result of 'Tattach' 9p request */
164 typedef struct TAttachRes {
165     /* if requestOnly was set: request object for further processing */
166     P9Req *req;
167 } TAttachRes;
168 
169 /* options for 'Tgetattr' 9p request */
170 typedef struct TGetAttrOpt {
171     /* 9P client being used (mandatory) */
172     QVirtio9P *client;
173     /* user supplied tag number being returned with response (optional) */
174     uint16_t tag;
175     /* file ID of file/dir whose attributes shall be retrieved (required) */
176     uint32_t fid;
177     /* bitmask indicating attribute fields to be retrieved (optional) */
178     uint64_t request_mask;
179     /* data being received from 9p server as 'Rgetattr' response (optional) */
180     struct {
181         v9fs_attr *attr;
182     } rgetattr;
183     /* only send Tgetattr request but not wait for a reply? (optional) */
184     bool requestOnly;
185     /* do we expect an Rlerror response, if yes which error code? (optional) */
186     uint32_t expectErr;
187 } TGetAttrOpt;
188 
189 /* result of 'Tgetattr' 9p request */
190 typedef struct TGetAttrRes {
191     /* if requestOnly was set: request object for further processing */
192     P9Req *req;
193 } TGetAttrRes;
194 
195 /* options for 'Tsetattr' 9p request */
196 typedef struct TSetAttrOpt {
197     /* 9P client being used (mandatory) */
198     QVirtio9P *client;
199     /* user supplied tag number being returned with response (optional) */
200     uint16_t tag;
201     /* file ID of file/dir whose attributes shall be modified (required) */
202     uint32_t fid;
203     /* new attribute values to be set by 9p server */
204     v9fs_attr attr;
205     /* only send Tsetattr request but not wait for a reply? (optional) */
206     bool requestOnly;
207     /* do we expect an Rlerror response, if yes which error code? (optional) */
208     uint32_t expectErr;
209 } TSetAttrOpt;
210 
211 /* result of 'Tsetattr' 9p request */
212 typedef struct TSetAttrRes {
213     /* if requestOnly was set: request object for further processing */
214     P9Req *req;
215 } TSetAttrRes;
216 
217 /* options for 'Treaddir' 9p request */
218 typedef struct TReadDirOpt {
219     /* 9P client being used (mandatory) */
220     QVirtio9P *client;
221     /* user supplied tag number being returned with response (optional) */
222     uint16_t tag;
223     /* file ID of directory whose entries shall be retrieved (required) */
224     uint32_t fid;
225     /* offset in entries stream, i.e. for multiple requests (optional) */
226     uint64_t offset;
227     /* maximum bytes to be returned by server (required) */
228     uint32_t count;
229     /* data being received from 9p server as 'Rreaddir' response (optional) */
230     struct {
231         uint32_t *count;
232         uint32_t *nentries;
233         struct V9fsDirent **entries;
234     } rreaddir;
235     /* only send Treaddir request but not wait for a reply? (optional) */
236     bool requestOnly;
237     /* do we expect an Rlerror response, if yes which error code? (optional) */
238     uint32_t expectErr;
239 } TReadDirOpt;
240 
241 /* result of 'Treaddir' 9p request */
242 typedef struct TReadDirRes {
243     /* if requestOnly was set: request object for further processing */
244     P9Req *req;
245 } TReadDirRes;
246 
247 /* options for 'Tlopen' 9p request */
248 typedef struct TLOpenOpt {
249     /* 9P client being used (mandatory) */
250     QVirtio9P *client;
251     /* user supplied tag number being returned with response (optional) */
252     uint16_t tag;
253     /* file ID of file / directory to be opened (required) */
254     uint32_t fid;
255     /* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */
256     uint32_t flags;
257     /* data being received from 9p server as 'Rlopen' response (optional) */
258     struct {
259         v9fs_qid *qid;
260         uint32_t *iounit;
261     } rlopen;
262     /* only send Tlopen request but not wait for a reply? (optional) */
263     bool requestOnly;
264     /* do we expect an Rlerror response, if yes which error code? (optional) */
265     uint32_t expectErr;
266 } TLOpenOpt;
267 
268 /* result of 'Tlopen' 9p request */
269 typedef struct TLOpenRes {
270     /* if requestOnly was set: request object for further processing */
271     P9Req *req;
272 } TLOpenRes;
273 
274 /* options for 'Twrite' 9p request */
275 typedef struct TWriteOpt {
276     /* 9P client being used (mandatory) */
277     QVirtio9P *client;
278     /* user supplied tag number being returned with response (optional) */
279     uint16_t tag;
280     /* file ID of file to write to (required) */
281     uint32_t fid;
282     /* start position of write from beginning of file (optional) */
283     uint64_t offset;
284     /* how many bytes to write */
285     uint32_t count;
286     /* data to be written */
287     const void *data;
288     /* only send Twrite request but not wait for a reply? (optional) */
289     bool requestOnly;
290     /* do we expect an Rlerror response, if yes which error code? (optional) */
291     uint32_t expectErr;
292 } TWriteOpt;
293 
294 /* result of 'Twrite' 9p request */
295 typedef struct TWriteRes {
296     /* if requestOnly was set: request object for further processing */
297     P9Req *req;
298     /* amount of bytes written */
299     uint32_t count;
300 } TWriteRes;
301 
302 /* options for 'Tflush' 9p request */
303 typedef struct TFlushOpt {
304     /* 9P client being used (mandatory) */
305     QVirtio9P *client;
306     /* user supplied tag number being returned with response (optional) */
307     uint16_t tag;
308     /* message to flush (required) */
309     uint16_t oldtag;
310     /* only send Tflush request but not wait for a reply? (optional) */
311     bool requestOnly;
312     /* do we expect an Rlerror response, if yes which error code? (optional) */
313     uint32_t expectErr;
314 } TFlushOpt;
315 
316 /* result of 'Tflush' 9p request */
317 typedef struct TFlushRes {
318     /* if requestOnly was set: request object for further processing */
319     P9Req *req;
320 } TFlushRes;
321 
322 /* options for 'Tmkdir' 9p request */
323 typedef struct TMkdirOpt {
324     /* 9P client being used (mandatory) */
325     QVirtio9P *client;
326     /* user supplied tag number being returned with response (optional) */
327     uint16_t tag;
328     /* low level variant of directory where new one shall be created */
329     uint32_t dfid;
330     /* high-level variant of directory where new one shall be created */
331     const char *atPath;
332     /* New directory's name (required) */
333     const char *name;
334     /* Linux mkdir(2) mode bits (optional) */
335     uint32_t mode;
336     /* effective group ID of caller */
337     uint32_t gid;
338     /* data being received from 9p server as 'Rmkdir' response (optional) */
339     struct {
340         /* QID of newly created directory */
341         v9fs_qid *qid;
342     } rmkdir;
343     /* only send Tmkdir request but not wait for a reply? (optional) */
344     bool requestOnly;
345     /* do we expect an Rlerror response, if yes which error code? (optional) */
346     uint32_t expectErr;
347 } TMkdirOpt;
348 
349 /* result of 'TMkdir' 9p request */
350 typedef struct TMkdirRes {
351     /* if requestOnly was set: request object for further processing */
352     P9Req *req;
353 } TMkdirRes;
354 
355 /* options for 'Tlcreate' 9p request */
356 typedef struct TlcreateOpt {
357     /* 9P client being used (mandatory) */
358     QVirtio9P *client;
359     /* user supplied tag number being returned with response (optional) */
360     uint16_t tag;
361     /* low-level variant of directory where new file shall be created */
362     uint32_t fid;
363     /* high-level variant of directory where new file shall be created */
364     const char *atPath;
365     /* name of new file (required) */
366     const char *name;
367     /* Linux kernel intent bits */
368     uint32_t flags;
369     /* Linux create(2) mode bits */
370     uint32_t mode;
371     /* effective group ID of caller */
372     uint32_t gid;
373     /* data being received from 9p server as 'Rlcreate' response (optional) */
374     struct {
375         v9fs_qid *qid;
376         uint32_t *iounit;
377     } rlcreate;
378     /* only send Tlcreate request but not wait for a reply? (optional) */
379     bool requestOnly;
380     /* do we expect an Rlerror response, if yes which error code? (optional) */
381     uint32_t expectErr;
382 } TlcreateOpt;
383 
384 /* result of 'Tlcreate' 9p request */
385 typedef struct TlcreateRes {
386     /* if requestOnly was set: request object for further processing */
387     P9Req *req;
388 } TlcreateRes;
389 
390 /* options for 'Tsymlink' 9p request */
391 typedef struct TsymlinkOpt {
392     /* 9P client being used (mandatory) */
393     QVirtio9P *client;
394     /* user supplied tag number being returned with response (optional) */
395     uint16_t tag;
396     /* low-level variant of directory where symlink shall be created */
397     uint32_t fid;
398     /* high-level variant of directory where symlink shall be created */
399     const char *atPath;
400     /* name of symlink (required) */
401     const char *name;
402     /* where symlink will point to (required) */
403     const char *symtgt;
404     /* effective group ID of caller */
405     uint32_t gid;
406     /* data being received from 9p server as 'Rsymlink' response (optional) */
407     struct {
408         v9fs_qid *qid;
409     } rsymlink;
410     /* only send Tsymlink request but not wait for a reply? (optional) */
411     bool requestOnly;
412     /* do we expect an Rlerror response, if yes which error code? (optional) */
413     uint32_t expectErr;
414 } TsymlinkOpt;
415 
416 /* result of 'Tsymlink' 9p request */
417 typedef struct TsymlinkRes {
418     /* if requestOnly was set: request object for further processing */
419     P9Req *req;
420 } TsymlinkRes;
421 
422 /* options for 'Tlink' 9p request */
423 typedef struct TlinkOpt {
424     /* 9P client being used (mandatory) */
425     QVirtio9P *client;
426     /* user supplied tag number being returned with response (optional) */
427     uint16_t tag;
428     /* low-level variant of directory where hard link shall be created */
429     uint32_t dfid;
430     /* high-level variant of directory where hard link shall be created */
431     const char *atPath;
432     /* low-level variant of target referenced by new hard link */
433     uint32_t fid;
434     /* high-level variant of target referenced by new hard link */
435     const char *toPath;
436     /* name of hard link (required) */
437     const char *name;
438     /* only send Tlink request but not wait for a reply? (optional) */
439     bool requestOnly;
440     /* do we expect an Rlerror response, if yes which error code? (optional) */
441     uint32_t expectErr;
442 } TlinkOpt;
443 
444 /* result of 'Tlink' 9p request */
445 typedef struct TlinkRes {
446     /* if requestOnly was set: request object for further processing */
447     P9Req *req;
448 } TlinkRes;
449 
450 /* options for 'Tunlinkat' 9p request */
451 typedef struct TunlinkatOpt {
452     /* 9P client being used (mandatory) */
453     QVirtio9P *client;
454     /* user supplied tag number being returned with response (optional) */
455     uint16_t tag;
456     /* low-level variant of directory where name shall be unlinked */
457     uint32_t dirfd;
458     /* high-level variant of directory where name shall be unlinked */
459     const char *atPath;
460     /* name of directory entry to be unlinked (required) */
461     const char *name;
462     /* Linux unlinkat(2) flags */
463     uint32_t flags;
464     /* only send Tunlinkat request but not wait for a reply? (optional) */
465     bool requestOnly;
466     /* do we expect an Rlerror response, if yes which error code? (optional) */
467     uint32_t expectErr;
468 } TunlinkatOpt;
469 
470 /* result of 'Tunlinkat' 9p request */
471 typedef struct TunlinkatRes {
472     /* if requestOnly was set: request object for further processing */
473     P9Req *req;
474 } TunlinkatRes;
475 
476 void v9fs_set_allocator(QGuestAllocator *t_alloc);
477 void v9fs_memwrite(P9Req *req, const void *addr, size_t len);
478 void v9fs_memskip(P9Req *req, size_t len);
479 void v9fs_memread(P9Req *req, void *addr, size_t len);
480 void v9fs_uint8_read(P9Req *req, uint8_t *val);
481 void v9fs_uint16_write(P9Req *req, uint16_t val);
482 void v9fs_uint16_read(P9Req *req, uint16_t *val);
483 void v9fs_uint32_write(P9Req *req, uint32_t val);
484 void v9fs_uint64_write(P9Req *req, uint64_t val);
485 void v9fs_uint32_read(P9Req *req, uint32_t *val);
486 void v9fs_uint64_read(P9Req *req, uint64_t *val);
487 uint16_t v9fs_string_size(const char *string);
488 void v9fs_string_write(P9Req *req, const char *string);
489 void v9fs_string_read(P9Req *req, uint16_t *len, char **string);
490 P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id,
491                      uint16_t tag);
492 void v9fs_req_send(P9Req *req);
493 void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len);
494 void v9fs_req_recv(P9Req *req, uint8_t id);
495 void v9fs_req_free(P9Req *req);
496 void v9fs_rlerror(P9Req *req, uint32_t *err);
497 TVersionRes v9fs_tversion(TVersionOpt);
498 void v9fs_rversion(P9Req *req, uint16_t *len, char **version);
499 TAttachRes v9fs_tattach(TAttachOpt);
500 void v9fs_rattach(P9Req *req, v9fs_qid *qid);
501 TWalkRes v9fs_twalk(TWalkOpt opt);
502 void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid);
503 TGetAttrRes v9fs_tgetattr(TGetAttrOpt);
504 void v9fs_rgetattr(P9Req *req, v9fs_attr *attr);
505 TSetAttrRes v9fs_tsetattr(TSetAttrOpt opt);
506 void v9fs_rsetattr(P9Req *req);
507 TReadDirRes v9fs_treaddir(TReadDirOpt);
508 void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries,
509                    struct V9fsDirent **entries);
510 void v9fs_free_dirents(struct V9fsDirent *e);
511 TLOpenRes v9fs_tlopen(TLOpenOpt);
512 void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
513 TWriteRes v9fs_twrite(TWriteOpt);
514 void v9fs_rwrite(P9Req *req, uint32_t *count);
515 TFlushRes v9fs_tflush(TFlushOpt);
516 void v9fs_rflush(P9Req *req);
517 TMkdirRes v9fs_tmkdir(TMkdirOpt);
518 void v9fs_rmkdir(P9Req *req, v9fs_qid *qid);
519 TlcreateRes v9fs_tlcreate(TlcreateOpt);
520 void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit);
521 TsymlinkRes v9fs_tsymlink(TsymlinkOpt);
522 void v9fs_rsymlink(P9Req *req, v9fs_qid *qid);
523 TlinkRes v9fs_tlink(TlinkOpt);
524 void v9fs_rlink(P9Req *req);
525 TunlinkatRes v9fs_tunlinkat(TunlinkatOpt);
526 void v9fs_runlinkat(P9Req *req);
527 
528 #endif
529