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