Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (85.6 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_rename(V9fsState *s, V9fsString *oldpath,
193
                            V9fsString *newpath)
194
{
195
    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
196
}
197

    
198
static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
199
{
200
    FsCred cred;
201
    cred_init(&cred);
202
    cred.fc_uid = uid;
203
    cred.fc_gid = gid;
204

    
205
    return s->ops->chown(&s->ctx, path->data, &cred);
206
}
207

    
208
static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
209
                                           const struct timespec times[2])
210
{
211
    return s->ops->utimensat(&s->ctx, path->data, times);
212
}
213

    
214
static int v9fs_do_remove(V9fsState *s, V9fsString *path)
215
{
216
    return s->ops->remove(&s->ctx, path->data);
217
}
218

    
219
static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
220
{
221
    return s->ops->fsync(&s->ctx, fd, datasync);
222
}
223

    
224
static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
225
{
226
    return s->ops->statfs(&s->ctx, path->data, stbuf);
227
}
228

    
229
static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
230
                             V9fsString *xattr_name,
231
                             void *value, size_t size, int flags)
232
{
233
    return s->ops->lsetxattr(&s->ctx, path->data,
234
                             xattr_name->data, value, size, flags);
235
}
236

    
237
static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
238
                                V9fsString *xattr_name)
239
{
240
    return s->ops->lremovexattr(&s->ctx, path->data,
241
                                xattr_name->data);
242
}
243

    
244

    
245
static void v9fs_string_init(V9fsString *str)
246
{
247
    str->data = NULL;
248
    str->size = 0;
249
}
250

    
251
static void v9fs_string_free(V9fsString *str)
252
{
253
    qemu_free(str->data);
254
    str->data = NULL;
255
    str->size = 0;
256
}
257

    
258
static void v9fs_string_null(V9fsString *str)
259
{
260
    v9fs_string_free(str);
261
}
262

    
263
static int number_to_string(void *arg, char type)
264
{
265
    unsigned int ret = 0;
266

    
267
    switch (type) {
268
    case 'u': {
269
        unsigned int num = *(unsigned int *)arg;
270

    
271
        do {
272
            ret++;
273
            num = num/10;
274
        } while (num);
275
        break;
276
    }
277
    case 'U': {
278
        unsigned long num = *(unsigned long *)arg;
279
        do {
280
            ret++;
281
            num = num/10;
282
        } while (num);
283
        break;
284
    }
285
    default:
286
        printf("Number_to_string: Unknown number format\n");
287
        return -1;
288
    }
289

    
290
    return ret;
291
}
292

    
293
static int GCC_FMT_ATTR(2, 0)
294
v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
295
{
296
    va_list ap2;
297
    char *iter = (char *)fmt;
298
    int len = 0;
299
    int nr_args = 0;
300
    char *arg_char_ptr;
301
    unsigned int arg_uint;
302
    unsigned long arg_ulong;
303

    
304
    /* Find the number of %'s that denotes an argument */
305
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
306
        nr_args++;
307
        iter++;
308
    }
309

    
310
    len = strlen(fmt) - 2*nr_args;
311

    
312
    if (!nr_args) {
313
        goto alloc_print;
314
    }
315

    
316
    va_copy(ap2, ap);
317

    
318
    iter = (char *)fmt;
319

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

    
351
alloc_print:
352
    *strp = qemu_malloc((len + 1) * sizeof(**strp));
353

    
354
    return vsprintf(*strp, fmt, ap);
355
}
356

    
357
static void GCC_FMT_ATTR(2, 3)
358
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
359
{
360
    va_list ap;
361
    int err;
362

    
363
    v9fs_string_free(str);
364

    
365
    va_start(ap, fmt);
366
    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
367
    BUG_ON(err == -1);
368
    va_end(ap);
369

    
370
    str->size = err;
371
}
372

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

    
379
/*
380
 * Return TRUE if s1 is an ancestor of s2.
381
 *
382
 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
383
 * As a special case, We treat s1 as ancestor of s2 if they are same!
384
 */
385
static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
386
{
387
    if (!strncmp(s1->data, s2->data, s1->size)) {
388
        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
389
            return 1;
390
        }
391
    }
392
    return 0;
393
}
394

    
395
static size_t v9fs_string_size(V9fsString *str)
396
{
397
    return str->size;
398
}
399

    
400
static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
401
{
402
    V9fsFidState *f;
403

    
404
    for (f = s->fid_list; f; f = f->next) {
405
        if (f->fid == fid) {
406
            return f;
407
        }
408
    }
409

    
410
    return NULL;
411
}
412

    
413
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
414
{
415
    V9fsFidState *f;
416

    
417
    f = lookup_fid(s, fid);
418
    if (f) {
419
        return NULL;
420
    }
421

    
422
    f = qemu_mallocz(sizeof(V9fsFidState));
423

    
424
    f->fid = fid;
425
    f->fid_type = P9_FID_NONE;
426

    
427
    f->next = s->fid_list;
428
    s->fid_list = f;
429

    
430
    return f;
431
}
432

    
433
static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
434
{
435
    int retval = 0;
436

    
437
    if (fidp->fs.xattr.copied_len == -1) {
438
        /* getxattr/listxattr fid */
439
        goto free_value;
440
    }
441
    /*
442
     * if this is fid for setxattr. clunk should
443
     * result in setxattr localcall
444
     */
445
    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
446
        /* clunk after partial write */
447
        retval = -EINVAL;
448
        goto free_out;
449
    }
450
    if (fidp->fs.xattr.len) {
451
        retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
452
                                   fidp->fs.xattr.value,
453
                                   fidp->fs.xattr.len,
454
                                   fidp->fs.xattr.flags);
455
    } else {
456
        retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
457
    }
458
free_out:
459
    v9fs_string_free(&fidp->fs.xattr.name);
460
free_value:
461
    if (fidp->fs.xattr.value) {
462
        qemu_free(fidp->fs.xattr.value);
463
    }
464
    return retval;
465
}
466

    
467
static int free_fid(V9fsState *s, int32_t fid)
468
{
469
    int retval = 0;
470
    V9fsFidState **fidpp, *fidp;
471

    
472
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
473
        if ((*fidpp)->fid == fid) {
474
            break;
475
        }
476
    }
477

    
478
    if (*fidpp == NULL) {
479
        return -ENOENT;
480
    }
481

    
482
    fidp = *fidpp;
483
    *fidpp = fidp->next;
484

    
485
    if (fidp->fid_type == P9_FID_FILE) {
486
        v9fs_do_close(s, fidp->fs.fd);
487
    } else if (fidp->fid_type == P9_FID_DIR) {
488
        v9fs_do_closedir(s, fidp->fs.dir);
489
    } else if (fidp->fid_type == P9_FID_XATTR) {
490
        retval = v9fs_xattr_fid_clunk(s, fidp);
491
    }
492
    v9fs_string_free(&fidp->path);
493
    qemu_free(fidp);
494

    
495
    return retval;
496
}
497

    
498
#define P9_QID_TYPE_DIR         0x80
499
#define P9_QID_TYPE_SYMLINK     0x02
500

    
501
#define P9_STAT_MODE_DIR        0x80000000
502
#define P9_STAT_MODE_APPEND     0x40000000
503
#define P9_STAT_MODE_EXCL       0x20000000
504
#define P9_STAT_MODE_MOUNT      0x10000000
505
#define P9_STAT_MODE_AUTH       0x08000000
506
#define P9_STAT_MODE_TMP        0x04000000
507
#define P9_STAT_MODE_SYMLINK    0x02000000
508
#define P9_STAT_MODE_LINK       0x01000000
509
#define P9_STAT_MODE_DEVICE     0x00800000
510
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
511
#define P9_STAT_MODE_SOCKET     0x00100000
512
#define P9_STAT_MODE_SETUID     0x00080000
513
#define P9_STAT_MODE_SETGID     0x00040000
514
#define P9_STAT_MODE_SETVTX     0x00010000
515

    
516
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
517
                                P9_STAT_MODE_SYMLINK |      \
518
                                P9_STAT_MODE_LINK |         \
519
                                P9_STAT_MODE_DEVICE |       \
520
                                P9_STAT_MODE_NAMED_PIPE |   \
521
                                P9_STAT_MODE_SOCKET)
522

    
523
/* This is the algorithm from ufs in spfs */
524
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
525
{
526
    size_t size;
527

    
528
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
529
    memcpy(&qidp->path, &stbuf->st_ino, size);
530
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
531
    qidp->type = 0;
532
    if (S_ISDIR(stbuf->st_mode)) {
533
        qidp->type |= P9_QID_TYPE_DIR;
534
    }
535
    if (S_ISLNK(stbuf->st_mode)) {
536
        qidp->type |= P9_QID_TYPE_SYMLINK;
537
    }
538
}
539

    
540
static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
541
{
542
    struct stat stbuf;
543
    int err;
544

    
545
    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
546
    if (err) {
547
        return err;
548
    }
549

    
550
    stat_to_qid(&stbuf, qidp);
551
    return 0;
552
}
553

    
554
static V9fsPDU *alloc_pdu(V9fsState *s)
555
{
556
    V9fsPDU *pdu = NULL;
557

    
558
    if (!QLIST_EMPTY(&s->free_list)) {
559
        pdu = QLIST_FIRST(&s->free_list);
560
        QLIST_REMOVE(pdu, next);
561
    }
562
    return pdu;
563
}
564

    
565
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
566
{
567
    if (pdu) {
568
        if (debug_9p_pdu) {
569
            pprint_pdu(pdu);
570
        }
571
        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
572
    }
573
}
574

    
575
size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
576
                        size_t offset, size_t size, int pack)
577
{
578
    int i = 0;
579
    size_t copied = 0;
580

    
581
    for (i = 0; size && i < sg_count; i++) {
582
        size_t len;
583
        if (offset >= sg[i].iov_len) {
584
            /* skip this sg */
585
            offset -= sg[i].iov_len;
586
            continue;
587
        } else {
588
            len = MIN(sg[i].iov_len - offset, size);
589
            if (pack) {
590
                memcpy(sg[i].iov_base + offset, addr, len);
591
            } else {
592
                memcpy(addr, sg[i].iov_base + offset, len);
593
            }
594
            size -= len;
595
            copied += len;
596
            addr += len;
597
            if (size) {
598
                offset = 0;
599
                continue;
600
            }
601
        }
602
    }
603

    
604
    return copied;
605
}
606

    
607
static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
608
{
609
    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
610
                         offset, size, 0);
611
}
612

    
613
static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
614
                        size_t size)
615
{
616
    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
617
                             offset, size, 1);
