cofs.c 9.0 KB

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