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