Statistics
| Branch: | Revision:

root / hw / virtio-9p.c @ b2c224be

History | View | Annotate | Download (71 kB)

1
/*
2
 * Virtio 9p backend
3
 *
4
 * Copyright IBM, Corp. 2010
5
 *
6
 * Authors:
7
 *  Anthony Liguori   <aliguori@us.ibm.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 *
12
 */
13

    
14
#include "virtio.h"
15
#include "pc.h"
16
#include "qemu_socket.h"
17
#include "virtio-9p.h"
18
#include "fsdev/qemu-fsdev.h"
19
#include "virtio-9p-debug.h"
20

    
21
int dotu = 1;
22
int debug_9p_pdu;
23

    
24
enum {
25
    Oread   = 0x00,
26
    Owrite  = 0x01,
27
    Ordwr   = 0x02,
28
    Oexec   = 0x03,
29
    Oexcl   = 0x04,
30
    Otrunc  = 0x10,
31
    Orexec  = 0x20,
32
    Orclose = 0x40,
33
    Oappend = 0x80,
34
};
35

    
36
static int omode_to_uflags(int8_t mode)
37
{
38
    int ret = 0;
39

    
40
    switch (mode & 3) {
41
    case Oread:
42
        ret = O_RDONLY;
43
        break;
44
    case Ordwr:
45
        ret = O_RDWR;
46
        break;
47
    case Owrite:
48
        ret = O_WRONLY;
49
        break;
50
    case Oexec:
51
        ret = O_RDONLY;
52
        break;
53
    }
54

    
55
    if (mode & Otrunc) {
56
        ret |= O_TRUNC;
57
    }
58

    
59
    if (mode & Oappend) {
60
        ret |= O_APPEND;
61
    }
62

    
63
    if (mode & Oexcl) {
64
        ret |= O_EXCL;
65
    }
66

    
67
    return ret;
68
}
69

    
70
void cred_init(FsCred *credp)
71
{
72
    credp->fc_uid = -1;
73
    credp->fc_gid = -1;
74
    credp->fc_mode = -1;
75
    credp->fc_rdev = -1;
76
}
77

    
78
static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
79
{
80
    return s->ops->lstat(&s->ctx, path->data, stbuf);
81
}
82

    
83
static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
84
{
85
    ssize_t len;
86

    
87
    buf->data = qemu_malloc(1024);
88

    
89
    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
90
    if (len > -1) {
91
        buf->size = len;
92
        buf->data[len] = 0;
93
    }
94

    
95
    return len;
96
}
97

    
98
static int v9fs_do_close(V9fsState *s, int fd)
99
{
100
    return s->ops->close(&s->ctx, fd);
101
}
102

    
103
static int v9fs_do_closedir(V9fsState *s, DIR *dir)
104
{
105
    return s->ops->closedir(&s->ctx, dir);
106
}
107

    
108
static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
109
{
110
    return s->ops->open(&s->ctx, path->data, flags);
111
}
112

    
113
static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
114
{
115
    return s->ops->opendir(&s->ctx, path->data);
116
}
117

    
118
static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
119
{
120
    return s->ops->rewinddir(&s->ctx, dir);
121
}
122

    
123
static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
124
{
125
    return s->ops->telldir(&s->ctx, dir);
126
}
127

    
128
static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
129
{
130
    return s->ops->readdir(&s->ctx, dir);
131
}
132

    
133
static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
134
{
135
    return s->ops->seekdir(&s->ctx, dir, off);
136
}
137

    
138
static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
139
                            int iovcnt)
140
{
141
    return s->ops->readv(&s->ctx, fd, iov, iovcnt);
142
}
143

    
144
static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
145
{
146
    return s->ops->lseek(&s->ctx, fd, offset, whence);
147
}
148

    
149
static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
150
                       int iovcnt)
151
{
152
    return s->ops->writev(&s->ctx, fd, iov, iovcnt);
153
}
154

    
155
static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
156
{
157
    FsCred cred;
158
    cred_init(&cred);
159
    cred.fc_mode = mode;
160
    return s->ops->chmod(&s->ctx, path->data, &cred);
161
}
162

    
163
static int v9fs_do_mknod(V9fsState *s, V9fsCreateState *vs, mode_t mode,
164
        dev_t dev)
165
{
166
    FsCred cred;
167
    cred_init(&cred);
168
    cred.fc_uid = vs->fidp->uid;
169
    cred.fc_mode = mode;
170
    cred.fc_rdev = dev;
171
    return s->ops->mknod(&s->ctx, vs->fullname.data, &cred);
172
}
173

    
174
static int v9fs_do_mkdir(V9fsState *s, V9fsCreateState *vs)
175
{
176
    FsCred cred;
177

    
178
    cred_init(&cred);
179
    cred.fc_uid = vs->fidp->uid;
180
    cred.fc_mode = vs->perm & 0777;
181

    
182
    return s->ops->mkdir(&s->ctx, vs->fullname.data, &cred);
183
}
184

    
185
static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
186
{
187
    return s->ops->fstat(&s->ctx, fd, stbuf);
188
}
189

    
190
static int v9fs_do_open2(V9fsState *s, V9fsCreateState *vs)
191
{
192
    FsCred cred;
193
    int flags;
194

    
195
    cred_init(&cred);
196
    cred.fc_uid = vs->fidp->uid;
197
    cred.fc_mode = vs->perm & 0777;
198
    flags = omode_to_uflags(vs->mode) | O_CREAT;
199

    
200
    return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
201
}
202

    
203
static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
204
{
205
    FsCred cred;
206
    cred_init(&cred);
207
    cred.fc_uid = vs->fidp->uid;
208
    cred.fc_mode = vs->perm | 0777;
209

    
210
    return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
211
            &cred);
212
}
213

    
214
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
215
{
216
    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
217
}
218

    
219
static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
220
{
221
    return s->ops->truncate(&s->ctx, path->data, size);
222
}
223

    
224
static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
225
                            V9fsString *newpath)
226
{
227
    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
228
}
229

    
230
static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
231
{
232
    FsCred cred;
233
    cred_init(&cred);
234
    cred.fc_uid = uid;
235
    cred.fc_gid = gid;
236

    
237
    return s->ops->chown(&s->ctx, path->data, &cred);
238
}
239

    
240
static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
241
                                           const struct timespec times[2])
242
{
243
    return s->ops->utimensat(&s->ctx, path->data, times);
244
}
245

    
246
static int v9fs_do_remove(V9fsState *s, V9fsString *path)
247
{
248
    return s->ops->remove(&s->ctx, path->data);
249
}
250

    
251
static int v9fs_do_fsync(V9fsState *s, int fd)
252
{
253
    return s->ops->fsync(&s->ctx, fd);
254
}
255

    
256
static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
257
{
258
    return s->ops->statfs(&s->ctx, path->data, stbuf);
259
}
260

    
261
static void v9fs_string_init(V9fsString *str)
262
{
263
    str->data = NULL;
264
    str->size = 0;
265
}
266

    
267
static void v9fs_string_free(V9fsString *str)
268
{
269
    qemu_free(str->data);
270
    str->data = NULL;
271
    str->size = 0;
272
}
273

    
274
static void v9fs_string_null(V9fsString *str)
275
{
276
    v9fs_string_free(str);
277
}
278

    
279
static int number_to_string(void *arg, char type)
280
{
281
    unsigned int ret = 0;
282

    
283
    switch (type) {
284
    case 'u': {
285
        unsigned int num = *(unsigned int *)arg;
286

    
287
        do {
288
            ret++;
289
            num = num/10;
290
        } while (num);
291
        break;
292
    }
293
    default:
294
        printf("Number_to_string: Unknown number format\n");
295
        return -1;
296
    }
297

    
298
    return ret;
299
}
300

    
301
static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
302
{
303
    va_list ap2;
304
    char *iter = (char *)fmt;
305
    int len = 0;
306
    int nr_args = 0;
307
    char *arg_char_ptr;
308
    unsigned int arg_uint;
309

    
310
    /* Find the number of %'s that denotes an argument */
311
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
312
        nr_args++;
313
        iter++;
314
    }
315

    
316
    len = strlen(fmt) - 2*nr_args;
317

    
318
    if (!nr_args) {
319
        goto alloc_print;
320
    }
321

    
322
    va_copy(ap2, ap);
323

    
324
    iter = (char *)fmt;
325

    
326
    /* Now parse the format string */
327
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
328
        iter++;
329
        switch (*iter) {
330
        case 'u':
331
            arg_uint = va_arg(ap2, unsigned int);
332
            len += number_to_string((void *)&arg_uint, 'u');
333
            break;
334
        case 's':
335
            arg_char_ptr = va_arg(ap2, char *);
336
            len += strlen(arg_char_ptr);
337
            break;
338
        case 'c':
339
            len += 1;
340
            break;
341
        default:
342
            fprintf(stderr,
343
                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
344
            return -1;
345
        }
346
        iter++;
347
    }
348

    
349
alloc_print:
350
    *strp = qemu_malloc((len + 1) * sizeof(**strp));
351

    
352
    return vsprintf(*strp, fmt, ap);
353
}
354

    
355
static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
356
{
357
    va_list ap;
358
    int err;
359

    
360
    v9fs_string_free(str);
361

    
362
    va_start(ap, fmt);
363
    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
364
    BUG_ON(err == -1);
365
    va_end(ap);
366

    
367
    str->size = err;
368
}
369

    
370
static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
371
{
372
    v9fs_string_free(lhs);
373
    v9fs_string_sprintf(lhs, "%s", rhs->data);
374
}
375

    
376
static size_t v9fs_string_size(V9fsString *str)
377
{
378
    return str->size;
379
}
380

    
381
static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
382
{
383
    V9fsFidState *f;
384

    
385
    for (f = s->fid_list; f; f = f->next) {
386
        if (f->fid == fid) {
387
            return f;
388
        }
389
    }
390

    
391
    return NULL;
392
}
393

    
394
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
395
{
396
    V9fsFidState *f;
397

    
398
    f = lookup_fid(s, fid);
399
    if (f) {
400
        return NULL;
401
    }
402

    
403
    f = qemu_mallocz(sizeof(V9fsFidState));
404

    
405
    f->fid = fid;
406
    f->fd = -1;
407
    f->dir = NULL;
408

    
409
    f->next = s->fid_list;
410
    s->fid_list = f;
411

    
412
    return f;
413
}
414

    
415
static int free_fid(V9fsState *s, int32_t fid)
416
{
417
    V9fsFidState **fidpp, *fidp;
418

    
419
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
420
        if ((*fidpp)->fid == fid) {
421
            break;
422
        }
423
    }
