Statistics
| Branch: | Revision:

root / hw / 9pfs / virtio-9p.c @ 7834cf77

History | View | Annotate | Download (81.3 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
int open_fd_hw;
26
int total_open_fd;
27
static int open_fd_rc;
28

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

    
41
static int omode_to_uflags(int8_t mode)
42
{
43
    int ret = 0;
44

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

    
60
    if (mode & Otrunc) {
61
        ret |= O_TRUNC;
62
    }
63

    
64
    if (mode & Oappend) {
65
        ret |= O_APPEND;
66
    }
67

    
68
    if (mode & Oexcl) {
69
        ret |= O_EXCL;
70
    }
71

    
72
    return ret;
73
}
74

    
75
void cred_init(FsCred *credp)
76
{
77
    credp->fc_uid = -1;
78
    credp->fc_gid = -1;
79
    credp->fc_mode = -1;
80
    credp->fc_rdev = -1;
81
}
82

    
83
static void v9fs_string_init(V9fsString *str)
84
{
85
    str->data = NULL;
86
    str->size = 0;
87
}
88

    
89
static void v9fs_string_free(V9fsString *str)
90
{
91
    g_free(str->data);
92
    str->data = NULL;
93
    str->size = 0;
94
}
95

    
96
static void v9fs_string_null(V9fsString *str)
97
{
98
    v9fs_string_free(str);
99
}
100

    
101
static int number_to_string(void *arg, char type)
102
{
103
    unsigned int ret = 0;
104

    
105
    switch (type) {
106
    case 'u': {
107
        unsigned int num = *(unsigned int *)arg;
108

    
109
        do {
110
            ret++;
111
            num = num/10;
112
        } while (num);
113
        break;
114
    }
115
    case 'U': {
116
        unsigned long num = *(unsigned long *)arg;
117
        do {
118
            ret++;
119
            num = num/10;
120
        } while (num);
121
        break;
122
    }
123
    default:
124
        printf("Number_to_string: Unknown number format\n");
125
        return -1;
126
    }
127

    
128
    return ret;
129
}
130

    
131
static int GCC_FMT_ATTR(2, 0)
132
v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
133
{
134
    va_list ap2;
135
    char *iter = (char *)fmt;
136
    int len = 0;
137
    int nr_args = 0;
138
    char *arg_char_ptr;
139
    unsigned int arg_uint;
140
    unsigned long arg_ulong;
141

    
142
    /* Find the number of %'s that denotes an argument */
143
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
144
        nr_args++;
145
        iter++;
146
    }
147

    
148
    len = strlen(fmt) - 2*nr_args;
149

    
150
    if (!nr_args) {
151
        goto alloc_print;
152
    }
153

    
154
    va_copy(ap2, ap);
155

    
156
    iter = (char *)fmt;
157

    
158
    /* Now parse the format string */
159
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
160
        iter++;
161
        switch (*iter) {
162
        case 'u':
163
            arg_uint = va_arg(ap2, unsigned int);
164
            len += number_to_string((void *)&arg_uint, 'u');
165
            break;
166
        case 'l':
167
            if (*++iter == 'u') {
168
                arg_ulong = va_arg(ap2, unsigned long);
169
                len += number_to_string((void *)&arg_ulong, 'U');
170
            } else {
171
                return -1;
172
            }
173
            break;
174
        case 's':
175
            arg_char_ptr = va_arg(ap2, char *);
176
            len += strlen(arg_char_ptr);
177
            break;
178
        case 'c':
179
            len += 1;
180
            break;
181
        default:
182
            fprintf(stderr,
183
                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
184
            return -1;
185
        }
186
        iter++;
187
    }
188

    
189
alloc_print:
190
    *strp = g_malloc((len + 1) * sizeof(**strp));
191

    
192
    return vsprintf(*strp, fmt, ap);
193
}
194

    
195
static void GCC_FMT_ATTR(2, 3)
196
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
197
{
198
    va_list ap;
199
    int err;
200

    
201
    v9fs_string_free(str);
202

    
203
    va_start(ap, fmt);
204
    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
205
    BUG_ON(err == -1);
206
    va_end(ap);
207

    
208
    str->size = err;
209
}
210

    
211
static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
212
{
213
    v9fs_string_free(lhs);
214
    v9fs_string_sprintf(lhs, "%s", rhs->data);
215
}
216

    
217
/*
218
 * Return TRUE if s1 is an ancestor of s2.
219
 *
220
 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
221
 * As a special case, We treat s1 as ancestor of s2 if they are same!
222
 */
223
static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
224
{
225
    if (!strncmp(s1->data, s2->data, s1->size)) {
226
        if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
227
            return 1;
228
        }
229
    }
230
    return 0;
231
}
232

    
233
static size_t v9fs_string_size(V9fsString *str)
234
{
235
    return str->size;
236
}
237

    
238
/*
239
 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
240
static int v9fs_reopen_fid(V9fsState *s, V9fsFidState *f)
241
{
242
    int err = 1;
243
    if (f->fid_type == P9_FID_FILE) {
244
        if (f->fs.fd == -1) {
245
            do {
246
                err = v9fs_co_open(s, f, f->open_flags);
247
            } while (err == -EINTR);
248
        }
249
    } else if (f->fid_type == P9_FID_DIR) {
250
        if (f->fs.dir == NULL) {
251
            do {
252
                err = v9fs_co_opendir(s, f);
253
            } while (err == -EINTR);
254
        }
255
    }
256
    return err;
257
}
258

    
259
static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
260
{
261
    int err;
262
    V9fsFidState *f;
263

    
264
    for (f = s->fid_list; f; f = f->next) {
265
        BUG_ON(f->clunked);
266
        if (f->fid == fid) {
267
            /*
268
             * Update the fid ref upfront so that
269
             * we don't get reclaimed when we yield
270
             * in open later.
271
             */
272
            f->ref++;
273
            /*
274
             * check whether we need to reopen the
275
             * file. We might have closed the fd
276
             * while trying to free up some file
277
             * descriptors.
278
             */
279
            err = v9fs_reopen_fid(s, f);
280
            if (err < 0) {
281
                f->ref--;
282
                return NULL;
283
            }
284
            /*
285
             * Mark the fid as referenced so that the LRU
286
             * reclaim won't close the file descriptor
287
             */
288
            f->flags |= FID_REFERENCED;
289
            return f;
290
        }
291
    }
292
    return NULL;
293
}
294

    
295
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
296
{
297
    V9fsFidState *f;
298

    
299
    for (f = s->fid_list; f; f = f->next) {
300
        /* If fid is already there return NULL */
301
        BUG_ON(f->clunked);
302
        if (f->fid == fid) {
303
            return NULL;
304
        }
305
    }
306
    f = g_malloc0(sizeof(V9fsFidState));
307
    f->fid = fid;
308
    f->fid_type = P9_FID_NONE;
309
    f->ref = 1;
310
    /*
311
     * Mark the fid as referenced so that the LRU
312
     * reclaim won't close the file descriptor
313
     */
314
    f->flags |= FID_REFERENCED;
315
    f->next = s->fid_list;
316
    s->fid_list = f;
317

    
318
    return f;
319
}
320

    
321
static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
322
{
323
    int retval = 0;
324

    
325
    if (fidp->fs.xattr.copied_len == -1) {
326
        /* getxattr/listxattr fid */
327
        goto free_value;
328
    }
329
    /*
330
     * if this is fid for setxattr. clunk should
331
     * result in setxattr localcall
332
     */
333
    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
334
        /* clunk after partial write */
335
        retval = -EINVAL;
336
        goto free_out;
337
    }
338
    if (fidp->fs.xattr.len) {
339
        retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
340
                                   fidp->fs.xattr.value,
341
                                   fidp->fs.xattr.len,
342
                                   fidp->fs.xattr.flags);
343
    } else {
344
        retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
345
    }
346
free_out:
347
    v9fs_string_free(&fidp->fs.xattr.name);
348
free_value:
349
    if (fidp->fs.xattr.value) {
350
        g_free(fidp->fs.xattr.value);
351
    }
352
    return retval;
353
}
354

    
355
static int free_fid(V9fsState *s, V9fsFidState *fidp)
356
{
357
    int retval = 0;
358

    
359
    if (fidp->fid_type == P9_FID_FILE) {
360
        /* If we reclaimed the fd no need to close */
361
        if (fidp->fs.fd != -1) {
362
            retval = v9fs_co_close(s, fidp->fs.fd);
363
        }
364
    } else if (fidp->fid_type == P9_FID_DIR) {
365
        if (fidp->fs.dir != NULL) {
366
            retval = v9fs_co_closedir(s, fidp->fs.dir);
367
        }
368
    } else if (fidp->fid_type == P9_FID_XATTR) {
369
        retval = v9fs_xattr_fid_clunk(s, fidp);
370
    }
371
    v9fs_string_free(&fidp->path);
372
    g_free(fidp);
373
    return retval;
374
}
375

    
376
static void put_fid(V9fsState *s, V9fsFidState *fidp)
377
{
378
    BUG_ON(!fidp->ref);
379
    fidp->ref--;
380
    /*
381
     * Don't free the fid if it is in reclaim list
382
     */
383
    if (!fidp->ref && fidp->clunked) {
384
        free_fid(s, fidp);
385
    }
386
}
387

    
388
static int clunk_fid(V9fsState *s, int32_t fid)
389
{
390
    V9fsFidState **fidpp, *fidp;
391

    
392
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
393
        if ((*fidpp)->fid == fid) {
394
            break;
395
        }
396
    }
397

    
398
    if (*fidpp == NULL) {
399
        return -ENOENT;
400
    }
401
    fidp = *fidpp;
402
    *fidpp = fidp->next;
403
    fidp->clunked = 1;
404
    return 0;
405
}
406

    
407
void v9fs_reclaim_fd(V9fsState *s)
408
{
409
    int reclaim_count = 0;
410
    V9fsFidState *f, *reclaim_list = NULL;
411

    
412
    for (f = s->fid_list; f; f = f->next) {
413
        /*
414
         * Unlink fids cannot be reclaimed. Check
415
         * for them and skip them. Also skip fids
416
         * currently being operated on.
417
         */
418
        if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
419
            continue;
420
        }
421
        /*
422
         * if it is a recently referenced fid
423
         * we leave the fid untouched and clear the
424
         * reference bit. We come back to it later
425
         * in the next iteration. (a simple LRU without
426
         * moving list elements around)
427
         */
428
        if (f->flags & FID_REFERENCED) {
429
            f->flags &= ~FID_REFERENCED;
430
            continue;
431
        }
432
        /*
433
         * Add fids to reclaim list.
434
         */
435
        if (f->fid_type == P9_FID_FILE) {
436
            if (f->fs.fd != -1) {
437
                /*
438
                 * Up the reference count so that
439
                 * a clunk request won't free this fid
440
                 */
441
                f->ref++;
442
                f->rclm_lst = reclaim_list;
443
                reclaim_list = f;
444
                f->fs_reclaim.fd = f->fs.fd;
445
                f->fs.fd = -1;
446
                reclaim_count++;
447
            }
448
        } else if (f->fid_type == P9_FID_DIR) {
449
            if (f->fs.dir != NULL) {
450
                /*
451
                 * Up the reference count so that
452
                 * a clunk request won't free this fid
453
                 */
454
                f->ref++;
455
                f->rclm_lst = reclaim_list;
456
                reclaim_list = f;
457
                f->fs_reclaim.dir = f->fs.dir;
458
                f->fs.dir = NULL;
459
                reclaim_count++;
460
            }
461
        }
462
        if (reclaim_count >= open_fd_rc) {
463
            break;
464
        }
465
    }
