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 "coth.h" 24 25 static ssize_t __readlink(V9fsState *s, V9fsPath *path, V9fsString *buf) 26 { 27 ssize_t len, maxlen = PATH_MAX; 28 29 buf->data = g_malloc(PATH_MAX); 30 for (;;) { 31 len = s->ops->readlink(&s->ctx, path, buf->data, maxlen); 32 if (len < 0) { 33 g_free(buf->data); 34 buf->data = NULL; 35 buf->size = 0; 36 break; 37 } else if (len == maxlen) { 38 /* 39 * We dodn't have space to put the NULL or we have more 40 * to read. Increase the size and try again 41 */ 42 maxlen *= 2; 43 g_free(buf->data); 44 buf->data = g_malloc(maxlen); 45 continue; 46 } 47 /* 48 * Null terminate the readlink output 49 */ 50 buf->data[len] = '\0'; 51 buf->size = len; 52 break; 53 } 54 return len; 55 } 56 57 int coroutine_fn v9fs_co_readlink(V9fsPDU *pdu, V9fsPath *path, V9fsString *buf) 58 { 59 int err; 60 V9fsState *s = pdu->s; 61 62 if (v9fs_request_cancelled(pdu)) { 63 return -EINTR; 64 } 65 v9fs_path_read_lock(s); 66 v9fs_co_run_in_worker( 67 { 68 err = __readlink(s, path, buf); 69 if (err < 0) { 70 err = -errno; 71 } 72 }); 73 v9fs_path_unlock(s); 74 return err; 75 } 76 77 int coroutine_fn v9fs_co_statfs(V9fsPDU *pdu, V9fsPath *path, 78 struct statfs *stbuf) 79 { 80 int err; 81 V9fsState *s = pdu->s; 82 83 if (v9fs_request_cancelled(pdu)) { 84 return -EINTR; 85 } 86 v9fs_path_read_lock(s); 87 v9fs_co_run_in_worker( 88 { 89 err = s->ops->statfs(&s->ctx, path, stbuf); 90 if (err < 0) { 91 err = -errno; 92 } 93 }); 94 v9fs_path_unlock(s); 95 return err; 96 } 97 98 int coroutine_fn v9fs_co_chmod(V9fsPDU *pdu, V9fsPath *path, mode_t mode) 99 { 100 int err; 101 FsCred cred; 102 V9fsState *s = pdu->s; 103 104 if (v9fs_request_cancelled(pdu)) { 105 return -EINTR; 106 } 107 cred_init(&cred); 108 cred.fc_mode = mode; 109 v9fs_path_read_lock(s); 110 v9fs_co_run_in_worker( 111 { 112 err = s->ops->chmod(&s->ctx, path, &cred); 113 if (err < 0) { 114 err = -errno; 115 } 116 }); 117 v9fs_path_unlock(s); 118 return err; 119 } 120 121 int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, 122 struct timespec times[2]) 123 { 124 int err; 125 V9fsState *s = pdu->s; 126 127 if (v9fs_request_cancelled(pdu)) { 128 return -EINTR; 129 } 130 v9fs_path_read_lock(s); 131 v9fs_co_run_in_worker( 132 { 133 err = s->ops->utimensat(&s->ctx, path, times); 134 if (err < 0) { 135 err = -errno; 136 } 137 }); 138 v9fs_path_unlock(s); 139 return err; 140 } 141 142 int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp, 143 struct timespec times[2]) 144 { 145 int err; 146 V9fsState *s = pdu->s; 147 148 if (v9fs_request_cancelled(pdu)) { 149 return -EINTR; 150 } 151 v9fs_co_run_in_worker( 152 { 153 err = s->ops->futimens(&s->ctx, fidp->fid_type, &fidp->fs, times); 154 if (err < 0) { 155 err = -errno; 156 } 157 }); 158 return err; 159 } 160 161 int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, 162 gid_t gid) 163 { 164 int err; 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 v9fs_path_read_lock(s); 175 v9fs_co_run_in_worker( 176 { 177 err = s->ops->chown(&s->ctx, path, &cred); 178 if (err < 0) { 179 err = -errno; 180 } 181 }); 182 v9fs_path_unlock(s); 183 return err; 184 } 185 186 int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) 187 { 188 int err; 189 V9fsState *s = pdu->s; 190 191 if (v9fs_request_cancelled(pdu)) { 192 return -EINTR; 193 } 194 v9fs_path_read_lock(s); 195 v9fs_co_run_in_worker( 196 { 197 err = s->ops->truncate(&s->ctx, path, size); 198 if (err < 0) { 199 err = -errno; 200 } 201 }); 202 v9fs_path_unlock(s); 203 return err; 204 } 205 206 int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size) 207 { 208 int err; 209 V9fsState *s = pdu->s; 210 211 if (v9fs_request_cancelled(pdu)) { 212 return -EINTR; 213 } 214 v9fs_co_run_in_worker( 215 { 216 err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size); 217 if (err < 0) { 218 err = -errno; 219 } 220 }); 221 return err; 222 } 223 224 int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, 225 V9fsString *name, uid_t uid, gid_t gid, 226 dev_t dev, mode_t mode, struct stat *stbuf) 227 { 228 int err; 229 V9fsPath path; 230 FsCred cred; 231 V9fsState *s = pdu->s; 232 233 if (v9fs_request_cancelled(pdu)) { 234 return -EINTR; 235 } 236 cred_init(&cred); 237 cred.fc_uid = uid; 238 cred.fc_gid = gid; 239 cred.fc_mode = mode; 240 cred.fc_rdev = dev; 241 v9fs_path_read_lock(s); 242 v9fs_co_run_in_worker( 243 { 244 err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred); 245 if (err < 0) { 246 err = -errno; 247 } else { 248 v9fs_path_init(&path); 249 err = v9fs_name_to_path(s, &fidp->path, name->data, &path); 250 if (!err) { 251 err = s->ops->lstat(&s->ctx, &path, stbuf); 252 if (err < 0) { 253 err = -errno; 254 } 255 } 256 v9fs_path_free(&path); 257 } 258 }); 259 v9fs_path_unlock(s); 260 return err; 261 } 262 263 /* Only works with path name based fid */ 264 int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) 265 { 266 int err; 267 V9fsState *s = pdu->s; 268 269 if (v9fs_request_cancelled(pdu)) { 270 return -EINTR; 271 } 272 v9fs_path_read_lock(s); 273 v9fs_co_run_in_worker( 274 { 275 err = s->ops->remove(&s->ctx, path->data); 276 if (err < 0) { 277 err = -errno; 278 } 279 }); 280 v9fs_path_unlock(s); 281 return err; 282 } 283 284 int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, 285 V9fsString *name, int flags) 286 { 287 int err; 288 V9fsState *s = pdu->s; 289 290 if (v9fs_request_cancelled(pdu)) { 291 return -EINTR; 292 } 293 v9fs_path_read_lock(s); 294 v9fs_co_run_in_worker( 295 { 296 err = s->ops->unlinkat(&s->ctx, path, name->data, flags); 297 if (err < 0) { 298 err = -errno; 299 } 300 }); 301 v9fs_path_unlock(s); 302 return err; 303 } 304 305 /* Only work with path name based fid */ 306 int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, 307 V9fsPath *newpath) 308 { 309 int err; 310 V9fsState *s = pdu->s; 311 312 if (v9fs_request_cancelled(pdu)) { 313 return -EINTR; 314 } 315 v9fs_co_run_in_worker( 316 { 317 err = s->ops->rename(&s->ctx, oldpath->data, newpath->data); 318 if (err < 0) { 319 err = -errno; 320 } 321 }); 322 return err; 323 } 324 325 int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, 326 V9fsString *oldname, V9fsPath *newdirpath, 327 V9fsString *newname) 328 { 329 int err; 330 V9fsState *s = pdu->s; 331 332 if (v9fs_request_cancelled(pdu)) { 333 return -EINTR; 334 } 335 v9fs_co_run_in_worker( 336 { 337 err = s->ops->renameat(&s->ctx, olddirpath, oldname->data, 338 newdirpath, newname->data); 339 if (err < 0) { 340 err = -errno; 341 } 342 }); 343 return err; 344 } 345 346 int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, 347 V9fsString *name, const char *oldpath, 348 gid_t gid, struct stat *stbuf) 349 { 350 int err; 351 FsCred cred; 352 V9fsPath path; 353 V9fsState *s = pdu->s; 354 355 if (v9fs_request_cancelled(pdu)) { 356 return -EINTR; 357 } 358 cred_init(&cred); 359 cred.fc_uid = dfidp->uid; 360 cred.fc_gid = gid; 361 cred.fc_mode = 0777; 362 v9fs_path_read_lock(s); 363 v9fs_co_run_in_worker( 364 { 365 err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path, 366 name->data, &cred); 367 if (err < 0) { 368 err = -errno; 369 } else { 370 v9fs_path_init(&path); 371 err = v9fs_name_to_path(s, &dfidp->path, name->data, &path); 372 if (!err) { 373 err = s->ops->lstat(&s->ctx, &path, stbuf); 374 if (err < 0) { 375 err = -errno; 376 } 377 } 378 v9fs_path_free(&path); 379 } 380 }); 381 v9fs_path_unlock(s); 382 return err; 383 } 384 385 /* 386 * For path name based fid we don't block. So we can 387 * directly call the fs driver ops. 388 */ 389 int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, 390 const char *name, V9fsPath *path) 391 { 392 int err; 393 V9fsState *s = pdu->s; 394 395 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { 396 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 397 if (err < 0) { 398 err = -errno; 399 } 400 } else { 401 if (v9fs_request_cancelled(pdu)) { 402 return -EINTR; 403 } 404 v9fs_co_run_in_worker( 405 { 406 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 407 if (err < 0) { 408 err = -errno; 409 } 410 }); 411 } 412 return err; 413 } 414