| 1 | #ifndef QEMU_9P_H |
| 2 | #define QEMU_9P_H |
| 3 | |
| 4 | #include <dirent.h> |
| 5 | #include <utime.h> |
| 6 | #include <sys/resource.h> |
| 7 | #include "fsdev/file-op-9p.h" |
| 8 | #include "fsdev/9p-iov-marshal.h" |
| 9 | #include "qemu/thread.h" |
| 10 | #include "qemu/coroutine.h" |
| 11 | #include "qemu/qht.h" |
| 12 | |
| 13 | enum { |
| 14 | P9_TLERROR = 6, |
| 15 | P9_RLERROR, |
| 16 | P9_TSTATFS = 8, |
| 17 | P9_RSTATFS, |
| 18 | P9_TLOPEN = 12, |
| 19 | P9_RLOPEN, |
| 20 | P9_TLCREATE = 14, |
| 21 | P9_RLCREATE, |
| 22 | P9_TSYMLINK = 16, |
| 23 | P9_RSYMLINK, |
| 24 | P9_TMKNOD = 18, |
| 25 | P9_RMKNOD, |
| 26 | P9_TRENAME = 20, |
| 27 | P9_RRENAME, |
| 28 | P9_TREADLINK = 22, |
| 29 | P9_RREADLINK, |
| 30 | P9_TGETATTR = 24, |
| 31 | P9_RGETATTR, |
| 32 | P9_TSETATTR = 26, |
| 33 | P9_RSETATTR, |
| 34 | P9_TXATTRWALK = 30, |
| 35 | P9_RXATTRWALK, |
| 36 | P9_TXATTRCREATE = 32, |
| 37 | P9_RXATTRCREATE, |
| 38 | P9_TREADDIR = 40, |
| 39 | P9_RREADDIR, |
| 40 | P9_TFSYNC = 50, |
| 41 | P9_RFSYNC, |
| 42 | P9_TLOCK = 52, |
| 43 | P9_RLOCK, |
| 44 | P9_TGETLOCK = 54, |
| 45 | P9_RGETLOCK, |
| 46 | P9_TLINK = 70, |
| 47 | P9_RLINK, |
| 48 | P9_TMKDIR = 72, |
| 49 | P9_RMKDIR, |
| 50 | P9_TRENAMEAT = 74, |
| 51 | P9_RRENAMEAT, |
| 52 | P9_TUNLINKAT = 76, |
| 53 | P9_RUNLINKAT, |
| 54 | P9_TVERSION = 100, |
| 55 | P9_RVERSION, |
| 56 | P9_TAUTH = 102, |
| 57 | P9_RAUTH, |
| 58 | P9_TATTACH = 104, |
| 59 | P9_RATTACH, |
| 60 | P9_TERROR = 106, |
| 61 | P9_RERROR, |
| 62 | P9_TFLUSH = 108, |
| 63 | P9_RFLUSH, |
| 64 | P9_TWALK = 110, |
| 65 | P9_RWALK, |
| 66 | P9_TOPEN = 112, |
| 67 | P9_ROPEN, |
| 68 | P9_TCREATE = 114, |
| 69 | P9_RCREATE, |
| 70 | P9_TREAD = 116, |
| 71 | P9_RREAD, |
| 72 | P9_TWRITE = 118, |
| 73 | P9_RWRITE, |
| 74 | P9_TCLUNK = 120, |
| 75 | P9_RCLUNK, |
| 76 | P9_TREMOVE = 122, |
| 77 | P9_RREMOVE, |
| 78 | P9_TSTAT = 124, |
| 79 | P9_RSTAT, |
| 80 | P9_TWSTAT = 126, |
| 81 | P9_RWSTAT, |
| 82 | }; |
| 83 | |
| 84 | |
| 85 | /* qid.types */ |
| 86 | enum { |
| 87 | P9_QTDIR = 0x80, |
| 88 | P9_QTAPPEND = 0x40, |
| 89 | P9_QTEXCL = 0x20, |
| 90 | P9_QTMOUNT = 0x10, |
| 91 | P9_QTAUTH = 0x08, |
| 92 | P9_QTTMP = 0x04, |
| 93 | P9_QTSYMLINK = 0x02, |
| 94 | P9_QTLINK = 0x01, |
| 95 | P9_QTFILE = 0x00, |
| 96 | }; |
| 97 | |
| 98 | typedef enum P9ProtoVersion { |
| 99 | V9FS_PROTO_2000U = 0x01, |
| 100 | V9FS_PROTO_2000L = 0x02, |
| 101 | } P9ProtoVersion; |
| 102 | |
| 103 | /* |
| 104 | * Minimum message size supported by this 9pfs server. |
| 105 | * |
| 106 | * A client establishes a session by sending a Tversion request along with a |
| 107 | * 'msize' parameter which suggests the server a maximum message size ever to be |
| 108 | * used for communication (for both requests and replies) between client and |
| 109 | * server during that session. If client suggests a 'msize' smaller than this |
| 110 | * value then session is denied by server with an error response. |
| 111 | */ |
| 112 | #define P9_MIN_MSIZE 4096 |
| 113 | |
| 114 | #define P9_NOTAG UINT16_MAX |
| 115 | #define P9_NOFID UINT32_MAX |
| 116 | #define P9_MAXWELEM 16 |
| 117 | |
| 118 | #define FID_REFERENCED 0x1 |
| 119 | #define FID_NON_RECLAIMABLE 0x2 |
| 120 | static inline char *rpath(FsContext *ctx, const char *path) |
| 121 | { |
| 122 | return g_strdup_printf("%s/%s", ctx->fs_root, path); |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | * ample room for Twrite/Rread header |
| 127 | * size[4] Tread/Twrite tag[2] fid[4] offset[8] count[4] |
| 128 | */ |
| 129 | #define P9_IOHDRSZ 24 |
| 130 | |
| 131 | typedef struct V9fsPDU V9fsPDU; |
| 132 | typedef struct V9fsState V9fsState; |
| 133 | typedef struct V9fsTransport V9fsTransport; |
| 134 | |
| 135 | typedef struct { |
| 136 | uint32_t size_le; |
| 137 | uint8_t id; |
| 138 | uint16_t tag_le; |
| 139 | } QEMU_PACKED P9MsgHeader; |
| 140 | /* According to the specification, 9p messages start with a 7-byte header. |
| 141 | * Since most of the code uses this header size in literal form, we must be |
| 142 | * sure this is indeed the case. |
| 143 | */ |
| 144 | QEMU_BUILD_BUG_ON(sizeof(P9MsgHeader) != 7); |
| 145 | |
| 146 | struct V9fsPDU { |
| 147 | uint32_t size; |
| 148 | uint16_t tag; |
| 149 | uint8_t id; |
| 150 | uint8_t cancelled; |
| 151 | CoQueue complete; |
| 152 | V9fsState *s; |
| 153 | QLIST_ENTRY(V9fsPDU) next; |
| 154 | uint32_t idx; |
| 155 | }; |
| 156 | |
| 157 | |
| 158 | /* FIXME |
| 159 | * 1) change user needs to set groups and stuff |
| 160 | */ |
| 161 | |
| 162 | #define MAX_REQ 128 |
| 163 | #define MAX_TAG_LEN 32 |
| 164 | |
| 165 | #define BUG_ON(cond) assert(!(cond)) |
| 166 | |
| 167 | typedef struct V9fsFidState V9fsFidState; |
| 168 | |
| 169 | enum { |
| 170 | P9_FID_NONE = 0, |
| 171 | P9_FID_FILE, |
| 172 | P9_FID_DIR, |
| 173 | P9_FID_XATTR, |
| 174 | }; |
| 175 | |
| 176 | typedef struct V9fsConf |
| 177 | { |
| 178 | /* tag name for the device */ |
| 179 | char *tag; |
| 180 | char *fsdev_id; |
| 181 | } V9fsConf; |
| 182 | |
| 183 | /* 9p2000.L xattr flags (matches Linux values) */ |
| 184 | #define P9_XATTR_CREATE 1 |
| 185 | #define P9_XATTR_REPLACE 2 |
| 186 | |
| 187 | typedef struct V9fsXattr |
| 188 | { |
| 189 | uint64_t copied_len; |
| 190 | uint64_t len; |
| 191 | void *value; |
| 192 | V9fsString name; |
| 193 | int flags; |
| 194 | bool xattrwalk_fid; |
| 195 | } V9fsXattr; |
| 196 | |
| 197 | typedef struct V9fsDir { |
| 198 | DIR *stream; |
| 199 | P9ProtoVersion proto_version; |
| 200 | /* readdir mutex type used for 9P2000.u protocol variant */ |
| 201 | CoMutex readdir_mutex_u; |
| 202 | /* readdir mutex type used for 9P2000.L protocol variant */ |
| 203 | QemuMutex readdir_mutex_L; |
| 204 | } V9fsDir; |
| 205 | |
| 206 | static inline void coroutine_fn v9fs_readdir_lock(V9fsDir *dir) |
| 207 | { |
| 208 | if (dir->proto_version == V9FS_PROTO_2000U) { |
| 209 | qemu_co_mutex_lock(&dir->readdir_mutex_u); |
| 210 | } else { |
| 211 | qemu_mutex_lock(&dir->readdir_mutex_L); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | static inline void coroutine_fn v9fs_readdir_unlock(V9fsDir *dir) |
| 216 | { |
| 217 | if (dir->proto_version == V9FS_PROTO_2000U) { |
| 218 | qemu_co_mutex_unlock(&dir->readdir_mutex_u); |
| 219 | } else { |
| 220 | qemu_mutex_unlock(&dir->readdir_mutex_L); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | static inline void v9fs_readdir_init(P9ProtoVersion proto_version, V9fsDir *dir) |
| 225 | { |
| 226 | dir->proto_version = proto_version; |
| 227 | if (proto_version == V9FS_PROTO_2000U) { |
| 228 | qemu_co_mutex_init(&dir->readdir_mutex_u); |
| 229 | } else { |
| 230 | qemu_mutex_init(&dir->readdir_mutex_L); |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | /* |
| 235 | * Type for 9p fs drivers' (a.k.a. 9p backends) result of readdir requests, |
| 236 | * which is a chained list of directory entries. |
| 237 | */ |
| 238 | typedef struct V9fsDirEnt { |
| 239 | /* mandatory (must not be NULL) information for all readdir requests */ |
| 240 | struct dirent *dent; |
| 241 | /* |
| 242 | * optional (may be NULL): A full stat of each directory entry is just |
| 243 | * done if explicitly told to fs driver. |
| 244 | */ |
| 245 | struct stat *st; |
| 246 | /* |
| 247 | * instead of an array, directory entries are always returned as |
| 248 | * chained list, that's because the amount of entries retrieved by fs |
| 249 | * drivers is dependent on the individual entries' name (since response |
| 250 | * messages are size limited), so the final amount cannot be estimated |
| 251 | * before hand |
| 252 | */ |
| 253 | struct V9fsDirEnt *next; |
| 254 | } V9fsDirEnt; |
| 255 | |
| 256 | /* |
| 257 | * Filled by fs driver on open and other |
| 258 | * calls. |
| 259 | */ |
| 260 | union V9fsFidOpenState { |
| 261 | int fd; |
| 262 | V9fsDir dir; |
| 263 | V9fsXattr xattr; |
| 264 | /* |
| 265 | * private pointer for fs drivers, that |
| 266 | * have its own internal representation of |
| 267 | * open files. |
| 268 | */ |
| 269 | void *private; |
| 270 | }; |
| 271 | |
| 272 | struct V9fsFidState { |
| 273 | int fid_type; |
| 274 | int32_t fid; |
| 275 | V9fsPath path; |
| 276 | V9fsFidOpenState fs; |
| 277 | V9fsFidOpenState fs_reclaim; |
| 278 | int flags; |
| 279 | int open_flags; |
| 280 | uid_t uid; |
| 281 | int ref; |
| 282 | bool clunked; |
| 283 | QSLIST_ENTRY(V9fsFidState) reclaim_next; |
| 284 | }; |
| 285 | |
| 286 | typedef enum AffixType_t { |
| 287 | AffixType_Prefix, |
| 288 | AffixType_Suffix, /* A.k.a. postfix. */ |
| 289 | } AffixType_t; |
| 290 | |
| 291 | /* |
| 292 | * Unique affix of variable length. |
| 293 | * |
| 294 | * An affix is (currently) either a suffix or a prefix, which is either |
| 295 | * going to be prepended (prefix) or appended (suffix) with some other |
| 296 | * number for the goal to generate unique numbers. Accordingly the |
| 297 | * suffixes (or prefixes) we generate @b must all have the mathematical |
| 298 | * property of being suffix-free (or prefix-free in case of prefixes) |
| 299 | * so that no matter what number we concatenate the affix with, that we |
| 300 | * always reliably get unique numbers as result after concatenation. |
| 301 | */ |
| 302 | typedef struct VariLenAffix { |
| 303 | AffixType_t type; /* Whether this affix is a suffix or a prefix. */ |
| 304 | uint64_t value; /* Actual numerical value of this affix. */ |
| 305 | /* |
| 306 | * Length of the affix, that is how many (of the lowest) bits of ``value`` |
| 307 | * must be used for appending/prepending this affix to its final resulting, |
| 308 | * unique number. |
| 309 | */ |
| 310 | int bits; |
| 311 | } VariLenAffix; |
| 312 | |
| 313 | /* See qid_inode_prefix_hash_bits(). */ |
| 314 | typedef struct { |
| 315 | dev_t dev; /* FS device on host. */ |
| 316 | /* |
| 317 | * How many (high) bits of the original inode number shall be used for |
| 318 | * hashing. |
| 319 | */ |
| 320 | int prefix_bits; |
| 321 | } QpdEntry; |
| 322 | |
| 323 | /* QID path prefix entry, see stat_to_qid */ |
| 324 | typedef struct { |
| 325 | dev_t dev; |
| 326 | uint16_t ino_prefix; |
| 327 | uint32_t qp_affix_index; |
| 328 | VariLenAffix qp_affix; |
| 329 | } QppEntry; |
| 330 | |
| 331 | /* QID path full entry, as above */ |
| 332 | typedef struct { |
| 333 | dev_t dev; |
| 334 | ino_t ino; |
| 335 | uint64_t path; |
| 336 | } QpfEntry; |
| 337 | |
| 338 | struct V9fsState { |
| 339 | QLIST_HEAD(, V9fsPDU) free_list; |
| 340 | QLIST_HEAD(, V9fsPDU) active_list; |
| 341 | GHashTable *fids; |
| 342 | FileOperations *ops; |
| 343 | FsContext ctx; |
| 344 | char *tag; |
| 345 | P9ProtoVersion proto_version; |
| 346 | int32_t msize; |
| 347 | V9fsPDU pdus[MAX_REQ]; |
| 348 | const V9fsTransport *transport; |
| 349 | /* |
| 350 | * lock ensuring atomic path update |
| 351 | * on rename. |
| 352 | */ |
| 353 | CoRwlock rename_lock; |
| 354 | int32_t root_fid; |
| 355 | Error *migration_blocker; |
| 356 | V9fsConf fsconf; |
| 357 | struct stat root_st; |
| 358 | dev_t dev_id; |
| 359 | struct qht qpd_table; |
| 360 | struct qht qpp_table; |
| 361 | struct qht qpf_table; |
| 362 | uint64_t qp_ndevices; /* Amount of entries in qpd_table. */ |
| 363 | uint16_t qp_affix_next; |
| 364 | uint64_t qp_fullpath_next; |
| 365 | bool reclaiming; |
| 366 | }; |
| 367 | |
| 368 | /* 9p2000.L open flags */ |
| 369 | #define P9_DOTL_RDONLY 00000000 |
| 370 | #define P9_DOTL_WRONLY 00000001 |
| 371 | #define P9_DOTL_RDWR 00000002 |
| 372 | #define P9_DOTL_NOACCESS 00000003 |
| 373 | #define P9_DOTL_CREATE 00000100 |
| 374 | #define P9_DOTL_EXCL 00000200 |
| 375 | #define P9_DOTL_NOCTTY 00000400 |
| 376 | #define P9_DOTL_TRUNC 00001000 |
| 377 | #define P9_DOTL_APPEND 00002000 |
| 378 | #define P9_DOTL_NONBLOCK 00004000 |
| 379 | #define P9_DOTL_DSYNC 00010000 |
| 380 | #define P9_DOTL_FASYNC 00020000 |
| 381 | #define P9_DOTL_DIRECT 00040000 |
| 382 | #define P9_DOTL_LARGEFILE 00100000 |
| 383 | #define P9_DOTL_DIRECTORY 00200000 |
| 384 | #define P9_DOTL_NOFOLLOW 00400000 |
| 385 | #define P9_DOTL_NOATIME 01000000 |
| 386 | #define P9_DOTL_CLOEXEC 02000000 |
| 387 | #define P9_DOTL_SYNC 04000000 |
| 388 | |
| 389 | /* 9p2000.L at flags */ |
| 390 | #define P9_DOTL_AT_REMOVEDIR 0x200 |
| 391 | |
| 392 | /* 9P2000.L lock type */ |
| 393 | #define P9_LOCK_TYPE_RDLCK 0 |
| 394 | #define P9_LOCK_TYPE_WRLCK 1 |
| 395 | #define P9_LOCK_TYPE_UNLCK 2 |
| 396 | |
| 397 | #define P9_LOCK_SUCCESS 0 |
| 398 | #define P9_LOCK_BLOCKED 1 |
| 399 | #define P9_LOCK_ERROR 2 |
| 400 | #define P9_LOCK_GRACE 3 |
| 401 | |
| 402 | #define P9_LOCK_FLAGS_BLOCK 1 |
| 403 | #define P9_LOCK_FLAGS_RECLAIM 2 |
| 404 | |
| 405 | typedef struct V9fsFlock |
| 406 | { |
| 407 | uint8_t type; |
| 408 | uint32_t flags; |
| 409 | uint64_t start; /* absolute offset */ |
| 410 | uint64_t length; |
| 411 | uint32_t proc_id; |
| 412 | V9fsString client_id; |
| 413 | } V9fsFlock; |
| 414 | |
| 415 | typedef struct V9fsGetlock |
| 416 | { |
| 417 | uint8_t type; |
| 418 | uint64_t start; /* absolute offset */ |
| 419 | uint64_t length; |
| 420 | uint32_t proc_id; |
| 421 | V9fsString client_id; |
| 422 | } V9fsGetlock; |
| 423 | |
| 424 | extern int open_fd_hw; |
| 425 | extern int total_open_fd; |
| 426 | |
| 427 | static inline void coroutine_fn |
| 428 | v9fs_path_write_lock(V9fsState *s) |
| 429 | { |
| 430 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
| 431 | qemu_co_rwlock_wrlock(&s->rename_lock); |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | static inline void coroutine_fn |
| 436 | v9fs_path_read_lock(V9fsState *s) |
| 437 | { |
| 438 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
| 439 | qemu_co_rwlock_rdlock(&s->rename_lock); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | static inline void coroutine_fn |
| 444 | v9fs_path_unlock(V9fsState *s) |
| 445 | { |
| 446 | if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { |
| 447 | qemu_co_rwlock_unlock(&s->rename_lock); |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | static inline uint8_t v9fs_request_cancelled(V9fsPDU *pdu) |
| 452 | { |
| 453 | return pdu->cancelled; |
| 454 | } |
| 455 | |
| 456 | void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu); |
| 457 | void v9fs_path_init(V9fsPath *path); |
| 458 | void v9fs_path_free(V9fsPath *path); |
| 459 | int G_GNUC_PRINTF(2, 3) v9fs_path_sprintf(V9fsPath *path, const char *fmt, |
| 460 | ...); |
| 461 | void v9fs_path_copy(V9fsPath *dst, const V9fsPath *src); |
| 462 | size_t v9fs_readdir_response_size(V9fsString *name); |
| 463 | int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, |
| 464 | const char *name, V9fsPath *path); |
| 465 | int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, |
| 466 | Error **errp); |
| 467 | void v9fs_device_unrealize_common(V9fsState *s); |
| 468 | |
| 469 | V9fsPDU *pdu_alloc(V9fsState *s); |
| 470 | void pdu_free(V9fsPDU *pdu); |
| 471 | void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr); |
| 472 | void v9fs_reset(V9fsState *s); |
| 473 | |
| 474 | struct V9fsTransport { |
| 475 | ssize_t coroutine_fn (*pdu_vmarshal)(V9fsPDU *pdu, size_t offset, |
| 476 | const char *fmt, va_list ap); |
| 477 | ssize_t coroutine_fn (*pdu_vunmarshal)(V9fsPDU *pdu, size_t offset, |
| 478 | const char *fmt, va_list ap); |
| 479 | void coroutine_fn (*init_in_iov_from_pdu)(V9fsPDU *pdu, |
| 480 | struct iovec **piov, |
| 481 | unsigned int *pniov, |
| 482 | size_t size); |
| 483 | void coroutine_fn (*init_out_iov_from_pdu)(V9fsPDU *pdu, |
| 484 | struct iovec **piov, |
| 485 | unsigned int *pniov, |
| 486 | size_t size); |
| 487 | void coroutine_fn (*push_and_notify)(V9fsPDU *pdu); |
| 488 | size_t coroutine_fn (*msize_limit)(V9fsState *s); |
| 489 | size_t coroutine_fn (*response_buffer_size)(V9fsPDU *pdu); |
| 490 | }; |
| 491 | |
| 492 | #endif |