1 2 /* 3 * Virtio 9p backend 4 * 5 * Copyright IBM, Corp. 2011 6 * 7 * Authors: 8 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 9 * 10 * This work is licensed under the terms of the GNU GPL, version 2. See 11 * the COPYING file in the top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "fsdev/qemu-fsdev.h" 17 #include "qemu/thread.h" 18 #include "qemu/coroutine.h" 19 #include "coth.h" 20 21 int 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 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 v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf) 66 { 67 int err; 68 V9fsState *s = pdu->s; 69 70 if (v9fs_request_cancelled(pdu)) { 71 return -EINTR; 72 } 73 v9fs_co_run_in_worker( 74 { 75 err = s->ops->fstat(&s->ctx, fidp->fid_type, &fidp->fs, stbuf); 76 if (err < 0) { 77 err = -errno; 78 } 79 }); 80 /* 81 * Some FS driver (local:mapped-file) can't support fetching attributes 82 * using file descriptor. Use Path name in that case. 83 */ 84 if (err == -EOPNOTSUPP) { 85 err = v9fs_co_lstat(pdu, &fidp->path, stbuf); 86 if (err == -ENOENT) { 87 /* 88 * fstat on an unlinked file. Work with partial results 89 * returned from s->ops->fstat 90 */ 91 err = 0; 92 } 93 } 94 return err; 95 } 96 97 int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags) 98 { 99 int err; 100 V9fsState *s = pdu->s; 101 102 if (v9fs_request_cancelled(pdu)) { 103 return -EINTR; 104 } 105 v9fs_path_read_lock(s); 106 v9fs_co_run_in_worker( 107 { 108 err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs); 109 if (err == -1) { 110 err = -errno; 111 } else { 112 err = 0; 113 } 114 }); 115 v9fs_path_unlock(s); 116 if (!err) { 117 total_open_fd++; 118 if (total_open_fd > open_fd_hw) { 119 v9fs_reclaim_fd(pdu); 120 } 121 } 122 return err; 123 } 124 125 int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, 126 int flags, int mode, struct stat *stbuf) 127 { 128 int err; 129 FsCred cred; 130 V9fsPath path; 131 V9fsState *s = pdu->s; 132 133 if (v9fs_request_cancelled(pdu)) { 134 return -EINTR; 135 } 136 cred_init(&cred); 137 cred.fc_mode = mode & 07777; 138 cred.fc_uid = fidp->uid; 139 cred.fc_gid = gid; 140 /* 141 * Hold the directory fid lock so that directory path name 142 * don't change. Read lock is fine because this fid cannot 143 * be used by any other operation. 144 */ 145 v9fs_path_read_lock(s); 146 v9fs_co_run_in_worker( 147 { 148 err = s->ops->open2(&s->ctx, &fidp->path, 149 name->data, flags, &cred, &fidp->fs); 150 if (err < 0) { 151 err = -errno; 152 } else { 153 v9fs_path_init(&path); 154 err = v9fs_name_to_path(s, &fidp->path, name->data, &path); 155 if (!err) { 156 err = s->ops->lstat(&s->ctx, &path, stbuf); 157 if (err < 0) { 158 err = -errno; 159 s->ops->close(&s->ctx, &fidp->fs); 160 } else { 161 v9fs_path_copy(&fidp->path, &path); 162 } 163 } else { 164 s->ops->close(&s->ctx, &fidp->fs); 165 } 166 v9fs_path_free(&path); 167 } 168 }); 169 v9fs_path_unlock(s); 170 if (!err) { 171 total_open_fd++; 172 if (total_open_fd > open_fd_hw) { 173 v9fs_reclaim_fd(pdu); 174 } 175 } 176 return err; 177 } 178 179 int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) 180 { 181 int err; 182 V9fsState *s = pdu->s; 183 184 if (v9fs_request_cancelled(pdu)) { 185 return -EINTR; 186 } 187 v9fs_co_run_in_worker( 188 { 189 err = s->ops->close(&s->ctx, fs); 190 if (err < 0) { 191 err = -errno; 192 } 193 }); 194 if (!err) { 195 total_open_fd--; 196 } 197 return err; 198 } 199 200 int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) 201 { 202 int err; 203 V9fsState *s = pdu->s; 204 205 if (v9fs_request_cancelled(pdu)) { 206 return -EINTR; 207 } 208 v9fs_co_run_in_worker( 209 { 210 err = s->ops->fsync(&s->ctx, fidp->fid_type, &fidp->fs, datasync); 211 if (err < 0) { 212 err = -errno; 213 } 214 }); 215 return err; 216 } 217 218 int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, 219 V9fsFidState *newdirfid, V9fsString *name) 220 { 221 int err; 222 V9fsState *s = pdu->s; 223 224 if (v9fs_request_cancelled(pdu)) { 225 return -EINTR; 226 } 227 v9fs_path_read_lock(s); 228 v9fs_co_run_in_worker( 229 { 230 err = s->ops->link(&s->ctx, &oldfid->path, 231 &newdirfid->path, name->data); 232 if (err < 0) { 233 err = -errno; 234 } 235 }); 236 v9fs_path_unlock(s); 237 return err; 238 } 239 240 int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, 241 struct iovec *iov, int iovcnt, int64_t offset) 242 { 243 int err; 244 V9fsState *s = pdu->s; 245 246 if (v9fs_request_cancelled(pdu)) { 247 return -EINTR; 248 } 249 v9fs_co_run_in_worker( 250 { 251 err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset); 252 if (err < 0) { 253 err = -errno; 254 } 255 }); 256 return err; 257 } 258 259 int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp, 260 struct iovec *iov, int iovcnt, int64_t offset) 261 { 262 int err; 263 V9fsState *s = pdu->s; 264 265 if (v9fs_request_cancelled(pdu)) { 266 return -EINTR; 267 } 268 v9fs_co_run_in_worker( 269 { 270 err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset); 271 if (err < 0) { 272 err = -errno; 273 } 274 }); 275 return err; 276 } 277