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

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: 
1.1.1.2 ! root       14: #include <glib.h>
        !            15: #include <glib/gprintf.h>
        !            16: 
1.1       root       17: #include "hw/virtio.h"
                     18: #include "hw/pc.h"
                     19: #include "qemu_socket.h"
                     20: #include "hw/virtio-pci.h"
                     21: #include "virtio-9p.h"
                     22: #include "fsdev/qemu-fsdev.h"
                     23: #include "virtio-9p-xattr.h"
1.1.1.2 ! root       24: #include "virtio-9p-coth.h"
        !            25: #include "trace.h"
        !            26: #include "migration.h"
        !            27: 
        !            28: int open_fd_hw;
        !            29: int total_open_fd;
        !            30: static int open_fd_rc;
1.1       root       31: 
                     32: enum {
                     33:     Oread   = 0x00,
                     34:     Owrite  = 0x01,
                     35:     Ordwr   = 0x02,
                     36:     Oexec   = 0x03,
                     37:     Oexcl   = 0x04,
                     38:     Otrunc  = 0x10,
                     39:     Orexec  = 0x20,
                     40:     Orclose = 0x40,
                     41:     Oappend = 0x80,
                     42: };
                     43: 
                     44: static int omode_to_uflags(int8_t mode)
                     45: {
                     46:     int ret = 0;
                     47: 
                     48:     switch (mode & 3) {
                     49:     case Oread:
                     50:         ret = O_RDONLY;
                     51:         break;
                     52:     case Ordwr:
                     53:         ret = O_RDWR;
                     54:         break;
                     55:     case Owrite:
                     56:         ret = O_WRONLY;
                     57:         break;
                     58:     case Oexec:
                     59:         ret = O_RDONLY;
                     60:         break;
                     61:     }
                     62: 
                     63:     if (mode & Otrunc) {
                     64:         ret |= O_TRUNC;
                     65:     }
                     66: 
                     67:     if (mode & Oappend) {
                     68:         ret |= O_APPEND;
                     69:     }
                     70: 
                     71:     if (mode & Oexcl) {
                     72:         ret |= O_EXCL;
                     73:     }
                     74: 
                     75:     return ret;
                     76: }
                     77: 
1.1.1.2 ! root       78: struct dotl_openflag_map {
        !            79:     int dotl_flag;
        !            80:     int open_flag;
        !            81: };
1.1       root       82: 
1.1.1.2 ! root       83: static int dotl_to_open_flags(int flags)
1.1       root       84: {
1.1.1.2 ! root       85:     int i;
        !            86:     /*
        !            87:      * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
        !            88:      * and P9_DOTL_NOACCESS
        !            89:      */
        !            90:     int oflags = flags & O_ACCMODE;
1.1       root       91: 
1.1.1.2 ! root       92:     struct dotl_openflag_map dotl_oflag_map[] = {
        !            93:         { P9_DOTL_CREATE, O_CREAT },
        !            94:         { P9_DOTL_EXCL, O_EXCL },
        !            95:         { P9_DOTL_NOCTTY , O_NOCTTY },
        !            96:         { P9_DOTL_TRUNC, O_TRUNC },
        !            97:         { P9_DOTL_APPEND, O_APPEND },
        !            98:         { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
        !            99:         { P9_DOTL_DSYNC, O_DSYNC },
        !           100:         { P9_DOTL_FASYNC, FASYNC },
        !           101:         { P9_DOTL_DIRECT, O_DIRECT },
        !           102:         { P9_DOTL_LARGEFILE, O_LARGEFILE },
        !           103:         { P9_DOTL_DIRECTORY, O_DIRECTORY },
        !           104:         { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
        !           105:         { P9_DOTL_NOATIME, O_NOATIME },
        !           106:         { P9_DOTL_SYNC, O_SYNC },
        !           107:     };
        !           108: 
        !           109:     for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
        !           110:         if (flags & dotl_oflag_map[i].dotl_flag) {
        !           111:             oflags |= dotl_oflag_map[i].open_flag;
        !           112:         }
1.1       root      113:     }
                    114: 
1.1.1.2 ! root      115:     return oflags;
1.1       root      116: }
                    117: 
1.1.1.2 ! root      118: void cred_init(FsCred *credp)
1.1       root      119: {
1.1.1.2 ! root      120:     credp->fc_uid = -1;
        !           121:     credp->fc_gid = -1;
        !           122:     credp->fc_mode = -1;
        !           123:     credp->fc_rdev = -1;
1.1       root      124: }
                    125: 
1.1.1.2 ! root      126: static int get_dotl_openflags(V9fsState *s, int oflags)
1.1       root      127: {
1.1.1.2 ! root      128:     int flags;
        !           129:     /*
        !           130:      * Filter the client open flags
        !           131:      */
        !           132:     flags = dotl_to_open_flags(oflags);
        !           133:     flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
        !           134:     /*
        !           135:      * Ignore direct disk access hint until the server supports it.
        !           136:      */
        !           137:     flags &= ~O_DIRECT;
        !           138:     return flags;
1.1       root      139: }
                    140: 
1.1.1.2 ! root      141: void v9fs_string_init(V9fsString *str)
1.1       root      142: {
                    143:     str->data = NULL;
                    144:     str->size = 0;
                    145: }
                    146: 
1.1.1.2 ! root      147: void v9fs_string_free(V9fsString *str)
1.1       root      148: {
1.1.1.2 ! root      149:     g_free(str->data);
1.1       root      150:     str->data = NULL;
                    151:     str->size = 0;
                    152: }
                    153: 
1.1.1.2 ! root      154: void v9fs_string_null(V9fsString *str)
1.1       root      155: {
                    156:     v9fs_string_free(str);
                    157: }
                    158: 
1.1.1.2 ! root      159: void GCC_FMT_ATTR(2, 3)
        !           160: v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
1.1       root      161: {
1.1.1.2 ! root      162:     va_list ap;
1.1       root      163: 
1.1.1.2 ! root      164:     v9fs_string_free(str);
1.1       root      165: 
1.1.1.2 ! root      166:     va_start(ap, fmt);
        !           167:     str->size = g_vasprintf(&str->data, fmt, ap);
        !           168:     va_end(ap);
1.1       root      169: }
                    170: 
1.1.1.2 ! root      171: void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
1.1       root      172: {
1.1.1.2 ! root      173:     v9fs_string_free(lhs);
        !           174:     v9fs_string_sprintf(lhs, "%s", rhs->data);
1.1       root      175: }
                    176: 
1.1.1.2 ! root      177: void v9fs_path_init(V9fsPath *path)
1.1       root      178: {
1.1.1.2 ! root      179:     path->data = NULL;
        !           180:     path->size = 0;
        !           181: }
1.1       root      182: 
1.1.1.2 ! root      183: void v9fs_path_free(V9fsPath *path)
        !           184: {
        !           185:     g_free(path->data);
        !           186:     path->data = NULL;
        !           187:     path->size = 0;
        !           188: }
1.1       root      189: 
1.1.1.2 ! root      190: void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
        !           191: {
        !           192:     v9fs_path_free(lhs);
        !           193:     lhs->data = g_malloc(rhs->size);
        !           194:     memcpy(lhs->data, rhs->data, rhs->size);
        !           195:     lhs->size = rhs->size;
1.1       root      196: }
                    197: 
1.1.1.2 ! root      198: int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
        !           199:                       const char *name, V9fsPath *path)
1.1       root      200: {
1.1.1.2 ! root      201:     int err;
        !           202:     err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
        !           203:     if (err < 0) {
        !           204:         err = -errno;
        !           205:     }
        !           206:     return err;
1.1       root      207: }
                    208: 
                    209: /*
                    210:  * Return TRUE if s1 is an ancestor of s2.
                    211:  *
                    212:  * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
                    213:  * As a special case, We treat s1 as ancestor of s2 if they are same!
                    214:  */
1.1.1.2 ! root      215: static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
1.1       root      216: {
1.1.1.2 ! root      217:     if (!strncmp(s1->data, s2->data, s1->size - 1)) {
        !           218:         if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
1.1       root      219:             return 1;
                    220:         }
                    221:     }
                    222:     return 0;
                    223: }
                    224: 
                    225: static size_t v9fs_string_size(V9fsString *str)
                    226: {
                    227:     return str->size;
                    228: }
                    229: 
1.1.1.2 ! root      230: /*
        !           231:  * returns 0 if fid got re-opened, 1 if not, < 0 on error */
        !           232: static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
        !           233: {
        !           234:     int err = 1;
        !           235:     if (f->fid_type == P9_FID_FILE) {
        !           236:         if (f->fs.fd == -1) {
        !           237:             do {
        !           238:                 err = v9fs_co_open(pdu, f, f->open_flags);
        !           239:             } while (err == -EINTR && !pdu->cancelled);
        !           240:         }
        !           241:     } else if (f->fid_type == P9_FID_DIR) {
        !           242:         if (f->fs.dir == NULL) {
        !           243:             do {
        !           244:                 err = v9fs_co_opendir(pdu, f);
        !           245:             } while (err == -EINTR && !pdu->cancelled);
        !           246:         }
        !           247:     }
        !           248:     return err;
        !           249: }
        !           250: 
        !           251: static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
1.1       root      252: {
1.1.1.2 ! root      253:     int err;
1.1       root      254:     V9fsFidState *f;
1.1.1.2 ! root      255:     V9fsState *s = pdu->s;
1.1       root      256: 
                    257:     for (f = s->fid_list; f; f = f->next) {
1.1.1.2 ! root      258:         BUG_ON(f->clunked);
1.1       root      259:         if (f->fid == fid) {
1.1.1.2 ! root      260:             /*
        !           261:              * Update the fid ref upfront so that
        !           262:              * we don't get reclaimed when we yield
        !           263:              * in open later.
        !           264:              */
        !           265:             f->ref++;
        !           266:             /*
        !           267:              * check whether we need to reopen the
        !           268:              * file. We might have closed the fd
        !           269:              * while trying to free up some file
        !           270:              * descriptors.
        !           271:              */
        !           272:             err = v9fs_reopen_fid(pdu, f);
        !           273:             if (err < 0) {
        !           274:                 f->ref--;
        !           275:                 return NULL;
        !           276:             }
        !           277:             /*
        !           278:              * Mark the fid as referenced so that the LRU
        !           279:              * reclaim won't close the file descriptor
        !           280:              */
        !           281:             f->flags |= FID_REFERENCED;
1.1       root      282:             return f;
                    283:         }
                    284:     }
                    285:     return NULL;
                    286: }
                    287: 
                    288: static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
                    289: {
                    290:     V9fsFidState *f;
                    291: 
1.1.1.2 ! root      292:     for (f = s->fid_list; f; f = f->next) {
        !           293:         /* If fid is already there return NULL */
        !           294:         BUG_ON(f->clunked);
        !           295:         if (f->fid == fid) {
        !           296:             return NULL;
        !           297:         }
1.1       root      298:     }
1.1.1.2 ! root      299:     f = g_malloc0(sizeof(V9fsFidState));
1.1       root      300:     f->fid = fid;
                    301:     f->fid_type = P9_FID_NONE;
1.1.1.2 ! root      302:     f->ref = 1;
        !           303:     /*
        !           304:      * Mark the fid as referenced so that the LRU
        !           305:      * reclaim won't close the file descriptor
        !           306:      */
        !           307:     f->flags |= FID_REFERENCED;
1.1       root      308:     f->next = s->fid_list;
                    309:     s->fid_list = f;
                    310: 
                    311:     return f;
                    312: }
                    313: 
1.1.1.2 ! root      314: static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
1.1       root      315: {
                    316:     int retval = 0;
                    317: 
                    318:     if (fidp->fs.xattr.copied_len == -1) {
                    319:         /* getxattr/listxattr fid */
                    320:         goto free_value;
                    321:     }
                    322:     /*
                    323:      * if this is fid for setxattr. clunk should
                    324:      * result in setxattr localcall
                    325:      */
                    326:     if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
                    327:         /* clunk after partial write */
                    328:         retval = -EINVAL;
                    329:         goto free_out;
                    330:     }
                    331:     if (fidp->fs.xattr.len) {
1.1.1.2 ! root      332:         retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
1.1       root      333:                                    fidp->fs.xattr.value,
                    334:                                    fidp->fs.xattr.len,
                    335:                                    fidp->fs.xattr.flags);
                    336:     } else {
1.1.1.2 ! root      337:         retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
1.1       root      338:     }
                    339: free_out:
                    340:     v9fs_string_free(&fidp->fs.xattr.name);
                    341: free_value:
                    342:     if (fidp->fs.xattr.value) {
1.1.1.2 ! root      343:         g_free(fidp->fs.xattr.value);
1.1       root      344:     }
                    345:     return retval;
                    346: }
                    347: 
1.1.1.2 ! root      348: static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
1.1       root      349: {
                    350:     int retval = 0;
1.1.1.2 ! root      351: 
        !           352:     if (fidp->fid_type == P9_FID_FILE) {
        !           353:         /* If we reclaimed the fd no need to close */
        !           354:         if (fidp->fs.fd != -1) {
        !           355:             retval = v9fs_co_close(pdu, &fidp->fs);
        !           356:         }
        !           357:     } else if (fidp->fid_type == P9_FID_DIR) {
        !           358:         if (fidp->fs.dir != NULL) {
        !           359:             retval = v9fs_co_closedir(pdu, &fidp->fs);
        !           360:         }
        !           361:     } else if (fidp->fid_type == P9_FID_XATTR) {
        !           362:         retval = v9fs_xattr_fid_clunk(pdu, fidp);
        !           363:     }
        !           364:     v9fs_path_free(&fidp->path);
        !           365:     g_free(fidp);
        !           366:     return retval;
        !           367: }
        !           368: 
        !           369: static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
        !           370: {
        !           371:     BUG_ON(!fidp->ref);
        !           372:     fidp->ref--;
        !           373:     /*
        !           374:      * Don't free the fid if it is in reclaim list
        !           375:      */
        !           376:     if (!fidp->ref && fidp->clunked) {
        !           377:         if (fidp->fid == pdu->s->root_fid) {
        !           378:             /*
        !           379:              * if the clunked fid is root fid then we
        !           380:              * have unmounted the fs on the client side.
        !           381:              * delete the migration blocker. Ideally, this
        !           382:              * should be hooked to transport close notification
        !           383:              */
        !           384:             if (pdu->s->migration_blocker) {
        !           385:                 migrate_del_blocker(pdu->s->migration_blocker);
        !           386:                 error_free(pdu->s->migration_blocker);
        !           387:                 pdu->s->migration_blocker = NULL;
        !           388:             }
        !           389:         }
        !           390:         free_fid(pdu, fidp);
        !           391:     }
        !           392: }
        !           393: 
        !           394: static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
        !           395: {
1.1       root      396:     V9fsFidState **fidpp, *fidp;
                    397: 
                    398:     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
                    399:         if ((*fidpp)->fid == fid) {
                    400:             break;
                    401:         }
                    402:     }
                    403:     if (*fidpp == NULL) {
1.1.1.2 ! root      404:         return NULL;
1.1       root      405:     }
                    406:     fidp = *fidpp;
                    407:     *fidpp = fidp->next;
1.1.1.2 ! root      408:     fidp->clunked = 1;
        !           409:     return fidp;
        !           410: }
1.1       root      411: 
1.1.1.2 ! root      412: void v9fs_reclaim_fd(V9fsPDU *pdu)
        !           413: {
        !           414:     int reclaim_count = 0;
        !           415:     V9fsState *s = pdu->s;
        !           416:     V9fsFidState *f, *reclaim_list = NULL;
1.1       root      417: 
1.1.1.2 ! root      418:     for (f = s->fid_list; f; f = f->next) {
        !           419:         /*
        !           420:          * Unlink fids cannot be reclaimed. Check
        !           421:          * for them and skip them. Also skip fids
        !           422:          * currently being operated on.
        !           423:          */
        !           424:         if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
        !           425:             continue;
        !           426:         }
        !           427:         /*
        !           428:          * if it is a recently referenced fid
        !           429:          * we leave the fid untouched and clear the
        !           430:          * reference bit. We come back to it later
        !           431:          * in the next iteration. (a simple LRU without
        !           432:          * moving list elements around)
        !           433:          */
        !           434:         if (f->flags & FID_REFERENCED) {
        !           435:             f->flags &= ~FID_REFERENCED;
        !           436:             continue;
        !           437:         }
        !           438:         /*
        !           439:          * Add fids to reclaim list.
        !           440:          */
        !           441:         if (f->fid_type == P9_FID_FILE) {
        !           442:             if (f->fs.fd != -1) {
        !           443:                 /*
        !           444:                  * Up the reference count so that
        !           445:                  * a clunk request won't free this fid
        !           446:                  */
        !           447:                 f->ref++;
        !           448:                 f->rclm_lst = reclaim_list;
        !           449:                 reclaim_list = f;
        !           450:                 f->fs_reclaim.fd = f->fs.fd;
        !           451:                 f->fs.fd = -1;
        !           452:                 reclaim_count++;
        !           453:             }
        !           454:         } else if (f->fid_type == P9_FID_DIR) {
        !           455:             if (f->fs.dir != NULL) {
        !           456:                 /*
        !           457:                  * Up the reference count so that
        !           458:                  * a clunk request won't free this fid
        !           459:                  */
        !           460:                 f->ref++;
        !           461:                 f->rclm_lst = reclaim_list;
        !           462:                 reclaim_list = f;
        !           463:                 f->fs_reclaim.dir = f->fs.dir;
        !           464:                 f->fs.dir = NULL;
        !           465:                 reclaim_count++;
        !           466:             }
        !           467:         }
        !           468:         if (reclaim_count >= open_fd_rc) {
        !           469:             break;
        !           470:         }
        !           471:     }
        !           472:     /*
        !           473:      * Now close the fid in reclaim list. Free them if they
        !           474:      * are already clunked.
        !           475:      */
        !           476:     while (reclaim_list) {
        !           477:         f = reclaim_list;
        !           478:         reclaim_list = f->rclm_lst;
        !           479:         if (f->fid_type == P9_FID_FILE) {
        !           480:             v9fs_co_close(pdu, &f->fs_reclaim);
        !           481:         } else if (f->fid_type == P9_FID_DIR) {
        !           482:             v9fs_co_closedir(pdu, &f->fs_reclaim);
        !           483:         }
        !           484:         f->rclm_lst = NULL;
        !           485:         /*
        !           486:          * Now drop the fid reference, free it
        !           487:          * if clunked.
        !           488:          */
        !           489:         put_fid(pdu, f);
        !           490:     }