424

    
425
    if (*fidpp == NULL) {
426
        return -ENOENT;
427
    }
428

    
429
    fidp = *fidpp;
430
    *fidpp = fidp->next;
431

    
432
    if (fidp->fd != -1) {
433
        v9fs_do_close(s, fidp->fd);
434
    }
435
    if (fidp->dir) {
436
        v9fs_do_closedir(s, fidp->dir);
437
    }
438
    v9fs_string_free(&fidp->path);
439
    qemu_free(fidp);
440

    
441
    return 0;
442
}
443

    
444
#define P9_QID_TYPE_DIR         0x80
445
#define P9_QID_TYPE_SYMLINK     0x02
446

    
447
#define P9_STAT_MODE_DIR        0x80000000
448
#define P9_STAT_MODE_APPEND     0x40000000
449
#define P9_STAT_MODE_EXCL       0x20000000
450
#define P9_STAT_MODE_MOUNT      0x10000000
451
#define P9_STAT_MODE_AUTH       0x08000000
452
#define P9_STAT_MODE_TMP        0x04000000
453
#define P9_STAT_MODE_SYMLINK    0x02000000
454
#define P9_STAT_MODE_LINK       0x01000000
455
#define P9_STAT_MODE_DEVICE     0x00800000
456
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
457
#define P9_STAT_MODE_SOCKET     0x00100000
458
#define P9_STAT_MODE_SETUID     0x00080000
459
#define P9_STAT_MODE_SETGID     0x00040000
460
#define P9_STAT_MODE_SETVTX     0x00010000
461

    
462
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
463
                                P9_STAT_MODE_SYMLINK |      \
464
                                P9_STAT_MODE_LINK |         \
465
                                P9_STAT_MODE_DEVICE |       \
466
                                P9_STAT_MODE_NAMED_PIPE |   \
467
                                P9_STAT_MODE_SOCKET)
468

    
469
/* This is the algorithm from ufs in spfs */
470
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
471
{
472
    size_t size;
473

    
474
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
475
    memcpy(&qidp->path, &stbuf->st_ino, size);
476
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
477
    qidp->type = 0;
478
    if (S_ISDIR(stbuf->st_mode)) {
479
        qidp->type |= P9_QID_TYPE_DIR;
480
    }
481
    if (S_ISLNK(stbuf->st_mode)) {
482
        qidp->type |= P9_QID_TYPE_SYMLINK;
483
    }
484
}
485

    
486
static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
487
{
488
    struct stat stbuf;
489
    int err;
490

    
491
    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
492
    if (err) {
493
        return err;
494
    }
495

    
496
    stat_to_qid(&stbuf, qidp);
497
    return 0;
498
}
499

    
500
static V9fsPDU *alloc_pdu(V9fsState *s)
501
{
502
    V9fsPDU *pdu = NULL;
503

    
504
    if (!QLIST_EMPTY(&s->free_list)) {
505
        pdu = QLIST_FIRST(&s->free_list);
506
        QLIST_REMOVE(pdu, next);
507
    }
508
    return pdu;
509
}
510

    
511
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
512
{
513
    if (pdu) {
514
        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
515
    }
516
}
517

    
518
size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
519
                        size_t offset, size_t size, int pack)
520
{
521
    int i = 0;
522
    size_t copied = 0;
523

    
524
    for (i = 0; size && i < sg_count; i++) {
525
        size_t len;
526
        if (offset >= sg[i].iov_len) {
527
            /* skip this sg */
528
            offset -= sg[i].iov_len;
529
            continue;
530
        } else {
531
            len = MIN(sg[i].iov_len - offset, size);
532
            if (pack) {
533
                memcpy(sg[i].iov_base + offset, addr, len);
534
            } else {
535
                memcpy(addr, sg[i].iov_base + offset, len);
536
            }
537
            size -= len;
538
            copied += len;
539
            addr += len;
540
            if (size) {
541
                offset = 0;
542
                continue;
543
            }
544
        }
545
    }
546

    
547
    return copied;
548
}
549

    
550
static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
551
{
552
    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
553
                         offset, size, 0);
554
}
555

    
556
static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
557
                        size_t size)
558
{
559
    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
560
                             offset, size, 1);
561
}
562

    
563
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
564
{
565
    size_t pos = 0;
566
    int i, j;
567
    struct iovec *src_sg;
568
    unsigned int num;
569

    
570
    if (rx) {
571
        src_sg = pdu->elem.in_sg;
572
        num = pdu->elem.in_num;
573
    } else {
574
        src_sg = pdu->elem.out_sg;
575
        num = pdu->elem.out_num;
576
    }
577

    
578
    j = 0;
579
    for (i = 0; i < num; i++) {
580
        if (offset <= pos) {
581
            sg[j].iov_base = src_sg[i].iov_base;
582
            sg[j].iov_len = src_sg[i].iov_len;
583
            j++;
584
        } else if (offset < (src_sg[i].iov_len + pos)) {
585
            sg[j].iov_base = src_sg[i].iov_base;
586
            sg[j].iov_len = src_sg[i].iov_len;
587
            sg[j].iov_base += (offset - pos);
588
            sg[j].iov_len -= (offset - pos);
589
            j++;
590
        }
591
        pos += src_sg[i].iov_len;
592
    }
593

    
594
    return j;
595
}
596

    
597
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
598
{
599
    size_t old_offset = offset;
600
    va_list ap;
601
    int i;
602

    
603
    va_start(ap, fmt);
604
    for (i = 0; fmt[i]; i++) {
605
        switch (fmt[i]) {
606
        case 'b': {
607
            uint8_t *valp = va_arg(ap, uint8_t *);
608
            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
609
            break;
610
        }
611
        case 'w': {
612
            uint16_t val, *valp;
613
            valp = va_arg(ap, uint16_t *);
614
            val = le16_to_cpupu(valp);
615
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
616
            *valp = val;
617
            break;
618
        }
619
        case 'd': {
620
            uint32_t val, *valp;
621
            valp = va_arg(ap, uint32_t *);
622
            val = le32_to_cpupu(valp);
623
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
624
            *valp = val;
625
            break;
626
        }
627
        case 'q': {
628
            uint64_t val, *valp;
629
            valp = va_arg(ap, uint64_t *);
630
            val = le64_to_cpup(valp);
631
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
632
            *valp = val;
633
            break;
634
        }
635
        case 'v': {
636
            struct iovec *iov = va_arg(ap, struct iovec *);
637
            int *iovcnt = va_arg(ap, int *);
638
            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
639
            break;
640
        }
641
        case 's': {
642
            V9fsString *str = va_arg(ap, V9fsString *);
643
            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
644
            /* FIXME: sanity check str->size */
645
            str->data = qemu_malloc(str->size + 1);
646
            offset += pdu_unpack(str->data, pdu, offset, str->size);
647
            str->data[str->size] = 0;
648
            break;
649
        }
650
        case 'Q': {
651
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
652
            offset += pdu_unmarshal(pdu, offset, "bdq",
653
                        &qidp->type, &qidp->version, &qidp->path);
654
            break;
655
        }
656
        case 'S': {
657
            V9fsStat *statp = va_arg(ap, V9fsStat *);
658
            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
659
                        &statp->size, &statp->type, &statp->dev,
660
                        &statp->qid, &statp->mode, &statp->atime,
661
                        &statp->mtime, &statp->length,
662
                        &statp->name, &statp->uid, &statp->gid,
663
                        &statp->muid, &statp->extension,
664
                        &statp->n_uid, &statp->n_gid,
665
                        &statp->n_muid);
666
            break;
667
        }
668
        case 'I': {
669
            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
670
            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
671
                        &iattr->valid, &iattr->mode,
672
                        &iattr->uid, &iattr->gid, &iattr->size,
673
                        &iattr->atime_sec, &iattr->atime_nsec,
674
                        &iattr->mtime_sec, &iattr->mtime_nsec);
675
            break;
676
        }
677
        default:
678
            break;
679
        }
680
    }
681

    
682
    va_end(ap);
683

    
684
    return offset - old_offset;
685
}
686

    
687
static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
688
{
689
    size_t old_offset = offset;
690
    va_list ap;
691
    int i;
692

    
693
    va_start(ap, fmt);
694
    for (i = 0; fmt[i]; i++) {
695
        switch (fmt[i]) {
696
        case 'b': {
697
            uint8_t val = va_arg(ap, int);
698
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
699
            break;
700
        }
701
        case 'w': {
702
            uint16_t val;
703
            cpu_to_le16w(&val, va_arg(ap, int));
704
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
705
            break;
706
        }
707
        case 'd': {
708
            uint32_t val;
709
            cpu_to_le32w(&val, va_arg(ap, uint32_t));
710
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
711
            break;
712
        }
713
        case 'q': {
714
            uint64_t val;
715
            cpu_to_le64w(&val, va_arg(ap, uint64_t));
716
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
717
            break;
718
        }
719
        case 'v': {
720
            struct iovec *iov = va_arg(ap, struct iovec *);
721
            int *iovcnt = va_arg(ap, int *);
722
            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
723
            break;
724
        }
725
        case 's': {
726
            V9fsString *str = va_arg(ap, V9fsString *);
727
            offset += pdu_marshal(pdu, offset, "w", str->size);
728
            offset += pdu_pack(pdu, offset, str->data, str->size);
729
            break;
730
        }
731
        case 'Q': {
732
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
733
            offset += pdu_marshal(pdu, offset, "bdq",
734
                        qidp->type, qidp->version, qidp->path);
735
            break;
736
        }
737
        case 'S': {
738
            V9fsStat *statp = va_arg(ap, V9fsStat *);
739
            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
740
                        statp->size, statp->type, statp->dev,
741
                        &statp->qid, statp->mode, statp->atime,
742
                        statp->mtime, statp->length, &statp->name,
743
                        &statp->uid, &statp->gid, &statp->muid,
744
                        &statp->extension, statp->n_uid,
745
                        statp->n_gid, statp->n_muid);
746
            break;
747
        }
748
        case 'A': {
749
            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
750
            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
751
                        statp->st_result_mask,
752
                        &statp->qid, statp->st_mode,
753
                        statp->st_uid, statp->st_gid,
754
                        statp->st_nlink, statp->st_rdev,
755
                        statp->st_size, statp->st_blksize, statp->st_blocks,
756
                        statp->st_atime_sec, statp->st_atime_nsec,
757
                        statp->st_mtime_sec, statp->st_mtime_nsec,
758
                        statp->st_ctime_sec, statp->st_ctime_nsec,
759
                        statp->st_btime_sec, statp->st_btime_nsec,
760
                        statp->st_gen, statp->st_data_version);
761
            break;
762
        }
763
        default:
764
            break;
765
        }
