qemu/hw/virtio-9p.c
<<
>>
Prefs
   1/*
   2 * Virtio 9p backend
   3 *
   4 * Copyright IBM, Corp. 2010
   5 *
   6 * Authors:
   7 *  Anthony Liguori   <aliguori@us.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#include "virtio.h"
  15#include "pc.h"
  16#include "qemu_socket.h"
  17#include "virtio-9p.h"
  18#include "fsdev/qemu-fsdev.h"
  19#include "virtio-9p-debug.h"
  20#include "virtio-9p-xattr.h"
  21
  22int debug_9p_pdu;
  23
  24enum {
  25    Oread   = 0x00,
  26    Owrite  = 0x01,
  27    Ordwr   = 0x02,
  28    Oexec   = 0x03,
  29    Oexcl   = 0x04,
  30    Otrunc  = 0x10,
  31    Orexec  = 0x20,
  32    Orclose = 0x40,
  33    Oappend = 0x80,
  34};
  35
  36static int omode_to_uflags(int8_t mode)
  37{
  38    int ret = 0;
  39
  40    switch (mode & 3) {
  41    case Oread:
  42        ret = O_RDONLY;
  43        break;
  44    case Ordwr:
  45        ret = O_RDWR;
  46        break;
  47    case Owrite:
  48        ret = O_WRONLY;
  49        break;
  50    case Oexec:
  51        ret = O_RDONLY;
  52        break;
  53    }
  54
  55    if (mode & Otrunc) {
  56        ret |= O_TRUNC;
  57    }
  58
  59    if (mode & Oappend) {
  60        ret |= O_APPEND;
  61    }
  62
  63    if (mode & Oexcl) {
  64        ret |= O_EXCL;
  65    }
  66
  67    return ret;
  68}
  69
  70void cred_init(FsCred *credp)
  71{
  72    credp->fc_uid = -1;
  73    credp->fc_gid = -1;
  74    credp->fc_mode = -1;
  75    credp->fc_rdev = -1;
  76}
  77
  78static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
  79{
  80    return s->ops->lstat(&s->ctx, path->data, stbuf);
  81}
  82
  83static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
  84{
  85    ssize_t len;
  86
  87    buf->data = qemu_malloc(1024);
  88
  89    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
  90    if (len > -1) {
  91        buf->size = len;
  92        buf->data[len] = 0;
  93    }
  94
  95    return len;
  96}
  97
  98static int v9fs_do_close(V9fsState *s, int fd)
  99{
 100    return s->ops->close(&s->ctx, fd);
 101}
 102
 103static int v9fs_do_closedir(V9fsState *s, DIR *dir)
 104{
 105    return s->ops->closedir(&s->ctx, dir);
 106}
 107
 108static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
 109{
 110    return s->ops->open(&s->ctx, path->data, flags);
 111}
 112
 113static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
 114{
 115    return s->ops->opendir(&s->ctx, path->data);
 116}
 117
 118static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
 119{
 120    return s->ops->rewinddir(&s->ctx, dir);
 121}
 122
 123static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
 124{
 125    return s->ops->telldir(&s->ctx, dir);
 126}
 127
 128static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
 129{
 130    return s->ops->readdir(&s->ctx, dir);
 131}
 132
 133static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
 134{
 135    return s->ops->seekdir(&s->ctx, dir, off);
 136}
 137
 138static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
 139                            int iovcnt, int64_t offset)
 140{
 141    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
 142}
 143
 144static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
 145                       int iovcnt, int64_t offset)
 146{
 147    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
 148}
 149
 150static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
 151{
 152    FsCred cred;
 153    cred_init(&cred);
 154    cred.fc_mode = mode;
 155    return s->ops->chmod(&s->ctx, path->data, &cred);
 156}
 157
 158static int v9fs_do_mknod(V9fsState *s, char *name,
 159        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
 160{
 161    FsCred cred;
 162    cred_init(&cred);
 163    cred.fc_uid = uid;
 164    cred.fc_gid = gid;
 165    cred.fc_mode = mode;
 166    cred.fc_rdev = dev;
 167    return s->ops->mknod(&s->ctx, name, &cred);
 168}
 169
 170static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
 171                uid_t uid, gid_t gid)
 172{
 173    FsCred cred;
 174
 175    cred_init(&cred);
 176    cred.fc_uid = uid;
 177    cred.fc_gid = gid;
 178    cred.fc_mode = mode;
 179
 180    return s->ops->mkdir(&s->ctx, name, &cred);
 181}
 182
 183static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
 184{
 185    return s->ops->fstat(&s->ctx, fd, stbuf);
 186}
 187
 188static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
 189        int flags, int mode)
 190{
 191    FsCred cred;
 192
 193    cred_init(&cred);
 194    cred.fc_uid = uid;
 195    cred.fc_gid = gid;
 196    cred.fc_mode = mode & 07777;
 197    flags = flags;
 198
 199    return s->ops->open2(&s->ctx, fullname, flags, &cred);
 200}
 201
 202static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
 203        const char *oldpath, const char *newpath, gid_t gid)
 204{
 205    FsCred cred;
 206    cred_init(&cred);
 207    cred.fc_uid = fidp->uid;
 208    cred.fc_gid = gid;
 209    cred.fc_mode = 0777;
 210
 211    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
 212}
 213
 214static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
 215{
 216    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
 217}
 218
 219static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
 220{
 221    return s->ops->truncate(&s->ctx, path->data, size);
 222}
 223
 224static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
 225                            V9fsString *newpath)
 226{
 227    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
 228}
 229
 230static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
 231{
 232    FsCred cred;
 233    cred_init(&cred);
 234    cred.fc_uid = uid;
 235    cred.fc_gid = gid;
 236
 237    return s->ops->chown(&s->ctx, path->data, &cred);
 238}
 239
 240static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
 241                                           const struct timespec times[2])
 242{
 243    return s->ops->utimensat(&s->ctx, path->data, times);
 244}
 245
 246static int v9fs_do_remove(V9fsState *s, V9fsString *path)
 247{
 248    return s->ops->remove(&s->ctx, path->data);
 249}
 250
 251static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
 252{
 253    return s->ops->fsync(&s->ctx, fd, datasync);
 254}
 255
 256static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
 257{
 258    return s->ops->statfs(&s->ctx, path->data, stbuf);
 259}
 260
 261static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
 262                             V9fsString *xattr_name,
 263                             void *value, size_t size)
 264{
 265    return s->ops->lgetxattr(&s->ctx, path->data,
 266                             xattr_name->data, value, size);
 267}
 268
 269static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
 270                              void *value, size_t size)
 271{
 272    return s->ops->llistxattr(&s->ctx, path->data,
 273                              value, size);
 274}
 275
 276static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
 277                             V9fsString *xattr_name,
 278                             void *value, size_t size, int flags)
 279{
 280    return s->ops->lsetxattr(&s->ctx, path->data,
 281                             xattr_name->data, value, size, flags);
 282}
 283
 284static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
 285                                V9fsString *xattr_name)
 286{
 287    return s->ops->lremovexattr(&s->ctx, path->data,
 288                                xattr_name->data);
 289}
 290
 291
 292static void v9fs_string_init(V9fsString *str)
 293{
 294    str->data = NULL;
 295    str->size = 0;
 296}
 297
 298static void v9fs_string_free(V9fsString *str)
 299{
 300    qemu_free(str->data);
 301    str->data = NULL;
 302    str->size = 0;
 303}
 304
 305static void v9fs_string_null(V9fsString *str)
 306{
 307    v9fs_string_free(str);
 308}
 309
 310static int number_to_string(void *arg, char type)
 311{
 312    unsigned int ret = 0;
 313
 314    switch (type) {
 315    case 'u': {
 316        unsigned int num = *(unsigned int *)arg;
 317
 318        do {
 319            ret++;
 320            num = num/10;
 321        } while (num);
 322        break;
 323    }
 324    case 'U': {
 325        unsigned long num = *(unsigned long *)arg;
 326        do {
 327            ret++;
 328            num = num/10;
 329        } while (num);
 330        break;
 331    }
 332    default:
 333        printf("Number_to_string: Unknown number format\n");
 334        return -1;
 335    }
 336
 337    return ret;
 338}
 339
 340static int GCC_FMT_ATTR(2, 0)
 341v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
 342{
 343    va_list ap2;
 344    char *iter = (char *)fmt;
 345    int len = 0;
 346    int nr_args = 0;
 347    char *arg_char_ptr;
 348    unsigned int arg_uint;
 349    unsigned long arg_ulong;
 350
 351    /* Find the number of %'s that denotes an argument */
 352    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
 353        nr_args++;
 354        iter++;
 355    }
 356
 357    len = strlen(fmt) - 2*nr_args;
 358
 359    if (!nr_args) {
 360        goto alloc_print;
 361    }
 362
 363    va_copy(ap2, ap);
 364
 365    iter = (char *)fmt;
 366
 367    /* Now parse the format string */
 368    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
 369        iter++;
 370        switch (*iter) {
 371        case 'u':
 372            arg_uint = va_arg(ap2, unsigned int);
 373            len += number_to_string((void *)&arg_uint, 'u');
 374            break;
 375        case 'l':
 376            if (*++iter == 'u') {
 377                arg_ulong = va_arg(ap2, unsigned long);
 378                len += number_to_string((void *)&arg_ulong, 'U');
 379            } else {
 380                return -1;
 381            }
 382            break;
 383        case 's':
 384            arg_char_ptr = va_arg(ap2, char *);
 385            len += strlen(arg_char_ptr);
 386            break;
 387        case 'c':
 388            len += 1;
 389            break;
 390        default:
 391            fprintf(stderr,
 392                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
 393            return -1;
 394        }
 395        iter++;
 396    }
 397
 398alloc_print:
 399    *strp = qemu_malloc((len + 1) * sizeof(**strp));
 400
 401    return vsprintf(*strp, fmt, ap);
 402}
 403
 404static void GCC_FMT_ATTR(2, 3)
 405v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
 406{
 407    va_list ap;
 408    int err;
 409
 410    v9fs_string_free(str);
 411
 412    va_start(ap, fmt);
 413    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
 414    BUG_ON(err == -1);
 415    va_end(ap);
 416
 417    str->size = err;
 418}
 419
 420static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
 421{
 422    v9fs_string_free(lhs);
 423    v9fs_string_sprintf(lhs, "%s", rhs->data);
 424}
 425
 426static size_t v9fs_string_size(V9fsString *str)
 427{
 428    return str->size;
 429}
 430
 431static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
 432{
 433    V9fsFidState *f;
 434
 435    for (f = s->fid_list; f; f = f->next) {
 436        if (f->fid == fid) {
 437            return f;
 438        }
 439    }
 440
 441    return NULL;
 442}
 443
 444static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
 445{
 446    V9fsFidState *f;
 447
 448    f = lookup_fid(s, fid);
 449    if (f) {
 450        return NULL;
 451    }
 452
 453    f = qemu_mallocz(sizeof(V9fsFidState));
 454
 455    f->fid = fid;
 456    f->fid_type = P9_FID_NONE;
 457
 458    f->next = s->fid_list;
 459    s->fid_list = f;
 460
 461    return f;
 462}
 463
 464static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
 465{
 466    int retval = 0;
 467
 468    if (fidp->fs.xattr.copied_len == -1) {
 469        /* getxattr/listxattr fid */
 470        goto free_value;
 471    }
 472    /*
 473     * if this is fid for setxattr. clunk should
 474     * result in setxattr localcall
 475     */
 476    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
 477        /* clunk after partial write */
 478        retval = -EINVAL;
 479        goto free_out;
 480    }
 481    if (fidp->fs.xattr.len) {
 482        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
 483                                   fidp->fs.xattr.value,
 484                                   fidp->fs.xattr.len,
 485                                   fidp->fs.xattr.flags);
 486    } else {
 487        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
 488    }
 489free_out:
 490    v9fs_string_free(&fidp->fs.xattr.name);
 491free_value:
 492    if (fidp->fs.xattr.value) {
 493        qemu_free(fidp->fs.xattr.value);
 494    }
 495    return retval;
 496}
 497
 498static int free_fid(V9fsState *s, int32_t fid)
 499{
 500    int retval = 0;
 501    V9fsFidState **fidpp, *fidp;
 502
 503    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
 504        if ((*fidpp)->fid == fid) {
 505            break;
 506        }
 507    }
 508
 509    if (*fidpp == NULL) {
 510        return -ENOENT;
 511    }
 512
 513    fidp = *fidpp;
 514    *fidpp = fidp->next;
 515
 516    if (fidp->fid_type == P9_FID_FILE) {
 517        v9fs_do_close(s, fidp->fs.fd);
 518    } else if (fidp->fid_type == P9_FID_DIR) {
 519        v9fs_do_closedir(s, fidp->fs.dir);
 520    } else if (fidp->fid_type == P9_FID_XATTR) {
 521        retval = v9fs_xattr_fid_clunk(s, fidp);
 522    }
 523    v9fs_string_free(&fidp->path);
 524    qemu_free(fidp);
 525
 526    return retval;
 527}
 528
 529#define P9_QID_TYPE_DIR         0x80
 530#define P9_QID_TYPE_SYMLINK     0x02
 531
 532#define P9_STAT_MODE_DIR        0x80000000
 533#define P9_STAT_MODE_APPEND     0x40000000
 534#define P9_STAT_MODE_EXCL       0x20000000
 535#define P9_STAT_MODE_MOUNT      0x10000000
 536#define P9_STAT_MODE_AUTH       0x08000000
 537#define P9_STAT_MODE_TMP        0x04000000
 538#define P9_STAT_MODE_SYMLINK    0x02000000
 539#define P9_STAT_MODE_LINK       0x01000000
 540#define P9_STAT_MODE_DEVICE     0x00800000
 541#define P9_STAT_MODE_NAMED_PIPE 0x00200000
 542#define P9_STAT_MODE_SOCKET     0x00100000
 543#define P9_STAT_MODE_SETUID     0x00080000
 544#define P9_STAT_MODE_SETGID     0x00040000
 545#define P9_STAT_MODE_SETVTX     0x00010000
 546
 547#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
 548                                P9_STAT_MODE_SYMLINK |      \
 549                                P9_STAT_MODE_LINK |         \
 550                                P9_STAT_MODE_DEVICE |       \
 551                                P9_STAT_MODE_NAMED_PIPE |   \
 552                                P9_STAT_MODE_SOCKET)
 553
 554/* This is the algorithm from ufs in spfs */
 555static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
 556{
 557    size_t size;
 558
 559    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
 560    memcpy(&qidp->path, &stbuf->st_ino, size);
 561    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
 562    qidp->type = 0;
 563    if (S_ISDIR(stbuf->st_mode)) {
 564        qidp->type |= P9_QID_TYPE_DIR;
 565    }
 566    if (S_ISLNK(stbuf->st_mode)) {
 567        qidp->type |= P9_QID_TYPE_SYMLINK;
 568    }
 569}
 570
 571static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
 572{
 573    struct stat stbuf;
 574    int err;
 575
 576    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
 577    if (err) {
 578        return err;
 579    }
 580
 581    stat_to_qid(&stbuf, qidp);
 582    return 0;
 583}
 584
 585static V9fsPDU *alloc_pdu(V9fsState *s)
 586{
 587    V9fsPDU *pdu = NULL;
 588
 589    if (!QLIST_EMPTY(&s->free_list)) {
 590        pdu = QLIST_FIRST(&s->free_list);
 591        QLIST_REMOVE(pdu, next);
 592    }
 593    return pdu;
 594}
 595
 596static void free_pdu(V9fsState *s, V9fsPDU *pdu)
 597{
 598    if (pdu) {
 599        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
 600    }
 601}
 602
 603size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
 604                        size_t offset, size_t size, int pack)
 605{
 606    int i = 0;
 607    size_t copied = 0;
 608
 609    for (i = 0; size && i < sg_count; i++) {
 610        size_t len;
 611        if (offset >= sg[i].iov_len) {
 612            /* skip this sg */
 613            offset -= sg[i].iov_len;
 614            continue;
 615        } else {
 616            len = MIN(sg[i].iov_len - offset, size);
 617            if (pack) {
 618                memcpy(sg[i].iov_base + offset, addr, len);
 619            } else {
 620                memcpy(addr, sg[i].iov_base + offset, len);
 621            }
 622            size -= len;
 623            copied += len;
 624            addr += len;
 625            if (size) {
 626                offset = 0;
 627                continue;
 628            }
 629        }
 630    }
 631
 632    return copied;
 633}
 634
 635static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
 636{
 637    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
 638                         offset, size, 0);
 639}
 640
 641static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
 642                        size_t size)
 643{
 644    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
 645                             offset, size, 1);
 646}
 647
 648static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
 649{
 650    size_t pos = 0;
 651    int i, j;
 652    struct iovec *src_sg;
 653    unsigned int num;
 654
 655    if (rx) {
 656        src_sg = pdu->elem.in_sg;
 657        num = pdu->elem.in_num;
 658    } else {
 659        src_sg = pdu->elem.out_sg;
 660        num = pdu->elem.out_num;
 661    }
 662
 663    j = 0;
 664    for (i = 0; i < num; i++) {
 665        if (offset <= pos) {
 666            sg[j].iov_base = src_sg[i].iov_base;
 667            sg[j].iov_len = src_sg[i].iov_len;
 668            j++;
 669        } else if (offset < (src_sg[i].iov_len + pos)) {
 670            sg[j].iov_base = src_sg[i].iov_base;
 671            sg[j].iov_len = src_sg[i].iov_len;
 672            sg[j].iov_base += (offset - pos);
 673            sg[j].iov_len -= (offset - pos);
 674            j++;
 675        }
 676        pos += src_sg[i].iov_len;
 677    }
 678
 679    return j;
 680}
 681
 682static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
 683{
 684    size_t old_offset = offset;
 685    va_list ap;
 686    int i;
 687
 688    va_start(ap, fmt);
 689    for (i = 0; fmt[i]; i++) {
 690        switch (fmt[i]) {
 691        case 'b': {
 692            uint8_t *valp = va_arg(ap, uint8_t *);
 693            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
 694            break;
 695        }
 696        case 'w': {
 697            uint16_t val, *valp;
 698            valp = va_arg(ap, uint16_t *);
 699            val = le16_to_cpupu(valp);
 700            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
 701            *valp = val;
 702            break;
 703        }
 704        case 'd': {
 705            uint32_t val, *valp;
 706            valp = va_arg(ap, uint32_t *);
 707            val = le32_to_cpupu(valp);
 708            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
 709            *valp = val;
 710            break;
 711        }
 712        case 'q': {
 713            uint64_t val, *valp;
 714            valp = va_arg(ap, uint64_t *);
 715            val = le64_to_cpup(valp);
 716            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
 717            *valp = val;
 718            break;
 719        }
 720        case 'v': {
 721            struct iovec *iov = va_arg(ap, struct iovec *);
 722            int *iovcnt = va_arg(ap, int *);
 723            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
 724            break;
 725        }
 726        case 's': {
 727            V9fsString *str = va_arg(ap, V9fsString *);
 728            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
 729            /* FIXME: sanity check str->size */
 730            str->data = qemu_malloc(str->size + 1);
 731            offset += pdu_unpack(str->data, pdu, offset, str->size);
 732            str->data[str->size] = 0;
 733            break;
 734        }
 735        case 'Q': {
 736            V9fsQID *qidp = va_arg(ap, V9fsQID *);
 737            offset += pdu_unmarshal(pdu, offset, "bdq",
 738                        &qidp->type, &qidp->version, &qidp->path);
 739            break;
 740        }
 741        case 'S': {
 742            V9fsStat *statp = va_arg(ap, V9fsStat *);
 743            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
 744                        &statp->size, &statp->type, &statp->dev,
 745                        &statp->qid, &statp->mode, &statp->atime,
 746                        &statp->mtime, &statp->length,
 747                        &statp->name, &statp->uid, &statp->gid,
 748                        &statp->muid, &statp->extension,
 749                        &statp->n_uid, &statp->n_gid,
 750                        &statp->n_muid);
 751            break;
 752        }
 753        case 'I': {
 754            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
 755            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
 756                        &iattr->valid, &iattr->mode,
 757                        &iattr->uid, &iattr->gid, &iattr->size,
 758                        &iattr->atime_sec, &iattr->atime_nsec,
 759                        &iattr->mtime_sec, &iattr->mtime_nsec);
 760            break;
 761        }
 762        default:
 763            break;
 764        }
 765    }
 766
 767    va_end(ap);
 768
 769    return offset - old_offset;
 770}
 771
 772static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
 773{
 774    size_t old_offset = offset;
 775    va_list ap;
 776    int i;
 777
 778    va_start(ap, fmt);
 779    for (i = 0; fmt[i]; i++) {
 780        switch (fmt[i]) {
 781        case 'b': {
 782            uint8_t val = va_arg(ap, int);
 783            offset += pdu_pack(pdu, offset, &val, sizeof(val));
 784            break;
 785        }
 786        case 'w': {
 787            uint16_t val;
 788            cpu_to_le16w(&val, va_arg(ap, int));
 789            offset += pdu_pack(pdu, offset, &val, sizeof(val));
 790            break;
 791        }
 792        case 'd': {
 793            uint32_t val;
 794            cpu_to_le32w(&val, va_arg(ap, uint32_t));
 795            offset += pdu_pack(pdu, offset, &val, sizeof(val));
 796            break;
 797        }
 798        case 'q': {
 799            uint64_t val;
 800            cpu_to_le64w(&val, va_arg(ap, uint64_t));
 801            offset += pdu_pack(pdu, offset, &val, sizeof(val));
 802            break;
 803        }
 804        case 'v': {
 805            struct iovec *iov = va_arg(ap, struct iovec *);
 806            int *iovcnt = va_arg(ap, int *);
 807            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
 808            break;
 809        }
 810        case 's': {
 811            V9fsString *str = va_arg(ap, V9fsString *);
 812            offset += pdu_marshal(pdu, offset, "w", str->size);
 813            offset += pdu_pack(pdu, offset, str->data, str->size);
 814            break;
 815        }
 816        case 'Q': {
 817            V9fsQID *qidp = va_arg(ap, V9fsQID *);
 818            offset += pdu_marshal(pdu, offset, "bdq",
 819                        qidp->type, qidp->version, qidp->path);
 820            break;
 821        }
 822        case 'S': {
 823            V9fsStat *statp = va_arg(ap, V9fsStat *);
 824            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
 825                        statp->size, statp->type, statp->dev,
 826                        &statp->qid, statp->mode, statp->atime,
 827                        statp->mtime, statp->length, &statp->name,
 828                        &statp->uid, &statp->gid, &statp->muid,
 829                        &statp->extension, statp->n_uid,
 830                        statp->n_gid, statp->n_muid);
 831            break;
 832        }
 833        case 'A': {
 834            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
 835            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
 836                        statp->st_result_mask,
 837                        &statp->qid, statp->st_mode,
 838                        statp->st_uid, statp->st_gid,
 839                        statp->st_nlink, statp->st_rdev,
 840                        statp->st_size, statp->st_blksize, statp->st_blocks,
 841                        statp->st_atime_sec, statp->st_atime_nsec,
 842                        statp->st_mtime_sec, statp->st_mtime_nsec,
 843                        statp->st_ctime_sec, statp->st_ctime_nsec,
 844                        statp->st_btime_sec, statp->st_btime_nsec,
 845                        statp->st_gen, statp->st_data_version);
 846            break;
 847        }
 848        default:
 849            break;
 850        }
 851    }
 852    va_end(ap);
 853
 854    return offset - old_offset;
 855}
 856
 857static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
 858{
 859    int8_t id = pdu->id + 1; /* Response */
 860
 861    if (len < 0) {
 862        int err = -len;
 863        len = 7;
 864
 865        if (s->proto_version != V9FS_PROTO_2000L) {
 866            V9fsString str;
 867
 868            str.data = strerror(err);
 869            str.size = strlen(str.data);
 870
 871            len += pdu_marshal(pdu, len, "s", &str);
 872            id = P9_RERROR;
 873        }
 874
 875        len += pdu_marshal(pdu, len, "d", err);
 876
 877        if (s->proto_version == V9FS_PROTO_2000L) {
 878            id = P9_RLERROR;
 879        }
 880    }
 881
 882    /* fill out the header */
 883    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
 884
 885    /* keep these in sync */
 886    pdu->size = len;
 887    pdu->id = id;
 888
 889    /* push onto queue and notify */
 890    virtqueue_push(s->vq, &pdu->elem, len);
 891
 892    /* FIXME: we should batch these completions */
 893    virtio_notify(&s->vdev, s->vq);
 894
 895    free_pdu(s, pdu);
 896}
 897
 898static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
 899{
 900    mode_t ret;
 901
 902    ret = mode & 0777;
 903    if (mode & P9_STAT_MODE_DIR) {
 904        ret |= S_IFDIR;
 905    }
 906
 907    if (mode & P9_STAT_MODE_SYMLINK) {
 908        ret |= S_IFLNK;
 909    }
 910    if (mode & P9_STAT_MODE_SOCKET) {
 911        ret |= S_IFSOCK;
 912    }
 913    if (mode & P9_STAT_MODE_NAMED_PIPE) {
 914        ret |= S_IFIFO;
 915    }
 916    if (mode & P9_STAT_MODE_DEVICE) {
 917        if (extension && extension->data[0] == 'c') {
 918            ret |= S_IFCHR;
 919        } else {
 920            ret |= S_IFBLK;
 921        }
 922    }
 923
 924    if (!(ret&~0777)) {
 925        ret |= S_IFREG;
 926    }
 927
 928    if (mode & P9_STAT_MODE_SETUID) {
 929        ret |= S_ISUID;
 930    }
 931    if (mode & P9_STAT_MODE_SETGID) {
 932        ret |= S_ISGID;
 933    }
 934    if (mode & P9_STAT_MODE_SETVTX) {
 935        ret |= S_ISVTX;
 936    }
 937
 938    return ret;
 939}
 940
 941static int donttouch_stat(V9fsStat *stat)
 942{
 943    if (stat->type == -1 &&
 944        stat->dev == -1 &&
 945        stat->qid.type == -1 &&
 946        stat->qid.version == -1 &&
 947        stat->qid.path == -1 &&
 948        stat->mode == -1 &&
 949        stat->atime == -1 &&
 950        stat->mtime == -1 &&
 951        stat->length == -1 &&
 952        !stat->name.size &&
 953        !stat->uid.size &&
 954        !stat->gid.size &&
 955        !stat->muid.size &&
 956        stat->n_uid == -1 &&
 957        stat->n_gid == -1 &&
 958        stat->n_muid == -1) {
 959        return 1;
 960    }
 961
 962    return 0;
 963}
 964
 965static void v9fs_stat_free(V9fsStat *stat)
 966{
 967    v9fs_string_free(&stat->name);
 968    v9fs_string_free(&stat->uid);
 969    v9fs_string_free(&stat->gid);
 970    v9fs_string_free(&stat->muid);
 971    v9fs_string_free(&stat->extension);
 972}
 973
 974static uint32_t stat_to_v9mode(const struct stat *stbuf)
 975{
 976    uint32_t mode;
 977
 978    mode = stbuf->st_mode & 0777;
 979    if (S_ISDIR(stbuf->st_mode)) {
 980        mode |= P9_STAT_MODE_DIR;
 981    }
 982
 983    if (S_ISLNK(stbuf->st_mode)) {
 984        mode |= P9_STAT_MODE_SYMLINK;
 985    }
 986
 987    if (S_ISSOCK(stbuf->st_mode)) {
 988        mode |= P9_STAT_MODE_SOCKET;
 989    }
 990
 991    if (S_ISFIFO(stbuf->st_mode)) {
 992        mode |= P9_STAT_MODE_NAMED_PIPE;
 993    }
 994
 995    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
 996        mode |= P9_STAT_MODE_DEVICE;
 997    }
 998
 999    if (stbuf->st_mode & S_ISUID) {
1000        mode |= P9_STAT_MODE_SETUID;
1001    }
1002
1003    if (stbuf->st_mode & S_ISGID) {
1004        mode |= P9_STAT_MODE_SETGID;
1005    }
1006
1007    if (stbuf->st_mode & S_ISVTX) {
1008        mode |= P9_STAT_MODE_SETVTX;
1009    }
1010
1011    return mode;
1012}
1013
1014static int stat_to_v9stat(V9fsState *s, V9fsString *name,
1015                            const struct stat *stbuf,
1016                            V9fsStat *v9stat)
1017{
1018    int err;
1019    const char *str;
1020
1021    memset(v9stat, 0, sizeof(*v9stat));
1022
1023    stat_to_qid(stbuf, &v9stat->qid);
1024    v9stat->mode = stat_to_v9mode(stbuf);
1025    v9stat->atime = stbuf->st_atime;
1026    v9stat->mtime = stbuf->st_mtime;
1027    v9stat->length = stbuf->st_size;
1028
1029    v9fs_string_null(&v9stat->uid);
1030    v9fs_string_null(&v9stat->gid);
1031    v9fs_string_null(&v9stat->muid);
1032
1033    v9stat->n_uid = stbuf->st_uid;
1034    v9stat->n_gid = stbuf->st_gid;
1035    v9stat->n_muid = 0;
1036
1037    v9fs_string_null(&v9stat->extension);
1038
1039    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1040        err = v9fs_do_readlink(s, name, &v9stat->extension);
1041        if (err == -1) {
1042            err = -errno;
1043            return err;
1044        }
1045        v9stat->extension.data[err] = 0;
1046        v9stat->extension.size = err;
1047    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1048        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1049                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1050                major(stbuf->st_rdev), minor(stbuf->st_rdev));
1051    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1052        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1053                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1054    }
1055
1056    str = strrchr(name->data, '/');
1057    if (str) {
1058        str += 1;
1059    } else {
1060        str = name->data;
1061    }
1062
1063    v9fs_string_sprintf(&v9stat->name, "%s", str);
1064
1065    v9stat->size = 61 +
1066        v9fs_string_size(&v9stat->name) +
1067        v9fs_string_size(&v9stat->uid) +
1068        v9fs_string_size(&v9stat->gid) +
1069        v9fs_string_size(&v9stat->muid) +
1070        v9fs_string_size(&v9stat->extension);
1071    return 0;
1072}
1073
1074#define P9_STATS_MODE          0x00000001ULL
1075#define P9_STATS_NLINK         0x00000002ULL
1076#define P9_STATS_UID           0x00000004ULL
1077#define P9_STATS_GID           0x00000008ULL
1078#define P9_STATS_RDEV          0x00000010ULL
1079#define P9_STATS_ATIME         0x00000020ULL
1080#define P9_STATS_MTIME         0x00000040ULL
1081#define P9_STATS_CTIME         0x00000080ULL
1082#define P9_STATS_INO           0x00000100ULL
1083#define P9_STATS_SIZE          0x00000200ULL
1084#define P9_STATS_BLOCKS        0x00000400ULL
1085
1086#define P9_STATS_BTIME         0x00000800ULL
1087#define P9_STATS_GEN           0x00001000ULL
1088#define P9_STATS_DATA_VERSION  0x00002000ULL
1089
1090#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
1091#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
1092
1093
1094static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1095                            V9fsStatDotl *v9lstat)
1096{
1097    memset(v9lstat, 0, sizeof(*v9lstat));
1098
1099    v9lstat->st_mode = stbuf->st_mode;
1100    v9lstat->st_nlink = stbuf->st_nlink;
1101    v9lstat->st_uid = stbuf->st_uid;
1102    v9lstat->st_gid = stbuf->st_gid;
1103    v9lstat->st_rdev = stbuf->st_rdev;
1104    v9lstat->st_size = stbuf->st_size;
1105    v9lstat->st_blksize = stbuf->st_blksize;
1106    v9lstat->st_blocks = stbuf->st_blocks;
1107    v9lstat->st_atime_sec = stbuf->st_atime;
1108    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1109    v9lstat->st_mtime_sec = stbuf->st_mtime;
1110    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1111    v9lstat->st_ctime_sec = stbuf->st_ctime;
1112    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1113    /* Currently we only support BASIC fields in stat */
1114    v9lstat->st_result_mask = P9_STATS_BASIC;
1115
1116    stat_to_qid(stbuf, &v9lstat->qid);
1117}
1118
1119static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1120{
1121    while (len && *iovcnt) {
1122        if (len < sg->iov_len) {
1123            sg->iov_len -= len;
1124            sg->iov_base += len;
1125            len = 0;
1126        } else {
1127            len -= sg->iov_len;
1128            sg++;
1129            *iovcnt -= 1;
1130        }
1131    }
1132
1133    return sg;
1134}
1135
1136static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1137{
1138    int i;
1139    int total = 0;
1140
1141    for (i = 0; i < *cnt; i++) {
1142        if ((total + sg[i].iov_len) > cap) {
1143            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1144            i++;
1145            break;
1146        }
1147        total += sg[i].iov_len;
1148    }
1149
1150    *cnt = i;
1151
1152    return sg;
1153}
1154
1155static void print_sg(struct iovec *sg, int cnt)
1156{
1157    int i;
1158
1159    printf("sg[%d]: {", cnt);
1160    for (i = 0; i < cnt; i++) {
1161        if (i) {
1162            printf(", ");
1163        }
1164        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1165    }
1166    printf("}\n");
1167}
1168
1169static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1170{
1171    V9fsString str;
1172    v9fs_string_init(&str);
1173    v9fs_string_copy(&str, dst);
1174    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1175    v9fs_string_free(&str);
1176}
1177
1178static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
1179{
1180    V9fsString version;
1181    size_t offset = 7;
1182
1183    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1184
1185    if (!strcmp(version.data, "9P2000.u")) {
1186        s->proto_version = V9FS_PROTO_2000U;
1187    } else if (!strcmp(version.data, "9P2000.L")) {
1188        s->proto_version = V9FS_PROTO_2000L;
1189    } else {
1190        v9fs_string_sprintf(&version, "unknown");
1191    }
1192
1193    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1194    complete_pdu(s, pdu, offset);
1195
1196    v9fs_string_free(&version);
1197}
1198
1199static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
1200{
1201    int32_t fid, afid, n_uname;
1202    V9fsString uname, aname;
1203    V9fsFidState *fidp;
1204    V9fsQID qid;
1205    size_t offset = 7;
1206    ssize_t err;
1207
1208    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1209
1210    fidp = alloc_fid(s, fid);
1211    if (fidp == NULL) {
1212        err = -EINVAL;
1213        goto out;
1214    }
1215
1216    fidp->uid = n_uname;
1217
1218    v9fs_string_sprintf(&fidp->path, "%s", "/");
1219    err = fid_to_qid(s, fidp, &qid);
1220    if (err) {
1221        err = -EINVAL;
1222        free_fid(s, fid);
1223        goto out;
1224    }
1225
1226    offset += pdu_marshal(pdu, offset, "Q", &qid);
1227
1228    err = offset;
1229out:
1230    complete_pdu(s, pdu, err);
1231    v9fs_string_free(&uname);
1232    v9fs_string_free(&aname);
1233}
1234
1235static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1236{
1237    if (err == -1) {
1238        err = -errno;
1239        goto out;
1240    }
1241
1242    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1243    if (err) {
1244        goto out;
1245    }
1246    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1247    err = vs->offset;
1248
1249out:
1250    complete_pdu(s, vs->pdu, err);
1251    v9fs_stat_free(&vs->v9stat);
1252    qemu_free(vs);
1253}
1254
1255static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
1256{
1257    int32_t fid;
1258    V9fsStatState *vs;
1259    ssize_t err = 0;
1260
1261    vs = qemu_malloc(sizeof(*vs));
1262    vs->pdu = pdu;
1263    vs->offset = 7;
1264
1265    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1266
1267    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1268
1269    vs->fidp = lookup_fid(s, fid);
1270    if (vs->fidp == NULL) {
1271        err = -ENOENT;
1272        goto out;
1273    }
1274
1275    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1276    v9fs_stat_post_lstat(s, vs, err);
1277    return;
1278
1279out:
1280    complete_pdu(s, vs->pdu, err);
1281    v9fs_stat_free(&vs->v9stat);
1282    qemu_free(vs);
1283}
1284
1285static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
1286                                                                int err)
1287{
1288    if (err == -1) {
1289        err = -errno;
1290        goto out;
1291    }
1292
1293    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
1294    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
1295    err = vs->offset;
1296
1297out:
1298    complete_pdu(s, vs->pdu, err);
1299    qemu_free(vs);
1300}
1301
1302static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
1303{
1304    int32_t fid;
1305    V9fsStatStateDotl *vs;
1306    ssize_t err = 0;
1307    V9fsFidState *fidp;
1308    uint64_t request_mask;
1309
1310    vs = qemu_malloc(sizeof(*vs));
1311    vs->pdu = pdu;
1312    vs->offset = 7;
1313
1314    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
1315
1316    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
1317
1318    fidp = lookup_fid(s, fid);
1319    if (fidp == NULL) {
1320        err = -ENOENT;
1321        goto out;
1322    }
1323
1324    /* Currently we only support BASIC fields in stat, so there is no
1325     * need to look at request_mask.
1326     */
1327    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
1328    v9fs_getattr_post_lstat(s, vs, err);
1329    return;
1330
1331out:
1332    complete_pdu(s, vs->pdu, err);
1333    qemu_free(vs);
1334}
1335
1336/* From Linux kernel code */
1337#define ATTR_MODE    (1 << 0)
1338#define ATTR_UID     (1 << 1)
1339#define ATTR_GID     (1 << 2)
1340#define ATTR_SIZE    (1 << 3)
1341#define ATTR_ATIME   (1 << 4)
1342#define ATTR_MTIME   (1 << 5)
1343#define ATTR_CTIME   (1 << 6)
1344#define ATTR_MASK    127
1345#define ATTR_ATIME_SET  (1 << 7)
1346#define ATTR_MTIME_SET  (1 << 8)
1347
1348static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
1349                                                                  int err)
1350{
1351    if (err == -1) {
1352        err = -errno;
1353        goto out;
1354    }
1355    err = vs->offset;
1356
1357out:
1358    complete_pdu(s, vs->pdu, err);
1359    qemu_free(vs);
1360}
1361
1362static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
1363{
1364    if (err == -1) {
1365        err = -errno;
1366        goto out;
1367    }
1368
1369    if (vs->v9iattr.valid & (ATTR_SIZE)) {
1370        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
1371    }
1372    v9fs_setattr_post_truncate(s, vs, err);
1373    return;
1374
1375out:
1376    complete_pdu(s, vs->pdu, err);
1377    qemu_free(vs);
1378}
1379
1380static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
1381                                                                   int err)
1382{
1383    if (err == -1) {
1384        err = -errno;
1385        goto out;
1386    }
1387
1388    /* If the only valid entry in iattr is ctime we can call
1389     * chown(-1,-1) to update the ctime of the file
1390     */
1391    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1392            ((vs->v9iattr.valid & ATTR_CTIME)
1393            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1394        if (!(vs->v9iattr.valid & ATTR_UID)) {
1395            vs->v9iattr.uid = -1;
1396        }
1397        if (!(vs->v9iattr.valid & ATTR_GID)) {
1398            vs->v9iattr.gid = -1;
1399        }
1400        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
1401                                                vs->v9iattr.gid);
1402    }
1403    v9fs_setattr_post_chown(s, vs, err);
1404    return;
1405
1406out:
1407    complete_pdu(s, vs->pdu, err);
1408    qemu_free(vs);
1409}
1410
1411static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
1412{
1413    if (err == -1) {
1414        err = -errno;
1415        goto out;
1416    }
1417
1418    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1419        struct timespec times[2];
1420        if (vs->v9iattr.valid & ATTR_ATIME) {
1421            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
1422                times[0].tv_sec = vs->v9iattr.atime_sec;
1423                times[0].tv_nsec = vs->v9iattr.atime_nsec;
1424            } else {
1425                times[0].tv_nsec = UTIME_NOW;
1426            }
1427        } else {
1428            times[0].tv_nsec = UTIME_OMIT;
1429        }
1430
1431        if (vs->v9iattr.valid & ATTR_MTIME) {
1432            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
1433                times[1].tv_sec = vs->v9iattr.mtime_sec;
1434                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
1435            } else {
1436                times[1].tv_nsec = UTIME_NOW;
1437            }
1438        } else {
1439            times[1].tv_nsec = UTIME_OMIT;
1440        }
1441        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
1442    }
1443    v9fs_setattr_post_utimensat(s, vs, err);
1444    return;
1445
1446out:
1447    complete_pdu(s, vs->pdu, err);
1448    qemu_free(vs);
1449}
1450
1451static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
1452{
1453    int32_t fid;
1454    V9fsSetattrState *vs;
1455    int err = 0;
1456
1457    vs = qemu_malloc(sizeof(*vs));
1458    vs->pdu = pdu;
1459    vs->offset = 7;
1460
1461    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
1462
1463    vs->fidp = lookup_fid(s, fid);
1464    if (vs->fidp == NULL) {
1465        err = -EINVAL;
1466        goto out;
1467    }
1468
1469    if (vs->v9iattr.valid & ATTR_MODE) {
1470        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
1471    }
1472
1473    v9fs_setattr_post_chmod(s, vs, err);
1474    return;
1475
1476out:
1477    complete_pdu(s, vs->pdu, err);
1478    qemu_free(vs);
1479}
1480
1481static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1482{
1483    complete_pdu(s, vs->pdu, err);
1484
1485    if (vs->nwnames) {
1486        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1487            v9fs_string_free(&vs->wnames[vs->name_idx]);
1488        }
1489
1490        qemu_free(vs->wnames);
1491        qemu_free(vs->qids);
1492    }
1493}
1494
1495static void v9fs_walk_marshal(V9fsWalkState *vs)
1496{
1497    int i;
1498    vs->offset = 7;
1499    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1500
1501    for (i = 0; i < vs->nwnames; i++) {
1502        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1503    }
1504}
1505
1506static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1507                                                                int err)
1508{
1509    if (err == -1) {
1510        free_fid(s, vs->newfidp->fid);
1511        v9fs_string_free(&vs->path);
1512        err = -ENOENT;
1513        goto out;
1514    }
1515
1516    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1517
1518    vs->name_idx++;
1519    if (vs->name_idx < vs->nwnames) {
1520        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1521                                            vs->wnames[vs->name_idx].data);
1522        v9fs_string_copy(&vs->newfidp->path, &vs->path);
1523
1524        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1525        v9fs_walk_post_newfid_lstat(s, vs, err);
1526        return;
1527    }
1528
1529    v9fs_string_free(&vs->path);
1530    v9fs_walk_marshal(vs);
1531    err = vs->offset;
1532out:
1533    v9fs_walk_complete(s, vs, err);
1534}
1535
1536static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1537        int err)
1538{
1539    if (err == -1) {
1540        v9fs_string_free(&vs->path);
1541        err = -ENOENT;
1542        goto out;
1543    }
1544
1545    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1546    vs->name_idx++;
1547    if (vs->name_idx < vs->nwnames) {
1548
1549        v9fs_string_sprintf(&vs->path, "%s/%s",
1550                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1551        v9fs_string_copy(&vs->fidp->path, &vs->path);
1552
1553        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1554        v9fs_walk_post_oldfid_lstat(s, vs, err);
1555        return;
1556    }
1557
1558    v9fs_string_free(&vs->path);
1559    v9fs_walk_marshal(vs);
1560    err = vs->offset;
1561out:
1562    v9fs_walk_complete(s, vs, err);
1563}
1564
1565static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
1566{
1567    int32_t fid, newfid;
1568    V9fsWalkState *vs;
1569    int err = 0;
1570    int i;
1571
1572    vs = qemu_malloc(sizeof(*vs));
1573    vs->pdu = pdu;
1574    vs->wnames = NULL;
1575    vs->qids = NULL;
1576    vs->offset = 7;
1577
1578    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1579                                            &newfid, &vs->nwnames);
1580
1581    if (vs->nwnames) {
1582        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1583
1584        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1585
1586        for (i = 0; i < vs->nwnames; i++) {
1587            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1588                                            &vs->wnames[i]);
1589        }
1590    }
1591
1592    vs->fidp = lookup_fid(s, fid);
1593    if (vs->fidp == NULL) {
1594        err = -ENOENT;
1595        goto out;
1596    }
1597
1598    /* FIXME: is this really valid? */
1599    if (fid == newfid) {
1600
1601        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1602        v9fs_string_init(&vs->path);
1603        vs->name_idx = 0;
1604
1605        if (vs->name_idx < vs->nwnames) {
1606            v9fs_string_sprintf(&vs->path, "%s/%s",
1607                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1608            v9fs_string_copy(&vs->fidp->path, &vs->path);
1609
1610            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1611            v9fs_walk_post_oldfid_lstat(s, vs, err);
1612            return;
1613        }
1614    } else {
1615        vs->newfidp = alloc_fid(s, newfid);
1616        if (vs->newfidp == NULL) {
1617            err = -EINVAL;
1618            goto out;
1619        }
1620
1621        vs->newfidp->uid = vs->fidp->uid;
1622        v9fs_string_init(&vs->path);
1623        vs->name_idx = 0;
1624        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1625
1626        if (vs->name_idx < vs->nwnames) {
1627            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1628                                vs->wnames[vs->name_idx].data);
1629            v9fs_string_copy(&vs->newfidp->path, &vs->path);
1630
1631            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1632            v9fs_walk_post_newfid_lstat(s, vs, err);
1633            return;
1634        }
1635    }
1636
1637    v9fs_walk_marshal(vs);
1638    err = vs->offset;
1639out:
1640    v9fs_walk_complete(s, vs, err);
1641}
1642
1643static int32_t get_iounit(V9fsState *s, V9fsString *name)
1644{
1645    struct statfs stbuf;
1646    int32_t iounit = 0;
1647
1648    /*
1649     * iounit should be multiples of f_bsize (host filesystem block size
1650     * and as well as less than (client msize - P9_IOHDRSZ))
1651     */
1652    if (!v9fs_do_statfs(s, name, &stbuf)) {
1653        iounit = stbuf.f_bsize;
1654        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1655    }
1656
1657    if (!iounit) {
1658        iounit = s->msize - P9_IOHDRSZ;
1659    }
1660    return iounit;
1661}
1662
1663static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1664{
1665    if (vs->fidp->fs.dir == NULL) {
1666        err = -errno;
1667        goto out;
1668    }
1669    vs->fidp->fid_type = P9_FID_DIR;
1670    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1671    err = vs->offset;
1672out:
1673    complete_pdu(s, vs->pdu, err);
1674    qemu_free(vs);
1675
1676}
1677
1678static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1679{
1680    int err;
1681    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1682    err = vs->offset;
1683    complete_pdu(s, vs->pdu, err);
1684    qemu_free(vs);
1685}
1686
1687static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1688{
1689    if (vs->fidp->fs.fd == -1) {
1690        err = -errno;
1691        goto out;
1692    }
1693    vs->fidp->fid_type = P9_FID_FILE;
1694    vs->iounit = get_iounit(s, &vs->fidp->path);
1695    v9fs_open_post_getiounit(s, vs);
1696    return;
1697out:
1698    complete_pdu(s, vs->pdu, err);
1699    qemu_free(vs);
1700}
1701
1702static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1703{
1704    int flags;
1705
1706    if (err) {
1707        err = -errno;
1708        goto out;
1709    }
1710
1711    stat_to_qid(&vs->stbuf, &vs->qid);
1712
1713    if (S_ISDIR(vs->stbuf.st_mode)) {
1714        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1715        v9fs_open_post_opendir(s, vs, err);
1716    } else {
1717        if (s->proto_version == V9FS_PROTO_2000L) {
1718            flags = vs->mode;
1719            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1720            /* Ignore direct disk access hint until the server supports it. */
1721            flags &= ~O_DIRECT;
1722        } else {
1723            flags = omode_to_uflags(vs->mode);
1724        }
1725        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1726        v9fs_open_post_open(s, vs, err);
1727    }
1728    return;
1729out:
1730    complete_pdu(s, vs->pdu, err);
1731    qemu_free(vs);
1732}
1733
1734static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
1735{
1736    int32_t fid;
1737    V9fsOpenState *vs;
1738    ssize_t err = 0;
1739
1740    vs = qemu_malloc(sizeof(*vs));
1741    vs->pdu = pdu;
1742    vs->offset = 7;
1743    vs->mode = 0;
1744
1745    if (s->proto_version == V9FS_PROTO_2000L) {
1746        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
1747    } else {
1748        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1749    }
1750
1751    vs->fidp = lookup_fid(s, fid);
1752    if (vs->fidp == NULL) {
1753        err = -ENOENT;
1754        goto out;
1755    }
1756
1757    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1758
1759    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1760
1761    v9fs_open_post_lstat(s, vs, err);
1762    return;
1763out:
1764    complete_pdu(s, pdu, err);
1765    qemu_free(vs);
1766}
1767
1768static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1769{
1770    if (err == 0) {
1771        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1772        stat_to_qid(&vs->stbuf, &vs->qid);
1773        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
1774                &vs->iounit);
1775        err = vs->offset;
1776    } else {
1777        vs->fidp->fid_type = P9_FID_NONE;
1778        err = -errno;
1779        if (vs->fidp->fs.fd > 0) {
1780            close(vs->fidp->fs.fd);
1781        }
1782    }
1783
1784    complete_pdu(s, vs->pdu, err);
1785    v9fs_string_free(&vs->name);
1786    v9fs_string_free(&vs->fullname);
1787    qemu_free(vs);
1788}
1789
1790static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
1791        int err)
1792{
1793    if (err) {
1794        err = -errno;
1795        goto out;
1796    }
1797    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1798
1799out:
1800    v9fs_post_lcreate(s, vs, err);
1801}
1802
1803static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
1804        int err)
1805{
1806    if (vs->fidp->fs.fd == -1) {
1807        err = -errno;
1808        goto out;
1809    }
1810    vs->fidp->fid_type = P9_FID_FILE;
1811    vs->iounit =  get_iounit(s, &vs->fullname);
1812    v9fs_lcreate_post_get_iounit(s, vs, err);
1813    return;
1814
1815out:
1816    v9fs_post_lcreate(s, vs, err);
1817}
1818
1819static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
1820{
1821    int32_t dfid, flags, mode;
1822    gid_t gid;
1823    V9fsLcreateState *vs;
1824    ssize_t err = 0;
1825
1826    vs = qemu_malloc(sizeof(*vs));
1827    vs->pdu = pdu;
1828    vs->offset = 7;
1829
1830    v9fs_string_init(&vs->fullname);
1831
1832    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
1833            &mode, &gid);
1834
1835    vs->fidp = lookup_fid(s, dfid);
1836    if (vs->fidp == NULL) {
1837        err = -ENOENT;
1838        goto out;
1839    }
1840
1841    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1842             vs->name.data);
1843
1844    /* Ignore direct disk access hint until the server supports it. */
1845    flags &= ~O_DIRECT;
1846
1847    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
1848            gid, flags, mode);
1849    v9fs_lcreate_post_do_open2(s, vs, err);
1850    return;
1851
1852out:
1853    complete_pdu(s, vs->pdu, err);
1854    v9fs_string_free(&vs->name);
1855    qemu_free(vs);
1856}
1857
1858static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
1859{
1860    if (err == -1) {
1861        err = -errno;
1862    }
1863    complete_pdu(s, pdu, err);
1864}
1865
1866static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
1867{
1868    int32_t fid;
1869    size_t offset = 7;
1870    V9fsFidState *fidp;
1871    int datasync;
1872    int err;
1873
1874    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1875    fidp = lookup_fid(s, fid);
1876    if (fidp == NULL) {
1877        err = -ENOENT;
1878        v9fs_post_do_fsync(s, pdu, err);
1879        return;
1880    }
1881    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
1882    v9fs_post_do_fsync(s, pdu, err);
1883}
1884
1885static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
1886{
1887    int32_t fid;
1888    size_t offset = 7;
1889    int err;
1890
1891    pdu_unmarshal(pdu, offset, "d", &fid);
1892
1893    err = free_fid(s, fid);
1894    if (err < 0) {
1895        goto out;
1896    }
1897
1898    offset = 7;
1899    err = offset;
1900out:
1901    complete_pdu(s, pdu, err);
1902}
1903
1904static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1905
1906static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1907{
1908    if (err) {
1909        goto out;
1910    }
1911    v9fs_stat_free(&vs->v9stat);
1912    v9fs_string_free(&vs->name);
1913    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1914    vs->offset += vs->count;
1915    err = vs->offset;
1916out:
1917    complete_pdu(s, vs->pdu, err);
1918    qemu_free(vs);
1919    return;
1920}
1921
1922static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1923                                    ssize_t err)
1924{
1925    if (err) {
1926        err = -errno;
1927        goto out;
1928    }
1929    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1930    if (err) {
1931        goto out;
1932    }
1933
1934    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1935                            &vs->v9stat);
1936    if ((vs->len != (vs->v9stat.size + 2)) ||
1937            ((vs->count + vs->len) > vs->max_count)) {
1938        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1939        v9fs_read_post_seekdir(s, vs, err);
1940        return;
1941    }
1942    vs->count += vs->len;
1943    v9fs_stat_free(&vs->v9stat);
1944    v9fs_string_free(&vs->name);
1945    vs->dir_pos = vs->dent->d_off;
1946    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1947    v9fs_read_post_readdir(s, vs, err);
1948    return;
1949out:
1950    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1951    v9fs_read_post_seekdir(s, vs, err);
1952    return;
1953
1954}
1955
1956static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1957{
1958    if (vs->dent) {
1959        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1960        v9fs_string_init(&vs->name);
1961        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1962                            vs->dent->d_name);
1963        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1964        v9fs_read_post_dir_lstat(s, vs, err);
1965        return;
1966    }
1967
1968    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1969    vs->offset += vs->count;
1970    err = vs->offset;
1971    complete_pdu(s, vs->pdu, err);
1972    qemu_free(vs);
1973    return;
1974}
1975
1976static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1977{
1978    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1979    v9fs_read_post_readdir(s, vs, err);
1980    return;
1981}
1982
1983static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1984                                       ssize_t err)
1985{
1986    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1987    v9fs_read_post_telldir(s, vs, err);
1988    return;
1989}
1990
1991static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1992{
1993    if (err  < 0) {
1994        /* IO error return the error */
1995        err = -errno;
1996        goto out;
1997    }
1998    vs->total += vs->len;
1999    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2000    if (vs->total < vs->count && vs->len > 0) {
2001        do {
2002            if (0) {
2003                print_sg(vs->sg, vs->cnt);
2004            }
2005            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2006                      vs->off);
2007            if (vs->len > 0) {
2008                vs->off += vs->len;
2009            }
2010        } while (vs->len == -1 && errno == EINTR);
2011        if (vs->len == -1) {
2012            err  = -errno;
2013        }
2014        v9fs_read_post_preadv(s, vs, err);
2015        return;
2016    }
2017    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2018    vs->offset += vs->count;
2019    err = vs->offset;
2020
2021out:
2022    complete_pdu(s, vs->pdu, err);
2023    qemu_free(vs);
2024}
2025
2026static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
2027{
2028    ssize_t err = 0;
2029    int read_count;
2030    int64_t xattr_len;
2031
2032    xattr_len = vs->fidp->fs.xattr.len;
2033    read_count = xattr_len - vs->off;
2034    if (read_count > vs->count) {
2035        read_count = vs->count;
2036    } else if (read_count < 0) {
2037        /*
2038         * read beyond XATTR value
2039         */
2040        read_count = 0;
2041    }
2042    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
2043    vs->offset += pdu_pack(vs->pdu, vs->offset,
2044                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
2045                           read_count);
2046    err = vs->offset;
2047    complete_pdu(s, vs->pdu, err);
2048    qemu_free(vs);
2049}
2050
2051static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
2052{
2053    int32_t fid;
2054    V9fsReadState *vs;
2055    ssize_t err = 0;
2056
2057    vs = qemu_malloc(sizeof(*vs));
2058    vs->pdu = pdu;
2059    vs->offset = 7;
2060    vs->total = 0;
2061    vs->len = 0;
2062    vs->count = 0;
2063
2064    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
2065
2066    vs->fidp = lookup_fid(s, fid);
2067    if (vs->fidp == NULL) {
2068        err = -EINVAL;
2069        goto out;
2070    }
2071
2072    if (vs->fidp->fid_type == P9_FID_DIR) {
2073        vs->max_count = vs->count;
2074        vs->count = 0;
2075        if (vs->off == 0) {
2076            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
2077        }
2078        v9fs_read_post_rewinddir(s, vs, err);
2079        return;
2080    } else if (vs->fidp->fid_type == P9_FID_FILE) {
2081        vs->sg = vs->iov;
2082        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
2083        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2084        if (vs->total <= vs->count) {
2085            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2086                                    vs->off);
2087            if (vs->len > 0) {
2088                vs->off += vs->len;
2089            }
2090            err = vs->len;
2091            v9fs_read_post_preadv(s, vs, err);
2092        }
2093        return;
2094    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2095        v9fs_xattr_read(s, vs);
2096        return;
2097    } else {
2098        err = -EINVAL;
2099    }
2100out:
2101    complete_pdu(s, pdu, err);
2102    qemu_free(vs);
2103}
2104
2105typedef struct V9fsReadDirState {
2106    V9fsPDU *pdu;
2107    V9fsFidState *fidp;
2108    V9fsQID qid;
2109    off_t saved_dir_pos;
2110    struct dirent *dent;
2111    int32_t count;
2112    int32_t max_count;
2113    size_t offset;
2114    int64_t initial_offset;
2115    V9fsString name;
2116} V9fsReadDirState;
2117
2118static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
2119{
2120    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
2121    vs->offset += vs->count;
2122    complete_pdu(s, vs->pdu, vs->offset);
2123    qemu_free(vs);
2124    return;
2125}
2126
2127/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
2128 * size of type (1) + size of name.size (2) + strlen(name.data)
2129 */
2130#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
2131
2132static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
2133{
2134    int len;
2135    size_t size;
2136
2137    if (vs->dent) {
2138        v9fs_string_init(&vs->name);
2139        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
2140
2141        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
2142            /* Ran out of buffer. Set dir back to old position and return */
2143            v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
2144            v9fs_readdir_post_seekdir(s, vs);
2145            return;
2146        }
2147
2148        /* Fill up just the path field of qid because the client uses
2149         * only that. To fill the entire qid structure we will have
2150         * to stat each dirent found, which is expensive
2151         */
2152        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
2153        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
2154        /* Fill the other fields with dummy values */
2155        vs->qid.type = 0;
2156        vs->qid.version = 0;
2157
2158        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
2159                              &vs->qid, vs->dent->d_off,
2160                              vs->dent->d_type, &vs->name);
2161        vs->count += len;
2162        v9fs_string_free(&vs->name);
2163        vs->saved_dir_pos = vs->dent->d_off;
2164        vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
2165        v9fs_readdir_post_readdir(s, vs);
2166        return;
2167    }
2168
2169    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
2170    vs->offset += vs->count;
2171    complete_pdu(s, vs->pdu, vs->offset);
2172    qemu_free(vs);
2173    return;
2174}
2175
2176static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
2177{
2178    vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
2179    v9fs_readdir_post_readdir(s, vs);
2180    return;
2181}
2182
2183static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
2184{
2185    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
2186    v9fs_readdir_post_telldir(s, vs);
2187    return;
2188}
2189
2190static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
2191{
2192    int32_t fid;
2193    V9fsReadDirState *vs;
2194    ssize_t err = 0;
2195    size_t offset = 7;
2196
2197    vs = qemu_malloc(sizeof(*vs));
2198    vs->pdu = pdu;
2199    vs->offset = 7;
2200    vs->count = 0;
2201
2202    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
2203                                                        &vs->max_count);
2204
2205    vs->fidp = lookup_fid(s, fid);
2206    if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
2207        err = -EINVAL;
2208        goto out;
2209    }
2210
2211    if (vs->initial_offset == 0) {
2212        v9fs_do_rewinddir(s, vs->fidp->fs.dir);
2213    } else {
2214        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
2215    }
2216
2217    v9fs_readdir_post_setdir(s, vs);
2218    return;
2219
2220out:
2221    complete_pdu(s, pdu, err);
2222    qemu_free(vs);
2223    return;
2224}
2225
2226static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
2227                                   ssize_t err)
2228{
2229    if (err  < 0) {
2230        /* IO error return the error */
2231        err = -errno;
2232        goto out;
2233    }
2234    vs->total += vs->len;
2235    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2236    if (vs->total < vs->count && vs->len > 0) {
2237        do {
2238            if (0) {
2239                print_sg(vs->sg, vs->cnt);
2240            }
2241            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2242                      vs->off);
2243            if (vs->len > 0) {
2244                vs->off += vs->len;
2245            }
2246        } while (vs->len == -1 && errno == EINTR);
2247        if (vs->len == -1) {
2248            err  = -errno;
2249        }
2250        v9fs_write_post_pwritev(s, vs, err);
2251        return;
2252    }
2253    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2254    err = vs->offset;
2255out:
2256    complete_pdu(s, vs->pdu, err);
2257    qemu_free(vs);
2258}
2259
2260static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
2261{
2262    int i, to_copy;
2263    ssize_t err = 0;
2264    int write_count;
2265    int64_t xattr_len;
2266
2267    xattr_len = vs->fidp->fs.xattr.len;
2268    write_count = xattr_len - vs->off;
2269    if (write_count > vs->count) {
2270        write_count = vs->count;
2271    } else if (write_count < 0) {
2272        /*
2273         * write beyond XATTR value len specified in
2274         * xattrcreate
2275         */
2276        err = -ENOSPC;
2277        goto out;
2278    }
2279    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
2280    err = vs->offset;
2281    vs->fidp->fs.xattr.copied_len += write_count;
2282    /*
2283     * Now copy the content from sg list
2284     */
2285    for (i = 0; i < vs->cnt; i++) {
2286        if (write_count > vs->sg[i].iov_len) {
2287            to_copy = vs->sg[i].iov_len;
2288        } else {
2289            to_copy = write_count;
2290        }
2291        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
2292               vs->sg[i].iov_base, to_copy);
2293        /* updating vs->off since we are not using below */
2294        vs->off += to_copy;
2295        write_count -= to_copy;
2296    }
2297out:
2298    complete_pdu(s, vs->pdu, err);
2299    qemu_free(vs);
2300}
2301
2302static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
2303{
2304    int32_t fid;
2305    V9fsWriteState *vs;
2306    ssize_t err;
2307
2308    vs = qemu_malloc(sizeof(*vs));
2309
2310    vs->pdu = pdu;
2311    vs->offset = 7;
2312    vs->sg = vs->iov;
2313    vs->total = 0;
2314    vs->len = 0;
2315
2316    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2317                  vs->sg, &vs->cnt);
2318
2319    vs->fidp = lookup_fid(s, fid);
2320    if (vs->fidp == NULL) {
2321        err = -EINVAL;
2322        goto out;
2323    }
2324
2325    if (vs->fidp->fid_type == P9_FID_FILE) {
2326        if (vs->fidp->fs.fd == -1) {
2327            err = -EINVAL;
2328            goto out;
2329        }
2330    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2331        /*
2332         * setxattr operation
2333         */
2334        v9fs_xattr_write(s, vs);
2335        return;
2336    } else {
2337        err = -EINVAL;
2338        goto out;
2339    }
2340    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2341    if (vs->total <= vs->count) {
2342        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
2343        if (vs->len > 0) {
2344            vs->off += vs->len;
2345        }
2346        err = vs->len;
2347        v9fs_write_post_pwritev(s, vs, err);
2348    }
2349    return;
2350out:
2351    complete_pdu(s, vs->pdu, err);
2352    qemu_free(vs);
2353}
2354
2355static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2356{
2357    int err;
2358    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2359    stat_to_qid(&vs->stbuf, &vs->qid);
2360
2361    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2362    err = vs->offset;
2363
2364    complete_pdu(s, vs->pdu, err);
2365    v9fs_string_free(&vs->name);
2366    v9fs_string_free(&vs->extension);
2367    v9fs_string_free(&vs->fullname);
2368    qemu_free(vs);
2369}
2370
2371static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2372{
2373    if (err == 0) {
2374        vs->iounit = get_iounit(s, &vs->fidp->path);
2375        v9fs_create_post_getiounit(s, vs);
2376        return;
2377    }
2378
2379    complete_pdu(s, vs->pdu, err);
2380    v9fs_string_free(&vs->name);
2381    v9fs_string_free(&vs->extension);
2382    v9fs_string_free(&vs->fullname);
2383    qemu_free(vs);
2384}
2385
2386static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2387{
2388    if (err) {
2389        err = -errno;
2390    }
2391    v9fs_post_create(s, vs, err);
2392}
2393
2394static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2395                                                                    int err)
2396{
2397    if (!vs->fidp->fs.dir) {
2398        err = -errno;
2399    }
2400    vs->fidp->fid_type = P9_FID_DIR;
2401    v9fs_post_create(s, vs, err);
2402}
2403
2404static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2405                                                                    int err)
2406{
2407    if (err) {
2408        err = -errno;
2409        goto out;
2410    }
2411
2412    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
2413    v9fs_create_post_opendir(s, vs, err);
2414    return;
2415
2416out:
2417    v9fs_post_create(s, vs, err);
2418}
2419
2420static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2421{
2422    if (err) {
2423        err = -errno;
2424        goto out;
2425    }
2426
2427    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2428    v9fs_create_post_dir_lstat(s, vs, err);
2429    return;
2430
2431out:
2432    v9fs_post_create(s, vs, err);
2433}
2434
2435static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2436{
2437    if (err) {
2438        vs->fidp->fid_type = P9_FID_NONE;
2439        close(vs->fidp->fs.fd);
2440        err = -errno;
2441    }
2442    v9fs_post_create(s, vs, err);
2443    return;
2444}
2445
2446static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2447{
2448    if (vs->fidp->fs.fd == -1) {
2449        err = -errno;
2450        goto out;
2451    }
2452    vs->fidp->fid_type = P9_FID_FILE;
2453    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
2454    v9fs_create_post_fstat(s, vs, err);
2455
2456    return;
2457
2458out:
2459    v9fs_post_create(s, vs, err);
2460
2461}
2462
2463static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2464{
2465
2466    if (err == 0 || errno != ENOENT) {
2467        err = -errno;
2468        goto out;
2469    }
2470
2471    if (vs->perm & P9_STAT_MODE_DIR) {
2472        err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
2473                vs->fidp->uid, -1);
2474        v9fs_create_post_mkdir(s, vs, err);
2475    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2476        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
2477                vs->fullname.data, -1);
2478        v9fs_create_post_perms(s, vs, err);
2479    } else if (vs->perm & P9_STAT_MODE_LINK) {
2480        int32_t nfid = atoi(vs->extension.data);
2481        V9fsFidState *nfidp = lookup_fid(s, nfid);
2482        if (nfidp == NULL) {
2483            err = -errno;
2484            v9fs_post_create(s, vs, err);
2485        }
2486        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2487        v9fs_create_post_perms(s, vs, err);
2488    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2489        char ctype;
2490        uint32_t major, minor;
2491        mode_t nmode = 0;
2492
2493        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2494                                        &minor) != 3) {
2495            err = -errno;
2496            v9fs_post_create(s, vs, err);
2497        }
2498
2499        switch (ctype) {
2500        case 'c':
2501            nmode = S_IFCHR;
2502            break;
2503        case 'b':
2504            nmode = S_IFBLK;
2505            break;
2506        default:
2507            err = -EIO;
2508            v9fs_post_create(s, vs, err);
2509        }
2510
2511        nmode |= vs->perm & 0777;
2512        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
2513                makedev(major, minor), vs->fidp->uid, -1);
2514        v9fs_create_post_perms(s, vs, err);
2515    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2516        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
2517                0, vs->fidp->uid, -1);
2518        v9fs_post_create(s, vs, err);
2519    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2520        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
2521                0, vs->fidp->uid, -1);
2522        v9fs_post_create(s, vs, err);
2523    } else {
2524        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
2525                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
2526
2527        v9fs_create_post_open2(s, vs, err);
2528    }
2529
2530    return;
2531
2532out:
2533    v9fs_post_create(s, vs, err);
2534}
2535
2536static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
2537{
2538    int32_t fid;
2539    V9fsCreateState *vs;
2540    int err = 0;
2541
2542    vs = qemu_malloc(sizeof(*vs));
2543    vs->pdu = pdu;
2544    vs->offset = 7;
2545
2546    v9fs_string_init(&vs->fullname);
2547
2548    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2549                                &vs->perm, &vs->mode, &vs->extension);
2550
2551    vs->fidp = lookup_fid(s, fid);
2552    if (vs->fidp == NULL) {
2553        err = -EINVAL;
2554        goto out;
2555    }
2556
2557    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2558                                                        vs->name.data);
2559
2560    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2561    v9fs_create_post_lstat(s, vs, err);
2562    return;
2563
2564out:
2565    complete_pdu(s, vs->pdu, err);
2566    v9fs_string_free(&vs->name);
2567    v9fs_string_free(&vs->extension);
2568    qemu_free(vs);
2569}
2570
2571static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
2572{
2573    if (err == 0) {
2574        stat_to_qid(&vs->stbuf, &vs->qid);
2575        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
2576        err = vs->offset;
2577    } else {
2578        err = -errno;
2579    }
2580    complete_pdu(s, vs->pdu, err);
2581    v9fs_string_free(&vs->name);
2582    v9fs_string_free(&vs->symname);
2583    v9fs_string_free(&vs->fullname);
2584    qemu_free(vs);
2585}
2586
2587static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
2588        int err)
2589{
2590    if (err) {
2591        goto out;
2592    }
2593    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2594out:
2595    v9fs_post_symlink(s, vs, err);
2596}
2597
2598static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
2599{
2600    int32_t dfid;
2601    V9fsSymlinkState *vs;
2602    int err = 0;
2603    gid_t gid;
2604
2605    vs = qemu_malloc(sizeof(*vs));
2606    vs->pdu = pdu;
2607    vs->offset = 7;
2608
2609    v9fs_string_init(&vs->fullname);
2610
2611    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
2612            &vs->symname, &gid);
2613
2614    vs->dfidp = lookup_fid(s, dfid);
2615    if (vs->dfidp == NULL) {
2616        err = -EINVAL;
2617        goto out;
2618    }
2619
2620    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
2621            vs->name.data);
2622    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
2623            vs->fullname.data, gid);
2624    v9fs_symlink_post_do_symlink(s, vs, err);
2625    return;
2626
2627out:
2628    complete_pdu(s, vs->pdu, err);
2629    v9fs_string_free(&vs->name);
2630    v9fs_string_free(&vs->symname);
2631    qemu_free(vs);
2632}
2633
2634static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
2635{
2636    /* A nop call with no return */
2637    complete_pdu(s, pdu, 7);
2638}
2639
2640static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
2641{
2642    int32_t dfid, oldfid;
2643    V9fsFidState *dfidp, *oldfidp;
2644    V9fsString name, fullname;
2645    size_t offset = 7;
2646    int err = 0;
2647
2648    v9fs_string_init(&fullname);
2649
2650    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2651
2652    dfidp = lookup_fid(s, dfid);
2653    if (dfidp == NULL) {
2654        err = -errno;
2655        goto out;
2656    }
2657
2658    oldfidp = lookup_fid(s, oldfid);
2659    if (oldfidp == NULL) {
2660        err = -errno;
2661        goto out;
2662    }
2663
2664    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2665    err = offset;
2666    err = v9fs_do_link(s, &oldfidp->path, &fullname);
2667    if (err) {
2668        err = -errno;
2669    }
2670    v9fs_string_free(&fullname);
2671
2672out:
2673    v9fs_string_free(&name);
2674    complete_pdu(s, pdu, err);
2675}
2676
2677static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
2678                                                                int err)
2679{
2680    if (err < 0) {
2681        err = -errno;
2682    } else {
2683        err = vs->offset;
2684    }
2685
2686    /* For TREMOVE we need to clunk the fid even on failed remove */
2687    free_fid(s, vs->fidp->fid);
2688
2689    complete_pdu(s, vs->pdu, err);
2690    qemu_free(vs);
2691}
2692
2693static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
2694{
2695    int32_t fid;
2696    V9fsRemoveState *vs;
2697    int err = 0;
2698
2699    vs = qemu_malloc(sizeof(*vs));
2700    vs->pdu = pdu;
2701    vs->offset = 7;
2702
2703    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
2704
2705    vs->fidp = lookup_fid(s, fid);
2706    if (vs->fidp == NULL) {
2707        err = -EINVAL;
2708        goto out;
2709    }
2710
2711    err = v9fs_do_remove(s, &vs->fidp->path);
2712    v9fs_remove_post_remove(s, vs, err);
2713    return;
2714
2715out:
2716    complete_pdu(s, pdu, err);
2717    qemu_free(vs);
2718}
2719
2720static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2721{
2722    if (err < 0) {
2723        goto out;
2724    }
2725
2726    err = vs->offset;
2727
2728out:
2729    v9fs_stat_free(&vs->v9stat);
2730    complete_pdu(s, vs->pdu, err);
2731    qemu_free(vs);
2732}
2733
2734static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2735{
2736    if (err < 0) {
2737        goto out;
2738    }
2739    if (vs->v9stat.length != -1) {
2740        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2741            err = -errno;
2742        }
2743    }
2744    v9fs_wstat_post_truncate(s, vs, err);
2745    return;
2746
2747out:
2748    v9fs_stat_free(&vs->v9stat);
2749    complete_pdu(s, vs->pdu, err);
2750    qemu_free(vs);
2751}
2752
2753static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
2754{
2755    int err = 0;
2756    char *old_name, *new_name;
2757    char *end;
2758
2759    if (vs->newdirfid != -1) {
2760        V9fsFidState *dirfidp;
2761        dirfidp = lookup_fid(s, vs->newdirfid);
2762
2763        if (dirfidp == NULL) {
2764            err = -ENOENT;
2765            goto out;
2766        }
2767
2768        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2769
2770        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
2771
2772        strcpy(new_name, dirfidp->path.data);
2773        strcat(new_name, "/");
2774        strcat(new_name + dirfidp->path.size, vs->name.data);
2775    } else {
2776        old_name = vs->fidp->path.data;
2777        end = strrchr(old_name, '/');
2778        if (end) {
2779            end++;
2780        } else {
2781            end = old_name;
2782        }
2783        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
2784
2785        strncat(new_name, old_name, end - old_name);
2786        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
2787    }
2788
2789    v9fs_string_free(&vs->name);
2790    vs->name.data = qemu_strdup(new_name);
2791    vs->name.size = strlen(new_name);
2792
2793    if (strcmp(new_name, vs->fidp->path.data) != 0) {
2794        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
2795            err = -errno;
2796        } else {
2797            V9fsFidState *fidp;
2798            /*
2799            * Fixup fid's pointing to the old name to
2800            * start pointing to the new name
2801            */
2802            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
2803                if (vs->fidp == fidp) {
2804                    /*
2805                    * we replace name of this fid towards the end
2806                    * so that our below strcmp will work
2807                    */
2808                    continue;
2809                }
2810                if (!strncmp(vs->fidp->path.data, fidp->path.data,
2811                    strlen(vs->fidp->path.data))) {
2812                    /* replace the name */
2813                    v9fs_fix_path(&fidp->path, &vs->name,
2814                                  strlen(vs->fidp->path.data));
2815                }
2816            }
2817            v9fs_string_copy(&vs->fidp->path, &vs->name);
2818        }
2819    }
2820out:
2821    v9fs_string_free(&vs->name);
2822    return err;
2823}
2824
2825static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
2826{
2827    complete_pdu(s, vs->pdu, err);
2828    qemu_free(vs);
2829}
2830
2831static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2832{
2833    if (err < 0) {
2834        goto out;
2835    }
2836
2837    if (vs->v9stat.name.size != 0) {
2838        V9fsRenameState *vr;
2839
2840        vr = qemu_mallocz(sizeof(V9fsRenameState));
2841        vr->newdirfid = -1;
2842        vr->pdu = vs->pdu;
2843        vr->fidp = vs->fidp;
2844        vr->offset = vs->offset;
2845        vr->name.size = vs->v9stat.name.size;
2846        vr->name.data = qemu_strdup(vs->v9stat.name.data);
2847
2848        err = v9fs_complete_rename(s, vr);
2849        qemu_free(vr);
2850    }
2851    v9fs_wstat_post_rename(s, vs, err);
2852    return;
2853
2854out:
2855    v9fs_stat_free(&vs->v9stat);
2856    complete_pdu(s, vs->pdu, err);
2857    qemu_free(vs);
2858}
2859
2860static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
2861{
2862    int32_t fid;
2863    V9fsRenameState *vs;
2864    ssize_t err = 0;
2865
2866    vs = qemu_malloc(sizeof(*vs));
2867    vs->pdu = pdu;
2868    vs->offset = 7;
2869
2870    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
2871
2872    vs->fidp = lookup_fid(s, fid);
2873    if (vs->fidp == NULL) {
2874        err = -ENOENT;
2875        goto out;
2876    }
2877
2878    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
2879
2880    err = v9fs_complete_rename(s, vs);
2881    v9fs_rename_post_rename(s, vs, err);
2882    return;
2883out:
2884    complete_pdu(s, vs->pdu, err);
2885    qemu_free(vs);
2886}
2887
2888static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2889{
2890    if (err < 0) {
2891        goto out;
2892    }
2893
2894    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2895        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2896                    vs->v9stat.n_gid)) {
2897            err = -errno;
2898        }
2899    }
2900    v9fs_wstat_post_chown(s, vs, err);
2901    return;
2902
2903out:
2904    v9fs_stat_free(&vs->v9stat);
2905    complete_pdu(s, vs->pdu, err);
2906    qemu_free(vs);
2907}
2908
2909static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2910{
2911    if (err < 0) {
2912        goto out;
2913    }
2914
2915    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2916        struct timespec times[2];
2917        if (vs->v9stat.atime != -1) {
2918            times[0].tv_sec = vs->v9stat.atime;
2919            times[0].tv_nsec = 0;
2920        } else {
2921            times[0].tv_nsec = UTIME_OMIT;
2922        }
2923        if (vs->v9stat.mtime != -1) {
2924            times[1].tv_sec = vs->v9stat.mtime;
2925            times[1].tv_nsec = 0;
2926        } else {
2927            times[1].tv_nsec = UTIME_OMIT;
2928        }
2929
2930        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2931            err = -errno;
2932        }
2933    }
2934
2935    v9fs_wstat_post_utime(s, vs, err);
2936    return;
2937
2938out:
2939    v9fs_stat_free(&vs->v9stat);
2940    complete_pdu(s, vs->pdu, err);
2941    qemu_free(vs);
2942}
2943
2944static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2945{
2946    if (err == -1) {
2947        err = -errno;
2948    }
2949    v9fs_stat_free(&vs->v9stat);
2950    complete_pdu(s, vs->pdu, err);
2951    qemu_free(vs);
2952}
2953
2954static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2955{
2956    uint32_t v9_mode;
2957
2958    if (err == -1) {
2959        err = -errno;
2960        goto out;
2961    }
2962
2963    v9_mode = stat_to_v9mode(&vs->stbuf);
2964
2965    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2966        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2967            /* Attempting to change the type */
2968            err = -EIO;
2969            goto out;
2970    }
2971
2972    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2973                    &vs->v9stat.extension))) {
2974            err = -errno;
2975     }
2976    v9fs_wstat_post_chmod(s, vs, err);
2977    return;
2978
2979out:
2980    v9fs_stat_free(&vs->v9stat);
2981    complete_pdu(s, vs->pdu, err);
2982    qemu_free(vs);
2983}
2984
2985static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
2986{
2987    int32_t fid;
2988    V9fsWstatState *vs;
2989    int err = 0;
2990
2991    vs = qemu_malloc(sizeof(*vs));
2992    vs->pdu = pdu;
2993    vs->offset = 7;
2994
2995    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2996
2997    vs->fidp = lookup_fid(s, fid);
2998    if (vs->fidp == NULL) {
2999        err = -EINVAL;
3000        goto out;
3001    }
3002
3003    /* do we need to sync the file? */
3004    if (donttouch_stat(&vs->v9stat)) {
3005        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
3006        v9fs_wstat_post_fsync(s, vs, err);
3007        return;
3008    }
3009
3010    if (vs->v9stat.mode != -1) {
3011        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
3012        v9fs_wstat_post_lstat(s, vs, err);
3013        return;
3014    }
3015
3016    v9fs_wstat_post_chmod(s, vs, err);
3017    return;
3018
3019out:
3020    v9fs_stat_free(&vs->v9stat);
3021    complete_pdu(s, vs->pdu, err);
3022    qemu_free(vs);
3023}
3024
3025static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
3026{
3027    int32_t bsize_factor;
3028
3029    if (err) {
3030        err = -errno;
3031        goto out;
3032    }
3033
3034    /*
3035     * compute bsize factor based on host file system block size
3036     * and client msize
3037     */
3038    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
3039    if (!bsize_factor) {
3040        bsize_factor = 1;
3041    }
3042    vs->v9statfs.f_type = vs->stbuf.f_type;
3043    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
3044    vs->v9statfs.f_bsize *= bsize_factor;
3045    /*
3046     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
3047     * adjust(divide) the number of blocks, free blocks and available
3048     * blocks by bsize factor
3049     */
3050    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
3051    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
3052    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
3053    vs->v9statfs.f_files = vs->stbuf.f_files;
3054    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
3055    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
3056                        (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
3057    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
3058
3059    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
3060         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
3061         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
3062         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
3063         vs->v9statfs.f_namelen);
3064
3065out:
3066    complete_pdu(s, vs->pdu, vs->offset);
3067    qemu_free(vs);
3068}
3069
3070static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
3071{
3072    V9fsStatfsState *vs;
3073    ssize_t err = 0;
3074
3075    vs = qemu_malloc(sizeof(*vs));
3076    vs->pdu = pdu;
3077    vs->offset = 7;
3078
3079    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
3080
3081    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
3082
3083    vs->fidp = lookup_fid(s, vs->fid);
3084    if (vs->fidp == NULL) {
3085        err = -ENOENT;
3086        goto out;
3087    }
3088
3089    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
3090    v9fs_statfs_post_statfs(s, vs, err);
3091    return;
3092
3093out:
3094    complete_pdu(s, vs->pdu, err);
3095    qemu_free(vs);
3096}
3097
3098static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
3099{
3100    if (err == -1) {
3101        err = -errno;
3102        goto out;
3103    }
3104
3105    stat_to_qid(&vs->stbuf, &vs->qid);
3106    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
3107    err = vs->offset;
3108out:
3109    complete_pdu(s, vs->pdu, err);
3110    v9fs_string_free(&vs->fullname);
3111    v9fs_string_free(&vs->name);
3112    qemu_free(vs);
3113}
3114
3115static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
3116{
3117    if (err == -1) {
3118        err = -errno;
3119        goto out;
3120    }
3121
3122    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
3123    v9fs_mknod_post_lstat(s, vs, err);
3124    return;
3125out:
3126    complete_pdu(s, vs->pdu, err);
3127    v9fs_string_free(&vs->fullname);
3128    v9fs_string_free(&vs->name);
3129    qemu_free(vs);
3130}
3131
3132static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
3133{
3134    int32_t fid;
3135    V9fsMkState *vs;
3136    int err = 0;
3137    V9fsFidState *fidp;
3138    gid_t gid;
3139    int mode;
3140    int major, minor;
3141
3142    vs = qemu_malloc(sizeof(*vs));
3143    vs->pdu = pdu;
3144    vs->offset = 7;
3145
3146    v9fs_string_init(&vs->fullname);
3147    pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
3148        &major, &minor, &gid);
3149
3150    fidp = lookup_fid(s, fid);
3151    if (fidp == NULL) {
3152        err = -ENOENT;
3153        goto out;
3154    }
3155
3156    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
3157    err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
3158        fidp->uid, gid);
3159    v9fs_mknod_post_mknod(s, vs, err);
3160    return;
3161
3162out:
3163    complete_pdu(s, vs->pdu, err);
3164    v9fs_string_free(&vs->fullname);
3165    v9fs_string_free(&vs->name);
3166    qemu_free(vs);
3167}
3168
3169/*
3170 * Implement posix byte range locking code
3171 * Server side handling of locking code is very simple, because 9p server in
3172 * QEMU can handle only one client. And most of the lock handling
3173 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
3174 * do any thing in * qemu 9p server side lock code path.
3175 * So when a TLOCK request comes, always return success
3176 */
3177
3178static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
3179{
3180    int32_t fid, err = 0;
3181    V9fsLockState *vs;
3182
3183    vs = qemu_mallocz(sizeof(*vs));
3184    vs->pdu = pdu;
3185    vs->offset = 7;
3186
3187    vs->flock = qemu_malloc(sizeof(*vs->flock));
3188    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
3189                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
3190                            &vs->flock->proc_id, &vs->flock->client_id);
3191
3192    vs->status = P9_LOCK_ERROR;
3193
3194    /* We support only block flag now (that too ignored currently) */
3195    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
3196        err = -EINVAL;
3197        goto out;
3198    }
3199    vs->fidp = lookup_fid(s, fid);
3200    if (vs->fidp == NULL) {
3201        err = -ENOENT;
3202        goto out;
3203    }
3204
3205    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3206    if (err < 0) {
3207        err = -errno;
3208        goto out;
3209    }
3210    vs->status = P9_LOCK_SUCCESS;
3211out:
3212    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
3213    complete_pdu(s, vs->pdu, err);
3214    qemu_free(vs->flock);
3215    qemu_free(vs);
3216}
3217
3218/*
3219 * When a TGETLOCK request comes, always return success because all lock
3220 * handling is done by client's VFS layer.
3221 */
3222
3223static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
3224{
3225    int32_t fid, err = 0;
3226    V9fsGetlockState *vs;
3227
3228    vs = qemu_mallocz(sizeof(*vs));
3229    vs->pdu = pdu;
3230    vs->offset = 7;
3231
3232    vs->glock = qemu_malloc(sizeof(*vs->glock));
3233    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
3234                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
3235                &vs->glock->client_id);
3236
3237    vs->fidp = lookup_fid(s, fid);
3238    if (vs->fidp == NULL) {
3239        err = -ENOENT;
3240        goto out;
3241    }
3242
3243    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3244    if (err < 0) {
3245        err = -errno;
3246        goto out;
3247    }
3248    vs->glock->type = F_UNLCK;
3249    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
3250                vs->glock->start, vs->glock->length, vs->glock->proc_id,
3251                &vs->glock->client_id);
3252out:
3253    complete_pdu(s, vs->pdu, err);
3254    qemu_free(vs->glock);
3255    qemu_free(vs);
3256}
3257
3258static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
3259{
3260    if (err == -1) {
3261        err = -errno;
3262        goto out;
3263    }
3264
3265    stat_to_qid(&vs->stbuf, &vs->qid);
3266    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
3267    err = vs->offset;
3268out:
3269    complete_pdu(s, vs->pdu, err);
3270    v9fs_string_free(&vs->fullname);
3271    v9fs_string_free(&vs->name);
3272    qemu_free(vs);
3273}
3274
3275static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
3276{
3277    if (err == -1) {
3278        err = -errno;
3279        goto out;
3280    }
3281
3282    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
3283    v9fs_mkdir_post_lstat(s, vs, err);
3284    return;
3285out:
3286    complete_pdu(s, vs->pdu, err);
3287    v9fs_string_free(&vs->fullname);
3288    v9fs_string_free(&vs->name);
3289    qemu_free(vs);
3290}
3291
3292static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
3293{
3294    int32_t fid;
3295    V9fsMkState *vs;
3296    int err = 0;
3297    V9fsFidState *fidp;
3298    gid_t gid;
3299    int mode;
3300
3301    vs = qemu_malloc(sizeof(*vs));
3302    vs->pdu = pdu;
3303    vs->offset = 7;
3304
3305    v9fs_string_init(&vs->fullname);
3306    pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
3307        &gid);
3308
3309    fidp = lookup_fid(s, fid);
3310    if (fidp == NULL) {
3311        err = -ENOENT;
3312        goto out;
3313    }
3314
3315    v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
3316    err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
3317    v9fs_mkdir_post_mkdir(s, vs, err);
3318    return;
3319
3320out:
3321    complete_pdu(s, vs->pdu, err);
3322    v9fs_string_free(&vs->fullname);
3323    v9fs_string_free(&vs->name);
3324    qemu_free(vs);
3325}
3326
3327static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
3328{
3329
3330    if (err < 0) {
3331        err = -errno;
3332        free_fid(s, vs->xattr_fidp->fid);
3333        goto out;
3334    }
3335    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
3336    err = vs->offset;
3337out:
3338    complete_pdu(s, vs->pdu, err);
3339    v9fs_string_free(&vs->name);
3340    qemu_free(vs);
3341    return;
3342}
3343
3344static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
3345{
3346    if (err < 0) {
3347        err = -errno;
3348        free_fid(s, vs->xattr_fidp->fid);
3349        goto out;
3350    }
3351    /*
3352     * Read the xattr value
3353     */
3354    vs->xattr_fidp->fs.xattr.len = vs->size;
3355    vs->xattr_fidp->fid_type = P9_FID_XATTR;
3356    vs->xattr_fidp->fs.xattr.copied_len = -1;
3357    if (vs->size) {
3358        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3359        err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
3360                                &vs->name, vs->xattr_fidp->fs.xattr.value,
3361                                vs->xattr_fidp->fs.xattr.len);
3362    }
3363    v9fs_post_xattr_getvalue(s, vs, err);
3364    return;
3365out:
3366    complete_pdu(s, vs->pdu, err);
3367    v9fs_string_free(&vs->name);
3368    qemu_free(vs);
3369}
3370
3371static void v9fs_post_lxattr_getvalue(V9fsState *s,
3372                                      V9fsXattrState *vs, int err)
3373{
3374    if (err < 0) {
3375        err = -errno;
3376        free_fid(s, vs->xattr_fidp->fid);
3377        goto out;
3378    }
3379    vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
3380    err = vs->offset;
3381out:
3382    complete_pdu(s, vs->pdu, err);
3383    v9fs_string_free(&vs->name);
3384    qemu_free(vs);
3385    return;
3386}
3387
3388static void v9fs_post_lxattr_check(V9fsState *s,
3389                                   V9fsXattrState *vs, ssize_t err)
3390{
3391    if (err < 0) {
3392        err = -errno;
3393        free_fid(s, vs->xattr_fidp->fid);
3394        goto out;
3395    }
3396    /*
3397     * Read the xattr value
3398     */
3399    vs->xattr_fidp->fs.xattr.len = vs->size;
3400    vs->xattr_fidp->fid_type = P9_FID_XATTR;
3401    vs->xattr_fidp->fs.xattr.copied_len = -1;
3402    if (vs->size) {
3403        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3404        err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
3405                                 vs->xattr_fidp->fs.xattr.value,
3406                                 vs->xattr_fidp->fs.xattr.len);
3407    }
3408    v9fs_post_lxattr_getvalue(s, vs, err);
3409    return;
3410out:
3411    complete_pdu(s, vs->pdu, err);
3412    v9fs_string_free(&vs->name);
3413    qemu_free(vs);
3414}
3415
3416static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
3417{
3418    ssize_t err = 0;
3419    V9fsXattrState *vs;
3420    int32_t fid, newfid;
3421
3422    vs = qemu_malloc(sizeof(*vs));
3423    vs->pdu = pdu;
3424    vs->offset = 7;
3425
3426    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
3427    vs->file_fidp = lookup_fid(s, fid);
3428    if (vs->file_fidp == NULL) {
3429        err = -ENOENT;
3430        goto out;
3431    }
3432
3433    vs->xattr_fidp = alloc_fid(s, newfid);
3434    if (vs->xattr_fidp == NULL) {
3435        err = -EINVAL;
3436        goto out;
3437    }
3438
3439    v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
3440    if (vs->name.data[0] == 0) {
3441        /*
3442         * listxattr request. Get the size first
3443         */
3444        vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
3445                                      NULL, 0);
3446        if (vs->size < 0) {
3447            err = vs->size;
3448        }
3449        v9fs_post_lxattr_check(s, vs, err);
3450        return;
3451    } else {
3452        /*
3453         * specific xattr fid. We check for xattr
3454         * presence also collect the xattr size
3455         */
3456        vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
3457                                     &vs->name, NULL, 0);
3458        if (vs->size < 0) {
3459            err = vs->size;
3460        }
3461        v9fs_post_xattr_check(s, vs, err);
3462        return;
3463    }
3464out:
3465    complete_pdu(s, vs->pdu, err);
3466    v9fs_string_free(&vs->name);
3467    qemu_free(vs);
3468}
3469
3470static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
3471{
3472    int flags;
3473    int32_t fid;
3474    ssize_t err = 0;
3475    V9fsXattrState *vs;
3476
3477    vs = qemu_malloc(sizeof(*vs));
3478    vs->pdu = pdu;
3479    vs->offset = 7;
3480
3481    pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
3482                  &fid, &vs->name, &vs->size, &flags);
3483
3484    vs->file_fidp = lookup_fid(s, fid);
3485    if (vs->file_fidp == NULL) {
3486        err = -EINVAL;
3487        goto out;
3488    }
3489
3490    /* Make the file fid point to xattr */
3491    vs->xattr_fidp = vs->file_fidp;
3492    vs->xattr_fidp->fid_type = P9_FID_XATTR;
3493    vs->xattr_fidp->fs.xattr.copied_len = 0;
3494    vs->xattr_fidp->fs.xattr.len = vs->size;
3495    vs->xattr_fidp->fs.xattr.flags = flags;
3496    v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
3497    v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
3498    if (vs->size)
3499        vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
3500    else
3501        vs->xattr_fidp->fs.xattr.value = NULL;
3502
3503out:
3504    complete_pdu(s, vs->pdu, err);
3505    v9fs_string_free(&vs->name);
3506    qemu_free(vs);
3507}
3508
3509static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
3510                                                    int err)
3511{
3512    if (err < 0) {
3513        err = -errno;
3514        goto out;
3515    }
3516    vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
3517    err = vs->offset;
3518out:
3519    complete_pdu(s, vs->pdu, err);
3520    v9fs_string_free(&vs->target);
3521    qemu_free(vs);
3522}
3523
3524static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
3525{
3526    int32_t fid;
3527    V9fsReadLinkState *vs;
3528    int err = 0;
3529    V9fsFidState *fidp;
3530
3531    vs = qemu_malloc(sizeof(*vs));
3532    vs->pdu = pdu;
3533    vs->offset = 7;
3534
3535    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
3536
3537    fidp = lookup_fid(s, fid);
3538    if (fidp == NULL) {
3539        err = -ENOENT;
3540        goto out;
3541    }
3542
3543    v9fs_string_init(&vs->target);
3544    err = v9fs_do_readlink(s, &fidp->path, &vs->target);
3545    v9fs_readlink_post_readlink(s, vs, err);
3546    return;
3547out:
3548    complete_pdu(s, vs->pdu, err);
3549    qemu_free(vs);
3550}
3551
3552typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
3553
3554static pdu_handler_t *pdu_handlers[] = {
3555    [P9_TREADDIR] = v9fs_readdir,
3556    [P9_TSTATFS] = v9fs_statfs,
3557    [P9_TGETATTR] = v9fs_getattr,
3558    [P9_TSETATTR] = v9fs_setattr,
3559    [P9_TXATTRWALK] = v9fs_xattrwalk,
3560    [P9_TXATTRCREATE] = v9fs_xattrcreate,
3561    [P9_TMKNOD] = v9fs_mknod,
3562    [P9_TRENAME] = v9fs_rename,
3563    [P9_TLOCK] = v9fs_lock,
3564    [P9_TGETLOCK] = v9fs_getlock,
3565    [P9_TREADLINK] = v9fs_readlink,
3566    [P9_TMKDIR] = v9fs_mkdir,
3567    [P9_TVERSION] = v9fs_version,
3568    [P9_TLOPEN] = v9fs_open,
3569    [P9_TATTACH] = v9fs_attach,
3570    [P9_TSTAT] = v9fs_stat,
3571    [P9_TWALK] = v9fs_walk,
3572    [P9_TCLUNK] = v9fs_clunk,
3573    [P9_TFSYNC] = v9fs_fsync,
3574    [P9_TOPEN] = v9fs_open,
3575    [P9_TREAD] = v9fs_read,
3576#if 0
3577    [P9_TAUTH] = v9fs_auth,
3578#endif
3579    [P9_TFLUSH] = v9fs_flush,
3580    [P9_TLINK] = v9fs_link,
3581    [P9_TSYMLINK] = v9fs_symlink,
3582    [P9_TCREATE] = v9fs_create,
3583    [P9_TLCREATE] = v9fs_lcreate,
3584    [P9_TWRITE] = v9fs_write,
3585    [P9_TWSTAT] = v9fs_wstat,
3586    [P9_TREMOVE] = v9fs_remove,
3587};
3588
3589static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3590{
3591    pdu_handler_t *handler;
3592
3593    if (debug_9p_pdu) {
3594        pprint_pdu(pdu);
3595    }
3596
3597    BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
3598
3599    handler = pdu_handlers[pdu->id];
3600    BUG_ON(handler == NULL);
3601
3602    handler(s, pdu);
3603}
3604
3605static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3606{
3607    V9fsState *s = (V9fsState *)vdev;
3608    V9fsPDU *pdu;
3609    ssize_t len;
3610
3611    while ((pdu = alloc_pdu(s)) &&
3612            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3613        uint8_t *ptr;
3614
3615        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3616        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3617
3618        ptr = pdu->elem.out_sg[0].iov_base;
3619
3620        memcpy(&pdu->size, ptr, 4);
3621        pdu->id = ptr[4];
3622        memcpy(&pdu->tag, ptr + 5, 2);
3623
3624        submit_pdu(s, pdu);
3625    }
3626
3627    free_pdu(s, pdu);
3628}
3629
3630static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
3631{
3632    features |= 1 << VIRTIO_9P_MOUNT_TAG;
3633    return features;
3634}
3635
3636static V9fsState *to_virtio_9p(VirtIODevice *vdev)
3637{
3638    return (V9fsState *)vdev;
3639}
3640
3641static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
3642{
3643    struct virtio_9p_config *cfg;
3644    V9fsState *s = to_virtio_9p(vdev);
3645
3646    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
3647                        s->tag_len);
3648    stw_raw(&cfg->tag_len, s->tag_len);
3649    memcpy(cfg->tag, s->tag, s->tag_len);
3650    memcpy(config, cfg, s->config_size);
3651    qemu_free(cfg);
3652}
3653
3654VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
3655 {
3656    V9fsState *s;
3657    int i, len;
3658    struct stat stat;
3659    FsTypeEntry *fse;
3660
3661
3662    s = (V9fsState *)virtio_common_init("virtio-9p",
3663                                    VIRTIO_ID_9P,
3664                                    sizeof(struct virtio_9p_config)+
3665                                    MAX_TAG_LEN,
3666                                    sizeof(V9fsState));
3667
3668    /* initialize pdu allocator */
3669    QLIST_INIT(&s->free_list);
3670    for (i = 0; i < (MAX_REQ - 1); i++) {
3671        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
3672    }
3673
3674    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
3675
3676    fse = get_fsdev_fsentry(conf->fsdev_id);
3677
3678    if (!fse) {
3679        /* We don't have a fsdev identified by fsdev_id */
3680        fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
3681                "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
3682        exit(1);
3683    }
3684
3685    if (!fse->path || !conf->tag) {
3686        /* we haven't specified a mount_tag or the path */
3687        fprintf(stderr, "fsdev with id %s needs path "
3688                "and Virtio-9p device needs mount_tag arguments\n",
3689                conf->fsdev_id);
3690        exit(1);
3691    }
3692
3693    if (!strcmp(fse->security_model, "passthrough")) {
3694        /* Files on the Fileserver set to client user credentials */
3695        s->ctx.fs_sm = SM_PASSTHROUGH;
3696        s->ctx.xops = passthrough_xattr_ops;
3697    } else if (!strcmp(fse->security_model, "mapped")) {
3698        /* Files on the fileserver are set to QEMU credentials.
3699         * Client user credentials are saved in extended attributes.
3700         */
3701        s->ctx.fs_sm = SM_MAPPED;
3702        s->ctx.xops = mapped_xattr_ops;
3703    } else if (!strcmp(fse->security_model, "none")) {
3704        /*
3705         * Files on the fileserver are set to QEMU credentials.
3706         */
3707        s->ctx.fs_sm = SM_NONE;
3708        s->ctx.xops = none_xattr_ops;
3709    } else {
3710        fprintf(stderr, "Default to security_model=none. You may want"
3711                " enable advanced security model using "
3712                "security option:\n\t security_model=passthrough \n\t "
3713                "security_model=mapped\n");
3714        s->ctx.fs_sm = SM_NONE;
3715        s->ctx.xops = none_xattr_ops;
3716    }
3717
3718    if (lstat(fse->path, &stat)) {
3719        fprintf(stderr, "share path %s does not exist\n", fse->path);
3720        exit(1);
3721    } else if (!S_ISDIR(stat.st_mode)) {
3722        fprintf(stderr, "share path %s is not a directory \n", fse->path);
3723        exit(1);
3724    }
3725
3726    s->ctx.fs_root = qemu_strdup(fse->path);
3727    len = strlen(conf->tag);
3728    if (len > MAX_TAG_LEN) {
3729        len = MAX_TAG_LEN;
3730    }
3731    /* s->tag is non-NULL terminated string */
3732    s->tag = qemu_malloc(len);
3733    memcpy(s->tag, conf->tag, len);
3734    s->tag_len = len;
3735    s->ctx.uid = -1;
3736
3737    s->ops = fse->ops;
3738    s->vdev.get_features = virtio_9p_get_features;
3739    s->config_size = sizeof(struct virtio_9p_config) +
3740                        s->tag_len;
3741    s->vdev.get_config = virtio_9p_get_config;
3742
3743    return &s->vdev;
3744}
3745