1.1       root      491: }
                    492: 
1.1.1.2 ! root      493: static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
        !           494: {
        !           495:     int err;
        !           496:     V9fsState *s = pdu->s;
        !           497:     V9fsFidState *fidp, head_fid;
1.1       root      498: 
1.1.1.2 ! root      499:     head_fid.next = s->fid_list;
        !           500:     for (fidp = s->fid_list; fidp; fidp = fidp->next) {
        !           501:         if (fidp->path.size != path->size) {
        !           502:             continue;
        !           503:         }
        !           504:         if (!memcmp(fidp->path.data, path->data, path->size)) {
        !           505:             /* Mark the fid non reclaimable. */
        !           506:             fidp->flags |= FID_NON_RECLAIMABLE;
        !           507: 
        !           508:             /* reopen the file/dir if already closed */
        !           509:             err = v9fs_reopen_fid(pdu, fidp);
        !           510:             if (err < 0) {
        !           511:                 return -1;
        !           512:             }
        !           513:             /*
        !           514:              * Go back to head of fid list because
        !           515:              * the list could have got updated when
        !           516:              * switched to the worker thread
        !           517:              */
        !           518:             if (err == 0) {
        !           519:                 fidp = &head_fid;
        !           520:             }
        !           521:         }
        !           522:     }
        !           523:     return 0;
        !           524: }
        !           525: 
        !           526: static void virtfs_reset(V9fsPDU *pdu)
        !           527: {
        !           528:     V9fsState *s = pdu->s;
        !           529:     V9fsFidState *fidp = NULL;
        !           530: 
        !           531:     /* Free all fids */
        !           532:     while (s->fid_list) {
        !           533:         fidp = s->fid_list;
        !           534:         s->fid_list = fidp->next;
        !           535: 
        !           536:         if (fidp->ref) {
        !           537:             fidp->clunked = 1;
        !           538:         } else {
        !           539:             free_fid(pdu, fidp);
        !           540:         }
        !           541:     }
        !           542:     if (fidp) {
        !           543:         /* One or more unclunked fids found... */
        !           544:         error_report("9pfs:%s: One or more uncluncked fids "
        !           545:                      "found during reset", __func__);
        !           546:     }
        !           547:     return;
        !           548: }
        !           549: 
        !           550: #define P9_QID_TYPE_DIR         0x80
        !           551: #define P9_QID_TYPE_SYMLINK     0x02
        !           552: 
        !           553: #define P9_STAT_MODE_DIR        0x80000000
        !           554: #define P9_STAT_MODE_APPEND     0x40000000
        !           555: #define P9_STAT_MODE_EXCL       0x20000000
        !           556: #define P9_STAT_MODE_MOUNT      0x10000000
        !           557: #define P9_STAT_MODE_AUTH       0x08000000
        !           558: #define P9_STAT_MODE_TMP        0x04000000
1.1       root      559: #define P9_STAT_MODE_SYMLINK    0x02000000
                    560: #define P9_STAT_MODE_LINK       0x01000000
                    561: #define P9_STAT_MODE_DEVICE     0x00800000
                    562: #define P9_STAT_MODE_NAMED_PIPE 0x00200000
                    563: #define P9_STAT_MODE_SOCKET     0x00100000
                    564: #define P9_STAT_MODE_SETUID     0x00080000
                    565: #define P9_STAT_MODE_SETGID     0x00040000
                    566: #define P9_STAT_MODE_SETVTX     0x00010000
                    567: 
                    568: #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
                    569:                                 P9_STAT_MODE_SYMLINK |      \
                    570:                                 P9_STAT_MODE_LINK |         \
                    571:                                 P9_STAT_MODE_DEVICE |       \
                    572:                                 P9_STAT_MODE_NAMED_PIPE |   \
                    573:                                 P9_STAT_MODE_SOCKET)
                    574: 
                    575: /* This is the algorithm from ufs in spfs */
                    576: static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
                    577: {
                    578:     size_t size;
                    579: 
1.1.1.2 ! root      580:     memset(&qidp->path, 0, sizeof(qidp->path));
1.1       root      581:     size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
                    582:     memcpy(&qidp->path, &stbuf->st_ino, size);
                    583:     qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
                    584:     qidp->type = 0;
                    585:     if (S_ISDIR(stbuf->st_mode)) {
                    586:         qidp->type |= P9_QID_TYPE_DIR;
                    587:     }
                    588:     if (S_ISLNK(stbuf->st_mode)) {
                    589:         qidp->type |= P9_QID_TYPE_SYMLINK;
                    590:     }
                    591: }
                    592: 
1.1.1.2 ! root      593: static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
1.1       root      594: {
                    595:     struct stat stbuf;
                    596:     int err;
                    597: 
1.1.1.2 ! root      598:     err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !           599:     if (err < 0) {
1.1       root      600:         return err;
                    601:     }
                    602:     stat_to_qid(&stbuf, qidp);
                    603:     return 0;
                    604: }
                    605: 
                    606: static V9fsPDU *alloc_pdu(V9fsState *s)
                    607: {
                    608:     V9fsPDU *pdu = NULL;
                    609: 
                    610:     if (!QLIST_EMPTY(&s->free_list)) {
1.1.1.2 ! root      611:         pdu = QLIST_FIRST(&s->free_list);
        !           612:         QLIST_REMOVE(pdu, next);
        !           613:         QLIST_INSERT_HEAD(&s->active_list, pdu, next);
1.1       root      614:     }
                    615:     return pdu;
                    616: }
                    617: 
                    618: static void free_pdu(V9fsState *s, V9fsPDU *pdu)
                    619: {
                    620:     if (pdu) {
1.1.1.2 ! root      621:         /*
        !           622:          * Cancelled pdu are added back to the freelist
        !           623:          * by flush request .
        !           624:          */
        !           625:         if (!pdu->cancelled) {
        !           626:             QLIST_REMOVE(pdu, next);
        !           627:             QLIST_INSERT_HEAD(&s->free_list, pdu, next);
1.1       root      628:         }
                    629:     }
                    630: }
                    631: 
                    632: size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                    633:                         size_t offset, size_t size, int pack)
                    634: {
                    635:     int i = 0;
                    636:     size_t copied = 0;
                    637: 
                    638:     for (i = 0; size && i < sg_count; i++) {
                    639:         size_t len;
                    640:         if (offset >= sg[i].iov_len) {
                    641:             /* skip this sg */
                    642:             offset -= sg[i].iov_len;
                    643:             continue;
                    644:         } else {
                    645:             len = MIN(sg[i].iov_len - offset, size);
                    646:             if (pack) {
                    647:                 memcpy(sg[i].iov_base + offset, addr, len);
                    648:             } else {
                    649:                 memcpy(addr, sg[i].iov_base + offset, len);
                    650:             }
                    651:             size -= len;
                    652:             copied += len;
                    653:             addr += len;
                    654:             if (size) {
                    655:                 offset = 0;
                    656:                 continue;
                    657:             }
                    658:         }
                    659:     }
                    660: 
                    661:     return copied;
                    662: }
                    663: 
                    664: static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
                    665: {
                    666:     return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
                    667:                          offset, size, 0);
                    668: }
                    669: 
                    670: static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
                    671:                         size_t size)
                    672: {
                    673:     return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
                    674:                              offset, size, 1);
                    675: }
                    676: 
                    677: static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    678: {
                    679:     size_t old_offset = offset;
                    680:     va_list ap;
                    681:     int i;
                    682: 
                    683:     va_start(ap, fmt);
                    684:     for (i = 0; fmt[i]; i++) {
                    685:         switch (fmt[i]) {
                    686:         case 'b': {
                    687:             uint8_t *valp = va_arg(ap, uint8_t *);
                    688:             offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
                    689:             break;
                    690:         }
                    691:         case 'w': {
                    692:             uint16_t val, *valp;
                    693:             valp = va_arg(ap, uint16_t *);
                    694:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    695:             *valp = le16_to_cpu(val);
                    696:             break;
                    697:         }
                    698:         case 'd': {
                    699:             uint32_t val, *valp;
                    700:             valp = va_arg(ap, uint32_t *);
                    701:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    702:             *valp = le32_to_cpu(val);
                    703:             break;
                    704:         }
                    705:         case 'q': {
                    706:             uint64_t val, *valp;
                    707:             valp = va_arg(ap, uint64_t *);
                    708:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    709:             *valp = le64_to_cpu(val);
                    710:             break;
                    711:         }
                    712:         case 's': {
                    713:             V9fsString *str = va_arg(ap, V9fsString *);
                    714:             offset += pdu_unmarshal(pdu, offset, "w", &str->size);
                    715:             /* FIXME: sanity check str->size */
1.1.1.2 ! root      716:             str->data = g_malloc(str->size + 1);
1.1       root      717:             offset += pdu_unpack(str->data, pdu, offset, str->size);
                    718:             str->data[str->size] = 0;
                    719:             break;
                    720:         }
                    721:         case 'Q': {
                    722:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    723:             offset += pdu_unmarshal(pdu, offset, "bdq",
                    724:                         &qidp->type, &qidp->version, &qidp->path);
                    725:             break;
                    726:         }
                    727:         case 'S': {
                    728:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    729:             offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
                    730:                         &statp->size, &statp->type, &statp->dev,
                    731:                         &statp->qid, &statp->mode, &statp->atime,
                    732:                         &statp->mtime, &statp->length,
                    733:                         &statp->name, &statp->uid, &statp->gid,
                    734:                         &statp->muid, &statp->extension,
                    735:                         &statp->n_uid, &statp->n_gid,
                    736:                         &statp->n_muid);
                    737:             break;
                    738:         }
                    739:         case 'I': {
                    740:             V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
                    741:             offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
                    742:                         &iattr->valid, &iattr->mode,
                    743:                         &iattr->uid, &iattr->gid, &iattr->size,
                    744:                         &iattr->atime_sec, &iattr->atime_nsec,
                    745:                         &iattr->mtime_sec, &iattr->mtime_nsec);
                    746:             break;
                    747:         }
                    748:         default:
                    749:             break;
                    750:         }
                    751:     }
                    752: 
                    753:     va_end(ap);
                    754: 
                    755:     return offset - old_offset;
                    756: }
                    757: 
                    758: static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    759: {
                    760:     size_t old_offset = offset;
                    761:     va_list ap;
                    762:     int i;
                    763: 
                    764:     va_start(ap, fmt);
                    765:     for (i = 0; fmt[i]; i++) {
                    766:         switch (fmt[i]) {
                    767:         case 'b': {
                    768:             uint8_t val = va_arg(ap, int);
                    769:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    770:             break;
                    771:         }
                    772:         case 'w': {
                    773:             uint16_t val;
                    774:             cpu_to_le16w(&val, va_arg(ap, int));
                    775:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    776:             break;
                    777:         }
                    778:         case 'd': {
                    779:             uint32_t val;
                    780:             cpu_to_le32w(&val, va_arg(ap, uint32_t));
                    781:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    782:             break;
                    783:         }
                    784:         case 'q': {
                    785:             uint64_t val;
                    786:             cpu_to_le64w(&val, va_arg(ap, uint64_t));
                    787:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    788:             break;
                    789:         }
                    790:         case 's': {
                    791:             V9fsString *str = va_arg(ap, V9fsString *);
                    792:             offset += pdu_marshal(pdu, offset, "w", str->size);
                    793:             offset += pdu_pack(pdu, offset, str->data, str->size);
                    794:             break;
                    795:         }
                    796:         case 'Q': {
                    797:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    798:             offset += pdu_marshal(pdu, offset, "bdq",
                    799:                         qidp->type, qidp->version, qidp->path);
                    800:             break;
                    801:         }
                    802:         case 'S': {
                    803:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    804:             offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
                    805:                         statp->size, statp->type, statp->dev,
                    806:                         &statp->qid, statp->mode, statp->atime,
                    807:                         statp->mtime, statp->length, &statp->name,
                    808:                         &statp->uid, &statp->gid, &statp->muid,
                    809:                         &statp->extension, statp->n_uid,
                    810:                         statp->n_gid, statp->n_muid);
                    811:             break;
                    812:         }
                    813:         case 'A': {
                    814:             V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
                    815:             offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
                    816:                         statp->st_result_mask,
                    817:                         &statp->qid, statp->st_mode,
                    818:                         statp->st_uid, statp->st_gid,
                    819:                         statp->st_nlink, statp->st_rdev,
                    820:                         statp->st_size, statp->st_blksize, statp->st_blocks,
                    821:                         statp->st_atime_sec, statp->st_atime_nsec,
                    822:                         statp->st_mtime_sec, statp->st_mtime_nsec,
                    823:                         statp->st_ctime_sec, statp->st_ctime_nsec,
                    824:                         statp->st_btime_sec, statp->st_btime_nsec,
                    825:                         statp->st_gen, statp->st_data_version);
                    826:             break;
                    827:         }
                    828:         default:
                    829:             break;
                    830:         }
                    831:     }
                    832:     va_end(ap);
                    833: 
                    834:     return offset - old_offset;
                    835: }
                    836: 
                    837: static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
                    838: {
                    839:     int8_t id = pdu->id + 1; /* Response */
                    840: 
                    841:     if (len < 0) {
                    842:         int err = -len;
                    843:         len = 7;
                    844: 
                    845:         if (s->proto_version != V9FS_PROTO_2000L) {
                    846:             V9fsString str;
                    847: 
                    848:             str.data = strerror(err);
                    849:             str.size = strlen(str.data);
                    850: 
                    851:             len += pdu_marshal(pdu, len, "s", &str);
                    852:             id = P9_RERROR;
                    853:         }
                    854: 
                    855:         len += pdu_marshal(pdu, len, "d", err);
                    856: 
                    857:         if (s->proto_version == V9FS_PROTO_2000L) {
                    858:             id = P9_RLERROR;
                    859:         }
1.1.1.2 ! root      860:         trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
1.1       root      861:     }
                    862: 
                    863:     /* fill out the header */
                    864:     pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
                    865: 
                    866:     /* keep these in sync */
                    867:     pdu->size = len;
                    868:     pdu->id = id;
                    869: 
                    870:     /* push onto queue and notify */
                    871:     virtqueue_push(s->vq, &pdu->elem, len);
                    872: 
                    873:     /* FIXME: we should batch these completions */
                    874:     virtio_notify(&s->vdev, s->vq);
                    875: 
1.1.1.2 ! root      876:     /* Now wakeup anybody waiting in flush for this request */
        !           877:     qemu_co_queue_next(&pdu->complete);
        !           878: 
1.1       root      879:     free_pdu(s, pdu);
                    880: }
                    881: 
                    882: static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
                    883: {
                    884:     mode_t ret;
                    885: 
                    886:     ret = mode & 0777;
                    887:     if (mode & P9_STAT_MODE_DIR) {
                    888:         ret |= S_IFDIR;
                    889:     }
                    890: 
                    891:     if (mode & P9_STAT_MODE_SYMLINK) {
                    892:         ret |= S_IFLNK;
                    893:     }
                    894:     if (mode & P9_STAT_MODE_SOCKET) {
                    895:         ret |= S_IFSOCK;
                    896:     }
                    897:     if (mode & P9_STAT_MODE_NAMED_PIPE) {
                    898:         ret |= S_IFIFO;
                    899:     }
                    900:     if (mode & P9_STAT_MODE_DEVICE) {
                    901:         if (extension && extension->data[0] == 'c') {
                    902:             ret |= S_IFCHR;
                    903:         } else {
                    904:             ret |= S_IFBLK;
                    905:         }
                    906:     }
                    907: 
                    908:     if (!(ret&~0777)) {
                    909:         ret |= S_IFREG;
                    910:     }
                    911: 
                    912:     if (mode & P9_STAT_MODE_SETUID) {
                    913:         ret |= S_ISUID;
                    914:     }
                    915:     if (mode & P9_STAT_MODE_SETGID) {
                    916:         ret |= S_ISGID;
                    917:     }
                    918:     if (mode & P9_STAT_MODE_SETVTX) {
                    919:         ret |= S_ISVTX;
                    920:     }
                    921: 
                    922:     return ret;
                    923: }
                    924: 
                    925: static int donttouch_stat(V9fsStat *stat)
                    926: {
                    927:     if (stat->type == -1 &&
                    928:         stat->dev == -1 &&
                    929:         stat->qid.type == -1 &&
                    930:         stat->qid.version == -1 &&
                    931:         stat->qid.path == -1 &&
                    932:         stat->mode == -1 &&
                    933:         stat->atime == -1 &&
                    934:         stat->mtime == -1 &&
                    935:         stat->length == -1 &&
                    936:         !stat->name.size &&
                    937:         !stat->uid.size &&
                    938:         !stat->gid.size &&
                    939:         !stat->muid.size &&
                    940:         stat->n_uid == -1 &&
                    941:         stat->n_gid == -1 &&
                    942:         stat->n_muid == -1) {
                    943:         return 1;
                    944:     }
                    945: 
                    946:     return 0;
                    947: }
                    948: 
                    949: static void v9fs_stat_free(V9fsStat *stat)
                    950: {
                    951:     v9fs_string_free(&stat->name);
                    952:     v9fs_string_free(&stat->uid);
                    953:     v9fs_string_free(&stat->gid);
                    954:     v9fs_string_free(&stat->muid);
                    955:     v9fs_string_free(&stat->extension);
                    956: }
                    957: 
                    958: static uint32_t stat_to_v9mode(const struct stat *stbuf)
                    959: {
                    960:     uint32_t mode;
                    961: 
                    962:     mode = stbuf->st_mode & 0777;
                    963:     if (S_ISDIR(stbuf->st_mode)) {
                    964:         mode |= P9_STAT_MODE_DIR;
                    965:     }
                    966: 
                    967:     if (S_ISLNK(stbuf->st_mode)) {
                    968:         mode |= P9_STAT_MODE_SYMLINK;
                    969:     }
                    970: 
                    971:     if (S_ISSOCK(stbuf->st_mode)) {
                    972:         mode |= P9_STAT_MODE_SOCKET;
                    973:     }
                    974: 
                    975:     if (S_ISFIFO(stbuf->st_mode)) {
                    976:         mode |= P9_STAT_MODE_NAMED_PIPE;
                    977:     }
                    978: 
                    979:     if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
                    980:         mode |= P9_STAT_MODE_DEVICE;
                    981:     }
                    982: 
                    983:     if (stbuf->st_mode & S_ISUID) {
                    984:         mode |= P9_STAT_MODE_SETUID;
                    985:     }
                    986: 
                    987:     if (stbuf->st_mode & S_ISGID) {
                    988:         mode |= P9_STAT_MODE_SETGID;
                    989:     }
                    990: 
                    991:     if (stbuf->st_mode & S_ISVTX) {
                    992:         mode |= P9_STAT_MODE_SETVTX;
                    993:     }
                    994: 
                    995:     return mode;
                    996: }
                    997: 