766
    }
767
    va_end(ap);
768

    
769
    return offset - old_offset;
770
}
771

    
772
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
773
{
774
    int8_t id = pdu->id + 1; /* Response */
775

    
776
    if (len < 0) {
777
        V9fsString str;
778
        int err = -len;
779

    
780
        str.data = strerror(err);
781
        str.size = strlen(str.data);
782

    
783
        len = 7;
784
        len += pdu_marshal(pdu, len, "s", &str);
785
        if (dotu) {
786
            len += pdu_marshal(pdu, len, "d", err);
787
        }
788

    
789
        id = P9_RERROR;
790
    }
791

    
792
    /* fill out the header */
793
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
794

    
795
    /* keep these in sync */
796
    pdu->size = len;
797
    pdu->id = id;
798

    
799
    /* push onto queue and notify */
800
    virtqueue_push(s->vq, &pdu->elem, len);
801

    
802
    /* FIXME: we should batch these completions */
803
    virtio_notify(&s->vdev, s->vq);
804

    
805
    free_pdu(s, pdu);
806
}
807

    
808
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
809
{
810
    mode_t ret;
811

    
812
    ret = mode & 0777;
813
    if (mode & P9_STAT_MODE_DIR) {
814
        ret |= S_IFDIR;
815
    }
816

    
817
    if (dotu) {
818
        if (mode & P9_STAT_MODE_SYMLINK) {
819
            ret |= S_IFLNK;
820
        }
821
        if (mode & P9_STAT_MODE_SOCKET) {
822
            ret |= S_IFSOCK;
823
        }
824
        if (mode & P9_STAT_MODE_NAMED_PIPE) {
825
            ret |= S_IFIFO;
826
        }
827
        if (mode & P9_STAT_MODE_DEVICE) {
828
            if (extension && extension->data[0] == 'c') {
829
                ret |= S_IFCHR;
830
            } else {
831
                ret |= S_IFBLK;
832
            }
833
        }
834
    }
835

    
836
    if (!(ret&~0777)) {
837
        ret |= S_IFREG;
838
    }
839

    
840
    if (mode & P9_STAT_MODE_SETUID) {
841
        ret |= S_ISUID;
842
    }
843
    if (mode & P9_STAT_MODE_SETGID) {
844
        ret |= S_ISGID;
845
    }
846
    if (mode & P9_STAT_MODE_SETVTX) {
847
        ret |= S_ISVTX;
848
    }
849

    
850
    return ret;
851
}
852

    
853
static int donttouch_stat(V9fsStat *stat)
854
{
855
    if (stat->type == -1 &&
856
        stat->dev == -1 &&
857
        stat->qid.type == -1 &&
858
        stat->qid.version == -1 &&
859
        stat->qid.path == -1 &&
860
        stat->mode == -1 &&
861
        stat->atime == -1 &&
862
        stat->mtime == -1 &&
863
        stat->length == -1 &&
864
        !stat->name.size &&
865
        !stat->uid.size &&
866
        !stat->gid.size &&
867
        !stat->muid.size &&
868
        stat->n_uid == -1 &&
869
        stat->n_gid == -1 &&
870
        stat->n_muid == -1) {
871
        return 1;
872
    }
873

    
874
    return 0;
875
}
876

    
877
static void v9fs_stat_free(V9fsStat *stat)
878
{
879
    v9fs_string_free(&stat->name);
880
    v9fs_string_free(&stat->uid);
881
    v9fs_string_free(&stat->gid);
882
    v9fs_string_free(&stat->muid);
883
    v9fs_string_free(&stat->extension);
884
}
885

    
886
static uint32_t stat_to_v9mode(const struct stat *stbuf)
887
{
888
    uint32_t mode;
889

    
890
    mode = stbuf->st_mode & 0777;
891
    if (S_ISDIR(stbuf->st_mode)) {
892
        mode |= P9_STAT_MODE_DIR;
893
    }
894

    
895
    if (dotu) {
896
        if (S_ISLNK(stbuf->st_mode)) {
897
            mode |= P9_STAT_MODE_SYMLINK;
898
        }
899

    
900
        if (S_ISSOCK(stbuf->st_mode)) {
901
            mode |= P9_STAT_MODE_SOCKET;
902
        }
903

    
904
        if (S_ISFIFO(stbuf->st_mode)) {
905
            mode |= P9_STAT_MODE_NAMED_PIPE;
906
        }
907

    
908
        if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
909
            mode |= P9_STAT_MODE_DEVICE;
910
        }
911

    
912
        if (stbuf->st_mode & S_ISUID) {
913
            mode |= P9_STAT_MODE_SETUID;
914
        }
915

    
916
        if (stbuf->st_mode & S_ISGID) {
917
            mode |= P9_STAT_MODE_SETGID;
918
        }
919

    
920
        if (stbuf->st_mode & S_ISVTX) {
921
            mode |= P9_STAT_MODE_SETVTX;
922
        }
923
    }
924

    
925
    return mode;
926
}
927

    
928
static int stat_to_v9stat(V9fsState *s, V9fsString *name,
929
                            const struct stat *stbuf,
930
                            V9fsStat *v9stat)
931
{
932
    int err;
933
    const char *str;
934

    
935
    memset(v9stat, 0, sizeof(*v9stat));
936

    
937
    stat_to_qid(stbuf, &v9stat->qid);
938
    v9stat->mode = stat_to_v9mode(stbuf);
939
    v9stat->atime = stbuf->st_atime;
940
    v9stat->mtime = stbuf->st_mtime;
941
    v9stat->length = stbuf->st_size;
942

    
943
    v9fs_string_null(&v9stat->uid);
944
    v9fs_string_null(&v9stat->gid);
945
    v9fs_string_null(&v9stat->muid);
946

    
947
    if (dotu) {
948
        v9stat->n_uid = stbuf->st_uid;
949
        v9stat->n_gid = stbuf->st_gid;
950
        v9stat->n_muid = 0;
951

    
952
        v9fs_string_null(&v9stat->extension);
953

    
954
        if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
955
            err = v9fs_do_readlink(s, name, &v9stat->extension);
956
            if (err == -1) {
957
                err = -errno;
958
                return err;
959
            }
960
            v9stat->extension.data[err] = 0;
961
            v9stat->extension.size = err;
962
        } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
963
            v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
964
                    S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
965
                    major(stbuf->st_rdev), minor(stbuf->st_rdev));
966
        } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
967
            v9fs_string_sprintf(&v9stat->extension, "%s %u",
968
                    "HARDLINKCOUNT", stbuf->st_nlink);
969
        }
970
    }
971

    
972
    str = strrchr(name->data, '/');
973
    if (str) {
974
        str += 1;
975
    } else {
976
        str = name->data;
977
    }
978

    
979
    v9fs_string_sprintf(&v9stat->name, "%s", str);
980

    
981
    v9stat->size = 61 +
982
        v9fs_string_size(&v9stat->name) +
983
        v9fs_string_size(&v9stat->uid) +
984
        v9fs_string_size(&v9stat->gid) +
985
        v9fs_string_size(&v9stat->muid) +
986
        v9fs_string_size(&v9stat->extension);
987
    return 0;
988
}
989

    
990
#define P9_STATS_MODE          0x00000001ULL
991
#define P9_STATS_NLINK         0x00000002ULL
992
#define P9_STATS_UID           0x00000004ULL
993
#define P9_STATS_GID           0x00000008ULL
994
#define P9_STATS_RDEV          0x00000010ULL
995
#define P9_STATS_ATIME         0x00000020ULL
996
#define P9_STATS_MTIME         0x00000040ULL
997
#define P9_STATS_CTIME         0x00000080ULL
998
#define P9_STATS_INO           0x00000100ULL
999
#define P9_STATS_SIZE          0x00000200ULL
1000
#define P9_STATS_BLOCKS        0x00000400ULL
1001

    
1002
#define P9_STATS_BTIME         0x00000800ULL
1003
#define P9_STATS_GEN           0x00001000ULL
1004
#define P9_STATS_DATA_VERSION  0x00002000ULL
1005

    
1006
#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
1007
#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
1008

    
1009

    
1010
static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1011
                            V9fsStatDotl *v9lstat)
