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_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) 21 { 22 int err; 23 ssize_t len; 24 V9fsState *s = pdu->s; 25 26 if (v9fs_request_cancelled(pdu)) { 27 return -EINTR; 28 } 29 buf->data = g_malloc(PATH_MAX); 30 v9fs_path_read_lock(s); 31 v9fs_co_run_in_worker( 32 { 33 len = s->ops->readlink(&s->ctx, path, 34 buf->data, PATH_MAX - 1); 35 if (len > -1) { 36 buf->size = len; 37 buf->data[len] = 0; 38 err = 0; 39 } else { 40 err = -errno; 41 } 42 }); 43 v9fs_path_unlock(s); 44 if (err) { 45 g_free(buf->data); 46 buf->data = NULL; 47 buf->size = 0; 48 } 49 return err; 50 } 51 52 int v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, struct statfs *stbuf) 53 { 54 int err; 55 V9fsState *s = pdu->s; 56 57 if (v9fs_request_cancelled(pdu)) { 58 return -EINTR; 59 } 60 v9fs_path_read_lock(s); 61 v9fs_co_run_in_worker( 62 { 63 err = s->ops->statfs(&s->ctx, path, stbuf); 64 if (err < 0) { 65 err = -errno; 66 } 67 }); 68 v9fs_path_unlock(s); 69 return err; 70 } 71 72 int v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) 73 { 74 int err; 75 FsCred cred; 76 V9fsState *s = pdu->s; 77 78 if (v9fs_request_cancelled(pdu)) { 79 return -EINTR; 80 } 81 cred_init(&cred); 82 cred.fc_mode = mode; 83 v9fs_path_read_lock(s); 84 v9fs_co_run_in_worker( 85 { 86 err = s->ops->chmod(&s->ctx, path, &cred); 87 if (err < 0) { 88 err = -errno; 89 } 90 }); 91 v9fs_path_unlock(s); 92 return err; 93 } 94 95 int v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, 96 struct timespec times[2]) 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->utimensat(&s->ctx, path, times); 108 if (err < 0) { 109 err = -errno; 110 } 111 }); 112 v9fs_path_unlock(s); 113 return err; 114 } 115 116 int v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid) 117 { 118 int err; 119 FsCred cred; 120 V9fsState *s = pdu->s; 121 122 if (v9fs_request_cancelled(pdu)) { 123 return -EINTR; 124 } 125 cred_init(&cred); 126 cred.fc_uid = uid; 127 cred.fc_gid = gid; 128 v9fs_path_read_lock(s); 129 v9fs_co_run_in_worker( 130 { 131 err = s->ops->chown(&s->ctx, path, &cred); 132 if (err < 0) { 133 err = -errno; 134 } 135 }); 136 v9fs_path_unlock(s); 137 return err; 138 } 139 140 int v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) 141 { 142 int err; 143 V9fsState *s = pdu->s; 144 145 if (v9fs_request_cancelled(pdu)) { 146 return -EINTR; 147 } 148 v9fs_path_read_lock(s); 149 v9fs_co_run_in_worker( 150 { 151 err = s->ops->truncate(&s->ctx, path, size); 152 if (err < 0) { 153 err = -errno; 154 } 155 }); 156 v9fs_path_unlock(s); 157 return err; 158 } 159 160 int v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid, 161 gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf) 162 { 163 int err; 164 V9fsPath path; 165 FsCred cred; 166 V9fsState *s = pdu->s; 167 168 if (v9fs_request_cancelled(pdu)) { 169 return -EINTR; 170 } 171 cred_init(&cred); 172 cred.fc_uid = uid; 173 cred.fc_gid = gid; 174 cred.fc_mode = mode; 175 cred.fc_rdev = dev; 176 v9fs_path_read_lock(s); 177 v9fs_co_run_in_worker( 178 { 179 err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred); 180 if (err < 0) { 181 err = -errno; 182 } else { 183 v9fs_path_init(&path); 184 err = v9fs_name_to_path(s, &fidp->path, name->data, &path); 185 if (!err) { 186 err = s->ops->lstat(&s->ctx, &path, stbuf); 187 if (err < 0) { 188 err = -errno; 189 } 190 } 191 v9fs_path_free(&path); 192 } 193 }); 194 v9fs_path_unlock(s); 195 return err; 196 } 197 198 /* Only works with path name based fid */ 199 int v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) 200 { 201 int err; 202 V9fsState *s = pdu->s; 203 204 if (v9fs_request_cancelled(pdu)) { 205 return -EINTR; 206 } 207 v9fs_path_read_lock(s); 208 v9fs_co_run_in_worker( 209 { 210 err = s->ops->remove(&s->ctx, path->data); 211 if (err < 0) { 212 err = -errno; 213 } 214 }); 215 v9fs_path_unlock(s); 216 return err; 217 } 218 219 int v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, V9fsString *name, int flags) 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->unlinkat(&s->ctx, path, name->data, flags); 231 if (err < 0) { 232 err = -errno; 233 } 234 }); 235 v9fs_path_unlock(s); 236 return err; 237 } 238 239 /* Only work with path name based fid */ 240 int v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, V9fsPath *newpath) 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->rename(&s->ctx, oldpath->data, newpath->data); 251 if (err < 0) { 252 err = -errno; 253 } 254 }); 255 return err; 256 } 257 258 int v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, V9fsString *oldname, 259 V9fsPath *newdirpath, V9fsString *newname) 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->renameat(&s->ctx, olddirpath, oldname->data, 270 newdirpath, newname->data); 271 if (err < 0) { 272 err = -errno; 273 } 274 }); 275 return err; 276 } 277 278 int v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, V9fsString *name, 279 const char *oldpath, gid_t gid, struct stat *stbuf) 280 { 281 int err; 282 FsCred cred; 283 V9fsPath path; 284 V9fsState *s = pdu->s; 285 286 if (v9fs_request_cancelled(pdu)) { 287 return -EINTR; 288 } 289 cred_init(&cred); 290 cred.fc_uid = dfidp->uid; 291 cred.fc_gid = gid; 292 cred.fc_mode = 0777; 293 v9fs_path_read_lock(s); 294 v9fs_co_run_in_worker( 295 { 296 err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path, 297 name->data, &cred); 298 if (err < 0) { 299 err = -errno; 300 } else { 301 v9fs_path_init(&path); 302 err = v9fs_name_to_path(s, &dfidp->path, name->data, &path); 303 if (!err) { 304 err = s->ops->lstat(&s->ctx, &path, stbuf); 305 if (err < 0) { 306 err = -errno; 307 } 308 } 309 v9fs_path_free(&path); 310 } 311 }); 312 v9fs_path_unlock(s); 313 return err; 314 } 315 316 /* 317 * For path name based fid we don't block. So we can 318 * directly call the fs driver ops. 319 */ 320 int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, 321 const char *name, V9fsPath *path) 322 { 323 int err; 324 V9fsState *s = pdu->s; 325 326 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { 327 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 328 if (err < 0) { 329 err = -errno; 330 } 331 } else { 332 if (v9fs_request_cancelled(pdu)) { 333 return -EINTR; 334 } 335 v9fs_co_run_in_worker( 336 { 337 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 338 if (err < 0) { 339 err = -errno; 340 } 341 }); 342 } 343 return err; 344 } 345