Statistics
| Branch: | Revision:

root / hw / 9pfs / virtio-9p.c @ e4e414a4

History | View | Annotate | Download (84 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 "hw/virtio.h"
15
#include "hw/pc.h"
16
#include "qemu_socket.h"
17
#include "hw/virtio-pci.h"
18
#include "virtio-9p.h"
19
#include "fsdev/qemu-fsdev.h"
20
#include "virtio-9p-debug.h"
21
#include "virtio-9p-xattr.h"
22
#include "virtio-9p-coth.h"
23

    
24
int debug_9p_pdu;
25

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

    
38
static int omode_to_uflags(int8_t mode)
39
{
40
    int ret = 0;
41

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

    
57
    if (mode & Otrunc) {
58
        ret |= O_TRUNC;
59
    }
60

    
61
    if (mode & Oappend) {
62
        ret |= O_APPEND;
63
    }
64

    
65
    if (mode & Oexcl) {
66
        ret |= O_EXCL;
67
    }
68

    
69
    return ret;
70
}
71

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

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

    
85
static int v9fs_do_close(V9fsState *s, int fd)
86
{
87
    return s->ops->close(&s->ctx, fd);
88
}
89

    
90
static int v9fs_do_closedir(V9fsState *s, DIR *dir)
91
{
92
    return s->ops->closedir(&s->ctx, dir);
93
}
94

    
95
static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
96
{
97
    return s->ops->open(&s->ctx, path->data, flags);
98
}
99

    
100
static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
101
{
102
    return s->ops->opendir(&s->ctx, path->data);
103
}
104

    
105
static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
106
{
107
    return s->ops->rewinddir(&s->ctx, dir);
108
}
109

    
110
static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
111
{
112
    return s->ops->telldir(&s->ctx, dir);
113
}
114

    
115
static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
116
{
117
    return s->ops->seekdir(&s->ctx, dir, off);
118
}
119

    
120
static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
121
                            int iovcnt, int64_t offset)
122
{
123
    return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
124
}
125

    
126
static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
127
                       int iovcnt, int64_t offset)
128
{
129
    return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
130
}
131

    
132
static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
133
{
134
    FsCred cred;
135
    cred_init(&cred);
136
    cred.fc_mode = mode;
137
    return s->ops->chmod(&s->ctx, path->data, &cred);
138
}
139

    
140
static int v9fs_do_mknod(V9fsState *s, char *name,
141
        mode_t mode, dev_t dev, uid_t uid, gid_t gid)
142
{
143
    FsCred cred;
144
    cred_init(&cred);
145
    cred.fc_uid = uid;
146
    cred.fc_gid = gid;
147
    cred.fc_mode = mode;
148
    cred.fc_rdev = dev;
149
    return s->ops->mknod(&s->ctx, name, &cred);
150
}
151

    
152
static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
153
{
154
    return s->ops->fstat(&s->ctx, fd, stbuf);
155
}
156

    
157
static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
158
        int flags, int mode)
159
{
160
    FsCred cred;
161

    
162
    cred_init(&cred);
163
    cred.fc_uid = uid;
164
    cred.fc_gid = gid;
165
    cred.fc_mode = mode & 07777;
166

    
167
    return s->ops->open2(&s->ctx, fullname, flags, &cred);
168
}
169

    
170
static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
171
        const char *oldpath, const char *newpath, gid_t gid)
172
{
173
    FsCred cred;
174
    cred_init(&cred);
175
    cred.fc_uid = fidp->uid;
176
    cred.fc_gid = gid;
177
    cred.fc_mode = 0777;
178

    
179
    return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
180
}
181

    
182
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
183
{
184
    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
185
}
186

    
187
static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
188
{
189
    return s->ops->truncate(&s->ctx, path->data, size);
190
}
191

    
192
static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
193
{
194
    FsCred cred;
195
    cred_init(&cred);
196
    cred.fc_uid = uid;
197
    cred.fc_gid = gid;
198

    
199
    return s->ops->chown(&s->ctx, path->data, &cred);
200
}
201

    
202
static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
203
                                           const struct timespec times[2])
204
{
205
    return s->ops->utimensat(&s->ctx, path->data, times);
206
}
207

    
208
static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
209
{
210
    return s->ops->fsync(&s->ctx, fd, datasync);
211
}
212

    
213
static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
214
{
215
    return s->ops->statfs(&s->ctx, path->data, stbuf);
216
}
217

    
218
static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
219
                             V9fsString *xattr_name,
220
                             void *value, size_t size, int flags)
221
{
222
    return s->ops->lsetxattr(&s->ctx, path->data,
223
                             xattr_name->data, value, size, flags);
224
}
225

    
226
static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
227
                                V9fsString *xattr_name)
228
{
229
    return s->ops->lremovexattr(&s->ctx, path->data,
230
                                xattr_name->data);
231
}
232

    
233

    
234
static void v9fs_string_init(V9fsString *str)
235
{
236
    str->data = NULL;
237
    str->size = 0;
238
}
239

    
240
static void v9fs_string_free(V9fsString *str)
241
{
242
    g_free(str->data);
243
    str->data = NULL;
244
    str->size = 0;
245
}
246

    
247
static void v9fs_string_null(V9fsString *str)
248
{
249
    v9fs_string_free(str);
250
}
251

    
252
static int number_to_string(void *arg, char type)
253
{
254
    unsigned int ret = 0;
255

    
256
    switch (type) {
257
    case 'u': {
258
        unsigned int num = *(unsigned int *)arg;
259

    
260
        do {
261
            ret++;
262
            num = num/10;
263
        } while (num);
264
        break;
265
    }
266
    case 'U': {
267
        unsigned long num = *(unsigned long *)arg;
268
        do {
269
            ret++;
270
            num = num/10;
271
        } while (num);
272
        break;
273
    }
274
    default:
275
        printf("Number_to_string: Unknown number format\n");
276
        return -1;
277
    }
278

    
279
    return ret;
280
}
281

    
282
static int GCC_FMT_ATTR(2, 0)
283
v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
284
{
285
    va_list ap2;
286
    char *iter = (char *)fmt;
287
    int len = 0;
288
    int nr_args = 0;
289
    char *arg_char_ptr;
290
    unsigned int arg_uint;
291
    unsigned long arg_ulong;
292

    
293
    /* Find the number of %'s that denotes an argument */
294
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
295
        nr_args++;
296
        iter++;
297
    }
298

    
299
    len = strlen(fmt) - 2*nr_args;
300

    
301
    if (!nr_args) {
302
        goto alloc_print;
303
    }
304

    
305
    va_copy(ap2, ap);
306

    
307
    iter = (char *)fmt;
308

    
309
    /* Now parse the format string */
310
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
311
        iter++;
312
        switch (*iter) {
313
        case 'u':
314
            arg_uint = va_arg(ap2, unsigned int);
315
            len += number_to_string((void *)&arg_uint, 'u');
316
            break;
317
        case 'l':
318
            if (*++iter == 'u') {
319
                arg_ulong = va_arg(ap2, unsigned long);
320
                len += number_to_string((void *)&arg_ulong, 'U');
321
            } else {
322
                return -1;
323
            }
324
            break;
325
        case 's':
326
            arg_char_ptr = va_arg(ap2, char *);
327
            len += strlen(arg_char_ptr);
328
            break;
329
        case 'c':
330
            len += 1;
331
            break;
332
        default:
333
            fprintf(stderr,
334
                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
335
            return -1;
336
        }
337
        iter++;
338
    }
339

    
340
alloc_print:
341
    *strp = g_malloc((len + 1) * sizeof(**strp));
342

    
343
    return vsprintf(*strp, fmt, ap);
344
}
345

    
346
static void GCC_FMT_ATTR(2, 3)
347
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
348
{
349
    va_list ap;
350
    int err;
351

    
352
    v9fs_string_free(str);
353

    
354
    va_start(ap, fmt);
355
    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
356
    BUG_ON(err == -1);
357
    va_end(ap);
358

    
359
    str->size = err;
360
}
361

    
362
static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
363
{
364
    v9fs_string_free(lhs);
365
    v9fs_string_sprintf(lhs, "%s", rhs->data);
366
}
367

    
368
/*
369
 * Return TRUE if s1 is an ancestor of s2.
370
 *
371
 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
372
 * As a special case, We treat s1 as ancestor of s2 if they are same!
373
 */
374
static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
375
{
376
    if (!strncmp(s1->data, s2->data, s1->size)) {
377
        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
378
            return 1;
379
        }
380
    }
381
    return 0;
382
}
383

    
384
static size_t v9fs_string_size(V9fsString *str)
385
{
386
    return str->size;
387
}
388

    
389
static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
390
{
391
    V9fsFidState *f;
392

    
393
    for (f = s->fid_list; f; f = f->next) {
394
        if (f->fid == fid) {
395
            return f;
396
        }
397
    }
398

    
399
    return NULL;
400
}
401

    
402
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
403
{
404
    V9fsFidState *f;
405

    
406
    f = lookup_fid(s, fid);
407
    if (f) {
408
        return NULL;
409
    }
410

    
411
    f = g_malloc0(sizeof(V9fsFidState));
412

    
413
    f->fid = fid;
414
    f->fid_type = P9_FID_NONE;
415

    
416
    f->next = s->fid_list;
417
    s->fid_list = f;
418

    
419
    return f;
420
}
421

    
422
static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
423
{
424
    int retval = 0;
425

    
426
    if (fidp->fs.xattr.copied_len == -1) {
427
        /* getxattr/listxattr fid */
428
        goto free_value;
429
    }
430
    /*
431
     * if this is fid for setxattr. clunk should
432
     * result in setxattr localcall
433
     */
434
    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
435
        /* clunk after partial write */
436
        retval = -EINVAL;
437
        goto free_out;
438
    }
439
    if (fidp->fs.xattr.len) {
440
        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
441
                                   fidp->fs.xattr.value,
442
                                   fidp->fs.xattr.len,
443
                                   fidp->fs.xattr.flags);
444
    } else {
445
        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
446
    }
447
free_out:
448
    v9fs_string_free(&fidp->fs.xattr.name);
449
free_value:
450
    if (fidp->fs.xattr.value) {
451
        g_free(fidp->fs.xattr.value);
452
    }
453
    return retval;
454
}
455

    
456
static int free_fid(V9fsState *s, int32_t fid)
457
{
458
    int retval = 0;
459
    V9fsFidState **fidpp, *fidp;
460

    
461
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
462
        if ((*fidpp)->fid == fid) {
463
            break;
464
        }
465
    }
466

    
467
    if (*fidpp == NULL) {
468
        return -ENOENT;
469
    }
470

    
471
    fidp = *fidpp;
472
    *fidpp = fidp->next;
473

    
474
    if (fidp->fid_type == P9_FID_FILE) {
475
        v9fs_do_close(s, fidp->fs.fd);
476
    } else if (fidp->fid_type == P9_FID_DIR) {
477
        v9fs_do_closedir(s, fidp->fs.dir);
478
    } else if (fidp->fid_type == P9_FID_XATTR) {
479
        retval = v9fs_xattr_fid_clunk(s, fidp);
480
    }
481
    v9fs_string_free(&fidp->path);
482
    g_free(fidp);
483

    
484
    return retval;
485
}
486

    
487
#define P9_QID_TYPE_DIR         0x80
488
#define P9_QID_TYPE_SYMLINK     0x02
489

    
490
#define P9_STAT_MODE_DIR        0x80000000
491
#define P9_STAT_MODE_APPEND     0x40000000
492
#define P9_STAT_MODE_EXCL       0x20000000
493
#define P9_STAT_MODE_MOUNT      0x10000000
494
#define P9_STAT_MODE_AUTH       0x08000000
495
#define P9_STAT_MODE_TMP        0x04000000
496
#define P9_STAT_MODE_SYMLINK    0x02000000
497
#define P9_STAT_MODE_LINK       0x01000000
498
#define P9_STAT_MODE_DEVICE     0x00800000
499
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
500
#define P9_STAT_MODE_SOCKET     0x00100000
501
#define P9_STAT_MODE_SETUID     0x00080000
502
#define P9_STAT_MODE_SETGID     0x00040000
503
#define P9_STAT_MODE_SETVTX     0x00010000
504

    
505
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
506
                                P9_STAT_MODE_SYMLINK |      \
507
                                P9_STAT_MODE_LINK |         \
508
                                P9_STAT_MODE_DEVICE |       \
509
                                P9_STAT_MODE_NAMED_PIPE |   \
510
                                P9_STAT_MODE_SOCKET)