1012
{
1013
    memset(v9lstat, 0, sizeof(*v9lstat));
1014

    
1015
    v9lstat->st_mode = stbuf->st_mode;
1016
    v9lstat->st_nlink = stbuf->st_nlink;
1017
    v9lstat->st_uid = stbuf->st_uid;
1018
    v9lstat->st_gid = stbuf->st_gid;
1019
    v9lstat->st_rdev = stbuf->st_rdev;
1020
    v9lstat->st_size = stbuf->st_size;
1021
    v9lstat->st_blksize = stbuf->st_blksize;
1022
    v9lstat->st_blocks = stbuf->st_blocks;
1023
    v9lstat->st_atime_sec = stbuf->st_atime;
1024
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1025
    v9lstat->st_mtime_sec = stbuf->st_mtime;
1026
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1027
    v9lstat->st_ctime_sec = stbuf->st_ctime;
1028
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1029
    /* Currently we only support BASIC fields in stat */
1030
    v9lstat->st_result_mask = P9_STATS_BASIC;
1031

    
1032
    stat_to_qid(stbuf, &v9lstat->qid);
1033
}
1034

    
1035
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1036
{
1037
    while (len && *iovcnt) {
1038
        if (len < sg->iov_len) {
1039
            sg->iov_len -= len;
1040
            sg->iov_base += len;
1041
            len = 0;
1042
        } else {
1043
            len -= sg->iov_len;
1044
            sg++;
1045
            *iovcnt -= 1;
1046
        }
1047
    }
1048

    
1049
    return sg;
1050
}
1051

    
1052
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1053
{
1054
    int i;
1055
    int total = 0;
1056

    
1057
    for (i = 0; i < *cnt; i++) {
1058
        if ((total + sg[i].iov_len) > cap) {
1059
            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1060
            i++;
1061
            break;
1062
        }
1063
        total += sg[i].iov_len;
1064
    }
1065

    
1066
    *cnt = i;
1067

    
1068
    return sg;
1069
}
1070

    
1071
static void print_sg(struct iovec *sg, int cnt)
1072
{
1073
    int i;
1074

    
1075
    printf("sg[%d]: {", cnt);
1076
    for (i = 0; i < cnt; i++) {
1077
        if (i) {
1078
            printf(", ");
1079
        }
1080
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1081
    }
1082
    printf("}\n");
1083
}
1084

    
1085
static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1086
{
1087
    V9fsString str;
1088
    v9fs_string_init(&str);
1089
    v9fs_string_copy(&str, dst);
1090
    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1091
    v9fs_string_free(&str);
1092
}
1093

    
1094
static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
1095
{
1096
    V9fsString version;
1097
    size_t offset = 7;
1098

    
1099
    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1100

    
1101
    if (!strcmp(version.data, "9P2000.u")) {
1102
        s->proto_version = V9FS_PROTO_2000U;
1103
    } else if (!strcmp(version.data, "9P2000.L")) {
1104
        s->proto_version = V9FS_PROTO_2000L;
1105
    } else {
1106
        v9fs_string_sprintf(&version, "unknown");
1107
    }
1108

    
1109
    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1110
    complete_pdu(s, pdu, offset);
1111

    
1112
    v9fs_string_free(&version);
1113
}
1114

    
1115
static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
1116
{
1117
    int32_t fid, afid, n_uname;
1118
    V9fsString uname, aname;
1119
    V9fsFidState *fidp;
1120
    V9fsQID qid;
1121
    size_t offset = 7;
1122
    ssize_t err;
1123

    
1124
    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1125

    
1126
    fidp = alloc_fid(s, fid);
1127
    if (fidp == NULL) {
1128
        err = -EINVAL;
1129
        goto out;
1130
    }
1131

    
1132
    fidp->uid = n_uname;
1133

    
1134
    v9fs_string_sprintf(&fidp->path, "%s", "/");
1135
    err = fid_to_qid(s, fidp, &qid);
1136
    if (err) {
1137
        err = -EINVAL;
1138
        free_fid(s, fid);
1139
        goto out;
1140
    }
1141

    
1142
    offset += pdu_marshal(pdu, offset, "Q", &qid);
1143

    
1144
    err = offset;
1145
out:
1146
    complete_pdu(s, pdu, err);
1147
    v9fs_string_free(&uname);
1148
    v9fs_string_free(&aname);
1149
}
1150

    
1151
static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1152
{
1153
    if (err == -1) {
1154
        err = -errno;
1155
        goto out;
1156
    }
1157

    
1158
    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1159
    if (err) {
1160
        goto out;
1161
    }
1162
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1163
    err = vs->offset;
1164

    
1165
out:
1166
    complete_pdu(s, vs->pdu, err);
1167
    v9fs_stat_free(&vs->v9stat);
1168
    qemu_free(vs);
1169
}
1170

    
1171
static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
1172
{
1173
    int32_t fid;
1174
    V9fsStatState *vs;
1175
    ssize_t err = 0;
1176

    
1177
    vs = qemu_malloc(sizeof(*vs));
1178
    vs->pdu = pdu;
1179
    vs->offset = 7;
1180

    
1181
    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1182

    
1183
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1184

    
1185
    vs->fidp = lookup_fid(s, fid);
1186
    if (vs->fidp == NULL) {
1187
        err = -ENOENT;
1188
        goto out;
1189
    }
1190

    
1191
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1192
    v9fs_stat_post_lstat(s, vs, err);
1193
    return;
1194

    
1195
out:
1196
    complete_pdu(s, vs->pdu, err);
1197
    v9fs_stat_free(&vs->v9stat);
1198
    qemu_free(vs);
1199
}
1200

    
1201
static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
1202
                                                                int err)
1203
{
1204
    if (err == -1) {
1205
        err = -errno;
1206
        goto out;
1207
    }
1208

    
1209
    stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
1210
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
1211
    err = vs->offset;
1212

    
1213
out:
1214
    complete_pdu(s, vs->pdu, err);
1215
    qemu_free(vs);
1216
}
1217

    
1218
static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
1219
{
1220
    int32_t fid;
1221
    V9fsStatStateDotl *vs;
1222
    ssize_t err = 0;
1223
    V9fsFidState *fidp;
1224
    uint64_t request_mask;
1225

    
1226
    vs = qemu_malloc(sizeof(*vs));
1227
    vs->pdu = pdu;
1228
    vs->offset = 7;
1229

    
1230
    memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
1231

    
1232
    pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
1233

    
1234
    fidp = lookup_fid(s, fid);
1235
    if (fidp == NULL) {
1236
        err = -ENOENT;
1237
        goto out;
1238
    }
1239

    
1240
    /* Currently we only support BASIC fields in stat, so there is no
1241
     * need to look at request_mask.
1242
     */
1243
    err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
1244
    v9fs_getattr_post_lstat(s, vs, err);
1245
    return;
1246

    
1247
out:
1248
    complete_pdu(s, vs->pdu, err);
1249
    qemu_free(vs);
1250
}
1251

    
1252
/* From Linux kernel code */
1253
#define ATTR_MODE    (1 << 0)
1254
#define ATTR_UID     (1 << 1)
1255
#define ATTR_GID     (1 << 2)
1256
#define ATTR_SIZE    (1 << 3)
1257
#define ATTR_ATIME   (1 << 4)
1258
#define ATTR_MTIME   (1 << 5)
1259
#define ATTR_CTIME   (1 << 6)
1260
#define ATTR_MASK    127
1261
#define ATTR_ATIME_SET  (1 << 7)
1262
#define ATTR_MTIME_SET  (1 << 8)
1263

    
1264
static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
1265
                                                                  int err)
1266
{
1267
    if (err == -1) {
1268
        err = -errno;
1269
        goto out;
1270
    }
1271
    err = vs->offset;
1272

    
1273
out:
1274
    complete_pdu(s, vs->pdu, err);
1275
    qemu_free(vs);
1276
}
1277

    
1278
static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
1279
{
1280
    if (err == -1) {
1281
        err = -errno;
1282
        goto out;
1283
    }
1284

    
1285
    if (vs->v9iattr.valid & (ATTR_SIZE)) {
1286
        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
1287
    }
1288
    v9fs_setattr_post_truncate(s, vs, err);
1289
    return;
1290

    
1291
out:
1292
    complete_pdu(s, vs->pdu, err);
1293
    qemu_free(vs);
1294
}
1295

    
1296
static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
1297
                                                                   int err)
1298
{
1299
    if (err == -1) {
1300
        err = -errno;
1301
        goto out;
1302
    }
1303

    
1304
    /* If the only valid entry in iattr is ctime we can call
1305
     * chown(-1,-1) to update the ctime of the file
1306
     */
1307
    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1308
            ((vs->v9iattr.valid & ATTR_CTIME)
1309
            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1310
        if (!(vs->v9iattr.valid & ATTR_UID)) {
1311
            vs->v9iattr.uid = -1;
1312
        }
1313
        if (!(vs->v9iattr.valid & ATTR_GID)) {
1314
            vs->v9iattr.gid = -1;
1315
        }
1316
        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
1317
                                                vs->v9iattr.gid);
1318
    }
1319
    v9fs_setattr_post_chown(s, vs, err);
1320
    return;
1321

    
1322
out:
1323
    complete_pdu(s, vs->pdu, err);
1324
    qemu_free(vs);
1325
}
1326

    
1327
static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
1328
{
1329
    if (err == -1) {
1330
        err = -errno;
1331
        goto out;
1332
    }
1333

    
1334
    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1335
        struct timespec times[2];
1336
        if (vs->v9iattr.valid & ATTR_ATIME) {
1337
            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
1338
                times[0].tv_sec = vs->v9iattr.atime_sec;
1339
                times[0].tv_nsec = vs->v9iattr.atime_nsec;
1340
            } else {
1341
                times[0].tv_nsec = UTIME_NOW;
1342
            }
1343
        } else {
1344
            times[0].tv_nsec = UTIME_OMIT;
1345
        }
1346

    
1347
        if (vs->v9iattr.valid & ATTR_MTIME) {
1348
            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
1349
                times[1].tv_sec = vs->v9iattr.mtime_sec;
1350
                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
1351
            } else {
1352
                times[1].tv_nsec = UTIME_NOW;
1353
            }
1354
        } else {
1355
            times[1].tv_nsec = UTIME_OMIT;
1356
        }
1357
        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
1358
    }
1359
    v9fs_setattr_post_utimensat(s, vs, err);
1360
    return;
1361

    
1362
out:
1363
    complete_pdu(s, vs->pdu, err);
1364
    qemu_free(vs);
1365
}
1366

    
1367
static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
1368
{
1369
    int32_t fid;
1370
    V9fsSetattrState *vs;
1371
    int err = 0;
1372

    
1373
    vs = qemu_malloc(sizeof(*vs));
1374
    vs->pdu = pdu;
1375
    vs->offset = 7;
1376

    
1377
    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
1378

    
1379
    vs->fidp = lookup_fid(s, fid);
1380
    if (vs->fidp == NULL) {
1381
        err = -EINVAL;
1382
        goto out;
1383
    }
1384

    
1385
    if (vs->v9iattr.valid & ATTR_MODE) {
1386
        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
1387
    }
1388

    
1389
    v9fs_setattr_post_chmod(s, vs, err);
1390
    return;
1391

    
1392
out:
1393
    complete_pdu(s, vs->pdu, err);
1394
    qemu_free(vs);
1395
}
1396

    
1397
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1398
{
1399
    complete_pdu(s, vs->pdu, err);
1400

    
1401
    if (vs->nwnames) {
1402
        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1403
            v9fs_string_free(&vs->wnames[vs->name_idx]);
1404
        }
1405

    
1406
        qemu_free(vs->wnames);
1407
        qemu_free(vs->qids);
1408
    }
1409
}
1410

    
1411
static void v9fs_walk_marshal(V9fsWalkState *vs)
1412
{
1413
    int i;
1414
    vs->offset = 7;
1415
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1416

    
1417
    for (i = 0; i < vs->nwnames; i++) {
1418
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1419
    }
1420
}
1421

    
1422
static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1423
                                                                int err)
1424
{
1425
    if (err == -1) {
1426
        free_fid(s, vs->newfidp->fid);
1427
        v9fs_string_free(&vs->path);
1428
        err = -ENOENT;
1429
        goto out;
1430
    }
1431

    
1432
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1433

    
1434
    vs->name_idx++;
1435
    if (vs->name_idx < vs->nwnames) {
1436
        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1437
                                            vs->wnames[vs->name_idx].data);
1438
        v9fs_string_copy(&vs->newfidp->path, &vs->path);
1439

    
1440
        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1441
        v9fs_walk_post_newfid_lstat(s, vs, err);
1442
        return;
1443
    }
1444

    
1445
    v9fs_string_free(&vs->path);
1446
    v9fs_walk_marshal(vs);
1447
    err = vs->offset;
1448
out:
1449
    v9fs_walk_complete(s, vs, err);
1450
}
1451

    
1452
static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1453
        int err)