1.1.1.2 ! root      998: static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
1.1       root      999:                             const struct stat *stbuf,
                   1000:                             V9fsStat *v9stat)
                   1001: {
                   1002:     int err;
                   1003:     const char *str;
                   1004: 
                   1005:     memset(v9stat, 0, sizeof(*v9stat));
                   1006: 
                   1007:     stat_to_qid(stbuf, &v9stat->qid);
                   1008:     v9stat->mode = stat_to_v9mode(stbuf);
                   1009:     v9stat->atime = stbuf->st_atime;
                   1010:     v9stat->mtime = stbuf->st_mtime;
                   1011:     v9stat->length = stbuf->st_size;
                   1012: 
                   1013:     v9fs_string_null(&v9stat->uid);
                   1014:     v9fs_string_null(&v9stat->gid);
                   1015:     v9fs_string_null(&v9stat->muid);
                   1016: 
                   1017:     v9stat->n_uid = stbuf->st_uid;
                   1018:     v9stat->n_gid = stbuf->st_gid;
                   1019:     v9stat->n_muid = 0;
                   1020: 
                   1021:     v9fs_string_null(&v9stat->extension);
                   1022: 
                   1023:     if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1.1.1.2 ! root     1024:         err = v9fs_co_readlink(pdu, name, &v9stat->extension);
        !          1025:         if (err < 0) {
1.1       root     1026:             return err;
                   1027:         }
                   1028:     } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
                   1029:         v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
                   1030:                 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
                   1031:                 major(stbuf->st_rdev), minor(stbuf->st_rdev));
                   1032:     } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
                   1033:         v9fs_string_sprintf(&v9stat->extension, "%s %lu",
                   1034:                 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
                   1035:     }
                   1036: 
                   1037:     str = strrchr(name->data, '/');
                   1038:     if (str) {
                   1039:         str += 1;
                   1040:     } else {
                   1041:         str = name->data;
                   1042:     }
                   1043: 
                   1044:     v9fs_string_sprintf(&v9stat->name, "%s", str);
                   1045: 
                   1046:     v9stat->size = 61 +
                   1047:         v9fs_string_size(&v9stat->name) +
                   1048:         v9fs_string_size(&v9stat->uid) +
                   1049:         v9fs_string_size(&v9stat->gid) +
                   1050:         v9fs_string_size(&v9stat->muid) +
                   1051:         v9fs_string_size(&v9stat->extension);
                   1052:     return 0;
                   1053: }
                   1054: 
                   1055: #define P9_STATS_MODE          0x00000001ULL
                   1056: #define P9_STATS_NLINK         0x00000002ULL
                   1057: #define P9_STATS_UID           0x00000004ULL
                   1058: #define P9_STATS_GID           0x00000008ULL
                   1059: #define P9_STATS_RDEV          0x00000010ULL
                   1060: #define P9_STATS_ATIME         0x00000020ULL
                   1061: #define P9_STATS_MTIME         0x00000040ULL
                   1062: #define P9_STATS_CTIME         0x00000080ULL
                   1063: #define P9_STATS_INO           0x00000100ULL
                   1064: #define P9_STATS_SIZE          0x00000200ULL
                   1065: #define P9_STATS_BLOCKS        0x00000400ULL
                   1066: 
                   1067: #define P9_STATS_BTIME         0x00000800ULL
                   1068: #define P9_STATS_GEN           0x00001000ULL
                   1069: #define P9_STATS_DATA_VERSION  0x00002000ULL
                   1070: 
                   1071: #define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
                   1072: #define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
                   1073: 
                   1074: 
                   1075: static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1.1.1.2 ! root     1076:                                 V9fsStatDotl *v9lstat)
1.1       root     1077: {
                   1078:     memset(v9lstat, 0, sizeof(*v9lstat));
                   1079: 
                   1080:     v9lstat->st_mode = stbuf->st_mode;
                   1081:     v9lstat->st_nlink = stbuf->st_nlink;
                   1082:     v9lstat->st_uid = stbuf->st_uid;
                   1083:     v9lstat->st_gid = stbuf->st_gid;
                   1084:     v9lstat->st_rdev = stbuf->st_rdev;
                   1085:     v9lstat->st_size = stbuf->st_size;
                   1086:     v9lstat->st_blksize = stbuf->st_blksize;
                   1087:     v9lstat->st_blocks = stbuf->st_blocks;
                   1088:     v9lstat->st_atime_sec = stbuf->st_atime;
                   1089:     v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
                   1090:     v9lstat->st_mtime_sec = stbuf->st_mtime;
                   1091:     v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
                   1092:     v9lstat->st_ctime_sec = stbuf->st_ctime;
                   1093:     v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
                   1094:     /* Currently we only support BASIC fields in stat */
                   1095:     v9lstat->st_result_mask = P9_STATS_BASIC;
                   1096: 
                   1097:     stat_to_qid(stbuf, &v9lstat->qid);
                   1098: }
                   1099: 
                   1100: static void print_sg(struct iovec *sg, int cnt)
                   1101: {
                   1102:     int i;
                   1103: 
                   1104:     printf("sg[%d]: {", cnt);
                   1105:     for (i = 0; i < cnt; i++) {
                   1106:         if (i) {
                   1107:             printf(", ");
                   1108:         }
                   1109:         printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
                   1110:     }
                   1111:     printf("}\n");
                   1112: }
                   1113: 
1.1.1.2 ! root     1114: /* Will call this only for path name based fid */
        !          1115: static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
        !          1116: {
        !          1117:     V9fsPath str;
        !          1118:     v9fs_path_init(&str);
        !          1119:     v9fs_path_copy(&str, dst);
        !          1120:     v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
        !          1121:     v9fs_path_free(&str);
        !          1122:     /* +1 to include terminating NULL */
        !          1123:     dst->size++;
        !          1124: }
        !          1125: 
        !          1126: static inline bool is_ro_export(FsContext *ctx)
1.1       root     1127: {
1.1.1.2 ! root     1128:     return ctx->export_flags & V9FS_RDONLY;
1.1       root     1129: }
                   1130: 
1.1.1.2 ! root     1131: static void v9fs_version(void *opaque)
1.1       root     1132: {
1.1.1.2 ! root     1133:     V9fsPDU *pdu = opaque;
        !          1134:     V9fsState *s = pdu->s;
1.1       root     1135:     V9fsString version;
                   1136:     size_t offset = 7;
                   1137: 
                   1138:     pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1.1.1.2 ! root     1139:     trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
        !          1140: 
        !          1141:     virtfs_reset(pdu);
1.1       root     1142: 
                   1143:     if (!strcmp(version.data, "9P2000.u")) {
                   1144:         s->proto_version = V9FS_PROTO_2000U;
                   1145:     } else if (!strcmp(version.data, "9P2000.L")) {
                   1146:         s->proto_version = V9FS_PROTO_2000L;
                   1147:     } else {
                   1148:         v9fs_string_sprintf(&version, "unknown");
                   1149:     }
                   1150: 
                   1151:     offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1.1.1.2 ! root     1152:     trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
        !          1153: 
1.1       root     1154:     complete_pdu(s, pdu, offset);
                   1155: 
                   1156:     v9fs_string_free(&version);
1.1.1.2 ! root     1157:     return;
1.1       root     1158: }
                   1159: 
1.1.1.2 ! root     1160: static void v9fs_attach(void *opaque)
1.1       root     1161: {
1.1.1.2 ! root     1162:     V9fsPDU *pdu = opaque;
        !          1163:     V9fsState *s = pdu->s;
1.1       root     1164:     int32_t fid, afid, n_uname;
                   1165:     V9fsString uname, aname;
                   1166:     V9fsFidState *fidp;
                   1167:     size_t offset = 7;
1.1.1.2 ! root     1168:     V9fsQID qid;
1.1       root     1169:     ssize_t err;
                   1170: 
                   1171:     pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1.1.1.2 ! root     1172:     trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
1.1       root     1173: 
                   1174:     fidp = alloc_fid(s, fid);
                   1175:     if (fidp == NULL) {
                   1176:         err = -EINVAL;
1.1.1.2 ! root     1177:         goto out_nofid;
1.1       root     1178:     }
                   1179:     fidp->uid = n_uname;
1.1.1.2 ! root     1180:     err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
        !          1181:     if (err < 0) {
1.1       root     1182:         err = -EINVAL;
1.1.1.2 ! root     1183:         clunk_fid(s, fid);
        !          1184:         goto out;
        !          1185:     }
        !          1186:     err = fid_to_qid(pdu, fidp, &qid);
        !          1187:     if (err < 0) {
        !          1188:         err = -EINVAL;
        !          1189:         clunk_fid(s, fid);
1.1       root     1190:         goto out;
                   1191:     }
                   1192:     offset += pdu_marshal(pdu, offset, "Q", &qid);
                   1193:     err = offset;
1.1.1.2 ! root     1194:     trace_v9fs_attach_return(pdu->tag, pdu->id,
        !          1195:                              qid.type, qid.version, qid.path);
        !          1196:     s->root_fid = fid;
        !          1197:     /* disable migration */
        !          1198:     error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
        !          1199:               s->ctx.fs_root, s->tag);
        !          1200:     migrate_add_blocker(s->migration_blocker);
1.1       root     1201: out:
1.1.1.2 ! root     1202:     put_fid(pdu, fidp);
        !          1203: out_nofid:
1.1       root     1204:     complete_pdu(s, pdu, err);
                   1205:     v9fs_string_free(&uname);
                   1206:     v9fs_string_free(&aname);
                   1207: }
                   1208: 
1.1.1.2 ! root     1209: static void v9fs_stat(void *opaque)
1.1       root     1210: {
                   1211:     int32_t fid;
1.1.1.2 ! root     1212:     V9fsStat v9stat;
1.1       root     1213:     ssize_t err = 0;
1.1.1.2 ! root     1214:     size_t offset = 7;
        !          1215:     struct stat stbuf;
        !          1216:     V9fsFidState *fidp;
        !          1217:     V9fsPDU *pdu = opaque;
        !          1218:     V9fsState *s = pdu->s;
1.1       root     1219: 
1.1.1.2 ! root     1220:     pdu_unmarshal(pdu, offset, "d", &fid);
        !          1221:     trace_v9fs_stat(pdu->tag, pdu->id, fid);
1.1       root     1222: 
1.1.1.2 ! root     1223:     fidp = get_fid(pdu, fid);
        !          1224:     if (fidp == NULL) {
1.1       root     1225:         err = -ENOENT;
1.1.1.2 ! root     1226:         goto out_nofid;
        !          1227:     }
        !          1228:     err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !          1229:     if (err < 0) {
1.1       root     1230:         goto out;
                   1231:     }
1.1.1.2 ! root     1232:     err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
        !          1233:     if (err < 0) {
1.1       root     1234:         goto out;
                   1235:     }
1.1.1.2 ! root     1236:     offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
        !          1237:     err = offset;
        !          1238:     trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
        !          1239:                            v9stat.atime, v9stat.mtime, v9stat.length);
        !          1240:     v9fs_stat_free(&v9stat);
1.1       root     1241: out:
1.1.1.2 ! root     1242:     put_fid(pdu, fidp);
        !          1243: out_nofid:
        !          1244:     complete_pdu(s, pdu, err);
1.1       root     1245: }
                   1246: 
1.1.1.2 ! root     1247: static void v9fs_getattr(void *opaque)
1.1       root     1248: {
                   1249:     int32_t fid;
1.1.1.2 ! root     1250:     size_t offset = 7;
        !          1251:     ssize_t retval = 0;
        !          1252:     struct stat stbuf;
1.1       root     1253:     V9fsFidState *fidp;
                   1254:     uint64_t request_mask;
1.1.1.2 ! root     1255:     V9fsStatDotl v9stat_dotl;
        !          1256:     V9fsPDU *pdu = opaque;
        !          1257:     V9fsState *s = pdu->s;
1.1       root     1258: 
1.1.1.2 ! root     1259:     pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
        !          1260:     trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
1.1       root     1261: 
1.1.1.2 ! root     1262:     fidp = get_fid(pdu, fid);
1.1       root     1263:     if (fidp == NULL) {
1.1.1.2 ! root     1264:         retval = -ENOENT;
        !          1265:         goto out_nofid;
1.1       root     1266:     }
1.1.1.2 ! root     1267:     /*
        !          1268:      * Currently we only support BASIC fields in stat, so there is no
1.1       root     1269:      * need to look at request_mask.
                   1270:      */
1.1.1.2 ! root     1271:     retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !          1272:     if (retval < 0) {
        !          1273:         goto out;
        !          1274:     }
        !          1275:     stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1.1       root     1276: 
1.1.1.2 ! root     1277:     /*  fill st_gen if requested and supported by underlying fs */
        !          1278:     if (request_mask & P9_STATS_GEN) {
        !          1279:         retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
        !          1280:         if (retval < 0) {
        !          1281:             goto out;
        !          1282:         }
        !          1283:         v9stat_dotl.st_result_mask |= P9_STATS_GEN;
        !          1284:     }
        !          1285:     retval = offset;
        !          1286:     retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
        !          1287:     trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
        !          1288:                               v9stat_dotl.st_mode, v9stat_dotl.st_uid,
        !          1289:                               v9stat_dotl.st_gid);
        !          1290: out:
        !          1291:     put_fid(pdu, fidp);
        !          1292: out_nofid:
        !          1293:     complete_pdu(s, pdu, retval);
1.1       root     1294: }
                   1295: 
                   1296: /* From Linux kernel code */
                   1297: #define ATTR_MODE    (1 << 0)
                   1298: #define ATTR_UID     (1 << 1)
                   1299: #define ATTR_GID     (1 << 2)
                   1300: #define ATTR_SIZE    (1 << 3)
                   1301: #define ATTR_ATIME   (1 << 4)
                   1302: #define ATTR_MTIME   (1 << 5)
                   1303: #define ATTR_CTIME   (1 << 6)
                   1304: #define ATTR_MASK    127
                   1305: #define ATTR_ATIME_SET  (1 << 7)
                   1306: #define ATTR_MTIME_SET  (1 << 8)
                   1307: 
1.1.1.2 ! root     1308: static void v9fs_setattr(void *opaque)
1.1       root     1309: {
1.1.1.2 ! root     1310:     int err = 0;
        !          1311:     int32_t fid;
        !          1312:     V9fsFidState *fidp;
        !          1313:     size_t offset = 7;
        !          1314:     V9fsIattr v9iattr;
        !          1315:     V9fsPDU *pdu = opaque;
        !          1316:     V9fsState *s = pdu->s;
1.1       root     1317: 
1.1.1.2 ! root     1318:     pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1.1       root     1319: 
1.1.1.2 ! root     1320:     fidp = get_fid(pdu, fid);
        !          1321:     if (fidp == NULL) {
        !          1322:         err = -EINVAL;
        !          1323:         goto out_nofid;
1.1       root     1324:     }
1.1.1.2 ! root     1325:     if (v9iattr.valid & ATTR_MODE) {
        !          1326:         err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
        !          1327:         if (err < 0) {
        !          1328:             goto out;
1.1       root     1329:         }
                   1330:     }
1.1.1.2 ! root     1331:     if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1.1       root     1332:         struct timespec times[2];
1.1.1.2 ! root     1333:         if (v9iattr.valid & ATTR_ATIME) {
        !          1334:             if (v9iattr.valid & ATTR_ATIME_SET) {
        !          1335:                 times[0].tv_sec = v9iattr.atime_sec;
        !          1336:                 times[0].tv_nsec = v9iattr.atime_nsec;
1.1       root     1337:             } else {
                   1338:                 times[0].tv_nsec = UTIME_NOW;
                   1339:             }
                   1340:         } else {
                   1341:             times[0].tv_nsec = UTIME_OMIT;
                   1342:         }
1.1.1.2 ! root     1343:         if (v9iattr.valid & ATTR_MTIME) {
        !          1344:             if (v9iattr.valid & ATTR_MTIME_SET) {
        !          1345:                 times[1].tv_sec = v9iattr.mtime_sec;
        !          1346:                 times[1].tv_nsec = v9iattr.mtime_nsec;
1.1       root     1347:             } else {
                   1348:                 times[1].tv_nsec = UTIME_NOW;
                   1349:             }
                   1350:         } else {
                   1351:             times[1].tv_nsec = UTIME_OMIT;
                   1352:         }
1.1.1.2 ! root     1353:         err = v9fs_co_utimensat(pdu, &fidp->path, times);
        !          1354:         if (err < 0) {
        !          1355:             goto out;
        !          1356:         }
1.1       root     1357:     }
1.1.1.2 ! root     1358:     /*
        !          1359:      * If the only valid entry in iattr is ctime we can call
        !          1360:      * chown(-1,-1) to update the ctime of the file
        !          1361:      */
        !          1362:     if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
        !          1363:         ((v9iattr.valid & ATTR_CTIME)
        !          1364:          && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
        !          1365:         if (!(v9iattr.valid & ATTR_UID)) {
        !          1366:             v9iattr.uid = -1;
        !          1367:         }
        !          1368:         if (!(v9iattr.valid & ATTR_GID)) {
        !          1369:             v9iattr.gid = -1;
        !          1370:         }
        !          1371:         err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
        !          1372:                             v9iattr.gid);
        !          1373:         if (err < 0) {
        !          1374:             goto out;
        !          1375:         }
        !          1376:     }
        !          1377:     if (v9iattr.valid & (ATTR_SIZE)) {
        !          1378:         err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
        !          1379:         if (err < 0) {
        !          1380:             goto out;
        !          1381:         }
        !          1382:     }
        !          1383:     err = offset;