618
}
619

    
620
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
621
{
622
    size_t pos = 0;
623
    int i, j;
624
    struct iovec *src_sg;
625
    unsigned int num;
626

    
627
    if (rx) {
628
        src_sg = pdu->elem.in_sg;
629
        num = pdu->elem.in_num;
630
    } else {
631
        src_sg = pdu->elem.out_sg;
632
        num = pdu->elem.out_num;
633
    }
634

    
635
    j = 0;
636
    for (i = 0; i < num; i++) {
637
        if (offset <= pos) {
638
            sg[j].iov_base = src_sg[i].iov_base;
639
            sg[j].iov_len = src_sg[i].iov_len;
640
            j++;
641
        } else if (offset < (src_sg[i].iov_len + pos)) {
642
            sg[j].iov_base = src_sg[i].iov_base;
643
            sg[j].iov_len = src_sg[i].iov_len;
644
            sg[j].iov_base += (offset - pos);
645
            sg[j].iov_len -= (offset - pos);
646
            j++;
647
        }
648
        pos += src_sg[i].iov_len;
649
    }
650

    
651
    return j;
652
}
653

    
654
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
655
{
656
    size_t old_offset = offset;
657
    va_list ap;
658
    int i;
659

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

    
736
    va_end(ap);
737

    
738
    return offset - old_offset;
739
}
740

    
741
static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
742
{
743
    size_t old_offset = offset;
744
    va_list ap;
745
    int i;
746

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

    
823
    return offset - old_offset;
824
}
825

    
826
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
827
{
828
    int8_t id = pdu->id + 1; /* Response */
829

    
830
    if (len < 0) {
831
        int err = -len;
832
        len = 7;
833

    
834
        if (s->proto_version != V9FS_PROTO_2000L) {
835
            V9fsString str;
836

    
837
            str.data = strerror(err);
838
            str.size = strlen(str.data);
839

    
840
            len += pdu_marshal(pdu, len, "s", &str);
841
            id = P9_RERROR;
842
        }
843

    
844
        len += pdu_marshal(pdu, len, "d", err);
845

    
846
        if (s->proto_version == V9FS_PROTO_2000L) {
847
            id = P9_RLERROR;
848
        }
849
    }
850

    
851
    /* fill out the header */
852
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
853

    
854
    /* keep these in sync */
855
    pdu->size = len;
856
    pdu->id = id;
857

    
858
    /* push onto queue and notify */
859
    virtqueue_push(s->vq, &pdu->elem, len);
860

    
861
    /* FIXME: we should batch these completions */
862
    virtio_notify(&s->vdev, s->vq);
863

    
864
    free_pdu(s, pdu);
865
}
866

    
867
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
868
{
869
    mode_t ret;
870

    
871
    ret = mode & 0777;
872
    if (mode & P9_STAT_MODE_DIR) {
873
        ret |= S_IFDIR;
874
    }
875

    
876
    if (mode & P9_STAT_MODE_SYMLINK) {
877
        ret |= S_IFLNK;
878
    }
879
    if (mode & P9_STAT_MODE_SOCKET) {
880
        ret |= S_IFSOCK;
881
    }
882
    if (mode & P9_STAT_MODE_NAMED_PIPE) {
883
        ret |= S_IFIFO;
884
    }
885
    if (mode & P9_STAT_MODE_DEVICE) {
886
        if (extension && extension->data[0] == 'c') {
887
            ret |= S_IFCHR;
888
        } else {
889
            ret |= S_IFBLK;
890
        }
891
    }
892

    
893
    if (!(ret&~0777)) {
894
        ret |= S_IFREG;
895
    }
896

    
897
    if (mode & P9_STAT_MODE_SETUID) {
898
        ret |= S_ISUID;
899
    }
900
    if (mode & P9_STAT_MODE_SETGID) {
901
        ret |= S_ISGID;
902
    }
903
    if (mode & P9_STAT_MODE_SETVTX) {
904
        ret |= S_ISVTX;
905
    }
906

    
907
    return ret;
908
}
909

    
910
static int donttouch_stat(V9fsStat *stat)
911
{
912
    if (stat->type == -1 &&
913
        stat->dev == -1 &&
914
        stat->qid.type == -1 &&
915
        stat->qid.version == -1 &&
916
        stat->qid.path == -1 &&
917
        stat->mode == -1 &&
918
        stat->atime == -1 &&
919
        stat->mtime == -1 &&
920
        stat->length == -1 &&
921
        !stat->name.size &&
922
        !stat->uid.size &&
923
        !stat->gid.size &&
924
        !stat->muid.size &&
925
        stat->n_uid == -1 &&
926
        stat->n_gid == -1 &&
927
        stat->n_muid == -1) {
928
        return 1;
929
    }
930

    
931
    return 0;
932
}
933

    
934
static void v9fs_stat_free(V9fsStat *stat)
935
{
936
    v9fs_string_free(&stat->name);
937
    v9fs_string_free(&stat->uid);
938
    v9fs_string_free(&stat->gid);
939
    v9fs_string_free(&stat->muid);
940
    v9fs_string_free(&stat->extension);
941
}
942

    
943
static uint32_t stat_to_v9mode(const struct stat *stbuf)
944
{
945
    uint32_t mode;
946

    
947
    mode = stbuf->st_mode & 0777;
948
    if (S_ISDIR(stbuf->st_mode)) {
949
        mode |= P9_STAT_MODE_DIR;
950
    }
951

    
952
    if (S_ISLNK(stbuf->st_mode)) {
953
        mode |= P9_STAT_MODE_SYMLINK;
954
    }
955

    
956
    if (S_ISSOCK(stbuf->st_mode)) {
957
        mode |= P9_STAT_MODE_SOCKET;
958
    }
959

    
960
    if (S_ISFIFO(stbuf->st_mode)) {
961
        mode |= P9_STAT_MODE_NAMED_PIPE;
962
    }
963

    
964
    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
965
        mode |= P9_STAT_MODE_DEVICE;
966
    }
967

    
968
    if (stbuf->st_mode & S_ISUID) {
969
        mode |= P9_STAT_MODE_SETUID;
970
    }
971

    
972
    if (stbuf->st_mode & S_ISGID) {
973
        mode |= P9_STAT_MODE_SETGID;
974
    }
975

    
976
    if (stbuf->st_mode & S_ISVTX) {
977
        mode |= P9_STAT_MODE_SETVTX;
978
    }
979

    
980
    return mode;
981
}
982

    
983
static int stat_to_v9stat(V9fsState *s, V9fsString *name,
984
                            const struct stat *stbuf,
985
                            V9fsStat *v9stat)
986
{
987
    int err;
988
    const char *str;
989

    
990
    memset(v9stat, 0, sizeof(*v9stat));
991

    
992
    stat_to_qid(stbuf, &v9stat->qid);
993
    v9stat->mode = stat_to_v9mode(stbuf);
994
    v9stat->atime = stbuf->st_atime;
995
    v9stat->mtime = stbuf->st_mtime;
996
    v9stat->length = stbuf->st_size;
997

    
998
    v9fs_string_null(&v9stat->uid);
999
    v9fs_string_null(&v9stat->gid);
1000
    v9fs_string_null(&v9stat->muid);
1001

    
1002
    v9stat->n_uid = stbuf->st_uid;
1003
    v9stat->n_gid = stbuf->st_gid;
1004
    v9stat->n_muid = 0;
1005

    
1006
    v9fs_string_null(&v9stat->extension);
1007

    
1008
    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1009
        err = v9fs_co_readlink(s, name, &v9stat->extension);
1010
        if (err < 0) {
1011
            return err;
1012
        }
1013
    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1014
        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1015
                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1016
                major(stbuf->st_rdev), minor(stbuf->st_rdev));
1017
    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1018
        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1019
                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1020
    }
1021

    
1022
    str = strrchr(name->data, '/');
1023
    if (str) {
1024
        str += 1;
1025
    } else {
1026
        str = name->data;
1027
    }
1028

    
1029
    v9fs_string_sprintf(&v9stat->name, "%s", str);
1030

    
1031
    v9stat->size = 61 +
1032
        v9fs_string_size(&v9stat->name) +
1033
        v9fs_string_size(&v9stat->uid) +
1034
        v9fs_string_size(&v9stat->gid) +
1035
        v9fs_string_size(&v9stat->muid) +
1036
        v9fs_string_size(&v9stat->extension);
1037
    return 0;
1038
}
1039

    
1040
#define P9_STATS_MODE          0x00000001ULL
1041
#define P9_STATS_NLINK         0x00000002ULL
1042
#define P9_STATS_UID           0x00000004ULL
1043
#define P9_STATS_GID           0x00000008ULL
1044
#define P9_STATS_RDEV          0x00000010ULL
1045
#define P9_STATS_ATIME         0x00000020ULL
1046
#define P9_STATS_MTIME         0x00000040ULL
1047
#define P9_STATS_CTIME         0x00000080ULL
1048
#define P9_STATS_INO           0x00000100ULL
1049
#define P9_STATS_SIZE          0x00000200ULL
1050
#define P9_STATS_BLOCKS        0x00000400ULL
1051

    
1052
#define P9_STATS_BTIME         0x00000800ULL
1053
#define P9_STATS_GEN           0x00001000ULL
1054
#define P9_STATS_DATA_VERSION  0x00002000ULL
1055

    
1056
#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
1057
#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
1058

    
1059

    
1060
static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1061
                                V9fsStatDotl *v9lstat)