1454
{
1455
    if (err == -1) {
1456
        v9fs_string_free(&vs->path);
1457
        err = -ENOENT;
1458
        goto out;
1459
    }
1460

    
1461
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1462
    vs->name_idx++;
1463
    if (vs->name_idx < vs->nwnames) {
1464

    
1465
        v9fs_string_sprintf(&vs->path, "%s/%s",
1466
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1467
        v9fs_string_copy(&vs->fidp->path, &vs->path);
1468

    
1469
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1470
        v9fs_walk_post_oldfid_lstat(s, vs, err);
1471
        return;
1472
    }
1473

    
1474
    v9fs_string_free(&vs->path);
1475
    v9fs_walk_marshal(vs);
1476
    err = vs->offset;
1477
out:
1478
    v9fs_walk_complete(s, vs, err);
1479
}
1480

    
1481
static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
1482
{
1483
    int32_t fid, newfid;
1484
    V9fsWalkState *vs;
1485
    int err = 0;
1486
    int i;
1487

    
1488
    vs = qemu_malloc(sizeof(*vs));
1489
    vs->pdu = pdu;
1490
    vs->wnames = NULL;
1491
    vs->qids = NULL;
1492
    vs->offset = 7;
1493

    
1494
    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1495
                                            &newfid, &vs->nwnames);
1496

    
1497
    if (vs->nwnames) {
1498
        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1499

    
1500
        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1501

    
1502
        for (i = 0; i < vs->nwnames; i++) {
1503
            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1504
                                            &vs->wnames[i]);
1505
        }
1506
    }
1507

    
1508
    vs->fidp = lookup_fid(s, fid);
1509
    if (vs->fidp == NULL) {
1510
        err = -ENOENT;
1511
        goto out;
1512
    }
1513

    
1514
    /* FIXME: is this really valid? */
1515
    if (fid == newfid) {
1516

    
1517
        BUG_ON(vs->fidp->fd != -1);
1518
        BUG_ON(vs->fidp->dir);
1519
        v9fs_string_init(&vs->path);
1520
        vs->name_idx = 0;
1521

    
1522
        if (vs->name_idx < vs->nwnames) {
1523
            v9fs_string_sprintf(&vs->path, "%s/%s",
1524
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1525
            v9fs_string_copy(&vs->fidp->path, &vs->path);
1526

    
1527
            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1528
            v9fs_walk_post_oldfid_lstat(s, vs, err);
1529
            return;
1530
        }
1531
    } else {
1532
        vs->newfidp = alloc_fid(s, newfid);
1533
        if (vs->newfidp == NULL) {
1534
            err = -EINVAL;
1535
            goto out;
1536
        }
1537

    
1538
        vs->newfidp->uid = vs->fidp->uid;
1539
        v9fs_string_init(&vs->path);
1540
        vs->name_idx = 0;
1541
        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1542

    
1543
        if (vs->name_idx < vs->nwnames) {
1544
            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1545
                                vs->wnames[vs->name_idx].data);
1546
            v9fs_string_copy(&vs->newfidp->path, &vs->path);
1547

    
1548
            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1549
            v9fs_walk_post_newfid_lstat(s, vs, err);
1550
            return;
1551
        }
1552
    }
1553

    
1554
    v9fs_walk_marshal(vs);
1555
    err = vs->offset;
1556
out:
1557
    v9fs_walk_complete(s, vs, err);
1558
}
1559

    
1560
static int32_t get_iounit(V9fsState *s, V9fsString *name)
1561
{
1562
    struct statfs stbuf;
1563
    int32_t iounit = 0;
1564

    
1565
    /*
1566
     * iounit should be multiples of f_bsize (host filesystem block size
1567
     * and as well as less than (client msize - P9_IOHDRSZ))
1568
     */
1569
    if (!v9fs_do_statfs(s, name, &stbuf)) {
1570
        iounit = stbuf.f_bsize;
1571
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1572
    }
1573

    
1574
    if (!iounit) {
1575
        iounit = s->msize - P9_IOHDRSZ;
1576
    }
1577
    return iounit;
1578
}
1579

    
1580
static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1581
{
1582
    if (vs->fidp->dir == NULL) {
1583
        err = -errno;
1584
        goto out;
1585
    }
1586

    
1587
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1588
    err = vs->offset;
1589
out:
1590
    complete_pdu(s, vs->pdu, err);
1591
    qemu_free(vs);
1592

    
1593
}
1594

    
1595
static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1596
{
1597
    int err;
1598
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1599
    err = vs->offset;
1600
    complete_pdu(s, vs->pdu, err);
1601
    qemu_free(vs);
1602
}
1603

    
1604
static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1605
{
1606
    if (vs->fidp->fd == -1) {
1607
        err = -errno;
1608
        goto out;
1609
    }
1610

    
1611
    vs->iounit = get_iounit(s, &vs->fidp->path);
1612
    v9fs_open_post_getiounit(s, vs);
1613
    return;
1614
out:
1615
    complete_pdu(s, vs->pdu, err);
1616
    qemu_free(vs);
1617
}
1618

    
1619
static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1620
{
1621
    if (err) {
1622
        err = -errno;
1623
        goto out;
1624
    }
1625

    
1626
    stat_to_qid(&vs->stbuf, &vs->qid);
1627

    
1628
    if (S_ISDIR(vs->stbuf.st_mode)) {
1629
        vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
1630
        v9fs_open_post_opendir(s, vs, err);
1631
    } else {
1632
        vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
1633
                                    omode_to_uflags(vs->mode));
1634
        v9fs_open_post_open(s, vs, err);
1635
    }
1636
    return;
1637
out:
1638
    complete_pdu(s, vs->pdu, err);
1639
    qemu_free(vs);
1640
}
1641

    
1642
static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
1643
{
1644
    int32_t fid;
1645
    V9fsOpenState *vs;
1646
    ssize_t err = 0;
1647

    
1648

    
1649
    vs = qemu_malloc(sizeof(*vs));
1650
    vs->pdu = pdu;
1651
    vs->offset = 7;
1652

    
1653
    pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1654

    
1655
    vs->fidp = lookup_fid(s, fid);
1656
    if (vs->fidp == NULL) {
1657
        err = -ENOENT;
1658
        goto out;
1659
    }
1660

    
1661
    BUG_ON(vs->fidp->fd != -1);
1662
    BUG_ON(vs->fidp->dir);
1663

    
1664
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1665

    
1666
    v9fs_open_post_lstat(s, vs, err);
1667
    return;
1668
out:
1669
    complete_pdu(s, pdu, err);
1670
    qemu_free(vs);
1671
}
1672

    
1673
static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
1674
{
1675
    int32_t fid;
1676
    size_t offset = 7;
1677
    int err;
1678

    
1679
    pdu_unmarshal(pdu, offset, "d", &fid);
1680

    
1681
    err = free_fid(s, fid);
1682
    if (err < 0) {
1683
        goto out;
1684
    }
1685

    
1686
    offset = 7;
1687
    err = offset;
1688
out:
1689
    complete_pdu(s, pdu, err);
1690
}
1691

    
1692
static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1693

    
1694
static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1695
{
1696
    if (err) {
1697
        goto out;
1698
    }
1699
    v9fs_stat_free(&vs->v9stat);
1700
    v9fs_string_free(&vs->name);
1701
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1702
    vs->offset += vs->count;
1703
    err = vs->offset;
1704
out:
1705
    complete_pdu(s, vs->pdu, err);
1706
    qemu_free(vs);
1707
    return;
1708
}
1709

    
1710
static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1711
                                    ssize_t err)
1712
{
1713
    if (err) {
1714
        err = -errno;
1715
        goto out;
1716
    }
1717
    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1718
    if (err) {
1719
        goto out;
1720
    }
1721

    
1722
    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1723
                            &vs->v9stat);
1724
    if ((vs->len != (vs->v9stat.size + 2)) ||
1725
            ((vs->count + vs->len) > vs->max_count)) {
1726
        v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1727
        v9fs_read_post_seekdir(s, vs, err);
1728
        return;
1729
    }
1730
    vs->count += vs->len;
1731
    v9fs_stat_free(&vs->v9stat);
1732
    v9fs_string_free(&vs->name);
1733
    vs->dir_pos = vs->dent->d_off;
1734
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1735
    v9fs_read_post_readdir(s, vs, err);
1736
    return;
1737
out:
1738
    v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1739
    v9fs_read_post_seekdir(s, vs, err);
1740
    return;
1741

    
1742
}
1743

    
1744
static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1745
{
1746
    if (vs->dent) {
1747
        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1748
        v9fs_string_init(&vs->name);
1749
        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1750
                            vs->dent->d_name);
1751
        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1752
        v9fs_read_post_dir_lstat(s, vs, err);
1753
        return;
1754
    }
1755

    
1756
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1757
    vs->offset += vs->count;
1758
    err = vs->offset;
1759
    complete_pdu(s, vs->pdu, err);
1760
    qemu_free(vs);
1761
    return;
1762
}
1763

    
1764
static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1765
{
1766
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1767
    v9fs_read_post_readdir(s, vs, err);
1768
    return;
1769
}
1770

    
1771
static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1772
                                       ssize_t err)
