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