cofile.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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. int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode,
  23. V9fsStatDotl *v9stat)
  24. {
  25. int err = 0;
  26. V9fsState *s = pdu->s;
  27. if (v9fs_request_cancelled(pdu)) {
  28. return -EINTR;
  29. }
  30. if (s->ctx.exops.get_st_gen) {
  31. v9fs_path_read_lock(s);
  32. v9fs_co_run_in_worker(
  33. {
  34. err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode,
  35. &v9stat->st_gen);
  36. if (err < 0) {
  37. err = -errno;
  38. }
  39. });
  40. v9fs_path_unlock(s);
  41. }
  42. return err;
  43. }
  44. int coroutine_fn v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf)
  45. {
  46. int err;
  47. V9fsState *s = pdu->s;
  48. if (v9fs_request_cancelled(pdu)) {
  49. return -EINTR;
  50. }
  51. v9fs_path_read_lock(s);
  52. v9fs_co_run_in_worker(
  53. {
  54. err = s->ops->lstat(&s->ctx, path, stbuf);
  55. if (err < 0) {
  56. err = -errno;
  57. }
  58. });
  59. v9fs_path_unlock(s);
  60. return err;
  61. }
  62. int coroutine_fn v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp,
  63. struct stat *stbuf)
  64. {
  65. int err;
  66. V9fsState *s = pdu->s;
  67. if (v9fs_request_cancelled(pdu)) {
  68. return -EINTR;
  69. }
  70. v9fs_co_run_in_worker(
  71. {
  72. err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf);
  73. if (err < 0) {
  74. err = -errno;
  75. }
  76. });
  77. /*
  78. * Some FS driver (local:mapped-file) can't support fetching attributes
  79. * using file descriptor. Use Path name in that case.
  80. */
  81. if (err == -EOPNOTSUPP) {
  82. err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
  83. if (err == -ENOENT) {
  84. /*
  85. * fstat on an unlinked file. Work with partial results
  86. * returned from s->ops->fstat
  87. */
  88. err = 0;
  89. }
  90. }
  91. return err;
  92. }
  93. int coroutine_fn v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags)
  94. {
  95. int err;
  96. V9fsState *s = pdu->s;
  97. if (v9fs_request_cancelled(pdu)) {
  98. return -EINTR;
  99. }
  100. v9fs_path_read_lock(s);
  101. v9fs_co_run_in_worker(
  102. {
  103. err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs);
  104. if (err == -1) {
  105. err = -errno;
  106. } else {
  107. err = 0;
  108. }
  109. });
  110. v9fs_path_unlock(s);
  111. if (!err) {
  112. total_open_fd++;
  113. if (total_open_fd > open_fd_hw) {
  114. v9fs_reclaim_fd(pdu);
  115. }
  116. }
  117. return err;
  118. }
  119. int coroutine_fn v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp,
  120. V9fsString *name, gid_t gid, int flags, int mode,
  121. struct stat *stbuf)
  122. {
  123. int err;
  124. FsCred cred;
  125. V9fsPath path;
  126. V9fsState *s = pdu->s;
  127. if (v9fs_request_cancelled(pdu)) {
  128. return -EINTR;
  129. }
  130. cred_init(&cred);
  131. cred.fc_mode = mode & 07777;
  132. cred.fc_uid = fidp->uid;
  133. cred.fc_gid = gid;
  134. /*
  135. * Hold the directory fid lock so that directory path name
  136. * don't change. Take the write lock to be sure this fid
  137. * cannot be used by another operation.
  138. */
  139. v9fs_path_write_lock(s);
  140. v9fs_co_run_in_worker(
  141. {
  142. err = s->ops->open2(&s->ctx, &fidp->path,
  143. name->data, flags, &cred, &fidp->fs);
  144. if (err < 0) {
  145. err = -errno;
  146. } else {
  147. v9fs_path_init(&path);
  148. err = v9fs_name_to_path(s, &fidp->path, name->data, &path);
  149. if (!err) {
  150. err = s->ops->lstat(&s->ctx, &path, stbuf);
  151. if (err < 0) {
  152. err = -errno;
  153. s->ops->close(&s->ctx, &fidp->fs);
  154. } else {
  155. v9fs_path_copy(&fidp->path, &path);
  156. }
  157. } else {
  158. s->ops->close(&s->ctx, &fidp->fs);
  159. }
  160. v9fs_path_free(&path);
  161. }
  162. });
  163. v9fs_path_unlock(s);
  164. if (!err) {
  165. total_open_fd++;
  166. if (total_open_fd > open_fd_hw) {
  167. v9fs_reclaim_fd(pdu);
  168. }
  169. }
  170. return err;
  171. }
  172. int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs)
  173. {
  174. int err;
  175. V9fsState *s = pdu->s;
  176. if (v9fs_request_cancelled(pdu)) {
  177. return -EINTR;
  178. }
  179. v9fs_co_run_in_worker(
  180. {
  181. err = s->ops->close(&s->ctx, fs);
  182. if (err < 0) {
  183. err = -errno;
  184. }
  185. });
  186. if (!err) {
  187. total_open_fd--;
  188. }
  189. return err;
  190. }
  191. int coroutine_fn v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync)
  192. {
  193. int err;
  194. V9fsState *s = pdu->s;
  195. if (v9fs_request_cancelled(pdu)) {
  196. return -EINTR;
  197. }
  198. v9fs_co_run_in_worker(
  199. {
  200. err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync);
  201. if (err < 0) {
  202. err = -errno;
  203. }
  204. });
  205. return err;
  206. }
  207. int coroutine_fn v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid,
  208. V9fsFidState *newdirfid, V9fsString *name)
  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->link(&s->ctx, &oldfid->path,
  219. &newdirfid->path, name->data);
  220. if (err < 0) {
  221. err = -errno;
  222. }
  223. });
  224. v9fs_path_unlock(s);
  225. return err;
  226. }
  227. int coroutine_fn v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
  228. struct iovec *iov, int iovcnt, int64_t offset)
  229. {
  230. int err;
  231. V9fsState *s = pdu->s;
  232. if (v9fs_request_cancelled(pdu)) {
  233. return -EINTR;
  234. }
  235. fsdev_co_throttle_request(s->ctx.fst, THROTTLE_WRITE, iov, iovcnt);
  236. v9fs_co_run_in_worker(
  237. {
  238. err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
  239. if (err < 0) {
  240. err = -errno;
  241. }
  242. });
  243. return err;
  244. }
  245. int coroutine_fn v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
  246. struct iovec *iov, int iovcnt, int64_t offset)
  247. {
  248. int err;
  249. V9fsState *s = pdu->s;
  250. if (v9fs_request_cancelled(pdu)) {
  251. return -EINTR;
  252. }
  253. fsdev_co_throttle_request(s->ctx.fst, THROTTLE_READ, iov, iovcnt);
  254. v9fs_co_run_in_worker(
  255. {
  256. err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
  257. if (err < 0) {
  258. err = -errno;
  259. }
  260. });
  261. return err;
  262. }