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 struct V9fsDirent { 69 v9fs_qid qid; 70 uint64_t offset; 71 uint8_t type; 72 char *name; 73 struct V9fsDirent *next; 74 }; 75 76 /* options for 'Twalk' 9p request */ 77 typedef struct TWalkOpt { 78 /* 9P client being used (mandatory) */ 79 QVirtio9P *client; 80 /* user supplied tag number being returned with response (optional) */ 81 uint16_t tag; 82 /* file ID of directory from where walk should start (optional) */ 83 uint32_t fid; 84 /* file ID for target directory being walked to (optional) */ 85 uint32_t newfid; 86 /* low level variant of path to walk to (optional) */ 87 uint16_t nwname; 88 char **wnames; 89 /* high level variant of path to walk to (optional) */ 90 const char *path; 91 /* data being received from 9p server as 'Rwalk' response (optional) */ 92 struct { 93 uint16_t *nwqid; 94 v9fs_qid **wqid; 95 } rwalk; 96 /* only send Twalk request but not wait for a reply? (optional) */ 97 bool requestOnly; 98 /* do we expect an Rlerror response, if yes which error code? (optional) */ 99 uint32_t expectErr; 100 } TWalkOpt; 101 102 /* result of 'Twalk' 9p request */ 103 typedef struct TWalkRes { 104 /* file ID of target directory been walked to */ 105 uint32_t newfid; 106 /* if requestOnly was set: request object for further processing */ 107 P9Req *req; 108 } TWalkRes; 109 110 /* options for 'Tversion' 9p request */ 111 typedef struct TVersionOpt { 112 /* 9P client being used (mandatory) */ 113 QVirtio9P *client; 114 /* user supplied tag number being returned with response (optional) */ 115 uint16_t tag; 116 /* maximum message size that can be handled by client (optional) */ 117 uint32_t msize; 118 /* protocol version (optional) */ 119 const char *version; 120 /* only send Tversion request but not wait for a reply? (optional) */ 121 bool requestOnly; 122 /* do we expect an Rlerror response, if yes which error code? (optional) */ 123 uint32_t expectErr; 124 } TVersionOpt; 125 126 /* result of 'Tversion' 9p request */ 127 typedef struct TVersionRes { 128 /* if requestOnly was set: request object for further processing */ 129 P9Req *req; 130 } TVersionRes; 131 132 /* options for 'Tattach' 9p request */ 133 typedef struct TAttachOpt { 134 /* 9P client being used (mandatory) */ 135 QVirtio9P *client; 136 /* user supplied tag number being returned with response (optional) */ 137 uint16_t tag; 138 /* file ID to be associated with root of file tree (optional) */ 139 uint32_t fid; 140 /* numerical uid of user being introduced to server (optional) */ 141 uint32_t n_uname; 142 /* data being received from 9p server as 'Rattach' response (optional) */ 143 struct { 144 /* server's idea of the root of the file tree */ 145 v9fs_qid *qid; 146 } rattach; 147 /* only send Tattach request but not wait for a reply? (optional) */ 148 bool requestOnly; 149 /* do we expect an Rlerror response, if yes which error code? (optional) */ 150 uint32_t expectErr; 151 } TAttachOpt; 152 153 /* result of 'Tattach' 9p request */ 154 typedef struct TAttachRes { 155 /* if requestOnly was set: request object for further processing */ 156 P9Req *req; 157 } TAttachRes; 158 159 /* options for 'Tgetattr' 9p request */ 160 typedef struct TGetAttrOpt { 161 /* 9P client being used (mandatory) */ 162 QVirtio9P *client; 163 /* user supplied tag number being returned with response (optional) */ 164 uint16_t tag; 165 /* file ID of file/dir whose attributes shall be retrieved (required) */ 166 uint32_t fid; 167 /* bitmask indicating attribute fields to be retrieved (optional) */ 168 uint64_t request_mask; 169 /* data being received from 9p server as 'Rgetattr' response (optional) */ 170 struct { 171 v9fs_attr *attr; 172 } rgetattr; 173 /* only send Tgetattr request but not wait for a reply? (optional) */ 174 bool requestOnly; 175 /* do we expect an Rlerror response, if yes which error code? (optional) */ 176 uint32_t expectErr; 177 } TGetAttrOpt; 178 179 /* result of 'Tgetattr' 9p request */ 180 typedef struct TGetAttrRes { 181 /* if requestOnly was set: request object for further processing */ 182 P9Req *req; 183 } TGetAttrRes; 184 185 /* options for 'Treaddir' 9p request */ 186 typedef struct TReadDirOpt { 187 /* 9P client being used (mandatory) */ 188 QVirtio9P *client; 189 /* user supplied tag number being returned with response (optional) */ 190 uint16_t tag; 191 /* file ID of directory whose entries shall be retrieved (required) */ 192 uint32_t fid; 193 /* offset in entries stream, i.e. for multiple requests (optional) */ 194 uint64_t offset; 195 /* maximum bytes to be returned by server (required) */ 196 uint32_t count; 197 /* data being received from 9p server as 'Rreaddir' response (optional) */ 198 struct { 199 uint32_t *count; 200 uint32_t *nentries; 201 struct V9fsDirent **entries; 202 } rreaddir; 203 /* only send Treaddir request but not wait for a reply? (optional) */ 204 bool requestOnly; 205 /* do we expect an Rlerror response, if yes which error code? (optional) */ 206 uint32_t expectErr; 207 } TReadDirOpt; 208 209 /* result of 'Treaddir' 9p request */ 210 typedef struct TReadDirRes { 211 /* if requestOnly was set: request object for further processing */ 212 P9Req *req; 213 } TReadDirRes; 214 215 /* options for 'Tlopen' 9p request */ 216 typedef struct TLOpenOpt { 217 /* 9P client being used (mandatory) */ 218 QVirtio9P *client; 219 /* user supplied tag number being returned with response (optional) */ 220 uint16_t tag; 221 /* file ID of file / directory to be opened (required) */ 222 uint32_t fid; 223 /* Linux open(2) flags such as O_RDONLY, O_RDWR, O_WRONLY (optional) */ 224 uint32_t flags; 225 /* data being received from 9p server as 'Rlopen' response (optional) */ 226 struct { 227 v9fs_qid *qid; 228 uint32_t *iounit; 229 } rlopen; 230 /* only send Tlopen request but not wait for a reply? (optional) */ 231 bool requestOnly; 232 /* do we expect an Rlerror response, if yes which error code? (optional) */ 233 uint32_t expectErr; 234 } TLOpenOpt; 235 236 /* result of 'Tlopen' 9p request */ 237 typedef struct TLOpenRes { 238 /* if requestOnly was set: request object for further processing */ 239 P9Req *req; 240 } TLOpenRes; 241 242 /* options for 'Twrite' 9p request */ 243 typedef struct TWriteOpt { 244 /* 9P client being used (mandatory) */ 245 QVirtio9P *client; 246 /* user supplied tag number being returned with response (optional) */ 247 uint16_t tag; 248 /* file ID of file to write to (required) */ 249 uint32_t fid; 250 /* start position of write from beginning of file (optional) */ 251 uint64_t offset; 252 /* how many bytes to write */ 253 uint32_t count; 254 /* data to be written */ 255 const void *data; 256 /* only send Twrite request but not wait for a reply? (optional) */ 257 bool requestOnly; 258 /* do we expect an Rlerror response, if yes which error code? (optional) */ 259 uint32_t expectErr; 260 } TWriteOpt; 261 262 /* result of 'Twrite' 9p request */ 263 typedef struct TWriteRes { 264 /* if requestOnly was set: request object for further processing */ 265 P9Req *req; 266 /* amount of bytes written */ 267 uint32_t count; 268 } TWriteRes; 269 270 /* options for 'Tflush' 9p request */ 271 typedef struct TFlushOpt { 272 /* 9P client being used (mandatory) */ 273 QVirtio9P *client; 274 /* user supplied tag number being returned with response (optional) */ 275 uint16_t tag; 276 /* message to flush (required) */ 277 uint16_t oldtag; 278 /* only send Tflush request but not wait for a reply? (optional) */ 279 bool requestOnly; 280 /* do we expect an Rlerror response, if yes which error code? (optional) */ 281 uint32_t expectErr; 282 } TFlushOpt; 283 284 /* result of 'Tflush' 9p request */ 285 typedef struct TFlushRes { 286 /* if requestOnly was set: request object for further processing */ 287 P9Req *req; 288 } TFlushRes; 289 290 /* options for 'Tmkdir' 9p request */ 291 typedef struct TMkdirOpt { 292 /* 9P client being used (mandatory) */ 293 QVirtio9P *client; 294 /* user supplied tag number being returned with response (optional) */ 295 uint16_t tag; 296 /* low level variant of directory where new one shall be created */ 297 uint32_t dfid; 298 /* high-level variant of directory where new one shall be created */ 299 const char *atPath; 300 /* New directory's name (required) */ 301 const char *name; 302 /* Linux mkdir(2) mode bits (optional) */ 303 uint32_t mode; 304 /* effective group ID of caller */ 305 uint32_t gid; 306 /* data being received from 9p server as 'Rmkdir' response (optional) */ 307 struct { 308 /* QID of newly created directory */ 309 v9fs_qid *qid; 310 } rmkdir; 311 /* only send Tmkdir request but not wait for a reply? (optional) */ 312 bool requestOnly; 313 /* do we expect an Rlerror response, if yes which error code? (optional) */ 314 uint32_t expectErr; 315 } TMkdirOpt; 316 317 /* result of 'TMkdir' 9p request */ 318 typedef struct TMkdirRes { 319 /* if requestOnly was set: request object for further processing */ 320 P9Req *req; 321 } TMkdirRes; 322 323 /* options for 'Tlcreate' 9p request */ 324 typedef struct TlcreateOpt { 325 /* 9P client being used (mandatory) */ 326 QVirtio9P *client; 327 /* user supplied tag number being returned with response (optional) */ 328 uint16_t tag; 329 /* low-level variant of directory where new file shall be created */ 330 uint32_t fid; 331 /* high-level variant of directory where new file shall be created */ 332 const char *atPath; 333 /* name of new file (required) */ 334 const char *name; 335 /* Linux kernel intent bits */ 336 uint32_t flags; 337 /* Linux create(2) mode bits */ 338 uint32_t mode; 339 /* effective group ID of caller */ 340 uint32_t gid; 341 /* data being received from 9p server as 'Rlcreate' response (optional) */ 342 struct { 343 v9fs_qid *qid; 344 uint32_t *iounit; 345 } rlcreate; 346 /* only send Tlcreate request but not wait for a reply? (optional) */ 347 bool requestOnly; 348 /* do we expect an Rlerror response, if yes which error code? (optional) */ 349 uint32_t expectErr; 350 } TlcreateOpt; 351 352 /* result of 'Tlcreate' 9p request */ 353 typedef struct TlcreateRes { 354 /* if requestOnly was set: request object for further processing */ 355 P9Req *req; 356 } TlcreateRes; 357 358 /* options for 'Tsymlink' 9p request */ 359 typedef struct TsymlinkOpt { 360 /* 9P client being used (mandatory) */ 361 QVirtio9P *client; 362 /* user supplied tag number being returned with response (optional) */ 363 uint16_t tag; 364 /* low-level variant of directory where symlink shall be created */ 365 uint32_t fid; 366 /* high-level variant of directory where symlink shall be created */ 367 const char *atPath; 368 /* name of symlink (required) */ 369 const char *name; 370 /* where symlink will point to (required) */ 371 const char *symtgt; 372 /* effective group ID of caller */ 373 uint32_t gid; 374 /* data being received from 9p server as 'Rsymlink' response (optional) */ 375 struct { 376 v9fs_qid *qid; 377 } rsymlink; 378 /* only send Tsymlink 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 } TsymlinkOpt; 383 384 /* result of 'Tsymlink' 9p request */ 385 typedef struct TsymlinkRes { 386 /* if requestOnly was set: request object for further processing */ 387 P9Req *req; 388 } TsymlinkRes; 389 390 /* options for 'Tlink' 9p request */ 391 typedef struct TlinkOpt { 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 hard link shall be created */ 397 uint32_t dfid; 398 /* high-level variant of directory where hard link shall be created */ 399 const char *atPath; 400 /* low-level variant of target referenced by new hard link */ 401 uint32_t fid; 402 /* high-level variant of target referenced by new hard link */ 403 const char *toPath; 404 /* name of hard link (required) */ 405 const char *name; 406 /* only send Tlink request but not wait for a reply? (optional) */ 407 bool requestOnly; 408 /* do we expect an Rlerror response, if yes which error code? (optional) */ 409 uint32_t expectErr; 410 } TlinkOpt; 411 412 /* result of 'Tlink' 9p request */ 413 typedef struct TlinkRes { 414 /* if requestOnly was set: request object for further processing */ 415 P9Req *req; 416 } TlinkRes; 417 418 /* options for 'Tunlinkat' 9p request */ 419 typedef struct TunlinkatOpt { 420 /* 9P client being used (mandatory) */ 421 QVirtio9P *client; 422 /* user supplied tag number being returned with response (optional) */ 423 uint16_t tag; 424 /* low-level variant of directory where name shall be unlinked */ 425 uint32_t dirfd; 426 /* high-level variant of directory where name shall be unlinked */ 427 const char *atPath; 428 /* name of directory entry to be unlinked (required) */ 429 const char *name; 430 /* Linux unlinkat(2) flags */ 431 uint32_t flags; 432 /* only send Tunlinkat request but not wait for a reply? (optional) */ 433 bool requestOnly; 434 /* do we expect an Rlerror response, if yes which error code? (optional) */ 435 uint32_t expectErr; 436 } TunlinkatOpt; 437 438 /* result of 'Tunlinkat' 9p request */ 439 typedef struct TunlinkatRes { 440 /* if requestOnly was set: request object for further processing */ 441 P9Req *req; 442 } TunlinkatRes; 443 444 void v9fs_set_allocator(QGuestAllocator *t_alloc); 445 void v9fs_memwrite(P9Req *req, const void *addr, size_t len); 446 void v9fs_memskip(P9Req *req, size_t len); 447 void v9fs_memread(P9Req *req, void *addr, size_t len); 448 void v9fs_uint8_read(P9Req *req, uint8_t *val); 449 void v9fs_uint16_write(P9Req *req, uint16_t val); 450 void v9fs_uint16_read(P9Req *req, uint16_t *val); 451 void v9fs_uint32_write(P9Req *req, uint32_t val); 452 void v9fs_uint64_write(P9Req *req, uint64_t val); 453 void v9fs_uint32_read(P9Req *req, uint32_t *val); 454 void v9fs_uint64_read(P9Req *req, uint64_t *val); 455 uint16_t v9fs_string_size(const char *string); 456 void v9fs_string_write(P9Req *req, const char *string); 457 void v9fs_string_read(P9Req *req, uint16_t *len, char **string); 458 P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, 459 uint16_t tag); 460 void v9fs_req_send(P9Req *req); 461 void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len); 462 void v9fs_req_recv(P9Req *req, uint8_t id); 463 void v9fs_req_free(P9Req *req); 464 void v9fs_rlerror(P9Req *req, uint32_t *err); 465 TVersionRes v9fs_tversion(TVersionOpt); 466 void v9fs_rversion(P9Req *req, uint16_t *len, char **version); 467 TAttachRes v9fs_tattach(TAttachOpt); 468 void v9fs_rattach(P9Req *req, v9fs_qid *qid); 469 TWalkRes v9fs_twalk(TWalkOpt opt); 470 void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid); 471 TGetAttrRes v9fs_tgetattr(TGetAttrOpt); 472 void v9fs_rgetattr(P9Req *req, v9fs_attr *attr); 473 TReadDirRes v9fs_treaddir(TReadDirOpt); 474 void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, 475 struct V9fsDirent **entries); 476 void v9fs_free_dirents(struct V9fsDirent *e); 477 TLOpenRes v9fs_tlopen(TLOpenOpt); 478 void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit); 479 TWriteRes v9fs_twrite(TWriteOpt); 480 void v9fs_rwrite(P9Req *req, uint32_t *count); 481 TFlushRes v9fs_tflush(TFlushOpt); 482 void v9fs_rflush(P9Req *req); 483 TMkdirRes v9fs_tmkdir(TMkdirOpt); 484 void v9fs_rmkdir(P9Req *req, v9fs_qid *qid); 485 TlcreateRes v9fs_tlcreate(TlcreateOpt); 486 void v9fs_rlcreate(P9Req *req, v9fs_qid *qid, uint32_t *iounit); 487 TsymlinkRes v9fs_tsymlink(TsymlinkOpt); 488 void v9fs_rsymlink(P9Req *req, v9fs_qid *qid); 489 TlinkRes v9fs_tlink(TlinkOpt); 490 void v9fs_rlink(P9Req *req); 491 TunlinkatRes v9fs_tunlinkat(TunlinkatOpt); 492 void v9fs_runlinkat(P9Req *req); 493 494 #endif 495