466
    /*
467
     * Now close the fid in reclaim list. Free them if they
468
     * are already clunked.
469
     */
470
    while (reclaim_list) {
471
        f = reclaim_list;
472
        reclaim_list = f->rclm_lst;
473
        if (f->fid_type == P9_FID_FILE) {
474
            v9fs_co_close(s, f->fs_reclaim.fd);
475
        } else if (f->fid_type == P9_FID_DIR) {
476
            v9fs_co_closedir(s, f->fs_reclaim.dir);
477
        }
478
        f->rclm_lst = NULL;
479
        /*
480
         * Now drop the fid reference, free it
481
         * if clunked.
482
         */
483
        put_fid(s, f);
484
    }
485
}
486

    
487
static int v9fs_mark_fids_unreclaim(V9fsState *s, V9fsString *str)
488
{
489
    int err;
490
    V9fsFidState *fidp, head_fid;
491

    
492
    head_fid.next = s->fid_list;
493
    for (fidp = s->fid_list; fidp; fidp = fidp->next) {
494
        if (!strcmp(fidp->path.data, str->data)) {
495
            /* Mark the fid non reclaimable. */
496
            fidp->flags |= FID_NON_RECLAIMABLE;
497

    
498
            /* reopen the file/dir if already closed */
499
            err = v9fs_reopen_fid(s, fidp);
500
            if (err < 0) {
501
                return -1;
502
            }
503
            /*
504
             * Go back to head of fid list because
505
             * the list could have got updated when
506
             * switched to the worker thread
507
             */
508
            if (err == 0) {
509
                fidp = &head_fid;
510
            }
511
        }
512
    }
513
    return 0;
514
}
515

    
516
#define P9_QID_TYPE_DIR         0x80
517
#define P9_QID_TYPE_SYMLINK     0x02
518

    
519
#define P9_STAT_MODE_DIR        0x80000000
520
#define P9_STAT_MODE_APPEND     0x40000000
521
#define P9_STAT_MODE_EXCL       0x20000000
522
#define P9_STAT_MODE_MOUNT      0x10000000
523
#define P9_STAT_MODE_AUTH       0x08000000
524
#define P9_STAT_MODE_TMP        0x04000000
525
#define P9_STAT_MODE_SYMLINK    0x02000000
526
#define P9_STAT_MODE_LINK       0x01000000
527
#define P9_STAT_MODE_DEVICE     0x00800000
528
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
529
#define P9_STAT_MODE_SOCKET     0x00100000
530
#define P9_STAT_MODE_SETUID     0x00080000
531
#define P9_STAT_MODE_SETGID     0x00040000
532
#define P9_STAT_MODE_SETVTX     0x00010000
533

    
534
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
535
                                P9_STAT_MODE_SYMLINK |      \
536
                                P9_STAT_MODE_LINK |         \
537
                                P9_STAT_MODE_DEVICE |       \
538
                                P9_STAT_MODE_NAMED_PIPE |   \
539
                                P9_STAT_MODE_SOCKET)
540

    
541
/* This is the algorithm from ufs in spfs */
542
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
543
{
544
    size_t size;
545

    
546
    memset(&qidp->path, 0, sizeof(qidp->path));
547
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
548
    memcpy(&qidp->path, &stbuf->st_ino, size);
549
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
550
    qidp->type = 0;
551
    if (S_ISDIR(stbuf->st_mode)) {
552
        qidp->type |= P9_QID_TYPE_DIR;
553
    }
554
    if (S_ISLNK(stbuf->st_mode)) {
555
        qidp->type |= P9_QID_TYPE_SYMLINK;
556
    }
557
}
558

    
559
static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
560
{
561
    struct stat stbuf;
562
    int err;
563

    
564
    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
565
    if (err < 0) {
566
        return err;
567
    }
568
    stat_to_qid(&stbuf, qidp);
569
    return 0;
570
}
571

    
572
static V9fsPDU *alloc_pdu(V9fsState *s)
573
{
574
    V9fsPDU *pdu = NULL;
575

    
576
    if (!QLIST_EMPTY(&s->free_list)) {
577
        pdu = QLIST_FIRST(&s->free_list);
578
        QLIST_REMOVE(pdu, next);
579
    }
580
    return pdu;
581
}
582

    
583
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
584
{
585
    if (pdu) {
586
        if (debug_9p_pdu) {
587
            pprint_pdu(pdu);
588
        }
589
        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
590
    }
591
}
592

    
593
size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
594
                        size_t offset, size_t size, int pack)
595
{
596
    int i = 0;
597
    size_t copied = 0;
598

    
599
    for (i = 0; size && i < sg_count; i++) {
600
        size_t len;
601
        if (offset >= sg[i].iov_len) {
602
            /* skip this sg */
603
            offset -= sg[i].iov_len;
604
            continue;
605
        } else {
606
            len = MIN(sg[i].iov_len - offset, size);
607
            if (pack) {
608
                memcpy(sg[i].iov_base + offset, addr, len);
609
            } else {
610
                memcpy(addr, sg[i].iov_base + offset, len);
611
            }
612
            size -= len;
613
            copied += len;
614
            addr += len;
615
            if (size) {
616
                offset = 0;
617
                continue;
618
            }
619
        }
620
    }
621

    
622
    return copied;
623
}
624

    
625
static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
626
{
627
    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
628
                         offset, size, 0);
629
}
630

    
631
static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
632
                        size_t size)
633
{
634
    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
635
                             offset, size, 1);
636
}
637

    
638
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
639
{
640
    size_t pos = 0;
641
    int i, j;
642
    struct iovec *src_sg;
643
    unsigned int num;
644

    
645
    if (rx) {
646
        src_sg = pdu->elem.in_sg;
647
        num = pdu->elem.in_num;
648
    } else {
649
        src_sg = pdu->elem.out_sg;
650
        num = pdu->elem.out_num;
651
    }
652

    
653
    j = 0;
654
    for (i = 0; i < num; i++) {
655
        if (offset <= pos) {
656
            sg[j].iov_base = src_sg[i].iov_base;
657
            sg[j].iov_len = src_sg[i].iov_len;
658
            j++;
659
        } else if (offset < (src_sg[i].iov_len + pos)) {
660
            sg[j].iov_base = src_sg[i].iov_base;
661
            sg[j].iov_len = src_sg[i].iov_len;
662
            sg[j].iov_base += (offset - pos);
663
            sg[j].iov_len -= (offset - pos);
664
            j++;
665
        }
666
        pos += src_sg[i].iov_len;
667
    }
668

    
669
    return j;
670
}
671

    
672
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
673
{
674
    size_t old_offset = offset;
675
    va_list ap;
676
    int i;
677

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

    
754
    va_end(ap);
755

    
756
    return offset - old_offset;
757
}
758

    
759
static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
760
{
761
    size_t old_offset = offset;
762
    va_list ap;
763
    int i;
764

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

    
841
    return offset - old_offset;
842
}
843

    
844
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
845
{
846
    int8_t id = pdu->id + 1; /* Response */
847

    
848
    if (len < 0) {
849
        int err = -len;
850
        len = 7;
851

    
852
        if (s->proto_version != V9FS_PROTO_2000L) {
853
            V9fsString str;
854

    
855
            str.data = strerror(err);
856
            str.size = strlen(str.data);
857

    
858
            len += pdu_marshal(pdu, len, "s", &str);
859
            id = P9_RERROR;
860
        }
861

    
862
        len += pdu_marshal(pdu, len, "d", err);
863

    
864
        if (s->proto_version == V9FS_PROTO_2000L) {
865
            id = P9_RLERROR;
866
        }
867
    }
868

    
869
    /* fill out the header */
870
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
871

    
872
    /* keep these in sync */
873
    pdu->size = len;
874
    pdu->id = id;
875

    
876
    /* push onto queue and notify */
877
    virtqueue_push(s->vq, &pdu->elem, len);
878

    
879
    /* FIXME: we should batch these completions */
880
    virtio_notify(&s->vdev, s->vq);
881

    
882
    free_pdu(s, pdu);
883
}
884

    
885
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
886
{
887
    mode_t ret;
888

    
889
    ret = mode & 0777;
890
    if (mode & P9_STAT_MODE_DIR) {
891
        ret |= S_IFDIR;
892
    }
893

    
894
    if (mode & P9_STAT_MODE_SYMLINK) {
895
        ret |= S_IFLNK;
896
    }
897
    if (mode & P9_STAT_MODE_SOCKET) {
898
        ret |= S_IFSOCK;
899
    }
900
    if (mode & P9_STAT_MODE_NAMED_PIPE) {
901
        ret |= S_IFIFO;
902
    }
903
    if (mode & P9_STAT_MODE_DEVICE) {
904
        if (extension && extension->data[0] == 'c') {
905
            ret |= S_IFCHR;
906
        } else {
907
            ret |= S_IFBLK;
908
        }
909
    }
910

    
911
    if (!(ret&~0777)) {
912
        ret |= S_IFREG;
913
    }
914

    
915
    if (mode & P9_STAT_MODE_SETUID) {
916
        ret |= S_ISUID;
917
    }
918
    if (mode & P9_STAT_MODE_SETGID) {
919
        ret |= S_ISGID;
920
    }
921
    if (mode & P9_STAT_MODE_SETVTX) {
922
        ret |= S_ISVTX;
923
    }
924

    
925
    return ret;
926
}
927

    
928
static int donttouch_stat(V9fsStat *stat)
929
{
930
    if (stat->type == -1 &&
931
        stat->dev == -1 &&
932
        stat->qid.type == -1 &&
933
        stat->qid.version == -1 &&
934
        stat->qid.path == -1 &&
935
        stat->mode == -1 &&
936
        stat->atime == -1 &&
937
        stat->mtime == -1 &&
938
        stat->length == -1 &&
939
        !stat->name.size &&
940
        !stat->uid.size &&
941
        !stat->gid.size &&
942
        !stat->muid.size &&
943
        stat->n_uid == -1 &&
944
        stat->n_gid == -1 &&
945
        stat->n_muid == -1) {
946
        return 1;
947
    }
948

    
949
    return 0;
950
}
951

    
952
static void v9fs_stat_free(V9fsStat *stat)
953
{
954
    v9fs_string_free(&stat->name);
955
    v9fs_string_free(&stat->uid);
956
    v9fs_string_free(&stat->gid);
957
    v9fs_string_free(&stat->muid);
958
    v9fs_string_free(&stat->extension);
959
}
960

    
961
static uint32_t stat_to_v9mode(const struct stat *stbuf)
962
{
963
    uint32_t mode;
964

    
965
    mode = stbuf->st_mode & 0777;
966
    if (S_ISDIR(stbuf->st_mode)) {
967
        mode |= P9_STAT_MODE_DIR;
968
    }
969

    
970
    if (S_ISLNK(stbuf->st_mode)) {
971
        mode |= P9_STAT_MODE_SYMLINK;
972
    }
973

    
974
    if (S_ISSOCK(stbuf->st_mode)) {
975
        mode |= P9_STAT_MODE_SOCKET;
976
    }
977

    
978
    if (S_ISFIFO(stbuf->st_mode)) {
979
        mode |= P9_STAT_MODE_NAMED_PIPE;
980
    }
981

    
982
    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
983
        mode |= P9_STAT_MODE_DEVICE;
984
    }
985

    
986
    if (stbuf->st_mode & S_ISUID) {
987
        mode |= P9_STAT_MODE_SETUID;
988
    }