1.1       root     1384: out:
1.1.1.2 ! root     1385:     put_fid(pdu, fidp);
        !          1386: out_nofid:
        !          1387:     complete_pdu(s, pdu, err);
1.1       root     1388: }
                   1389: 
1.1.1.2 ! root     1390: static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1.1       root     1391: {
1.1.1.2 ! root     1392:     int i;
        !          1393:     size_t offset = 7;
        !          1394:     offset += pdu_marshal(pdu, offset, "w", nwnames);
        !          1395:     for (i = 0; i < nwnames; i++) {
        !          1396:         offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
        !          1397:     }
        !          1398:     return offset;
        !          1399: }
1.1       root     1400: 
1.1.1.2 ! root     1401: static void v9fs_walk(void *opaque)
        !          1402: {
        !          1403:     int name_idx;
        !          1404:     V9fsQID *qids = NULL;
        !          1405:     int i, err = 0;
        !          1406:     V9fsPath dpath, path;
        !          1407:     uint16_t nwnames;
        !          1408:     struct stat stbuf;
        !          1409:     size_t offset = 7;
        !          1410:     int32_t fid, newfid;
        !          1411:     V9fsString *wnames = NULL;
        !          1412:     V9fsFidState *fidp;
        !          1413:     V9fsFidState *newfidp = NULL;;
        !          1414:     V9fsPDU *pdu = opaque;
        !          1415:     V9fsState *s = pdu->s;
        !          1416: 
        !          1417:     offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
        !          1418:                             &newfid, &nwnames);
        !          1419: 
        !          1420:     trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
        !          1421: 
        !          1422:     if (nwnames && nwnames <= P9_MAXWELEM) {
        !          1423:         wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
        !          1424:         qids   = g_malloc0(sizeof(qids[0]) * nwnames);
        !          1425:         for (i = 0; i < nwnames; i++) {
        !          1426:             offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
        !          1427:         }
        !          1428:     } else if (nwnames > P9_MAXWELEM) {
1.1       root     1429:         err = -EINVAL;
1.1.1.2 ! root     1430:         goto out_nofid;
1.1       root     1431:     }
1.1.1.2 ! root     1432:     fidp = get_fid(pdu, fid);
        !          1433:     if (fidp == NULL) {
        !          1434:         err = -ENOENT;
        !          1435:         goto out_nofid;
1.1       root     1436:     }
1.1.1.2 ! root     1437:     v9fs_path_init(&dpath);
        !          1438:     v9fs_path_init(&path);
        !          1439:     /*
        !          1440:      * Both dpath and path initially poin to fidp.
        !          1441:      * Needed to handle request with nwnames == 0
        !          1442:      */
        !          1443:     v9fs_path_copy(&dpath, &fidp->path);
        !          1444:     v9fs_path_copy(&path, &fidp->path);
        !          1445:     for (name_idx = 0; name_idx < nwnames; name_idx++) {
        !          1446:         err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
        !          1447:         if (err < 0) {
        !          1448:             goto out;
        !          1449:         }
        !          1450:         err = v9fs_co_lstat(pdu, &path, &stbuf);
        !          1451:         if (err < 0) {
        !          1452:             goto out;
        !          1453:         }
        !          1454:         stat_to_qid(&stbuf, &qids[name_idx]);
        !          1455:         v9fs_path_copy(&dpath, &path);
        !          1456:     }
        !          1457:     if (fid == newfid) {
        !          1458:         BUG_ON(fidp->fid_type != P9_FID_NONE);
        !          1459:         v9fs_path_copy(&fidp->path, &path);
        !          1460:     } else {
        !          1461:         newfidp = alloc_fid(s, newfid);
        !          1462:         if (newfidp == NULL) {
        !          1463:             err = -EINVAL;
        !          1464:             goto out;
        !          1465:         }
        !          1466:         newfidp->uid = fidp->uid;
        !          1467:         v9fs_path_copy(&newfidp->path, &path);
        !          1468:     }
        !          1469:     err = v9fs_walk_marshal(pdu, nwnames, qids);
        !          1470:     trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
1.1       root     1471: out:
1.1.1.2 ! root     1472:     put_fid(pdu, fidp);
        !          1473:     if (newfidp) {
        !          1474:         put_fid(pdu, newfidp);
        !          1475:     }
        !          1476:     v9fs_path_free(&dpath);
        !          1477:     v9fs_path_free(&path);
        !          1478: out_nofid:
        !          1479:     complete_pdu(s, pdu, err);
        !          1480:     if (nwnames && nwnames <= P9_MAXWELEM) {
        !          1481:         for (name_idx = 0; name_idx < nwnames; name_idx++) {
        !          1482:             v9fs_string_free(&wnames[name_idx]);
        !          1483:         }
        !          1484:         g_free(wnames);
        !          1485:         g_free(qids);
        !          1486:     }
        !          1487:     return;
1.1       root     1488: }
                   1489: 
1.1.1.2 ! root     1490: static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
1.1       root     1491: {
1.1.1.2 ! root     1492:     struct statfs stbuf;
        !          1493:     int32_t iounit = 0;
        !          1494:     V9fsState *s = pdu->s;
1.1       root     1495: 
1.1.1.2 ! root     1496:     /*
        !          1497:      * iounit should be multiples of f_bsize (host filesystem block size
        !          1498:      * and as well as less than (client msize - P9_IOHDRSZ))
        !          1499:      */
        !          1500:     if (!v9fs_co_statfs(pdu, path, &stbuf)) {
        !          1501:         iounit = stbuf.f_bsize;
        !          1502:         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
        !          1503:     }
        !          1504:     if (!iounit) {
        !          1505:         iounit = s->msize - P9_IOHDRSZ;
1.1       root     1506:     }
1.1.1.2 ! root     1507:     return iounit;
1.1       root     1508: }
                   1509: 
1.1.1.2 ! root     1510: static void v9fs_open(void *opaque)
1.1       root     1511: {
1.1.1.2 ! root     1512:     int flags;
        !          1513:     int32_t fid;
        !          1514:     int32_t mode;
        !          1515:     V9fsQID qid;
        !          1516:     int iounit = 0;
        !          1517:     ssize_t err = 0;
        !          1518:     size_t offset = 7;
        !          1519:     struct stat stbuf;
        !          1520:     V9fsFidState *fidp;
        !          1521:     V9fsPDU *pdu = opaque;
        !          1522:     V9fsState *s = pdu->s;
1.1       root     1523: 
1.1.1.2 ! root     1524:     if (s->proto_version == V9FS_PROTO_2000L) {
        !          1525:         pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
        !          1526:     } else {
        !          1527:         pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1.1       root     1528:     }
1.1.1.2 ! root     1529:     trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1.1       root     1530: 
1.1.1.2 ! root     1531:     fidp = get_fid(pdu, fid);
        !          1532:     if (fidp == NULL) {
1.1       root     1533:         err = -ENOENT;
1.1.1.2 ! root     1534:         goto out_nofid;
1.1       root     1535:     }
1.1.1.2 ! root     1536:     BUG_ON(fidp->fid_type != P9_FID_NONE);
1.1       root     1537: 
1.1.1.2 ! root     1538:     err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !          1539:     if (err < 0) {
1.1       root     1540:         goto out;
                   1541:     }
1.1.1.2 ! root     1542:     stat_to_qid(&stbuf, &qid);
        !          1543:     if (S_ISDIR(stbuf.st_mode)) {
        !          1544:         err = v9fs_co_opendir(pdu, fidp);
        !          1545:         if (err < 0) {
1.1       root     1546:             goto out;
                   1547:         }
1.1.1.2 ! root     1548:         fidp->fid_type = P9_FID_DIR;
        !          1549:         offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
        !          1550:         err = offset;
1.1       root     1551:     } else {
                   1552:         if (s->proto_version == V9FS_PROTO_2000L) {
1.1.1.2 ! root     1553:             flags = get_dotl_openflags(s, mode);
1.1       root     1554:         } else {
1.1.1.2 ! root     1555:             flags = omode_to_uflags(mode);
1.1       root     1556:         }
1.1.1.2 ! root     1557:         if (is_ro_export(&s->ctx)) {
        !          1558:             if (mode & O_WRONLY || mode & O_RDWR ||
        !          1559:                 mode & O_APPEND || mode & O_TRUNC) {
        !          1560:                 err = -EROFS;
        !          1561:                 goto out;
        !          1562:             }
        !          1563:             flags |= O_NOATIME;
1.1       root     1564:         }
1.1.1.2 ! root     1565:         err = v9fs_co_open(pdu, fidp, flags);
        !          1566:         if (err < 0) {
        !          1567:             goto out;
        !          1568:         }
        !          1569:         fidp->fid_type = P9_FID_FILE;
        !          1570:         fidp->open_flags = flags;
        !          1571:         if (flags & O_EXCL) {
        !          1572:             /*
        !          1573:              * We let the host file system do O_EXCL check
        !          1574:              * We should not reclaim such fd
        !          1575:              */
        !          1576:             fidp->flags |= FID_NON_RECLAIMABLE;
        !          1577:         }
        !          1578:         iounit = get_iounit(pdu, &fidp->path);
        !          1579:         offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
        !          1580:         err = offset;
1.1       root     1581:     }
1.1.1.2 ! root     1582:     trace_v9fs_open_return(pdu->tag, pdu->id,
        !          1583:                            qid.type, qid.version, qid.path, iounit);
1.1       root     1584: out:
1.1.1.2 ! root     1585:     put_fid(pdu, fidp);
        !          1586: out_nofid:
        !          1587:     complete_pdu(s, pdu, err);
1.1       root     1588: }
                   1589: 
1.1.1.2 ! root     1590: static void v9fs_lcreate(void *opaque)
1.1       root     1591: {
                   1592:     int32_t dfid, flags, mode;
                   1593:     gid_t gid;
                   1594:     ssize_t err = 0;
1.1.1.2 ! root     1595:     ssize_t offset = 7;
        !          1596:     V9fsString name;
        !          1597:     V9fsFidState *fidp;
        !          1598:     struct stat stbuf;
        !          1599:     V9fsQID qid;
        !          1600:     int32_t iounit;
        !          1601:     V9fsPDU *pdu = opaque;
1.1       root     1602: 
1.1.1.2 ! root     1603:     pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
        !          1604:                   &mode, &gid);
        !          1605:     trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1.1       root     1606: 
1.1.1.2 ! root     1607:     fidp = get_fid(pdu, dfid);
        !          1608:     if (fidp == NULL) {
1.1       root     1609:         err = -ENOENT;
1.1.1.2 ! root     1610:         goto out_nofid;
1.1       root     1611:     }
                   1612: 
1.1.1.2 ! root     1613:     flags = get_dotl_openflags(pdu->s, flags);
        !          1614:     err = v9fs_co_open2(pdu, fidp, &name, gid,
        !          1615:                         flags | O_CREAT, mode, &stbuf);
        !          1616:     if (err < 0) {
        !          1617:         goto out;
1.1       root     1618:     }
1.1.1.2 ! root     1619:     fidp->fid_type = P9_FID_FILE;
        !          1620:     fidp->open_flags = flags;
        !          1621:     if (flags & O_EXCL) {
        !          1622:         /*
        !          1623:          * We let the host file system do O_EXCL check
        !          1624:          * We should not reclaim such fd
        !          1625:          */
        !          1626:         fidp->flags |= FID_NON_RECLAIMABLE;
        !          1627:     }
        !          1628:     iounit =  get_iounit(pdu, &fidp->path);
        !          1629:     stat_to_qid(&stbuf, &qid);
        !          1630:     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
        !          1631:     err = offset;
        !          1632:     trace_v9fs_lcreate_return(pdu->tag, pdu->id,
        !          1633:                               qid.type, qid.version, qid.path, iounit);
        !          1634: out:
        !          1635:     put_fid(pdu, fidp);
        !          1636: out_nofid:
        !          1637:     complete_pdu(pdu->s, pdu, err);
        !          1638:     v9fs_string_free(&name);
1.1       root     1639: }
                   1640: 
1.1.1.2 ! root     1641: static void v9fs_fsync(void *opaque)
1.1       root     1642: {
1.1.1.2 ! root     1643:     int err;
1.1       root     1644:     int32_t fid;
1.1.1.2 ! root     1645:     int datasync;
1.1       root     1646:     size_t offset = 7;
                   1647:     V9fsFidState *fidp;
1.1.1.2 ! root     1648:     V9fsPDU *pdu = opaque;
        !          1649:     V9fsState *s = pdu->s;
1.1       root     1650: 
                   1651:     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1.1.1.2 ! root     1652:     trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
        !          1653: 
        !          1654:     fidp = get_fid(pdu, fid);
1.1       root     1655:     if (fidp == NULL) {
                   1656:         err = -ENOENT;
1.1.1.2 ! root     1657:         goto out_nofid;
        !          1658:     }
        !          1659:     err = v9fs_co_fsync(pdu, fidp, datasync);
        !          1660:     if (!err) {
        !          1661:         err = offset;
1.1       root     1662:     }
1.1.1.2 ! root     1663:     put_fid(pdu, fidp);
        !          1664: out_nofid:
        !          1665:     complete_pdu(s, pdu, err);
1.1       root     1666: }
                   1667: 
1.1.1.2 ! root     1668: static void v9fs_clunk(void *opaque)
1.1       root     1669: {
1.1.1.2 ! root     1670:     int err;
1.1       root     1671:     int32_t fid;
                   1672:     size_t offset = 7;
1.1.1.2 ! root     1673:     V9fsFidState *fidp;
        !          1674:     V9fsPDU *pdu = opaque;
        !          1675:     V9fsState *s = pdu->s;
1.1       root     1676: 
                   1677:     pdu_unmarshal(pdu, offset, "d", &fid);
1.1.1.2 ! root     1678:     trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1.1       root     1679: 
1.1.1.2 ! root     1680:     fidp = clunk_fid(s, fid);
        !          1681:     if (fidp == NULL) {
        !          1682:         err = -ENOENT;
        !          1683:         goto out_nofid;
1.1       root     1684:     }
1.1.1.2 ! root     1685:     /*
        !          1686:      * Bump the ref so that put_fid will
        !          1687:      * free the fid.
        !          1688:      */
        !          1689:     fidp->ref++;
1.1       root     1690:     err = offset;
1.1.1.2 ! root     1691: 
        !          1692:     put_fid(pdu, fidp);
        !          1693: out_nofid:
1.1       root     1694:     complete_pdu(s, pdu, err);
                   1695: }
                   1696: 
1.1.1.2 ! root     1697: static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
        !          1698:                            uint64_t off, uint32_t max_count)
1.1       root     1699: {
1.1.1.2 ! root     1700:     size_t offset = 7;
        !          1701:     int read_count;
        !          1702:     int64_t xattr_len;
1.1       root     1703: 
1.1.1.2 ! root     1704:     xattr_len = fidp->fs.xattr.len;
        !          1705:     read_count = xattr_len - off;
        !          1706:     if (read_count > max_count) {
        !          1707:         read_count = max_count;
        !          1708:     } else if (read_count < 0) {
        !          1709:         /*
        !          1710:          * read beyond XATTR value
        !          1711:          */
        !          1712:         read_count = 0;
1.1       root     1713:     }
1.1.1.2 ! root     1714:     offset += pdu_marshal(pdu, offset, "d", read_count);
        !          1715:     offset += pdu_pack(pdu, offset,
        !          1716:                        ((char *)fidp->fs.xattr.value) + off,
        !          1717:                        read_count);
        !          1718:     return offset;
1.1       root     1719: }
                   1720: 