511

    
512
/* This is the algorithm from ufs in spfs */
513
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
514
{
515
    size_t size;
516

    
517
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
518
    memcpy(&qidp->path, &stbuf->st_ino, size);
519
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
520
    qidp->type = 0;
521
    if (S_ISDIR(stbuf->st_mode)) {
522
        qidp->type |= P9_QID_TYPE_DIR;
523
    }
524
    if (S_ISLNK(stbuf->st_mode)) {
525
        qidp->type |= P9_QID_TYPE_SYMLINK;
526
    }
527
}
528

    
529
static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
530
{
531
    struct stat stbuf;
532
    int err;
533

    
534
    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
535
    if (err) {
536
        return err;
537
    }
538

    
539
    stat_to_qid(&stbuf, qidp);
540
    return 0;
541
}
542

    
543
static V9fsPDU *alloc_pdu(V9fsState *s)
544
{
545
    V9fsPDU *pdu = NULL;
546

    
547
    if (!QLIST_EMPTY(&s->free_list)) {
548
        pdu = QLIST_FIRST(&s->free_list);
549
        QLIST_REMOVE(pdu, next);
550
    }
551
    return pdu;
552
}
553

    
554
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
555
{
556
    if (pdu) {
557
        if (debug_9p_pdu) {
558
            pprint_pdu(pdu);
559
        }
560
        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
561
    }
562
}
563

    
564
size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
565
                        size_t offset, size_t size, int pack)
566
{
567
    int i = 0;
568
    size_t copied = 0;
569

    
570
    for (i = 0; size && i < sg_count; i++) {
571
        size_t len;
572
        if (offset >= sg[i].iov_len) {
573
            /* skip this sg */
574
            offset -= sg[i].iov_len;
575
            continue;
576
        } else {
577
            len = MIN(sg[i].iov_len - offset, size);
578
            if (pack) {
579
                memcpy(sg[i].iov_base + offset, addr, len);
580
            } else {
581
                memcpy(addr, sg[i].iov_base + offset, len);
582
            }
583
            size -= len;
584
            copied += len;
585
            addr += len;
586
            if (size) {
587
                offset = 0;
588
                continue;
589
            }
590
        }
591
    }
592

    
593
    return copied;
594
}
595

    
596
static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
597
{
598
    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
599
                         offset, size, 0);
600
}
601

    
602
static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
603
                        size_t size)
604
{
605
    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
606
                             offset, size, 1);
607
}
608

    
609
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
610
{
611
    size_t pos = 0;
612
    int i, j;
613
    struct iovec *src_sg;
614
    unsigned int num;
615

    
616
    if (rx) {
617
        src_sg = pdu->elem.in_sg;
618
        num = pdu->elem.in_num;
619
    } else {
620
        src_sg = pdu->elem.out_sg;
621
        num = pdu->elem.out_num;
622
    }
623

    
624
    j = 0;
625
    for (i = 0; i < num; i++) {
626
        if (offset <= pos) {
627
            sg[j].iov_base = src_sg[i].iov_base;
628
            sg[j].iov_len = src_sg[i].iov_len;
629
            j++;
630
        } else if (offset < (src_sg[i].iov_len + pos)) {
631
            sg[j].iov_base = src_sg[i].iov_base;
632
            sg[j].iov_len = src_sg[i].iov_len;
633
            sg[j].iov_base += (offset - pos);
634
            sg[j].iov_len -= (offset - pos);
635
            j++;
636
        }
637
        pos += src_sg[i].iov_len;
638
    }
639

    
640
    return j;
641
}
642

    
643
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
644
{
645
    size_t old_offset = offset;
646
    va_list ap;
647
    int i;
648

    
649
    va_start(ap, fmt);
650
    for (i = 0; fmt[i]; i++) {
651
        switch (fmt[i]) {
652
        case 'b': {
653
            uint8_t *valp = va_arg(ap, uint8_t *);
654
            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
655
            break;
656
        }
657
        case 'w': {
658
            uint16_t val, *valp;
659
            valp = va_arg(ap, uint16_t *);
660
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
661
            *valp = le16_to_cpu(val);
662
            break;
663
        }
664
        case 'd': {
665
            uint32_t val, *valp;
666
            valp = va_arg(ap, uint32_t *);
667
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
668
            *valp = le32_to_cpu(val);
669
            break;
670
        }
671
        case 'q': {
672
            uint64_t val, *valp;
673
            valp = va_arg(ap, uint64_t *);
674
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
675
            *valp = le64_to_cpu(val);
676
            break;
677
        }
678
        case 'v': {
679
            struct iovec *iov = va_arg(ap, struct iovec *);
680
            int *iovcnt = va_arg(ap, int *);
681
            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
682
            break;
683
        }
684
        case 's': {
685
            V9fsString *str = va_arg(ap, V9fsString *);
686
            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
687
            /* FIXME: sanity check str->size */
688
            str->data = g_malloc(str->size + 1);
689
            offset += pdu_unpack(str->data, pdu, offset, str->size);
690
            str->data[str->size] = 0;
691
            break;
692
        }
693
        case 'Q': {
694
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
695
            offset += pdu_unmarshal(pdu, offset, "bdq",
696
                        &qidp->type, &qidp->version, &qidp->path);
697
            break;
698
        }
699
        case 'S': {
700
            V9fsStat *statp = va_arg(ap, V9fsStat *);
701
            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
702
                        &statp->size, &statp->type, &statp->dev,
703
                        &statp->qid, &statp->mode, &statp->atime,
704
                        &statp->mtime, &statp->length,
705
                        &statp->name, &statp->uid, &statp->gid,
706
                        &statp->muid, &statp->extension,
707
                        &statp->n_uid, &statp->n_gid,
708
                        &statp->n_muid);
709
            break;
710
        }
711
        case 'I': {
712
            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
713
            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
714
                        &iattr->valid, &iattr->mode,
715
                        &iattr->uid, &iattr->gid, &iattr->size,
716
                        &iattr->atime_sec, &iattr->atime_nsec,
717
                        &iattr->mtime_sec, &iattr->mtime_nsec);
718
            break;
719
        }
720
        default:
721
            break;
722
        }
723
    }
724

    
725
    va_end(ap);
726

    
727
    return offset - old_offset;
728
}
729

    
730
static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
731
{
732
    size_t old_offset = offset;
733
    va_list ap;
734
    int i;
735

    
736
    va_start(ap, fmt);
737
    for (i = 0; fmt[i]; i++) {
738
        switch (fmt[i]) {
739
        case 'b': {
740
            uint8_t val = va_arg(ap, int);
741
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
742
            break;
743
        }
744
        case 'w': {
745
            uint16_t val;
746
            cpu_to_le16w(&val, va_arg(ap, int));
747
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
748
            break;
749
        }
750
        case 'd': {
751
            uint32_t val;
752
            cpu_to_le32w(&val, va_arg(ap, uint32_t));
753
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
754
            break;
755
        }
756
        case 'q': {
757
            uint64_t val;
758
            cpu_to_le64w(&val, va_arg(ap, uint64_t));
759
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
760
            break;
761
        }
762
        case 'v': {
763
            struct iovec *iov = va_arg(ap, struct iovec *);
764
            int *iovcnt = va_arg(ap, int *);
765
            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
766
            break;
767
        }
768
        case 's': {
769
            V9fsString *str = va_arg(ap, V9fsString *);
770
            offset += pdu_marshal(pdu, offset, "w", str->size);
771
            offset += pdu_pack(pdu, offset, str->data, str->size);
772
            break;
773
        }
774
        case 'Q': {
775
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
776
            offset += pdu_marshal(pdu, offset, "bdq",
777
                        qidp->type, qidp->version, qidp->path);
778
            break;
779
        }
780
        case 'S': {
781
            V9fsStat *statp = va_arg(ap, V9fsStat *);
782
            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
783
                        statp->size, statp->type, statp->dev,
784
                        &statp->qid, statp->mode, statp->atime,
785
                        statp->mtime, statp->length, &statp->name,
786
                        &statp->uid, &statp->gid, &statp->muid,
787
                        &statp->extension, statp->n_uid,
788
                        statp->n_gid, statp->n_muid);
789
            break;
790
        }
791
        case 'A': {
792
            V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
793
            offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
794
                        statp->st_result_mask,
795
                        &statp->qid, statp->st_mode,
796
                        statp->st_uid, statp->st_gid,
797
                        statp->st_nlink, statp->st_rdev,
798
                        statp->st_size, statp->st_blksize, statp->st_blocks,
799
                        statp->st_atime_sec, statp->st_atime_nsec,
800
                        statp->st_mtime_sec, statp->st_mtime_nsec,
801
                        statp->st_ctime_sec, statp->st_ctime_nsec,
802
                        statp->st_btime_sec, statp->st_btime_nsec,
803
                        statp->st_gen, statp->st_data_version);
804
            break;
805
        }
806
        default:
807
            break;
808
        }
809
    }
810
    va_end(ap);
811

    
812
    return offset - old_offset;
813
}
814

    
815
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
816
{
817
    int8_t id = pdu->id + 1; /* Response */
818

    
819
    if (len < 0) {
820
        int err = -len;
821
        len = 7;
822

    
823
        if (s->proto_version != V9FS_PROTO_2000L) {
824
            V9fsString str;
825

    
826
            str.data = strerror(err);
827
            str.size = strlen(str.data);
828

    
829
            len += pdu_marshal(pdu, len, "s", &str);
830
            id = P9_RERROR;
831
        }
832

    
833
        len += pdu_marshal(pdu, len, "d", err);
834

    
835
        if (s->proto_version == V9FS_PROTO_2000L) {
836
            id = P9_RLERROR;
837
        }
838
    }
839

    
840
    /* fill out the header */
841
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
842

    
843
    /* keep these in sync */
844
    pdu->size = len;
845
    pdu->id = id;
846

    
847
    /* push onto queue and notify */
848
    virtqueue_push(s->vq, &pdu->elem, len);
849

    
850
    /* FIXME: we should batch these completions */
851
    virtio_notify(&s->vdev, s->vq);
852

    
853
    free_pdu(s, pdu);
854
}
855

    
856
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
857
{
858
    mode_t ret;
859

    
860
    ret = mode & 0777;
861
    if (mode & P9_STAT_MODE_DIR) {
862
        ret |= S_IFDIR;
863
    }
864

    
865
    if (mode & P9_STAT_MODE_SYMLINK) {
866
        ret |= S_IFLNK;
867
    }
868
    if (mode & P9_STAT_MODE_SOCKET) {
869
        ret |= S_IFSOCK;
870
    }
871
    if (mode & P9_STAT_MODE_NAMED_PIPE) {
872
        ret |= S_IFIFO;
873
    }
874
    if (mode & P9_STAT_MODE_DEVICE) {
875
        if (extension && extension->data[0] == 'c') {
876
            ret |= S_IFCHR;
877
        } else {
878
            ret |= S_IFBLK;
879
        }
880
    }
881

    
882
    if (!(ret&~0777)) {
883
        ret |= S_IFREG;
884
    }
885

    
886
    if (mode & P9_STAT_MODE_SETUID) {
887
        ret |= S_ISUID;
888
    }
889
    if (mode & P9_STAT_MODE_SETGID) {
890
        ret |= S_ISGID;
891
    }
892
    if (mode & P9_STAT_MODE_SETVTX) {
893
        ret |= S_ISVTX;
894
    }
895

    
896
    return ret;
897
}
898

    
899
static int donttouch_stat(V9fsStat *stat)
900
{
901
    if (stat->type == -1 &&
902
        stat->dev == -1 &&
903
        stat->qid.type == -1 &&
904
        stat->qid.version == -1 &&
905
        stat->qid.path == -1 &&
906
        stat->mode == -1 &&
907
        stat->atime == -1 &&
908
        stat->mtime == -1 &&
909
        stat->length == -1 &&
910
        !stat->name.size &&
911
        !stat->uid.size &&
912
        !stat->gid.size &&
913
        !stat->muid.size &&
914
        stat->n_uid == -1 &&
915
        stat->n_gid == -1 &&
916
        stat->n_muid == -1) {
917
        return 1;
918
    }
919

    
920
    return 0;
921
}
922

    
923
static void v9fs_stat_free(V9fsStat *stat)
924
{
925
    v9fs_string_free(&stat->name);
926
    v9fs_string_free(&stat->uid);
927
    v9fs_string_free(&stat->gid);
928
    v9fs_string_free(&stat->muid);
929
    v9fs_string_free(&stat->extension);
930
}
931

    
932
static uint32_t stat_to_v9mode(const struct stat *stbuf)
933
{
934
    uint32_t mode;
935

    
936
    mode = stbuf->st_mode & 0777;
937
    if (S_ISDIR(stbuf->st_mode)) {
938
        mode |= P9_STAT_MODE_DIR;
939
    }
940

    
941
    if (S_ISLNK(stbuf->st_mode)) {
942
        mode |= P9_STAT_MODE_SYMLINK;
943
    }
944

    
945
    if (S_ISSOCK(stbuf->st_mode)) {
946
        mode |= P9_STAT_MODE_SOCKET;
947
    }
948

    
949
    if (S_ISFIFO(stbuf->st_mode)) {
950
        mode |= P9_STAT_MODE_NAMED_PIPE;
951
    }
952

    
953
    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
954
        mode |= P9_STAT_MODE_DEVICE;
955
    }