989

    
990
    if (stbuf->st_mode & S_ISGID) {
991
        mode |= P9_STAT_MODE_SETGID;
992
    }
993

    
994
    if (stbuf->st_mode & S_ISVTX) {
995
        mode |= P9_STAT_MODE_SETVTX;
996
    }
997

    
998
    return mode;
999
}
1000

    
1001
static int stat_to_v9stat(V9fsState *s, V9fsString *name,
1002
                            const struct stat *stbuf,
1003
                            V9fsStat *v9stat)
1004
{
1005
    int err;
1006
    const char *str;
1007

    
1008
    memset(v9stat, 0, sizeof(*v9stat));
1009

    
1010
    stat_to_qid(stbuf, &v9stat->qid);
1011
    v9stat->mode = stat_to_v9mode(stbuf);
1012
    v9stat->atime = stbuf->st_atime;
1013
    v9stat->mtime = stbuf->st_mtime;
1014
    v9stat->length = stbuf->st_size;
1015

    
1016
    v9fs_string_null(&v9stat->uid);
1017
    v9fs_string_null(&v9stat->gid);
1018
    v9fs_string_null(&v9stat->muid);
1019

    
1020
    v9stat->n_uid = stbuf->st_uid;
1021
    v9stat->n_gid = stbuf->st_gid;
1022
    v9stat->n_muid = 0;
1023

    
1024
    v9fs_string_null(&v9stat->extension);
1025

    
1026
    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
1027
        err = v9fs_co_readlink(s, name, &v9stat->extension);
1028
        if (err < 0) {
1029
            return err;
1030
        }
1031
    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
1032
        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
1033
                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
1034
                major(stbuf->st_rdev), minor(stbuf->st_rdev));
1035
    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
1036
        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
1037
                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1038
    }
1039

    
1040
    str = strrchr(name->data, '/');
1041
    if (str) {
1042
        str += 1;
1043
    } else {
1044
        str = name->data;
1045
    }
1046

    
1047
    v9fs_string_sprintf(&v9stat->name, "%s", str);
1048

    
1049
    v9stat->size = 61 +
1050
        v9fs_string_size(&v9stat->name) +
1051
        v9fs_string_size(&v9stat->uid) +
1052
        v9fs_string_size(&v9stat->gid) +
1053
        v9fs_string_size(&v9stat->muid) +
1054
        v9fs_string_size(&v9stat->extension);
1055
    return 0;
1056
}
1057

    
1058
#define P9_STATS_MODE          0x00000001ULL
1059
#define P9_STATS_NLINK         0x00000002ULL
1060
#define P9_STATS_UID           0x00000004ULL
1061
#define P9_STATS_GID           0x00000008ULL
1062
#define P9_STATS_RDEV          0x00000010ULL
1063
#define P9_STATS_ATIME         0x00000020ULL
1064
#define P9_STATS_MTIME         0x00000040ULL
1065
#define P9_STATS_CTIME         0x00000080ULL
1066
#define P9_STATS_INO           0x00000100ULL
1067
#define P9_STATS_SIZE          0x00000200ULL
1068
#define P9_STATS_BLOCKS        0x00000400ULL
1069

    
1070
#define P9_STATS_BTIME         0x00000800ULL
1071
#define P9_STATS_GEN           0x00001000ULL
1072
#define P9_STATS_DATA_VERSION  0x00002000ULL
1073

    
1074
#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
1075
#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
1076

    
1077

    
1078
static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
1079
                                V9fsStatDotl *v9lstat)
1080
{
1081
    memset(v9lstat, 0, sizeof(*v9lstat));
1082

    
1083
    v9lstat->st_mode = stbuf->st_mode;
1084
    v9lstat->st_nlink = stbuf->st_nlink;
1085
    v9lstat->st_uid = stbuf->st_uid;
1086
    v9lstat->st_gid = stbuf->st_gid;
1087
    v9lstat->st_rdev = stbuf->st_rdev;
1088
    v9lstat->st_size = stbuf->st_size;
1089
    v9lstat->st_blksize = stbuf->st_blksize;
1090
    v9lstat->st_blocks = stbuf->st_blocks;
1091
    v9lstat->st_atime_sec = stbuf->st_atime;
1092
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
1093
    v9lstat->st_mtime_sec = stbuf->st_mtime;
1094
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
1095
    v9lstat->st_ctime_sec = stbuf->st_ctime;
1096
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
1097
    /* Currently we only support BASIC fields in stat */
1098
    v9lstat->st_result_mask = P9_STATS_BASIC;
1099

    
1100
    stat_to_qid(stbuf, &v9lstat->qid);
1101
}
1102

    
1103
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
1104
{
1105
    while (len && *iovcnt) {
1106
        if (len < sg->iov_len) {
1107
            sg->iov_len -= len;
1108
            sg->iov_base += len;
1109
            len = 0;
1110
        } else {
1111
            len -= sg->iov_len;
1112
            sg++;
1113
            *iovcnt -= 1;
1114
        }
1115
    }
1116

    
1117
    return sg;
1118
}
1119

    
1120
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
1121
{
1122
    int i;
1123
    int total = 0;
1124

    
1125
    for (i = 0; i < *cnt; i++) {
1126
        if ((total + sg[i].iov_len) > cap) {
1127
            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
1128
            i++;
1129
            break;
1130
        }
1131
        total += sg[i].iov_len;
1132
    }
1133

    
1134
    *cnt = i;
1135

    
1136
    return sg;
1137
}
1138

    
1139
static void print_sg(struct iovec *sg, int cnt)
1140
{
1141
    int i;
1142

    
1143
    printf("sg[%d]: {", cnt);
1144
    for (i = 0; i < cnt; i++) {
1145
        if (i) {
1146
            printf(", ");
1147
        }
1148
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
1149
    }
1150
    printf("}\n");
1151
}
1152

    
1153
static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
1154
{
1155
    V9fsString str;
1156
    v9fs_string_init(&str);
1157
    v9fs_string_copy(&str, dst);
1158
    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
1159
    v9fs_string_free(&str);
1160
}
1161

    
1162
static void v9fs_version(void *opaque)
1163
{
1164
    V9fsPDU *pdu = opaque;
1165
    V9fsState *s = pdu->s;
1166
    V9fsString version;
1167
    size_t offset = 7;
1168

    
1169
    pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1170

    
1171
    if (!strcmp(version.data, "9P2000.u")) {
1172
        s->proto_version = V9FS_PROTO_2000U;
1173
    } else if (!strcmp(version.data, "9P2000.L")) {
1174
        s->proto_version = V9FS_PROTO_2000L;
1175
    } else {
1176
        v9fs_string_sprintf(&version, "unknown");
1177
    }
1178

    
1179
    offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1180
    complete_pdu(s, pdu, offset);
1181

    
1182
    v9fs_string_free(&version);
1183
    return;
1184
}
1185

    
1186
static void v9fs_attach(void *opaque)
1187
{
1188
    V9fsPDU *pdu = opaque;
1189
    V9fsState *s = pdu->s;
1190
    int32_t fid, afid, n_uname;
1191
    V9fsString uname, aname;
1192
    V9fsFidState *fidp;
1193
    size_t offset = 7;
1194
    V9fsQID qid;
1195
    ssize_t err;
1196

    
1197
    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1198

    
1199
    fidp = alloc_fid(s, fid);
1200
    if (fidp == NULL) {
1201
        err = -EINVAL;
1202
        goto out_nofid;
1203
    }
1204
    fidp->uid = n_uname;
1205
    v9fs_string_sprintf(&fidp->path, "%s", "/");
1206
    err = fid_to_qid(s, fidp, &qid);
1207
    if (err < 0) {
1208
        err = -EINVAL;
1209
        clunk_fid(s, fid);
1210
        goto out;
1211
    }
1212
    offset += pdu_marshal(pdu, offset, "Q", &qid);
1213
    err = offset;
1214
out:
1215
    put_fid(s, fidp);
1216
out_nofid:
1217
    complete_pdu(s, pdu, err);
1218
    v9fs_string_free(&uname);
1219
    v9fs_string_free(&aname);
1220
}
1221

    
1222
static void v9fs_stat(void *opaque)
1223
{
1224
    int32_t fid;
1225
    V9fsStat v9stat;
1226
    ssize_t err = 0;
1227
    size_t offset = 7;
1228
    struct stat stbuf;
1229
    V9fsFidState *fidp;
1230
    V9fsPDU *pdu = opaque;
1231
    V9fsState *s = pdu->s;
1232

    
1233
    pdu_unmarshal(pdu, offset, "d", &fid);
1234

    
1235
    fidp = get_fid(s, fid);
1236
    if (fidp == NULL) {
1237
        err = -ENOENT;
1238
        goto out_nofid;
1239
    }
1240
    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1241
    if (err < 0) {
1242
        goto out;
1243
    }
1244
    err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
1245
    if (err < 0) {
1246
        goto out;
1247
    }
1248
    offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1249
    err = offset;
1250
    v9fs_stat_free(&v9stat);
1251
out:
1252
    put_fid(s, fidp);
1253
out_nofid:
1254
    complete_pdu(s, pdu, err);
1255
}
1256

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

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

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

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

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

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

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

    
1387
static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1388
{
1389
    int i;
1390
    size_t offset = 7;
1391
    offset += pdu_marshal(pdu, offset, "w", nwnames);
1392
    for (i = 0; i < nwnames; i++) {
1393
        offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
1394
    }
1395
    return offset;
1396
}
1397

    
1398
static void v9fs_walk(void *opaque)
1399
{
1400
    int name_idx;
1401
    V9fsQID *qids = NULL;
1402
    int i, err = 0;
1403
    V9fsString path;
1404
    uint16_t nwnames;
1405
    struct stat stbuf;
1406
    size_t offset = 7;
1407
    int32_t fid, newfid;
1408
    V9fsString *wnames = NULL;
1409
    V9fsFidState *fidp;
1410
    V9fsFidState *newfidp = NULL;;
1411
    V9fsPDU *pdu = opaque;
1412
    V9fsState *s = pdu->s;
1413

    
1414
    offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1415
                            &newfid, &nwnames);
1416

    
1417
    if (nwnames && nwnames <= P9_MAXWELEM) {
1418
        wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1419
        qids   = g_malloc0(sizeof(qids[0]) * nwnames);
1420
        for (i = 0; i < nwnames; i++) {
1421
            offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1422
        }
1423

    
1424
    } else if (nwnames > P9_MAXWELEM) {
1425
        err = -EINVAL;
1426
        goto out_nofid;
1427
    }
1428
    fidp = get_fid(s, fid);
1429
    if (fidp == NULL) {
1430
        err = -ENOENT;
1431
        goto out_nofid;
1432
    }
1433
    if (fid == newfid) {
1434
        BUG_ON(fidp->fid_type != P9_FID_NONE);
1435
        v9fs_string_init(&path);
1436
        for (name_idx = 0; name_idx < nwnames; name_idx++) {
1437
            v9fs_string_sprintf(&path, "%s/%s",
1438
                                fidp->path.data, wnames[name_idx].data);
1439
            v9fs_string_copy(&fidp->path, &path);
1440

    
1441
            err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1442
            if (err < 0) {
1443
                v9fs_string_free(&path);
1444
                goto out;
1445
            }
1446
            stat_to_qid(&stbuf, &qids[name_idx]);
1447
        }
1448
        v9fs_string_free(&path);
1449
    } else {
1450
        newfidp = alloc_fid(s, newfid);
1451
        if (newfidp == NULL) {
1452
            err = -EINVAL;
1453
            goto out;
1454
        }
1455
        newfidp->uid = fidp->uid;
1456
        v9fs_string_init(&path);
1457
        v9fs_string_copy(&newfidp->path, &fidp->path);
1458
        for (name_idx = 0; name_idx < nwnames; name_idx++) {
1459
            v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
1460
                                wnames[name_idx].data);
1461
            v9fs_string_copy(&newfidp->path, &path);
1462
            err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
1463
            if (err < 0) {
1464
                clunk_fid(s, newfidp->fid);
1465
                v9fs_string_free(&path);
1466
                goto out;
1467
            }
1468
            stat_to_qid(&stbuf, &qids[name_idx]);
1469
        }