1062
{
1063
    memset(v9lstat, 0, sizeof(*v9lstat));
1064

    
1065
    v9lstat->st_mode = stbuf->st_mode;
1066
    v9lstat->st_nlink = stbuf->st_nlink;
1067
    v9lstat->st_uid = stbuf->st_uid;
1068
    v9lstat->st_gid = stbuf->st_gid;
1069
    v9lstat->st_rdev = stbuf->st_rdev;
1070
    v9lstat->st_size = stbuf->st_size;
1071
    v9lstat->st_blksize = stbuf->st_blksize;
1072
    v9lstat->st_blocks = stbuf->st_blocks;
1073
    v9lstat->st_atime_sec = stbuf->st_atime;
1074
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1075
    v9lstat->st_mtime_sec = stbuf->st_mtime;
1076
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1077
    v9lstat->st_ctime_sec = stbuf->st_ctime;
1078
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1079
    /* Currently we only support BASIC fields in stat */
1080
    v9lstat->st_result_mask = P9_STATS_BASIC;
1081

    
1082
    stat_to_qid(stbuf, &v9lstat->qid);
1083
}
1084

    
1085
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1086
{
1087
    while (len && *iovcnt) {
1088
        if (len < sg->iov_len) {
1089
            sg->iov_len -= len;
1090
            sg->iov_base += len;
1091
            len = 0;
1092
        } else {
1093
            len -= sg->iov_len;
1094
            sg++;
1095
            *iovcnt -= 1;
1096
        }
1097
    }
1098

    
1099
    return sg;
1100
}
1101

    
1102
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1103
{
1104
    int i;
1105
    int total = 0;
1106

    
1107
    for (i = 0; i < *cnt; i++) {
1108
        if ((total + sg[i].iov_len) > cap) {
1109
            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1110
            i++;
1111
            break;
1112
        }
1113
        total += sg[i].iov_len;
1114
    }
1115

    
1116
    *cnt = i;
1117

    
1118
    return sg;
1119
}
1120

    
1121
static void print_sg(struct iovec *sg, int cnt)
1122
{
1123
    int i;
1124

    
1125
    printf("sg[%d]: {", cnt);
1126
    for (i = 0; i < cnt; i++) {
1127
        if (i) {
1128
            printf(", ");
1129
        }
1130
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1131
    }
1132
    printf("}\n");
1133
}
1134

    
1135
static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1136
{
1137
    V9fsString str;
1138
    v9fs_string_init(&str);
1139
    v9fs_string_copy(&str, dst);
1140
    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1141
    v9fs_string_free(&str);
1142
}
1143

    
1144
static void v9fs_version(void *opaque)
1145
{
1146
    V9fsPDU *pdu = opaque;
1147
    V9fsState *s = pdu->s;
1148
    V9fsString version;
1149
    size_t offset = 7;
1150

    
1151
    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1152

    
1153
    if (!strcmp(version.data, "9P2000.u")) {
1154
        s->proto_version = V9FS_PROTO_2000U;
1155
    } else if (!strcmp(version.data, "9P2000.L")) {
1156
        s->proto_version = V9FS_PROTO_2000L;
1157
    } else {
1158
        v9fs_string_sprintf(&version, "unknown");
1159
    }
1160

    
1161
    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1162
    complete_pdu(s, pdu, offset);
1163

    
1164
    v9fs_string_free(&version);
1165
    return;
1166
}
1167

    
1168
static void v9fs_attach(void *opaque)
1169
{
1170
    V9fsPDU *pdu = opaque;
1171
    V9fsState *s = pdu->s;
1172
    int32_t fid, afid, n_uname;
1173
    V9fsString uname, aname;
1174
    V9fsFidState *fidp;
1175
    V9fsQID qid;
1176
    size_t offset = 7;
1177
    ssize_t err;
1178

    
1179
    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1180

    
1181
    fidp = alloc_fid(s, fid);
1182
    if (fidp == NULL) {
1183
        err = -EINVAL;
1184
        goto out;
1185
    }
1186

    
1187
    fidp->uid = n_uname;
1188

    
1189
    v9fs_string_sprintf(&fidp->path, "%s", "/");
1190
    err = fid_to_qid(s, fidp, &qid);
1191
    if (err) {
1192
        err = -EINVAL;
1193
        free_fid(s, fid);
1194
        goto out;
1195
    }
1196

    
1197
    offset += pdu_marshal(pdu, offset, "Q", &qid);
1198

    
1199
    err = offset;
1200
out:
1201
    complete_pdu(s, pdu, err);
1202
    v9fs_string_free(&uname);
1203
    v9fs_string_free(&aname);
1204
}
1205

    
1206
static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1207
{
1208
    if (err == -1) {
1209
        err = -errno;
1210
        goto out;
1211
    }
1212

    
1213
    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1214
    if (err) {
1215
        goto out;
1216
    }
1217
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1218
    err = vs->offset;
1219

    
1220
out:
1221
    complete_pdu(s, vs->pdu, err);
1222
    v9fs_stat_free(&vs->v9stat);
1223
    qemu_free(vs);
1224
}
1225

    
1226
static void v9fs_stat(void *opaque)
1227
{
1228
    V9fsPDU *pdu = opaque;
1229
    V9fsState *s = pdu->s;
1230
    int32_t fid;
1231
    V9fsStatState *vs;
1232
    ssize_t err = 0;
1233

    
1234
    vs = qemu_malloc(sizeof(*vs));
1235
    vs->pdu = pdu;
1236
    vs->offset = 7;
1237

    
1238
    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1239

    
1240
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1241

    
1242
    vs->fidp = lookup_fid(s, fid);
1243
    if (vs->fidp == NULL) {
1244
        err = -ENOENT;
1245
        goto out;
1246
    }
1247

    
1248
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1249
    v9fs_stat_post_lstat(s, vs, err);
1250
    return;
1251

    
1252
out:
1253
    complete_pdu(s, vs->pdu, err);
1254
    v9fs_stat_free(&vs->v9stat);
1255
    qemu_free(vs);
1256
}
1257

    
1258
static void v9fs_getattr(void *opaque)
1259
{
1260
    int32_t fid;
1261
    size_t offset = 7;
1262
    ssize_t retval = 0;
1263
    struct stat stbuf;
1264
    V9fsFidState *fidp;
1265
    uint64_t request_mask;
1266
    V9fsStatDotl v9stat_dotl;
1267
    V9fsPDU *pdu = opaque;
1268
    V9fsState *s = pdu->s;
1269

    
1270
    pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1271

    
1272
    fidp = lookup_fid(s, fid);
1273
    if (fidp == NULL) {
1274
        retval = -ENOENT;
1275
        goto out;
1276
    }
1277
    /*
1278
     * Currently we only support BASIC fields in stat, so there is no
1279
     * need to look at request_mask.
1280
     */
1281
    retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1282
    if (retval < 0) {
1283
        goto out;
1284
    }
1285
    stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1286
    retval = offset;
1287
    retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1288
out:
1289
    complete_pdu(s, pdu, retval);
1290
}
1291

    
1292
/* From Linux kernel code */
1293
#define ATTR_MODE    (1 << 0)
1294
#define ATTR_UID     (1 << 1)
1295
#define ATTR_GID     (1 << 2)
1296
#define ATTR_SIZE    (1 << 3)
1297
#define ATTR_ATIME   (1 << 4)
1298
#define ATTR_MTIME   (1 << 5)
1299
#define ATTR_CTIME   (1 << 6)
1300
#define ATTR_MASK    127
1301
#define ATTR_ATIME_SET  (1 << 7)
1302
#define ATTR_MTIME_SET  (1 << 8)
1303

    
1304
static void v9fs_setattr(void *opaque)
1305
{
1306
    int err = 0;
1307
    int32_t fid;
1308
    V9fsFidState *fidp;
1309
    size_t offset = 7;
1310
    V9fsIattr v9iattr;
1311
    V9fsPDU *pdu = opaque;
1312
    V9fsState *s = pdu->s;
1313

    
1314
    pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1315

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

    
1384
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1385
{
1386
    complete_pdu(s, vs->pdu, err);
1387

    
1388
    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1389
        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1390
            v9fs_string_free(&vs->wnames[vs->name_idx]);
1391
        }
1392

    
1393
        qemu_free(vs->wnames);
1394
        qemu_free(vs->qids);
1395
    }
1396
}
1397

    
1398
static void v9fs_walk_marshal(V9fsWalkState *vs)
1399
{
1400
    int i;
1401
    vs->offset = 7;
1402
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1403

    
1404
    for (i = 0; i < vs->nwnames; i++) {
1405
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1406
    }
1407
}
1408

    
1409
static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1410
                                                                int err)
1411
{
1412
    if (err == -1) {
1413
        free_fid(s, vs->newfidp->fid);
1414
        v9fs_string_free(&vs->path);
1415
        err = -ENOENT;
1416
        goto out;
1417
    }
1418

    
1419
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1420

    
1421
    vs->name_idx++;
1422
    if (vs->name_idx < vs->nwnames) {
1423
        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1424
                                            vs->wnames[vs->name_idx].data);
1425
        v9fs_string_copy(&vs->newfidp->path, &vs->path);
1426

    
1427
        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1428
        v9fs_walk_post_newfid_lstat(s, vs, err);
1429
        return;
1430
    }
1431

    
1432
    v9fs_string_free(&vs->path);
1433
    v9fs_walk_marshal(vs);
1434
    err = vs->offset;
1435
out:
1436
    v9fs_walk_complete(s, vs, err);
1437
}
1438

    
1439
static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1440
        int err)
1441
{
1442
    if (err == -1) {
1443
        v9fs_string_free(&vs->path);
1444
        err = -ENOENT;
1445
        goto out;
1446
    }
1447

    
1448
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1449
    vs->name_idx++;
1450
    if (vs->name_idx < vs->nwnames) {
1451

    
1452
        v9fs_string_sprintf(&vs->path, "%s/%s",
1453
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1454
        v9fs_string_copy(&vs->fidp->path, &vs->path);
1455

    
1456
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1457
        v9fs_walk_post_oldfid_lstat(s, vs, err);
1458
        return;
1459
    }
1460

    
1461
    v9fs_string_free(&vs->path);
1462
    v9fs_walk_marshal(vs);
1463
    err = vs->offset;
1464
out:
1465
    v9fs_walk_complete(s, vs, err);
1466
}
1467

    
1468
static void v9fs_walk(void *opaque)
1469
{
1470
    V9fsPDU *pdu = opaque;
1471
    V9fsState *s = pdu->s;
1472
    int32_t fid, newfid;
1473
    V9fsWalkState *vs;
1474
    int err = 0;
1475
    int i;
1476

    
1477
    vs = qemu_malloc(sizeof(*vs));
1478
    vs->pdu = pdu;
1479
    vs->wnames = NULL;
1480
    vs->qids = NULL;
1481
    vs->offset = 7;
1482

    
1483
    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1484
                                            &newfid, &vs->nwnames);
1485

    
1486
    if (vs->nwnames && vs->nwnames <= P9_MAXWELEM) {
1487
        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1488

    
1489
        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1490

    
1491
        for (i = 0; i < vs->nwnames; i++) {
1492
            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1493
                                            &vs->wnames[i]);
1494
        }
1495
    } else if (vs->nwnames > P9_MAXWELEM) {
1496
        err = -EINVAL;
1497
        goto out;
1498
    }
1499

    
1500
    vs->fidp = lookup_fid(s, fid);
1501
    if (vs->fidp == NULL) {
1502
        err = -ENOENT;
1503
        goto out;
1504
    }
1505

    
1506
    /* FIXME: is this really valid? */
1507
    if (fid == newfid) {
1508

    
1509
        BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1510
        v9fs_string_init(&vs->path);
1511
        vs->name_idx = 0;
1512

    
1513
        if (vs->name_idx < vs->nwnames) {
1514
            v9fs_string_sprintf(&vs->path, "%s/%s",
1515
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1516
            v9fs_string_copy(&vs->fidp->path, &vs->path);
1517

    
1518
            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1519
            v9fs_walk_post_oldfid_lstat(s, vs, err);
1520
            return;
1521
        }
1522
    } else {
1523
        vs->newfidp = alloc_fid(s, newfid);
1524
        if (vs->newfidp == NULL) {
1525
            err = -EINVAL;
1526
            goto out;
1527
        }
1528

    
1529
        vs->newfidp->uid = vs->fidp->uid;
1530
        v9fs_string_init(&vs->path);
1531
        vs->name_idx = 0;
1532
        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1533

    
1534
        if (vs->name_idx < vs->nwnames) {
1535
            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1536
                                vs->wnames[vs->name_idx].data);
1537
            v9fs_string_copy(&vs->newfidp->path, &vs->path);
1538

    
1539
            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1540
            v9fs_walk_post_newfid_lstat(s, vs, err);
1541
            return;
1542
        }
1543
    }
1544

    
1545
    v9fs_walk_marshal(vs);
1546
    err = vs->offset;
1547
out:
1548
    v9fs_walk_complete(s, vs, err);