956

    
957
    if (stbuf->st_mode & S_ISUID) {
958
        mode |= P9_STAT_MODE_SETUID;
959
    }
960

    
961
    if (stbuf->st_mode & S_ISGID) {
962
        mode |= P9_STAT_MODE_SETGID;
963
    }
964

    
965
    if (stbuf->st_mode & S_ISVTX) {
966
        mode |= P9_STAT_MODE_SETVTX;
967
    }
968

    
969
    return mode;
970
}
971

    
972
static int stat_to_v9stat(V9fsState *s, V9fsString *name,
973
                            const struct stat *stbuf,
974
                            V9fsStat *v9stat)
975
{
976
    int err;
977
    const char *str;
978

    
979
    memset(v9stat, 0, sizeof(*v9stat));
980

    
981
    stat_to_qid(stbuf, &v9stat->qid);
982
    v9stat->mode = stat_to_v9mode(stbuf);
983
    v9stat->atime = stbuf->st_atime;
984
    v9stat->mtime = stbuf->st_mtime;
985
    v9stat->length = stbuf->st_size;
986

    
987
    v9fs_string_null(&v9stat->uid);
988
    v9fs_string_null(&v9stat->gid);
989
    v9fs_string_null(&v9stat->muid);
990

    
991
    v9stat->n_uid = stbuf->st_uid;
992
    v9stat->n_gid = stbuf->st_gid;
993
    v9stat->n_muid = 0;
994

    
995
    v9fs_string_null(&v9stat->extension);
996

    
997
    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
998
        err = v9fs_co_readlink(s, name, &v9stat->extension);
999
        if (err < 0) {
1000
            return err;
1001
        }
1002
    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1003
        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1004
                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1005
                major(stbuf->st_rdev), minor(stbuf->st_rdev));
1006
    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1007
        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1008
                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1009
    }
1010

    
1011
    str = strrchr(name->data, '/');
1012
    if (str) {
1013
        str += 1;
1014
    } else {
1015
        str = name->data;
1016
    }
1017

    
1018
    v9fs_string_sprintf(&v9stat->name, "%s", str);
1019

    
1020
    v9stat->size = 61 +
1021
        v9fs_string_size(&v9stat->name) +
1022
        v9fs_string_size(&v9stat->uid) +
1023
        v9fs_string_size(&v9stat->gid) +
1024
        v9fs_string_size(&v9stat->muid) +
1025
        v9fs_string_size(&v9stat->extension);
1026
    return 0;
1027
}
1028

    
1029
#define P9_STATS_MODE          0x00000001ULL
1030
#define P9_STATS_NLINK         0x00000002ULL
1031
#define P9_STATS_UID           0x00000004ULL
1032
#define P9_STATS_GID           0x00000008ULL
1033
#define P9_STATS_RDEV          0x00000010ULL
1034
#define P9_STATS_ATIME         0x00000020ULL
1035
#define P9_STATS_MTIME         0x00000040ULL
1036
#define P9_STATS_CTIME         0x00000080ULL
1037
#define P9_STATS_INO           0x00000100ULL
1038
#define P9_STATS_SIZE          0x00000200ULL
1039
#define P9_STATS_BLOCKS        0x00000400ULL
1040

    
1041
#define P9_STATS_BTIME         0x00000800ULL
1042
#define P9_STATS_GEN           0x00001000ULL
1043
#define P9_STATS_DATA_VERSION  0x00002000ULL
1044

    
1045
#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
1046
#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
1047

    
1048

    
1049
static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1050
                                V9fsStatDotl *v9lstat)
1051
{
1052
    memset(v9lstat, 0, sizeof(*v9lstat));
1053

    
1054
    v9lstat->st_mode = stbuf->st_mode;
1055
    v9lstat->st_nlink = stbuf->st_nlink;
1056
    v9lstat->st_uid = stbuf->st_uid;
1057
    v9lstat->st_gid = stbuf->st_gid;
1058
    v9lstat->st_rdev = stbuf->st_rdev;
1059
    v9lstat->st_size = stbuf->st_size;
1060
    v9lstat->st_blksize = stbuf->st_blksize;
1061
    v9lstat->st_blocks = stbuf->st_blocks;
1062
    v9lstat->st_atime_sec = stbuf->st_atime;
1063
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1064
    v9lstat->st_mtime_sec = stbuf->st_mtime;
1065
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1066
    v9lstat->st_ctime_sec = stbuf->st_ctime;
1067
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1068
    /* Currently we only support BASIC fields in stat */
1069
    v9lstat->st_result_mask = P9_STATS_BASIC;
1070

    
1071
    stat_to_qid(stbuf, &v9lstat->qid);
1072
}
1073

    
1074
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1075
{
1076
    while (len && *iovcnt) {
1077
        if (len < sg->iov_len) {
1078
            sg->iov_len -= len;
1079
            sg->iov_base += len;
1080
            len = 0;
1081
        } else {
1082
            len -= sg->iov_len;
1083
            sg++;
1084
            *iovcnt -= 1;
1085
        }
1086
    }
1087

    
1088
    return sg;
1089
}
1090

    
1091
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1092
{
1093
    int i;
1094
    int total = 0;
1095

    
1096
    for (i = 0; i < *cnt; i++) {
1097
        if ((total + sg[i].iov_len) > cap) {
1098
            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1099
            i++;
1100
            break;
1101
        }
1102
        total += sg[i].iov_len;
1103
    }
1104

    
1105
    *cnt = i;
1106

    
1107
    return sg;
1108
}
1109

    
1110
static void print_sg(struct iovec *sg, int cnt)
1111
{
1112
    int i;
1113

    
1114
    printf("sg[%d]: {", cnt);
1115
    for (i = 0; i < cnt; i++) {
1116
        if (i) {
1117
            printf(", ");
1118
        }
1119
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1120
    }
1121
    printf("}\n");
1122
}
1123

    
1124
static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1125
{
1126
    V9fsString str;
1127
    v9fs_string_init(&str);
1128
    v9fs_string_copy(&str, dst);
1129
    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1130
    v9fs_string_free(&str);
1131
}
1132

    
1133
static void v9fs_version(void *opaque)
1134
{
1135
    V9fsPDU *pdu = opaque;
1136
    V9fsState *s = pdu->s;
1137
    V9fsString version;
1138
    size_t offset = 7;
1139

    
1140
    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1141

    
1142
    if (!strcmp(version.data, "9P2000.u")) {
1143
        s->proto_version = V9FS_PROTO_2000U;
1144
    } else if (!strcmp(version.data, "9P2000.L")) {
1145
        s->proto_version = V9FS_PROTO_2000L;
1146
    } else {
1147
        v9fs_string_sprintf(&version, "unknown");
1148
    }
1149

    
1150
    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1151
    complete_pdu(s, pdu, offset);
1152

    
1153
    v9fs_string_free(&version);
1154
    return;
1155
}
1156

    
1157
static void v9fs_attach(void *opaque)
1158
{
1159
    V9fsPDU *pdu = opaque;
1160
    V9fsState *s = pdu->s;
1161
    int32_t fid, afid, n_uname;
1162
    V9fsString uname, aname;
1163
    V9fsFidState *fidp;
1164
    V9fsQID qid;
1165
    size_t offset = 7;
1166
    ssize_t err;
1167

    
1168
    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1169

    
1170
    fidp = alloc_fid(s, fid);
1171
    if (fidp == NULL) {
1172
        err = -EINVAL;
1173
        goto out;
1174
    }
1175

    
1176
    fidp->uid = n_uname;
1177

    
1178
    v9fs_string_sprintf(&fidp->path, "%s", "/");
1179
    err = fid_to_qid(s, fidp, &qid);
1180
    if (err) {
1181
        err = -EINVAL;
1182
        free_fid(s, fid);
1183
        goto out;
1184
    }
1185

    
1186
    offset += pdu_marshal(pdu, offset, "Q", &qid);
1187

    
1188
    err = offset;
1189
out:
1190
    complete_pdu(s, pdu, err);
1191
    v9fs_string_free(&uname);
1192
    v9fs_string_free(&aname);
1193
}
1194

    
1195
static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1196
{
1197
    if (err == -1) {
1198
        err = -errno;
1199
        goto out;
1200
    }
1201

    
1202
    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1203
    if (err) {
1204
        goto out;
1205
    }
1206
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1207
    err = vs->offset;
1208

    
1209
out:
1210
    complete_pdu(s, vs->pdu, err);
1211
    v9fs_stat_free(&vs->v9stat);
1212
    g_free(vs);
1213
}
1214

    
1215
static void v9fs_stat(void *opaque)
1216
{
1217
    V9fsPDU *pdu = opaque;
1218
    V9fsState *s = pdu->s;
1219
    int32_t fid;
1220
    V9fsStatState *vs;
1221
    ssize_t err = 0;
1222

    
1223
    vs = g_malloc(sizeof(*vs));
1224
    vs->pdu = pdu;
1225
    vs->offset = 7;
1226

    
1227
    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1228

    
1229
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1230

    
1231
    vs->fidp = lookup_fid(s, fid);
1232
    if (vs->fidp == NULL) {
1233
        err = -ENOENT;
1234
        goto out;
1235
    }
1236

    
1237
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1238
    v9fs_stat_post_lstat(s, vs, err);
1239
    return;
1240

    
1241
out:
1242
    complete_pdu(s, vs->pdu, err);
1243
    v9fs_stat_free(&vs->v9stat);
1244
    g_free(vs);
1245
}
1246

    
1247
static void v9fs_getattr(void *opaque)
1248
{
1249
    int32_t fid;
1250
    size_t offset = 7;
1251
    ssize_t retval = 0;
1252
    struct stat stbuf;
1253
    V9fsFidState *fidp;
1254
    uint64_t request_mask;
1255
    V9fsStatDotl v9stat_dotl;
1256
    V9fsPDU *pdu = opaque;
1257
    V9fsState *s = pdu->s;
1258

    
1259
    pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1260

    
1261
    fidp = lookup_fid(s, fid);
1262
    if (fidp == NULL) {
1263
        retval = -ENOENT;
1264
        goto out;
1265
    }
1266
    /*
1267
     * Currently we only support BASIC fields in stat, so there is no
1268
     * need to look at request_mask.
1269
     */
1270
    retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1271
    if (retval < 0) {
1272
        goto out;
1273
    }
1274
    stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1275
    retval = offset;
1276
    retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1277
out:
1278
    complete_pdu(s, pdu, retval);
1279
}
1280

    
1281
/* From Linux kernel code */
1282
#define ATTR_MODE    (1 << 0)
1283
#define ATTR_UID     (1 << 1)
1284
#define ATTR_GID     (1 << 2)
1285
#define ATTR_SIZE    (1 << 3)
1286
#define ATTR_ATIME   (1 << 4)
1287
#define ATTR_MTIME   (1 << 5)
1288
#define ATTR_CTIME   (1 << 6)
1289
#define ATTR_MASK    127
1290
#define ATTR_ATIME_SET  (1 << 7)
1291
#define ATTR_MTIME_SET  (1 << 8)
1292

    
1293
static void v9fs_setattr(void *opaque)
1294
{
1295
    int err = 0;
1296
    int32_t fid;
1297
    V9fsFidState *fidp;
1298
    size_t offset = 7;
1299
    V9fsIattr v9iattr;
1300
    V9fsPDU *pdu = opaque;
1301
    V9fsState *s = pdu->s;
1302

    
1303
    pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1304

    
1305
    fidp = lookup_fid(s, fid);
1306
    if (fidp == NULL) {
1307
        err = -EINVAL;
1308
        goto out;
1309
    }
1310
    if (v9iattr.valid & ATTR_MODE) {
1311
        err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
1312
        if (err < 0) {
1313
            goto out;
1314
        }
1315
    }
1316
    if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1317
        struct timespec times[2];
1318
        if (v9iattr.valid & ATTR_ATIME) {
1319
            if (v9iattr.valid & ATTR_ATIME_SET) {
1320
                times[0].tv_sec = v9iattr.atime_sec;
1321
                times[0].tv_nsec = v9iattr.atime_nsec;
1322
            } else {
1323
                times[0].tv_nsec = UTIME_NOW;
1324
            }
1325
        } else {
1326
            times[0].tv_nsec = UTIME_OMIT;
1327
        }
1328
        if (v9iattr.valid & ATTR_MTIME) {
1329
            if (v9iattr.valid & ATTR_MTIME_SET) {
1330
                times[1].tv_sec = v9iattr.mtime_sec;
1331
                times[1].tv_nsec = v9iattr.mtime_nsec;
1332
            } else {
1333
                times[1].tv_nsec = UTIME_NOW;
1334
            }
1335
        } else {
1336
            times[1].tv_nsec = UTIME_OMIT;
1337
        }
1338
        err = v9fs_co_utimensat(s, &fidp->path, times);
1339
        if (err < 0) {
1340
            goto out;
1341
        }
1342
    }
