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