1549
}
1550

    
1551
static int32_t get_iounit(V9fsState *s, V9fsString *name)
1552
{
1553
    struct statfs stbuf;
1554
    int32_t iounit = 0;
1555

    
1556
    /*
1557
     * iounit should be multiples of f_bsize (host filesystem block size
1558
     * and as well as less than (client msize - P9_IOHDRSZ))
1559
     */
1560
    if (!v9fs_do_statfs(s, name, &stbuf)) {
1561
        iounit = stbuf.f_bsize;
1562
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1563
    }
1564

    
1565
    if (!iounit) {
1566
        iounit = s->msize - P9_IOHDRSZ;
1567
    }
1568
    return iounit;
1569
}
1570

    
1571
static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1572
{
1573
    if (vs->fidp->fs.dir == NULL) {
1574
        err = -errno;
1575
        goto out;
1576
    }
1577
    vs->fidp->fid_type = P9_FID_DIR;
1578
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1579
    err = vs->offset;
1580
out:
1581
    complete_pdu(s, vs->pdu, err);
1582
    qemu_free(vs);
1583

    
1584
}
1585

    
1586
static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
1587
{
1588
    int err;
1589
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
1590
    err = vs->offset;
1591
    complete_pdu(s, vs->pdu, err);
1592
    qemu_free(vs);
1593
}
1594

    
1595
static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1596
{
1597
    if (vs->fidp->fs.fd == -1) {
1598
        err = -errno;
1599
        goto out;
1600
    }
1601
    vs->fidp->fid_type = P9_FID_FILE;
1602
    vs->iounit = get_iounit(s, &vs->fidp->path);
1603
    v9fs_open_post_getiounit(s, vs);
1604
    return;
1605
out:
1606
    complete_pdu(s, vs->pdu, err);
1607
    qemu_free(vs);
1608
}
1609

    
1610
static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1611
{
1612
    int flags;
1613

    
1614
    if (err) {
1615
        err = -errno;
1616
        goto out;
1617
    }
1618

    
1619
    stat_to_qid(&vs->stbuf, &vs->qid);
1620

    
1621
    if (S_ISDIR(vs->stbuf.st_mode)) {
1622
        vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1623
        v9fs_open_post_opendir(s, vs, err);
1624
    } else {
1625
        if (s->proto_version == V9FS_PROTO_2000L) {
1626
            flags = vs->mode;
1627
            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1628
            /* Ignore direct disk access hint until the server supports it. */
1629
            flags &= ~O_DIRECT;
1630
        } else {
1631
            flags = omode_to_uflags(vs->mode);
1632
        }
1633
        vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1634
        v9fs_open_post_open(s, vs, err);
1635
    }
1636
    return;
1637
out:
1638
    complete_pdu(s, vs->pdu, err);
1639
    qemu_free(vs);
1640
}
1641

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

    
1650
    vs = qemu_malloc(sizeof(*vs));
1651
    vs->pdu = pdu;
1652
    vs->offset = 7;
1653
    vs->mode = 0;
1654

    
1655
    if (s->proto_version == V9FS_PROTO_2000L) {
1656
        pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
1657
    } else {
1658
        pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1659
    }
1660

    
1661
    vs->fidp = lookup_fid(s, fid);
1662
    if (vs->fidp == NULL) {
1663
        err = -ENOENT;
1664
        goto out;
1665
    }
1666

    
1667
    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1668

    
1669
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1670

    
1671
    v9fs_open_post_lstat(s, vs, err);
1672
    return;
1673
out:
1674
    complete_pdu(s, pdu, err);
1675
    qemu_free(vs);
1676
}
1677

    
1678
static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1679
{
1680
    if (err == 0) {
1681
        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1682
        stat_to_qid(&vs->stbuf, &vs->qid);
1683
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
1684
                vs->iounit);
1685
        err = vs->offset;
1686
    } else {
1687
        vs->fidp->fid_type = P9_FID_NONE;
1688
        err = -errno;
1689
        if (vs->fidp->fs.fd > 0) {
1690
            close(vs->fidp->fs.fd);
1691
        }
1692
    }
1693

    
1694
    complete_pdu(s, vs->pdu, err);
1695
    v9fs_string_free(&vs->name);
1696
    v9fs_string_free(&vs->fullname);
1697
    qemu_free(vs);
1698
}
1699

    
1700
static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
1701
        int err)
1702
{
1703
    if (err) {
1704
        err = -errno;
1705
        goto out;
1706
    }
1707
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1708

    
1709
out:
1710
    v9fs_post_lcreate(s, vs, err);
1711
}
1712

    
1713
static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
1714
        int err)
1715
{
1716
    if (vs->fidp->fs.fd == -1) {
1717
        err = -errno;
1718
        goto out;
1719
    }
1720
    vs->fidp->fid_type = P9_FID_FILE;
1721
    vs->iounit =  get_iounit(s, &vs->fullname);
1722
    v9fs_lcreate_post_get_iounit(s, vs, err);
1723
    return;
1724

    
1725
out:
1726
    v9fs_post_lcreate(s, vs, err);
1727
}
1728

    
1729
static void v9fs_lcreate(void *opaque)
1730
{
1731
    V9fsPDU *pdu = opaque;
1732
    V9fsState *s = pdu->s;
1733
    int32_t dfid, flags, mode;
1734
    gid_t gid;
1735
    V9fsLcreateState *vs;
1736
    ssize_t err = 0;
1737

    
1738
    vs = qemu_malloc(sizeof(*vs));
1739
    vs->pdu = pdu;
1740
    vs->offset = 7;
1741

    
1742
    v9fs_string_init(&vs->fullname);
1743

    
1744
    pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
1745
            &mode, &gid);
1746

    
1747
    vs->fidp = lookup_fid(s, dfid);
1748
    if (vs->fidp == NULL) {
1749
        err = -ENOENT;
1750
        goto out;
1751
    }
1752

    
1753
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1754
             vs->name.data);
1755

    
1756
    /* Ignore direct disk access hint until the server supports it. */
1757
    flags &= ~O_DIRECT;
1758

    
1759
    vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
1760
            gid, flags, mode);
1761
    v9fs_lcreate_post_do_open2(s, vs, err);
1762
    return;
1763

    
1764
out:
1765
    complete_pdu(s, vs->pdu, err);
1766
    v9fs_string_free(&vs->name);
1767
    qemu_free(vs);
1768
}
1769

    
1770
static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
1771
{
1772
    if (err == -1) {
1773
        err = -errno;
1774
    }
1775
    complete_pdu(s, pdu, err);
1776
}
1777

    
1778
static void v9fs_fsync(void *opaque)
1779
{
1780
    V9fsPDU *pdu = opaque;
1781
    V9fsState *s = pdu->s;
1782
    int32_t fid;
1783
    size_t offset = 7;
1784
    V9fsFidState *fidp;
1785
    int datasync;
1786
    int err;
1787

    
1788
    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1789
    fidp = lookup_fid(s, fid);
1790
    if (fidp == NULL) {
1791
        err = -ENOENT;
1792
        v9fs_post_do_fsync(s, pdu, err);
1793
        return;
1794
    }
1795
    err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
1796
    v9fs_post_do_fsync(s, pdu, err);
1797
}
1798

    
1799
static void v9fs_clunk(void *opaque)
1800
{
1801
    V9fsPDU *pdu = opaque;
1802
    V9fsState *s = pdu->s;
1803
    int32_t fid;
1804
    size_t offset = 7;
1805
    int err;
1806

    
1807
    pdu_unmarshal(pdu, offset, "d", &fid);
1808

    
1809
    err = free_fid(s, fid);
1810
    if (err < 0) {
1811
        goto out;
1812
    }
1813

    
1814
    offset = 7;
1815
    err = offset;
1816
out:
1817
    complete_pdu(s, pdu, err);
1818
}
1819

    
1820
static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1821

    
1822
static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1823
{
1824
    if (err) {
1825
        goto out;
1826
    }
1827
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1828
    vs->offset += vs->count;
1829
    err = vs->offset;
1830
out:
1831
    complete_pdu(s, vs->pdu, err);
1832
    v9fs_stat_free(&vs->v9stat);
1833
    v9fs_string_free(&vs->name);
1834
    qemu_free(vs);
1835
    return;
1836
}
1837

    
1838
static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1839
                                    ssize_t err)
1840
{
1841
    if (err) {
1842
        err = -errno;
1843
        goto out;
1844
    }
1845
    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1846
    if (err) {
1847
        goto out;
1848
    }
1849

    
1850
    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1851
                            &vs->v9stat);
1852
    if ((vs->len != (vs->v9stat.size + 2)) ||
1853
            ((vs->count + vs->len) > vs->max_count)) {
1854
        v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1855
        v9fs_read_post_seekdir(s, vs, err);
1856
        return;
1857
    }
1858
    vs->count += vs->len;
1859
    v9fs_stat_free(&vs->v9stat);
1860
    v9fs_string_free(&vs->name);
1861
    vs->dir_pos = vs->dent->d_off;
1862
    v9fs_co_readdir(s, vs->fidp, &vs->dent);
1863
    v9fs_read_post_readdir(s, vs, err);
1864
    return;
1865
out:
1866
    v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1867
    v9fs_read_post_seekdir(s, vs, err);
1868
    return;
1869

    
1870
}
1871

    
1872
static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1873
{
1874
    if (vs->dent) {
1875
        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1876
        v9fs_string_init(&vs->name);
1877
        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1878
                            vs->dent->d_name);
1879
        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1880
        v9fs_read_post_dir_lstat(s, vs, err);
1881
        return;
1882
    }
1883

    
1884
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1885
    vs->offset += vs->count;
1886
    err = vs->offset;
1887
    complete_pdu(s, vs->pdu, err);
1888
    qemu_free(vs);
1889
    return;
1890
}
1891

    
1892
static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1893
{
1894
    v9fs_co_readdir(s, vs->fidp, &vs->dent);
1895
    v9fs_read_post_readdir(s, vs, err);
1896
    return;
1897
}
1898

    
1899
static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1900
                                       ssize_t err)
1901
{
1902
    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1903
    v9fs_read_post_telldir(s, vs, err);
1904
    return;
1905
}
1906

    
1907
static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1908
{
1909
    if (err  < 0) {
1910
        /* IO error return the error */
1911
        err = -errno;
1912
        goto out;
1913
    }
1914
    vs->total += vs->len;
1915
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1916
    if (vs->total < vs->count && vs->len > 0) {
1917
        do {
1918
            if (0) {
1919
                print_sg(vs->sg, vs->cnt);
1920
            }
1921
            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
1922
                      vs->off);
1923
            if (vs->len > 0) {
1924
                vs->off += vs->len;
1925
            }
1926
        } while (vs->len == -1 && errno == EINTR);
1927
        if (vs->len == -1) {
1928
            err  = -errno;
1929
        }
1930
        v9fs_read_post_preadv(s, vs, err);
1931
        return;
1932
    }
1933
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1934
    vs->offset += vs->count;
1935
    err = vs->offset;
1936

    
1937
out:
1938
    complete_pdu(s, vs->pdu, err);
1939
    qemu_free(vs);
