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_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, 143 gid_t gid) 144 { 145 int err; 146 FsCred cred; 147 V9fsState *s = pdu->s; 148 149 if (v9fs_request_cancelled(pdu)) { 150 return -EINTR; 151 } 152 cred_init(&cred); 153 cred.fc_uid = uid; 154 cred.fc_gid = gid; 155 v9fs_path_read_lock(s); 156 v9fs_co_run_in_worker( 157 { 158 err = s->ops->chown(&s->ctx, path, &cred); 159 if (err < 0) { 160 err = -errno; 161 } 162 }); 163 v9fs_path_unlock(s); 164 return err; 165 } 166 167 int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) 168 { 169 int err; 170 V9fsState *s = pdu->s; 171 172 if (v9fs_request_cancelled(pdu)) { 173 return -EINTR; 174 } 175 v9fs_path_read_lock(s); 176 v9fs_co_run_in_worker( 177 { 178 err = s->ops->truncate(&s->ctx, path, size); 179 if (err < 0) { 180 err = -errno; 181 } 182 }); 183 v9fs_path_unlock(s); 184 return err; 185 } 186 187 int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, 188 V9fsString *name, uid_t uid, gid_t gid, 189 dev_t dev, mode_t mode, struct stat *stbuf) 190 { 191 int err; 192 V9fsPath path; 193 FsCred cred; 194 V9fsState *s = pdu->s; 195 196 if (v9fs_request_cancelled(pdu)) { 197 return -EINTR; 198 } 199 cred_init(&cred); 200 cred.fc_uid = uid; 201 cred.fc_gid = gid; 202 cred.fc_mode = mode; 203 cred.fc_rdev = dev; 204 v9fs_path_read_lock(s); 205 v9fs_co_run_in_worker( 206 { 207 err = s->ops->mknod(&s->ctx, &fidp->path, name->data, &cred); 208 if (err < 0) { 209 err = -errno; 210 } else { 211 v9fs_path_init(&path); 212 err = v9fs_name_to_path(s, &fidp->path, name->data, &path); 213 if (!err) { 214 err = s->ops->lstat(&s->ctx, &path, stbuf); 215 if (err < 0) { 216 err = -errno; 217 } 218 } 219 v9fs_path_free(&path); 220 } 221 }); 222 v9fs_path_unlock(s); 223 return err; 224 } 225 226 /* Only works with path name based fid */ 227 int coroutine_fn v9fs_co_remove(V9fsPDU *pdu, V9fsPath *path) 228 { 229 int err; 230 V9fsState *s = pdu->s; 231 232 if (v9fs_request_cancelled(pdu)) { 233 return -EINTR; 234 } 235 v9fs_path_read_lock(s); 236 v9fs_co_run_in_worker( 237 { 238 err = s->ops->remove(&s->ctx, path->data); 239 if (err < 0) { 240 err = -errno; 241 } 242 }); 243 v9fs_path_unlock(s); 244 return err; 245 } 246 247 int coroutine_fn v9fs_co_unlinkat(V9fsPDU *pdu, V9fsPath *path, 248 V9fsString *name, int flags) 249 { 250 int err; 251 V9fsState *s = pdu->s; 252 253 if (v9fs_request_cancelled(pdu)) { 254 return -EINTR; 255 } 256 v9fs_path_read_lock(s); 257 v9fs_co_run_in_worker( 258 { 259 err = s->ops->unlinkat(&s->ctx, path, name->data, flags); 260 if (err < 0) { 261 err = -errno; 262 } 263 }); 264 v9fs_path_unlock(s); 265 return err; 266 } 267 268 /* Only work with path name based fid */ 269 int coroutine_fn v9fs_co_rename(V9fsPDU *pdu, V9fsPath *oldpath, 270 V9fsPath *newpath) 271 { 272 int err; 273 V9fsState *s = pdu->s; 274 275 if (v9fs_request_cancelled(pdu)) { 276 return -EINTR; 277 } 278 v9fs_co_run_in_worker( 279 { 280 err = s->ops->rename(&s->ctx, oldpath->data, newpath->data); 281 if (err < 0) { 282 err = -errno; 283 } 284 }); 285 return err; 286 } 287 288 int coroutine_fn v9fs_co_renameat(V9fsPDU *pdu, V9fsPath *olddirpath, 289 V9fsString *oldname, V9fsPath *newdirpath, 290 V9fsString *newname) 291 { 292 int err; 293 V9fsState *s = pdu->s; 294 295 if (v9fs_request_cancelled(pdu)) { 296 return -EINTR; 297 } 298 v9fs_co_run_in_worker( 299 { 300 err = s->ops->renameat(&s->ctx, olddirpath, oldname->data, 301 newdirpath, newname->data); 302 if (err < 0) { 303 err = -errno; 304 } 305 }); 306 return err; 307 } 308 309 int coroutine_fn v9fs_co_symlink(V9fsPDU *pdu, V9fsFidState *dfidp, 310 V9fsString *name, const char *oldpath, 311 gid_t gid, struct stat *stbuf) 312 { 313 int err; 314 FsCred cred; 315 V9fsPath path; 316 V9fsState *s = pdu->s; 317 318 if (v9fs_request_cancelled(pdu)) { 319 return -EINTR; 320 } 321 cred_init(&cred); 322 cred.fc_uid = dfidp->uid; 323 cred.fc_gid = gid; 324 cred.fc_mode = 0777; 325 v9fs_path_read_lock(s); 326 v9fs_co_run_in_worker( 327 { 328 err = s->ops->symlink(&s->ctx, oldpath, &dfidp->path, 329 name->data, &cred); 330 if (err < 0) { 331 err = -errno; 332 } else { 333 v9fs_path_init(&path); 334 err = v9fs_name_to_path(s, &dfidp->path, name->data, &path); 335 if (!err) { 336 err = s->ops->lstat(&s->ctx, &path, stbuf); 337 if (err < 0) { 338 err = -errno; 339 } 340 } 341 v9fs_path_free(&path); 342 } 343 }); 344 v9fs_path_unlock(s); 345 return err; 346 } 347 348 /* 349 * For path name based fid we don't block. So we can 350 * directly call the fs driver ops. 351 */ 352 int coroutine_fn v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, 353 const char *name, V9fsPath *path) 354 { 355 int err; 356 V9fsState *s = pdu->s; 357 358 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { 359 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 360 if (err < 0) { 361 err = -errno; 362 } 363 } else { 364 if (v9fs_request_cancelled(pdu)) { 365 return -EINTR; 366 } 367 v9fs_co_run_in_worker( 368 { 369 err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 370 if (err < 0) { 371 err = -errno; 372 } 373 }); 374 } 375 return err; 376 } 377