1773
{
1774
    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
1775
    v9fs_read_post_telldir(s, vs, err);
1776
    return;
1777
}
1778

    
1779
static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1780
{
1781
    if (err  < 0) {
1782
        /* IO error return the error */
1783
        err = -errno;
1784
        goto out;
1785
    }
1786
    vs->total += vs->len;
1787
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1788
    if (vs->total < vs->count && vs->len > 0) {
1789
        do {
1790
            if (0) {
1791
                print_sg(vs->sg, vs->cnt);
1792
            }
1793
            vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1794
        } while (vs->len == -1 && errno == EINTR);
1795
        if (vs->len == -1) {
1796
            err  = -errno;
1797
        }
1798
        v9fs_read_post_readv(s, vs, err);
1799
        return;
1800
    }
1801
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1802
    vs->offset += vs->count;
1803
    err = vs->offset;
1804

    
1805
out:
1806
    complete_pdu(s, vs->pdu, err);
1807
    qemu_free(vs);
1808
}
1809

    
1810
static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
1811
{
1812
    if (err == -1) {
1813
        err = -errno;
1814
        goto out;
1815
    }
1816
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1817

    
1818
    if (vs->total < vs->count) {
1819
        do {
1820
            if (0) {
1821
                print_sg(vs->sg, vs->cnt);
1822
            }
1823
            vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1824
        } while (vs->len == -1 && errno == EINTR);
1825
        if (vs->len == -1) {
1826
            err  = -errno;
1827
        }
1828
        v9fs_read_post_readv(s, vs, err);
1829
        return;
1830
    }
1831
out:
1832
    complete_pdu(s, vs->pdu, err);
1833
    qemu_free(vs);
1834
}
1835

    
1836
static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
1837
{
1838
    int32_t fid;
1839
    V9fsReadState *vs;
1840
    ssize_t err = 0;
1841

    
1842
    vs = qemu_malloc(sizeof(*vs));
1843
    vs->pdu = pdu;
1844
    vs->offset = 7;
1845
    vs->total = 0;
1846
    vs->len = 0;
1847
    vs->count = 0;
1848

    
1849
    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
1850

    
1851
    vs->fidp = lookup_fid(s, fid);
1852
    if (vs->fidp == NULL) {
1853
        err = -EINVAL;
1854
        goto out;
1855
    }
1856

    
1857
    if (vs->fidp->dir) {
1858
        vs->max_count = vs->count;
1859
        vs->count = 0;
1860
        if (vs->off == 0) {
1861
            v9fs_do_rewinddir(s, vs->fidp->dir);
1862
        }
1863
        v9fs_read_post_rewinddir(s, vs, err);
1864
        return;
1865
    } else if (vs->fidp->fd != -1) {
1866
        vs->sg = vs->iov;
1867
        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1868
        err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
1869
        v9fs_read_post_lseek(s, vs, err);
1870
        return;
1871
    } else {
1872
        err = -EINVAL;
1873
    }
1874
out:
1875
    complete_pdu(s, pdu, err);
1876
    qemu_free(vs);
1877
}
1878

    
1879
typedef struct V9fsReadDirState {
1880
    V9fsPDU *pdu;
1881
    V9fsFidState *fidp;
1882
    V9fsQID qid;
1883
    off_t saved_dir_pos;
1884
    struct dirent *dent;
1885
    int32_t count;
1886
    int32_t max_count;
1887
    size_t offset;
1888
    int64_t initial_offset;
1889
    V9fsString name;
1890
} V9fsReadDirState;
1891

    
1892
static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
1893
{
1894
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1895
    vs->offset += vs->count;
1896
    complete_pdu(s, vs->pdu, vs->offset);
1897
    qemu_free(vs);
1898
    return;
1899
}
1900

    
1901
/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
1902
 * size of type (1) + size of name.size (2) + strlen(name.data)
1903
 */
1904
#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
1905

    
1906
static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
1907
{
1908
    int len;
1909
    size_t size;
1910

    
1911
    if (vs->dent) {
1912
        v9fs_string_init(&vs->name);
1913
        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
1914

    
1915
        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
1916
            /* Ran out of buffer. Set dir back to old position and return */
1917
            v9fs_do_seekdir(s, vs->fidp->dir, vs->saved_dir_pos);
1918
            v9fs_readdir_post_seekdir(s, vs);
1919
            return;
1920
        }
1921

    
1922
        /* Fill up just the path field of qid because the client uses
1923
         * only that. To fill the entire qid structure we will have
1924
         * to stat each dirent found, which is expensive
1925
         */
1926
        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
1927
        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
1928
        /* Fill the other fields with dummy values */
1929
        vs->qid.type = 0;
1930
        vs->qid.version = 0;
1931

    
1932
        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
1933
                              &vs->qid, vs->dent->d_off,
1934
                              vs->dent->d_type, &vs->name);
1935
        vs->count += len;
1936
        v9fs_string_free(&vs->name);
1937
        vs->saved_dir_pos = vs->dent->d_off;
1938
        vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1939
        v9fs_readdir_post_readdir(s, vs);
1940
        return;
1941
    }
1942

    
1943
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1944
    vs->offset += vs->count;
1945
    complete_pdu(s, vs->pdu, vs->offset);
1946
    qemu_free(vs);
1947
    return;
1948
}
1949

    
1950
static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
1951
{
1952
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1953
    v9fs_readdir_post_readdir(s, vs);
1954
    return;
1955
}
1956

    
1957
static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
1958
{
1959
    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
1960
    v9fs_readdir_post_telldir(s, vs);
1961
    return;
1962
}
1963

    
1964
static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
1965
{
1966
    int32_t fid;
1967
    V9fsReadDirState *vs;
1968
    ssize_t err = 0;
1969
    size_t offset = 7;
1970

    
1971
    vs = qemu_malloc(sizeof(*vs));
1972
    vs->pdu = pdu;
1973
    vs->offset = 7;
1974
    vs->count = 0;
1975

    
1976
    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
1977
                                                        &vs->max_count);
1978

    
1979
    vs->fidp = lookup_fid(s, fid);
1980
    if (vs->fidp == NULL || !(vs->fidp->dir)) {
1981
        err = -EINVAL;
1982
        goto out;
1983
    }
1984

    
1985
    if (vs->initial_offset == 0) {
1986
        v9fs_do_rewinddir(s, vs->fidp->dir);
1987
    } else {
1988
        v9fs_do_seekdir(s, vs->fidp->dir, vs->initial_offset);
1989
    }
1990

    
1991
    v9fs_readdir_post_setdir(s, vs);
1992
    return;
1993

    
1994
out:
1995
    complete_pdu(s, pdu, err);
1996
    qemu_free(vs);
1997
    return;
1998
}
1999

    
2000
static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
2001
                                   ssize_t err)
2002
{
2003
    if (err  < 0) {
2004
        /* IO error return the error */
2005
        err = -errno;
2006
        goto out;
2007
    }
2008
    vs->total += vs->len;
2009
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2010
    if (vs->total < vs->count && vs->len > 0) {
2011
        do {
2012
            if (0) {
2013
                print_sg(vs->sg, vs->cnt);
2014
            }
2015
            vs->len =  v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
2016
        } while (vs->len == -1 && errno == EINTR);
2017
        if (vs->len == -1) {
2018
            err  = -errno;
2019
        }
2020
        v9fs_write_post_writev(s, vs, err);
2021
        return;
2022
    }
2023
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2024

    
2025
    err = vs->offset;
2026
out:
2027
    complete_pdu(s, vs->pdu, err);
2028
    qemu_free(vs);
2029
}
2030

    
2031
static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
2032
{
2033
    if (err == -1) {
2034
        err = -errno;
2035
        goto out;
2036
    }
2037
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2038

    
2039
    if (vs->total < vs->count) {
2040
        do {
2041
            if (0) {
2042
                print_sg(vs->sg, vs->cnt);
2043
            }
2044
            vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
2045
        } while (vs->len == -1 && errno == EINTR);
2046
        if (vs->len == -1) {
2047
            err  = -errno;
2048
        }
2049
        v9fs_write_post_writev(s, vs, err);
2050
        return;
2051
    }
2052

    
2053
out:
2054
    complete_pdu(s, vs->pdu, err);
2055
    qemu_free(vs);
2056
}
2057

    
2058
static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
2059
{
2060
    int32_t fid;
2061
    V9fsWriteState *vs;
2062
    ssize_t err;
2063

    
2064
    vs = qemu_malloc(sizeof(*vs));
2065

    
2066
    vs->pdu = pdu;
2067
    vs->offset = 7;
2068
    vs->sg = vs->iov;
2069
    vs->total = 0;
2070
    vs->len = 0;
2071

    
2072
    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2073
                    vs->sg, &vs->cnt);
2074

    
2075
    vs->fidp = lookup_fid(s, fid);
2076
    if (vs->fidp == NULL) {
2077
        err = -EINVAL;
2078
        goto out;
2079
    }
2080

    
2081
    if (vs->fidp->fd == -1) {
2082
        err = -EINVAL;
2083
        goto out;
2084
    }
2085

    
2086
    err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
2087

    
2088
    v9fs_write_post_lseek(s, vs, err);
2089
    return;
2090

    
2091
out:
2092
    complete_pdu(s, vs->pdu, err);
2093
    qemu_free(vs);
2094
}
2095

    
2096
static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2097
{
2098
    int err;
2099
    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2100
    stat_to_qid(&vs->stbuf, &vs->qid);
2101

    
2102
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2103
    err = vs->offset;
2104

    
2105
    complete_pdu(s, vs->pdu, err);
2106
    v9fs_string_free(&vs->name);
2107
    v9fs_string_free(&vs->extension);
2108
    v9fs_string_free(&vs->fullname);
2109
    qemu_free(vs);
2110
}
2111

    
2112
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2113
{
2114
    if (err == 0) {
2115
        vs->iounit = get_iounit(s, &vs->fidp->path);
2116
        v9fs_create_post_getiounit(s, vs);
2117
        return;
2118
    }
2119

    
2120
    complete_pdu(s, vs->pdu, err);
2121
    v9fs_string_free(&vs->name);
2122
    v9fs_string_free(&vs->extension);
2123
    v9fs_string_free(&vs->fullname);
2124
    qemu_free(vs);
2125
}
2126

    
2127
static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2128
{
2129
    if (err) {
2130
        err = -errno;
2131
    }
2132
    v9fs_post_create(s, vs, err);
2133
}
2134

    
2135
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2136
                                                                    int err)
2137
{
2138
    if (!vs->fidp->dir) {
2139
        err = -errno;
2140
    }
2141
    v9fs_post_create(s, vs, err);
2142
}
2143

    
2144
static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2145
                                                                    int err)
2146
{
2147
    if (err) {
2148
        err = -errno;
2149
        goto out;
2150
    }
2151

    
2152
    vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
2153
    v9fs_create_post_opendir(s, vs, err);
2154
    return;
2155

    
2156
out:
2157
    v9fs_post_create(s, vs, err);
2158
}
2159

    
2160
static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2161
{
2162
    if (err) {
2163
        err = -errno;
2164
        goto out;
2165
    }
2166

    
2167
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2168
    v9fs_create_post_dir_lstat(s, vs, err);
2169
    return;
2170

    
2171
out:
2172
    v9fs_post_create(s, vs, err);
2173
}
2174

    
2175
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2176
{
2177
    if (err) {
2178
        vs->fidp->fd = -1;
2179
        err = -errno;
2180
    }
2181

    
2182
    v9fs_post_create(s, vs, err);
2183
    return;
2184
}
2185

    
2186
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2187
{
2188
    if (vs->fidp->fd == -1) {
2189
        err = -errno;
2190
        goto out;
2191
    }
2192

    
2193
    err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
2194
    v9fs_create_post_fstat(s, vs, err);
2195

    
2196
    return;
2197

    
2198
out:
2199
    v9fs_post_create(s, vs, err);
2200

    
2201
}
2202

    
2203
static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2204
{
2205

    
2206
    if (err == 0 || errno != ENOENT) {
2207
        err = -errno;
2208
        goto out;
2209
    }
2210

    
2211
    if (vs->perm & P9_STAT_MODE_DIR) {
2212
        err = v9fs_do_mkdir(s, vs);
2213
        v9fs_create_post_mkdir(s, vs, err);
2214
    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2215
        err = v9fs_do_symlink(s, vs);
2216
        v9fs_create_post_perms(s, vs, err);
2217
    } else if (vs->perm & P9_STAT_MODE_LINK) {
2218
        int32_t nfid = atoi(vs->extension.data);
2219
        V9fsFidState *nfidp = lookup_fid(s, nfid);
2220
        if (nfidp == NULL) {
2221
            err = -errno;
2222
            v9fs_post_create(s, vs, err);
2223
        }
2224
        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2225
        v9fs_create_post_perms(s, vs, err);
2226
    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2227
        char ctype;
2228
        uint32_t major, minor;
2229
        mode_t nmode = 0;
2230

    
2231
        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2232
                                        &minor) != 3) {
2233
            err = -errno;
2234
            v9fs_post_create(s, vs, err);
2235
        }