1.1.1.2 ! root     1721: static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
        !          1722:                                      V9fsFidState *fidp, uint32_t max_count)
        !          1723: {
        !          1724:     V9fsPath path;
        !          1725:     V9fsStat v9stat;
        !          1726:     int len, err = 0;
        !          1727:     int32_t count = 0;
        !          1728:     struct stat stbuf;
        !          1729:     off_t saved_dir_pos;
        !          1730:     struct dirent *dent, *result;
1.1       root     1731: 
1.1.1.2 ! root     1732:     /* save the directory position */
        !          1733:     saved_dir_pos = v9fs_co_telldir(pdu, fidp);
        !          1734:     if (saved_dir_pos < 0) {
        !          1735:         return saved_dir_pos;
        !          1736:     }
1.1       root     1737: 
1.1.1.2 ! root     1738:     dent = g_malloc(sizeof(struct dirent));
1.1       root     1739: 
1.1.1.2 ! root     1740:     while (1) {
        !          1741:         v9fs_path_init(&path);
        !          1742:         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
        !          1743:         if (err || !result) {
        !          1744:             break;
        !          1745:         }
        !          1746:         err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
        !          1747:         if (err < 0) {
        !          1748:             goto out;
        !          1749:         }
        !          1750:         err = v9fs_co_lstat(pdu, &path, &stbuf);
        !          1751:         if (err < 0) {
        !          1752:             goto out;
        !          1753:         }
        !          1754:         err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
        !          1755:         if (err < 0) {
        !          1756:             goto out;
1.1       root     1757:         }
1.1.1.2 ! root     1758:         /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
        !          1759:         len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
        !          1760:         if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
        !          1761:             /* Ran out of buffer. Set dir back to old position and return */
        !          1762:             v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
        !          1763:             v9fs_stat_free(&v9stat);
        !          1764:             v9fs_path_free(&path);
        !          1765:             g_free(dent);
        !          1766:             return count;
        !          1767:         }
        !          1768:         count += len;
        !          1769:         v9fs_stat_free(&v9stat);
        !          1770:         v9fs_path_free(&path);
        !          1771:         saved_dir_pos = dent->d_off;
1.1       root     1772:     }
                   1773: out:
1.1.1.2 ! root     1774:     g_free(dent);
        !          1775:     v9fs_path_free(&path);
        !          1776:     if (err < 0) {
        !          1777:         return err;
        !          1778:     }
        !          1779:     return count;
1.1       root     1780: }
                   1781: 
1.1.1.2 ! root     1782: /*
        !          1783:  * Create a QEMUIOVector for a sub-region of PDU iovecs
        !          1784:  *
        !          1785:  * @qiov:       uninitialized QEMUIOVector
        !          1786:  * @skip:       number of bytes to skip from beginning of PDU
        !          1787:  * @size:       number of bytes to include
        !          1788:  * @is_write:   true - write, false - read
        !          1789:  *
        !          1790:  * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
        !          1791:  * with qemu_iovec_destroy().
        !          1792:  */
        !          1793: static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
        !          1794:                                     uint64_t skip, size_t size,
        !          1795:                                     bool is_write)
        !          1796: {
        !          1797:     QEMUIOVector elem;
        !          1798:     struct iovec *iov;
        !          1799:     unsigned int niov;
        !          1800: 
        !          1801:     if (is_write) {
        !          1802:         iov = pdu->elem.out_sg;
        !          1803:         niov = pdu->elem.out_num;
        !          1804:     } else {
        !          1805:         iov = pdu->elem.in_sg;
        !          1806:         niov = pdu->elem.in_num;
1.1       root     1807:     }
1.1.1.2 ! root     1808: 
        !          1809:     qemu_iovec_init_external(&elem, iov, niov);
        !          1810:     qemu_iovec_init(qiov, niov);
        !          1811:     qemu_iovec_copy(qiov, &elem, skip, size);
1.1       root     1812: }
                   1813: 
1.1.1.2 ! root     1814: static void v9fs_read(void *opaque)
1.1       root     1815: {
                   1816:     int32_t fid;
1.1.1.2 ! root     1817:     uint64_t off;
1.1       root     1818:     ssize_t err = 0;
1.1.1.2 ! root     1819:     int32_t count = 0;
        !          1820:     size_t offset = 7;
        !          1821:     uint32_t max_count;
        !          1822:     V9fsFidState *fidp;
        !          1823:     V9fsPDU *pdu = opaque;
        !          1824:     V9fsState *s = pdu->s;
1.1       root     1825: 
1.1.1.2 ! root     1826:     pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
        !          1827:     trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1.1       root     1828: 
1.1.1.2 ! root     1829:     fidp = get_fid(pdu, fid);
        !          1830:     if (fidp == NULL) {
1.1       root     1831:         err = -EINVAL;
1.1.1.2 ! root     1832:         goto out_nofid;
1.1       root     1833:     }
1.1.1.2 ! root     1834:     if (fidp->fid_type == P9_FID_DIR) {
1.1       root     1835: 
1.1.1.2 ! root     1836:         if (off == 0) {
        !          1837:             v9fs_co_rewinddir(pdu, fidp);
1.1       root     1838:         }
1.1.1.2 ! root     1839:         count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
        !          1840:         if (count < 0) {
        !          1841:             err = count;
        !          1842:             goto out;
        !          1843:         }
        !          1844:         err = offset;
        !          1845:         err += pdu_marshal(pdu, offset, "d", count);
        !          1846:         err += count;
        !          1847:     } else if (fidp->fid_type == P9_FID_FILE) {
        !          1848:         QEMUIOVector qiov_full;
        !          1849:         QEMUIOVector qiov;
        !          1850:         int32_t len;
        !          1851: 
        !          1852:         v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
        !          1853:         qemu_iovec_init(&qiov, qiov_full.niov);
        !          1854:         do {
        !          1855:             qemu_iovec_reset(&qiov);
        !          1856:             qemu_iovec_copy(&qiov, &qiov_full, count, qiov_full.size - count);
        !          1857:             if (0) {
        !          1858:                 print_sg(qiov.iov, qiov.niov);
        !          1859:             }
        !          1860:             /* Loop in case of EINTR */
        !          1861:             do {
        !          1862:                 len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
        !          1863:                 if (len >= 0) {
        !          1864:                     off   += len;
        !          1865:                     count += len;
        !          1866:                 }
        !          1867:             } while (len == -EINTR && !pdu->cancelled);
        !          1868:             if (len < 0) {
        !          1869:                 /* IO error return the error */
        !          1870:                 err = len;
        !          1871:                 goto out;
        !          1872:             }
        !          1873:         } while (count < max_count && len > 0);
        !          1874:         err = offset;
        !          1875:         err += pdu_marshal(pdu, offset, "d", count);
        !          1876:         err += count;
        !          1877:         qemu_iovec_destroy(&qiov);
        !          1878:         qemu_iovec_destroy(&qiov_full);
        !          1879:     } else if (fidp->fid_type == P9_FID_XATTR) {
        !          1880:         err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1.1       root     1881:     } else {
                   1882:         err = -EINVAL;
                   1883:     }
1.1.1.2 ! root     1884:     trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
1.1       root     1885: out:
1.1.1.2 ! root     1886:     put_fid(pdu, fidp);
        !          1887: out_nofid:
1.1       root     1888:     complete_pdu(s, pdu, err);
                   1889: }
                   1890: 
1.1.1.2 ! root     1891: static size_t v9fs_readdir_data_size(V9fsString *name)
1.1       root     1892: {
1.1.1.2 ! root     1893:     /*
        !          1894:      * Size of each dirent on the wire: size of qid (13) + size of offset (8)
        !          1895:      * size of type (1) + size of name.size (2) + strlen(name.data)
        !          1896:      */
        !          1897:     return 24 + v9fs_string_size(name);
1.1       root     1898: }
                   1899: 
1.1.1.2 ! root     1900: static int v9fs_do_readdir(V9fsPDU *pdu,
        !          1901:                            V9fsFidState *fidp, int32_t max_count)
1.1       root     1902: {
                   1903:     size_t size;
1.1.1.2 ! root     1904:     V9fsQID qid;
        !          1905:     V9fsString name;
        !          1906:     int len, err = 0;
        !          1907:     int32_t count = 0;
        !          1908:     off_t saved_dir_pos;
        !          1909:     struct dirent *dent, *result;
1.1       root     1910: 
1.1.1.2 ! root     1911:     /* save the directory position */
        !          1912:     saved_dir_pos = v9fs_co_telldir(pdu, fidp);
        !          1913:     if (saved_dir_pos < 0) {
        !          1914:         return saved_dir_pos;
        !          1915:     }
        !          1916: 
        !          1917:     dent = g_malloc(sizeof(struct dirent));
1.1       root     1918: 
1.1.1.2 ! root     1919:     while (1) {
        !          1920:         err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
        !          1921:         if (err || !result) {
        !          1922:             break;
        !          1923:         }
        !          1924:         v9fs_string_init(&name);
        !          1925:         v9fs_string_sprintf(&name, "%s", dent->d_name);
        !          1926:         if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1.1       root     1927:             /* Ran out of buffer. Set dir back to old position and return */
1.1.1.2 ! root     1928:             v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
        !          1929:             v9fs_string_free(&name);
        !          1930:             g_free(dent);
        !          1931:             return count;
1.1       root     1932:         }
1.1.1.2 ! root     1933:         /*
        !          1934:          * Fill up just the path field of qid because the client uses
1.1       root     1935:          * only that. To fill the entire qid structure we will have
                   1936:          * to stat each dirent found, which is expensive
                   1937:          */
1.1.1.2 ! root     1938:         size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
        !          1939:         memcpy(&qid.path, &dent->d_ino, size);
1.1       root     1940:         /* Fill the other fields with dummy values */
1.1.1.2 ! root     1941:         qid.type = 0;
        !          1942:         qid.version = 0;
1.1       root     1943: 
1.1.1.2 ! root     1944:         /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
        !          1945:         len = pdu_marshal(pdu, 11 + count, "Qqbs",
        !          1946:                           &qid, dent->d_off,
        !          1947:                           dent->d_type, &name);
        !          1948:         count += len;
        !          1949:         v9fs_string_free(&name);
        !          1950:         saved_dir_pos = dent->d_off;
        !          1951:     }
        !          1952:     g_free(dent);
        !          1953:     if (err < 0) {
        !          1954:         return err;
        !          1955:     }
        !          1956:     return count;
1.1       root     1957: }
                   1958: 
1.1.1.2 ! root     1959: static void v9fs_readdir(void *opaque)
1.1       root     1960: {
                   1961:     int32_t fid;
1.1.1.2 ! root     1962:     V9fsFidState *fidp;
        !          1963:     ssize_t retval = 0;
1.1       root     1964:     size_t offset = 7;
1.1.1.2 ! root     1965:     uint64_t initial_offset;
        !          1966:     int32_t count;
        !          1967:     uint32_t max_count;
        !          1968:     V9fsPDU *pdu = opaque;
        !          1969:     V9fsState *s = pdu->s;
1.1       root     1970: 
1.1.1.2 ! root     1971:     pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1.1       root     1972: 
1.1.1.2 ! root     1973:     trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1.1       root     1974: 
1.1.1.2 ! root     1975:     fidp = get_fid(pdu, fid);
        !          1976:     if (fidp == NULL) {
        !          1977:         retval = -EINVAL;
        !          1978:         goto out_nofid;
        !          1979:     }
        !          1980:     if (!fidp->fs.dir) {
        !          1981:         retval = -EINVAL;
1.1       root     1982:         goto out;
                   1983:     }
1.1.1.2 ! root     1984:     if (initial_offset == 0) {
        !          1985:         v9fs_co_rewinddir(pdu, fidp);
1.1       root     1986:     } else {
1.1.1.2 ! root     1987:         v9fs_co_seekdir(pdu, fidp, initial_offset);
1.1       root     1988:     }
1.1.1.2 ! root     1989:     count = v9fs_do_readdir(pdu, fidp, max_count);
        !          1990:     if (count < 0) {
        !          1991:         retval = count;
1.1       root     1992:         goto out;
                   1993:     }
1.1.1.2 ! root     1994:     retval = offset;
        !          1995:     retval += pdu_marshal(pdu, offset, "d", count);
        !          1996:     retval += count;
        !          1997:     trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
1.1       root     1998: out:
1.1.1.2 ! root     1999:     put_fid(pdu, fidp);
        !          2000: out_nofid:
        !          2001:     complete_pdu(s, pdu, retval);
1.1       root     2002: }
                   2003: 
1.1.1.2 ! root     2004: static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
        !          2005:                             uint64_t off, uint32_t count,
        !          2006:                             struct iovec *sg, int cnt)
1.1       root     2007: {
                   2008:     int i, to_copy;
                   2009:     ssize_t err = 0;
                   2010:     int write_count;
                   2011:     int64_t xattr_len;
1.1.1.2 ! root     2012:     size_t offset = 7;
        !          2013: 
1.1       root     2014: 
1.1.1.2 ! root     2015:     xattr_len = fidp->fs.xattr.len;
        !          2016:     write_count = xattr_len - off;
        !          2017:     if (write_count > count) {
        !          2018:         write_count = count;
1.1       root     2019:     } else if (write_count < 0) {
                   2020:         /*
                   2021:          * write beyond XATTR value len specified in
                   2022:          * xattrcreate
                   2023:          */
                   2024:         err = -ENOSPC;
                   2025:         goto out;
                   2026:     }
1.1.1.2 ! root     2027:     offset += pdu_marshal(pdu, offset, "d", write_count);
        !          2028:     err = offset;
        !          2029:     fidp->fs.xattr.copied_len += write_count;
1.1       root     2030:     /*
                   2031:      * Now copy the content from sg list
                   2032:      */
1.1.1.2 ! root     2033:     for (i = 0; i < cnt; i++) {
        !          2034:         if (write_count > sg[i].iov_len) {
        !          2035:             to_copy = sg[i].iov_len;
1.1       root     2036:         } else {
                   2037:             to_copy = write_count;
                   2038:         }
1.1.1.2 ! root     2039:         memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1.1       root     2040:         /* updating vs->off since we are not using below */
1.1.1.2 ! root     2041:         off += to_copy;
1.1       root     2042:         write_count -= to_copy;
                   2043:     }
                   2044: out:
1.1.1.2 ! root     2045:     return err;
1.1       root     2046: }
                   2047: 
1.1.1.2 ! root     2048: static void v9fs_write(void *opaque)
1.1       root     2049: {
                   2050:     ssize_t err;
1.1.1.2 ! root     2051:     int32_t fid;
        !          2052:     uint64_t off;
        !          2053:     uint32_t count;
        !          2054:     int32_t len = 0;
        !          2055:     int32_t total = 0;
        !          2056:     size_t offset = 7;
        !          2057:     V9fsFidState *fidp;
        !          2058:     V9fsPDU *pdu = opaque;
        !          2059:     V9fsState *s = pdu->s;
        !          2060:     QEMUIOVector qiov_full;
        !          2061:     QEMUIOVector qiov;
        !          2062: 
        !          2063:     offset += pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
        !          2064:     v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
        !          2065:     trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
1.1       root     2066: 
1.1.1.2 ! root     2067:     fidp = get_fid(pdu, fid);
        !          2068:     if (fidp == NULL) {
1.1       root     2069:         err = -EINVAL;
1.1.1.2 ! root     2070:         goto out_nofid;
1.1       root     2071:     }
1.1.1.2 ! root     2072:     if (fidp->fid_type == P9_FID_FILE) {
        !          2073:         if (fidp->fs.fd == -1) {
1.1       root     2074:             err = -EINVAL;
                   2075:             goto out;
                   2076:         }
1.1.1.2 ! root     2077:     } else if (fidp->fid_type == P9_FID_XATTR) {
1.1       root     2078:         /*
                   2079:          * setxattr operation
                   2080:          */
1.1.1.2 ! root     2081:         err = v9fs_xattr_write(s, pdu, fidp, off, count,
        !          2082:                                qiov_full.iov, qiov_full.niov);
        !          2083:         goto out;
1.1       root     2084:     } else {
                   2085:         err = -EINVAL;
                   2086:         goto out;
                   2087:     }
1.1.1.2 ! root     2088:     qemu_iovec_init(&qiov, qiov_full.niov);
        !          2089:     do {
        !          2090:         qemu_iovec_reset(&qiov);
        !          2091:         qemu_iovec_copy(&qiov, &qiov_full, total, qiov_full.size - total);
        !          2092:         if (0) {
        !          2093:             print_sg(qiov.iov, qiov.niov);
1.1       root     2094:         }
1.1.1.2 ! root     2095:         /* Loop in case of EINTR */
        !          2096:         do {
        !          2097:             len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
        !          2098:             if (len >= 0) {
        !          2099:                 off   += len;
        !          2100:                 total += len;
        !          2101:             }
        !          2102:         } while (len == -EINTR && !pdu->cancelled);
        !          2103:         if (len < 0) {
        !          2104:             /* IO error return the error */
        !          2105:             err = len;
        !          2106:             goto out_qiov;
        !          2107:         }
        !          2108:     } while (total < count && len > 0);
1.1       root     2109: 
1.1.1.2 ! root     2110:     offset = 7;
        !          2111:     offset += pdu_marshal(pdu, offset, "d", total);
        !          2112:     err = offset;
        !          2113:     trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
        !          2114: out_qiov:
        !          2115:     qemu_iovec_destroy(&qiov);
        !          2116: out:
        !          2117:     put_fid(pdu, fidp);
        !          2118: out_nofid:
        !          2119:     qemu_iovec_destroy(&qiov_full);
        !          2120:     complete_pdu(s, pdu, err);
1.1       root     2121: }
                   2122: 
1.1.1.2 ! root     2123: static void v9fs_create(void *opaque)
1.1       root     2124: {
1.1.1.2 ! root     2125:     int32_t fid;
        !          2126:     int err = 0;
        !          2127:     size_t offset = 7;
        !          2128:     V9fsFidState *fidp;
        !          2129:     V9fsQID qid;
        !          2130:     int32_t perm;
        !          2131:     int8_t mode;
        !          2132:     V9fsPath path;
        !          2133:     struct stat stbuf;
        !          2134:     V9fsString name;
        !          2135:     V9fsString extension;
        !          2136:     int iounit;
        !          2137:     V9fsPDU *pdu = opaque;
1.1       root     2138: 
1.1.1.2 ! root     2139:     v9fs_path_init(&path);
1.1       root     2140: 
1.1.1.2 ! root     2141:     pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
        !          2142:                   &perm, &mode, &extension);