1343
    /*
1344
     * If the only valid entry in iattr is ctime we can call
1345
     * chown(-1,-1) to update the ctime of the file
1346
     */
1347
    if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1348
        ((v9iattr.valid & ATTR_CTIME)
1349
         && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1350
        if (!(v9iattr.valid & ATTR_UID)) {
1351
            v9iattr.uid = -1;
1352
        }
1353
        if (!(v9iattr.valid & ATTR_GID)) {
1354
            v9iattr.gid = -1;
1355
        }
1356
        err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
1357
                            v9iattr.gid);
1358
        if (err < 0) {
1359
            goto out;
1360
        }
1361
    }
1362
    if (v9iattr.valid & (ATTR_SIZE)) {
1363
        err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
1364
        if (err < 0) {
1365
            goto out;
1366
        }
1367
    }
1368
    err = offset;
1369
out:
1370
    complete_pdu(s, pdu, err);
1371
}
1372

    
1373
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1374
{
1375
    complete_pdu(s, vs->pdu, err);
1376

    
1377
    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1378
        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1379
            v9fs_string_free(&vs->wnames[vs->name_idx]);
1380
        }
1381

    
1382
        g_free(vs->wnames);
1383
        g_free(vs->qids);
1384
    }
1385
}
1386

    
1387
static void v9fs_walk_marshal(V9fsWalkState *vs)
1388
{
1389
    int i;
1390
    vs->offset = 7;
1391
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1392

    
1393
    for (i = 0; i < vs->nwnames; i++) {
1394
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1395
    }
1396
}
1397

    
1398
static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1399
                                                                int err)
1400
{
1401
    if (err == -1) {
1402
        free_fid(s, vs->newfidp->fid);
1403
        v9fs_string_free(&vs->path);
1404
        err = -ENOENT;
1405
        goto out;
1406
    }
1407

    
1408
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1409

    
1410
    vs->name_idx++;
1411
    if (vs->name_idx < vs->nwnames) {
1412
        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1413
                                            vs->wnames[vs->name_idx].data);
1414
        v9fs_string_copy(&vs->newfidp->path, &vs->path);
1415

    
1416
        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1417
        v9fs_walk_post_newfid_lstat(s, vs, err);
1418
        return;
1419
    }
1420

    
1421
    v9fs_string_free(&vs->path);
1422
    v9fs_walk_marshal(vs);
1423
    err = vs->offset;
1424
out:
1425
    v9fs_walk_complete(s, vs, err);
1426
}
1427

    
1428
static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1429
        int err)
1430
{
1431
    if (err == -1) {
1432
        v9fs_string_free(&vs->path);
1433
        err = -ENOENT;
1434
        goto out;
1435
    }
1436

    
1437
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1438
    vs->name_idx++;
1439
    if (vs->name_idx < vs->nwnames) {
1440

    
1441
        v9fs_string_sprintf(&vs->path, "%s/%s",
1442
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1443
        v9fs_string_copy(&vs->fidp->path, &vs->path);
1444

    
1445
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1446
        v9fs_walk_post_oldfid_lstat(s, vs, err);
1447
        return;
1448
    }
1449

    
1450
    v9fs_string_free(&vs->path);
1451
    v9fs_walk_marshal(vs);
1452
    err = vs->offset;
1453
out:
1454
    v9fs_walk_complete(s, vs, err);
1455
}
1456

    
1457
static void v9fs_walk(void *opaque)
1458
{
1459
    V9fsPDU *pdu = opaque;
1460
    V9fsState *s = pdu->s;
1461
    int32_t fid, newfid;
1462
    V9fsWalkState *vs;
1463
    int err = 0;
1464
    int i;
1465

    
1466
    vs = g_malloc(sizeof(*vs));
1467
    vs->pdu = pdu;
1468
    vs->wnames = NULL;
1469
    vs->qids = NULL;
1470
    vs->offset = 7;
1471

    
1472
    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1473
                                            &newfid, &vs->nwnames);
1474

    
1475
    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1476
        vs->wnames = g_malloc0(sizeof(vs->wnames[0]) * vs->nwnames);
1477

    
1478
        vs->qids = g_malloc0(sizeof(vs->qids[0]) * vs->nwnames);
1479

    
1480
        for (i = 0; i < vs->nwnames; i++) {
1481
            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1482
                                            &vs->wnames[i]);
1483
        }
1484
    } else if (vs->nwnames > P9_MAXWELEM) {
1485
        err = -EINVAL;
1486
        goto out;
1487
    }
1488

    
1489
    vs->fidp = lookup_fid(s, fid);
1490
    if (vs->fidp == NULL) {
1491
        err = -ENOENT;
1492
        goto out;
1493
    }
1494

    
1495
    /* FIXME: is this really valid? */
1496
    if (fid == newfid) {
1497

    
1498
        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1499
        v9fs_string_init(&vs->path);
1500
        vs->name_idx = 0;
1501

    
1502
        if (vs->name_idx < vs->nwnames) {
1503
            v9fs_string_sprintf(&vs->path, "%s/%s",
1504
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1505
            v9fs_string_copy(&vs->fidp->path, &vs->path);
1506

    
1507
            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1508
            v9fs_walk_post_oldfid_lstat(s, vs, err);
1509
            return;
1510
        }
1511
    } else {
1512
        vs->newfidp = alloc_fid(s, newfid);
1513
        if (vs->newfidp == NULL) {
1514
            err = -EINVAL;
1515
            goto out;
1516
        }
1517

    
1518
        vs->newfidp->uid = vs->fidp->uid;
1519
        v9fs_string_init(&vs->path);
1520
        vs->name_idx = 0;
1521
        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1522

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

    
1528
            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1529
            v9fs_walk_post_newfid_lstat(s, vs, err);
1530
            return;
1531
        }
1532
    }
1533

    
1534
    v9fs_walk_marshal(vs);
1535
    err = vs->offset;
1536
out:
1537
    v9fs_walk_complete(s, vs, err);
1538
}
1539

    
1540
static int32_t get_iounit(V9fsState *s, V9fsString *name)
1541
{
1542
    struct statfs stbuf;
1543
    int32_t iounit = 0;
1544

    
1545
    /*
1546
     * iounit should be multiples of f_bsize (host filesystem block size
1547
     * and as well as less than (client msize - P9_IOHDRSZ))
1548
     */
1549
    if (!v9fs_do_statfs(s, name, &stbuf)) {
1550
        iounit = stbuf.f_bsize;
1551
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1552
    }
1553

    
1554
    if (!iounit) {
1555
        iounit = s->msize - P9_IOHDRSZ;
1556
    }
1557
    return iounit;
1558
}
1559

    
1560
static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1561
{
1562
    if (vs->fidp->fs.dir == NULL) {
1563
        err = -errno;
1564
        goto out;
1565
    }
1566
    vs->fidp->fid_type = P9_FID_DIR;
1567
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1568
    err = vs->offset;
1569
out:
1570
    complete_pdu(s, vs->pdu, err);
1571
    g_free(vs);
1572

    
1573
}
1574

    
1575
static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1576
{
1577
    int err;
1578
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1579
    err = vs->offset;
1580
    complete_pdu(s, vs->pdu, err);
1581
    g_free(vs);
1582
}
1583

    
1584
static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1585
{
1586
    if (vs->fidp->fs.fd == -1) {
1587
        err = -errno;
1588
        goto out;
1589
    }
1590
    vs->fidp->fid_type = P9_FID_FILE;
1591
    vs->iounit = get_iounit(s, &vs->fidp->path);
1592
    v9fs_open_post_getiounit(s, vs);
1593
    return;
1594
out:
1595
    complete_pdu(s, vs->pdu, err);
1596
    g_free(vs);
1597
}
1598

    
1599
static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1600
{
1601
    int flags;
1602

    
1603
    if (err) {
1604
        err = -errno;
1605
        goto out;
1606
    }
1607

    
1608
    stat_to_qid(&vs->stbuf, &vs->qid);
1609

    
1610
    if (S_ISDIR(vs->stbuf.st_mode)) {
1611
        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1612
        v9fs_open_post_opendir(s, vs, err);
1613
    } else {
1614
        if (s->proto_version == V9FS_PROTO_2000L) {
1615
            flags = vs->mode;
1616
            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1617
            /* Ignore direct disk access hint until the server supports it. */
1618
            flags &= ~O_DIRECT;
1619
        } else {
1620
            flags = omode_to_uflags(vs->mode);
1621
        }
1622
        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1623
        v9fs_open_post_open(s, vs, err);
1624
    }
1625
    return;
1626
out:
1627
    complete_pdu(s, vs->pdu, err);
1628
    g_free(vs);
1629
}
1630

    
1631
static void v9fs_open(void *opaque)
1632
{
1633
    V9fsPDU *pdu = opaque;
1634
    V9fsState *s = pdu->s;
1635
    int32_t fid;
1636
    V9fsOpenState *vs;
1637
    ssize_t err = 0;
1638

    
1639
    vs = g_malloc(sizeof(*vs));
1640
    vs->pdu = pdu;
1641
    vs->offset = 7;
1642
    vs->mode = 0;
1643

    
1644
    if (s->proto_version == V9FS_PROTO_2000L) {
1645
        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
1646
    } else {
1647
        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1648
    }
1649

    
1650
    vs->fidp = lookup_fid(s, fid);
1651
    if (vs->fidp == NULL) {
1652
        err = -ENOENT;
1653
        goto out;
1654
    }
1655

    
1656
    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1657

    
1658
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1659

    
1660
    v9fs_open_post_lstat(s, vs, err);
1661
    return;
1662
out:
1663
    complete_pdu(s, pdu, err);
1664
    g_free(vs);
1665
}
1666

    
1667
static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1668
{
1669
    if (err == 0) {
1670
        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1671
        stat_to_qid(&vs->stbuf, &vs->qid);
1672
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
1673
                vs->iounit);
1674
        err = vs->offset;
1675
    } else {
1676
        vs->fidp->fid_type = P9_FID_NONE;
1677
        err = -errno;
1678
        if (vs->fidp->fs.fd > 0) {
1679
            close(vs->fidp->fs.fd);
1680
        }
1681
    }
1682

    
1683
    complete_pdu(s, vs->pdu, err);
1684
    v9fs_string_free(&vs->name);
1685
    v9fs_string_free(&vs->fullname);
1686
    g_free(vs);
1687
}
1688

    
1689
static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
1690
        int err)
1691
{
1692
    if (err) {
1693
        err = -errno;
1694
        goto out;
1695
    }
1696
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1697

    
1698
out:
1699
    v9fs_post_lcreate(s, vs, err);
1700
}
1701

    
1702
static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
1703
        int err)
1704
{
1705
    if (vs->fidp->fs.fd == -1) {
1706
        err = -errno;
1707
        goto out;
1708
    }
1709
    vs->fidp->fid_type = P9_FID_FILE;
1710
    vs->iounit =  get_iounit(s, &vs->fullname);
1711
    v9fs_lcreate_post_get_iounit(s, vs, err);
1712
    return;
1713

    
1714
out:
1715
    v9fs_post_lcreate(s, vs, err);
1716
}
1717

    
1718
static void v9fs_lcreate(void *opaque)
1719
{
1720
    V9fsPDU *pdu = opaque;
1721
    V9fsState *s = pdu->s;
1722
    int32_t dfid, flags, mode;
1723
    gid_t gid;
1724
    V9fsLcreateState *vs;
1725
    ssize_t err = 0;
1726

    
1727
    vs = g_malloc(sizeof(*vs));
1728
    vs->pdu = pdu;
1729
    vs->offset = 7;
1730

    
1731
    v9fs_string_init(&vs->fullname);
1732

    
1733
    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
1734
            &mode, &gid);
1735

    
1736
    vs->fidp = lookup_fid(s, dfid);
1737
    if (vs->fidp == NULL) {
1738
        err = -ENOENT;
1739
        goto out;
1740
    }
1741

    
1742
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1743
             vs->name.data);
1744

    
1745
    /* Ignore direct disk access hint until the server supports it. */