2236

    
2237
        switch (ctype) {
2238
        case 'c':
2239
            nmode = S_IFCHR;
2240
            break;
2241
        case 'b':
2242
            nmode = S_IFBLK;
2243
            break;
2244
        default:
2245
            err = -EIO;
2246
            v9fs_post_create(s, vs, err);
2247
        }
2248

    
2249
        nmode |= vs->perm & 0777;
2250
        err = v9fs_do_mknod(s, vs, nmode, makedev(major, minor));
2251
        v9fs_create_post_perms(s, vs, err);
2252
    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2253
        err = v9fs_do_mknod(s, vs, S_IFIFO | (vs->perm & 0777), 0);
2254
        v9fs_post_create(s, vs, err);
2255
    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2256
        err = v9fs_do_mknod(s, vs, S_IFSOCK | (vs->perm & 0777), 0);
2257
        v9fs_post_create(s, vs, err);
2258
    } else {
2259
        vs->fidp->fd = v9fs_do_open2(s, vs);
2260
        v9fs_create_post_open2(s, vs, err);
2261
    }
2262

    
2263
    return;
2264

    
2265
out:
2266
    v9fs_post_create(s, vs, err);
2267
}
2268

    
2269
static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
2270
{
2271
    int32_t fid;
2272
    V9fsCreateState *vs;
2273
    int err = 0;
2274

    
2275
    vs = qemu_malloc(sizeof(*vs));
2276
    vs->pdu = pdu;
2277
    vs->offset = 7;
2278

    
2279
    v9fs_string_init(&vs->fullname);
2280

    
2281
    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2282
                                &vs->perm, &vs->mode, &vs->extension);
2283

    
2284
    vs->fidp = lookup_fid(s, fid);
2285
    if (vs->fidp == NULL) {
2286
        err = -EINVAL;
2287
        goto out;
2288
    }
2289

    
2290
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2291
                                                        vs->name.data);
2292

    
2293
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2294
    v9fs_create_post_lstat(s, vs, err);
2295
    return;
2296

    
2297
out:
2298
    complete_pdu(s, vs->pdu, err);
2299
    v9fs_string_free(&vs->name);
2300
    v9fs_string_free(&vs->extension);
2301
    qemu_free(vs);
2302
}
2303

    
2304
static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
2305
{
2306
    /* A nop call with no return */
2307
    complete_pdu(s, pdu, 7);
2308
}
2309

    
2310
static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
2311
{
2312
    int32_t dfid, oldfid;
2313
    V9fsFidState *dfidp, *oldfidp;
2314
    V9fsString name, fullname;
2315
    size_t offset = 7;
2316
    int err = 0;
2317

    
2318
    v9fs_string_init(&fullname);
2319

    
2320
    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2321

    
2322
    dfidp = lookup_fid(s, dfid);
2323
    if (dfidp == NULL) {
2324
        err = -errno;
2325
        goto out;
2326
    }
2327

    
2328
    oldfidp = lookup_fid(s, oldfid);
2329
    if (oldfidp == NULL) {
2330
        err = -errno;
2331
        goto out;
2332
    }
2333

    
2334
    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2335
    err = offset;
2336
    err = v9fs_do_link(s, &oldfidp->path, &fullname);
2337
    if (err) {
2338
        err = -errno;
2339
    }
2340
    v9fs_string_free(&fullname);
2341

    
2342
out:
2343
    v9fs_string_free(&name);
2344
    complete_pdu(s, pdu, err);
2345
}
2346

    
2347
static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
2348
                                                                int err)
2349
{
2350
    if (err < 0) {
2351
        err = -errno;
2352
    } else {
2353
        err = vs->offset;
2354
    }
2355

    
2356
    /* For TREMOVE we need to clunk the fid even on failed remove */
2357
    free_fid(s, vs->fidp->fid);
2358

    
2359
    complete_pdu(s, vs->pdu, err);
2360
    qemu_free(vs);
2361
}
2362

    
2363
static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
2364
{
2365
    int32_t fid;
2366
    V9fsRemoveState *vs;
2367
    int err = 0;
2368

    
2369
    vs = qemu_malloc(sizeof(*vs));
2370
    vs->pdu = pdu;
2371
    vs->offset = 7;
2372

    
2373
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
2374

    
2375
    vs->fidp = lookup_fid(s, fid);
2376
    if (vs->fidp == NULL) {
2377
        err = -EINVAL;
2378
        goto out;
2379
    }
2380

    
2381
    err = v9fs_do_remove(s, &vs->fidp->path);
2382
    v9fs_remove_post_remove(s, vs, err);
2383
    return;
2384

    
2385
out:
2386
    complete_pdu(s, pdu, err);
2387
    qemu_free(vs);
2388
}
2389

    
2390
static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2391
{
2392
    if (err < 0) {
2393
        goto out;
2394
    }
2395

    
2396
    err = vs->offset;
2397

    
2398
out:
2399
    v9fs_stat_free(&vs->v9stat);
2400
    complete_pdu(s, vs->pdu, err);
2401
    qemu_free(vs);
2402
}
2403

    
2404
static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2405
{
2406
    if (err < 0) {
2407
        goto out;
2408
    }
2409

    
2410
    if (vs->v9stat.name.size != 0) {
2411
        v9fs_string_free(&vs->nname);
2412
    }
2413

    
2414
    if (vs->v9stat.length != -1) {
2415
        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2416
            err = -errno;
2417
        }
2418
    }
2419
    v9fs_wstat_post_truncate(s, vs, err);
2420
    return;
2421

    
2422
out:
2423
    v9fs_stat_free(&vs->v9stat);
2424
    complete_pdu(s, vs->pdu, err);
2425
    qemu_free(vs);
2426
}
2427

    
2428
static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2429
{
2430
    V9fsFidState *fidp;
2431
    if (err < 0) {
2432
        goto out;
2433
    }
2434

    
2435
    if (vs->v9stat.name.size != 0) {
2436
        char *old_name, *new_name;
2437
        char *end;
2438

    
2439
        old_name = vs->fidp->path.data;
2440
        end = strrchr(old_name, '/');
2441
        if (end) {
2442
            end++;
2443
        } else {
2444
            end = old_name;
2445
        }
2446

    
2447
        new_name = qemu_mallocz(end - old_name + vs->v9stat.name.size + 1);
2448

    
2449
        memcpy(new_name, old_name, end - old_name);
2450
        memcpy(new_name + (end - old_name), vs->v9stat.name.data,
2451
                vs->v9stat.name.size);
2452
        vs->nname.data = new_name;
2453
        vs->nname.size = strlen(new_name);
2454

    
2455
        if (strcmp(new_name, vs->fidp->path.data) != 0) {
2456
            if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
2457
                err = -errno;
2458
            } else {
2459
                /*
2460
                 * Fixup fid's pointing to the old name to
2461
                 * start pointing to the new name
2462
                 */
2463
                for (fidp = s->fid_list; fidp; fidp = fidp->next) {
2464

    
2465
                    if (vs->fidp == fidp) {
2466
                        /*
2467
                         * we replace name of this fid towards the end
2468
                         * so that our below strcmp will work
2469
                         */
2470
                        continue;
2471
                    }
2472
                    if (!strncmp(vs->fidp->path.data, fidp->path.data,
2473
                                 strlen(vs->fidp->path.data))) {
2474
                        /* replace the name */
2475
                        v9fs_fix_path(&fidp->path, &vs->nname,
2476
                                      strlen(vs->fidp->path.data));
2477
                    }
2478
                }
2479
                v9fs_string_copy(&vs->fidp->path, &vs->nname);
2480
            }
2481
        }
2482
    }
2483
    v9fs_wstat_post_rename(s, vs, err);
2484
    return;
2485

    
2486
out:
2487
    v9fs_stat_free(&vs->v9stat);
2488
    complete_pdu(s, vs->pdu, err);
2489
    qemu_free(vs);
2490
}
2491

    
2492
static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2493
{
2494
    if (err < 0) {
2495
        goto out;
2496
    }
2497

    
2498
    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2499
        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2500
                    vs->v9stat.n_gid)) {
2501
            err = -errno;
2502
        }
2503
    }
2504
    v9fs_wstat_post_chown(s, vs, err);
2505
    return;
2506

    
2507
out:
2508
    v9fs_stat_free(&vs->v9stat);
2509
    complete_pdu(s, vs->pdu, err);
2510
    qemu_free(vs);
2511
}
2512

    
2513
static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2514
{
2515
    if (err < 0) {
2516
        goto out;
2517
    }
2518

    
2519
    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2520
        struct timespec times[2];
2521
        if (vs->v9stat.atime != -1) {
2522
            times[0].tv_sec = vs->v9stat.atime;
2523
            times[0].tv_nsec = 0;
2524
        } else {
2525
            times[0].tv_nsec = UTIME_OMIT;
2526
        }
2527
        if (vs->v9stat.mtime != -1) {
2528
            times[1].tv_sec = vs->v9stat.mtime;
2529
            times[1].tv_nsec = 0;
2530
        } else {
2531
            times[1].tv_nsec = UTIME_OMIT;
2532
        }
2533

    
2534
        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2535
            err = -errno;
2536
        }
2537
    }
2538

    
2539
    v9fs_wstat_post_utime(s, vs, err);
2540
    return;
2541

    
2542
out:
2543
    v9fs_stat_free(&vs->v9stat);
2544
    complete_pdu(s, vs->pdu, err);
2545
    qemu_free(vs);
