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 "qemu/error-report.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 /* 'man 2 close' suggests to ignore close() errors except of EBADF */ 202 if (unlikely(err && errno == EBADF)) { 203 /* unexpected case as we should have checked for a valid file handle */ 204 error_report("9pfs: WARNING: v9fs_co_close() failed with EBADF"); 205 } else { 206 total_open_fd--; 207 } 208 return err; 209 } 210 211 int coroutine_fn v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) 212 { 213 int err; 214 V9fsState *s = pdu->s; 215 216 if (v9fs_request_cancelled(pdu)) { 217 return -EINTR; 218 } 219 v9fs_co_run_in_worker( 220 { 221 err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync); 222 if (err < 0) { 223 err = -errno; 224 } 225 }); 226 return err; 227 } 228 229 int coroutine_fn v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, 230 V9fsFidState *newdirfid, V9fsString *name) 231 { 232 int err; 233 V9fsState *s = pdu->s; 234 235 if (v9fs_request_cancelled(pdu)) { 236 return -EINTR; 237 } 238 v9fs_path_read_lock(s); 239 v9fs_co_run_in_worker( 240 { 241 err = s->ops->link(&s->ctx, &oldfid->path, 242 &newdirfid->path, name->data); 243 if (err < 0) { 244 err = -errno; 245 } 246 }); 247 v9fs_path_unlock(s); 248 return err; 249 } 250 251 int coroutine_fn v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, 252 struct iovec *iov, int iovcnt, int64_t offset) 253 { 254 int err; 255 V9fsState *s = pdu->s; 256 257 if (v9fs_request_cancelled(pdu)) { 258 return -EINTR; 259 } 260 fsdev_co_throttle_request(s->ctx.fst, THROTTLE_WRITE, iov, iovcnt); 261 v9fs_co_run_in_worker( 262 { 263 err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset); 264 if (err < 0) { 265 err = -errno; 266 } 267 }); 268 return err; 269 } 270 271 int coroutine_fn v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp, 272 struct iovec *iov, int iovcnt, int64_t offset) 273 { 274 int err; 275 V9fsState *s = pdu->s; 276 277 if (v9fs_request_cancelled(pdu)) { 278 return -EINTR; 279 } 280 fsdev_co_throttle_request(s->ctx.fst, THROTTLE_READ, iov, iovcnt); 281 v9fs_co_run_in_worker( 282 { 283 err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset); 284 if (err < 0) { 285 err = -errno; 286 } 287 }); 288 return err; 289 } 290