1746
    flags &= ~O_DIRECT;
1747

    
1748
    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
1749
            gid, flags, mode);
1750
    v9fs_lcreate_post_do_open2(s, vs, err);
1751
    return;
1752

    
1753
out:
1754
    complete_pdu(s, vs->pdu, err);
1755
    v9fs_string_free(&vs->name);
1756
    g_free(vs);
1757
}
1758

    
1759
static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
1760
{
1761
    if (err == -1) {
1762
        err = -errno;
1763
    }
1764
    complete_pdu(s, pdu, err);
1765
}
1766

    
1767
static void v9fs_fsync(void *opaque)
1768
{
1769
    V9fsPDU *pdu = opaque;
1770
    V9fsState *s = pdu->s;
1771
    int32_t fid;
1772
    size_t offset = 7;
1773
    V9fsFidState *fidp;
1774
    int datasync;
1775
    int err;
1776

    
1777
    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1778
    fidp = lookup_fid(s, fid);
1779
    if (fidp == NULL) {
1780
        err = -ENOENT;
1781
        v9fs_post_do_fsync(s, pdu, err);
1782
        return;
1783
    }
1784
    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
1785
    v9fs_post_do_fsync(s, pdu, err);
1786
}
1787

    
1788
static void v9fs_clunk(void *opaque)
1789
{
1790
    V9fsPDU *pdu = opaque;
1791
    V9fsState *s = pdu->s;
1792
    int32_t fid;
1793
    size_t offset = 7;
1794
    int err;
1795

    
1796
    pdu_unmarshal(pdu, offset, "d", &fid);
1797

    
1798
    err = free_fid(s, fid);
1799
    if (err < 0) {
1800
        goto out;
1801
    }
1802

    
1803
    offset = 7;
1804
    err = offset;
1805
out:
1806
    complete_pdu(s, pdu, err);
1807
}
1808

    
1809
static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1810

    
1811
static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1812
{
1813
    if (err) {
1814
        goto out;
1815
    }
1816
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1817
    vs->offset += vs->count;
1818
    err = vs->offset;
1819
out:
1820
    complete_pdu(s, vs->pdu, err);
1821
    v9fs_stat_free(&vs->v9stat);
1822
    v9fs_string_free(&vs->name);
1823
    g_free(vs);
1824
    return;
1825
}
1826

    
1827
static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1828
                                    ssize_t err)
1829
{
1830
    if (err) {
1831
        err = -errno;
1832
        goto out;
1833
    }
1834
    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1835
    if (err) {
1836
        goto out;
1837
    }
1838

    
1839
    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1840
                            &vs->v9stat);
1841
    if ((vs->len != (vs->v9stat.size + 2)) ||
1842
            ((vs->count + vs->len) > vs->max_count)) {
1843
        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1844
        v9fs_read_post_seekdir(s, vs, err);
1845
        return;
1846
    }
1847
    vs->count += vs->len;
1848
    v9fs_stat_free(&vs->v9stat);
1849
    v9fs_string_free(&vs->name);
1850
    vs->dir_pos = vs->dent->d_off;
1851
    v9fs_co_readdir(s, vs->fidp, &vs->dent);
1852
    v9fs_read_post_readdir(s, vs, err);
1853
    return;
1854
out:
1855
    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1856
    v9fs_read_post_seekdir(s, vs, err);
1857
    return;
1858

    
1859
}
1860

    
1861
static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1862
{
1863
    if (vs->dent) {
1864
        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1865
        v9fs_string_init(&vs->name);
1866
        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1867
                            vs->dent->d_name);
1868
        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1869
        v9fs_read_post_dir_lstat(s, vs, err);
1870
        return;
1871
    }
1872

    
1873
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1874
    vs->offset += vs->count;
1875
    err = vs->offset;
1876
    complete_pdu(s, vs->pdu, err);
1877
    g_free(vs);
1878
    return;
1879
}
1880

    
1881
static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1882
{
1883
    v9fs_co_readdir(s, vs->fidp, &vs->dent);
1884
    v9fs_read_post_readdir(s, vs, err);
1885
    return;
1886
}
1887

    
1888
static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1889
                                       ssize_t err)
1890
{
1891
    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1892
    v9fs_read_post_telldir(s, vs, err);
1893
    return;
1894
}
1895

    
1896
static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1897
{
1898
    if (err  < 0) {
1899
        /* IO error return the error */
1900
        err = -errno;
1901
        goto out;
1902
    }
1903
    vs->total += vs->len;
1904
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1905
    if (vs->total < vs->count && vs->len > 0) {
1906
        do {
1907
            if (0) {
1908
                print_sg(vs->sg, vs->cnt);
1909
            }
1910
            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
1911
                      vs->off);
1912
            if (vs->len > 0) {
1913
                vs->off += vs->len;
1914
            }
1915
        } while (vs->len == -1 && errno == EINTR);
1916
        if (vs->len == -1) {
1917
            err  = -errno;
1918
        }
1919
        v9fs_read_post_preadv(s, vs, err);
1920
        return;
1921
    }
1922
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1923
    vs->offset += vs->count;
1924
    err = vs->offset;
1925

    
1926
out:
1927
    complete_pdu(s, vs->pdu, err);
1928
    g_free(vs);
1929
}
1930

    
1931
static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
1932
{
1933
    ssize_t err = 0;
1934
    int read_count;
1935
    int64_t xattr_len;
1936

    
1937
    xattr_len = vs->fidp->fs.xattr.len;
1938
    read_count = xattr_len - vs->off;
1939
    if (read_count > vs->count) {
1940
        read_count = vs->count;
1941
    } else if (read_count < 0) {
1942
        /*
1943
         * read beyond XATTR value
1944
         */
1945
        read_count = 0;
1946
    }
1947
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
1948
    vs->offset += pdu_pack(vs->pdu, vs->offset,
1949
                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
1950
                           read_count);
1951
    err = vs->offset;
1952
    complete_pdu(s, vs->pdu, err);
1953
    g_free(vs);
1954
}
1955

    
1956
static void v9fs_read(void *opaque)
1957
{
1958
    V9fsPDU *pdu = opaque;
1959
    V9fsState *s = pdu->s;
1960
    int32_t fid;
1961
    V9fsReadState *vs;
1962
    ssize_t err = 0;
1963

    
1964
    vs = g_malloc(sizeof(*vs));
1965
    vs->pdu = pdu;
1966
    vs->offset = 7;
1967
    vs->total = 0;
1968
    vs->len = 0;
1969
    vs->count = 0;
1970

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

    
1973
    vs->fidp = lookup_fid(s, fid);
1974
    if (vs->fidp == NULL) {
1975
        err = -EINVAL;
1976
        goto out;
1977
    }
1978

    
1979
    if (vs->fidp->fid_type == P9_FID_DIR) {
1980
        vs->max_count = vs->count;
1981
        vs->count = 0;
1982
        if (vs->off == 0) {
1983
            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
1984
        }
1985
        v9fs_read_post_rewinddir(s, vs, err);
1986
        return;
1987
    } else if (vs->fidp->fid_type == P9_FID_FILE) {
1988
        vs->sg = vs->iov;
1989
        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1990
        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1991
        if (vs->total <= vs->count) {
1992
            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
1993
                                    vs->off);
1994
            if (vs->len > 0) {
1995
                vs->off += vs->len;
1996
            }
1997
            err = vs->len;
1998
            v9fs_read_post_preadv(s, vs, err);
1999
        }
2000
        return;
2001
    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2002
        v9fs_xattr_read(s, vs);
2003
        return;
2004
    } else {
2005
        err = -EINVAL;
2006
    }
2007
out:
2008
    complete_pdu(s, pdu, err);
2009
    g_free(vs);
2010
}
2011

    
2012
static size_t v9fs_readdir_data_size(V9fsString *name)
2013
{
2014
    /*
2015
     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
2016
     * size of type (1) + size of name.size (2) + strlen(name.data)
2017
     */
2018
    return 24 + v9fs_string_size(name);
2019
}
2020

    
2021
static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
2022
                           V9fsFidState *fidp, int32_t max_count)
2023
{
2024
    size_t size;
2025
    V9fsQID qid;
2026
    V9fsString name;
2027
    int len, err = 0;
2028
    int32_t count = 0;
2029
    off_t saved_dir_pos;
2030
    struct dirent *dent;
2031

    
2032
    /* save the directory position */
2033
    saved_dir_pos = v9fs_co_telldir(s, fidp);
2034
    if (saved_dir_pos < 0) {
2035
        return saved_dir_pos;
2036
    }
2037
    while (1) {
2038
        err = v9fs_co_readdir(s, fidp, &dent);
2039
        if (err || !dent) {
2040
            break;
2041
        }
2042
        v9fs_string_init(&name);
2043
        v9fs_string_sprintf(&name, "%s", dent->d_name);
2044
        if ((count + v9fs_readdir_data_size(&name)) > max_count) {
2045
            /* Ran out of buffer. Set dir back to old position and return */
2046
            v9fs_co_seekdir(s, fidp, saved_dir_pos);
2047
            v9fs_string_free(&name);
2048
            return count;
2049
        }
2050
        /*
2051
         * Fill up just the path field of qid because the client uses
2052
         * only that. To fill the entire qid structure we will have
2053
         * to stat each dirent found, which is expensive
2054
         */
2055
        size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
2056
        memcpy(&qid.path, &dent->d_ino, size);
2057
        /* Fill the other fields with dummy values */
2058
        qid.type = 0;
2059
        qid.version = 0;
2060

    
2061
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2062
        len = pdu_marshal(pdu, 11 + count, "Qqbs",
2063
                          &qid, dent->d_off,
2064
                          dent->d_type, &name);
2065
        count += len;
2066
        v9fs_string_free(&name);
2067
        saved_dir_pos = dent->d_off;
2068
    }
2069
    if (err < 0) {
2070
        return err;
2071
    }
2072
    return count;
2073
}
2074

    
2075
static void v9fs_readdir(void *opaque)
2076
{
2077
    int32_t fid;
2078
    V9fsFidState *fidp;
2079
    ssize_t retval = 0;
2080
    size_t offset = 7;
2081
    int64_t initial_offset;
2082
    int32_t count, max_count;
2083
    V9fsPDU *pdu = opaque;
2084
    V9fsState *s = pdu->s;
2085

    
2086
    pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
2087

    
2088
    fidp = lookup_fid(s, fid);
2089
    if (fidp == NULL || !fidp->fs.dir) {
2090
        retval = -EINVAL;
2091
        goto out;
2092
    }
2093
    if (initial_offset == 0) {
2094
        v9fs_co_rewinddir(s, fidp);
2095
    } else {
2096
        v9fs_co_seekdir(s, fidp, initial_offset);
2097
    }
2098
    count = v9fs_do_readdir(s, pdu, fidp, max_count);
2099
    if (count < 0) {
2100
        retval = count;
2101
        goto out;
2102
    }
2103
    retval = offset;
2104
    retval += pdu_marshal(pdu, offset, "d", count);
2105
    retval += count;
2106
out:
2107
    complete_pdu(s, pdu, retval);
2108
}
2109

    
2110
static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
2111
                                   ssize_t err)
2112
{
2113
    if (err  < 0) {
2114
        /* IO error return the error */
2115
        err = -errno;
2116
        goto out;
2117
    }
2118
    vs->total += vs->len;
2119
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2120
    if (vs->total < vs->count && vs->len > 0) {
2121
        do {
2122
            if (0) {
2123
                print_sg(vs->sg, vs->cnt);
2124
            }
2125
            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2126
                      vs->off);
2127
            if (vs->len > 0) {
2128
                vs->off += vs->len;
2129
            }
2130
        } while (vs->len == -1 && errno == EINTR);
2131
        if (vs->len == -1) {
2132
            err  = -errno;
2133
        }
2134
        v9fs_write_post_pwritev(s, vs, err);
2135
        return;
2136
    }
2137
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2138
    err = vs->offset;
2139
out:
2140
    complete_pdu(s, vs->pdu, err);
2141
    g_free(vs);
2142
}
2143

    
2144
static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
2145
{
2146
    int i, to_copy;
2147
    ssize_t err = 0;
2148
    int write_count;
2149
    int64_t xattr_len;
2150

    
2151
    xattr_len = vs->fidp->fs.xattr.len;
2152
    write_count = xattr_len - vs->off;
2153
    if (write_count > vs->count) {
2154
        write_count = vs->count;
2155
    } else if (write_count < 0) {
2156
        /*
2157
         * write beyond XATTR value len specified in
2158
         * xattrcreate
2159
         */
2160
        err = -ENOSPC;
2161
        goto out;
2162
    }
2163
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
2164
    err = vs->offset;
2165
    vs->fidp->fs.xattr.copied_len += write_count;
2166
    /*
2167
     * Now copy the content from sg list
2168
     */
2169
    for (i = 0; i < vs->cnt; i++) {
2170
        if (write_count > vs->sg[i].iov_len) {
2171
            to_copy = vs->sg[i].iov_len;
2172
        } else {
2173
            to_copy = write_count;
2174
        }
2175
        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
2176
               vs->sg[i].iov_base, to_copy);
2177
        /* updating vs->off since we are not using below */
2178
        vs->off += to_copy;
2179
        write_count -= to_copy;
2180
    }