2546
}
2547

    
2548
static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2549
{
2550
    if (err == -1) {
2551
        err = -errno;
2552
    }
2553
    v9fs_stat_free(&vs->v9stat);
2554
    complete_pdu(s, vs->pdu, err);
2555
    qemu_free(vs);
2556
}
2557

    
2558
static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2559
{
2560
    uint32_t v9_mode;
2561

    
2562
    if (err == -1) {
2563
        err = -errno;
2564
        goto out;
2565
    }
2566

    
2567
    v9_mode = stat_to_v9mode(&vs->stbuf);
2568

    
2569
    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2570
        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2571
            /* Attempting to change the type */
2572
            err = -EIO;
2573
            goto out;
2574
    }
2575

    
2576
    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2577
                    &vs->v9stat.extension))) {
2578
            err = -errno;
2579
     }
2580
    v9fs_wstat_post_chmod(s, vs, err);
2581
    return;
2582

    
2583
out:
2584
    v9fs_stat_free(&vs->v9stat);
2585
    complete_pdu(s, vs->pdu, err);
2586
    qemu_free(vs);
2587
}
2588

    
2589
static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
2590
{
2591
    int32_t fid;
2592
    V9fsWstatState *vs;
2593
    int err = 0;
2594

    
2595
    vs = qemu_malloc(sizeof(*vs));
2596
    vs->pdu = pdu;
2597
    vs->offset = 7;
2598

    
2599
    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2600

    
2601
    vs->fidp = lookup_fid(s, fid);
2602
    if (vs->fidp == NULL) {
2603
        err = -EINVAL;
2604
        goto out;
2605
    }
2606

    
2607
    /* do we need to sync the file? */
2608
    if (donttouch_stat(&vs->v9stat)) {
2609
        err = v9fs_do_fsync(s, vs->fidp->fd);
2610
        v9fs_wstat_post_fsync(s, vs, err);
2611
        return;
2612
    }
2613

    
2614
    if (vs->v9stat.mode != -1) {
2615
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2616
        v9fs_wstat_post_lstat(s, vs, err);
2617
        return;
2618
    }
2619

    
2620
    v9fs_wstat_post_chmod(s, vs, err);
2621
    return;
2622

    
2623
out:
2624
    v9fs_stat_free(&vs->v9stat);
2625
    complete_pdu(s, vs->pdu, err);
2626
    qemu_free(vs);
2627
}
2628

    
2629
static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
2630
{
2631
    int32_t bsize_factor;
2632

    
2633
    if (err) {
2634
        err = -errno;
2635
        goto out;
2636
    }
2637

    
2638
    /*
2639
     * compute bsize factor based on host file system block size
2640
     * and client msize
2641
     */
2642
    bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
2643
    if (!bsize_factor) {
2644
        bsize_factor = 1;
2645
    }
2646
    vs->v9statfs.f_type = vs->stbuf.f_type;
2647
    vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
2648
    vs->v9statfs.f_bsize *= bsize_factor;
2649
    /*
2650
     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2651
     * adjust(divide) the number of blocks, free blocks and available
2652
     * blocks by bsize factor
2653
     */
2654
    vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
2655
    vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
2656
    vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
2657
    vs->v9statfs.f_files = vs->stbuf.f_files;
2658
    vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
2659
    vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
2660
                        (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
2661
    vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
2662

    
2663
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
2664
         vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
2665
         vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
2666
         vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
2667
         vs->v9statfs.f_namelen);
2668

    
2669
out:
2670
    complete_pdu(s, vs->pdu, vs->offset);
2671
    qemu_free(vs);
2672
}
2673

    
2674
static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
2675
{
2676
    V9fsStatfsState *vs;
2677
    ssize_t err = 0;
2678

    
2679
    vs = qemu_malloc(sizeof(*vs));
2680
    vs->pdu = pdu;
2681
    vs->offset = 7;
2682

    
2683
    memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
2684

    
2685
    pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
2686

    
2687
    vs->fidp = lookup_fid(s, vs->fid);
2688
    if (vs->fidp == NULL) {
2689
        err = -ENOENT;
2690
        goto out;
2691
    }
2692

    
2693
    err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
2694
    v9fs_statfs_post_statfs(s, vs, err);
2695
    return;
2696

    
2697
out:
2698
    complete_pdu(s, vs->pdu, err);
2699
    qemu_free(vs);
2700
}
2701

    
2702
typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
2703

    
2704
static pdu_handler_t *pdu_handlers[] = {
2705
    [P9_TREADDIR] = v9fs_readdir,
2706
    [P9_TSTATFS] = v9fs_statfs,
2707
    [P9_TGETATTR] = v9fs_getattr,
2708
    [P9_TSETATTR] = v9fs_setattr,
2709
    [P9_TVERSION] = v9fs_version,
2710
    [P9_TATTACH] = v9fs_attach,
2711
    [P9_TSTAT] = v9fs_stat,
2712
    [P9_TWALK] = v9fs_walk,
2713
    [P9_TCLUNK] = v9fs_clunk,
2714
    [P9_TOPEN] = v9fs_open,
2715
    [P9_TREAD] = v9fs_read,
2716
#if 0
2717
    [P9_TAUTH] = v9fs_auth,
2718
#endif
2719
    [P9_TFLUSH] = v9fs_flush,
2720
    [P9_TLINK] = v9fs_link,
2721
    [P9_TCREATE] = v9fs_create,
2722
    [P9_TWRITE] = v9fs_write,
2723
    [P9_TWSTAT] = v9fs_wstat,
2724
    [P9_TREMOVE] = v9fs_remove,
2725
};
2726

    
2727
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
2728
{
2729
    pdu_handler_t *handler;
2730

    
2731
    if (debug_9p_pdu) {
2732
        pprint_pdu(pdu);
2733
    }
2734

    
2735
    BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
2736

    
2737
    handler = pdu_handlers[pdu->id];
2738
    BUG_ON(handler == NULL);
2739

    
2740
    handler(s, pdu);
2741
}
2742

    
2743
static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
2744
{
2745
    V9fsState *s = (V9fsState *)vdev;
2746
    V9fsPDU *pdu;
2747
    ssize_t len;
2748

    
2749
    while ((pdu = alloc_pdu(s)) &&
2750
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
2751
        uint8_t *ptr;
2752

    
2753
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
2754
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
2755

    
2756
        ptr = pdu->elem.out_sg[0].iov_base;
2757

    
2758
        memcpy(&pdu->size, ptr, 4);
2759
        pdu->id = ptr[4];
2760
        memcpy(&pdu->tag, ptr + 5, 2);
2761

    
2762
        submit_pdu(s, pdu);
2763
    }
2764

    
2765
    free_pdu(s, pdu);
2766
}
2767

    
2768
static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
2769
{
2770
    features |= 1 << VIRTIO_9P_MOUNT_TAG;
2771
    return features;
2772
}
2773

    
2774
static V9fsState *to_virtio_9p(VirtIODevice *vdev)
2775
{
2776
    return (V9fsState *)vdev;
2777
}
2778

    
2779
static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
2780
{
2781
    struct virtio_9p_config *cfg;
2782
    V9fsState *s = to_virtio_9p(vdev);
2783

    
2784
    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
2785
                        s->tag_len);
2786
    stw_raw(&cfg->tag_len, s->tag_len);
2787
    memcpy(cfg->tag, s->tag, s->tag_len);
2788
    memcpy(config, cfg, s->config_size);
2789
    qemu_free(cfg);
2790
}
2791

    
2792
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
2793
 {
2794
    V9fsState *s;
2795
    int i, len;
2796
    struct stat stat;
2797
    FsTypeEntry *fse;
2798

    
2799

    
2800
    s = (V9fsState *)virtio_common_init("virtio-9p",
2801
                                    VIRTIO_ID_9P,
2802
                                    sizeof(struct virtio_9p_config)+
2803
                                    MAX_TAG_LEN,
2804
                                    sizeof(V9fsState));
2805

    
2806
    /* initialize pdu allocator */
2807
    QLIST_INIT(&s->free_list);
2808
    for (i = 0; i < (MAX_REQ - 1); i++) {
2809
        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
2810
    }
2811

    
2812
    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
2813

    
2814
    fse = get_fsdev_fsentry(conf->fsdev_id);
2815

    
2816
    if (!fse) {
2817
        /* We don't have a fsdev identified by fsdev_id */
2818
        fprintf(stderr, "Virtio-9p device couldn't find fsdev "
2819
                    "with the id %s\n", conf->fsdev_id);
2820
        exit(1);
2821
    }
2822

    
2823
    if (!fse->path || !conf->tag) {
2824
        /* we haven't specified a mount_tag or the path */
2825
        fprintf(stderr, "fsdev with id %s needs path "
2826
                "and Virtio-9p device needs mount_tag arguments\n",
2827
                conf->fsdev_id);
2828
        exit(1);
2829
    }
2830

    
2831
    if (!strcmp(fse->security_model, "passthrough")) {
2832
        /* Files on the Fileserver set to client user credentials */
2833
        s->ctx.fs_sm = SM_PASSTHROUGH;
2834
    } else if (!strcmp(fse->security_model, "mapped")) {
2835
        /* Files on the fileserver are set to QEMU credentials.
2836
         * Client user credentials are saved in extended attributes.
2837
         */
2838
        s->ctx.fs_sm = SM_MAPPED;
2839
    } else {
2840
        /* user haven't specified a correct security option */
2841
        fprintf(stderr, "one of the following must be specified as the"
2842
                "security option:\n\t security_model=passthrough \n\t "
2843
                "security_model=mapped\n");
2844
        return NULL;
2845
    }
2846

    
2847
    if (lstat(fse->path, &stat)) {
2848
        fprintf(stderr, "share path %s does not exist\n", fse->path);
2849
        exit(1);
2850
    } else if (!S_ISDIR(stat.st_mode)) {
2851
        fprintf(stderr, "share path %s is not a directory \n", fse->path);
2852
        exit(1);
2853
    }
2854

    
2855
    s->ctx.fs_root = qemu_strdup(fse->path);
2856
    len = strlen(conf->tag);
2857
    if (len > MAX_TAG_LEN) {
2858
        len = MAX_TAG_LEN;
2859
    }
2860
    /* s->tag is non-NULL terminated string */
2861
    s->tag = qemu_malloc(len);
2862
    memcpy(s->tag, conf->tag, len);
2863
    s->tag_len = len;
2864
    s->ctx.uid = -1;
2865

    
2866
    s->ops = fse->ops;
2867
    s->vdev.get_features = virtio_9p_get_features;
2868
    s->config_size = sizeof(struct virtio_9p_config) +
2869
                        s->tag_len;
2870
    s->vdev.get_config = virtio_9p_get_config;
2871

    
2872
    return &s->vdev;
2873
}