1470
        v9fs_string_free(&path);
1471
    }
1472
    err = v9fs_walk_marshal(pdu, nwnames, qids);
1473
out:
1474
    put_fid(s, fidp);
1475
    if (newfidp) {
1476
        put_fid(s, newfidp);
1477
    }
1478
out_nofid:
1479
    complete_pdu(s, pdu, err);
1480
    if (nwnames && nwnames <= P9_MAXWELEM) {
1481
        for (name_idx = 0; name_idx < nwnames; name_idx++) {
1482
            v9fs_string_free(&wnames[name_idx]);
1483
        }
1484
        g_free(wnames);
1485
        g_free(qids);
1486
    }
1487
}
1488

    
1489
static int32_t get_iounit(V9fsState *s, V9fsString *name)
1490
{
1491
    struct statfs stbuf;
1492
    int32_t iounit = 0;
1493

    
1494
    /*
1495
     * iounit should be multiples of f_bsize (host filesystem block size
1496
     * and as well as less than (client msize - P9_IOHDRSZ))
1497
     */
1498
    if (!v9fs_co_statfs(s, name, &stbuf)) {
1499
        iounit = stbuf.f_bsize;
1500
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1501
    }
1502
    if (!iounit) {
1503
        iounit = s->msize - P9_IOHDRSZ;
1504
    }
1505
    return iounit;
1506
}
1507

    
1508
static void v9fs_open(void *opaque)
1509
{
1510
    int flags;
1511
    int iounit;
1512
    int32_t fid;
1513
    int32_t mode;
1514
    V9fsQID qid;
1515
    ssize_t err = 0;
1516
    size_t offset = 7;
1517
    struct stat stbuf;
1518
    V9fsFidState *fidp;
1519
    V9fsPDU *pdu = opaque;
1520
    V9fsState *s = pdu->s;
1521

    
1522
    if (s->proto_version == V9FS_PROTO_2000L) {
1523
        pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1524
    } else {
1525
        pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1526
    }
1527
    fidp = get_fid(s, fid);
1528
    if (fidp == NULL) {
1529
        err = -ENOENT;
1530
        goto out_nofid;
1531
    }
1532
    BUG_ON(fidp->fid_type != P9_FID_NONE);
1533

    
1534
    err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1535
    if (err < 0) {
1536
        goto out;
1537
    }
1538
    stat_to_qid(&stbuf, &qid);
1539
    if (S_ISDIR(stbuf.st_mode)) {
1540
        err = v9fs_co_opendir(s, fidp);
1541
        if (err < 0) {
1542
            goto out;
1543
        }
1544
        fidp->fid_type = P9_FID_DIR;
1545
        offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1546
        err = offset;
1547
    } else {
1548
        if (s->proto_version == V9FS_PROTO_2000L) {
1549
            flags = mode;
1550
            flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1551
            /* Ignore direct disk access hint until the server supports it. */
1552
            flags &= ~O_DIRECT;
1553
        } else {
1554
            flags = omode_to_uflags(mode);
1555
        }
1556
        err = v9fs_co_open(s, fidp, flags);
1557
        if (err < 0) {
1558
            goto out;
1559
        }
1560
        fidp->fid_type = P9_FID_FILE;
1561
        fidp->open_flags = flags;
1562
        if (flags & O_EXCL) {
1563
            /*
1564
             * We let the host file system do O_EXCL check
1565
             * We should not reclaim such fd
1566
             */
1567
            fidp->flags |= FID_NON_RECLAIMABLE;
1568
        }
1569
        iounit = get_iounit(s, &fidp->path);
1570
        offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1571
        err = offset;
1572
    }
1573
out:
1574
    put_fid(s, fidp);
1575
out_nofid:
1576
    complete_pdu(s, pdu, err);
1577
}
1578

    
1579
static void v9fs_lcreate(void *opaque)
1580
{
1581
    int32_t dfid, flags, mode;
1582
    gid_t gid;
1583
    ssize_t err = 0;
1584
    ssize_t offset = 7;
1585
    V9fsString fullname;
1586
    V9fsString name;
1587
    V9fsFidState *fidp;
1588
    struct stat stbuf;
1589
    V9fsQID qid;
1590
    int32_t iounit;
1591
    V9fsPDU *pdu = opaque;
1592

    
1593
    v9fs_string_init(&fullname);
1594
    pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1595
                  &mode, &gid);
1596

    
1597
    fidp = get_fid(pdu->s, dfid);
1598
    if (fidp == NULL) {
1599
        err = -ENOENT;
1600
        goto out_nofid;
1601
    }
1602
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
1603

    
1604
    /* Ignore direct disk access hint until the server supports it. */
1605
    flags &= ~O_DIRECT;
1606

    
1607
    err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
1608
    if (err < 0) {
1609
        goto out;
1610
    }
1611
    fidp->fid_type = P9_FID_FILE;
1612
    fidp->open_flags = flags;
1613
    if (flags & O_EXCL) {
1614
        /*
1615
         * We let the host file system do O_EXCL check
1616
         * We should not reclaim such fd
1617
         */
1618
        fidp->flags |= FID_NON_RECLAIMABLE;
1619
    }
1620
    iounit =  get_iounit(pdu->s, &fullname);
1621

    
1622
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1623
    if (err < 0) {
1624
        fidp->fid_type = P9_FID_NONE;
1625
        if (fidp->fs.fd > 0) {
1626
            v9fs_co_close(pdu->s, fidp->fs.fd);
1627
        }
1628
        goto out;
1629
    }
1630
    v9fs_string_copy(&fidp->path, &fullname);
1631
    stat_to_qid(&stbuf, &qid);
1632
    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1633
    err = offset;
1634
out:
1635
    put_fid(pdu->s, fidp);
1636
out_nofid:
1637
    complete_pdu(pdu->s, pdu, err);
1638
    v9fs_string_free(&name);
1639
    v9fs_string_free(&fullname);
1640
}
1641

    
1642
static void v9fs_fsync(void *opaque)
1643
{
1644
    int err;
1645
    int32_t fid;
1646
    int datasync;
1647
    size_t offset = 7;
1648
    V9fsFidState *fidp;
1649
    V9fsPDU *pdu = opaque;
1650
    V9fsState *s = pdu->s;
1651

    
1652
    pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1653
    fidp = get_fid(s, fid);
1654
    if (fidp == NULL) {
1655
        err = -ENOENT;
1656
        goto out_nofid;
1657
    }
1658
    err = v9fs_co_fsync(s, fidp, datasync);
1659
    if (!err) {
1660
        err = offset;
1661
    }
1662
    put_fid(s, fidp);
1663
out_nofid:
1664
    complete_pdu(s, pdu, err);
1665
}
1666

    
1667
static void v9fs_clunk(void *opaque)
1668
{
1669
    int err;
1670
    int32_t fid;
1671
    size_t offset = 7;
1672
    V9fsFidState *fidp;
1673
    V9fsPDU *pdu = opaque;
1674
    V9fsState *s = pdu->s;
1675

    
1676
    pdu_unmarshal(pdu, offset, "d", &fid);
1677

    
1678
    fidp = get_fid(s, fid);
1679
    if (fidp == NULL) {
1680
        err = -ENOENT;
1681
        goto out_nofid;
1682
    }
1683
    err = clunk_fid(s, fidp->fid);
1684
    if (err < 0) {
1685
        goto out;
1686
    }
1687
    err = offset;
1688
out:
1689
    put_fid(s, fidp);
1690
out_nofid:
1691
    complete_pdu(s, pdu, err);
1692
}
1693

    
1694
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1695
                           V9fsFidState *fidp, int64_t off, int32_t max_count)
1696
{
1697
    size_t offset = 7;
1698
    int read_count;
1699
    int64_t xattr_len;
1700

    
1701
    xattr_len = fidp->fs.xattr.len;
1702
    read_count = xattr_len - off;
1703
    if (read_count > max_count) {
1704
        read_count = max_count;
1705
    } else if (read_count < 0) {
1706
        /*
1707
         * read beyond XATTR value
1708
         */
1709
        read_count = 0;
1710
    }
1711
    offset += pdu_marshal(pdu, offset, "d", read_count);
1712
    offset += pdu_pack(pdu, offset,
1713
                       ((char *)fidp->fs.xattr.value) + off,
1714
                       read_count);
1715
    return offset;
1716
}
1717

    
1718
static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
1719
                                     V9fsFidState *fidp, int32_t max_count)
1720
{
1721
    V9fsString name;
1722
    V9fsStat v9stat;
1723
    int len, err = 0;
1724
    int32_t count = 0;
1725
    struct stat stbuf;
1726
    off_t saved_dir_pos;
1727
    struct dirent *dent, *result;
1728

    
1729
    /* save the directory position */
1730
    saved_dir_pos = v9fs_co_telldir(s, fidp);
1731
    if (saved_dir_pos < 0) {
1732
        return saved_dir_pos;
1733
    }
1734

    
1735
    dent = g_malloc(sizeof(struct dirent));
1736

    
1737
    while (1) {
1738
        v9fs_string_init(&name);
1739
        err = v9fs_co_readdir_r(s, fidp, dent, &result);
1740
        if (err || !result) {
1741
            break;
1742
        }
1743
        v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
1744
        err = v9fs_co_lstat(s, &name, &stbuf);
1745
        if (err < 0) {
1746
            goto out;
1747
        }
1748
        err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
1749
        if (err < 0) {
1750
            goto out;
1751
        }
1752
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1753
        len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1754
        if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1755
            /* Ran out of buffer. Set dir back to old position and return */
1756
            v9fs_co_seekdir(s, fidp, saved_dir_pos);
1757
            v9fs_stat_free(&v9stat);
1758
            v9fs_string_free(&name);
1759
            g_free(dent);
1760
            return count;
1761
        }
1762
        count += len;
1763
        v9fs_stat_free(&v9stat);
1764
        v9fs_string_free(&name);
1765
        saved_dir_pos = dent->d_off;
1766
    }
1767
out:
1768
    g_free(dent);
1769
    v9fs_string_free(&name);
1770
    if (err < 0) {
1771
        return err;
1772
    }
1773
    return count;
