9p-synth.c 16 KB

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