1940
}
1941

    
1942
static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
1943
{
1944
    ssize_t err = 0;
1945
    int read_count;
1946
    int64_t xattr_len;
1947

    
1948
    xattr_len = vs->fidp->fs.xattr.len;
1949
    read_count = xattr_len - vs->off;
1950
    if (read_count > vs->count) {
1951
        read_count = vs->count;
1952
    } else if (read_count < 0) {
1953
        /*
1954
         * read beyond XATTR value
1955
         */
1956
        read_count = 0;
1957
    }
1958
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
1959
    vs->offset += pdu_pack(vs->pdu, vs->offset,
1960
                           ((char *)vs->fidp->fs.xattr.value) + vs->off,
1961
                           read_count);
1962
    err = vs->offset;
1963
    complete_pdu(s, vs->pdu, err);
1964
    qemu_free(vs);
1965
}
1966

    
1967
static void v9fs_read(void *opaque)
1968
{
1969
    V9fsPDU *pdu = opaque;
1970
    V9fsState *s = pdu->s;
1971
    int32_t fid;
1972
    V9fsReadState *vs;
1973
    ssize_t err = 0;
1974

    
1975
    vs = qemu_malloc(sizeof(*vs));
1976
    vs->pdu = pdu;
1977
    vs->offset = 7;
1978
    vs->total = 0;
1979
    vs->len = 0;
1980
    vs->count = 0;
1981

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

    
1984
    vs->fidp = lookup_fid(s, fid);
1985
    if (vs->fidp == NULL) {
1986
        err = -EINVAL;
1987
        goto out;
1988
    }
1989

    
1990
    if (vs->fidp->fid_type == P9_FID_DIR) {
1991
        vs->max_count = vs->count;
1992
        vs->count = 0;
1993
        if (vs->off == 0) {
1994
            v9fs_do_rewinddir(s, vs->fidp->fs.dir);
1995
        }
1996
        v9fs_read_post_rewinddir(s, vs, err);
1997
        return;
1998
    } else if (vs->fidp->fid_type == P9_FID_FILE) {
1999
        vs->sg = vs->iov;
2000
        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
2001
        vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2002
        if (vs->total <= vs->count) {
2003
            vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2004
                                    vs->off);
2005
            if (vs->len > 0) {
2006
                vs->off += vs->len;
2007
            }
2008
            err = vs->len;
2009
            v9fs_read_post_preadv(s, vs, err);
2010
        }
2011
        return;
2012
    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2013
        v9fs_xattr_read(s, vs);
2014
        return;
2015
    } else {
2016
        err = -EINVAL;
2017
    }
2018
out:
2019
    complete_pdu(s, pdu, err);
2020
    qemu_free(vs);
2021
}
2022

    
2023
static size_t v9fs_readdir_data_size(V9fsString *name)
2024
{
2025
    /*
2026
     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
2027
     * size of type (1) + size of name.size (2) + strlen(name.data)
2028
     */
2029
    return 24 + v9fs_string_size(name);
2030
}
2031

    
2032
static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
2033
                           V9fsFidState *fidp, int32_t max_count)
2034
{
2035
    size_t size;
2036
    V9fsQID qid;
2037
    V9fsString name;
2038
    int len, err = 0;
2039
    int32_t count = 0;
2040
    off_t saved_dir_pos;
2041
    struct dirent *dent;
2042

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

    
2072
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
2073
        len = pdu_marshal(pdu, 11 + count, "Qqbs",
2074
                          &qid, dent->d_off,
2075
                          dent->d_type, &name);
2076
        count += len;
2077
        v9fs_string_free(&name);
2078
        saved_dir_pos = dent->d_off;
2079
    }
2080
    if (err < 0) {
2081
        return err;
2082
    }
2083
    return count;
2084
}
2085

    
2086
static void v9fs_readdir(void *opaque)
2087
{
2088
    int32_t fid;
2089
    V9fsFidState *fidp;
2090
    ssize_t retval = 0;
2091
    size_t offset = 7;
2092
    int64_t initial_offset;
2093
    int32_t count, max_count;
2094
    V9fsPDU *pdu = opaque;
2095
    V9fsState *s = pdu->s;
2096

    
2097
    pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
2098

    
2099
    fidp = lookup_fid(s, fid);
2100
    if (fidp == NULL || !fidp->fs.dir) {
2101
        retval = -EINVAL;
2102
        goto out;
2103
    }
2104
    if (initial_offset == 0) {
2105
        v9fs_co_rewinddir(s, fidp);
2106
    } else {
2107
        v9fs_co_seekdir(s, fidp, initial_offset);
2108
    }
2109
    count = v9fs_do_readdir(s, pdu, fidp, max_count);
2110
    if (count < 0) {
2111
        retval = count;
2112
        goto out;
2113
    }
2114
    retval = offset;
2115
    retval += pdu_marshal(pdu, offset, "d", count);
2116
    retval += count;
2117
out:
2118
    complete_pdu(s, pdu, retval);
2119
}
2120

    
2121
static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
2122
                                   ssize_t err)
2123
{
2124
    if (err  < 0) {
2125
        /* IO error return the error */
2126
        err = -errno;
2127
        goto out;
2128
    }
2129
    vs->total += vs->len;
2130
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
2131
    if (vs->total < vs->count && vs->len > 0) {
2132
        do {
2133
            if (0) {
2134
                print_sg(vs->sg, vs->cnt);
2135
            }
2136
            vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
2137
                      vs->off);
2138
            if (vs->len > 0) {
2139
                vs->off += vs->len;
2140
            }
2141
        } while (vs->len == -1 && errno == EINTR);
2142
        if (vs->len == -1) {
2143
            err  = -errno;
2144
        }
2145
        v9fs_write_post_pwritev(s, vs, err);
2146
        return;
2147
    }
2148
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
2149
    err = vs->offset;
2150
out:
2151
    complete_pdu(s, vs->pdu, err);
2152
    qemu_free(vs);
2153
}
2154

    
2155
static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
2156
{
2157
    int i, to_copy;
2158
    ssize_t err = 0;
2159
    int write_count;
2160
    int64_t xattr_len;
2161

    
2162
    xattr_len = vs->fidp->fs.xattr.len;
2163
    write_count = xattr_len - vs->off;
2164
    if (write_count > vs->count) {
2165
        write_count = vs->count;
2166
    } else if (write_count < 0) {
2167
        /*
2168
         * write beyond XATTR value len specified in
2169
         * xattrcreate
2170
         */
2171
        err = -ENOSPC;
2172
        goto out;
2173
    }
2174
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
2175
    err = vs->offset;
2176
    vs->fidp->fs.xattr.copied_len += write_count;
2177
    /*
2178
     * Now copy the content from sg list
2179
     */
2180
    for (i = 0; i < vs->cnt; i++) {
2181
        if (write_count > vs->sg[i].iov_len) {
2182
            to_copy = vs->sg[i].iov_len;
2183
        } else {
2184
            to_copy = write_count;
2185
        }
2186
        memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
2187
               vs->sg[i].iov_base, to_copy);
2188
        /* updating vs->off since we are not using below */
2189
        vs->off += to_copy;
2190
        write_count -= to_copy;
2191
    }
2192
out:
2193
    complete_pdu(s, vs->pdu, err);
2194
    qemu_free(vs);
2195
}
2196

    
2197
static void v9fs_write(void *opaque)
2198
{
2199
    V9fsPDU *pdu = opaque;
2200
    V9fsState *s = pdu->s;
2201
    int32_t fid;
2202
    V9fsWriteState *vs;
2203
    ssize_t err;
2204

    
2205
    vs = qemu_malloc(sizeof(*vs));
2206

    
2207
    vs->pdu = pdu;
2208
    vs->offset = 7;
2209
    vs->sg = vs->iov;
2210
    vs->total = 0;
2211
    vs->len = 0;
2212

    
2213
    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
2214
                  vs->sg, &vs->cnt);
2215

    
2216
    vs->fidp = lookup_fid(s, fid);
2217
    if (vs->fidp == NULL) {
2218
        err = -EINVAL;
2219
        goto out;
2220
    }
2221

    
2222
    if (vs->fidp->fid_type == P9_FID_FILE) {
2223
        if (vs->fidp->fs.fd == -1) {
2224
            err = -EINVAL;
2225
            goto out;
2226
        }
2227
    } else if (vs->fidp->fid_type == P9_FID_XATTR) {
2228
        /*
2229
         * setxattr operation
2230
         */
2231
        v9fs_xattr_write(s, vs);
2232
        return;
2233
    } else {
2234
        err = -EINVAL;
2235
        goto out;
2236
    }
2237
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
2238
    if (vs->total <= vs->count) {
2239
        vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
2240
        if (vs->len > 0) {
2241
            vs->off += vs->len;
2242
        }
2243
        err = vs->len;
2244
        v9fs_write_post_pwritev(s, vs, err);
2245
    }
2246
    return;
2247
out:
2248
    complete_pdu(s, vs->pdu, err);
2249
    qemu_free(vs);
2250
}
2251

    
2252
static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
2253
{
2254
    int err;
2255
    v9fs_string_copy(&vs->fidp->path, &vs->fullname);
2256
    stat_to_qid(&vs->stbuf, &vs->qid);
2257

    
2258
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
2259
    err = vs->offset;
2260

    
2261
    complete_pdu(s, vs->pdu, err);
2262
    v9fs_string_free(&vs->name);
2263
    v9fs_string_free(&vs->extension);
2264
    v9fs_string_free(&vs->fullname);
2265
    qemu_free(vs);
2266
}
2267

    
2268
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
2269
{
2270
    if (err == 0) {
2271
        vs->iounit = get_iounit(s, &vs->fidp->path);
2272
        v9fs_create_post_getiounit(s, vs);
2273
        return;
2274
    }
2275

    
2276
    complete_pdu(s, vs->pdu, err);
2277
    v9fs_string_free(&vs->name);
2278
    v9fs_string_free(&vs->extension);
2279
    v9fs_string_free(&vs->fullname);
2280
    qemu_free(vs);
2281
}
2282

    
2283
static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
2284
{
2285
    if (err) {
2286
        err = -errno;
2287
    }
2288
    v9fs_post_create(s, vs, err);
2289
}
2290

    
2291
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
2292
                                                                    int err)
2293
{
2294
    if (!vs->fidp->fs.dir) {
2295
        err = -errno;
2296
    }
2297
    vs->fidp->fid_type = P9_FID_DIR;
2298
    v9fs_post_create(s, vs, err);
2299
}
2300

    
2301
static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
2302
                                                                    int err)
2303
{
2304
    if (err) {
2305
        err = -errno;
2306
        goto out;
2307
    }
2308

    
2309
    vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
2310
    v9fs_create_post_opendir(s, vs, err);
2311
    return;
2312

    
2313
out:
2314
    v9fs_post_create(s, vs, err);
2315
}
2316

    
2317
static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
2318
{
2319
    if (err < 0) {
2320
        goto out;
2321
    }
2322

    
2323
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2324
    v9fs_create_post_dir_lstat(s, vs, err);
2325
    return;
2326

    
2327
out:
2328
    v9fs_post_create(s, vs, err);
2329
}
2330

    
2331
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
2332
{
2333
    if (err) {
2334
        vs->fidp->fid_type = P9_FID_NONE;
2335
        close(vs->fidp->fs.fd);
2336
        err = -errno;
2337
    }
2338
    v9fs_post_create(s, vs, err);
2339
    return;
2340
}
2341

    
2342
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
2343
{
2344
    if (vs->fidp->fs.fd == -1) {
2345
        err = -errno;
2346
        goto out;
2347
    }
2348
    vs->fidp->fid_type = P9_FID_FILE;
2349
    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
2350
    v9fs_create_post_fstat(s, vs, err);
2351

    
2352
    return;
2353

    
2354
out:
2355
    v9fs_post_create(s, vs, err);
2356

    
2357
}
2358

    
2359
static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
2360
{
2361

    
2362
    if (err == 0 || errno != ENOENT) {
2363
        err = -errno;
2364
        goto out;
2365
    }
2366

    
2367
    if (vs->perm & P9_STAT_MODE_DIR) {
2368
        err = v9fs_co_mkdir(s, vs->fullname.data, vs->perm & 0777,
2369
                vs->fidp->uid, -1);
2370
        v9fs_create_post_mkdir(s, vs, err);
2371
    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
2372
        err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
2373
                vs->fullname.data, -1);
2374
        v9fs_create_post_perms(s, vs, err);
2375
    } else if (vs->perm & P9_STAT_MODE_LINK) {
2376
        int32_t nfid = atoi(vs->extension.data);
2377
        V9fsFidState *nfidp = lookup_fid(s, nfid);
2378
        if (nfidp == NULL) {
2379
            err = -errno;
2380
            v9fs_post_create(s, vs, err);
2381
        }
2382
        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
2383
        v9fs_create_post_perms(s, vs, err);
2384
    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
2385
        char ctype;
2386
        uint32_t major, minor;
2387
        mode_t nmode = 0;
2388

    
2389
        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
2390
                                        &minor) != 3) {
2391
            err = -errno;
2392
            v9fs_post_create(s, vs, err);
2393
        }