1.1       root     2143: 
1.1.1.2 ! root     2144:     trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
1.1       root     2145: 
1.1.1.2 ! root     2146:     fidp = get_fid(pdu, fid);
        !          2147:     if (fidp == NULL) {
        !          2148:         err = -EINVAL;
        !          2149:         goto out_nofid;
1.1       root     2150:     }
1.1.1.2 ! root     2151:     if (perm & P9_STAT_MODE_DIR) {
        !          2152:         err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
        !          2153:                             fidp->uid, -1, &stbuf);
        !          2154:         if (err < 0) {
        !          2155:             goto out;
        !          2156:         }
        !          2157:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2158:         if (err < 0) {
        !          2159:             goto out;
        !          2160:         }
        !          2161:         v9fs_path_copy(&fidp->path, &path);
        !          2162:         err = v9fs_co_opendir(pdu, fidp);
        !          2163:         if (err < 0) {
        !          2164:             goto out;
        !          2165:         }
        !          2166:         fidp->fid_type = P9_FID_DIR;
        !          2167:     } else if (perm & P9_STAT_MODE_SYMLINK) {
        !          2168:         err = v9fs_co_symlink(pdu, fidp, &name,
        !          2169:                               extension.data, -1 , &stbuf);
        !          2170:         if (err < 0) {
        !          2171:             goto out;
        !          2172:         }
        !          2173:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2174:         if (err < 0) {
        !          2175:             goto out;
        !          2176:         }
        !          2177:         v9fs_path_copy(&fidp->path, &path);
        !          2178:     } else if (perm & P9_STAT_MODE_LINK) {
        !          2179:         int32_t ofid = atoi(extension.data);
        !          2180:         V9fsFidState *ofidp = get_fid(pdu, ofid);
        !          2181:         if (ofidp == NULL) {
        !          2182:             err = -EINVAL;
        !          2183:             goto out;
        !          2184:         }
        !          2185:         err = v9fs_co_link(pdu, ofidp, fidp, &name);
        !          2186:         put_fid(pdu, ofidp);
        !          2187:         if (err < 0) {
        !          2188:             goto out;
        !          2189:         }
        !          2190:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2191:         if (err < 0) {
        !          2192:             fidp->fid_type = P9_FID_NONE;
        !          2193:             goto out;
1.1       root     2194:         }
1.1.1.2 ! root     2195:         v9fs_path_copy(&fidp->path, &path);
        !          2196:         err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !          2197:         if (err < 0) {
        !          2198:             fidp->fid_type = P9_FID_NONE;
        !          2199:             goto out;
        !          2200:         }
        !          2201:     } else if (perm & P9_STAT_MODE_DEVICE) {
1.1       root     2202:         char ctype;
                   2203:         uint32_t major, minor;
                   2204:         mode_t nmode = 0;
                   2205: 
1.1.1.2 ! root     2206:         if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
1.1       root     2207:             err = -errno;
1.1.1.2 ! root     2208:             goto out;
1.1       root     2209:         }
                   2210: 
                   2211:         switch (ctype) {
                   2212:         case 'c':
                   2213:             nmode = S_IFCHR;
                   2214:             break;
                   2215:         case 'b':
                   2216:             nmode = S_IFBLK;
                   2217:             break;
                   2218:         default:
                   2219:             err = -EIO;
1.1.1.2 ! root     2220:             goto out;
1.1       root     2221:         }
                   2222: 
1.1.1.2 ! root     2223:         nmode |= perm & 0777;
        !          2224:         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
        !          2225:                             makedev(major, minor), nmode, &stbuf);
        !          2226:         if (err < 0) {
        !          2227:             goto out;
        !          2228:         }
        !          2229:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2230:         if (err < 0) {
        !          2231:             goto out;
        !          2232:         }
        !          2233:         v9fs_path_copy(&fidp->path, &path);
        !          2234:     } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
        !          2235:         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
        !          2236:                             0, S_IFIFO | (perm & 0777), &stbuf);
        !          2237:         if (err < 0) {
        !          2238:             goto out;
        !          2239:         }
        !          2240:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2241:         if (err < 0) {
        !          2242:             goto out;
        !          2243:         }
        !          2244:         v9fs_path_copy(&fidp->path, &path);
        !          2245:     } else if (perm & P9_STAT_MODE_SOCKET) {
        !          2246:         err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
        !          2247:                             0, S_IFSOCK | (perm & 0777), &stbuf);
        !          2248:         if (err < 0) {
        !          2249:             goto out;
        !          2250:         }
        !          2251:         err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
        !          2252:         if (err < 0) {
        !          2253:             goto out;
        !          2254:         }
        !          2255:         v9fs_path_copy(&fidp->path, &path);
1.1       root     2256:     } else {
1.1.1.2 ! root     2257:         err = v9fs_co_open2(pdu, fidp, &name, -1,
        !          2258:                             omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
        !          2259:         if (err < 0) {
        !          2260:             goto out;
        !          2261:         }
        !          2262:         fidp->fid_type = P9_FID_FILE;
        !          2263:         fidp->open_flags = omode_to_uflags(mode);
        !          2264:         if (fidp->open_flags & O_EXCL) {
        !          2265:             /*
        !          2266:              * We let the host file system do O_EXCL check
        !          2267:              * We should not reclaim such fd
        !          2268:              */
        !          2269:             fidp->flags |= FID_NON_RECLAIMABLE;
        !          2270:         }
1.1       root     2271:     }
1.1.1.2 ! root     2272:     iounit = get_iounit(pdu, &fidp->path);
        !          2273:     stat_to_qid(&stbuf, &qid);
        !          2274:     offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
        !          2275:     err = offset;
        !          2276:     trace_v9fs_create_return(pdu->tag, pdu->id,
        !          2277:                              qid.type, qid.version, qid.path, iounit);
1.1       root     2278: out:
1.1.1.2 ! root     2279:     put_fid(pdu, fidp);
        !          2280: out_nofid:
        !          2281:    complete_pdu(pdu->s, pdu, err);
        !          2282:    v9fs_string_free(&name);
        !          2283:    v9fs_string_free(&extension);
        !          2284:    v9fs_path_free(&path);
1.1       root     2285: }
                   2286: 
1.1.1.2 ! root     2287: static void v9fs_symlink(void *opaque)
1.1       root     2288: {
1.1.1.2 ! root     2289:     V9fsPDU *pdu = opaque;
        !          2290:     V9fsString name;
        !          2291:     V9fsString symname;
        !          2292:     V9fsFidState *dfidp;
        !          2293:     V9fsQID qid;
        !          2294:     struct stat stbuf;
        !          2295:     int32_t dfid;
1.1       root     2296:     int err = 0;
1.1.1.2 ! root     2297:     gid_t gid;
        !          2298:     size_t offset = 7;
1.1       root     2299: 
1.1.1.2 ! root     2300:     pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
        !          2301:     trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
1.1       root     2302: 
1.1.1.2 ! root     2303:     dfidp = get_fid(pdu, dfid);
        !          2304:     if (dfidp == NULL) {
1.1       root     2305:         err = -EINVAL;
1.1.1.2 ! root     2306:         goto out_nofid;
1.1       root     2307:     }
1.1.1.2 ! root     2308:     err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
        !          2309:     if (err < 0) {
1.1       root     2310:         goto out;
                   2311:     }
1.1.1.2 ! root     2312:     stat_to_qid(&stbuf, &qid);
        !          2313:     offset += pdu_marshal(pdu, offset, "Q", &qid);
        !          2314:     err = offset;
        !          2315:     trace_v9fs_symlink_return(pdu->tag, pdu->id,
        !          2316:                               qid.type, qid.version, qid.path);
1.1       root     2317: out:
1.1.1.2 ! root     2318:     put_fid(pdu, dfidp);
        !          2319: out_nofid:
        !          2320:     complete_pdu(pdu->s, pdu, err);
        !          2321:     v9fs_string_free(&name);
        !          2322:     v9fs_string_free(&symname);
1.1       root     2323: }
                   2324: 
1.1.1.2 ! root     2325: static void v9fs_flush(void *opaque)
1.1       root     2326: {
1.1.1.2 ! root     2327:     int16_t tag;
        !          2328:     size_t offset = 7;
        !          2329:     V9fsPDU *cancel_pdu;
        !          2330:     V9fsPDU *pdu = opaque;
        !          2331:     V9fsState *s = pdu->s;
1.1       root     2332: 
1.1.1.2 ! root     2333:     pdu_unmarshal(pdu, offset, "w", &tag);
        !          2334:     trace_v9fs_flush(pdu->tag, pdu->id, tag);
1.1       root     2335: 
1.1.1.2 ! root     2336:     QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
        !          2337:         if (cancel_pdu->tag == tag) {
        !          2338:             break;
        !          2339:         }
        !          2340:     }
        !          2341:     if (cancel_pdu) {
        !          2342:         cancel_pdu->cancelled = 1;
        !          2343:         /*
        !          2344:          * Wait for pdu to complete.
        !          2345:          */
        !          2346:         qemu_co_queue_wait(&cancel_pdu->complete);
        !          2347:         cancel_pdu->cancelled = 0;
        !          2348:         free_pdu(pdu->s, cancel_pdu);
1.1       root     2349:     }
                   2350:     complete_pdu(s, pdu, 7);
1.1.1.2 ! root     2351:     return;
1.1       root     2352: }
                   2353: 
1.1.1.2 ! root     2354: static void v9fs_link(void *opaque)
1.1       root     2355: {
1.1.1.2 ! root     2356:     V9fsPDU *pdu = opaque;
        !          2357:     V9fsState *s = pdu->s;
1.1       root     2358:     int32_t dfid, oldfid;
                   2359:     V9fsFidState *dfidp, *oldfidp;
1.1.1.2 ! root     2360:     V9fsString name;;
1.1       root     2361:     size_t offset = 7;
                   2362:     int err = 0;
                   2363: 
                   2364:     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
1.1.1.2 ! root     2365:     trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
1.1       root     2366: 
1.1.1.2 ! root     2367:     dfidp = get_fid(pdu, dfid);
1.1       root     2368:     if (dfidp == NULL) {
1.1.1.2 ! root     2369:         err = -ENOENT;
        !          2370:         goto out_nofid;
1.1       root     2371:     }
                   2372: 
1.1.1.2 ! root     2373:     oldfidp = get_fid(pdu, oldfid);
1.1       root     2374:     if (oldfidp == NULL) {
1.1.1.2 ! root     2375:         err = -ENOENT;
1.1       root     2376:         goto out;
                   2377:     }
1.1.1.2 ! root     2378:     err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
        !          2379:     if (!err) {
        !          2380:         err = offset;
1.1       root     2381:     }
                   2382: out:
1.1.1.2 ! root     2383:     put_fid(pdu, dfidp);
        !          2384: out_nofid:
1.1       root     2385:     v9fs_string_free(&name);
                   2386:     complete_pdu(s, pdu, err);
                   2387: }
                   2388: 
1.1.1.2 ! root     2389: /* Only works with path name based fid */
        !          2390: static void v9fs_remove(void *opaque)
1.1       root     2391: {
1.1.1.2 ! root     2392:     int32_t fid;
        !          2393:     int err = 0;
        !          2394:     size_t offset = 7;
        !          2395:     V9fsFidState *fidp;
        !          2396:     V9fsPDU *pdu = opaque;
        !          2397: 
        !          2398:     pdu_unmarshal(pdu, offset, "d", &fid);
        !          2399:     trace_v9fs_remove(pdu->tag, pdu->id, fid);
        !          2400: 
        !          2401:     fidp = get_fid(pdu, fid);
        !          2402:     if (fidp == NULL) {
        !          2403:         err = -EINVAL;
        !          2404:         goto out_nofid;
        !          2405:     }
        !          2406:     /* if fs driver is not path based, return EOPNOTSUPP */
        !          2407:     if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
        !          2408:         err = -EOPNOTSUPP;
        !          2409:         goto out_err;
        !          2410:     }
        !          2411:     /*
        !          2412:      * IF the file is unlinked, we cannot reopen
        !          2413:      * the file later. So don't reclaim fd
        !          2414:      */
        !          2415:     err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
1.1       root     2416:     if (err < 0) {
1.1.1.2 ! root     2417:         goto out_err;
1.1       root     2418:     }
1.1.1.2 ! root     2419:     err = v9fs_co_remove(pdu, &fidp->path);
        !          2420:     if (!err) {
        !          2421:         err = offset;
        !          2422:     }
        !          2423: out_err:
1.1       root     2424:     /* For TREMOVE we need to clunk the fid even on failed remove */
1.1.1.2 ! root     2425:     clunk_fid(pdu->s, fidp->fid);
        !          2426:     put_fid(pdu, fidp);
        !          2427: out_nofid:
        !          2428:     complete_pdu(pdu->s, pdu, err);
1.1       root     2429: }
                   2430: 
1.1.1.2 ! root     2431: static void v9fs_unlinkat(void *opaque)
1.1       root     2432: {
                   2433:     int err = 0;
1.1.1.2 ! root     2434:     V9fsString name;
        !          2435:     int32_t dfid, flags;
        !          2436:     size_t offset = 7;
        !          2437:     V9fsPath path;
        !          2438:     V9fsFidState *dfidp;
        !          2439:     V9fsPDU *pdu = opaque;
1.1       root     2440: 
1.1.1.2 ! root     2441:     pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
1.1       root     2442: 
1.1.1.2 ! root     2443:     dfidp = get_fid(pdu, dfid);
        !          2444:     if (dfidp == NULL) {
1.1       root     2445:         err = -EINVAL;
1.1.1.2 ! root     2446:         goto out_nofid;
1.1       root     2447:     }
1.1.1.2 ! root     2448:     /*
        !          2449:      * IF the file is unlinked, we cannot reopen
        !          2450:      * the file later. So don't reclaim fd
        !          2451:      */
        !          2452:     v9fs_path_init(&path);
        !          2453:     err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
1.1       root     2454:     if (err < 0) {
1.1.1.2 ! root     2455:         goto out_err;
1.1       root     2456:     }
1.1.1.2 ! root     2457:     err = v9fs_mark_fids_unreclaim(pdu, &path);
1.1       root     2458:     if (err < 0) {
1.1.1.2 ! root     2459:         goto out_err;
1.1       root     2460:     }
1.1.1.2 ! root     2461:     err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
        !          2462:     if (!err) {
        !          2463:         err = offset;
        !          2464:     }
        !          2465: out_err:
        !          2466:     put_fid(pdu, dfidp);
        !          2467:     v9fs_path_free(&path);
        !          2468: out_nofid:
        !          2469:     complete_pdu(pdu->s, pdu, err);
        !          2470:     v9fs_string_free(&name);
1.1       root     2471: }
                   2472: 
1.1.1.2 ! root     2473: 
        !          2474: /* Only works with path name based fid */
        !          2475: static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
        !          2476:                                 int32_t newdirfid, V9fsString *name)
1.1       root     2477: {
1.1.1.2 ! root     2478:     char *end;
1.1       root     2479:     int err = 0;
1.1.1.2 ! root     2480:     V9fsPath new_path;
        !          2481:     V9fsFidState *tfidp;
        !          2482:     V9fsState *s = pdu->s;
        !          2483:     V9fsFidState *dirfidp = NULL;
1.1       root     2484:     char *old_name, *new_name;
                   2485: 
1.1.1.2 ! root     2486:     v9fs_path_init(&new_path);
        !          2487:     if (newdirfid != -1) {
        !          2488:         dirfidp = get_fid(pdu, newdirfid);
1.1       root     2489:         if (dirfidp == NULL) {
                   2490:             err = -ENOENT;
1.1.1.2 ! root     2491:             goto out_nofid;
1.1       root     2492:         }
                   2493:         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
1.1.1.2 ! root     2494:         v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
1.1       root     2495:     } else {
1.1.1.2 ! root     2496:         old_name = fidp->path.data;
1.1       root     2497:         end = strrchr(old_name, '/');
                   2498:         if (end) {
                   2499:             end++;
                   2500:         } else {
                   2501:             end = old_name;
                   2502:         }
1.1.1.2 ! root     2503:         new_name = g_malloc0(end - old_name + name->size + 1);
1.1       root     2504:         strncat(new_name, old_name, end - old_name);
1.1.1.2 ! root     2505:         strncat(new_name + (end - old_name), name->data, name->size);
        !          2506:         v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
        !          2507:         g_free(new_name);
1.1       root     2508:     }
1.1.1.2 ! root     2509:     err = v9fs_co_rename(pdu, &fidp->path, &new_path);
        !          2510:     if (err < 0) {
        !          2511:         goto out;
        !          2512:     }
        !          2513:     /*
        !          2514:      * Fixup fid's pointing to the old name to
        !          2515:      * start pointing to the new name
        !          2516:      */
        !          2517:     for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
        !          2518:         if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
        !          2519:             /* replace the name */
        !          2520:             v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
1.1       root     2521:         }
                   2522:     }
                   2523: out:
1.1.1.2 ! root     2524:     if (dirfidp) {
        !          2525:         put_fid(pdu, dirfidp);
        !          2526:     }
        !          2527:     v9fs_path_free(&new_path);
        !          2528: out_nofid:
1.1       root     2529:     return err;
                   2530: }
                   2531: 
1.1.1.2 ! root     2532: /* Only works with path name based fid */
        !          2533: static void v9fs_rename(void *opaque)
1.1       root     2534: {
1.1.1.2 ! root     2535:     int32_t fid;
        !          2536:     ssize_t err = 0;
        !          2537:     size_t offset = 7;
        !          2538:     V9fsString name;
        !          2539:     int32_t newdirfid;
        !          2540:     V9fsFidState *fidp;
        !          2541:     V9fsPDU *pdu = opaque;
        !          2542:     V9fsState *s = pdu->s;
1.1       root     2543: 
1.1.1.2 ! root     2544:     pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
        !          2545: 
        !          2546:     fidp = get_fid(pdu, fid);
        !          2547:     if (fidp == NULL) {
        !          2548:         err = -ENOENT;
        !          2549:         goto out_nofid;
        !          2550:     }
        !          2551:     BUG_ON(fidp->fid_type != P9_FID_NONE);
        !          2552:     /* if fs driver is not path based, return EOPNOTSUPP */
        !          2553:     if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
        !          2554:         err = -EOPNOTSUPP;
1.1       root     2555:         goto out;
                   2556:     }