2181
out:
2182
    complete_pdu(s, vs->pdu, err);
2183
    g_free(vs);
2184
}
2185

    
2186
static void v9fs_write(void *opaque)
2187
{
2188
    V9fsPDU *pdu = opaque;
2189
    V9fsState *s = pdu->s;
2190
    int32_t fid;
2191
    V9fsWriteState *vs;
2192
    ssize_t err;
2193

    
2194
    vs = g_malloc(sizeof(*vs));
2195

    
2196
    vs->pdu = pdu;
2197
    vs->offset = 7;
2198
    vs->sg = vs->iov;
2199
    vs->total = 0;
2200
    vs->len = 0;
2201

    
2202
    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2203
                  vs->sg, &vs->cnt);
2204

    
2205
    vs->fidp = lookup_fid(s, fid);
2206
    if (vs->fidp == NULL) {
2207
        err = -EINVAL;
2208
        goto out;
2209
    }
2210

    
2211
    if (vs->fidp->fid_type == P9_FID_FILE) {
2212
        if (vs->fidp->fs.fd == -1) {
2213
            err = -EINVAL;
2214
            goto out;
2215
        }
2216
    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2217
        /*
2218
         * setxattr operation
2219
         */
2220
        v9fs_xattr_write(s, vs);
2221
        return;
2222
    } else {
2223
        err = -EINVAL;
2224
        goto out;
2225
    }
2226
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2227
    if (vs->total <= vs->count) {
2228
        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
2229
        if (vs->len > 0) {
2230
            vs->off += vs->len;
2231
        }
2232
        err = vs->len;
2233
        v9fs_write_post_pwritev(s, vs, err);
2234
    }
2235
    return;
2236
out:
2237
    complete_pdu(s, vs->pdu, err);
2238
    g_free(vs);
2239
}
2240

    
2241
static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2242
{
2243
    int err;
2244
    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2245
    stat_to_qid(&vs->stbuf, &vs->qid);
2246

    
2247
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2248
    err = vs->offset;
2249

    
2250
    complete_pdu(s, vs->pdu, err);
2251
    v9fs_string_free(&vs->name);
2252
    v9fs_string_free(&vs->extension);
2253
    v9fs_string_free(&vs->fullname);
2254
    g_free(vs);
2255
}
2256

    
2257
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2258
{
2259
    if (err == 0) {
2260
        vs->iounit = get_iounit(s, &vs->fidp->path);
2261
        v9fs_create_post_getiounit(s, vs);
2262
        return;
2263
    }
2264

    
2265
    complete_pdu(s, vs->pdu, err);
2266
    v9fs_string_free(&vs->name);
2267
    v9fs_string_free(&vs->extension);
2268
    v9fs_string_free(&vs->fullname);
2269
    g_free(vs);
2270
}
2271

    
2272
static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2273
{
2274
    if (err) {
2275
        err = -errno;
2276
    }
2277
    v9fs_post_create(s, vs, err);
2278
}
2279

    
2280
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2281
                                                                    int err)
2282
{
2283
    if (!vs->fidp->fs.dir) {
2284
        err = -errno;
2285
    }
2286
    vs->fidp->fid_type = P9_FID_DIR;
2287
    v9fs_post_create(s, vs, err);
2288
}
2289

    
2290
static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2291
                                                                    int err)
2292
{
2293
    if (err) {
2294
        err = -errno;
2295
        goto out;
2296
    }
2297

    
2298
    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
2299
    v9fs_create_post_opendir(s, vs, err);
2300
    return;
2301

    
2302
out:
2303
    v9fs_post_create(s, vs, err);
2304
}
2305

    
2306
static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2307
{
2308
    if (err < 0) {
2309
        goto out;
2310
    }
2311

    
2312
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2313
    v9fs_create_post_dir_lstat(s, vs, err);
2314
    return;
2315

    
2316
out:
2317
    v9fs_post_create(s, vs, err);
2318
}
2319

    
2320
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2321
{
2322
    if (err) {
2323
        vs->fidp->fid_type = P9_FID_NONE;
2324
        close(vs->fidp->fs.fd);
2325
        err = -errno;
2326
    }
2327
    v9fs_post_create(s, vs, err);
2328
    return;
2329
}
2330

    
2331
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2332
{
2333
    if (vs->fidp->fs.fd == -1) {
2334
        err = -errno;
2335
        goto out;
2336
    }
2337
    vs->fidp->fid_type = P9_FID_FILE;
2338
    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
2339
    v9fs_create_post_fstat(s, vs, err);
2340

    
2341
    return;
2342

    
2343
out:
2344
    v9fs_post_create(s, vs, err);
2345

    
2346
}
2347

    
2348
static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2349
{
2350

    
2351
    if (err == 0 || errno != ENOENT) {
2352
        err = -errno;
2353
        goto out;
2354
    }
2355

    
2356
    if (vs->perm & P9_STAT_MODE_DIR) {
2357
        err = v9fs_co_mkdir(s, vs->fullname.data, vs->perm & 0777,
2358
                vs->fidp->uid, -1);
2359
        v9fs_create_post_mkdir(s, vs, err);
2360
    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2361
        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
2362
                vs->fullname.data, -1);
2363
        v9fs_create_post_perms(s, vs, err);
2364
    } else if (vs->perm & P9_STAT_MODE_LINK) {
2365
        int32_t nfid = atoi(vs->extension.data);
2366
        V9fsFidState *nfidp = lookup_fid(s, nfid);
2367
        if (nfidp == NULL) {
2368
            err = -errno;
2369
            v9fs_post_create(s, vs, err);
2370
        }
2371
        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2372
        v9fs_create_post_perms(s, vs, err);
2373
    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2374
        char ctype;
2375
        uint32_t major, minor;
2376
        mode_t nmode = 0;
2377

    
2378
        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2379
                                        &minor) != 3) {
2380
            err = -errno;
2381
            v9fs_post_create(s, vs, err);
2382
        }
2383

    
2384
        switch (ctype) {
2385
        case 'c':
2386
            nmode = S_IFCHR;
2387
            break;
2388
        case 'b':
2389
            nmode = S_IFBLK;
2390
            break;
2391
        default:
2392
            err = -EIO;
2393
            v9fs_post_create(s, vs, err);
2394
        }
2395

    
2396
        nmode |= vs->perm & 0777;
2397
        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
2398
                makedev(major, minor), vs->fidp->uid, -1);
2399
        v9fs_create_post_perms(s, vs, err);
2400
    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2401
        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
2402
                0, vs->fidp->uid, -1);
2403
        v9fs_post_create(s, vs, err);
2404
    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2405
        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
2406
                0, vs->fidp->uid, -1);
2407
        v9fs_post_create(s, vs, err);
2408
    } else {
2409
        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
2410
                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
2411

    
2412
        v9fs_create_post_open2(s, vs, err);
2413
    }
2414

    
2415
    return;
2416

    
2417
out:
2418
    v9fs_post_create(s, vs, err);
2419
}
2420

    
2421
static void v9fs_create(void *opaque)
2422
{
2423
    V9fsPDU *pdu = opaque;
2424
    V9fsState *s = pdu->s;
2425
    int32_t fid;
2426
    V9fsCreateState *vs;
2427
    int err = 0;
2428

    
2429
    vs = g_malloc(sizeof(*vs));
2430
    vs->pdu = pdu;
2431
    vs->offset = 7;
2432

    
2433
    v9fs_string_init(&vs->fullname);
2434

    
2435
    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2436
                                &vs->perm, &vs->mode, &vs->extension);
2437

    
2438
    vs->fidp = lookup_fid(s, fid);
2439
    if (vs->fidp == NULL) {
2440
        err = -EINVAL;
2441
        goto out;
2442
    }
2443

    
2444
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2445
                                                        vs->name.data);
2446

    
2447
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2448
    v9fs_create_post_lstat(s, vs, err);
2449
    return;
2450

    
2451
out:
2452
    complete_pdu(s, vs->pdu, err);
2453
    v9fs_string_free(&vs->name);
2454
    v9fs_string_free(&vs->extension);
2455
    g_free(vs);
2456
}
2457

    
2458
static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
2459
{
2460
    if (err == 0) {
2461
        stat_to_qid(&vs->stbuf, &vs->qid);
2462
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
2463
        err = vs->offset;
2464
    } else {
2465
        err = -errno;
2466
    }
2467
    complete_pdu(s, vs->pdu, err);
2468
    v9fs_string_free(&vs->name);
2469
    v9fs_string_free(&vs->symname);
2470
    v9fs_string_free(&vs->fullname);
2471
    g_free(vs);
2472
}
2473

    
2474
static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
2475
        int err)
2476
{
2477
    if (err) {
2478
        goto out;
2479
    }
2480
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2481
out:
2482
    v9fs_post_symlink(s, vs, err);
2483
}
2484

    
2485
static void v9fs_symlink(void *opaque)
2486
{
2487
    V9fsPDU *pdu = opaque;
2488
    V9fsState *s = pdu->s;
2489
    int32_t dfid;
2490
    V9fsSymlinkState *vs;
2491
    int err = 0;
2492
    gid_t gid;
2493

    
2494
    vs = g_malloc(sizeof(*vs));
2495
    vs->pdu = pdu;
2496
    vs->offset = 7;
2497

    
2498
    v9fs_string_init(&vs->fullname);
2499

    
2500
    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
2501
            &vs->symname, &gid);
2502

    
2503
    vs->dfidp = lookup_fid(s, dfid);
2504
    if (vs->dfidp == NULL) {
2505
        err = -EINVAL;
2506
        goto out;
2507
    }
2508

    
2509
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
2510
            vs->name.data);
2511
    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
2512
            vs->fullname.data, gid);
2513
    v9fs_symlink_post_do_symlink(s, vs, err);
2514
    return;
2515

    
2516
out:
2517
    complete_pdu(s, vs->pdu, err);
2518
    v9fs_string_free(&vs->name);
2519
    v9fs_string_free(&vs->symname);
2520
    g_free(vs);
2521
}
2522

    
2523
static void v9fs_flush(void *opaque)
2524
{
2525
    V9fsPDU *pdu = opaque;
2526
    V9fsState *s = pdu->s;
2527
    /* A nop call with no return */
2528
    complete_pdu(s, pdu, 7);
2529
    return;
2530
}
2531

    
2532
static void v9fs_link(void *opaque)
2533
{
2534
    V9fsPDU *pdu = opaque;
2535
    V9fsState *s = pdu->s;
2536
    int32_t dfid, oldfid;
2537
    V9fsFidState *dfidp, *oldfidp;
2538
    V9fsString name, fullname;
2539
    size_t offset = 7;
2540
    int err = 0;
2541

    
2542
    v9fs_string_init(&fullname);
2543

    
2544
    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2545

    
2546
    dfidp = lookup_fid(s, dfid);
2547
    if (dfidp == NULL) {
2548
        err = -errno;
2549
        goto out;
2550
    }
2551

    
2552
    oldfidp = lookup_fid(s, oldfid);
2553
    if (oldfidp == NULL) {
2554
        err = -errno;
2555
        goto out;
2556
    }
2557

    
2558
    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2559
    err = offset;
2560
    err = v9fs_do_link(s, &oldfidp->path, &fullname);
2561
    if (err) {
2562
        err = -errno;
2563
    }
2564
    v9fs_string_free(&fullname);
2565

    
2566
out:
2567
    v9fs_string_free(&name);
2568
    complete_pdu(s, pdu, err);
2569
}
2570

    
2571
static void v9fs_remove(void *opaque)
2572
{
2573
    int32_t fid;
2574
    int err = 0;
2575
    size_t offset = 7;
2576
    V9fsFidState *fidp;
2577
    V9fsPDU *pdu = opaque;
2578

    
2579
    pdu_unmarshal(pdu, offset, "d", &fid);
2580

    
2581
    fidp = lookup_fid(pdu->s, fid);
2582
    if (fidp == NULL) {
2583
        err = -EINVAL;
2584
        goto out;
2585
    }
2586
    err = v9fs_co_remove(pdu->s, &fidp->path);
2587
    if (!err) {
2588
        err = offset;
2589
    }
2590

    
2591
    /* For TREMOVE we need to clunk the fid even on failed remove */
2592
    free_fid(pdu->s, fidp->fid);
2593
out:
2594
    complete_pdu(pdu->s, pdu, err);
2595
}
2596

    
2597
static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2598
{
2599
    if (err < 0) {
2600
        goto out;
2601
    }
2602

    
2603
    err = vs->offset;
2604

    
2605
out:
2606
    v9fs_stat_free(&vs->v9stat);
2607
    complete_pdu(s, vs->pdu, err);
2608
    g_free(vs);
2609
}
2610

    
2611
static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2612
{
2613
    if (err < 0) {
2614
        goto out;
2615
    }
2616
    if (vs->v9stat.length != -1) {
2617
        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2618
            err = -errno;
2619
        }
2620
    }