2394

    
2395
        switch (ctype) {
2396
        case 'c':
2397
            nmode = S_IFCHR;
2398
            break;
2399
        case 'b':
2400
            nmode = S_IFBLK;
2401
            break;
2402
        default:
2403
            err = -EIO;
2404
            v9fs_post_create(s, vs, err);
2405
        }
2406

    
2407
        nmode |= vs->perm & 0777;
2408
        err = v9fs_do_mknod(s, vs->fullname.data, nmode,
2409
                makedev(major, minor), vs->fidp->uid, -1);
2410
        v9fs_create_post_perms(s, vs, err);
2411
    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
2412
        err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
2413
                0, vs->fidp->uid, -1);
2414
        v9fs_post_create(s, vs, err);
2415
    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
2416
        err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
2417
                0, vs->fidp->uid, -1);
2418
        v9fs_post_create(s, vs, err);
2419
    } else {
2420
        vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
2421
                -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
2422

    
2423
        v9fs_create_post_open2(s, vs, err);
2424
    }
2425

    
2426
    return;
2427

    
2428
out:
2429
    v9fs_post_create(s, vs, err);
2430
}
2431

    
2432
static void v9fs_create(void *opaque)
2433
{
2434
    V9fsPDU *pdu = opaque;
2435
    V9fsState *s = pdu->s;
2436
    int32_t fid;
2437
    V9fsCreateState *vs;
2438
    int err = 0;
2439

    
2440
    vs = qemu_malloc(sizeof(*vs));
2441
    vs->pdu = pdu;
2442
    vs->offset = 7;
2443

    
2444
    v9fs_string_init(&vs->fullname);
2445

    
2446
    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
2447
                                &vs->perm, &vs->mode, &vs->extension);
2448

    
2449
    vs->fidp = lookup_fid(s, fid);
2450
    if (vs->fidp == NULL) {
2451
        err = -EINVAL;
2452
        goto out;
2453
    }
2454

    
2455
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
2456
                                                        vs->name.data);
2457

    
2458
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2459
    v9fs_create_post_lstat(s, vs, err);
2460
    return;
2461

    
2462
out:
2463
    complete_pdu(s, vs->pdu, err);
2464
    v9fs_string_free(&vs->name);
2465
    v9fs_string_free(&vs->extension);
2466
    qemu_free(vs);
2467
}
2468

    
2469
static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
2470
{
2471
    if (err == 0) {
2472
        stat_to_qid(&vs->stbuf, &vs->qid);
2473
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
2474
        err = vs->offset;
2475
    } else {
2476
        err = -errno;
2477
    }
2478
    complete_pdu(s, vs->pdu, err);
2479
    v9fs_string_free(&vs->name);
2480
    v9fs_string_free(&vs->symname);
2481
    v9fs_string_free(&vs->fullname);
2482
    qemu_free(vs);
2483
}
2484

    
2485
static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
2486
        int err)
2487
{
2488
    if (err) {
2489
        goto out;
2490
    }
2491
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
2492
out:
2493
    v9fs_post_symlink(s, vs, err);
2494
}
2495

    
2496
static void v9fs_symlink(void *opaque)
2497
{
2498
    V9fsPDU *pdu = opaque;
2499
    V9fsState *s = pdu->s;
2500
    int32_t dfid;
2501
    V9fsSymlinkState *vs;
2502
    int err = 0;
2503
    gid_t gid;
2504

    
2505
    vs = qemu_malloc(sizeof(*vs));
2506
    vs->pdu = pdu;
2507
    vs->offset = 7;
2508

    
2509
    v9fs_string_init(&vs->fullname);
2510

    
2511
    pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
2512
            &vs->symname, &gid);
2513

    
2514
    vs->dfidp = lookup_fid(s, dfid);
2515
    if (vs->dfidp == NULL) {
2516
        err = -EINVAL;
2517
        goto out;
2518
    }
2519

    
2520
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
2521
            vs->name.data);
2522
    err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
2523
            vs->fullname.data, gid);
2524
    v9fs_symlink_post_do_symlink(s, vs, err);
2525
    return;
2526

    
2527
out:
2528
    complete_pdu(s, vs->pdu, err);
2529
    v9fs_string_free(&vs->name);
2530
    v9fs_string_free(&vs->symname);
2531
    qemu_free(vs);
2532
}
2533

    
2534
static void v9fs_flush(void *opaque)
2535
{
2536
    V9fsPDU *pdu = opaque;
2537
    V9fsState *s = pdu->s;
2538
    /* A nop call with no return */
2539
    complete_pdu(s, pdu, 7);
2540
    return;
2541
}
2542

    
2543
static void v9fs_link(void *opaque)
2544
{
2545
    V9fsPDU *pdu = opaque;
2546
    V9fsState *s = pdu->s;
2547
    int32_t dfid, oldfid;
2548
    V9fsFidState *dfidp, *oldfidp;
2549
    V9fsString name, fullname;
2550
    size_t offset = 7;
2551
    int err = 0;
2552

    
2553
    v9fs_string_init(&fullname);
2554

    
2555
    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2556

    
2557
    dfidp = lookup_fid(s, dfid);
2558
    if (dfidp == NULL) {
2559
        err = -errno;
2560
        goto out;
2561
    }
2562

    
2563
    oldfidp = lookup_fid(s, oldfid);
2564
    if (oldfidp == NULL) {
2565
        err = -errno;
2566
        goto out;
2567
    }
2568

    
2569
    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2570
    err = offset;
2571
    err = v9fs_do_link(s, &oldfidp->path, &fullname);
2572
    if (err) {
2573
        err = -errno;
2574
    }
2575
    v9fs_string_free(&fullname);
2576

    
2577
out:
2578
    v9fs_string_free(&name);
2579
    complete_pdu(s, pdu, err);
2580
}
2581

    
2582
static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
2583
                                                                int err)
2584
{
2585
    if (err < 0) {
2586
        err = -errno;
2587
    } else {
2588
        err = vs->offset;
2589
    }
2590

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

    
2594
    complete_pdu(s, vs->pdu, err);
2595
    qemu_free(vs);
2596
}
2597

    
2598
static void v9fs_remove(void *opaque)
2599
{
2600
    V9fsPDU *pdu = opaque;
2601
    V9fsState *s = pdu->s;
2602
    int32_t fid;
2603
    V9fsRemoveState *vs;
2604
    int err = 0;
2605

    
2606
    vs = qemu_malloc(sizeof(*vs));
2607
    vs->pdu = pdu;
2608
    vs->offset = 7;
2609

    
2610
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
2611

    
2612
    vs->fidp = lookup_fid(s, fid);
2613
    if (vs->fidp == NULL) {
2614
        err = -EINVAL;
2615
        goto out;
2616
    }
2617

    
2618
    err = v9fs_do_remove(s, &vs->fidp->path);
2619
    v9fs_remove_post_remove(s, vs, err);
2620
    return;
2621

    
2622
out:
2623
    complete_pdu(s, pdu, err);
2624
    qemu_free(vs);
2625
}
2626

    
2627
static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
2628
{
2629
    if (err < 0) {
2630
        goto out;
2631
    }
2632

    
2633
    err = vs->offset;
2634

    
2635
out:
2636
    v9fs_stat_free(&vs->v9stat);
2637
    complete_pdu(s, vs->pdu, err);
2638
    qemu_free(vs);
2639
}
2640

    
2641
static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
2642
{
2643
    if (err < 0) {
2644
        goto out;
2645
    }
2646
    if (vs->v9stat.length != -1) {
2647
        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
2648
            err = -errno;
2649
        }
2650
    }
2651
    v9fs_wstat_post_truncate(s, vs, err);
2652
    return;
2653

    
2654
out:
2655
    v9fs_stat_free(&vs->v9stat);
2656
    complete_pdu(s, vs->pdu, err);
2657
    qemu_free(vs);
2658
}
2659

    
2660
static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
2661
{
2662
    int err = 0;
2663
    char *old_name, *new_name;
2664
    char *end;
2665

    
2666
    if (vs->newdirfid != -1) {
2667
        V9fsFidState *dirfidp;
2668
        dirfidp = lookup_fid(s, vs->newdirfid);
2669

    
2670
        if (dirfidp == NULL) {
2671
            err = -ENOENT;
2672
            goto out;
2673
        }
2674

    
2675
        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2676

    
2677
        new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
2678

    
2679
        strcpy(new_name, dirfidp->path.data);
2680
        strcat(new_name, "/");
2681
        strcat(new_name + dirfidp->path.size, vs->name.data);
2682
    } else {
2683
        old_name = vs->fidp->path.data;
2684
        end = strrchr(old_name, '/');
2685
        if (end) {
2686
            end++;
2687
        } else {
2688
            end = old_name;
2689
        }
2690
        new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
2691

    
2692
        strncat(new_name, old_name, end - old_name);
2693
        strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
2694
    }
2695

    
2696
    v9fs_string_free(&vs->name);
2697
    vs->name.data = qemu_strdup(new_name);
2698
    vs->name.size = strlen(new_name);
2699

    
2700
    if (strcmp(new_name, vs->fidp->path.data) != 0) {
2701
        if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
2702
            err = -errno;
2703
        } else {
2704
            V9fsFidState *fidp;
2705
            /*
2706
            * Fixup fid's pointing to the old name to
2707
            * start pointing to the new name
2708
            */
2709
            for (fidp = s->fid_list; fidp; fidp = fidp->next) {
2710
                if (vs->fidp == fidp) {
2711
                    /*
2712
                    * we replace name of this fid towards the end so
2713
                    * that our below v9fs_path_is_ancestor check will
2714
                    * work
2715
                    */
2716
                    continue;
2717
                }
2718
                if (v9fs_path_is_ancestor(&vs->fidp->path, &fidp->path)) {
2719
                    /* replace the name */
2720
                    v9fs_fix_path(&fidp->path, &vs->name,
2721
                                  strlen(vs->fidp->path.data));
2722
                }
2723
            }
2724
            v9fs_string_copy(&vs->fidp->path, &vs->name);
2725
        }
2726
    }
2727
out:
2728
    v9fs_string_free(&vs->name);
2729
    return err;