1774
}
1775

    
1776
static void v9fs_read(void *opaque)
1777
{
1778
    int32_t fid;
1779
    int64_t off;
1780
    ssize_t err = 0;
1781
    int32_t count = 0;
1782
    size_t offset = 7;
1783
    int32_t max_count;
1784
    V9fsFidState *fidp;
1785
    V9fsPDU *pdu = opaque;
1786
    V9fsState *s = pdu->s;
1787

    
1788
    pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1789

    
1790
    fidp = get_fid(s, fid);
1791
    if (fidp == NULL) {
1792
        err = -EINVAL;
1793
        goto out_nofid;
1794
    }
1795
    if (fidp->fid_type == P9_FID_DIR) {
1796

    
1797
        if (off == 0) {
1798
            v9fs_co_rewinddir(s, fidp);
1799
        }
1800
        count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
1801
        if (count < 0) {
1802
            err = count;
1803
            goto out;
1804
        }
1805
        err = offset;
1806
        err += pdu_marshal(pdu, offset, "d", count);
1807
        err += count;
1808
    } else if (fidp->fid_type == P9_FID_FILE) {
1809
        int32_t cnt;
1810
        int32_t len;
1811
        struct iovec *sg;
1812
        struct iovec iov[128]; /* FIXME: bad, bad, bad */
1813

    
1814
        sg = iov;
1815
        pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1816
        sg = cap_sg(sg, max_count, &cnt);
1817
        do {
1818
            if (0) {
1819
                print_sg(sg, cnt);
1820
            }
1821
            /* Loop in case of EINTR */
1822
            do {
1823
                len = v9fs_co_preadv(s, fidp, sg, cnt, off);
1824
                if (len >= 0) {
1825
                    off   += len;
1826
                    count += len;
1827
                }
1828
            } while (len == -EINTR);
1829
            if (len < 0) {
1830
                /* IO error return the error */
1831
                err = len;
1832
                goto out;
1833
            }
1834
            sg = adjust_sg(sg, len, &cnt);
1835
        } while (count < max_count && len > 0);
1836
        err = offset;
1837
        err += pdu_marshal(pdu, offset, "d", count);
1838
        err += count;
1839
    } else if (fidp->fid_type == P9_FID_XATTR) {
1840
        err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1841
    } else {
1842
        err = -EINVAL;
1843
    }
1844
out:
1845
    put_fid(s, fidp);
1846
out_nofid:
1847
    complete_pdu(s, pdu, err);
1848
}
1849

    
1850
static size_t v9fs_readdir_data_size(V9fsString *name)
1851
{
1852
    /*
1853
     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1854
     * size of type (1) + size of name.size (2) + strlen(name.data)
1855
     */
1856
    return 24 + v9fs_string_size(name);
1857
}
1858

    
1859
static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
1860
                           V9fsFidState *fidp, int32_t max_count)
1861
{
1862
    size_t size;
1863
    V9fsQID qid;
1864
    V9fsString name;
1865
    int len, err = 0;
1866
    int32_t count = 0;
1867
    off_t saved_dir_pos;
1868
    struct dirent *dent, *result;
1869

    
1870
    /* save the directory position */
1871
    saved_dir_pos = v9fs_co_telldir(s, fidp);
1872
    if (saved_dir_pos < 0) {
1873
        return saved_dir_pos;
1874
    }
1875

    
1876
    dent = g_malloc(sizeof(struct dirent));
1877

    
1878
    while (1) {
1879
        err = v9fs_co_readdir_r(s, fidp, dent, &result);
1880
        if (err || !result) {
1881
            break;
1882
        }
1883
        v9fs_string_init(&name);
1884
        v9fs_string_sprintf(&name, "%s", dent->d_name);
1885
        if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1886
            /* Ran out of buffer. Set dir back to old position and return */
1887
            v9fs_co_seekdir(s, fidp, saved_dir_pos);
1888
            v9fs_string_free(&name);
1889
            g_free(dent);
1890
            return count;
1891
        }
1892
        /*
1893
         * Fill up just the path field of qid because the client uses
1894
         * only that. To fill the entire qid structure we will have
1895
         * to stat each dirent found, which is expensive
1896
         */
1897
        size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1898
        memcpy(&qid.path, &dent->d_ino, size);
1899
        /* Fill the other fields with dummy values */
1900
        qid.type = 0;
1901
        qid.version = 0;
1902

    
1903
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1904
        len = pdu_marshal(pdu, 11 + count, "Qqbs",
1905
                          &qid, dent->d_off,
1906
                          dent->d_type, &name);
1907
        count += len;
1908
        v9fs_string_free(&name);
1909
        saved_dir_pos = dent->d_off;
1910
    }
1911
    g_free(dent);
1912
    if (err < 0) {
1913
        return err;
1914
    }
1915
    return count;
1916
}
1917

    
1918
static void v9fs_readdir(void *opaque)
1919
{
1920
    int32_t fid;
1921
    V9fsFidState *fidp;
1922
    ssize_t retval = 0;
1923
    size_t offset = 7;
1924
    int64_t initial_offset;
1925
    int32_t count, max_count;
1926
    V9fsPDU *pdu = opaque;
1927
    V9fsState *s = pdu->s;
1928

    
1929
    pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1930

    
1931
    fidp = get_fid(s, fid);
1932
    if (fidp == NULL) {
1933
        retval = -EINVAL;
1934
        goto out_nofid;
1935
    }
1936
    if (!fidp->fs.dir) {
1937
        retval = -EINVAL;
1938
        goto out;
1939
    }
1940
    if (initial_offset == 0) {
1941
        v9fs_co_rewinddir(s, fidp);
1942
    } else {
1943
        v9fs_co_seekdir(s, fidp, initial_offset);
1944
    }
1945
    count = v9fs_do_readdir(s, pdu, fidp, max_count);
1946
    if (count < 0) {
1947
        retval = count;
1948
        goto out;
1949
    }
1950
    retval = offset;
1951
    retval += pdu_marshal(pdu, offset, "d", count);
1952
    retval += count;
1953
out:
1954
    put_fid(s, fidp);
1955
out_nofid:
1956
    complete_pdu(s, pdu, retval);
1957
}
1958

    
1959
static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1960
                            int64_t off, int32_t count,
1961
                            struct iovec *sg, int cnt)
1962
{
1963
    int i, to_copy;
1964
    ssize_t err = 0;
1965
    int write_count;
1966
    int64_t xattr_len;
1967
    size_t offset = 7;
1968

    
1969

    
1970
    xattr_len = fidp->fs.xattr.len;
1971
    write_count = xattr_len - off;
1972
    if (write_count > count) {
1973
        write_count = count;
1974
    } else if (write_count < 0) {
1975
        /*
1976
         * write beyond XATTR value len specified in
1977
         * xattrcreate
1978
         */
1979
        err = -ENOSPC;
1980
        goto out;
1981
    }
1982
    offset += pdu_marshal(pdu, offset, "d", write_count);
1983
    err = offset;
1984
    fidp->fs.xattr.copied_len += write_count;
1985
    /*
1986
     * Now copy the content from sg list
1987
     */
1988
    for (i = 0; i < cnt; i++) {
1989
        if (write_count > sg[i].iov_len) {
1990
            to_copy = sg[i].iov_len;
1991
        } else {
1992
            to_copy = write_count;
1993
        }
1994
        memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1995
        /* updating vs->off since we are not using below */
1996
        off += to_copy;
1997
        write_count -= to_copy;
1998
    }
1999
out:
2000
    return err;
2001
}
2002

    
2003
static void v9fs_write(void *opaque)
2004
{
2005
    int cnt;
2006
    ssize_t err;
2007
    int32_t fid;
2008
    int64_t off;
2009
    int32_t count;
2010
    int32_t len = 0;
2011
    int32_t total = 0;
2012
    size_t offset = 7;
2013
    V9fsFidState *fidp;
2014
    struct iovec iov[128]; /* FIXME: bad, bad, bad */
2015
    struct iovec *sg = iov;
2016
    V9fsPDU *pdu = opaque;
2017
    V9fsState *s = pdu->s;
2018

    
2019
    pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
2020

    
2021
    fidp = get_fid(s, fid);
2022
    if (fidp == NULL) {
2023
        err = -EINVAL;
2024
        goto out_nofid;
2025
    }
2026
    if (fidp->fid_type == P9_FID_FILE) {
2027
        if (fidp->fs.fd == -1) {
2028
            err = -EINVAL;
2029
            goto out;
2030
        }
2031
    } else if (fidp->fid_type == P9_FID_XATTR) {
2032
        /*
2033
         * setxattr operation
2034
         */
2035
        err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
2036
        goto out;
2037
    } else {
2038
        err = -EINVAL;
2039
        goto out;
2040
    }
2041
    sg = cap_sg(sg, count, &cnt);
2042
    do {
2043
        if (0) {
2044
            print_sg(sg, cnt);
2045
        }
2046
        /* Loop in case of EINTR */
2047
        do {
2048
            len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
2049
            if (len >= 0) {
2050
                off   += len;
2051
                total += len;
2052
            }
2053
        } while (len == -EINTR);
2054
        if (len < 0) {
2055
            /* IO error return the error */
2056
            err = len;
2057
            goto out;
2058
        }
2059
        sg = adjust_sg(sg, len, &cnt);
2060
    } while (total < count && len > 0);
2061
    offset += pdu_marshal(pdu, offset, "d", total);
2062
    err = offset;
2063
out:
2064
    put_fid(s, fidp);
2065
out_nofid:
2066
    complete_pdu(s, pdu, err);
2067
}
2068

    
2069
static void v9fs_create(void *opaque)
2070
{
2071
    int32_t fid;
2072
    int err = 0;
2073
    size_t offset = 7;
2074
    V9fsFidState *fidp;
2075
    V9fsQID qid;
2076
    int32_t perm;
2077
    int8_t mode;
2078
    struct stat stbuf;
2079
    V9fsString name;
2080
    V9fsString extension;
2081
    V9fsString fullname;
2082
    int iounit;
2083
    V9fsPDU *pdu = opaque;
2084

    
2085
    v9fs_string_init(&fullname);
2086

    
2087
    pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2088
                  &perm, &mode, &extension);
2089

    
2090
    fidp = get_fid(pdu->s, fid);
2091
    if (fidp == NULL) {
2092
        err = -EINVAL;
2093
        goto out_nofid;
2094
    }
2095

    
2096
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2097
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2098
    if (!err) {
2099
        err = -EEXIST;
2100
        goto out;
2101
    } else if (err != -ENOENT) {
2102
        goto out;
2103
    }
2104
    if (perm & P9_STAT_MODE_DIR) {
2105
        err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
2106
                            fidp->uid, -1);
2107
        if (err < 0) {
2108
            goto out;
2109
        }
2110
        v9fs_string_copy(&fidp->path, &fullname);
2111
        err = v9fs_co_opendir(pdu->s, fidp);
2112
        if (err < 0) {
2113
            goto out;
2114
        }
2115
        fidp->fid_type = P9_FID_DIR;
2116
    } else if (perm & P9_STAT_MODE_SYMLINK) {
2117
        err = v9fs_co_symlink(pdu->s, fidp, extension.data,
2118
                              fullname.data, -1);
2119
        if (err < 0) {
2120
            goto out;
2121
        }
2122
    } else if (perm & P9_STAT_MODE_LINK) {
2123
        int32_t nfid = atoi(extension.data);
2124
        V9fsFidState *nfidp = get_fid(pdu->s, nfid);
2125
        if (nfidp == NULL) {
2126
            err = -EINVAL;
2127
            goto out;
2128
        }
2129
        err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
2130
        if (err < 0) {
2131
            put_fid(pdu->s, nfidp);
2132
            goto out;
2133
        }
2134
        put_fid(pdu->s, nfidp);
2135
    } else if (perm & P9_STAT_MODE_DEVICE) {
2136
        char ctype;
2137
        uint32_t major, minor;
2138
        mode_t nmode = 0;
2139

    
2140
        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2141
            err = -errno;
2142
            goto out;
2143
        }
2144

    
2145
        switch (ctype) {
2146
        case 'c':
2147
            nmode = S_IFCHR;
2148
            break;
2149
        case 'b':
2150
            nmode = S_IFBLK;
2151
            break;
2152
        default:
2153
            err = -EIO;
2154
            goto out;
2155
        }
2156

    
2157
        nmode |= perm & 0777;