2621
    v9fs_wstat_post_truncate(s, vs, err);
2622
    return;
2623

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

    
2630
static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2631
                                int32_t newdirfid, V9fsString *name)
2632
{
2633
    char *end;
2634
    int err = 0;
2635
    char *old_name, *new_name;
2636

    
2637
    if (newdirfid != -1) {
2638
        V9fsFidState *dirfidp;
2639
        dirfidp = lookup_fid(s, newdirfid);
2640
        if (dirfidp == NULL) {
2641
            err = -ENOENT;
2642
            goto out;
2643
        }
2644
        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2645

    
2646
        new_name = g_malloc0(dirfidp->path.size + name->size + 2);
2647

    
2648
        strcpy(new_name, dirfidp->path.data);
2649
        strcat(new_name, "/");
2650
        strcat(new_name + dirfidp->path.size, name->data);
2651
    } else {
2652
        old_name = fidp->path.data;
2653
        end = strrchr(old_name, '/');
2654
        if (end) {
2655
            end++;
2656
        } else {
2657
            end = old_name;
2658
        }
2659
        new_name = g_malloc0(end - old_name + name->size + 1);
2660

    
2661
        strncat(new_name, old_name, end - old_name);
2662
        strncat(new_name + (end - old_name), name->data, name->size);
2663
    }
2664

    
2665
    v9fs_string_free(name);
2666
    name->data = new_name;
2667
    name->size = strlen(new_name);
2668

    
2669
    if (strcmp(new_name, fidp->path.data) != 0) {
2670
        err = v9fs_co_rename(s, &fidp->path, name);
2671
        if (err < 0) {
2672
            goto out;
2673
        }
2674
        V9fsFidState *tfidp;
2675
        /*
2676
         * Fixup fid's pointing to the old name to
2677
         * start pointing to the new name
2678
         */
2679
        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2680
            if (fidp == tfidp) {
2681
                /*
2682
                 * we replace name of this fid towards the end
2683
                 * so that our below strcmp will work
2684
                 */
2685
                continue;
2686
            }
2687
            if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2688
                /* replace the name */
2689
                v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2690
            }
2691
        }
2692
        v9fs_string_copy(&fidp->path, name);
2693
    }
2694
out:
2695
    return err;
2696
}
2697

    
2698
static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2699
{
2700
    if (err < 0) {
2701
        goto out;
2702
    }
2703

    
2704
    if (vs->v9stat.name.size != 0) {
2705
        err = v9fs_complete_rename(s, vs->fidp, -1, &vs->v9stat.name);
2706
    }
2707
    v9fs_wstat_post_rename(s, vs, err);
2708
    return;
2709

    
2710
out:
2711
    v9fs_stat_free(&vs->v9stat);
2712
    complete_pdu(s, vs->pdu, err);
2713
    g_free(vs);
2714
}
2715

    
2716
static void v9fs_rename(void *opaque)
2717
{
2718
    int32_t fid;
2719
    ssize_t err = 0;
2720
    size_t offset = 7;
2721
    V9fsString name;
2722
    int32_t newdirfid;
2723
    V9fsFidState *fidp;
2724
    V9fsPDU *pdu = opaque;
2725
    V9fsState *s = pdu->s;
2726

    
2727
    pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2728

    
2729
    fidp = lookup_fid(s, fid);
2730
    if (fidp == NULL) {
2731
        err = -ENOENT;
2732
        goto out;
2733
    }
2734
    BUG_ON(fidp->fid_type != P9_FID_NONE);
2735

    
2736
    err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2737
    if (!err) {
2738
        err = offset;
2739
    }
2740
out:
2741
    complete_pdu(s, pdu, err);
2742
    v9fs_string_free(&name);
2743
}
2744

    
2745
static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2746
{
2747
    if (err < 0) {
2748
        goto out;
2749
    }
2750

    
2751
    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2752
        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2753
                    vs->v9stat.n_gid)) {
2754
            err = -errno;
2755
        }
2756
    }
2757
    v9fs_wstat_post_chown(s, vs, err);
2758
    return;
2759

    
2760
out:
2761
    v9fs_stat_free(&vs->v9stat);
2762
    complete_pdu(s, vs->pdu, err);
2763
    g_free(vs);
2764
}
2765

    
2766
static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2767
{
2768
    if (err < 0) {
2769
        goto out;
2770
    }
2771

    
2772
    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2773
        struct timespec times[2];
2774
        if (vs->v9stat.atime != -1) {
2775
            times[0].tv_sec = vs->v9stat.atime;
2776
            times[0].tv_nsec = 0;
2777
        } else {
2778
            times[0].tv_nsec = UTIME_OMIT;
2779
        }
2780
        if (vs->v9stat.mtime != -1) {
2781
            times[1].tv_sec = vs->v9stat.mtime;
2782
            times[1].tv_nsec = 0;
2783
        } else {
2784
            times[1].tv_nsec = UTIME_OMIT;
2785
        }
2786

    
2787
        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2788
            err = -errno;
2789
        }
2790
    }
2791

    
2792
    v9fs_wstat_post_utime(s, vs, err);
2793
    return;
2794

    
2795
out:
2796
    v9fs_stat_free(&vs->v9stat);
2797
    complete_pdu(s, vs->pdu, err);
2798
    g_free(vs);
2799
}
2800

    
2801
static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2802
{
2803
    if (err == -1) {
2804
        err = -errno;
2805
    }
2806
    v9fs_stat_free(&vs->v9stat);
2807
    complete_pdu(s, vs->pdu, err);
2808
    g_free(vs);
2809
}
2810

    
2811
static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2812
{
2813
    uint32_t v9_mode;
2814

    
2815
    if (err == -1) {
2816
        err = -errno;
2817
        goto out;
2818
    }
2819

    
2820
    v9_mode = stat_to_v9mode(&vs->stbuf);
2821

    
2822
    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2823
        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2824
            /* Attempting to change the type */
2825
            err = -EIO;
2826
            goto out;
2827
    }
2828

    
2829
    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2830
                    &vs->v9stat.extension))) {
2831
            err = -errno;
2832
     }
2833
    v9fs_wstat_post_chmod(s, vs, err);
2834
    return;
2835

    
2836
out:
2837
    v9fs_stat_free(&vs->v9stat);
2838
    complete_pdu(s, vs->pdu, err);
2839
    g_free(vs);
2840
}
2841

    
2842
static void v9fs_wstat(void *opaque)
2843
{
2844
    V9fsPDU *pdu = opaque;
2845
    V9fsState *s = pdu->s;
2846
    int32_t fid;
2847
    V9fsWstatState *vs;
2848
    int err = 0;
2849

    
2850
    vs = g_malloc(sizeof(*vs));
2851
    vs->pdu = pdu;
2852
    vs->offset = 7;
2853

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

    
2856
    vs->fidp = lookup_fid(s, fid);
2857
    if (vs->fidp == NULL) {
2858
        err = -EINVAL;
2859
        goto out;
2860
    }
2861

    
2862
    /* do we need to sync the file? */
2863
    if (donttouch_stat(&vs->v9stat)) {
2864
        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
2865
        v9fs_wstat_post_fsync(s, vs, err);
2866
        return;
2867
    }
2868

    
2869
    if (vs->v9stat.mode != -1) {
2870
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2871
        v9fs_wstat_post_lstat(s, vs, err);
2872
        return;
2873
    }
2874

    
2875
    v9fs_wstat_post_chmod(s, vs, err);
2876
    return;
2877

    
2878
out:
2879
    v9fs_stat_free(&vs->v9stat);
2880
    complete_pdu(s, vs->pdu, err);
2881
    g_free(vs);
2882
}
2883

    
2884
static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2885
{
2886
    uint32_t f_type;
2887
    uint32_t f_bsize;
2888
    uint64_t f_blocks;
2889
    uint64_t f_bfree;
2890
    uint64_t f_bavail;
2891
    uint64_t f_files;
2892
    uint64_t f_ffree;
2893
    uint64_t fsid_val;
2894
    uint32_t f_namelen;
2895
    size_t offset = 7;
2896
    int32_t bsize_factor;
2897

    
2898
    /*
2899
     * compute bsize factor based on host file system block size
2900
     * and client msize
2901
     */
2902
    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2903
    if (!bsize_factor) {
2904
        bsize_factor = 1;
2905
    }
2906
    f_type  = stbuf->f_type;
2907
    f_bsize = stbuf->f_bsize;
2908
    f_bsize *= bsize_factor;
2909
    /*
2910
     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2911
     * adjust(divide) the number of blocks, free blocks and available
2912
     * blocks by bsize factor
2913
     */
2914
    f_blocks = stbuf->f_blocks/bsize_factor;
2915
    f_bfree  = stbuf->f_bfree/bsize_factor;
2916
    f_bavail = stbuf->f_bavail/bsize_factor;
2917
    f_files  = stbuf->f_files;
2918
    f_ffree  = stbuf->f_ffree;
2919
    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2920
               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2921
    f_namelen = stbuf->f_namelen;
2922

    
2923
    return pdu_marshal(pdu, offset, "ddqqqqqqd",
2924
                       f_type, f_bsize, f_blocks, f_bfree,
2925
                       f_bavail, f_files, f_ffree,
2926
                       fsid_val, f_namelen);
2927
}
2928

    
2929
static void v9fs_statfs(void *opaque)
2930
{
2931
    int32_t fid;
2932
    ssize_t retval = 0;
2933
    size_t offset = 7;
2934
    V9fsFidState *fidp;
2935
    struct statfs stbuf;
2936
    V9fsPDU *pdu = opaque;
2937
    V9fsState *s = pdu->s;
2938

    
2939
    pdu_unmarshal(pdu, offset, "d", &fid);
2940
    fidp = lookup_fid(s, fid);
2941
    if (fidp == NULL) {
2942
        retval = -ENOENT;
2943
        goto out;
2944
    }
2945
    retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2946
    if (retval < 0) {
2947
        goto out;
2948
    }
2949
    retval = offset;
2950
    retval += v9fs_fill_statfs(s, pdu, &stbuf);
2951
out:
2952
    complete_pdu(s, pdu, retval);
2953
    return;
2954
}
2955

    
2956
static void v9fs_mknod(void *opaque)
2957
{
2958

    
2959
    int mode;
2960
    gid_t gid;
2961
    int32_t fid;
2962
    V9fsQID qid;
2963
    int err = 0;
2964
    int major, minor;
2965
    size_t offset = 7;
2966
    V9fsString name;
2967
    struct stat stbuf;
2968
    V9fsString fullname;
2969
    V9fsFidState *fidp;
2970
    V9fsPDU *pdu = opaque;
2971
    V9fsState *s = pdu->s;
2972

    
2973
    v9fs_string_init(&fullname);
2974
    pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2975
                  &major, &minor, &gid);
2976

    
2977
    fidp = lookup_fid(s, fid);
2978
    if (fidp == NULL) {
2979
        err = -ENOENT;
2980
        goto out;
2981
    }
2982
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2983
    err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2984
                        makedev(major, minor), mode);
2985
    if (err < 0) {
2986
        goto out;
2987
    }
2988
    err = v9fs_co_lstat(s, &fullname, &stbuf);
2989
    if (err < 0) {
2990
        goto out;
2991
    }
2992
    stat_to_qid(&stbuf, &qid);
2993
    err = offset;
2994
    err += pdu_marshal(pdu, offset, "Q", &qid);
2995
out:
2996
    complete_pdu(s, pdu, err);
2997
    v9fs_string_free(&fullname);
2998
    v9fs_string_free(&name);
2999
}
3000

    
3001
/*
3002
 * Implement posix byte range locking code
3003
 * Server side handling of locking code is very simple, because 9p server in
3004
 * QEMU can handle only one client. And most of the lock handling
3005
 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
3006
 * do any thing in * qemu 9p server side lock code path.
3007
 * So when a TLOCK request comes, always return success
3008
 */
