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