2730
}
2731

    
2732
static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
2733
{
2734
    complete_pdu(s, vs->pdu, err);
2735
    qemu_free(vs);
2736
}
2737

    
2738
static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
2739
{
2740
    if (err < 0) {
2741
        goto out;
2742
    }
2743

    
2744
    if (vs->v9stat.name.size != 0) {
2745
        V9fsRenameState *vr;
2746

    
2747
        vr = qemu_mallocz(sizeof(V9fsRenameState));
2748
        vr->newdirfid = -1;
2749
        vr->pdu = vs->pdu;
2750
        vr->fidp = vs->fidp;
2751
        vr->offset = vs->offset;
2752
        vr->name.size = vs->v9stat.name.size;
2753
        vr->name.data = qemu_strdup(vs->v9stat.name.data);
2754

    
2755
        err = v9fs_complete_rename(s, vr);
2756
        qemu_free(vr);
2757
    }
2758
    v9fs_wstat_post_rename(s, vs, err);
2759
    return;
2760

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

    
2767
static void v9fs_rename(void *opaque)
2768
{
2769
    V9fsPDU *pdu = opaque;
2770
    V9fsState *s = pdu->s;
2771
    int32_t fid;
2772
    V9fsRenameState *vs;
2773
    ssize_t err = 0;
2774

    
2775
    vs = qemu_malloc(sizeof(*vs));
2776
    vs->pdu = pdu;
2777
    vs->offset = 7;
2778

    
2779
    pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
2780

    
2781
    vs->fidp = lookup_fid(s, fid);
2782
    if (vs->fidp == NULL) {
2783
        err = -ENOENT;
2784
        goto out;
2785
    }
2786

    
2787
    BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
2788

    
2789
    err = v9fs_complete_rename(s, vs);
2790
    v9fs_rename_post_rename(s, vs, err);
2791
    return;
2792
out:
2793
    complete_pdu(s, vs->pdu, err);
2794
    qemu_free(vs);
2795
}
2796

    
2797
static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2798
{
2799
    if (err < 0) {
2800
        goto out;
2801
    }
2802

    
2803
    if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
2804
        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2805
                    vs->v9stat.n_gid)) {
2806
            err = -errno;
2807
        }
2808
    }
2809
    v9fs_wstat_post_chown(s, vs, err);
2810
    return;
2811

    
2812
out:
2813
    v9fs_stat_free(&vs->v9stat);
2814
    complete_pdu(s, vs->pdu, err);
2815
    qemu_free(vs);
2816
}
2817

    
2818
static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2819
{
2820
    if (err < 0) {
2821
        goto out;
2822
    }
2823

    
2824
    if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
2825
        struct timespec times[2];
2826
        if (vs->v9stat.atime != -1) {
2827
            times[0].tv_sec = vs->v9stat.atime;
2828
            times[0].tv_nsec = 0;
2829
        } else {
2830
            times[0].tv_nsec = UTIME_OMIT;
2831
        }
2832
        if (vs->v9stat.mtime != -1) {
2833
            times[1].tv_sec = vs->v9stat.mtime;
2834
            times[1].tv_nsec = 0;
2835
        } else {
2836
            times[1].tv_nsec = UTIME_OMIT;
2837
        }
2838

    
2839
        if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
2840
            err = -errno;
2841
        }
2842
    }
2843

    
2844
    v9fs_wstat_post_utime(s, vs, err);
2845
    return;
2846

    
2847
out:
2848
    v9fs_stat_free(&vs->v9stat);
2849
    complete_pdu(s, vs->pdu, err);
2850
    qemu_free(vs);
2851
}
2852

    
2853
static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2854
{
2855
    if (err == -1) {
2856
        err = -errno;
2857
    }
2858
    v9fs_stat_free(&vs->v9stat);
2859
    complete_pdu(s, vs->pdu, err);
2860
    qemu_free(vs);
2861
}
2862

    
2863
static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2864
{
2865
    uint32_t v9_mode;
2866

    
2867
    if (err == -1) {
2868
        err = -errno;
2869
        goto out;
2870
    }
2871

    
2872
    v9_mode = stat_to_v9mode(&vs->stbuf);
2873

    
2874
    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2875
        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2876
            /* Attempting to change the type */
2877
            err = -EIO;
2878
            goto out;
2879
    }
2880

    
2881
    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2882
                    &vs->v9stat.extension))) {
2883
            err = -errno;
2884
     }
2885
    v9fs_wstat_post_chmod(s, vs, err);
2886
    return;
2887

    
2888
out:
2889
    v9fs_stat_free(&vs->v9stat);
2890
    complete_pdu(s, vs->pdu, err);
2891
    qemu_free(vs);
2892
}
2893

    
2894
static void v9fs_wstat(void *opaque)
2895
{
2896
    V9fsPDU *pdu = opaque;
2897
    V9fsState *s = pdu->s;
2898
    int32_t fid;
2899
    V9fsWstatState *vs;
2900
    int err = 0;
2901

    
2902
    vs = qemu_malloc(sizeof(*vs));
2903
    vs->pdu = pdu;
2904
    vs->offset = 7;
2905

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

    
2908
    vs->fidp = lookup_fid(s, fid);
2909
    if (vs->fidp == NULL) {
2910
        err = -EINVAL;
2911
        goto out;
2912
    }
2913

    
2914
    /* do we need to sync the file? */
2915
    if (donttouch_stat(&vs->v9stat)) {
2916
        err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
2917
        v9fs_wstat_post_fsync(s, vs, err);
2918
        return;
2919
    }
2920

    
2921
    if (vs->v9stat.mode != -1) {
2922
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2923
        v9fs_wstat_post_lstat(s, vs, err);
2924
        return;
2925
    }
2926

    
2927
    v9fs_wstat_post_chmod(s, vs, err);
2928
    return;
2929

    
2930
out:
2931
    v9fs_stat_free(&vs->v9stat);
2932
    complete_pdu(s, vs->pdu, err);
2933
    qemu_free(vs);
2934
}
2935

    
2936
static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2937
{
2938
    uint32_t f_type;
2939
    uint32_t f_bsize;
2940
    uint64_t f_blocks;
2941
    uint64_t f_bfree;
2942
    uint64_t f_bavail;
2943
    uint64_t f_files;
2944
    uint64_t f_ffree;
2945
    uint64_t fsid_val;
2946
    uint32_t f_namelen;
2947
    size_t offset = 7;
2948
    int32_t bsize_factor;
2949

    
2950
    /*
2951
     * compute bsize factor based on host file system block size
2952
     * and client msize
2953
     */
2954
    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2955
    if (!bsize_factor) {
2956
        bsize_factor = 1;
2957
    }
2958
    f_type  = stbuf->f_type;
2959
    f_bsize = stbuf->f_bsize;
2960
    f_bsize *= bsize_factor;
2961
    /*
2962
     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2963
     * adjust(divide) the number of blocks, free blocks and available
2964
     * blocks by bsize factor
2965
     */
2966
    f_blocks = stbuf->f_blocks/bsize_factor;
2967
    f_bfree  = stbuf->f_bfree/bsize_factor;
2968
    f_bavail = stbuf->f_bavail/bsize_factor;
2969
    f_files  = stbuf->f_files;
2970
    f_ffree  = stbuf->f_ffree;
2971
    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2972
               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2973
    f_namelen = stbuf->f_namelen;
2974

    
2975
    return pdu_marshal(pdu, offset, "ddqqqqqqd",
2976
                       f_type, f_bsize, f_blocks, f_bfree,
2977
                       f_bavail, f_files, f_ffree,
2978
                       fsid_val, f_namelen);
2979
}
2980

    
2981
static void v9fs_statfs(void *opaque)
2982
{
2983
    int32_t fid;
2984
    ssize_t retval = 0;
2985
    size_t offset = 7;
2986
    V9fsFidState *fidp;
2987
    struct statfs stbuf;
2988
    V9fsPDU *pdu = opaque;
2989
    V9fsState *s = pdu->s;
2990

    
2991
    pdu_unmarshal(pdu, offset, "d", &fid);
2992
    fidp = lookup_fid(s, fid);
2993
    if (fidp == NULL) {
2994
        retval = -ENOENT;
2995
        goto out;
2996
    }
2997
    retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2998
    if (retval < 0) {
2999
        goto out;
3000
    }
3001
    retval = offset;
3002
    retval += v9fs_fill_statfs(s, pdu, &stbuf);
3003
out:
3004
    complete_pdu(s, pdu, retval);
3005
    return;
3006
}
3007

    
3008
static void v9fs_mknod(void *opaque)
3009
{
3010

    
3011
    int mode;
3012
    gid_t gid;
3013
    int32_t fid;
3014
    V9fsQID qid;
3015
    int err = 0;
3016
    int major, minor;
3017
    size_t offset = 7;
3018
    V9fsString name;
3019
    struct stat stbuf;
3020
    V9fsString fullname;
3021
    V9fsFidState *fidp;
3022
    V9fsPDU *pdu = opaque;
3023
    V9fsState *s = pdu->s;
3024

    
3025
    v9fs_string_init(&fullname);
3026
    pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
3027
                  &major, &minor, &gid);
3028

    
3029
    fidp = lookup_fid(s, fid);
3030
    if (fidp == NULL) {
3031
        err = -ENOENT;
3032
        goto out;
3033
    }
3034
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
3035
    err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
3036
                        makedev(major, minor), mode);
3037
    if (err < 0) {
3038
        goto out;
3039
    }
3040
    err = v9fs_co_lstat(s, &fullname, &stbuf);
3041
    if (err < 0) {
3042
        goto out;
3043
    }
3044
    stat_to_qid(&stbuf, &qid);
3045
    err = offset;
3046
    err += pdu_marshal(pdu, offset, "Q", &qid);
3047
out:
3048
    complete_pdu(s, pdu, err);
3049
    v9fs_string_free(&fullname);
3050
    v9fs_string_free(&name);
3051
}
3052

    
3053
/*
3054
 * Implement posix byte range locking code
3055
 * Server side handling of locking code is very simple, because 9p server in
3056
 * QEMU can handle only one client. And most of the lock handling
3057
 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
3058
 * do any thing in * qemu 9p server side lock code path.
3059
 * So when a TLOCK request comes, always return success
3060
 */
3061

    
3062
static void v9fs_lock(void *opaque)
3063
{
3064
    V9fsPDU *pdu = opaque;
3065
    V9fsState *s = pdu->s;
3066
    int32_t fid, err = 0;
3067
    V9fsLockState *vs;
3068

    
3069
    vs = qemu_mallocz(sizeof(*vs));
3070
    vs->pdu = pdu;
3071
    vs->offset = 7;
3072

    
3073
    vs->flock = qemu_malloc(sizeof(*vs->flock));
3074
    pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
3075
                &vs->flock->flags, &vs->flock->start, &vs->flock->length,
3076
                            &vs->flock->proc_id, &vs->flock->client_id);
3077

    
3078
    vs->status = P9_LOCK_ERROR;
3079

    
3080
    /* We support only block flag now (that too ignored currently) */
3081
    if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
3082
        err = -EINVAL;
3083
        goto out;
3084
    }
3085
    vs->fidp = lookup_fid(s, fid);
3086
    if (vs->fidp == NULL) {
3087
        err = -ENOENT;
3088
        goto out;
3089
    }
3090

    
3091
    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3092
    if (err < 0) {
3093
        err = -errno;
3094
        goto out;
3095
    }
3096
    vs->status = P9_LOCK_SUCCESS;
3097
out:
3098
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
3099
    complete_pdu(s, vs->pdu, err);
3100
    qemu_free(vs->flock);
3101
    qemu_free(vs);
3102
}
3103

    
3104
/*
3105
 * When a TGETLOCK request comes, always return success because all lock
3106
 * handling is done by client's VFS layer.
3107
 */
