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