2158
        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2159
                            makedev(major, minor), nmode);
2160
        if (err < 0) {
2161
            goto out;
2162
        }
2163
    } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2164
        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2165
                            0, S_IFIFO | (perm & 0777));
2166
        if (err < 0) {
2167
            goto out;
2168
        }
2169
    } else if (perm & P9_STAT_MODE_SOCKET) {
2170
        err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
2171
                            0, S_IFSOCK | (perm & 0777));
2172
        if (err < 0) {
2173
            goto out;
2174
        }
2175
    } else {
2176
        err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
2177
                            omode_to_uflags(mode)|O_CREAT, perm);
2178
        if (err < 0) {
2179
            goto out;
2180
        }
2181
        fidp->fid_type = P9_FID_FILE;
2182
        fidp->open_flags = omode_to_uflags(mode);
2183
        if (fidp->open_flags & O_EXCL) {
2184
            /*
2185
             * We let the host file system do O_EXCL check
2186
             * We should not reclaim such fd
2187
             */
2188
            fidp->flags |= FID_NON_RECLAIMABLE;
2189
        }
2190
    }
2191
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2192
    if (err < 0) {
2193
        fidp->fid_type = P9_FID_NONE;
2194
        if (fidp->fs.fd) {
2195
            v9fs_co_close(pdu->s, fidp->fs.fd);
2196
        }
2197
        goto out;
2198
    }
2199
    iounit = get_iounit(pdu->s, &fidp->path);
2200
    v9fs_string_copy(&fidp->path, &fullname);
2201
    stat_to_qid(&stbuf, &qid);
2202
    offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2203
    err = offset;
2204
out:
2205
    put_fid(pdu->s, fidp);
2206
out_nofid:
2207
   complete_pdu(pdu->s, pdu, err);
2208
   v9fs_string_free(&name);
2209
   v9fs_string_free(&extension);
2210
   v9fs_string_free(&fullname);
2211
}
2212

    
2213
static void v9fs_symlink(void *opaque)
2214
{
2215
    V9fsPDU *pdu = opaque;
2216
    V9fsString name;
2217
    V9fsString symname;
2218
    V9fsString fullname;
2219
    V9fsFidState *dfidp;
2220
    V9fsQID qid;
2221
    struct stat stbuf;
2222
    int32_t dfid;
2223
    int err = 0;
2224
    gid_t gid;
2225
    size_t offset = 7;
2226

    
2227
    v9fs_string_init(&fullname);
2228
    pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2229

    
2230
    dfidp = get_fid(pdu->s, dfid);
2231
    if (dfidp == NULL) {
2232
        err = -EINVAL;
2233
        goto out_nofid;
2234
    }
2235

    
2236
    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2237
    err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
2238
    if (err < 0) {
2239
        goto out;
2240
    }
2241
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2242
    if (err < 0) {
2243
        goto out;
2244
    }
2245
    stat_to_qid(&stbuf, &qid);
2246
    offset += pdu_marshal(pdu, offset, "Q", &qid);
2247
    err = offset;
2248
out:
2249
    put_fid(pdu->s, dfidp);
2250
out_nofid:
2251
    complete_pdu(pdu->s, pdu, err);
2252
    v9fs_string_free(&name);
2253
    v9fs_string_free(&symname);
2254
    v9fs_string_free(&fullname);
2255
}
2256

    
2257
static void v9fs_flush(void *opaque)
2258
{
2259
    V9fsPDU *pdu = opaque;
2260
    V9fsState *s = pdu->s;
2261
    /* A nop call with no return */
2262
    complete_pdu(s, pdu, 7);
2263
    return;
2264
}
2265

    
2266
static void v9fs_link(void *opaque)
2267
{
2268
    V9fsPDU *pdu = opaque;
2269
    V9fsState *s = pdu->s;
2270
    int32_t dfid, oldfid;
2271
    V9fsFidState *dfidp, *oldfidp;
2272
    V9fsString name, fullname;
2273
    size_t offset = 7;
2274
    int err = 0;
2275

    
2276
    v9fs_string_init(&fullname);
2277

    
2278
    pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2279

    
2280
    dfidp = get_fid(s, dfid);
2281
    if (dfidp == NULL) {
2282
        err = -ENOENT;
2283
        goto out_nofid;
2284
    }
2285

    
2286
    oldfidp = get_fid(s, oldfid);
2287
    if (oldfidp == NULL) {
2288
        err = -ENOENT;
2289
        goto out;
2290
    }
2291

    
2292
    v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2293
    err = v9fs_co_link(s, &oldfidp->path, &fullname);
2294
    if (!err) {
2295
        err = offset;
2296
    }
2297
    v9fs_string_free(&fullname);
2298

    
2299
out:
2300
    put_fid(s, dfidp);
2301
out_nofid:
2302
    v9fs_string_free(&name);
2303
    complete_pdu(s, pdu, err);
2304
}
2305

    
2306
static void v9fs_remove(void *opaque)
2307
{
2308
    int32_t fid;
2309
    int err = 0;
2310
    size_t offset = 7;
2311
    V9fsFidState *fidp;
2312
    V9fsPDU *pdu = opaque;
2313

    
2314
    pdu_unmarshal(pdu, offset, "d", &fid);
2315

    
2316
    fidp = get_fid(pdu->s, fid);
2317
    if (fidp == NULL) {
2318
        err = -EINVAL;
2319
        goto out_nofid;
2320
    }
2321
    /*
2322
     * IF the file is unlinked, we cannot reopen
2323
     * the file later. So don't reclaim fd
2324
     */
2325
    err = v9fs_mark_fids_unreclaim(pdu->s, &fidp->path);
2326
    if (err < 0) {
2327
        goto out_err;
2328
    }
2329
    err = v9fs_co_remove(pdu->s, &fidp->path);
2330
    if (!err) {
2331
        err = offset;
2332
    }
2333
out_err:
2334
    /* For TREMOVE we need to clunk the fid even on failed remove */
2335
    clunk_fid(pdu->s, fidp->fid);
2336
    put_fid(pdu->s, fidp);
2337
out_nofid:
2338
    complete_pdu(pdu->s, pdu, err);
2339
}
2340

    
2341
static void v9fs_unlinkat(void *opaque)
2342
{
2343
    int err = 0;
2344
    V9fsString name;
2345
    int32_t dfid, flags;
2346
    size_t offset = 7;
2347
    V9fsFidState *dfidp;
2348
    V9fsPDU *pdu = opaque;
2349
    V9fsString full_name;
2350

    
2351
    pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2352

    
2353
    dfidp = get_fid(pdu->s, dfid);
2354
    if (dfidp == NULL) {
2355
        err = -EINVAL;
2356
        goto out_nofid;
2357
    }
2358
    v9fs_string_init(&full_name);
2359
    v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data);
2360
    /*
2361
     * IF the file is unlinked, we cannot reopen
2362
     * the file later. So don't reclaim fd
2363
     */
2364
    err = v9fs_mark_fids_unreclaim(pdu->s, &full_name);
2365
    if (err < 0) {
2366
        goto out_err;
2367
    }
2368
    err = v9fs_co_remove(pdu->s, &full_name);
2369
    if (!err) {
2370
        err = offset;
2371
    }
2372
out_err:
2373
    put_fid(pdu->s, dfidp);
2374
    v9fs_string_free(&full_name);
2375
out_nofid:
2376
    complete_pdu(pdu->s, pdu, err);
2377
    v9fs_string_free(&name);
2378
}
2379

    
2380
static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2381
                                int32_t newdirfid, V9fsString *name)
2382
{
2383
    char *end;
2384
    int err = 0;
2385
    V9fsFidState *dirfidp = NULL;
2386
    char *old_name, *new_name;
2387

    
2388
    if (newdirfid != -1) {
2389
        dirfidp = get_fid(s, newdirfid);
2390
        if (dirfidp == NULL) {
2391
            err = -ENOENT;
2392
            goto out_nofid;
2393
        }
2394
        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2395

    
2396
        new_name = g_malloc0(dirfidp->path.size + name->size + 2);
2397

    
2398
        strcpy(new_name, dirfidp->path.data);
2399
        strcat(new_name, "/");
2400
        strcat(new_name + dirfidp->path.size, name->data);
2401
    } else {
2402
        old_name = fidp->path.data;
2403
        end = strrchr(old_name, '/');
2404
        if (end) {
2405
            end++;
2406
        } else {
2407
            end = old_name;
2408
        }
2409
        new_name = g_malloc0(end - old_name + name->size + 1);
2410

    
2411
        strncat(new_name, old_name, end - old_name);
2412
        strncat(new_name + (end - old_name), name->data, name->size);
2413
    }
2414

    
2415
    v9fs_string_free(name);
2416
    name->data = new_name;
2417
    name->size = strlen(new_name);
2418

    
2419
    if (strcmp(new_name, fidp->path.data) != 0) {
2420
        err = v9fs_co_rename(s, &fidp->path, name);
2421
        if (err < 0) {
2422
            goto out;
2423
        }
2424
        V9fsFidState *tfidp;
2425
        /*
2426
         * Fixup fid's pointing to the old name to
2427
         * start pointing to the new name
2428
         */
2429
        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2430
            if (fidp == tfidp) {
2431
                /*
2432
                 * we replace name of this fid towards the end
2433
                 * so that our below strcmp will work
2434
                 */
2435
                continue;
2436
            }
2437
            if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2438
                /* replace the name */
2439
                v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2440
            }
2441
        }
2442
        v9fs_string_copy(&fidp->path, name);
2443
    }
2444
out:
2445
    if (dirfidp) {
2446
        put_fid(s, dirfidp);
2447
    }
2448
out_nofid:
2449
    return err;
2450
}
2451

    
2452
static void v9fs_rename(void *opaque)
2453
{
2454
    int32_t fid;
2455
    ssize_t err = 0;
2456
    size_t offset = 7;
2457
    V9fsString name;
2458
    int32_t newdirfid;
2459
    V9fsFidState *fidp;
2460
    V9fsPDU *pdu = opaque;
2461
    V9fsState *s = pdu->s;
2462

    
2463
    pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2464

    
2465
    fidp = get_fid(s, fid);
2466
    if (fidp == NULL) {
2467
        err = -ENOENT;
2468
        goto out_nofid;
2469
    }
2470
    BUG_ON(fidp->fid_type != P9_FID_NONE);
2471

    
2472
    err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2473
    if (!err) {
2474
        err = offset;
2475
    }
2476
    put_fid(s, fidp);
2477
out_nofid:
2478
    complete_pdu(s, pdu, err);
2479
    v9fs_string_free(&name);
2480
}
2481

    
2482
static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid,
2483
                                  V9fsString *old_name, int32_t newdirfid,
2484
                                  V9fsString *new_name)
2485
{
2486
    int err = 0;
2487
    V9fsString old_full_name, new_full_name;
2488
    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2489

    
2490
    olddirfidp = get_fid(s, olddirfid);
2491
    if (olddirfidp == NULL) {
2492
        err = -ENOENT;
2493
        goto out;
2494
    }
2495
    v9fs_string_init(&old_full_name);
2496
    v9fs_string_init(&new_full_name);
2497

    
2498
    v9fs_string_sprintf(&old_full_name, "%s/%s",
2499
                        olddirfidp->path.data, old_name->data);
2500
    if (newdirfid != -1) {
2501
        newdirfidp = get_fid(s, newdirfid);
2502
        if (newdirfidp == NULL) {
2503
            err = -ENOENT;
2504
            goto out;
2505
        }
2506
        v9fs_string_sprintf(&new_full_name, "%s/%s",
2507
                            newdirfidp->path.data, new_name->data);
2508
    } else {
2509
        v9fs_string_sprintf(&new_full_name, "%s/%s",
2510
                            olddirfidp->path.data, new_name->data);
2511
    }
2512

    
2513
    if (strcmp(old_full_name.data, new_full_name.data) != 0) {
2514
        V9fsFidState *tfidp;
2515
        err = v9fs_co_rename(s, &old_full_name, &new_full_name);
2516
        if (err < 0) {
2517
            goto out;
2518
        }
2519
        /*
2520
         * Fixup fid's pointing to the old name to
2521
         * start pointing to the new name
2522
         */
2523
        for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2524
            if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) {
2525
                /* replace the name */
2526
                v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size);
2527
            }