1.1.1.2 ! root     2557:     v9fs_path_write_lock(s);
        !          2558:     err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
        !          2559:     v9fs_path_unlock(s);
        !          2560:     if (!err) {
        !          2561:         err = offset;
1.1       root     2562:     }
                   2563: out:
1.1.1.2 ! root     2564:     put_fid(pdu, fidp);
        !          2565: out_nofid:
        !          2566:     complete_pdu(s, pdu, err);
        !          2567:     v9fs_string_free(&name);
1.1       root     2568: }
                   2569: 
1.1.1.2 ! root     2570: static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
        !          2571:                                V9fsString *old_name, V9fsPath *newdir,
        !          2572:                                V9fsString *new_name)
        !          2573: {
        !          2574:     V9fsFidState *tfidp;
        !          2575:     V9fsPath oldpath, newpath;
        !          2576:     V9fsState *s = pdu->s;
1.1       root     2577: 
                   2578: 
1.1.1.2 ! root     2579:     v9fs_path_init(&oldpath);
        !          2580:     v9fs_path_init(&newpath);
        !          2581:     v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
        !          2582:     v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
1.1       root     2583: 
1.1.1.2 ! root     2584:     /*
        !          2585:      * Fixup fid's pointing to the old name to
        !          2586:      * start pointing to the new name
        !          2587:      */
        !          2588:     for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
        !          2589:         if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
        !          2590:             /* replace the name */
        !          2591:             v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
        !          2592:         }
1.1       root     2593:     }
1.1.1.2 ! root     2594:     v9fs_path_free(&oldpath);
        !          2595:     v9fs_path_free(&newpath);
1.1       root     2596: }
                   2597: 
1.1.1.2 ! root     2598: static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
        !          2599:                                   V9fsString *old_name, int32_t newdirfid,
        !          2600:                                   V9fsString *new_name)
1.1       root     2601: {
1.1.1.2 ! root     2602:     int err = 0;
        !          2603:     V9fsState *s = pdu->s;
        !          2604:     V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
        !          2605: 
        !          2606:     olddirfidp = get_fid(pdu, olddirfid);
        !          2607:     if (olddirfidp == NULL) {
        !          2608:         err = -ENOENT;
1.1       root     2609:         goto out;
                   2610:     }
1.1.1.2 ! root     2611:     if (newdirfid != -1) {
        !          2612:         newdirfidp = get_fid(pdu, newdirfid);
        !          2613:         if (newdirfidp == NULL) {
        !          2614:             err = -ENOENT;
        !          2615:             goto out;
1.1       root     2616:         }
1.1.1.2 ! root     2617:     } else {
        !          2618:         newdirfidp = get_fid(pdu, olddirfid);
1.1       root     2619:     }
                   2620: 
1.1.1.2 ! root     2621:     err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
        !          2622:                            &newdirfidp->path, new_name);
1.1       root     2623:     if (err < 0) {
                   2624:         goto out;
                   2625:     }
1.1.1.2 ! root     2626:     if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
        !          2627:         /* Only for path based fid  we need to do the below fixup */
        !          2628:         v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
        !          2629:                            &newdirfidp->path, new_name);
1.1       root     2630:     }
                   2631: out:
1.1.1.2 ! root     2632:     if (olddirfidp) {
        !          2633:         put_fid(pdu, olddirfidp);
        !          2634:     }
        !          2635:     if (newdirfidp) {
        !          2636:         put_fid(pdu, newdirfidp);
1.1       root     2637:     }
1.1.1.2 ! root     2638:     return err;
1.1       root     2639: }
                   2640: 
1.1.1.2 ! root     2641: static void v9fs_renameat(void *opaque)
1.1       root     2642: {
1.1.1.2 ! root     2643:     ssize_t err = 0;
        !          2644:     size_t offset = 7;
        !          2645:     V9fsPDU *pdu = opaque;
        !          2646:     V9fsState *s = pdu->s;
        !          2647:     int32_t olddirfid, newdirfid;
        !          2648:     V9fsString old_name, new_name;
        !          2649: 
        !          2650:     pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
        !          2651:                   &old_name, &newdirfid, &new_name);
        !          2652: 
        !          2653:     v9fs_path_write_lock(s);
        !          2654:     err = v9fs_complete_renameat(pdu, olddirfid,
        !          2655:                                  &old_name, newdirfid, &new_name);
        !          2656:     v9fs_path_unlock(s);
        !          2657:     if (!err) {
        !          2658:         err = offset;
1.1       root     2659:     }
1.1.1.2 ! root     2660:     complete_pdu(s, pdu, err);
        !          2661:     v9fs_string_free(&old_name);
        !          2662:     v9fs_string_free(&new_name);
1.1       root     2663: }
                   2664: 
1.1.1.2 ! root     2665: static void v9fs_wstat(void *opaque)
1.1       root     2666: {
                   2667:     int32_t fid;
                   2668:     int err = 0;
1.1.1.2 ! root     2669:     int16_t unused;
        !          2670:     V9fsStat v9stat;
        !          2671:     size_t offset = 7;
        !          2672:     struct stat stbuf;
        !          2673:     V9fsFidState *fidp;
        !          2674:     V9fsPDU *pdu = opaque;
        !          2675:     V9fsState *s = pdu->s;
1.1       root     2676: 
1.1.1.2 ! root     2677:     pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
        !          2678:     trace_v9fs_wstat(pdu->tag, pdu->id, fid,
        !          2679:                      v9stat.mode, v9stat.atime, v9stat.mtime);
1.1       root     2680: 
1.1.1.2 ! root     2681:     fidp = get_fid(pdu, fid);
        !          2682:     if (fidp == NULL) {
1.1       root     2683:         err = -EINVAL;
1.1.1.2 ! root     2684:         goto out_nofid;
1.1       root     2685:     }
                   2686:     /* do we need to sync the file? */
1.1.1.2 ! root     2687:     if (donttouch_stat(&v9stat)) {
        !          2688:         err = v9fs_co_fsync(pdu, fidp, 0);
        !          2689:         goto out;
1.1       root     2690:     }
1.1.1.2 ! root     2691:     if (v9stat.mode != -1) {
        !          2692:         uint32_t v9_mode;
        !          2693:         err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
        !          2694:         if (err < 0) {
        !          2695:             goto out;
        !          2696:         }
        !          2697:         v9_mode = stat_to_v9mode(&stbuf);
        !          2698:         if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
        !          2699:             (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
        !          2700:             /* Attempting to change the type */
        !          2701:             err = -EIO;
        !          2702:             goto out;
        !          2703:         }
        !          2704:         err = v9fs_co_chmod(pdu, &fidp->path,
        !          2705:                             v9mode_to_mode(v9stat.mode,
        !          2706:                                            &v9stat.extension));
        !          2707:         if (err < 0) {
        !          2708:             goto out;
        !          2709:         }
1.1       root     2710:     }
1.1.1.2 ! root     2711:     if (v9stat.mtime != -1 || v9stat.atime != -1) {
        !          2712:         struct timespec times[2];
        !          2713:         if (v9stat.atime != -1) {
        !          2714:             times[0].tv_sec = v9stat.atime;
        !          2715:             times[0].tv_nsec = 0;
        !          2716:         } else {
        !          2717:             times[0].tv_nsec = UTIME_OMIT;
        !          2718:         }
        !          2719:         if (v9stat.mtime != -1) {
        !          2720:             times[1].tv_sec = v9stat.mtime;
        !          2721:             times[1].tv_nsec = 0;
        !          2722:         } else {
        !          2723:             times[1].tv_nsec = UTIME_OMIT;
        !          2724:         }
        !          2725:         err = v9fs_co_utimensat(pdu, &fidp->path, times);
        !          2726:         if (err < 0) {
        !          2727:             goto out;
        !          2728:         }
        !          2729:     }
        !          2730:     if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
        !          2731:         err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
        !          2732:         if (err < 0) {
        !          2733:             goto out;
        !          2734:         }
        !          2735:     }
        !          2736:     if (v9stat.name.size != 0) {
        !          2737:         err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
        !          2738:         if (err < 0) {
        !          2739:             goto out;
        !          2740:         }
        !          2741:     }
        !          2742:     if (v9stat.length != -1) {
        !          2743:         err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
        !          2744:         if (err < 0) {
        !          2745:             goto out;
        !          2746:         }
        !          2747:     }
        !          2748:     err = offset;
1.1       root     2749: out:
1.1.1.2 ! root     2750:     put_fid(pdu, fidp);
        !          2751: out_nofid:
        !          2752:     v9fs_stat_free(&v9stat);
        !          2753:     complete_pdu(s, pdu, err);
1.1       root     2754: }
                   2755: 
1.1.1.2 ! root     2756: static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
1.1       root     2757: {
1.1.1.2 ! root     2758:     uint32_t f_type;
        !          2759:     uint32_t f_bsize;
        !          2760:     uint64_t f_blocks;
        !          2761:     uint64_t f_bfree;
        !          2762:     uint64_t f_bavail;
        !          2763:     uint64_t f_files;
        !          2764:     uint64_t f_ffree;
        !          2765:     uint64_t fsid_val;
        !          2766:     uint32_t f_namelen;
        !          2767:     size_t offset = 7;
1.1       root     2768:     int32_t bsize_factor;
                   2769: 
                   2770:     /*
                   2771:      * compute bsize factor based on host file system block size
                   2772:      * and client msize
                   2773:      */
1.1.1.2 ! root     2774:     bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
1.1       root     2775:     if (!bsize_factor) {
                   2776:         bsize_factor = 1;
                   2777:     }
1.1.1.2 ! root     2778:     f_type  = stbuf->f_type;
        !          2779:     f_bsize = stbuf->f_bsize;
        !          2780:     f_bsize *= bsize_factor;
1.1       root     2781:     /*
                   2782:      * f_bsize is adjusted(multiplied) by bsize factor, so we need to
                   2783:      * adjust(divide) the number of blocks, free blocks and available
                   2784:      * blocks by bsize factor
                   2785:      */
1.1.1.2 ! root     2786:     f_blocks = stbuf->f_blocks/bsize_factor;
        !          2787:     f_bfree  = stbuf->f_bfree/bsize_factor;
        !          2788:     f_bavail = stbuf->f_bavail/bsize_factor;
        !          2789:     f_files  = stbuf->f_files;
        !          2790:     f_ffree  = stbuf->f_ffree;
        !          2791:     fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
        !          2792:                (unsigned long long)stbuf->f_fsid.__val[1] << 32;
        !          2793:     f_namelen = stbuf->f_namelen;
        !          2794: 
        !          2795:     return pdu_marshal(pdu, offset, "ddqqqqqqd",
        !          2796:                        f_type, f_bsize, f_blocks, f_bfree,
        !          2797:                        f_bavail, f_files, f_ffree,
        !          2798:                        fsid_val, f_namelen);
1.1       root     2799: }
                   2800: 
1.1.1.2 ! root     2801: static void v9fs_statfs(void *opaque)
1.1       root     2802: {
1.1.1.2 ! root     2803:     int32_t fid;
        !          2804:     ssize_t retval = 0;
        !          2805:     size_t offset = 7;
        !          2806:     V9fsFidState *fidp;
        !          2807:     struct statfs stbuf;
        !          2808:     V9fsPDU *pdu = opaque;
        !          2809:     V9fsState *s = pdu->s;
1.1       root     2810: 
1.1.1.2 ! root     2811:     pdu_unmarshal(pdu, offset, "d", &fid);
        !          2812:     fidp = get_fid(pdu, fid);
        !          2813:     if (fidp == NULL) {
        !          2814:         retval = -ENOENT;
        !          2815:         goto out_nofid;
1.1       root     2816:     }
1.1.1.2 ! root     2817:     retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
        !          2818:     if (retval < 0) {
1.1       root     2819:         goto out;
                   2820:     }
1.1.1.2 ! root     2821:     retval = offset;
        !          2822:     retval += v9fs_fill_statfs(s, pdu, &stbuf);
1.1       root     2823: out:
1.1.1.2 ! root     2824:     put_fid(pdu, fidp);
        !          2825: out_nofid:
        !          2826:     complete_pdu(s, pdu, retval);
1.1       root     2827:     return;
                   2828: }
                   2829: 
1.1.1.2 ! root     2830: static void v9fs_mknod(void *opaque)
1.1       root     2831: {
1.1.1.2 ! root     2832: 
        !          2833:     int mode;
        !          2834:     gid_t gid;
1.1       root     2835:     int32_t fid;
1.1.1.2 ! root     2836:     V9fsQID qid;
1.1       root     2837:     int err = 0;
                   2838:     int major, minor;
1.1.1.2 ! root     2839:     size_t offset = 7;
        !          2840:     V9fsString name;
        !          2841:     struct stat stbuf;
        !          2842:     V9fsFidState *fidp;
        !          2843:     V9fsPDU *pdu = opaque;
        !          2844:     V9fsState *s = pdu->s;
1.1       root     2845: 
1.1.1.2 ! root     2846:     pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
        !          2847:                   &major, &minor, &gid);
        !          2848:     trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
1.1       root     2849: 
1.1.1.2 ! root     2850:     fidp = get_fid(pdu, fid);
1.1       root     2851:     if (fidp == NULL) {
                   2852:         err = -ENOENT;
1.1.1.2 ! root     2853:         goto out_nofid;
        !          2854:     }
        !          2855:     err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
        !          2856:                         makedev(major, minor), mode, &stbuf);
        !          2857:     if (err < 0) {
1.1       root     2858:         goto out;
                   2859:     }
1.1.1.2 ! root     2860:     stat_to_qid(&stbuf, &qid);
        !          2861:     err = offset;
        !          2862:     err += pdu_marshal(pdu, offset, "Q", &qid);
        !          2863:     trace_v9fs_mknod_return(pdu->tag, pdu->id,
        !          2864:                             qid.type, qid.version, qid.path);
1.1       root     2865: out:
1.1.1.2 ! root     2866:     put_fid(pdu, fidp);
        !          2867: out_nofid:
        !          2868:     complete_pdu(s, pdu, err);
        !          2869:     v9fs_string_free(&name);
1.1       root     2870: }
                   2871: 
                   2872: /*
                   2873:  * Implement posix byte range locking code
                   2874:  * Server side handling of locking code is very simple, because 9p server in
                   2875:  * QEMU can handle only one client. And most of the lock handling
                   2876:  * (like conflict, merging) etc is done by the VFS layer itself, so no need to
                   2877:  * do any thing in * qemu 9p server side lock code path.
                   2878:  * So when a TLOCK request comes, always return success
                   2879:  */
1.1.1.2 ! root     2880: static void v9fs_lock(void *opaque)
1.1       root     2881: {
1.1.1.2 ! root     2882:     int8_t status;
        !          2883:     V9fsFlock *flock;
        !          2884:     size_t offset = 7;
        !          2885:     struct stat stbuf;
        !          2886:     V9fsFidState *fidp;
1.1       root     2887:     int32_t fid, err = 0;
1.1.1.2 ! root     2888:     V9fsPDU *pdu = opaque;
        !          2889:     V9fsState *s = pdu->s;
        !          2890: 
        !          2891:     flock = g_malloc(sizeof(*flock));
        !          2892:     pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
        !          2893:                   &flock->flags, &flock->start, &flock->length,
        !          2894:                   &flock->proc_id, &flock->client_id);
1.1       root     2895: 
1.1.1.2 ! root     2896:     trace_v9fs_lock(pdu->tag, pdu->id, fid,
        !          2897:                     flock->type, flock->start, flock->length);
1.1       root     2898: 
1.1.1.2 ! root     2899:     status = P9_LOCK_ERROR;
1.1       root     2900: 
                   2901:     /* We support only block flag now (that too ignored currently) */
1.1.1.2 ! root     2902:     if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
1.1       root     2903:         err = -EINVAL;
1.1.1.2 ! root     2904:         goto out_nofid;
1.1       root     2905:     }
1.1.1.2 ! root     2906:     fidp = get_fid(pdu, fid);
        !          2907:     if (fidp == NULL) {
1.1       root     2908:         err = -ENOENT;
1.1.1.2 ! root     2909:         goto out_nofid;
1.1       root     2910:     }
1.1.1.2 ! root     2911:     err = v9fs_co_fstat(pdu, fidp, &stbuf);
1.1       root     2912:     if (err < 0) {
                   2913:         goto out;
                   2914:     }
1.1.1.2 ! root     2915:     status = P9_LOCK_SUCCESS;
1.1       root     2916: out:
1.1.1.2 ! root     2917:     put_fid(pdu, fidp);
        !          2918: out_nofid:
        !          2919:     err = offset;
        !          2920:     err += pdu_marshal(pdu, offset, "b", status);
        !          2921:     trace_v9fs_lock_return(pdu->tag, pdu->id, status);
        !          2922:     complete_pdu(s, pdu, err);
        !          2923:     v9fs_string_free(&flock->client_id);
        !          2924:     g_free(flock);
1.1       root     2925: }
                   2926: 
                   2927: /*
                   2928:  * When a TGETLOCK request comes, always return success because all lock
                   2929:  * handling is done by client's VFS layer.
                   2930:  */
1.1.1.2 ! root     2931: static void v9fs_getlock(void *opaque)
1.1       root     2932: {
1.1.1.2 ! root     2933:     size_t offset = 7;
        !          2934:     struct stat stbuf;
        !          2935:     V9fsFidState *fidp;
        !          2936:     V9fsGetlock *glock;
1.1       root     2937:     int32_t fid, err = 0;
1.1.1.2 ! root     2938:     V9fsPDU *pdu = opaque;
        !          2939:     V9fsState *s = pdu->s;
        !          2940: 
        !          2941:     glock = g_malloc(sizeof(*glock));
        !          2942:     pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
        !          2943:                   &glock->start, &glock->length, &glock->proc_id,
        !          2944:                   &glock->client_id);
