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