cofs.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * 9p backend
  3. *
  4. * Copyright IBM, Corp. 2011
  5. *
  6. * Authors:
  7. * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2. See
  10. * the COPYING file in the top-level directory.
  11. *
  12. */
  13. /*
  14. * Not so fast! You might want to read the 9p developer docs first:
  15. * https://wiki.qemu.org/Documentation/9p
  16. */
  17. #include "qemu/osdep.h"
  18. #include "fsdev/qemu-fsdev.h"
  19. #include "qemu/thread.h"
  20. #include "qemu/main-loop.h"
  21. #include "coth.h"
  22. static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf)
  23. {
  24. ssize_t len, maxlen = PATH_MAX;
  25. buf->data = g_malloc(PATH_MAX);
  26. for (;;) {
  27. len = s->ops->readlink(&s->ctx, path, buf->data, maxlen);
  28. if (len < 0) {
  29. g_free(buf->data);
  30. buf->data = NULL;
  31. buf->size = 0;
  32. break;
  33. } else if (len == maxlen) {
  34. /*
  35. * We dodn't have space to put the NULL or we have more
  36. * to read. Increase the size and try again
  37. */
  38. maxlen *= 2;
  39. g_free(buf->data);
  40. buf->data = g_malloc(maxlen);
  41. continue;
  42. }
  43. /*
  44. * Null terminate the readlink output
  45. */
  46. buf->data[len] = '\0';
  47. buf->size = len;
  48. break;
  49. }
  50. return len;
  51. }
  52. int coroutine_fn v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf)
  53. {
  54. int err;
  55. V9fsState *s = pdu->s;
  56. if (v9fs_request_cancelled(pdu)) {
  57. return -EINTR;
  58. }
  59. v9fs_path_read_lock(s);
  60. v9fs_co_run_in_worker(
  61. {
  62. err = __readlink(s, path, buf);
  63. if (err < 0) {
  64. err = -errno;
  65. }
  66. });
  67. v9fs_path_unlock(s);
  68. return err;
  69. }
  70. int coroutine_fn v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path,
  71. struct statfs *stbuf)
  72. {
  73. int err;
  74. V9fsState *s = pdu->s;
  75. if (v9fs_request_cancelled(pdu)) {
  76. return -EINTR;
  77. }
  78. v9fs_path_read_lock(s);
  79. v9fs_co_run_in_worker(
  80. {
  81. err = s->ops->statfs(&s->ctx, path, stbuf);
  82. if (err < 0) {
  83. err = -errno;
  84. }
  85. });
  86. v9fs_path_unlock(s);
  87. return err;
  88. }
  89. int coroutine_fn v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode)
  90. {
  91. int err;
  92. FsCred cred;
  93. V9fsState *s = pdu->s;
  94. if (v9fs_request_cancelled(pdu)) {
  95. return -EINTR;
  96. }
  97. cred_init(&cred);
  98. cred.fc_mode = mode;
  99. v9fs_path_read_lock(s);
  100. v9fs_co_run_in_worker(
  101. {
  102. err = s->ops->chmod(&s->ctx, path, &cred);
  103. if (err < 0) {
  104. err = -errno;
  105. }
  106. });
  107. v9fs_path_unlock(s);
  108. return err;
  109. }
  110. int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path,
  111. struct timespec times[2])
  112. {
  113. int err;
  114. V9fsState *s = pdu->s;
  115. if (v9fs_request_cancelled(pdu)) {
  116. return -EINTR;
  117. }
  118. v9fs_path_read_lock(s);
  119. v9fs_co_run_in_worker(
  120. {
  121. err = s->ops->utimensat(&s->ctx, path, times);
  122. if (err < 0) {
  123. err = -errno;
  124. }
  125. });
  126. v9fs_path_unlock(s);
  127. return err;
  128. }
  129. int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid,
  130. gid_t gid)
  131. {
  132. int err;
  133. FsCred cred;
  134. V9fsState *s = pdu->s;
  135. if (v9fs_request_cancelled(pdu)) {
  136. return -EINTR;
  137. }
  138. cred_init(&cred);
  139. cred.fc_uid = uid;
  140. cred.fc_gid = gid;
  141. v9fs_path_read_lock(s);
  142. v9fs_co_run_in_worker(
  143. {
  144. err = s->ops->chown(&s->ctx, path, &cred);
  145. if (err < 0) {
  146. err = -errno;
  147. }
  148. });
  149. v9fs_path_unlock(s);
  150. return err;
  151. }
  152. int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size)
  153. {
  154. int err;
  155. V9fsState *s = pdu->s;
  156. if (v9fs_request_cancelled(pdu)) {
  157. return -EINTR;
  158. }
  159. v9fs_path_read_lock(s);
  160. v9fs_co_run_in_worker(
  161. {
  162. err = s->ops->truncate(&s->ctx, path, size);
  163. if (err < 0) {
  164. err = -errno;
  165. }
  166. });
  167. v9fs_path_unlock(s);
  168. return err;
  169. }
  170. int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp,
  171. V9fsString *name, uid_t uid, gid_t gid,
  172. dev_t dev, mode_t mode, struct stat *stbuf)
  173. {
  174. int err;
  175. V9fsPath path;
  176. FsCred cred;
  177. V9fsState *s = pdu->s;
  178. if (v9fs_request_cancelled(pdu)) {
  179. return -EINTR;
  180. }
  181. cred_init(&cred);
  182. cred.fc_uid = uid;
  183. cred.fc_gid = gid;
  184. cred.fc_mode = mode;
  185. cred.fc_rdev = dev;
  186. v9fs_path_read_lock(s);
  187. v9fs_co_run_in_worker(
  188. {
  189. err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred);
  190. if (err < 0) {
  191. err = -errno;
  192. } else {
  193. v9fs_path_init(&path);
  194. err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
  195. if (!err) {
  196. err = s->ops->lstat(&s->ctx, &path, stbuf);
  197. if (err < 0) {
  198. err = -errno;
  199. }
  200. }
  201. v9fs_path_free(&path);
  202. }
  203. });
  204. v9fs_path_unlock(s);
  205. return err;
  206. }
  207. /* Only works with path name based fid */
  208. int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path)
  209. {
  210. int err;
  211. V9fsState *s = pdu->s;
  212. if (v9fs_request_cancelled(pdu)) {
  213. return -EINTR;
  214. }
  215. v9fs_path_read_lock(s);
  216. v9fs_co_run_in_worker(
  217. {
  218. err = s->ops->remove(&s->ctx, path->data);
  219. if (err < 0) {
  220. err = -errno;
  221. }
  222. });
  223. v9fs_path_unlock(s);
  224. return err;
  225. }
  226. int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path,
  227. V9fsString *name, int flags)
  228. {
  229. int err;
  230. V9fsState *s = pdu->s;
  231. if (v9fs_request_cancelled(pdu)) {
  232. return -EINTR;
  233. }
  234. v9fs_path_read_lock(s);
  235. v9fs_co_run_in_worker(
  236. {
  237. err = s->ops->unlinkat(&s->ctx, path, name->data, flags);
  238. if (err < 0) {
  239. err = -errno;
  240. }
  241. });
  242. v9fs_path_unlock(s);
  243. return err;
  244. }
  245. /* Only work with path name based fid */
  246. int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath,
  247. V9fsPath *newpath)
  248. {
  249. int err;
  250. V9fsState *s = pdu->s;
  251. if (v9fs_request_cancelled(pdu)) {
  252. return -EINTR;
  253. }
  254. v9fs_co_run_in_worker(
  255. {
  256. err = s->ops->rename(&s->ctx, oldpath->data, newpath->data);
  257. if (err < 0) {
  258. err = -errno;
  259. }
  260. });
  261. return err;
  262. }
  263. int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath,
  264. V9fsString *oldname, V9fsPath *newdirpath,
  265. V9fsString *newname)
  266. {
  267. int err;
  268. V9fsState *s = pdu->s;
  269. if (v9fs_request_cancelled(pdu)) {
  270. return -EINTR;
  271. }
  272. v9fs_co_run_in_worker(
  273. {
  274. err = s->ops->renameat(&s->ctx, olddirpath, oldname->data,
  275. newdirpath, newname->data);
  276. if (err < 0) {
  277. err = -errno;
  278. }
  279. });
  280. return err;
  281. }
  282. int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp,
  283. V9fsString *name, const char *oldpath,
  284. gid_t gid, struct stat *stbuf)
  285. {
  286. int err;
  287. FsCred cred;
  288. V9fsPath path;
  289. V9fsState *s = pdu->s;
  290. if (v9fs_request_cancelled(pdu)) {
  291. return -EINTR;
  292. }
  293. cred_init(&cred);
  294. cred.fc_uid = dfidp->uid;
  295. cred.fc_gid = gid;
  296. cred.fc_mode = 0777;
  297. v9fs_path_read_lock(s);
  298. v9fs_co_run_in_worker(
  299. {
  300. err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path,
  301. name->data, &cred);
  302. if (err < 0) {
  303. err = -errno;
  304. } else {
  305. v9fs_path_init(&path);
  306. err = v9fs_name_to_path(s, &dfidp->path, name->data, &path);
  307. if (!err) {
  308. err = s->ops->lstat(&s->ctx, &path, stbuf);
  309. if (err < 0) {
  310. err = -errno;
  311. }
  312. }
  313. v9fs_path_free(&path);
  314. }
  315. });
  316. v9fs_path_unlock(s);
  317. return err;
  318. }
  319. /*
  320. * For path name based fid we don't block. So we can
  321. * directly call the fs driver ops.
  322. */
  323. int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath,
  324. const char *name, V9fsPath *path)
  325. {
  326. int err;
  327. V9fsState *s = pdu->s;
  328. if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
  329. err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
  330. if (err < 0) {
  331. err = -errno;
  332. }
  333. } else {
  334. if (v9fs_request_cancelled(pdu)) {
  335. return -EINTR;
  336. }
  337. v9fs_co_run_in_worker(
  338. {
  339. err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
  340. if (err < 0) {
  341. err = -errno;
  342. }
  343. });
  344. }
  345. return err;
  346. }