3108

    
3109
static void v9fs_getlock(void *opaque)
3110
{
3111
    V9fsPDU *pdu = opaque;
3112
    V9fsState *s = pdu->s;
3113
    int32_t fid, err = 0;
3114
    V9fsGetlockState *vs;
3115

    
3116
    vs = qemu_mallocz(sizeof(*vs));
3117
    vs->pdu = pdu;
3118
    vs->offset = 7;
3119

    
3120
    vs->glock = qemu_malloc(sizeof(*vs->glock));
3121
    pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
3122
                &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
3123
                &vs->glock->client_id);
3124

    
3125
    vs->fidp = lookup_fid(s, fid);
3126
    if (vs->fidp == NULL) {
3127
        err = -ENOENT;
3128
        goto out;
3129
    }
3130

    
3131
    err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
3132
    if (err < 0) {
3133
        err = -errno;
3134
        goto out;
3135
    }
3136
    vs->glock->type = F_UNLCK;
3137
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
3138
                vs->glock->start, vs->glock->length, vs->glock->proc_id,
3139
                &vs->glock->client_id);
3140
out:
3141
    complete_pdu(s, vs->pdu, err);
3142
    qemu_free(vs->glock);
3143
    qemu_free(vs);
3144
}
3145

    
3146
static void v9fs_mkdir(void *opaque)
3147
{
3148
    V9fsPDU *pdu = opaque;
3149
    size_t offset = 7;
3150
    int32_t fid;
3151
    struct stat stbuf;
3152
    V9fsString name, fullname;
3153
    V9fsQID qid;
3154
    V9fsFidState *fidp;
3155
    gid_t gid;
3156
    int mode;
3157
    int err = 0;
3158

    
3159
    v9fs_string_init(&fullname);
3160
    pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
3161

    
3162
    fidp = lookup_fid(pdu->s, fid);
3163
    if (fidp == NULL) {
3164
        err = -ENOENT;
3165
        goto out;
3166
    }
3167
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
3168
    err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
3169
    if (err < 0) {
3170
        goto out;
3171
    }
3172
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
3173
    if (err < 0) {
3174
        goto out;
3175
    }
3176
    stat_to_qid(&stbuf, &qid);
3177
    offset += pdu_marshal(pdu, offset, "Q", &qid);
3178
    err = offset;
3179
out:
3180
    complete_pdu(pdu->s, pdu, err);
3181
    v9fs_string_free(&fullname);
3182
    v9fs_string_free(&name);
3183
}
3184

    
3185
static void v9fs_xattrwalk(void *opaque)
3186
{
3187
    int64_t size;
3188
    V9fsString name;
3189
    ssize_t err = 0;
3190
    size_t offset = 7;
3191
    int32_t fid, newfid;
3192
    V9fsFidState *file_fidp;
3193
    V9fsFidState *xattr_fidp;
3194
    V9fsPDU *pdu = opaque;
3195
    V9fsState *s = pdu->s;
3196

    
3197
    pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3198
    file_fidp = lookup_fid(s, fid);
3199
    if (file_fidp == NULL) {
3200
        err = -ENOENT;
3201
        goto out;
3202
    }
3203
    xattr_fidp = alloc_fid(s, newfid);
3204
    if (xattr_fidp == NULL) {
3205
        err = -EINVAL;
3206
        goto out;
3207
    }
3208
    v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
3209
    if (name.data[0] == 0) {
3210
        /*
3211
         * listxattr request. Get the size first
3212
         */
3213
        size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
3214
        if (size < 0) {
3215
            err = size;
3216
            free_fid(s, xattr_fidp->fid);
3217
            goto out;
3218
        }
3219
        /*
3220
         * Read the xattr value
3221
         */
3222
        xattr_fidp->fs.xattr.len = size;
3223
        xattr_fidp->fid_type = P9_FID_XATTR;
3224
        xattr_fidp->fs.xattr.copied_len = -1;
3225
        if (size) {
3226
            xattr_fidp->fs.xattr.value = qemu_malloc(size);
3227
            err = v9fs_co_llistxattr(s, &xattr_fidp->path,
3228
                                     xattr_fidp->fs.xattr.value,
3229
                                     xattr_fidp->fs.xattr.len);
3230
            if (err < 0) {
3231
                free_fid(s, xattr_fidp->fid);
3232
                goto out;
3233
            }
3234
        }
3235
        offset += pdu_marshal(pdu, offset, "q", size);
3236
        err = offset;
3237
    } else {
3238
        /*
3239
         * specific xattr fid. We check for xattr
3240
         * presence also collect the xattr size
3241
         */
3242
        size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3243
                                 &name, NULL, 0);
3244
        if (size < 0) {
3245
            err = size;
3246
            free_fid(s, xattr_fidp->fid);
3247
            goto out;
3248
        }
3249
        /*
3250
         * Read the xattr value
3251
         */
3252
        xattr_fidp->fs.xattr.len = size;
3253
        xattr_fidp->fid_type = P9_FID_XATTR;
3254
        xattr_fidp->fs.xattr.copied_len = -1;
3255
        if (size) {
3256
            xattr_fidp->fs.xattr.value = qemu_malloc(size);
3257
            err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
3258
                                    &name, xattr_fidp->fs.xattr.value,
3259
                                    xattr_fidp->fs.xattr.len);
3260
            if (err < 0) {
3261
                free_fid(s, xattr_fidp->fid);
3262
                goto out;
3263
            }
3264
        }
3265
        offset += pdu_marshal(pdu, offset, "q", size);
3266
        err = offset;
3267
    }
3268
out:
3269
    complete_pdu(s, pdu, err);
3270
    v9fs_string_free(&name);
3271
}
3272

    
3273
static void v9fs_xattrcreate(void *opaque)
3274
{
3275
    int flags;
3276
    int32_t fid;
3277
    int64_t size;
3278
    ssize_t err = 0;
3279
    V9fsString name;
3280
    size_t offset = 7;
3281
    V9fsFidState *file_fidp;
3282
    V9fsFidState *xattr_fidp;
3283
    V9fsPDU *pdu = opaque;
3284
    V9fsState *s = pdu->s;
3285

    
3286
    pdu_unmarshal(pdu, offset, "dsqd",
3287
                  &fid, &name, &size, &flags);
3288

    
3289
    file_fidp = lookup_fid(s, fid);
3290
    if (file_fidp == NULL) {
3291
        err = -EINVAL;
3292
        goto out;
3293
    }
3294
    /* Make the file fid point to xattr */
3295
    xattr_fidp = file_fidp;
3296
    xattr_fidp->fid_type = P9_FID_XATTR;
3297
    xattr_fidp->fs.xattr.copied_len = 0;
3298
    xattr_fidp->fs.xattr.len = size;
3299
    xattr_fidp->fs.xattr.flags = flags;
3300
    v9fs_string_init(&xattr_fidp->fs.xattr.name);
3301
    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3302
    if (size) {
3303
        xattr_fidp->fs.xattr.value = qemu_malloc(size);
3304
    } else {
3305
        xattr_fidp->fs.xattr.value = NULL;
3306
    }
3307
    err = offset;
3308
out:
3309
    complete_pdu(s, pdu, err);
3310
    v9fs_string_free(&name);
3311
}
3312

    
3313
static void v9fs_readlink(void *opaque)
3314
{
3315
    V9fsPDU *pdu = opaque;
3316
    size_t offset = 7;
3317
    V9fsString target;
3318
    int32_t fid;
3319
    int err = 0;
3320
    V9fsFidState *fidp;
3321

    
3322
    pdu_unmarshal(pdu, offset, "d", &fid);
3323
    fidp = lookup_fid(pdu->s, fid);
3324
    if (fidp == NULL) {
3325
        err = -ENOENT;
3326
        goto out;
3327
    }
3328

    
3329
    v9fs_string_init(&target);
3330
    err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
3331
    if (err < 0) {
3332
        goto out;
3333
    }
3334
    offset += pdu_marshal(pdu, offset, "s", &target);
3335
    err = offset;
3336
    v9fs_string_free(&target);
3337
out:
3338
    complete_pdu(pdu->s, pdu, err);
3339
}
3340

    
3341
static CoroutineEntry *pdu_co_handlers[] = {
3342
    [P9_TREADDIR] = v9fs_readdir,
3343
    [P9_TSTATFS] = v9fs_statfs,
3344
    [P9_TGETATTR] = v9fs_getattr,
3345
    [P9_TSETATTR] = v9fs_setattr,
3346
    [P9_TXATTRWALK] = v9fs_xattrwalk,
3347
    [P9_TXATTRCREATE] = v9fs_xattrcreate,
3348
    [P9_TMKNOD] = v9fs_mknod,
3349
    [P9_TRENAME] = v9fs_rename,
3350
    [P9_TLOCK] = v9fs_lock,
3351
    [P9_TGETLOCK] = v9fs_getlock,
3352
    [P9_TREADLINK] = v9fs_readlink,
3353
    [P9_TMKDIR] = v9fs_mkdir,
3354
    [P9_TVERSION] = v9fs_version,
3355
    [P9_TLOPEN] = v9fs_open,
3356
    [P9_TATTACH] = v9fs_attach,
3357
    [P9_TSTAT] = v9fs_stat,
3358
    [P9_TWALK] = v9fs_walk,
3359
    [P9_TCLUNK] = v9fs_clunk,
3360
    [P9_TFSYNC] = v9fs_fsync,
3361
    [P9_TOPEN] = v9fs_open,
3362
    [P9_TREAD] = v9fs_read,
3363
#if 0
3364
    [P9_TAUTH] = v9fs_auth,
3365
#endif
3366
    [P9_TFLUSH] = v9fs_flush,
3367
    [P9_TLINK] = v9fs_link,
3368
    [P9_TSYMLINK] = v9fs_symlink,
3369
    [P9_TCREATE] = v9fs_create,
3370
    [P9_TLCREATE] = v9fs_lcreate,
3371
    [P9_TWRITE] = v9fs_write,
3372
    [P9_TWSTAT] = v9fs_wstat,
3373
    [P9_TREMOVE] = v9fs_remove,
3374
};
3375

    
3376
static void v9fs_op_not_supp(void *opaque)
3377
{
3378
    V9fsPDU *pdu = opaque;
3379
    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3380
}
3381

    
3382
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3383
{
3384
    Coroutine *co;
3385
    CoroutineEntry *handler;
3386

    
3387
    if (debug_9p_pdu) {
3388
        pprint_pdu(pdu);
3389
    }
3390
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3391
        (pdu_co_handlers[pdu->id] == NULL)) {
3392
        handler = v9fs_op_not_supp;
3393
    } else {
3394
        handler = pdu_co_handlers[pdu->id];
3395
    }
3396
    co = qemu_coroutine_create(handler);
3397
    qemu_coroutine_enter(co, pdu);
3398
}
3399

    
3400
void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3401
{
3402
    V9fsState *s = (V9fsState *)vdev;
3403
    V9fsPDU *pdu;
3404
    ssize_t len;
3405

    
3406
    while ((pdu = alloc_pdu(s)) &&
3407
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3408
        uint8_t *ptr;
3409
        pdu->s = s;
3410
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3411
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3412

    
3413
        ptr = pdu->elem.out_sg[0].iov_base;
3414

    
3415
        memcpy(&pdu->size, ptr, 4);
3416
        pdu->id = ptr[4];
3417
        memcpy(&pdu->tag, ptr + 5, 2);
3418
        submit_pdu(s, pdu);
3419
    }
3420
    free_pdu(s, pdu);
3421
}