Annotation of qemu/hw/9pfs/virtio-9p.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.