9p-synth.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /*
  2. * 9p synthetic file system support
  3. *
  4. * Copyright IBM, Corp. 2011
  5. *
  6. * Authors:
  7. * Malahal Naineni <malahal@us.ibm.com>
  8. * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2. See
  11. * the COPYING file in the top-level directory.
  12. *
  13. */
  14. /*
  15. * Not so fast! You might want to read the 9p developer docs first:
  16. * https://wiki.qemu.org/Documentation/9p
  17. */
  18. #include "qemu/osdep.h"
  19. #include "9p.h"
  20. #include "fsdev/qemu-fsdev.h"
  21. #include "9p-synth.h"
  22. #include "qemu/rcu.h"
  23. #include "qemu/rcu_queue.h"
  24. #include "qemu/cutils.h"
  25. #include "system/qtest.h"
  26. /* Root node for synth file system */
  27. static V9fsSynthNode synth_root = {
  28. .name = "/",
  29. .actual_attr = {
  30. .mode = 0555 | S_IFDIR,
  31. .nlink = 1,
  32. },
  33. .attr = &synth_root.actual_attr,
  34. };
  35. static QemuMutex synth_mutex;
  36. static int synth_node_count;
  37. /* set to 1 when the synth fs is ready */
  38. static int synth_fs;
  39. static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode,
  40. const char *name,
  41. V9fsSynthNodeAttr *attr, int inode)
  42. {
  43. V9fsSynthNode *node;
  44. /* Add directory type and remove write bits */
  45. mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH);
  46. node = g_new0(V9fsSynthNode, 1);
  47. if (attr) {
  48. /* We are adding .. or . entries */
  49. node->attr = attr;
  50. node->attr->nlink++;
  51. } else {
  52. node->attr = &node->actual_attr;
  53. node->attr->inode = inode;
  54. node->attr->nlink = 1;
  55. /* We don't allow write to directories */
  56. node->attr->mode = mode;
  57. node->attr->write = NULL;
  58. node->attr->read = NULL;
  59. }
  60. node->private = node;
  61. pstrcpy(node->name, sizeof(node->name), name);
  62. QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
  63. return node;
  64. }
  65. int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode,
  66. const char *name, V9fsSynthNode **result)
  67. {
  68. V9fsSynthNode *node, *tmp;
  69. if (!synth_fs) {
  70. return -EAGAIN;
  71. }
  72. if (!name || (strlen(name) >= NAME_MAX)) {
  73. return -EINVAL;
  74. }
  75. if (!parent) {
  76. parent = &synth_root;
  77. }
  78. QEMU_LOCK_GUARD(&synth_mutex);
  79. QLIST_FOREACH(tmp, &parent->child, sibling) {
  80. if (!strcmp(tmp->name, name)) {
  81. return -EEXIST;
  82. }
  83. }
  84. /* Add the name */
  85. node = v9fs_add_dir_node(parent, mode, name, NULL, ++synth_node_count);
  86. v9fs_add_dir_node(node, parent->attr->mode, "..",
  87. parent->attr, parent->attr->inode);
  88. v9fs_add_dir_node(node, node->attr->mode, ".",
  89. node->attr, node->attr->inode);
  90. *result = node;
  91. return 0;
  92. }
  93. int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode,
  94. const char *name, v9fs_synth_read read,
  95. v9fs_synth_write write, void *arg)
  96. {
  97. V9fsSynthNode *node, *tmp;
  98. if (!synth_fs) {
  99. return -EAGAIN;
  100. }
  101. if (!name || (strlen(name) >= NAME_MAX)) {
  102. return -EINVAL;
  103. }
  104. if (!parent) {
  105. parent = &synth_root;
  106. }
  107. QEMU_LOCK_GUARD(&synth_mutex);
  108. QLIST_FOREACH(tmp, &parent->child, sibling) {
  109. if (!strcmp(tmp->name, name)) {
  110. return -EEXIST;
  111. }
  112. }
  113. /* Add file type and remove write bits */
  114. mode = ((mode & 0777) | S_IFREG);
  115. node = g_new0(V9fsSynthNode, 1);
  116. node->attr = &node->actual_attr;
  117. node->attr->inode = ++synth_node_count;
  118. node->attr->nlink = 1;
  119. node->attr->read = read;
  120. node->attr->write = write;
  121. node->attr->mode = mode;
  122. node->private = arg;
  123. pstrcpy(node->name, sizeof(node->name), name);
  124. QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling);
  125. return 0;
  126. }
  127. static void synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf)
  128. {
  129. stbuf->st_dev = 0;
  130. stbuf->st_ino = node->attr->inode;
  131. stbuf->st_mode = node->attr->mode;
  132. stbuf->st_nlink = node->attr->nlink;
  133. stbuf->st_uid = 0;
  134. stbuf->st_gid = 0;
  135. stbuf->st_rdev = 0;
  136. stbuf->st_size = 0;
  137. stbuf->st_blksize = 0;
  138. stbuf->st_blocks = 0;
  139. stbuf->st_atime = 0;
  140. stbuf->st_mtime = 0;
  141. stbuf->st_ctime = 0;
  142. }
  143. static int synth_lstat(FsContext *fs_ctx,
  144. V9fsPath *fs_path, struct stat *stbuf)
  145. {
  146. V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
  147. synth_fill_statbuf(node, stbuf);
  148. return 0;
  149. }
  150. static int synth_fstat(FsContext *fs_ctx, int fid_type,
  151. V9fsFidOpenState *fs, struct stat *stbuf)
  152. {
  153. V9fsSynthOpenState *synth_open = fs->private;
  154. synth_fill_statbuf(synth_open->node, stbuf);
  155. return 0;
  156. }
  157. static int synth_opendir(FsContext *ctx,
  158. V9fsPath *fs_path, V9fsFidOpenState *fs)
  159. {
  160. V9fsSynthOpenState *synth_open;
  161. V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
  162. /*
  163. * V9fsSynthOpenState contains 'struct dirent' which have OS-specific
  164. * properties, thus it's zero cleared on allocation here and below
  165. * in synth_open.
  166. */
  167. synth_open = g_new0(V9fsSynthOpenState, 1);
  168. synth_open->node = node;
  169. node->open_count++;
  170. fs->private = synth_open;
  171. return 0;
  172. }
  173. static int synth_closedir(FsContext *ctx, V9fsFidOpenState *fs)
  174. {
  175. V9fsSynthOpenState *synth_open = fs->private;
  176. V9fsSynthNode *node = synth_open->node;
  177. node->open_count--;
  178. g_free(synth_open);
  179. fs->private = NULL;
  180. return 0;
  181. }
  182. static off_t synth_telldir(FsContext *ctx, V9fsFidOpenState *fs)
  183. {
  184. V9fsSynthOpenState *synth_open = fs->private;
  185. return synth_open->offset;
  186. }
  187. static void synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
  188. {
  189. V9fsSynthOpenState *synth_open = fs->private;
  190. synth_open->offset = off;
  191. }
  192. static void synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs)
  193. {
  194. synth_seekdir(ctx, fs, 0);
  195. }
  196. static void synth_direntry(V9fsSynthNode *node,
  197. struct dirent *entry, off_t off)
  198. {
  199. size_t sz = strlen(node->name) + 1;
  200. /*
  201. * 'entry' is always inside of V9fsSynthOpenState which have NAME_MAX
  202. * back padding. Ensure we do not overflow it.
  203. */
  204. g_assert(sizeof(struct dirent) + NAME_MAX >=
  205. offsetof(struct dirent, d_name) + sz);
  206. memcpy(entry->d_name, node->name, sz);
  207. entry->d_ino = node->attr->inode;
  208. #ifdef CONFIG_DARWIN
  209. entry->d_seekoff = off + 1;
  210. #else
  211. entry->d_off = off + 1;
  212. #endif
  213. }
  214. static struct dirent *synth_get_dentry(V9fsSynthNode *dir,
  215. struct dirent *entry, off_t off)
  216. {
  217. int i = 0;
  218. V9fsSynthNode *node;
  219. rcu_read_lock();
  220. QLIST_FOREACH(node, &dir->child, sibling) {
  221. /* This is the off child of the directory */
  222. if (i == off) {
  223. break;
  224. }
  225. i++;
  226. }
  227. rcu_read_unlock();
  228. if (!node) {
  229. /* end of directory */
  230. return NULL;
  231. }
  232. synth_direntry(node, entry, off);
  233. return entry;
  234. }
  235. static struct dirent *synth_readdir(FsContext *ctx, V9fsFidOpenState *fs)
  236. {
  237. struct dirent *entry;
  238. V9fsSynthOpenState *synth_open = fs->private;
  239. V9fsSynthNode *node = synth_open->node;
  240. entry = synth_get_dentry(node, &synth_open->dent, synth_open->offset);
  241. if (entry) {
  242. synth_open->offset++;
  243. }
  244. return entry;
  245. }
  246. static int synth_open(FsContext *ctx, V9fsPath *fs_path,
  247. int flags, V9fsFidOpenState *fs)
  248. {
  249. V9fsSynthOpenState *synth_open;
  250. V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data;
  251. synth_open = g_new0(V9fsSynthOpenState, 1);
  252. synth_open->node = node;
  253. node->open_count++;
  254. fs->private = synth_open;
  255. return 0;
  256. }
  257. static int synth_open2(FsContext *fs_ctx, V9fsPath *dir_path,
  258. const char *name, int flags,
  259. FsCred *credp, V9fsFidOpenState *fs)
  260. {
  261. errno = ENOSYS;
  262. return -1;
  263. }
  264. static int synth_close(FsContext *ctx, V9fsFidOpenState *fs)
  265. {
  266. V9fsSynthOpenState *synth_open = fs->private;
  267. V9fsSynthNode *node = synth_open->node;
  268. node->open_count--;
  269. g_free(synth_open);
  270. fs->private = NULL;
  271. return 0;
  272. }
  273. static ssize_t synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs,
  274. const struct iovec *iov,
  275. int iovcnt, off_t offset)
  276. {
  277. int i, count = 0, wcount;
  278. V9fsSynthOpenState *synth_open = fs->private;
  279. V9fsSynthNode *node = synth_open->node;
  280. if (!node->attr->write) {
  281. errno = EPERM;
  282. return -1;
  283. }
  284. for (i = 0; i < iovcnt; i++) {
  285. wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len,
  286. offset, node->private);
  287. offset += wcount;
  288. count += wcount;
  289. /* If we wrote less than requested. we are done */
  290. if (wcount < iov[i].iov_len) {
  291. break;
  292. }
  293. }
  294. return count;
  295. }
  296. static ssize_t synth_preadv(FsContext *ctx, V9fsFidOpenState *fs,
  297. const struct iovec *iov,
  298. int iovcnt, off_t offset)
  299. {
  300. int i, count = 0, rcount;
  301. V9fsSynthOpenState *synth_open = fs->private;
  302. V9fsSynthNode *node = synth_open->node;
  303. if (!node->attr->read) {
  304. errno = EPERM;
  305. return -1;
  306. }
  307. for (i = 0; i < iovcnt; i++) {
  308. rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len,
  309. offset, node->private);
  310. offset += rcount;
  311. count += rcount;
  312. /* If we read less than requested. we are done */
  313. if (rcount < iov[i].iov_len) {
  314. break;
  315. }
  316. }
  317. return count;
  318. }
  319. static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset)
  320. {
  321. errno = ENOSYS;
  322. return -1;
  323. }
  324. static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
  325. {
  326. errno = EPERM;
  327. return -1;
  328. }
  329. static int synth_mknod(FsContext *fs_ctx, V9fsPath *path,
  330. const char *buf, FsCred *credp)
  331. {
  332. errno = EPERM;
  333. return -1;
  334. }
  335. static int synth_mkdir(FsContext *fs_ctx, V9fsPath *path,
  336. const char *buf, FsCred *credp)
  337. {
  338. errno = EPERM;
  339. return -1;
  340. }
  341. static ssize_t synth_readlink(FsContext *fs_ctx, V9fsPath *path,
  342. char *buf, size_t bufsz)
  343. {
  344. errno = ENOSYS;
  345. return -1;
  346. }
  347. static int synth_symlink(FsContext *fs_ctx, const char *oldpath,
  348. V9fsPath *newpath, const char *buf, FsCred *credp)
  349. {
  350. errno = EPERM;
  351. return -1;
  352. }
  353. static int synth_link(FsContext *fs_ctx, V9fsPath *oldpath,
  354. V9fsPath *newpath, const char *buf)
  355. {
  356. errno = EPERM;
  357. return -1;
  358. }
  359. static int synth_rename(FsContext *ctx, const char *oldpath,
  360. const char *newpath)
  361. {
  362. errno = EPERM;
  363. return -1;
  364. }
  365. static int synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp)
  366. {
  367. errno = EPERM;
  368. return -1;
  369. }
  370. static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path,
  371. const struct timespec *buf)
  372. {
  373. errno = EPERM;
  374. return 0;
  375. }
  376. static int synth_remove(FsContext *ctx, const char *path)
  377. {
  378. errno = EPERM;
  379. return -1;
  380. }
  381. static int synth_fsync(FsContext *ctx, int fid_type,
  382. V9fsFidOpenState *fs, int datasync)
  383. {
  384. errno = ENOSYS;
  385. return 0;
  386. }
  387. static int synth_statfs(FsContext *s, V9fsPath *fs_path,
  388. struct statfs *stbuf)
  389. {
  390. stbuf->f_type = 0xABCD;
  391. stbuf->f_bsize = 512;
  392. stbuf->f_blocks = 0;
  393. stbuf->f_files = synth_node_count;
  394. #ifndef CONFIG_DARWIN
  395. stbuf->f_namelen = NAME_MAX;
  396. #endif
  397. return 0;
  398. }
  399. static ssize_t synth_lgetxattr(FsContext *ctx, V9fsPath *path,
  400. const char *name, void *value, size_t size)
  401. {
  402. errno = ENOTSUP;
  403. return -1;
  404. }
  405. static ssize_t synth_llistxattr(FsContext *ctx, V9fsPath *path,
  406. void *value, size_t size)
  407. {
  408. errno = ENOTSUP;
  409. return -1;
  410. }
  411. static int synth_lsetxattr(FsContext *ctx, V9fsPath *path,
  412. const char *name, void *value,
  413. size_t size, int flags)
  414. {
  415. errno = ENOTSUP;
  416. return -1;
  417. }
  418. static int synth_lremovexattr(FsContext *ctx,
  419. V9fsPath *path, const char *name)
  420. {
  421. errno = ENOTSUP;
  422. return -1;
  423. }
  424. static int synth_name_to_path(FsContext *ctx, V9fsPath *dir_path,
  425. const char *name, V9fsPath *target)
  426. {
  427. V9fsSynthNode *node;
  428. V9fsSynthNode *dir_node;
  429. /* "." and ".." are not allowed */
  430. if (!strcmp(name, ".") || !strcmp(name, "..")) {
  431. errno = EINVAL;
  432. return -1;
  433. }
  434. if (!dir_path) {
  435. dir_node = &synth_root;
  436. } else {
  437. dir_node = *(V9fsSynthNode **)dir_path->data;
  438. }
  439. if (!strcmp(name, "/")) {
  440. node = dir_node;
  441. goto out;
  442. }
  443. /* search for the name in the children */
  444. rcu_read_lock();
  445. QLIST_FOREACH(node, &dir_node->child, sibling) {
  446. if (!strcmp(node->name, name)) {
  447. break;
  448. }
  449. }
  450. rcu_read_unlock();
  451. if (!node) {
  452. errno = ENOENT;
  453. return -1;
  454. }
  455. out:
  456. /* Copy the node pointer to fid */
  457. g_free(target->data);
  458. target->data = g_memdup(&node, sizeof(void *));
  459. target->size = sizeof(void *);
  460. return 0;
  461. }
  462. static int synth_renameat(FsContext *ctx, V9fsPath *olddir,
  463. const char *old_name, V9fsPath *newdir,
  464. const char *new_name)
  465. {
  466. errno = EPERM;
  467. return -1;
  468. }
  469. static int synth_unlinkat(FsContext *ctx, V9fsPath *dir,
  470. const char *name, int flags)
  471. {
  472. errno = EPERM;
  473. return -1;
  474. }
  475. static ssize_t v9fs_synth_qtest_write(void *buf, int len, off_t offset,
  476. void *arg)
  477. {
  478. return 1;
  479. }
  480. static ssize_t v9fs_synth_qtest_flush_write(void *buf, int len, off_t offset,
  481. void *arg)
  482. {
  483. bool should_block = !!*(uint8_t *)buf;
  484. if (should_block) {
  485. /* This will cause the server to call us again until we're cancelled */
  486. errno = EINTR;
  487. return -1;
  488. }
  489. return 1;
  490. }
  491. static int synth_init(FsContext *ctx, Error **errp)
  492. {
  493. QLIST_INIT(&synth_root.child);
  494. qemu_mutex_init(&synth_mutex);
  495. /* Add "." and ".." entries for root */
  496. v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
  497. "..", synth_root.attr, synth_root.attr->inode);
  498. v9fs_add_dir_node(&synth_root, synth_root.attr->mode,
  499. ".", synth_root.attr, synth_root.attr->inode);
  500. /* Mark the subsystem is ready for use */
  501. synth_fs = 1;
  502. if (qtest_enabled()) {
  503. V9fsSynthNode *node = NULL;
  504. int i, ret;
  505. /* Directory hierarchy for WALK test */
  506. for (i = 0; i < P9_MAXWELEM; i++) {
  507. char *name = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i);
  508. ret = qemu_v9fs_synth_mkdir(node, 0700, name, &node);
  509. assert(!ret);
  510. g_free(name);
  511. }
  512. /* File for LOPEN test */
  513. ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_LOPEN_FILE,
  514. NULL, NULL, ctx);
  515. assert(!ret);
  516. /* File for WRITE test */
  517. ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_WRITE_FILE,
  518. NULL, v9fs_synth_qtest_write, ctx);
  519. assert(!ret);
  520. /* File for FLUSH test */
  521. ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_FLUSH_FILE,
  522. NULL, v9fs_synth_qtest_flush_write,
  523. ctx);
  524. assert(!ret);
  525. /* Directory for READDIR test */
  526. {
  527. V9fsSynthNode *dir = NULL;
  528. ret = qemu_v9fs_synth_mkdir(
  529. NULL, 0700, QTEST_V9FS_SYNTH_READDIR_DIR, &dir
  530. );
  531. assert(!ret);
  532. for (i = 0; i < QTEST_V9FS_SYNTH_READDIR_NFILES; ++i) {
  533. char *name = g_strdup_printf(
  534. QTEST_V9FS_SYNTH_READDIR_FILE, i
  535. );
  536. ret = qemu_v9fs_synth_add_file(
  537. dir, 0, name, NULL, NULL, ctx
  538. );
  539. assert(!ret);
  540. g_free(name);
  541. }
  542. }
  543. }
  544. return 0;
  545. }
  546. FileOperations synth_ops = {
  547. .init = synth_init,
  548. .lstat = synth_lstat,
  549. .readlink = synth_readlink,
  550. .close = synth_close,
  551. .closedir = synth_closedir,
  552. .open = synth_open,
  553. .opendir = synth_opendir,
  554. .rewinddir = synth_rewinddir,
  555. .telldir = synth_telldir,
  556. .readdir = synth_readdir,
  557. .seekdir = synth_seekdir,
  558. .preadv = synth_preadv,
  559. .pwritev = synth_pwritev,
  560. .chmod = synth_chmod,
  561. .mknod = synth_mknod,
  562. .mkdir = synth_mkdir,
  563. .fstat = synth_fstat,
  564. .open2 = synth_open2,
  565. .symlink = synth_symlink,
  566. .link = synth_link,
  567. .truncate = synth_truncate,
  568. .rename = synth_rename,
  569. .chown = synth_chown,
  570. .utimensat = synth_utimensat,
  571. .remove = synth_remove,
  572. .fsync = synth_fsync,
  573. .statfs = synth_statfs,
  574. .lgetxattr = synth_lgetxattr,
  575. .llistxattr = synth_llistxattr,
  576. .lsetxattr = synth_lsetxattr,
  577. .lremovexattr = synth_lremovexattr,
  578. .name_to_path = synth_name_to_path,
  579. .renameat = synth_renameat,
  580. .unlinkat = synth_unlinkat,
  581. };