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