3009
static void v9fs_lock(void *opaque)
3010
{
3011
    int8_t status;
3012
    V9fsFlock *flock;
3013
    size_t offset = 7;
3014
    struct stat stbuf;
3015
    V9fsFidState *fidp;
3016
    int32_t fid, err = 0;
3017
    V9fsPDU *pdu = opaque;
3018
    V9fsState *s = pdu->s;
3019

    
3020
    flock = g_malloc(sizeof(*flock));
3021
    pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
3022
                  &flock->flags, &flock->start, &flock->length,
3023
                  &flock->proc_id, &flock->client_id);
3024
    status = P9_LOCK_ERROR;
3025

    
3026
    /* We support only block flag now (that too ignored currently) */
3027
    if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
3028
        err = -EINVAL;
3029
        goto out;
3030
    }
3031
    fidp = lookup_fid(s, fid);
3032
    if (fidp == NULL) {
3033
        err = -ENOENT;
3034
        goto out;
3035
    }
3036
    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
3037
    if (err < 0) {
3038
        goto out;
3039
    }
3040
    status = P9_LOCK_SUCCESS;
3041
out:
3042
    err = offset;
3043
    err += pdu_marshal(pdu, offset, "b", status);
3044
    complete_pdu(s, pdu, err);
3045
    g_free(flock);
3046
}
3047

    
3048
/*
3049
 * When a TGETLOCK request comes, always return success because all lock
3050
 * handling is done by client's VFS layer.
3051
 */
3052
static void v9fs_getlock(void *opaque)
3053
{
3054
    size_t offset = 7;
3055
    struct stat stbuf;
3056
    V9fsFidState *fidp;
3057
    V9fsGetlock *glock;
3058
    int32_t fid, err = 0;
3059
    V9fsPDU *pdu = opaque;
3060
    V9fsState *s = pdu->s;
3061

    
3062
    glock = g_malloc(sizeof(*glock));
3063
    pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
3064
                  &glock->start, &glock->length, &glock->proc_id,
3065
                  &glock->client_id);
3066

    
3067
    fidp = lookup_fid(s, fid);
3068
    if (fidp == NULL) {
3069
        err = -ENOENT;
3070
        goto out;
3071
    }
3072
    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
3073
    if (err < 0) {
3074
        goto out;
3075
    }
3076
    glock->type = F_UNLCK;
3077
    offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
3078
                          glock->start, glock->length, glock->proc_id,
3079
                          &glock->client_id);
3080
    err = offset;
3081
out:
3082
    complete_pdu(s, pdu, err);
3083
    g_free(glock);
3084
}
3085

    
3086
static void v9fs_mkdir(void *opaque)
3087
{
3088
    V9fsPDU *pdu = opaque;
3089
    size_t offset = 7;
3090
    int32_t fid;
3091
    struct stat stbuf;
3092
    V9fsString name, fullname;
3093
    V9fsQID qid;
3094
    V9fsFidState *fidp;
3095
    gid_t gid;
3096
    int mode;
3097
    int err = 0;
3098

    
3099
    v9fs_string_init(&fullname);
3100
    pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3101

    
3102
    fidp = lookup_fid(pdu->s, fid);
3103
    if (fidp == NULL) {
3104
        err = -ENOENT;
3105
        goto out;
3106
    }
3107
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
3108
    err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
3109
    if (err < 0) {
3110
        goto out;
3111
    }
3112
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
3113
    if (err < 0) {
3114
        goto out;
3115
    }
3116
    stat_to_qid(&stbuf, &qid);
3117
    offset += pdu_marshal(pdu, offset, "Q", &qid);
3118
    err = offset;
3119
out:
3120
    complete_pdu(pdu->s, pdu, err);
3121
    v9fs_string_free(&fullname);
3122
    v9fs_string_free(&name);
3123
}
3124

    
3125
static void v9fs_xattrwalk(void *opaque)
3126
{
3127
    int64_t size;
3128
    V9fsString name;
3129
    ssize_t err = 0;
3130
    size_t offset = 7;
3131
    int32_t fid, newfid;
3132
    V9fsFidState *file_fidp;
3133
    V9fsFidState *xattr_fidp;
3134
    V9fsPDU *pdu = opaque;
3135
    V9fsState *s = pdu->s;
3136

    
3137
    pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3138
    file_fidp = lookup_fid(s, fid);
3139
    if (file_fidp == NULL) {
3140
        err = -ENOENT;
3141
        goto out;
3142
    }
3143
    xattr_fidp = alloc_fid(s, newfid);
3144
    if (xattr_fidp == NULL) {
3145
        err = -EINVAL;
3146
        goto out;
3147
    }
3148
    v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
3149
    if (name.data[0] == 0) {
3150
        /*
3151
         * listxattr request. Get the size first
3152
         */
3153
        size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
3154
        if (size < 0) {
3155
            err = size;
3156
            free_fid(s, xattr_fidp->fid);
3157
            goto out;
3158
        }
3159
        /*
3160
         * Read the xattr value
3161
         */
3162
        xattr_fidp->fs.xattr.len = size;
3163
        xattr_fidp->fid_type = P9_FID_XATTR;
3164
        xattr_fidp->fs.xattr.copied_len = -1;
3165
        if (size) {
3166
            xattr_fidp->fs.xattr.value = g_malloc(size);
3167
            err = v9fs_co_llistxattr(s, &xattr_fidp->path,
3168
                                     xattr_fidp->fs.xattr.value,
3169
                                     xattr_fidp->fs.xattr.len);
3170
            if (err < 0) {
3171
                free_fid(s, xattr_fidp->fid);
3172
                goto out;
3173
            }
3174
        }
3175
        offset += pdu_marshal(pdu, offset, "q", size);
3176
        err = offset;
3177
    } else {
3178
        /*
3179
         * specific xattr fid. We check for xattr
3180
         * presence also collect the xattr size
3181
         */
3182
        size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3183
                                 &name, NULL, 0);
3184
        if (size < 0) {
3185
            err = size;
3186
            free_fid(s, xattr_fidp->fid);
3187
            goto out;
3188
        }
3189
        /*
3190
         * Read the xattr value
3191
         */
3192
        xattr_fidp->fs.xattr.len = size;
3193
        xattr_fidp->fid_type = P9_FID_XATTR;
3194
        xattr_fidp->fs.xattr.copied_len = -1;
3195
        if (size) {
3196
            xattr_fidp->fs.xattr.value = g_malloc(size);
3197
            err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3198
                                    &name, xattr_fidp->fs.xattr.value,
3199
                                    xattr_fidp->fs.xattr.len);
3200
            if (err < 0) {
3201
                free_fid(s, xattr_fidp->fid);
3202
                goto out;
3203
            }
3204
        }
3205
        offset += pdu_marshal(pdu, offset, "q", size);
3206
        err = offset;
3207
    }
3208
out:
3209
    complete_pdu(s, pdu, err);
3210
    v9fs_string_free(&name);
3211
}
3212

    
3213
static void v9fs_xattrcreate(void *opaque)
3214
{
3215
    int flags;
3216
    int32_t fid;
3217
    int64_t size;
3218
    ssize_t err = 0;
3219
    V9fsString name;
3220
    size_t offset = 7;
3221
    V9fsFidState *file_fidp;
3222
    V9fsFidState *xattr_fidp;
3223
    V9fsPDU *pdu = opaque;
3224
    V9fsState *s = pdu->s;
3225

    
3226
    pdu_unmarshal(pdu, offset, "dsqd",
3227
                  &fid, &name, &size, &flags);
3228

    
3229
    file_fidp = lookup_fid(s, fid);
3230
    if (file_fidp == NULL) {
3231
        err = -EINVAL;
3232
        goto out;
3233
    }
3234
    /* Make the file fid point to xattr */
3235
    xattr_fidp = file_fidp;
3236
    xattr_fidp->fid_type = P9_FID_XATTR;
3237
    xattr_fidp->fs.xattr.copied_len = 0;
3238
    xattr_fidp->fs.xattr.len = size;
3239
    xattr_fidp->fs.xattr.flags = flags;
3240
    v9fs_string_init(&xattr_fidp->fs.xattr.name);
3241
    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3242
    if (size) {
3243
        xattr_fidp->fs.xattr.value = g_malloc(size);
3244
    } else {
3245
        xattr_fidp->fs.xattr.value = NULL;
3246
    }
3247
    err = offset;
3248
out:
3249
    complete_pdu(s, pdu, err);
3250
    v9fs_string_free(&name);
3251
}
3252

    
3253
static void v9fs_readlink(void *opaque)
3254
{
3255
    V9fsPDU *pdu = opaque;
3256
    size_t offset = 7;
3257
    V9fsString target;
3258
    int32_t fid;
3259
    int err = 0;
3260
    V9fsFidState *fidp;
3261

    
3262
    pdu_unmarshal(pdu, offset, "d", &fid);
3263
    fidp = lookup_fid(pdu->s, fid);
3264
    if (fidp == NULL) {
3265
        err = -ENOENT;
3266
        goto out;
3267
    }
3268

    
3269
    v9fs_string_init(&target);
3270
    err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
3271
    if (err < 0) {
3272
        goto out;
3273
    }
3274
    offset += pdu_marshal(pdu, offset, "s", &target);
3275
    err = offset;
3276
    v9fs_string_free(&target);
3277
out:
3278
    complete_pdu(pdu->s, pdu, err);
3279
}
3280

    
3281
static CoroutineEntry *pdu_co_handlers[] = {
3282
    [P9_TREADDIR] = v9fs_readdir,
3283
    [P9_TSTATFS] = v9fs_statfs,
3284
    [P9_TGETATTR] = v9fs_getattr,
3285
    [P9_TSETATTR] = v9fs_setattr,
3286
    [P9_TXATTRWALK] = v9fs_xattrwalk,
3287
    [P9_TXATTRCREATE] = v9fs_xattrcreate,
3288
    [P9_TMKNOD] = v9fs_mknod,
3289
    [P9_TRENAME] = v9fs_rename,
3290
    [P9_TLOCK] = v9fs_lock,
3291
    [P9_TGETLOCK] = v9fs_getlock,
3292
    [P9_TREADLINK] = v9fs_readlink,
3293
    [P9_TMKDIR] = v9fs_mkdir,
3294
    [P9_TVERSION] = v9fs_version,
3295
    [P9_TLOPEN] = v9fs_open,
3296
    [P9_TATTACH] = v9fs_attach,
3297
    [P9_TSTAT] = v9fs_stat,
3298
    [P9_TWALK] = v9fs_walk,
3299
    [P9_TCLUNK] = v9fs_clunk,
3300
    [P9_TFSYNC] = v9fs_fsync,
3301
    [P9_TOPEN] = v9fs_open,
3302
    [P9_TREAD] = v9fs_read,
3303
#if 0
3304
    [P9_TAUTH] = v9fs_auth,
3305
#endif
3306
    [P9_TFLUSH] = v9fs_flush,
3307
    [P9_TLINK] = v9fs_link,
3308
    [P9_TSYMLINK] = v9fs_symlink,
3309
    [P9_TCREATE] = v9fs_create,
3310
    [P9_TLCREATE] = v9fs_lcreate,
3311
    [P9_TWRITE] = v9fs_write,
3312
    [P9_TWSTAT] = v9fs_wstat,
3313
    [P9_TREMOVE] = v9fs_remove,
3314
};
3315

    
3316
static void v9fs_op_not_supp(void *opaque)
3317
{
3318
    V9fsPDU *pdu = opaque;
3319
    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3320
}
3321

    
3322
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3323
{
3324
    Coroutine *co;
3325
    CoroutineEntry *handler;
3326

    
3327
    if (debug_9p_pdu) {
3328
        pprint_pdu(pdu);
3329
    }
3330
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3331
        (pdu_co_handlers[pdu->id] == NULL)) {
3332
        handler = v9fs_op_not_supp;
3333
    } else {
3334
        handler = pdu_co_handlers[pdu->id];
3335
    }
3336
    co = qemu_coroutine_create(handler);
3337
    qemu_coroutine_enter(co, pdu);
3338
}
3339

    
3340
void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3341
{
3342
    V9fsState *s = (V9fsState *)vdev;
3343
    V9fsPDU *pdu;
3344
    ssize_t len;
3345

    
3346
    while ((pdu = alloc_pdu(s)) &&
3347
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3348
        uint8_t *ptr;
3349
        pdu->s = s;
3350
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3351
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3352

    
3353
        ptr = pdu->elem.out_sg[0].iov_base;
3354

    
3355
        memcpy(&pdu->size, ptr, 4);
3356
        pdu->id = ptr[4];
3357
        memcpy(&pdu->tag, ptr + 5, 2);
3358
        submit_pdu(s, pdu);
3359
    }
3360
    free_pdu(s, pdu);
3361
}