2528
        }
2529
    }
2530
out:
2531
    if (olddirfidp) {
2532
        put_fid(s, olddirfidp);
2533
    }
2534
    if (newdirfidp) {
2535
        put_fid(s, newdirfidp);
2536
    }
2537
    v9fs_string_free(&old_full_name);
2538
    v9fs_string_free(&new_full_name);
2539
    return err;
2540
}
2541

    
2542
static void v9fs_renameat(void *opaque)
2543
{
2544
    ssize_t err = 0;
2545
    size_t offset = 7;
2546
    V9fsPDU *pdu = opaque;
2547
    V9fsState *s = pdu->s;
2548
    int32_t olddirfid, newdirfid;
2549
    V9fsString old_name, new_name;
2550

    
2551
    pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2552
                  &old_name, &newdirfid, &new_name);
2553

    
2554
    err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name);
2555
    if (!err) {
2556
        err = offset;
2557
    }
2558
    complete_pdu(s, pdu, err);
2559
    v9fs_string_free(&old_name);
2560
    v9fs_string_free(&new_name);
2561
}
2562

    
2563
static void v9fs_wstat(void *opaque)
2564
{
2565
    int32_t fid;
2566
    int err = 0;
2567
    int16_t unused;
2568
    V9fsStat v9stat;
2569
    size_t offset = 7;
2570
    struct stat stbuf;
2571
    V9fsFidState *fidp;
2572
    V9fsPDU *pdu = opaque;
2573
    V9fsState *s = pdu->s;
2574

    
2575
    pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2576

    
2577
    fidp = get_fid(s, fid);
2578
    if (fidp == NULL) {
2579
        err = -EINVAL;
2580
        goto out_nofid;
2581
    }
2582
    /* do we need to sync the file? */
2583
    if (donttouch_stat(&v9stat)) {
2584
        err = v9fs_co_fsync(s, fidp, 0);
2585
        goto out;
2586
    }
2587
    if (v9stat.mode != -1) {
2588
        uint32_t v9_mode;
2589
        err = v9fs_co_lstat(s, &fidp->path, &stbuf);
2590
        if (err < 0) {
2591
            goto out;
2592
        }
2593
        v9_mode = stat_to_v9mode(&stbuf);
2594
        if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2595
            (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2596
            /* Attempting to change the type */
2597
            err = -EIO;
2598
            goto out;
2599
        }
2600
        err = v9fs_co_chmod(s, &fidp->path,
2601
                            v9mode_to_mode(v9stat.mode,
2602
                                           &v9stat.extension));
2603
        if (err < 0) {
2604
            goto out;
2605
        }
2606
    }
2607
    if (v9stat.mtime != -1 || v9stat.atime != -1) {
2608
        struct timespec times[2];
2609
        if (v9stat.atime != -1) {
2610
            times[0].tv_sec = v9stat.atime;
2611
            times[0].tv_nsec = 0;
2612
        } else {
2613
            times[0].tv_nsec = UTIME_OMIT;
2614
        }
2615
        if (v9stat.mtime != -1) {
2616
            times[1].tv_sec = v9stat.mtime;
2617
            times[1].tv_nsec = 0;
2618
        } else {
2619
            times[1].tv_nsec = UTIME_OMIT;
2620
        }
2621
        err = v9fs_co_utimensat(s, &fidp->path, times);
2622
        if (err < 0) {
2623
            goto out;
2624
        }
2625
    }
2626
    if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2627
        err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2628
        if (err < 0) {
2629
            goto out;
2630
        }
2631
    }
2632
    if (v9stat.name.size != 0) {
2633
        err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
2634
        if (err < 0) {
2635
            goto out;
2636
        }
2637
    }
2638
    if (v9stat.length != -1) {
2639
        err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
2640
        if (err < 0) {
2641
            goto out;
2642
        }
2643
    }
2644
    err = offset;
2645
out:
2646
    put_fid(s, fidp);
2647
out_nofid:
2648
    v9fs_stat_free(&v9stat);
2649
    complete_pdu(s, pdu, err);
2650
}
2651

    
2652
static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2653
{
2654
    uint32_t f_type;
2655
    uint32_t f_bsize;
2656
    uint64_t f_blocks;
2657
    uint64_t f_bfree;
2658
    uint64_t f_bavail;
2659
    uint64_t f_files;
2660
    uint64_t f_ffree;
2661
    uint64_t fsid_val;
2662
    uint32_t f_namelen;
2663
    size_t offset = 7;
2664
    int32_t bsize_factor;
2665

    
2666
    /*
2667
     * compute bsize factor based on host file system block size
2668
     * and client msize
2669
     */
2670
    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2671
    if (!bsize_factor) {
2672
        bsize_factor = 1;
2673
    }
2674
    f_type  = stbuf->f_type;
2675
    f_bsize = stbuf->f_bsize;
2676
    f_bsize *= bsize_factor;
2677
    /*
2678
     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2679
     * adjust(divide) the number of blocks, free blocks and available
2680
     * blocks by bsize factor
2681
     */
2682
    f_blocks = stbuf->f_blocks/bsize_factor;
2683
    f_bfree  = stbuf->f_bfree/bsize_factor;
2684
    f_bavail = stbuf->f_bavail/bsize_factor;
2685
    f_files  = stbuf->f_files;
2686
    f_ffree  = stbuf->f_ffree;
2687
    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2688
               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2689
    f_namelen = stbuf->f_namelen;
2690

    
2691
    return pdu_marshal(pdu, offset, "ddqqqqqqd",
2692
                       f_type, f_bsize, f_blocks, f_bfree,
2693
                       f_bavail, f_files, f_ffree,
2694
                       fsid_val, f_namelen);
2695
}
2696

    
2697
static void v9fs_statfs(void *opaque)
2698
{
2699
    int32_t fid;
2700
    ssize_t retval = 0;
2701
    size_t offset = 7;
2702
    V9fsFidState *fidp;
2703
    struct statfs stbuf;
2704
    V9fsPDU *pdu = opaque;
2705
    V9fsState *s = pdu->s;
2706

    
2707
    pdu_unmarshal(pdu, offset, "d", &fid);
2708
    fidp = get_fid(s, fid);
2709
    if (fidp == NULL) {
2710
        retval = -ENOENT;
2711
        goto out_nofid;
2712
    }
2713
    retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2714
    if (retval < 0) {
2715
        goto out;
2716
    }
2717
    retval = offset;
2718
    retval += v9fs_fill_statfs(s, pdu, &stbuf);
2719
out:
2720
    put_fid(s, fidp);
2721
out_nofid:
2722
    complete_pdu(s, pdu, retval);
2723
    return;
2724
}
2725

    
2726
static void v9fs_mknod(void *opaque)
2727
{
2728

    
2729
    int mode;
2730
    gid_t gid;
2731
    int32_t fid;
2732
    V9fsQID qid;
2733
    int err = 0;
2734
    int major, minor;
2735
    size_t offset = 7;
2736
    V9fsString name;
2737
    struct stat stbuf;
2738
    V9fsString fullname;
2739
    V9fsFidState *fidp;
2740
    V9fsPDU *pdu = opaque;
2741
    V9fsState *s = pdu->s;
2742

    
2743
    v9fs_string_init(&fullname);
2744
    pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2745
                  &major, &minor, &gid);
2746

    
2747
    fidp = get_fid(s, fid);
2748
    if (fidp == NULL) {
2749
        err = -ENOENT;
2750
        goto out_nofid;
2751
    }
2752
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2753
    err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2754
                        makedev(major, minor), mode);
2755
    if (err < 0) {
2756
        goto out;
2757
    }
2758
    err = v9fs_co_lstat(s, &fullname, &stbuf);
2759
    if (err < 0) {
2760
        goto out;
2761
    }
2762
    stat_to_qid(&stbuf, &qid);
2763
    err = offset;
2764
    err += pdu_marshal(pdu, offset, "Q", &qid);
2765
out:
2766
    put_fid(s, fidp);
2767
out_nofid:
2768
    complete_pdu(s, pdu, err);
2769
    v9fs_string_free(&fullname);
2770
    v9fs_string_free(&name);
2771
}
2772

    
2773
/*
2774
 * Implement posix byte range locking code
2775
 * Server side handling of locking code is very simple, because 9p server in
2776
 * QEMU can handle only one client. And most of the lock handling
2777
 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2778
 * do any thing in * qemu 9p server side lock code path.
2779
 * So when a TLOCK request comes, always return success
2780
 */
2781
static void v9fs_lock(void *opaque)
2782
{
2783
    int8_t status;
2784
    V9fsFlock *flock;
2785
    size_t offset = 7;
2786
    struct stat stbuf;
2787
    V9fsFidState *fidp;
2788
    int32_t fid, err = 0;
2789
    V9fsPDU *pdu = opaque;
2790
    V9fsState *s = pdu->s;
2791

    
2792
    flock = g_malloc(sizeof(*flock));
2793
    pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2794
                  &flock->flags, &flock->start, &flock->length,
2795
                  &flock->proc_id, &flock->client_id);
2796
    status = P9_LOCK_ERROR;
2797

    
2798
    /* We support only block flag now (that too ignored currently) */
2799
    if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2800
        err = -EINVAL;
2801
        goto out_nofid;
2802
    }
2803
    fidp = get_fid(s, fid);
2804
    if (fidp == NULL) {
2805
        err = -ENOENT;
2806
        goto out_nofid;
2807
    }
2808
    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2809
    if (err < 0) {
2810
        goto out;
2811
    }
2812
    status = P9_LOCK_SUCCESS;
2813
out:
2814
    put_fid(s, fidp);
2815
out_nofid:
2816
    err = offset;
2817
    err += pdu_marshal(pdu, offset, "b", status);
2818
    complete_pdu(s, pdu, err);
2819
    v9fs_string_free(&flock->client_id);
2820
    g_free(flock);
2821
}
2822

    
2823
/*
2824
 * When a TGETLOCK request comes, always return success because all lock
2825
 * handling is done by client's VFS layer.
2826
 */
2827
static void v9fs_getlock(void *opaque)
2828
{
2829
    size_t offset = 7;
2830
    struct stat stbuf;
2831
    V9fsFidState *fidp;
2832
    V9fsGetlock *glock;
2833
    int32_t fid, err = 0;
2834
    V9fsPDU *pdu = opaque;
2835
    V9fsState *s = pdu->s;
2836

    
2837
    glock = g_malloc(sizeof(*glock));
2838
    pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
2839
                  &glock->start, &glock->length, &glock->proc_id,
2840
                  &glock->client_id);
2841

    
2842
    fidp = get_fid(s, fid);
2843
    if (fidp == NULL) {
2844
        err = -ENOENT;
2845
        goto out_nofid;
2846
    }
2847
    err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2848
    if (err < 0) {
2849
        goto out;
2850
    }
