Annotation of qemu/hw/9pfs/virtio-9p.c, revision 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.