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

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

unix.superglobalmegacorp.com

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