2851
    glock->type = F_UNLCK;
2852
    offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
2853
                          glock->start, glock->length, glock->proc_id,
2854
                          &glock->client_id);
2855
    err = offset;
2856
out:
2857
    put_fid(s, fidp);
2858
out_nofid:
2859
    complete_pdu(s, pdu, err);
2860
    v9fs_string_free(&glock->client_id);
2861
    g_free(glock);
2862
}
2863

    
2864
static void v9fs_mkdir(void *opaque)
2865
{
2866
    V9fsPDU *pdu = opaque;
2867
    size_t offset = 7;
2868
    int32_t fid;
2869
    struct stat stbuf;
2870
    V9fsString name, fullname;
2871
    V9fsQID qid;
2872
    V9fsFidState *fidp;
2873
    gid_t gid;
2874
    int mode;
2875
    int err = 0;
2876

    
2877
    v9fs_string_init(&fullname);
2878
    pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2879

    
2880
    fidp = get_fid(pdu->s, fid);
2881
    if (fidp == NULL) {
2882
        err = -ENOENT;
2883
        goto out_nofid;
2884
    }
2885
    v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2886
    err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
2887
    if (err < 0) {
2888
        goto out;
2889
    }
2890
    err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2891
    if (err < 0) {
2892
        goto out;
2893
    }
2894
    stat_to_qid(&stbuf, &qid);
2895
    offset += pdu_marshal(pdu, offset, "Q", &qid);
2896
    err = offset;
2897
out:
2898
    put_fid(pdu->s, fidp);
2899
out_nofid:
2900
    complete_pdu(pdu->s, pdu, err);
2901
    v9fs_string_free(&fullname);
2902
    v9fs_string_free(&name);
2903
}
2904

    
2905
static void v9fs_xattrwalk(void *opaque)
2906
{
2907
    int64_t size;
2908
    V9fsString name;
2909
    ssize_t err = 0;
2910
    size_t offset = 7;
2911
    int32_t fid, newfid;
2912
    V9fsFidState *file_fidp;
2913
    V9fsFidState *xattr_fidp = NULL;
2914
    V9fsPDU *pdu = opaque;
2915
    V9fsState *s = pdu->s;
2916

    
2917
    pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2918
    file_fidp = get_fid(s, fid);
2919
    if (file_fidp == NULL) {
2920
        err = -ENOENT;
2921
        goto out_nofid;
2922
    }
2923
    xattr_fidp = alloc_fid(s, newfid);
2924
    if (xattr_fidp == NULL) {
2925
        err = -EINVAL;
2926
        goto out;
2927
    }
2928
    v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
2929
    if (name.data[0] == 0) {
2930
        /*
2931
         * listxattr request. Get the size first
2932
         */
2933
        size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
2934
        if (size < 0) {
2935
            err = size;
2936
            clunk_fid(s, xattr_fidp->fid);
2937
            goto out;
2938
        }
2939
        /*
2940
         * Read the xattr value
2941
         */
2942
        xattr_fidp->fs.xattr.len = size;
2943
        xattr_fidp->fid_type = P9_FID_XATTR;
2944
        xattr_fidp->fs.xattr.copied_len = -1;
2945
        if (size) {
2946
            xattr_fidp->fs.xattr.value = g_malloc(size);
2947
            err = v9fs_co_llistxattr(s, &xattr_fidp->path,
2948
                                     xattr_fidp->fs.xattr.value,
2949
                                     xattr_fidp->fs.xattr.len);
2950
            if (err < 0) {
2951
                clunk_fid(s, xattr_fidp->fid);
2952
                goto out;
2953
            }
2954
        }
2955
        offset += pdu_marshal(pdu, offset, "q", size);
2956
        err = offset;
2957
    } else {
2958
        /*
2959
         * specific xattr fid. We check for xattr
2960
         * presence also collect the xattr size
2961
         */
2962
        size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2963
                                 &name, NULL, 0);
2964
        if (size < 0) {
2965
            err = size;
2966
            clunk_fid(s, xattr_fidp->fid);
2967
            goto out;
2968
        }
2969
        /*
2970
         * Read the xattr value
2971
         */
2972
        xattr_fidp->fs.xattr.len = size;
2973
        xattr_fidp->fid_type = P9_FID_XATTR;
2974
        xattr_fidp->fs.xattr.copied_len = -1;
2975
        if (size) {
2976
            xattr_fidp->fs.xattr.value = g_malloc(size);
2977
            err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2978
                                    &name, xattr_fidp->fs.xattr.value,
2979
                                    xattr_fidp->fs.xattr.len);
2980
            if (err < 0) {
2981
                clunk_fid(s, xattr_fidp->fid);
2982
                goto out;
2983
            }
2984
        }
2985
        offset += pdu_marshal(pdu, offset, "q", size);
2986
        err = offset;
2987
    }
2988
out:
2989
    put_fid(s, file_fidp);
2990
    if (xattr_fidp) {
2991
        put_fid(s, xattr_fidp);
2992
    }
2993
out_nofid:
2994
    complete_pdu(s, pdu, err);
2995
    v9fs_string_free(&name);
2996
}
2997

    
2998
static void v9fs_xattrcreate(void *opaque)
2999
{
3000
    int flags;
3001
    int32_t fid;
3002
    int64_t size;
3003
    ssize_t err = 0;
3004
    V9fsString name;
3005
    size_t offset = 7;
3006
    V9fsFidState *file_fidp;
3007
    V9fsFidState *xattr_fidp;
3008
    V9fsPDU *pdu = opaque;
3009
    V9fsState *s = pdu->s;
3010

    
3011
    pdu_unmarshal(pdu, offset, "dsqd",
3012
                  &fid, &name, &size, &flags);
3013

    
3014
    file_fidp = get_fid(s, fid);
3015
    if (file_fidp == NULL) {
3016
        err = -EINVAL;
3017
        goto out_nofid;
3018
    }
3019
    /* Make the file fid point to xattr */
3020
    xattr_fidp = file_fidp;
3021
    xattr_fidp->fid_type = P9_FID_XATTR;
3022
    xattr_fidp->fs.xattr.copied_len = 0;
3023
    xattr_fidp->fs.xattr.len = size;
3024
    xattr_fidp->fs.xattr.flags = flags;
3025
    v9fs_string_init(&xattr_fidp->fs.xattr.name);
3026
    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3027
    if (size) {
3028
        xattr_fidp->fs.xattr.value = g_malloc(size);
3029
    } else {
3030
        xattr_fidp->fs.xattr.value = NULL;
3031
    }
3032
    err = offset;
3033
    put_fid(s, file_fidp);
3034
out_nofid:
3035
    complete_pdu(s, pdu, err);
3036
    v9fs_string_free(&name);
3037
}
3038

    
3039
static void v9fs_readlink(void *opaque)
3040
{
3041
    V9fsPDU *pdu = opaque;
3042
    size_t offset = 7;
3043
    V9fsString target;
3044
    int32_t fid;
3045
    int err = 0;
3046
    V9fsFidState *fidp;
3047

    
3048
    pdu_unmarshal(pdu, offset, "d", &fid);
3049
    fidp = get_fid(pdu->s, fid);
3050
    if (fidp == NULL) {
3051
        err = -ENOENT;
3052
        goto out_nofid;
3053
    }
3054

    
3055
    v9fs_string_init(&target);
3056
    err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
3057
    if (err < 0) {
3058
        goto out;
3059
    }
3060
    offset += pdu_marshal(pdu, offset, "s", &target);
3061
    err = offset;
3062
    v9fs_string_free(&target);
3063
out:
3064
    put_fid(pdu->s, fidp);
3065
out_nofid:
3066
    complete_pdu(pdu->s, pdu, err);
3067
}
3068

    
3069
static CoroutineEntry *pdu_co_handlers[] = {
3070
    [P9_TREADDIR] = v9fs_readdir,
3071
    [P9_TSTATFS] = v9fs_statfs,
3072
    [P9_TGETATTR] = v9fs_getattr,
3073
    [P9_TSETATTR] = v9fs_setattr,
3074
    [P9_TXATTRWALK] = v9fs_xattrwalk,
3075
    [P9_TXATTRCREATE] = v9fs_xattrcreate,
3076
    [P9_TMKNOD] = v9fs_mknod,
3077
    [P9_TRENAME] = v9fs_rename,
3078
    [P9_TLOCK] = v9fs_lock,
3079
    [P9_TGETLOCK] = v9fs_getlock,
3080
    [P9_TRENAMEAT] = v9fs_renameat,
3081
    [P9_TREADLINK] = v9fs_readlink,
3082
    [P9_TUNLINKAT] = v9fs_unlinkat,
3083
    [P9_TMKDIR] = v9fs_mkdir,
3084
    [P9_TVERSION] = v9fs_version,
3085
    [P9_TLOPEN] = v9fs_open,
3086
    [P9_TATTACH] = v9fs_attach,
3087
    [P9_TSTAT] = v9fs_stat,
3088
    [P9_TWALK] = v9fs_walk,
3089
    [P9_TCLUNK] = v9fs_clunk,
3090
    [P9_TFSYNC] = v9fs_fsync,
3091
    [P9_TOPEN] = v9fs_open,
3092
    [P9_TREAD] = v9fs_read,
3093
#if 0
3094
    [P9_TAUTH] = v9fs_auth,
3095
#endif
3096
    [P9_TFLUSH] = v9fs_flush,
3097
    [P9_TLINK] = v9fs_link,
3098
    [P9_TSYMLINK] = v9fs_symlink,
3099
    [P9_TCREATE] = v9fs_create,
3100
    [P9_TLCREATE] = v9fs_lcreate,
3101
    [P9_TWRITE] = v9fs_write,
3102
    [P9_TWSTAT] = v9fs_wstat,
3103
    [P9_TREMOVE] = v9fs_remove,
3104
};
3105

    
3106
static void v9fs_op_not_supp(void *opaque)
3107
{
3108
    V9fsPDU *pdu = opaque;
3109
    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3110
}
3111

    
3112
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3113
{
3114
    Coroutine *co;
3115
    CoroutineEntry *handler;
3116

    
3117
    if (debug_9p_pdu) {
3118
        pprint_pdu(pdu);
3119
    }
3120
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3121
        (pdu_co_handlers[pdu->id] == NULL)) {
3122
        handler = v9fs_op_not_supp;
3123
    } else {
3124
        handler = pdu_co_handlers[pdu->id];
3125
    }
3126
    co = qemu_coroutine_create(handler);
3127
    qemu_coroutine_enter(co, pdu);
3128
}
3129

    
3130
void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3131
{
3132
    V9fsState *s = (V9fsState *)vdev;
3133
    V9fsPDU *pdu;
3134
    ssize_t len;
3135

    
3136
    while ((pdu = alloc_pdu(s)) &&
3137
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3138
        uint8_t *ptr;
3139
        pdu->s = s;
3140
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3141
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3142

    
3143
        ptr = pdu->elem.out_sg[0].iov_base;
3144

    
3145
        memcpy(&pdu->size, ptr, 4);
3146
        pdu->id = ptr[4];
3147
        memcpy(&pdu->tag, ptr + 5, 2);
3148
        submit_pdu(s, pdu);
3149
    }
3150
    free_pdu(s, pdu);
3151
}
3152

    
3153
void virtio_9p_set_fd_limit(void)
3154
{
3155
    struct rlimit rlim;
3156
    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3157
        fprintf(stderr, "Failed to get the resource limit\n");
3158
        exit(1);
3159
    }
3160
    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3161
    open_fd_rc = rlim.rlim_cur/2;
3162
}