1.1       root     2945: 
1.1.1.2 ! root     2946:     trace_v9fs_getlock(pdu->tag, pdu->id, fid,
        !          2947:                        glock->type, glock->start, glock->length);
1.1       root     2948: 
1.1.1.2 ! root     2949:     fidp = get_fid(pdu, fid);
        !          2950:     if (fidp == NULL) {
1.1       root     2951:         err = -ENOENT;
1.1.1.2 ! root     2952:         goto out_nofid;
1.1       root     2953:     }
1.1.1.2 ! root     2954:     err = v9fs_co_fstat(pdu, fidp, &stbuf);
1.1       root     2955:     if (err < 0) {
                   2956:         goto out;
                   2957:     }
1.1.1.2 ! root     2958:     glock->type = P9_LOCK_TYPE_UNLCK;
        !          2959:     offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
        !          2960:                           glock->start, glock->length, glock->proc_id,
        !          2961:                           &glock->client_id);
        !          2962:     err = offset;
        !          2963:     trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start,
        !          2964:                               glock->length, glock->proc_id);
1.1       root     2965: out:
1.1.1.2 ! root     2966:     put_fid(pdu, fidp);
        !          2967: out_nofid:
        !          2968:     complete_pdu(s, pdu, err);
        !          2969:     v9fs_string_free(&glock->client_id);
        !          2970:     g_free(glock);
1.1       root     2971: }
                   2972: 
1.1.1.2 ! root     2973: static void v9fs_mkdir(void *opaque)
1.1       root     2974: {
1.1.1.2 ! root     2975:     V9fsPDU *pdu = opaque;
        !          2976:     size_t offset = 7;
1.1       root     2977:     int32_t fid;
1.1.1.2 ! root     2978:     struct stat stbuf;
        !          2979:     V9fsQID qid;
        !          2980:     V9fsString name;
1.1       root     2981:     V9fsFidState *fidp;
                   2982:     gid_t gid;
                   2983:     int mode;
1.1.1.2 ! root     2984:     int err = 0;
        !          2985: 
        !          2986:     pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
1.1       root     2987: 
1.1.1.2 ! root     2988:     trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
1.1       root     2989: 
1.1.1.2 ! root     2990:     fidp = get_fid(pdu, fid);
1.1       root     2991:     if (fidp == NULL) {
                   2992:         err = -ENOENT;
1.1.1.2 ! root     2993:         goto out_nofid;
1.1       root     2994:     }
1.1.1.2 ! root     2995:     err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
1.1       root     2996:     if (err < 0) {
                   2997:         goto out;
                   2998:     }
1.1.1.2 ! root     2999:     stat_to_qid(&stbuf, &qid);
        !          3000:     offset += pdu_marshal(pdu, offset, "Q", &qid);
        !          3001:     err = offset;
        !          3002:     trace_v9fs_mkdir_return(pdu->tag, pdu->id,
        !          3003:                             qid.type, qid.version, qid.path, err);
1.1       root     3004: out:
1.1.1.2 ! root     3005:     put_fid(pdu, fidp);
        !          3006: out_nofid:
        !          3007:     complete_pdu(pdu->s, pdu, err);
        !          3008:     v9fs_string_free(&name);
1.1       root     3009: }
                   3010: 
1.1.1.2 ! root     3011: static void v9fs_xattrwalk(void *opaque)
1.1       root     3012: {
1.1.1.2 ! root     3013:     int64_t size;
        !          3014:     V9fsString name;
1.1       root     3015:     ssize_t err = 0;
1.1.1.2 ! root     3016:     size_t offset = 7;
1.1       root     3017:     int32_t fid, newfid;
1.1.1.2 ! root     3018:     V9fsFidState *file_fidp;
        !          3019:     V9fsFidState *xattr_fidp = NULL;
        !          3020:     V9fsPDU *pdu = opaque;
        !          3021:     V9fsState *s = pdu->s;
        !          3022: 
        !          3023:     pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
        !          3024:     trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
1.1       root     3025: 
1.1.1.2 ! root     3026:     file_fidp = get_fid(pdu, fid);
        !          3027:     if (file_fidp == NULL) {
1.1       root     3028:         err = -ENOENT;
1.1.1.2 ! root     3029:         goto out_nofid;
1.1       root     3030:     }
1.1.1.2 ! root     3031:     xattr_fidp = alloc_fid(s, newfid);
        !          3032:     if (xattr_fidp == NULL) {
1.1       root     3033:         err = -EINVAL;
                   3034:         goto out;
                   3035:     }
1.1.1.2 ! root     3036:     v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
        !          3037:     if (name.data[0] == 0) {
1.1       root     3038:         /*
                   3039:          * listxattr request. Get the size first
                   3040:          */
1.1.1.2 ! root     3041:         size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
        !          3042:         if (size < 0) {
        !          3043:             err = size;
        !          3044:             clunk_fid(s, xattr_fidp->fid);
        !          3045:             goto out;
        !          3046:         }
        !          3047:         /*
        !          3048:          * Read the xattr value
        !          3049:          */
        !          3050:         xattr_fidp->fs.xattr.len = size;
        !          3051:         xattr_fidp->fid_type = P9_FID_XATTR;
        !          3052:         xattr_fidp->fs.xattr.copied_len = -1;
        !          3053:         if (size) {
        !          3054:             xattr_fidp->fs.xattr.value = g_malloc(size);
        !          3055:             err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
        !          3056:                                      xattr_fidp->fs.xattr.value,
        !          3057:                                      xattr_fidp->fs.xattr.len);
        !          3058:             if (err < 0) {
        !          3059:                 clunk_fid(s, xattr_fidp->fid);
        !          3060:                 goto out;
        !          3061:             }
1.1       root     3062:         }
1.1.1.2 ! root     3063:         offset += pdu_marshal(pdu, offset, "q", size);
        !          3064:         err = offset;
1.1       root     3065:     } else {
                   3066:         /*
                   3067:          * specific xattr fid. We check for xattr
                   3068:          * presence also collect the xattr size
                   3069:          */
1.1.1.2 ! root     3070:         size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
        !          3071:                                  &name, NULL, 0);
        !          3072:         if (size < 0) {
        !          3073:             err = size;
        !          3074:             clunk_fid(s, xattr_fidp->fid);
        !          3075:             goto out;
        !          3076:         }
        !          3077:         /*
        !          3078:          * Read the xattr value
        !          3079:          */
        !          3080:         xattr_fidp->fs.xattr.len = size;
        !          3081:         xattr_fidp->fid_type = P9_FID_XATTR;
        !          3082:         xattr_fidp->fs.xattr.copied_len = -1;
        !          3083:         if (size) {
        !          3084:             xattr_fidp->fs.xattr.value = g_malloc(size);
        !          3085:             err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
        !          3086:                                     &name, xattr_fidp->fs.xattr.value,
        !          3087:                                     xattr_fidp->fs.xattr.len);
        !          3088:             if (err < 0) {
        !          3089:                 clunk_fid(s, xattr_fidp->fid);
        !          3090:                 goto out;
        !          3091:             }
1.1       root     3092:         }
1.1.1.2 ! root     3093:         offset += pdu_marshal(pdu, offset, "q", size);
        !          3094:         err = offset;
1.1       root     3095:     }
1.1.1.2 ! root     3096:     trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
1.1       root     3097: out:
1.1.1.2 ! root     3098:     put_fid(pdu, file_fidp);
        !          3099:     if (xattr_fidp) {
        !          3100:         put_fid(pdu, xattr_fidp);
        !          3101:     }
        !          3102: out_nofid:
        !          3103:     complete_pdu(s, pdu, err);
        !          3104:     v9fs_string_free(&name);
1.1       root     3105: }
                   3106: 
1.1.1.2 ! root     3107: static void v9fs_xattrcreate(void *opaque)
1.1       root     3108: {
                   3109:     int flags;
                   3110:     int32_t fid;
1.1.1.2 ! root     3111:     int64_t size;
1.1       root     3112:     ssize_t err = 0;
1.1.1.2 ! root     3113:     V9fsString name;
        !          3114:     size_t offset = 7;
        !          3115:     V9fsFidState *file_fidp;
        !          3116:     V9fsFidState *xattr_fidp;
        !          3117:     V9fsPDU *pdu = opaque;
        !          3118:     V9fsState *s = pdu->s;
        !          3119: 
        !          3120:     pdu_unmarshal(pdu, offset, "dsqd",
        !          3121:                   &fid, &name, &size, &flags);
        !          3122:     trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
1.1       root     3123: 
1.1.1.2 ! root     3124:     file_fidp = get_fid(pdu, fid);
        !          3125:     if (file_fidp == NULL) {
1.1       root     3126:         err = -EINVAL;
1.1.1.2 ! root     3127:         goto out_nofid;
1.1       root     3128:     }
                   3129:     /* Make the file fid point to xattr */
1.1.1.2 ! root     3130:     xattr_fidp = file_fidp;
        !          3131:     xattr_fidp->fid_type = P9_FID_XATTR;
        !          3132:     xattr_fidp->fs.xattr.copied_len = 0;
        !          3133:     xattr_fidp->fs.xattr.len = size;
        !          3134:     xattr_fidp->fs.xattr.flags = flags;
        !          3135:     v9fs_string_init(&xattr_fidp->fs.xattr.name);
        !          3136:     v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
        !          3137:     if (size) {
        !          3138:         xattr_fidp->fs.xattr.value = g_malloc(size);
        !          3139:     } else {
        !          3140:         xattr_fidp->fs.xattr.value = NULL;
1.1       root     3141:     }
1.1.1.2 ! root     3142:     err = offset;
        !          3143:     put_fid(pdu, file_fidp);
        !          3144: out_nofid:
        !          3145:     complete_pdu(s, pdu, err);
        !          3146:     v9fs_string_free(&name);
1.1       root     3147: }
                   3148: 
1.1.1.2 ! root     3149: static void v9fs_readlink(void *opaque)
1.1       root     3150: {
1.1.1.2 ! root     3151:     V9fsPDU *pdu = opaque;
        !          3152:     size_t offset = 7;
        !          3153:     V9fsString target;
1.1       root     3154:     int32_t fid;
                   3155:     int err = 0;
                   3156:     V9fsFidState *fidp;
                   3157: 
1.1.1.2 ! root     3158:     pdu_unmarshal(pdu, offset, "d", &fid);
        !          3159:     trace_v9fs_readlink(pdu->tag, pdu->id, fid);
        !          3160:     fidp = get_fid(pdu, fid);
1.1       root     3161:     if (fidp == NULL) {
                   3162:         err = -ENOENT;
1.1.1.2 ! root     3163:         goto out_nofid;
1.1       root     3164:     }
                   3165: 
1.1.1.2 ! root     3166:     v9fs_string_init(&target);
        !          3167:     err = v9fs_co_readlink(pdu, &fidp->path, &target);
        !          3168:     if (err < 0) {
        !          3169:         goto out;
        !          3170:     }
        !          3171:     offset += pdu_marshal(pdu, offset, "s", &target);
        !          3172:     err = offset;
        !          3173:     trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
        !          3174:     v9fs_string_free(&target);
1.1       root     3175: out:
1.1.1.2 ! root     3176:     put_fid(pdu, fidp);
        !          3177: out_nofid:
        !          3178:     complete_pdu(pdu->s, pdu, err);
1.1       root     3179: }
                   3180: 
1.1.1.2 ! root     3181: static CoroutineEntry *pdu_co_handlers[] = {
1.1       root     3182:     [P9_TREADDIR] = v9fs_readdir,
                   3183:     [P9_TSTATFS] = v9fs_statfs,
                   3184:     [P9_TGETATTR] = v9fs_getattr,
                   3185:     [P9_TSETATTR] = v9fs_setattr,
                   3186:     [P9_TXATTRWALK] = v9fs_xattrwalk,
                   3187:     [P9_TXATTRCREATE] = v9fs_xattrcreate,
                   3188:     [P9_TMKNOD] = v9fs_mknod,
                   3189:     [P9_TRENAME] = v9fs_rename,
                   3190:     [P9_TLOCK] = v9fs_lock,
                   3191:     [P9_TGETLOCK] = v9fs_getlock,
1.1.1.2 ! root     3192:     [P9_TRENAMEAT] = v9fs_renameat,
1.1       root     3193:     [P9_TREADLINK] = v9fs_readlink,
1.1.1.2 ! root     3194:     [P9_TUNLINKAT] = v9fs_unlinkat,
1.1       root     3195:     [P9_TMKDIR] = v9fs_mkdir,
                   3196:     [P9_TVERSION] = v9fs_version,
                   3197:     [P9_TLOPEN] = v9fs_open,
                   3198:     [P9_TATTACH] = v9fs_attach,
                   3199:     [P9_TSTAT] = v9fs_stat,
                   3200:     [P9_TWALK] = v9fs_walk,
                   3201:     [P9_TCLUNK] = v9fs_clunk,
                   3202:     [P9_TFSYNC] = v9fs_fsync,
                   3203:     [P9_TOPEN] = v9fs_open,
                   3204:     [P9_TREAD] = v9fs_read,
                   3205: #if 0
                   3206:     [P9_TAUTH] = v9fs_auth,
                   3207: #endif
                   3208:     [P9_TFLUSH] = v9fs_flush,
                   3209:     [P9_TLINK] = v9fs_link,
                   3210:     [P9_TSYMLINK] = v9fs_symlink,
                   3211:     [P9_TCREATE] = v9fs_create,
                   3212:     [P9_TLCREATE] = v9fs_lcreate,
                   3213:     [P9_TWRITE] = v9fs_write,
                   3214:     [P9_TWSTAT] = v9fs_wstat,
                   3215:     [P9_TREMOVE] = v9fs_remove,
                   3216: };
                   3217: 
1.1.1.2 ! root     3218: static void v9fs_op_not_supp(void *opaque)
1.1       root     3219: {
1.1.1.2 ! root     3220:     V9fsPDU *pdu = opaque;
        !          3221:     complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
        !          3222: }
        !          3223: 
        !          3224: static void v9fs_fs_ro(void *opaque)
        !          3225: {
        !          3226:     V9fsPDU *pdu = opaque;
        !          3227:     complete_pdu(pdu->s, pdu, -EROFS);
        !          3228: }
        !          3229: 
        !          3230: static inline bool is_read_only_op(V9fsPDU *pdu)
        !          3231: {
        !          3232:     switch (pdu->id) {
        !          3233:     case P9_TREADDIR:
        !          3234:     case P9_TSTATFS:
        !          3235:     case P9_TGETATTR:
        !          3236:     case P9_TXATTRWALK:
        !          3237:     case P9_TLOCK:
        !          3238:     case P9_TGETLOCK:
        !          3239:     case P9_TREADLINK:
        !          3240:     case P9_TVERSION:
        !          3241:     case P9_TLOPEN:
        !          3242:     case P9_TATTACH:
        !          3243:     case P9_TSTAT:
        !          3244:     case P9_TWALK:
        !          3245:     case P9_TCLUNK:
        !          3246:     case P9_TFSYNC:
        !          3247:     case P9_TOPEN:
        !          3248:     case P9_TREAD:
        !          3249:     case P9_TAUTH:
        !          3250:     case P9_TFLUSH:
        !          3251:         return 1;
        !          3252:     default:
        !          3253:         return 0;
        !          3254:     }
1.1       root     3255: }
                   3256: 
                   3257: static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
                   3258: {
1.1.1.2 ! root     3259:     Coroutine *co;
        !          3260:     CoroutineEntry *handler;
1.1       root     3261: 
1.1.1.2 ! root     3262:     if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
        !          3263:         (pdu_co_handlers[pdu->id] == NULL)) {
1.1       root     3264:         handler = v9fs_op_not_supp;
                   3265:     } else {
1.1.1.2 ! root     3266:         handler = pdu_co_handlers[pdu->id];
        !          3267:     }
        !          3268: 
        !          3269:     if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
        !          3270:         handler = v9fs_fs_ro;
1.1       root     3271:     }
1.1.1.2 ! root     3272:     co = qemu_coroutine_create(handler);
        !          3273:     qemu_coroutine_enter(co, pdu);
1.1       root     3274: }
                   3275: 
                   3276: void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
                   3277: {
                   3278:     V9fsState *s = (V9fsState *)vdev;
                   3279:     V9fsPDU *pdu;
                   3280:     ssize_t len;
                   3281: 
                   3282:     while ((pdu = alloc_pdu(s)) &&
                   3283:             (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
                   3284:         uint8_t *ptr;
1.1.1.2 ! root     3285:         pdu->s = s;
1.1       root     3286:         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
                   3287:         BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
                   3288: 
                   3289:         ptr = pdu->elem.out_sg[0].iov_base;
                   3290: 
                   3291:         memcpy(&pdu->size, ptr, 4);
                   3292:         pdu->id = ptr[4];
                   3293:         memcpy(&pdu->tag, ptr + 5, 2);
1.1.1.2 ! root     3294:         qemu_co_queue_init(&pdu->complete);
1.1       root     3295:         submit_pdu(s, pdu);
                   3296:     }
                   3297:     free_pdu(s, pdu);
                   3298: }
1.1.1.2 ! root     3299: 
        !          3300: void virtio_9p_set_fd_limit(void)
        !          3301: {
        !          3302:     struct rlimit rlim;
        !          3303:     if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
        !          3304:         fprintf(stderr, "Failed to get the resource limit\n");
        !          3305:         exit(1);
        !          3306:     }
        !          3307:     open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
        !          3308:     open_fd_rc = rlim.rlim_cur/2;
        !          3309: }

unix.superglobalmegacorp.com

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