Statistics
| Branch: | Revision:

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

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

    
24
int open_fd_hw;
25
int total_open_fd;
26
static int open_fd_rc;
27

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

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

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

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

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

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

    
71
    return ret;
72
}
73

    
74
struct dotl_openflag_map {
75
    int dotl_flag;
76
    int open_flag;
77
};
78

    
79
static int dotl_to_open_flags(int flags)
80
{
81
    int i;
82
    /*
83
     * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
84
     * and P9_DOTL_NOACCESS
85
     */
86
    int oflags = flags & O_ACCMODE;
87

    
88
    struct dotl_openflag_map dotl_oflag_map[] = {
89
        { P9_DOTL_CREATE, O_CREAT },
90
        { P9_DOTL_EXCL, O_EXCL },
91
        { P9_DOTL_NOCTTY , O_NOCTTY },
92
        { P9_DOTL_TRUNC, O_TRUNC },
93
        { P9_DOTL_APPEND, O_APPEND },
94
        { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
95
        { P9_DOTL_DSYNC, O_DSYNC },
96
        { P9_DOTL_FASYNC, FASYNC },
97
        { P9_DOTL_DIRECT, O_DIRECT },
98
        { P9_DOTL_LARGEFILE, O_LARGEFILE },
99
        { P9_DOTL_DIRECTORY, O_DIRECTORY },
100
        { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
101
        { P9_DOTL_NOATIME, O_NOATIME },
102
        { P9_DOTL_SYNC, O_SYNC },
103
    };
104

    
105
    for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
106
        if (flags & dotl_oflag_map[i].dotl_flag) {
107
            oflags |= dotl_oflag_map[i].open_flag;
108
        }
109
    }
110

    
111
    return oflags;
112
}
113

    
114
void cred_init(FsCred *credp)
115
{
116
    credp->fc_uid = -1;
117
    credp->fc_gid = -1;
118
    credp->fc_mode = -1;
119
    credp->fc_rdev = -1;
120
}
121

    
122
static int get_dotl_openflags(V9fsState *s, int oflags)
123
{
124
    int flags;
125
    /*
126
     * Filter the client open flags
127
     */
128
    flags = dotl_to_open_flags(oflags);
129
    flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
130
    /*
131
     * Ignore direct disk access hint until the server supports it.
132
     */
133
    flags &= ~O_DIRECT;
134
    return flags;
135
}
136

    
137
void v9fs_path_init(V9fsPath *path)
138
{
139
    path->data = NULL;
140
    path->size = 0;
141
}
142

    
143
void v9fs_path_free(V9fsPath *path)
144
{
145
    g_free(path->data);
146
    path->data = NULL;
147
    path->size = 0;
148
}
149

    
150
void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
151
{
152
    v9fs_path_free(lhs);
153
    lhs->data = g_malloc(rhs->size);
154
    memcpy(lhs->data, rhs->data, rhs->size);
155
    lhs->size = rhs->size;
156
}
157

    
158
int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
159
                      const char *name, V9fsPath *path)
160
{
161
    int err;
162
    err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
163
    if (err < 0) {
164
        err = -errno;
165
    }
166
    return err;
167
}
168

    
169
/*
170
 * Return TRUE if s1 is an ancestor of s2.
171
 *
172
 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
173
 * As a special case, We treat s1 as ancestor of s2 if they are same!
174
 */
175
static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
176
{
177
    if (!strncmp(s1->data, s2->data, s1->size - 1)) {
178
        if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
179
            return 1;
180
        }
181
    }
182
    return 0;
183
}
184

    
185
static size_t v9fs_string_size(V9fsString *str)
186
{
187
    return str->size;
188
}
189

    
190
/*
191
 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
192
static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
193
{
194
    int err = 1;
195
    if (f->fid_type == P9_FID_FILE) {
196
        if (f->fs.fd == -1) {
197
            do {
198
                err = v9fs_co_open(pdu, f, f->open_flags);
199
            } while (err == -EINTR && !pdu->cancelled);
200
        }
201
    } else if (f->fid_type == P9_FID_DIR) {
202
        if (f->fs.dir == NULL) {
203
            do {
204
                err = v9fs_co_opendir(pdu, f);
205
            } while (err == -EINTR && !pdu->cancelled);
206
        }
207
    }
208
    return err;
209
}
210

    
211
static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
212
{
213
    int err;
214
    V9fsFidState *f;
215
    V9fsState *s = pdu->s;
216

    
217
    for (f = s->fid_list; f; f = f->next) {
218
        BUG_ON(f->clunked);
219
        if (f->fid == fid) {
220
            /*
221
             * Update the fid ref upfront so that
222
             * we don't get reclaimed when we yield
223
             * in open later.
224
             */
225
            f->ref++;
226
            /*
227
             * check whether we need to reopen the
228
             * file. We might have closed the fd
229
             * while trying to free up some file
230
             * descriptors.
231
             */
232
            err = v9fs_reopen_fid(pdu, f);
233
            if (err < 0) {
234
                f->ref--;
235
                return NULL;
236
            }
237
            /*
238
             * Mark the fid as referenced so that the LRU
239
             * reclaim won't close the file descriptor
240
             */
241
            f->flags |= FID_REFERENCED;
242
            return f;
243
        }
244
    }
245
    return NULL;
246
}
247

    
248
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
249
{
250
    V9fsFidState *f;
251

    
252
    for (f = s->fid_list; f; f = f->next) {
253
        /* If fid is already there return NULL */
254
        BUG_ON(f->clunked);
255
        if (f->fid == fid) {
256
            return NULL;
257
        }
258
    }
259
    f = g_malloc0(sizeof(V9fsFidState));
260
    f->fid = fid;
261
    f->fid_type = P9_FID_NONE;
262
    f->ref = 1;
263
    /*
264
     * Mark the fid as referenced so that the LRU
265
     * reclaim won't close the file descriptor
266
     */
267
    f->flags |= FID_REFERENCED;
268
    f->next = s->fid_list;
269
    s->fid_list = f;
270

    
271
    return f;
272
}
273

    
274
static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
275
{
276
    int retval = 0;
277

    
278
    if (fidp->fs.xattr.copied_len == -1) {
279
        /* getxattr/listxattr fid */
280
        goto free_value;
281
    }
282
    /*
283
     * if this is fid for setxattr. clunk should
284
     * result in setxattr localcall
285
     */
286
    if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
287
        /* clunk after partial write */
288
        retval = -EINVAL;
289
        goto free_out;
290
    }
291
    if (fidp->fs.xattr.len) {
292
        retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
293
                                   fidp->fs.xattr.value,
294
                                   fidp->fs.xattr.len,
295
                                   fidp->fs.xattr.flags);
296
    } else {
297
        retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
298
    }
299
free_out:
300
    v9fs_string_free(&fidp->fs.xattr.name);
301
free_value:
302
    if (fidp->fs.xattr.value) {
303
        g_free(fidp->fs.xattr.value);
304
    }
305
    return retval;
306
}
307

    
308
static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
309
{
310
    int retval = 0;
311

    
312
    if (fidp->fid_type == P9_FID_FILE) {
313
        /* If we reclaimed the fd no need to close */
314
        if (fidp->fs.fd != -1) {
315
            retval = v9fs_co_close(pdu, &fidp->fs);
316
        }
317
    } else if (fidp->fid_type == P9_FID_DIR) {
318
        if (fidp->fs.dir != NULL) {
319
            retval = v9fs_co_closedir(pdu, &fidp->fs);
320
        }
321
    } else if (fidp->fid_type == P9_FID_XATTR) {
322
        retval = v9fs_xattr_fid_clunk(pdu, fidp);
323
    }
324
    v9fs_path_free(&fidp->path);
325
    g_free(fidp);
326
    return retval;
327
}
328

    
329
static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
330
{
331
    BUG_ON(!fidp->ref);
332
    fidp->ref--;
333
    /*
334
     * Don't free the fid if it is in reclaim list
335
     */
336
    if (!fidp->ref && fidp->clunked) {
337
        if (fidp->fid == pdu->s->root_fid) {
338
            /*
339
             * if the clunked fid is root fid then we
340
             * have unmounted the fs on the client side.
341
             * delete the migration blocker. Ideally, this
342
             * should be hooked to transport close notification
343
             */
344
            if (pdu->s->migration_blocker) {
345
                migrate_del_blocker(pdu->s->migration_blocker);
346
                error_free(pdu->s->migration_blocker);
347
                pdu->s->migration_blocker = NULL;
348
            }
349
        }
350
        return free_fid(pdu, fidp);
351
    }
352
    return 0;
353
}
354

    
355
static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
356
{
357
    V9fsFidState **fidpp, *fidp;
358

    
359
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
360
        if ((*fidpp)->fid == fid) {
361
            break;
362
        }
363
    }
364
    if (*fidpp == NULL) {
365
        return NULL;
366
    }
367
    fidp = *fidpp;
368
    *fidpp = fidp->next;
369
    fidp->clunked = 1;
370
    return fidp;
371
}
372

    
373
void v9fs_reclaim_fd(V9fsPDU *pdu)
374
{
375
    int reclaim_count = 0;
376
    V9fsState *s = pdu->s;
377
    V9fsFidState *f, *reclaim_list = NULL;
378

    
379
    for (f = s->fid_list; f; f = f->next) {
380
        /*
381
         * Unlink fids cannot be reclaimed. Check
382
         * for them and skip them. Also skip fids
383
         * currently being operated on.
384
         */
385
        if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
386
            continue;
387
        }
388
        /*
389
         * if it is a recently referenced fid
390
         * we leave the fid untouched and clear the
391
         * reference bit. We come back to it later
392
         * in the next iteration. (a simple LRU without
393
         * moving list elements around)
394
         */
395
        if (f->flags & FID_REFERENCED) {
396
            f->flags &= ~FID_REFERENCED;
397
            continue;
398
        }
399
        /*
400
         * Add fids to reclaim list.
401
         */
402
        if (f->fid_type == P9_FID_FILE) {
403
            if (f->fs.fd != -1) {
404
                /*
405
                 * Up the reference count so that
406
                 * a clunk request won't free this fid
407
                 */
408
                f->ref++;
409
                f->rclm_lst = reclaim_list;
410
                reclaim_list = f;
411
                f->fs_reclaim.fd = f->fs.fd;
412
                f->fs.fd = -1;
413
                reclaim_count++;
414
            }
415
        } else if (f->fid_type == P9_FID_DIR) {
416
            if (f->fs.dir != NULL) {
417
                /*
418
                 * Up the reference count so that
419
                 * a clunk request won't free this fid
420
                 */
421
                f->ref++;
422
                f->rclm_lst = reclaim_list;
423
                reclaim_list = f;
424
                f->fs_reclaim.dir = f->fs.dir;
425
                f->fs.dir = NULL;
426
                reclaim_count++;
427
            }
428
        }
429
        if (reclaim_count >= open_fd_rc) {
430
            break;
431
        }
432
    }
433
    /*
434
     * Now close the fid in reclaim list. Free them if they
435
     * are already clunked.
436
     */
437
    while (reclaim_list) {
438
        f = reclaim_list;
439
        reclaim_list = f->rclm_lst;
440
        if (f->fid_type == P9_FID_FILE) {
441
            v9fs_co_close(pdu, &f->fs_reclaim);
442
        } else if (f->fid_type == P9_FID_DIR) {
443
            v9fs_co_closedir(pdu, &f->fs_reclaim);
444
        }
445
        f->rclm_lst = NULL;
446
        /*
447
         * Now drop the fid reference, free it
448
         * if clunked.
449
         */
450
        put_fid(pdu, f);
451
    }
452
}
453

    
454
static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
455
{
456
    int err;
457
    V9fsState *s = pdu->s;
458
    V9fsFidState *fidp, head_fid;
459

    
460
    head_fid.next = s->fid_list;
461
    for (fidp = s->fid_list; fidp; fidp = fidp->next) {
462
        if (fidp->path.size != path->size) {
463
            continue;
464
        }
465
        if (!memcmp(fidp->path.data, path->data, path->size)) {
466
            /* Mark the fid non reclaimable. */
467
            fidp->flags |= FID_NON_RECLAIMABLE;
468

    
469
            /* reopen the file/dir if already closed */
470
            err = v9fs_reopen_fid(pdu, fidp);
471
            if (err < 0) {
472
                return -1;
473
            }
474
            /*
475
             * Go back to head of fid list because
476
             * the list could have got updated when
477
             * switched to the worker thread
478
             */
479
            if (err == 0) {
480
                fidp = &head_fid;
481
            }
482
        }
483
    }
484
    return 0;
485
}
486

    
487
static void virtfs_reset(V9fsPDU *pdu)
488
{
489
    V9fsState *s = pdu->s;
490
    V9fsFidState *fidp = NULL;
491

    
492
    /* Free all fids */
493
    while (s->fid_list) {
494
        fidp = s->fid_list;
495
        s->fid_list = fidp->next;
496

    
497
        if (fidp->ref) {
498
            fidp->clunked = 1;
499
        } else {
500
            free_fid(pdu, fidp);
501
        }
502
    }
503
    if (fidp) {
504
        /* One or more unclunked fids found... */
505
        error_report("9pfs:%s: One or more uncluncked fids "
506
                     "found during reset", __func__);
507
    }
508
}
509

    
510
#define P9_QID_TYPE_DIR         0x80
511
#define P9_QID_TYPE_SYMLINK     0x02
512

    
513
#define P9_STAT_MODE_DIR        0x80000000
514
#define P9_STAT_MODE_APPEND     0x40000000
515
#define P9_STAT_MODE_EXCL       0x20000000
516
#define P9_STAT_MODE_MOUNT      0x10000000
517
#define P9_STAT_MODE_AUTH       0x08000000
518
#define P9_STAT_MODE_TMP        0x04000000
519
#define P9_STAT_MODE_SYMLINK    0x02000000
520
#define P9_STAT_MODE_LINK       0x01000000
521
#define P9_STAT_MODE_DEVICE     0x00800000
522
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
523
#define P9_STAT_MODE_SOCKET     0x00100000
524
#define P9_STAT_MODE_SETUID     0x00080000
525
#define P9_STAT_MODE_SETGID     0x00040000
526
#define P9_STAT_MODE_SETVTX     0x00010000
527

    
528
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
529
                                P9_STAT_MODE_SYMLINK |      \
530
                                P9_STAT_MODE_LINK |         \
531
                                P9_STAT_MODE_DEVICE |       \
532
                                P9_STAT_MODE_NAMED_PIPE |   \
533
                                P9_STAT_MODE_SOCKET)
534

    
535
/* This is the algorithm from ufs in spfs */
536
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
537
{
538
    size_t size;
539

    
540
    memset(&qidp->path, 0, sizeof(qidp->path));
541
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
542
    memcpy(&qidp->path, &stbuf->st_ino, size);
543
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
544
    qidp->type = 0;
545
    if (S_ISDIR(stbuf->st_mode)) {
546
        qidp->type |= P9_QID_TYPE_DIR;
547
    }
548
    if (S_ISLNK(stbuf->st_mode)) {
549
        qidp->type |= P9_QID_TYPE_SYMLINK;
550
    }
551
}
552

    
553
static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
554
{
555
    struct stat stbuf;
556
    int err;
557

    
558
    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
559
    if (err < 0) {
560
        return err;
561
    }
562
    stat_to_qid(&stbuf, qidp);
563
    return 0;
564
}
565

    
566
static V9fsPDU *alloc_pdu(V9fsState *s)
567
{
568
    V9fsPDU *pdu = NULL;
569

    
570
    if (!QLIST_EMPTY(&s->free_list)) {
571
        pdu = QLIST_FIRST(&s->free_list);
572
        QLIST_REMOVE(pdu, next);
573
        QLIST_INSERT_HEAD(&s->active_list, pdu, next);
574
    }
575
    return pdu;
576
}
577

    
578
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
579
{
580
    if (pdu) {
581
        /*
582
         * Cancelled pdu are added back to the freelist
583
         * by flush request .
584
         */
585
        if (!pdu->cancelled) {
586
            QLIST_REMOVE(pdu, next);
587
            QLIST_INSERT_HEAD(&s->free_list, pdu, next);
588
        }
589
    }
590
}
591

    
592
/*
593
 * We don't do error checking for pdu_marshal/unmarshal here
594
 * because we always expect to have enough space to encode
595
 * error details
596
 */
597
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
598
{
599
    int8_t id = pdu->id + 1; /* Response */
600

    
601
    if (len < 0) {
602
        int err = -len;
603
        len = 7;
604

    
605
        if (s->proto_version != V9FS_PROTO_2000L) {
606
            V9fsString str;
607

    
608
            str.data = strerror(err);
609
            str.size = strlen(str.data);
610

    
611
            len += pdu_marshal(pdu, len, "s", &str);
612
            id = P9_RERROR;
613
        }
614

    
615
        len += pdu_marshal(pdu, len, "d", err);
616

    
617
        if (s->proto_version == V9FS_PROTO_2000L) {
618
            id = P9_RLERROR;
619
        }
620
        trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
621
    }
622

    
623
    /* fill out the header */
624
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
625

    
626
    /* keep these in sync */
627
    pdu->size = len;
628
    pdu->id = id;
629

    
630
    /* push onto queue and notify */
631
    virtqueue_push(s->vq, &pdu->elem, len);
632

    
633
    /* FIXME: we should batch these completions */
634
    virtio_notify(VIRTIO_DEVICE(s), s->vq);
635

    
636
    /* Now wakeup anybody waiting in flush for this request */
637
    qemu_co_queue_next(&pdu->complete);
638

    
639
    free_pdu(s, pdu);
640
}
641

    
642
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
643
{
644
    mode_t ret;
645

    
646
    ret = mode & 0777;
647
    if (mode & P9_STAT_MODE_DIR) {
648
        ret |= S_IFDIR;
649
    }
650

    
651
    if (mode & P9_STAT_MODE_SYMLINK) {
652
        ret |= S_IFLNK;
653
    }
654
    if (mode & P9_STAT_MODE_SOCKET) {
655
        ret |= S_IFSOCK;
656
    }
657
    if (mode & P9_STAT_MODE_NAMED_PIPE) {
658
        ret |= S_IFIFO;
659
    }
660
    if (mode & P9_STAT_MODE_DEVICE) {
661
        if (extension->size && extension->data[0] == 'c') {
662
            ret |= S_IFCHR;
663
        } else {
664
            ret |= S_IFBLK;
665
        }
666
    }
667

    
668
    if (!(ret&~0777)) {
669
        ret |= S_IFREG;
670
    }
671

    
672
    if (mode & P9_STAT_MODE_SETUID) {
673
        ret |= S_ISUID;
674
    }
675
    if (mode & P9_STAT_MODE_SETGID) {
676
        ret |= S_ISGID;
677
    }
678
    if (mode & P9_STAT_MODE_SETVTX) {
679
        ret |= S_ISVTX;
680
    }
681

    
682
    return ret;
683
}
684

    
685
static int donttouch_stat(V9fsStat *stat)
686
{
687
    if (stat->type == -1 &&
688
        stat->dev == -1 &&
689
        stat->qid.type == -1 &&
690
        stat->qid.version == -1 &&
691
        stat->qid.path == -1 &&
692
        stat->mode == -1 &&
693
        stat->atime == -1 &&
694
        stat->mtime == -1 &&
695
        stat->length == -1 &&
696
        !stat->name.size &&
697
        !stat->uid.size &&
698
        !stat->gid.size &&
699
        !stat->muid.size &&
700
        stat->n_uid == -1 &&
701
        stat->n_gid == -1 &&
702
        stat->n_muid == -1) {
703
        return 1;
704
    }
705

    
706
    return 0;
707
}
708

    
709
static void v9fs_stat_init(V9fsStat *stat)
710
{
711
    v9fs_string_init(&stat->name);
712
    v9fs_string_init(&stat->uid);
713
    v9fs_string_init(&stat->gid);
714
    v9fs_string_init(&stat->muid);
715
    v9fs_string_init(&stat->extension);
716
}
717

    
718
static void v9fs_stat_free(V9fsStat *stat)
719
{
720
    v9fs_string_free(&stat->name);
721
    v9fs_string_free(&stat->uid);
722
    v9fs_string_free(&stat->gid);
723
    v9fs_string_free(&stat->muid);
724
    v9fs_string_free(&stat->extension);
725
}
726

    
727
static uint32_t stat_to_v9mode(const struct stat *stbuf)
728
{
729
    uint32_t mode;
730

    
731
    mode = stbuf->st_mode & 0777;
732
    if (S_ISDIR(stbuf->st_mode)) {
733
        mode |= P9_STAT_MODE_DIR;
734
    }
735

    
736
    if (S_ISLNK(stbuf->st_mode)) {
737
        mode |= P9_STAT_MODE_SYMLINK;
738
    }
739

    
740
    if (S_ISSOCK(stbuf->st_mode)) {
741
        mode |= P9_STAT_MODE_SOCKET;
742
    }
743

    
744
    if (S_ISFIFO(stbuf->st_mode)) {
745
        mode |= P9_STAT_MODE_NAMED_PIPE;
746
    }
747

    
748
    if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
749
        mode |= P9_STAT_MODE_DEVICE;
750
    }
751

    
752
    if (stbuf->st_mode & S_ISUID) {
753
        mode |= P9_STAT_MODE_SETUID;
754
    }
755

    
756
    if (stbuf->st_mode & S_ISGID) {
757
        mode |= P9_STAT_MODE_SETGID;
758
    }
759

    
760
    if (stbuf->st_mode & S_ISVTX) {
761
        mode |= P9_STAT_MODE_SETVTX;
762
    }
763

    
764
    return mode;
765
}
766

    
767
static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
768
                            const struct stat *stbuf,
769
                            V9fsStat *v9stat)
770
{
771
    int err;
772
    const char *str;
773

    
774
    memset(v9stat, 0, sizeof(*v9stat));
775

    
776
    stat_to_qid(stbuf, &v9stat->qid);
777
    v9stat->mode = stat_to_v9mode(stbuf);
778
    v9stat->atime = stbuf->st_atime;
779
    v9stat->mtime = stbuf->st_mtime;
780
    v9stat->length = stbuf->st_size;
781

    
782
    v9fs_string_null(&v9stat->uid);
783
    v9fs_string_null(&v9stat->gid);
784
    v9fs_string_null(&v9stat->muid);
785

    
786
    v9stat->n_uid = stbuf->st_uid;
787
    v9stat->n_gid = stbuf->st_gid;
788
    v9stat->n_muid = 0;
789

    
790
    v9fs_string_null(&v9stat->extension);
791

    
792
    if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
793
        err = v9fs_co_readlink(pdu, name, &v9stat->extension);
794
        if (err < 0) {
795
            return err;
796
        }
797
    } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
798
        v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
799
                S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
800
                major(stbuf->st_rdev), minor(stbuf->st_rdev));
801
    } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
802
        v9fs_string_sprintf(&v9stat->extension, "%s %lu",
803
                "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
804
    }
805

    
806
    str = strrchr(name->data, '/');
807
    if (str) {
808
        str += 1;
809
    } else {
810
        str = name->data;
811
    }
812

    
813
    v9fs_string_sprintf(&v9stat->name, "%s", str);
814

    
815
    v9stat->size = 61 +
816
        v9fs_string_size(&v9stat->name) +
817
        v9fs_string_size(&v9stat->uid) +
818
        v9fs_string_size(&v9stat->gid) +
819
        v9fs_string_size(&v9stat->muid) +
820
        v9fs_string_size(&v9stat->extension);
821
    return 0;
822
}
823

    
824
#define P9_STATS_MODE          0x00000001ULL
825
#define P9_STATS_NLINK         0x00000002ULL
826
#define P9_STATS_UID           0x00000004ULL
827
#define P9_STATS_GID           0x00000008ULL
828
#define P9_STATS_RDEV          0x00000010ULL
829
#define P9_STATS_ATIME         0x00000020ULL
830
#define P9_STATS_MTIME         0x00000040ULL
831
#define P9_STATS_CTIME         0x00000080ULL
832
#define P9_STATS_INO           0x00000100ULL
833
#define P9_STATS_SIZE          0x00000200ULL
834
#define P9_STATS_BLOCKS        0x00000400ULL
835

    
836
#define P9_STATS_BTIME         0x00000800ULL
837
#define P9_STATS_GEN           0x00001000ULL
838
#define P9_STATS_DATA_VERSION  0x00002000ULL
839

    
840
#define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
841
#define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
842

    
843

    
844
static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
845
                                V9fsStatDotl *v9lstat)
846
{
847
    memset(v9lstat, 0, sizeof(*v9lstat));
848

    
849
    v9lstat->st_mode = stbuf->st_mode;
850
    v9lstat->st_nlink = stbuf->st_nlink;
851
    v9lstat->st_uid = stbuf->st_uid;
852
    v9lstat->st_gid = stbuf->st_gid;
853
    v9lstat->st_rdev = stbuf->st_rdev;
854
    v9lstat->st_size = stbuf->st_size;
855
    v9lstat->st_blksize = stbuf->st_blksize;
856
    v9lstat->st_blocks = stbuf->st_blocks;
857
    v9lstat->st_atime_sec = stbuf->st_atime;
858
    v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
859
    v9lstat->st_mtime_sec = stbuf->st_mtime;
860
    v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
861
    v9lstat->st_ctime_sec = stbuf->st_ctime;
862
    v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
863
    /* Currently we only support BASIC fields in stat */
864
    v9lstat->st_result_mask = P9_STATS_BASIC;
865

    
866
    stat_to_qid(stbuf, &v9lstat->qid);
867
}
868

    
869
static void print_sg(struct iovec *sg, int cnt)
870
{
871
    int i;
872

    
873
    printf("sg[%d]: {", cnt);
874
    for (i = 0; i < cnt; i++) {
875
        if (i) {
876
            printf(", ");
877
        }
878
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
879
    }
880
    printf("}\n");
881
}
882

    
883
/* Will call this only for path name based fid */
884
static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
885
{
886
    V9fsPath str;
887
    v9fs_path_init(&str);
888
    v9fs_path_copy(&str, dst);
889
    v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
890
    v9fs_path_free(&str);
891
    /* +1 to include terminating NULL */
892
    dst->size++;
893
}
894

    
895
static inline bool is_ro_export(FsContext *ctx)
896
{
897
    return ctx->export_flags & V9FS_RDONLY;
898
}
899

    
900
static void v9fs_version(void *opaque)
901
{
902
    ssize_t err;
903
    V9fsPDU *pdu = opaque;
904
    V9fsState *s = pdu->s;
905
    V9fsString version;
906
    size_t offset = 7;
907

    
908
    v9fs_string_init(&version);
909
    err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
910
    if (err < 0) {
911
        offset = err;
912
        goto out;
913
    }
914
    trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
915

    
916
    virtfs_reset(pdu);
917

    
918
    if (!strcmp(version.data, "9P2000.u")) {
919
        s->proto_version = V9FS_PROTO_2000U;
920
    } else if (!strcmp(version.data, "9P2000.L")) {
921
        s->proto_version = V9FS_PROTO_2000L;
922
    } else {
923
        v9fs_string_sprintf(&version, "unknown");
924
    }
925

    
926
    err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
927
    if (err < 0) {
928
        offset = err;
929
        goto out;
930
    }
931
    offset += err;
932
    trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
933
out:
934
    complete_pdu(s, pdu, offset);
935
    v9fs_string_free(&version);
936
}
937

    
938
static void v9fs_attach(void *opaque)
939
{
940
    V9fsPDU *pdu = opaque;
941
    V9fsState *s = pdu->s;
942
    int32_t fid, afid, n_uname;
943
    V9fsString uname, aname;
944
    V9fsFidState *fidp;
945
    size_t offset = 7;
946
    V9fsQID qid;
947
    ssize_t err;
948

    
949
    v9fs_string_init(&uname);
950
    v9fs_string_init(&aname);
951
    err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
952
                        &afid, &uname, &aname, &n_uname);
953
    if (err < 0) {
954
        goto out_nofid;
955
    }
956
    trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
957

    
958
    fidp = alloc_fid(s, fid);
959
    if (fidp == NULL) {
960
        err = -EINVAL;
961
        goto out_nofid;
962
    }
963
    fidp->uid = n_uname;
964
    err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
965
    if (err < 0) {
966
        err = -EINVAL;
967
        clunk_fid(s, fid);
968
        goto out;
969
    }
970
    err = fid_to_qid(pdu, fidp, &qid);
971
    if (err < 0) {
972
        err = -EINVAL;
973
        clunk_fid(s, fid);
974
        goto out;
975
    }
976
    err = pdu_marshal(pdu, offset, "Q", &qid);
977
    if (err < 0) {
978
        clunk_fid(s, fid);
979
        goto out;
980
    }
981
    err += offset;
982
    trace_v9fs_attach_return(pdu->tag, pdu->id,
983
                             qid.type, qid.version, qid.path);
984
    /*
985
     * disable migration if we haven't done already.
986
     * attach could get called multiple times for the same export.
987
     */
988
    if (!s->migration_blocker) {
989
        s->root_fid = fid;
990
        error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
991
                  s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
992
        migrate_add_blocker(s->migration_blocker);
993
    }
994
out:
995
    put_fid(pdu, fidp);
996
out_nofid:
997
    complete_pdu(s, pdu, err);
998
    v9fs_string_free(&uname);
999
    v9fs_string_free(&aname);
1000
}
1001

    
1002
static void v9fs_stat(void *opaque)
1003
{
1004
    int32_t fid;
1005
    V9fsStat v9stat;
1006
    ssize_t err = 0;
1007
    size_t offset = 7;
1008
    struct stat stbuf;
1009
    V9fsFidState *fidp;
1010
    V9fsPDU *pdu = opaque;
1011
    V9fsState *s = pdu->s;
1012

    
1013
    err = pdu_unmarshal(pdu, offset, "d", &fid);
1014
    if (err < 0) {
1015
        goto out_nofid;
1016
    }
1017
    trace_v9fs_stat(pdu->tag, pdu->id, fid);
1018

    
1019
    fidp = get_fid(pdu, fid);
1020
    if (fidp == NULL) {
1021
        err = -ENOENT;
1022
        goto out_nofid;
1023
    }
1024
    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1025
    if (err < 0) {
1026
        goto out;
1027
    }
1028
    err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
1029
    if (err < 0) {
1030
        goto out;
1031
    }
1032
    err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1033
    if (err < 0) {
1034
        v9fs_stat_free(&v9stat);
1035
        goto out;
1036
    }
1037
    trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1038
                           v9stat.atime, v9stat.mtime, v9stat.length);
1039
    err += offset;
1040
    v9fs_stat_free(&v9stat);
1041
out:
1042
    put_fid(pdu, fidp);
1043
out_nofid:
1044
    complete_pdu(s, pdu, err);
1045
}
1046

    
1047
static void v9fs_getattr(void *opaque)
1048
{
1049
    int32_t fid;
1050
    size_t offset = 7;
1051
    ssize_t retval = 0;
1052
    struct stat stbuf;
1053
    V9fsFidState *fidp;
1054
    uint64_t request_mask;
1055
    V9fsStatDotl v9stat_dotl;
1056
    V9fsPDU *pdu = opaque;
1057
    V9fsState *s = pdu->s;
1058

    
1059
    retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1060
    if (retval < 0) {
1061
        goto out_nofid;
1062
    }
1063
    trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
1064

    
1065
    fidp = get_fid(pdu, fid);
1066
    if (fidp == NULL) {
1067
        retval = -ENOENT;
1068
        goto out_nofid;
1069
    }
1070
    /*
1071
     * Currently we only support BASIC fields in stat, so there is no
1072
     * need to look at request_mask.
1073
     */
1074
    retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1075
    if (retval < 0) {
1076
        goto out;
1077
    }
1078
    stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1079

    
1080
    /*  fill st_gen if requested and supported by underlying fs */
1081
    if (request_mask & P9_STATS_GEN) {
1082
        retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
1083
        switch (retval) {
1084
        case 0:
1085
            /* we have valid st_gen: update result mask */
1086
            v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1087
            break;
1088
        case -EINTR:
1089
            /* request cancelled, e.g. by Tflush */
1090
            goto out;
1091
        default:
1092
            /* failed to get st_gen: not fatal, ignore */
1093
            break;
1094
        }
1095
    }
1096
    retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1097
    if (retval < 0) {
1098
        goto out;
1099
    }
1100
    retval += offset;
1101
    trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1102
                              v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1103
                              v9stat_dotl.st_gid);
1104
out:
1105
    put_fid(pdu, fidp);
1106
out_nofid:
1107
    complete_pdu(s, pdu, retval);
1108
}
1109

    
1110
/* Attribute flags */
1111
#define P9_ATTR_MODE       (1 << 0)
1112
#define P9_ATTR_UID        (1 << 1)
1113
#define P9_ATTR_GID        (1 << 2)
1114
#define P9_ATTR_SIZE       (1 << 3)
1115
#define P9_ATTR_ATIME      (1 << 4)
1116
#define P9_ATTR_MTIME      (1 << 5)
1117
#define P9_ATTR_CTIME      (1 << 6)
1118
#define P9_ATTR_ATIME_SET  (1 << 7)
1119
#define P9_ATTR_MTIME_SET  (1 << 8)
1120

    
1121
#define P9_ATTR_MASK    127
1122

    
1123
static void v9fs_setattr(void *opaque)
1124
{
1125
    int err = 0;
1126
    int32_t fid;
1127
    V9fsFidState *fidp;
1128
    size_t offset = 7;
1129
    V9fsIattr v9iattr;
1130
    V9fsPDU *pdu = opaque;
1131
    V9fsState *s = pdu->s;
1132

    
1133
    err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1134
    if (err < 0) {
1135
        goto out_nofid;
1136
    }
1137

    
1138
    fidp = get_fid(pdu, fid);
1139
    if (fidp == NULL) {
1140
        err = -EINVAL;
1141
        goto out_nofid;
1142
    }
1143
    if (v9iattr.valid & P9_ATTR_MODE) {
1144
        err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
1145
        if (err < 0) {
1146
            goto out;
1147
        }
1148
    }
1149
    if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
1150
        struct timespec times[2];
1151
        if (v9iattr.valid & P9_ATTR_ATIME) {
1152
            if (v9iattr.valid & P9_ATTR_ATIME_SET) {
1153
                times[0].tv_sec = v9iattr.atime_sec;
1154
                times[0].tv_nsec = v9iattr.atime_nsec;
1155
            } else {
1156
                times[0].tv_nsec = UTIME_NOW;
1157
            }
1158
        } else {
1159
            times[0].tv_nsec = UTIME_OMIT;
1160
        }
1161
        if (v9iattr.valid & P9_ATTR_MTIME) {
1162
            if (v9iattr.valid & P9_ATTR_MTIME_SET) {
1163
                times[1].tv_sec = v9iattr.mtime_sec;
1164
                times[1].tv_nsec = v9iattr.mtime_nsec;
1165
            } else {
1166
                times[1].tv_nsec = UTIME_NOW;
1167
            }
1168
        } else {
1169
            times[1].tv_nsec = UTIME_OMIT;
1170
        }
1171
        err = v9fs_co_utimensat(pdu, &fidp->path, times);
1172
        if (err < 0) {
1173
            goto out;
1174
        }
1175
    }
1176
    /*
1177
     * If the only valid entry in iattr is ctime we can call
1178
     * chown(-1,-1) to update the ctime of the file
1179
     */
1180
    if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
1181
        ((v9iattr.valid & P9_ATTR_CTIME)
1182
         && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
1183
        if (!(v9iattr.valid & P9_ATTR_UID)) {
1184
            v9iattr.uid = -1;
1185
        }
1186
        if (!(v9iattr.valid & P9_ATTR_GID)) {
1187
            v9iattr.gid = -1;
1188
        }
1189
        err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
1190
                            v9iattr.gid);
1191
        if (err < 0) {
1192
            goto out;
1193
        }
1194
    }
1195
    if (v9iattr.valid & (P9_ATTR_SIZE)) {
1196
        err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
1197
        if (err < 0) {
1198
            goto out;
1199
        }
1200
    }
1201
    err = offset;
1202
out:
1203
    put_fid(pdu, fidp);
1204
out_nofid:
1205
    complete_pdu(s, pdu, err);
1206
}
1207

    
1208
static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1209
{
1210
    int i;
1211
    ssize_t err;
1212
    size_t offset = 7;
1213

    
1214
    err = pdu_marshal(pdu, offset, "w", nwnames);
1215
    if (err < 0) {
1216
        return err;
1217
    }
1218
    offset += err;
1219
    for (i = 0; i < nwnames; i++) {
1220
        err = pdu_marshal(pdu, offset, "Q", &qids[i]);
1221
        if (err < 0) {
1222
            return err;
1223
        }
1224
        offset += err;
1225
    }
1226
    return offset;
1227
}
1228

    
1229
static void v9fs_walk(void *opaque)
1230
{
1231
    int name_idx;
1232
    V9fsQID *qids = NULL;
1233
    int i, err = 0;
1234
    V9fsPath dpath, path;
1235
    uint16_t nwnames;
1236
    struct stat stbuf;
1237
    size_t offset = 7;
1238
    int32_t fid, newfid;
1239
    V9fsString *wnames = NULL;
1240
    V9fsFidState *fidp;
1241
    V9fsFidState *newfidp = NULL;
1242
    V9fsPDU *pdu = opaque;
1243
    V9fsState *s = pdu->s;
1244

    
1245
    err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
1246
    if (err < 0) {
1247
        complete_pdu(s, pdu, err);
1248
        return ;
1249
    }
1250
    offset += err;
1251

    
1252
    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1253

    
1254
    if (nwnames && nwnames <= P9_MAXWELEM) {
1255
        wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1256
        qids   = g_malloc0(sizeof(qids[0]) * nwnames);
1257
        for (i = 0; i < nwnames; i++) {
1258
            err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1259
            if (err < 0) {
1260
                goto out_nofid;
1261
            }
1262
            offset += err;
1263
        }
1264
    } else if (nwnames > P9_MAXWELEM) {
1265
        err = -EINVAL;
1266
        goto out_nofid;
1267
    }
1268
    fidp = get_fid(pdu, fid);
1269
    if (fidp == NULL) {
1270
        err = -ENOENT;
1271
        goto out_nofid;
1272
    }
1273
    v9fs_path_init(&dpath);
1274
    v9fs_path_init(&path);
1275
    /*
1276
     * Both dpath and path initially poin to fidp.
1277
     * Needed to handle request with nwnames == 0
1278
     */
1279
    v9fs_path_copy(&dpath, &fidp->path);
1280
    v9fs_path_copy(&path, &fidp->path);
1281
    for (name_idx = 0; name_idx < nwnames; name_idx++) {
1282
        err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
1283
        if (err < 0) {
1284
            goto out;
1285
        }
1286
        err = v9fs_co_lstat(pdu, &path, &stbuf);
1287
        if (err < 0) {
1288
            goto out;
1289
        }
1290
        stat_to_qid(&stbuf, &qids[name_idx]);
1291
        v9fs_path_copy(&dpath, &path);
1292
    }
1293
    if (fid == newfid) {
1294
        BUG_ON(fidp->fid_type != P9_FID_NONE);
1295
        v9fs_path_copy(&fidp->path, &path);
1296
    } else {
1297
        newfidp = alloc_fid(s, newfid);
1298
        if (newfidp == NULL) {
1299
            err = -EINVAL;
1300
            goto out;
1301
        }
1302
        newfidp->uid = fidp->uid;
1303
        v9fs_path_copy(&newfidp->path, &path);
1304
    }
1305
    err = v9fs_walk_marshal(pdu, nwnames, qids);
1306
    trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
1307
out:
1308
    put_fid(pdu, fidp);
1309
    if (newfidp) {
1310
        put_fid(pdu, newfidp);
1311
    }
1312
    v9fs_path_free(&dpath);
1313
    v9fs_path_free(&path);
1314
out_nofid:
1315
    complete_pdu(s, pdu, err);
1316
    if (nwnames && nwnames <= P9_MAXWELEM) {
1317
        for (name_idx = 0; name_idx < nwnames; name_idx++) {
1318
            v9fs_string_free(&wnames[name_idx]);
1319
        }
1320
        g_free(wnames);
1321
        g_free(qids);
1322
    }
1323
}
1324

    
1325
static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
1326
{
1327
    struct statfs stbuf;
1328
    int32_t iounit = 0;
1329
    V9fsState *s = pdu->s;
1330

    
1331
    /*
1332
     * iounit should be multiples of f_bsize (host filesystem block size
1333
     * and as well as less than (client msize - P9_IOHDRSZ))
1334
     */
1335
    if (!v9fs_co_statfs(pdu, path, &stbuf)) {
1336
        iounit = stbuf.f_bsize;
1337
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1338
    }
1339
    if (!iounit) {
1340
        iounit = s->msize - P9_IOHDRSZ;
1341
    }
1342
    return iounit;
1343
}
1344

    
1345
static void v9fs_open(void *opaque)
1346
{
1347
    int flags;
1348
    int32_t fid;
1349
    int32_t mode;
1350
    V9fsQID qid;
1351
    int iounit = 0;
1352
    ssize_t err = 0;
1353
    size_t offset = 7;
1354
    struct stat stbuf;
1355
    V9fsFidState *fidp;
1356
    V9fsPDU *pdu = opaque;
1357
    V9fsState *s = pdu->s;
1358

    
1359
    if (s->proto_version == V9FS_PROTO_2000L) {
1360
        err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1361
    } else {
1362
        uint8_t modebyte;
1363
        err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
1364
        mode = modebyte;
1365
    }
1366
    if (err < 0) {
1367
        goto out_nofid;
1368
    }
1369
    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1370

    
1371
    fidp = get_fid(pdu, fid);
1372
    if (fidp == NULL) {
1373
        err = -ENOENT;
1374
        goto out_nofid;
1375
    }
1376
    BUG_ON(fidp->fid_type != P9_FID_NONE);
1377

    
1378
    err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
1379
    if (err < 0) {
1380
        goto out;
1381
    }
1382
    stat_to_qid(&stbuf, &qid);
1383
    if (S_ISDIR(stbuf.st_mode)) {
1384
        err = v9fs_co_opendir(pdu, fidp);
1385
        if (err < 0) {
1386
            goto out;
1387
        }
1388
        fidp->fid_type = P9_FID_DIR;
1389
        err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
1390
        if (err < 0) {
1391
            goto out;
1392
        }
1393
        err += offset;
1394
    } else {
1395
        if (s->proto_version == V9FS_PROTO_2000L) {
1396
            flags = get_dotl_openflags(s, mode);
1397
        } else {
1398
            flags = omode_to_uflags(mode);
1399
        }
1400
        if (is_ro_export(&s->ctx)) {
1401
            if (mode & O_WRONLY || mode & O_RDWR ||
1402
                mode & O_APPEND || mode & O_TRUNC) {
1403
                err = -EROFS;
1404
                goto out;
1405
            }
1406
        }
1407
        err = v9fs_co_open(pdu, fidp, flags);
1408
        if (err < 0) {
1409
            goto out;
1410
        }
1411
        fidp->fid_type = P9_FID_FILE;
1412
        fidp->open_flags = flags;
1413
        if (flags & O_EXCL) {
1414
            /*
1415
             * We let the host file system do O_EXCL check
1416
             * We should not reclaim such fd
1417
             */
1418
            fidp->flags |= FID_NON_RECLAIMABLE;
1419
        }
1420
        iounit = get_iounit(pdu, &fidp->path);
1421
        err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1422
        if (err < 0) {
1423
            goto out;
1424
        }
1425
        err += offset;
1426
    }
1427
    trace_v9fs_open_return(pdu->tag, pdu->id,
1428
                           qid.type, qid.version, qid.path, iounit);
1429
out:
1430
    put_fid(pdu, fidp);
1431
out_nofid:
1432
    complete_pdu(s, pdu, err);
1433
}
1434

    
1435
static void v9fs_lcreate(void *opaque)
1436
{
1437
    int32_t dfid, flags, mode;
1438
    gid_t gid;
1439
    ssize_t err = 0;
1440
    ssize_t offset = 7;
1441
    V9fsString name;
1442
    V9fsFidState *fidp;
1443
    struct stat stbuf;
1444
    V9fsQID qid;
1445
    int32_t iounit;
1446
    V9fsPDU *pdu = opaque;
1447

    
1448
    v9fs_string_init(&name);
1449
    err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
1450
                        &name, &flags, &mode, &gid);
1451
    if (err < 0) {
1452
        goto out_nofid;
1453
    }
1454
    trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1455

    
1456
    fidp = get_fid(pdu, dfid);
1457
    if (fidp == NULL) {
1458
        err = -ENOENT;
1459
        goto out_nofid;
1460
    }
1461

    
1462
    flags = get_dotl_openflags(pdu->s, flags);
1463
    err = v9fs_co_open2(pdu, fidp, &name, gid,
1464
                        flags | O_CREAT, mode, &stbuf);
1465
    if (err < 0) {
1466
        goto out;
1467
    }
1468
    fidp->fid_type = P9_FID_FILE;
1469
    fidp->open_flags = flags;
1470
    if (flags & O_EXCL) {
1471
        /*
1472
         * We let the host file system do O_EXCL check
1473
         * We should not reclaim such fd
1474
         */
1475
        fidp->flags |= FID_NON_RECLAIMABLE;
1476
    }
1477
    iounit =  get_iounit(pdu, &fidp->path);
1478
    stat_to_qid(&stbuf, &qid);
1479
    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1480
    if (err < 0) {
1481
        goto out;
1482
    }
1483
    err += offset;
1484
    trace_v9fs_lcreate_return(pdu->tag, pdu->id,
1485
                              qid.type, qid.version, qid.path, iounit);
1486
out:
1487
    put_fid(pdu, fidp);
1488
out_nofid:
1489
    complete_pdu(pdu->s, pdu, err);
1490
    v9fs_string_free(&name);
1491
}
1492

    
1493
static void v9fs_fsync(void *opaque)
1494
{
1495
    int err;
1496
    int32_t fid;
1497
    int datasync;
1498
    size_t offset = 7;
1499
    V9fsFidState *fidp;
1500
    V9fsPDU *pdu = opaque;
1501
    V9fsState *s = pdu->s;
1502

    
1503
    err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1504
    if (err < 0) {
1505
        goto out_nofid;
1506
    }
1507
    trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1508

    
1509
    fidp = get_fid(pdu, fid);
1510
    if (fidp == NULL) {
1511
        err = -ENOENT;
1512
        goto out_nofid;
1513
    }
1514
    err = v9fs_co_fsync(pdu, fidp, datasync);
1515
    if (!err) {
1516
        err = offset;
1517
    }
1518
    put_fid(pdu, fidp);
1519
out_nofid:
1520
    complete_pdu(s, pdu, err);
1521
}
1522

    
1523
static void v9fs_clunk(void *opaque)
1524
{
1525
    int err;
1526
    int32_t fid;
1527
    size_t offset = 7;
1528
    V9fsFidState *fidp;
1529
    V9fsPDU *pdu = opaque;
1530
    V9fsState *s = pdu->s;
1531

    
1532
    err = pdu_unmarshal(pdu, offset, "d", &fid);
1533
    if (err < 0) {
1534
        goto out_nofid;
1535
    }
1536
    trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1537

    
1538
    fidp = clunk_fid(s, fid);
1539
    if (fidp == NULL) {
1540
        err = -ENOENT;
1541
        goto out_nofid;
1542
    }
1543
    /*
1544
     * Bump the ref so that put_fid will
1545
     * free the fid.
1546
     */
1547
    fidp->ref++;
1548
    err = put_fid(pdu, fidp);
1549
    if (!err) {
1550
        err = offset;
1551
    }
1552
out_nofid:
1553
    complete_pdu(s, pdu, err);
1554
}
1555

    
1556
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1557
                           uint64_t off, uint32_t max_count)
1558
{
1559
    ssize_t err;
1560
    size_t offset = 7;
1561
    int read_count;
1562
    int64_t xattr_len;
1563

    
1564
    xattr_len = fidp->fs.xattr.len;
1565
    read_count = xattr_len - off;
1566
    if (read_count > max_count) {
1567
        read_count = max_count;
1568
    } else if (read_count < 0) {
1569
        /*
1570
         * read beyond XATTR value
1571
         */
1572
        read_count = 0;
1573
    }
1574
    err = pdu_marshal(pdu, offset, "d", read_count);
1575
    if (err < 0) {
1576
        return err;
1577
    }
1578
    offset += err;
1579
    err = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
1580
                    ((char *)fidp->fs.xattr.value) + off,
1581
                    read_count);
1582
    if (err < 0) {
1583
        return err;
1584
    }
1585
    offset += err;
1586
    return offset;
1587
}
1588

    
1589
static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
1590
                                     V9fsFidState *fidp, uint32_t max_count)
1591
{
1592
    V9fsPath path;
1593
    V9fsStat v9stat;
1594
    int len, err = 0;
1595
    int32_t count = 0;
1596
    struct stat stbuf;
1597
    off_t saved_dir_pos;
1598
    struct dirent *dent, *result;
1599

    
1600
    /* save the directory position */
1601
    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1602
    if (saved_dir_pos < 0) {
1603
        return saved_dir_pos;
1604
    }
1605

    
1606
    dent = g_malloc(sizeof(struct dirent));
1607

    
1608
    while (1) {
1609
        v9fs_path_init(&path);
1610
        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
1611
        if (err || !result) {
1612
            break;
1613
        }
1614
        err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
1615
        if (err < 0) {
1616
            goto out;
1617
        }
1618
        err = v9fs_co_lstat(pdu, &path, &stbuf);
1619
        if (err < 0) {
1620
            goto out;
1621
        }
1622
        err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
1623
        if (err < 0) {
1624
            goto out;
1625
        }
1626
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1627
        len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1628
        if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1629
            /* Ran out of buffer. Set dir back to old position and return */
1630
            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1631
            v9fs_stat_free(&v9stat);
1632
            v9fs_path_free(&path);
1633
            g_free(dent);
1634
            return count;
1635
        }
1636
        count += len;
1637
        v9fs_stat_free(&v9stat);
1638
        v9fs_path_free(&path);
1639
        saved_dir_pos = dent->d_off;
1640
    }
1641
out:
1642
    g_free(dent);
1643
    v9fs_path_free(&path);
1644
    if (err < 0) {
1645
        return err;
1646
    }
1647
    return count;
1648
}
1649

    
1650
/*
1651
 * Create a QEMUIOVector for a sub-region of PDU iovecs
1652
 *
1653
 * @qiov:       uninitialized QEMUIOVector
1654
 * @skip:       number of bytes to skip from beginning of PDU
1655
 * @size:       number of bytes to include
1656
 * @is_write:   true - write, false - read
1657
 *
1658
 * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
1659
 * with qemu_iovec_destroy().
1660
 */
1661
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
1662
                                    size_t skip, size_t size,
1663
                                    bool is_write)
1664
{
1665
    QEMUIOVector elem;
1666
    struct iovec *iov;
1667
    unsigned int niov;
1668

    
1669
    if (is_write) {
1670
        iov = pdu->elem.out_sg;
1671
        niov = pdu->elem.out_num;
1672
    } else {
1673
        iov = pdu->elem.in_sg;
1674
        niov = pdu->elem.in_num;
1675
    }
1676

    
1677
    qemu_iovec_init_external(&elem, iov, niov);
1678
    qemu_iovec_init(qiov, niov);
1679
    qemu_iovec_concat(qiov, &elem, skip, size);
1680
}
1681

    
1682
static void v9fs_read(void *opaque)
1683
{
1684
    int32_t fid;
1685
    uint64_t off;
1686
    ssize_t err = 0;
1687
    int32_t count = 0;
1688
    size_t offset = 7;
1689
    uint32_t max_count;
1690
    V9fsFidState *fidp;
1691
    V9fsPDU *pdu = opaque;
1692
    V9fsState *s = pdu->s;
1693

    
1694
    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1695
    if (err < 0) {
1696
        goto out_nofid;
1697
    }
1698
    trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1699

    
1700
    fidp = get_fid(pdu, fid);
1701
    if (fidp == NULL) {
1702
        err = -EINVAL;
1703
        goto out_nofid;
1704
    }
1705
    if (fidp->fid_type == P9_FID_DIR) {
1706

    
1707
        if (off == 0) {
1708
            v9fs_co_rewinddir(pdu, fidp);
1709
        }
1710
        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
1711
        if (count < 0) {
1712
            err = count;
1713
            goto out;
1714
        }
1715
        err = pdu_marshal(pdu, offset, "d", count);
1716
        if (err < 0) {
1717
            goto out;
1718
        }
1719
        err += offset + count;
1720
    } else if (fidp->fid_type == P9_FID_FILE) {
1721
        QEMUIOVector qiov_full;
1722
        QEMUIOVector qiov;
1723
        int32_t len;
1724

    
1725
        v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
1726
        qemu_iovec_init(&qiov, qiov_full.niov);
1727
        do {
1728
            qemu_iovec_reset(&qiov);
1729
            qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
1730
            if (0) {
1731
                print_sg(qiov.iov, qiov.niov);
1732
            }
1733
            /* Loop in case of EINTR */
1734
            do {
1735
                len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
1736
                if (len >= 0) {
1737
                    off   += len;
1738
                    count += len;
1739
                }
1740
            } while (len == -EINTR && !pdu->cancelled);
1741
            if (len < 0) {
1742
                /* IO error return the error */
1743
                err = len;
1744
                goto out;
1745
            }
1746
        } while (count < max_count && len > 0);
1747
        err = pdu_marshal(pdu, offset, "d", count);
1748
        if (err < 0) {
1749
            goto out;
1750
        }
1751
        err += offset + count;
1752
        qemu_iovec_destroy(&qiov);
1753
        qemu_iovec_destroy(&qiov_full);
1754
    } else if (fidp->fid_type == P9_FID_XATTR) {
1755
        err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1756
    } else {
1757
        err = -EINVAL;
1758
    }
1759
    trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
1760
out:
1761
    put_fid(pdu, fidp);
1762
out_nofid:
1763
    complete_pdu(s, pdu, err);
1764
}
1765

    
1766
static size_t v9fs_readdir_data_size(V9fsString *name)
1767
{
1768
    /*
1769
     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1770
     * size of type (1) + size of name.size (2) + strlen(name.data)
1771
     */
1772
    return 24 + v9fs_string_size(name);
1773
}
1774

    
1775
static int v9fs_do_readdir(V9fsPDU *pdu,
1776
                           V9fsFidState *fidp, int32_t max_count)
1777
{
1778
    size_t size;
1779
    V9fsQID qid;
1780
    V9fsString name;
1781
    int len, err = 0;
1782
    int32_t count = 0;
1783
    off_t saved_dir_pos;
1784
    struct dirent *dent, *result;
1785

    
1786
    /* save the directory position */
1787
    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1788
    if (saved_dir_pos < 0) {
1789
        return saved_dir_pos;
1790
    }
1791

    
1792
    dent = g_malloc(sizeof(struct dirent));
1793

    
1794
    while (1) {
1795
        err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
1796
        if (err || !result) {
1797
            break;
1798
        }
1799
        v9fs_string_init(&name);
1800
        v9fs_string_sprintf(&name, "%s", dent->d_name);
1801
        if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1802
            /* Ran out of buffer. Set dir back to old position and return */
1803
            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1804
            v9fs_string_free(&name);
1805
            g_free(dent);
1806
            return count;
1807
        }
1808
        /*
1809
         * Fill up just the path field of qid because the client uses
1810
         * only that. To fill the entire qid structure we will have
1811
         * to stat each dirent found, which is expensive
1812
         */
1813
        size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1814
        memcpy(&qid.path, &dent->d_ino, size);
1815
        /* Fill the other fields with dummy values */
1816
        qid.type = 0;
1817
        qid.version = 0;
1818

    
1819
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1820
        len = pdu_marshal(pdu, 11 + count, "Qqbs",
1821
                          &qid, dent->d_off,
1822
                          dent->d_type, &name);
1823
        if (len < 0) {
1824
            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1825
            v9fs_string_free(&name);
1826
            g_free(dent);
1827
            return len;
1828
        }
1829
        count += len;
1830
        v9fs_string_free(&name);
1831
        saved_dir_pos = dent->d_off;
1832
    }
1833
    g_free(dent);
1834
    if (err < 0) {
1835
        return err;
1836
    }
1837
    return count;
1838
}
1839

    
1840
static void v9fs_readdir(void *opaque)
1841
{
1842
    int32_t fid;
1843
    V9fsFidState *fidp;
1844
    ssize_t retval = 0;
1845
    size_t offset = 7;
1846
    uint64_t initial_offset;
1847
    int32_t count;
1848
    uint32_t max_count;
1849
    V9fsPDU *pdu = opaque;
1850
    V9fsState *s = pdu->s;
1851

    
1852
    retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
1853
                           &initial_offset, &max_count);
1854
    if (retval < 0) {
1855
        goto out_nofid;
1856
    }
1857
    trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1858

    
1859
    fidp = get_fid(pdu, fid);
1860
    if (fidp == NULL) {
1861
        retval = -EINVAL;
1862
        goto out_nofid;
1863
    }
1864
    if (!fidp->fs.dir) {
1865
        retval = -EINVAL;
1866
        goto out;
1867
    }
1868
    if (initial_offset == 0) {
1869
        v9fs_co_rewinddir(pdu, fidp);
1870
    } else {
1871
        v9fs_co_seekdir(pdu, fidp, initial_offset);
1872
    }
1873
    count = v9fs_do_readdir(pdu, fidp, max_count);
1874
    if (count < 0) {
1875
        retval = count;
1876
        goto out;
1877
    }
1878
    retval = pdu_marshal(pdu, offset, "d", count);
1879
    if (retval < 0) {
1880
        goto out;
1881
    }
1882
    retval += count + offset;
1883
    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
1884
out:
1885
    put_fid(pdu, fidp);
1886
out_nofid:
1887
    complete_pdu(s, pdu, retval);
1888
}
1889

    
1890
static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1891
                            uint64_t off, uint32_t count,
1892
                            struct iovec *sg, int cnt)
1893
{
1894
    int i, to_copy;
1895
    ssize_t err = 0;
1896
    int write_count;
1897
    int64_t xattr_len;
1898
    size_t offset = 7;
1899

    
1900

    
1901
    xattr_len = fidp->fs.xattr.len;
1902
    write_count = xattr_len - off;
1903
    if (write_count > count) {
1904
        write_count = count;
1905
    } else if (write_count < 0) {
1906
        /*
1907
         * write beyond XATTR value len specified in
1908
         * xattrcreate
1909
         */
1910
        err = -ENOSPC;
1911
        goto out;
1912
    }
1913
    err = pdu_marshal(pdu, offset, "d", write_count);
1914
    if (err < 0) {
1915
        return err;
1916
    }
1917
    err += offset;
1918
    fidp->fs.xattr.copied_len += write_count;
1919
    /*
1920
     * Now copy the content from sg list
1921
     */
1922
    for (i = 0; i < cnt; i++) {
1923
        if (write_count > sg[i].iov_len) {
1924
            to_copy = sg[i].iov_len;
1925
        } else {
1926
            to_copy = write_count;
1927
        }
1928
        memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1929
        /* updating vs->off since we are not using below */
1930
        off += to_copy;
1931
        write_count -= to_copy;
1932
    }
1933
out:
1934
    return err;
1935
}
1936

    
1937
static void v9fs_write(void *opaque)
1938
{
1939
    ssize_t err;
1940
    int32_t fid;
1941
    uint64_t off;
1942
    uint32_t count;
1943
    int32_t len = 0;
1944
    int32_t total = 0;
1945
    size_t offset = 7;
1946
    V9fsFidState *fidp;
1947
    V9fsPDU *pdu = opaque;
1948
    V9fsState *s = pdu->s;
1949
    QEMUIOVector qiov_full;
1950
    QEMUIOVector qiov;
1951

    
1952
    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
1953
    if (err < 0) {
1954
        return complete_pdu(s, pdu, err);
1955
    }
1956
    offset += err;
1957
    v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
1958
    trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
1959

    
1960
    fidp = get_fid(pdu, fid);
1961
    if (fidp == NULL) {
1962
        err = -EINVAL;
1963
        goto out_nofid;
1964
    }
1965
    if (fidp->fid_type == P9_FID_FILE) {
1966
        if (fidp->fs.fd == -1) {
1967
            err = -EINVAL;
1968
            goto out;
1969
        }
1970
    } else if (fidp->fid_type == P9_FID_XATTR) {
1971
        /*
1972
         * setxattr operation
1973
         */
1974
        err = v9fs_xattr_write(s, pdu, fidp, off, count,
1975
                               qiov_full.iov, qiov_full.niov);
1976
        goto out;
1977
    } else {
1978
        err = -EINVAL;
1979
        goto out;
1980
    }
1981
    qemu_iovec_init(&qiov, qiov_full.niov);
1982
    do {
1983
        qemu_iovec_reset(&qiov);
1984
        qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
1985
        if (0) {
1986
            print_sg(qiov.iov, qiov.niov);
1987
        }
1988
        /* Loop in case of EINTR */
1989
        do {
1990
            len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
1991
            if (len >= 0) {
1992
                off   += len;
1993
                total += len;
1994
            }
1995
        } while (len == -EINTR && !pdu->cancelled);
1996
        if (len < 0) {
1997
            /* IO error return the error */
1998
            err = len;
1999
            goto out_qiov;
2000
        }
2001
    } while (total < count && len > 0);
2002

    
2003
    offset = 7;
2004
    err = pdu_marshal(pdu, offset, "d", total);
2005
    if (err < 0) {
2006
        goto out;
2007
    }
2008
    err += offset;
2009
    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
2010
out_qiov:
2011
    qemu_iovec_destroy(&qiov);
2012
out:
2013
    put_fid(pdu, fidp);
2014
out_nofid:
2015
    qemu_iovec_destroy(&qiov_full);
2016
    complete_pdu(s, pdu, err);
2017
}
2018

    
2019
static void v9fs_create(void *opaque)
2020
{
2021
    int32_t fid;
2022
    int err = 0;
2023
    size_t offset = 7;
2024
    V9fsFidState *fidp;
2025
    V9fsQID qid;
2026
    int32_t perm;
2027
    int8_t mode;
2028
    V9fsPath path;
2029
    struct stat stbuf;
2030
    V9fsString name;
2031
    V9fsString extension;
2032
    int iounit;
2033
    V9fsPDU *pdu = opaque;
2034

    
2035
    v9fs_path_init(&path);
2036
    v9fs_string_init(&name);
2037
    v9fs_string_init(&extension);
2038
    err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2039
                        &perm, &mode, &extension);
2040
    if (err < 0) {
2041
        goto out_nofid;
2042
    }
2043
    trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2044

    
2045
    fidp = get_fid(pdu, fid);
2046
    if (fidp == NULL) {
2047
        err = -EINVAL;
2048
        goto out_nofid;
2049
    }
2050
    if (perm & P9_STAT_MODE_DIR) {
2051
        err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
2052
                            fidp->uid, -1, &stbuf);
2053
        if (err < 0) {
2054
            goto out;
2055
        }
2056
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2057
        if (err < 0) {
2058
            goto out;
2059
        }
2060
        v9fs_path_copy(&fidp->path, &path);
2061
        err = v9fs_co_opendir(pdu, fidp);
2062
        if (err < 0) {
2063
            goto out;
2064
        }
2065
        fidp->fid_type = P9_FID_DIR;
2066
    } else if (perm & P9_STAT_MODE_SYMLINK) {
2067
        err = v9fs_co_symlink(pdu, fidp, &name,
2068
                              extension.data, -1 , &stbuf);
2069
        if (err < 0) {
2070
            goto out;
2071
        }
2072
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2073
        if (err < 0) {
2074
            goto out;
2075
        }
2076
        v9fs_path_copy(&fidp->path, &path);
2077
    } else if (perm & P9_STAT_MODE_LINK) {
2078
        int32_t ofid = atoi(extension.data);
2079
        V9fsFidState *ofidp = get_fid(pdu, ofid);
2080
        if (ofidp == NULL) {
2081
            err = -EINVAL;
2082
            goto out;
2083
        }
2084
        err = v9fs_co_link(pdu, ofidp, fidp, &name);
2085
        put_fid(pdu, ofidp);
2086
        if (err < 0) {
2087
            goto out;
2088
        }
2089
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2090
        if (err < 0) {
2091
            fidp->fid_type = P9_FID_NONE;
2092
            goto out;
2093
        }
2094
        v9fs_path_copy(&fidp->path, &path);
2095
        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2096
        if (err < 0) {
2097
            fidp->fid_type = P9_FID_NONE;
2098
            goto out;
2099
        }
2100
    } else if (perm & P9_STAT_MODE_DEVICE) {
2101
        char ctype;
2102
        uint32_t major, minor;
2103
        mode_t nmode = 0;
2104

    
2105
        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2106
            err = -errno;
2107
            goto out;
2108
        }
2109

    
2110
        switch (ctype) {
2111
        case 'c':
2112
            nmode = S_IFCHR;
2113
            break;
2114
        case 'b':
2115
            nmode = S_IFBLK;
2116
            break;
2117
        default:
2118
            err = -EIO;
2119
            goto out;
2120
        }
2121

    
2122
        nmode |= perm & 0777;
2123
        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2124
                            makedev(major, minor), nmode, &stbuf);
2125
        if (err < 0) {
2126
            goto out;
2127
        }
2128
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2129
        if (err < 0) {
2130
            goto out;
2131
        }
2132
        v9fs_path_copy(&fidp->path, &path);
2133
    } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
2134
        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2135
                            0, S_IFIFO | (perm & 0777), &stbuf);
2136
        if (err < 0) {
2137
            goto out;
2138
        }
2139
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2140
        if (err < 0) {
2141
            goto out;
2142
        }
2143
        v9fs_path_copy(&fidp->path, &path);
2144
    } else if (perm & P9_STAT_MODE_SOCKET) {
2145
        err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
2146
                            0, S_IFSOCK | (perm & 0777), &stbuf);
2147
        if (err < 0) {
2148
            goto out;
2149
        }
2150
        err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2151
        if (err < 0) {
2152
            goto out;
2153
        }
2154
        v9fs_path_copy(&fidp->path, &path);
2155
    } else {
2156
        err = v9fs_co_open2(pdu, fidp, &name, -1,
2157
                            omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
2158
        if (err < 0) {
2159
            goto out;
2160
        }
2161
        fidp->fid_type = P9_FID_FILE;
2162
        fidp->open_flags = omode_to_uflags(mode);
2163
        if (fidp->open_flags & O_EXCL) {
2164
            /*
2165
             * We let the host file system do O_EXCL check
2166
             * We should not reclaim such fd
2167
             */
2168
            fidp->flags |= FID_NON_RECLAIMABLE;
2169
        }
2170
    }
2171
    iounit = get_iounit(pdu, &fidp->path);
2172
    stat_to_qid(&stbuf, &qid);
2173
    err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2174
    if (err < 0) {
2175
        goto out;
2176
    }
2177
    err += offset;
2178
    trace_v9fs_create_return(pdu->tag, pdu->id,
2179
                             qid.type, qid.version, qid.path, iounit);
2180
out:
2181
    put_fid(pdu, fidp);
2182
out_nofid:
2183
   complete_pdu(pdu->s, pdu, err);
2184
   v9fs_string_free(&name);
2185
   v9fs_string_free(&extension);
2186
   v9fs_path_free(&path);
2187
}
2188

    
2189
static void v9fs_symlink(void *opaque)
2190
{
2191
    V9fsPDU *pdu = opaque;
2192
    V9fsString name;
2193
    V9fsString symname;
2194
    V9fsFidState *dfidp;
2195
    V9fsQID qid;
2196
    struct stat stbuf;
2197
    int32_t dfid;
2198
    int err = 0;
2199
    gid_t gid;
2200
    size_t offset = 7;
2201

    
2202
    v9fs_string_init(&name);
2203
    v9fs_string_init(&symname);
2204
    err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2205
    if (err < 0) {
2206
        goto out_nofid;
2207
    }
2208
    trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
2209

    
2210
    dfidp = get_fid(pdu, dfid);
2211
    if (dfidp == NULL) {
2212
        err = -EINVAL;
2213
        goto out_nofid;
2214
    }
2215
    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
2216
    if (err < 0) {
2217
        goto out;
2218
    }
2219
    stat_to_qid(&stbuf, &qid);
2220
    err =  pdu_marshal(pdu, offset, "Q", &qid);
2221
    if (err < 0) {
2222
        goto out;
2223
    }
2224
    err += offset;
2225
    trace_v9fs_symlink_return(pdu->tag, pdu->id,
2226
                              qid.type, qid.version, qid.path);
2227
out:
2228
    put_fid(pdu, dfidp);
2229
out_nofid:
2230
    complete_pdu(pdu->s, pdu, err);
2231
    v9fs_string_free(&name);
2232
    v9fs_string_free(&symname);
2233
}
2234

    
2235
static void v9fs_flush(void *opaque)
2236
{
2237
    ssize_t err;
2238
    int16_t tag;
2239
    size_t offset = 7;
2240
    V9fsPDU *cancel_pdu;
2241
    V9fsPDU *pdu = opaque;
2242
    V9fsState *s = pdu->s;
2243

    
2244
    err = pdu_unmarshal(pdu, offset, "w", &tag);
2245
    if (err < 0) {
2246
        complete_pdu(s, pdu, err);
2247
        return;
2248
    }
2249
    trace_v9fs_flush(pdu->tag, pdu->id, tag);
2250

    
2251
    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2252
        if (cancel_pdu->tag == tag) {
2253
            break;
2254
        }
2255
    }
2256
    if (cancel_pdu) {
2257
        cancel_pdu->cancelled = 1;
2258
        /*
2259
         * Wait for pdu to complete.
2260
         */
2261
        qemu_co_queue_wait(&cancel_pdu->complete);
2262
        cancel_pdu->cancelled = 0;
2263
        free_pdu(pdu->s, cancel_pdu);
2264
    }
2265
    complete_pdu(s, pdu, 7);
2266
}
2267

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

    
2278
    v9fs_string_init(&name);
2279
    err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2280
    if (err < 0) {
2281
        goto out_nofid;
2282
    }
2283
    trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
2284

    
2285
    dfidp = get_fid(pdu, dfid);
2286
    if (dfidp == NULL) {
2287
        err = -ENOENT;
2288
        goto out_nofid;
2289
    }
2290

    
2291
    oldfidp = get_fid(pdu, oldfid);
2292
    if (oldfidp == NULL) {
2293
        err = -ENOENT;
2294
        goto out;
2295
    }
2296
    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
2297
    if (!err) {
2298
        err = offset;
2299
    }
2300
out:
2301
    put_fid(pdu, dfidp);
2302
out_nofid:
2303
    v9fs_string_free(&name);
2304
    complete_pdu(s, pdu, err);
2305
}
2306

    
2307
/* Only works with path name based fid */
2308
static void v9fs_remove(void *opaque)
2309
{
2310
    int32_t fid;
2311
    int err = 0;
2312
    size_t offset = 7;
2313
    V9fsFidState *fidp;
2314
    V9fsPDU *pdu = opaque;
2315

    
2316
    err = pdu_unmarshal(pdu, offset, "d", &fid);
2317
    if (err < 0) {
2318
        goto out_nofid;
2319
    }
2320
    trace_v9fs_remove(pdu->tag, pdu->id, fid);
2321

    
2322
    fidp = get_fid(pdu, fid);
2323
    if (fidp == NULL) {
2324
        err = -EINVAL;
2325
        goto out_nofid;
2326
    }
2327
    /* if fs driver is not path based, return EOPNOTSUPP */
2328
    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2329
        err = -EOPNOTSUPP;
2330
        goto out_err;
2331
    }
2332
    /*
2333
     * IF the file is unlinked, we cannot reopen
2334
     * the file later. So don't reclaim fd
2335
     */
2336
    err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
2337
    if (err < 0) {
2338
        goto out_err;
2339
    }
2340
    err = v9fs_co_remove(pdu, &fidp->path);
2341
    if (!err) {
2342
        err = offset;
2343
    }
2344
out_err:
2345
    /* For TREMOVE we need to clunk the fid even on failed remove */
2346
    clunk_fid(pdu->s, fidp->fid);
2347
    put_fid(pdu, fidp);
2348
out_nofid:
2349
    complete_pdu(pdu->s, pdu, err);
2350
}
2351

    
2352
static void v9fs_unlinkat(void *opaque)
2353
{
2354
    int err = 0;
2355
    V9fsString name;
2356
    int32_t dfid, flags;
2357
    size_t offset = 7;
2358
    V9fsPath path;
2359
    V9fsFidState *dfidp;
2360
    V9fsPDU *pdu = opaque;
2361

    
2362
    v9fs_string_init(&name);
2363
    err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2364
    if (err < 0) {
2365
        goto out_nofid;
2366
    }
2367
    dfidp = get_fid(pdu, dfid);
2368
    if (dfidp == NULL) {
2369
        err = -EINVAL;
2370
        goto out_nofid;
2371
    }
2372
    /*
2373
     * IF the file is unlinked, we cannot reopen
2374
     * the file later. So don't reclaim fd
2375
     */
2376
    v9fs_path_init(&path);
2377
    err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
2378
    if (err < 0) {
2379
        goto out_err;
2380
    }
2381
    err = v9fs_mark_fids_unreclaim(pdu, &path);
2382
    if (err < 0) {
2383
        goto out_err;
2384
    }
2385
    err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
2386
    if (!err) {
2387
        err = offset;
2388
    }
2389
out_err:
2390
    put_fid(pdu, dfidp);
2391
    v9fs_path_free(&path);
2392
out_nofid:
2393
    complete_pdu(pdu->s, pdu, err);
2394
    v9fs_string_free(&name);
2395
}
2396

    
2397

    
2398
/* Only works with path name based fid */
2399
static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
2400
                                int32_t newdirfid, V9fsString *name)
2401
{
2402
    char *end;
2403
    int err = 0;
2404
    V9fsPath new_path;
2405
    V9fsFidState *tfidp;
2406
    V9fsState *s = pdu->s;
2407
    V9fsFidState *dirfidp = NULL;
2408
    char *old_name, *new_name;
2409

    
2410
    v9fs_path_init(&new_path);
2411
    if (newdirfid != -1) {
2412
        dirfidp = get_fid(pdu, newdirfid);
2413
        if (dirfidp == NULL) {
2414
            err = -ENOENT;
2415
            goto out_nofid;
2416
        }
2417
        BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2418
        v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
2419
    } else {
2420
        old_name = fidp->path.data;
2421
        end = strrchr(old_name, '/');
2422
        if (end) {
2423
            end++;
2424
        } else {
2425
            end = old_name;
2426
        }
2427
        new_name = g_malloc0(end - old_name + name->size + 1);
2428
        strncat(new_name, old_name, end - old_name);
2429
        strncat(new_name + (end - old_name), name->data, name->size);
2430
        v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
2431
        g_free(new_name);
2432
    }
2433
    err = v9fs_co_rename(pdu, &fidp->path, &new_path);
2434
    if (err < 0) {
2435
        goto out;
2436
    }
2437
    /*
2438
     * Fixup fid's pointing to the old name to
2439
     * start pointing to the new name
2440
     */
2441
    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2442
        if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2443
            /* replace the name */
2444
            v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
2445
        }
2446
    }
2447
out:
2448
    if (dirfidp) {
2449
        put_fid(pdu, dirfidp);
2450
    }
2451
    v9fs_path_free(&new_path);
2452
out_nofid:
2453
    return err;
2454
}
2455

    
2456
/* Only works with path name based fid */
2457
static void v9fs_rename(void *opaque)
2458
{
2459
    int32_t fid;
2460
    ssize_t err = 0;
2461
    size_t offset = 7;
2462
    V9fsString name;
2463
    int32_t newdirfid;
2464
    V9fsFidState *fidp;
2465
    V9fsPDU *pdu = opaque;
2466
    V9fsState *s = pdu->s;
2467

    
2468
    v9fs_string_init(&name);
2469
    err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2470
    if (err < 0) {
2471
        goto out_nofid;
2472
    }
2473
    fidp = get_fid(pdu, fid);
2474
    if (fidp == NULL) {
2475
        err = -ENOENT;
2476
        goto out_nofid;
2477
    }
2478
    BUG_ON(fidp->fid_type != P9_FID_NONE);
2479
    /* if fs driver is not path based, return EOPNOTSUPP */
2480
    if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
2481
        err = -EOPNOTSUPP;
2482
        goto out;
2483
    }
2484
    v9fs_path_write_lock(s);
2485
    err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
2486
    v9fs_path_unlock(s);
2487
    if (!err) {
2488
        err = offset;
2489
    }
2490
out:
2491
    put_fid(pdu, fidp);
2492
out_nofid:
2493
    complete_pdu(s, pdu, err);
2494
    v9fs_string_free(&name);
2495
}
2496

    
2497
static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2498
                               V9fsString *old_name, V9fsPath *newdir,
2499
                               V9fsString *new_name)
2500
{
2501
    V9fsFidState *tfidp;
2502
    V9fsPath oldpath, newpath;
2503
    V9fsState *s = pdu->s;
2504

    
2505

    
2506
    v9fs_path_init(&oldpath);
2507
    v9fs_path_init(&newpath);
2508
    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2509
    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2510

    
2511
    /*
2512
     * Fixup fid's pointing to the old name to
2513
     * start pointing to the new name
2514
     */
2515
    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2516
        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2517
            /* replace the name */
2518
            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2519
        }
2520
    }
2521
    v9fs_path_free(&oldpath);
2522
    v9fs_path_free(&newpath);
2523
}
2524

    
2525
static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
2526
                                  V9fsString *old_name, int32_t newdirfid,
2527
                                  V9fsString *new_name)
2528
{
2529
    int err = 0;
2530
    V9fsState *s = pdu->s;
2531
    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2532

    
2533
    olddirfidp = get_fid(pdu, olddirfid);
2534
    if (olddirfidp == NULL) {
2535
        err = -ENOENT;
2536
        goto out;
2537
    }
2538
    if (newdirfid != -1) {
2539
        newdirfidp = get_fid(pdu, newdirfid);
2540
        if (newdirfidp == NULL) {
2541
            err = -ENOENT;
2542
            goto out;
2543
        }
2544
    } else {
2545
        newdirfidp = get_fid(pdu, olddirfid);
2546
    }
2547

    
2548
    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2549
                           &newdirfidp->path, new_name);
2550
    if (err < 0) {
2551
        goto out;
2552
    }
2553
    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
2554
        /* Only for path based fid  we need to do the below fixup */
2555
        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
2556
                           &newdirfidp->path, new_name);
2557
    }
2558
out:
2559
    if (olddirfidp) {
2560
        put_fid(pdu, olddirfidp);
2561
    }
2562
    if (newdirfidp) {
2563
        put_fid(pdu, newdirfidp);
2564
    }
2565
    return err;
2566
}
2567

    
2568
static void v9fs_renameat(void *opaque)
2569
{
2570
    ssize_t err = 0;
2571
    size_t offset = 7;
2572
    V9fsPDU *pdu = opaque;
2573
    V9fsState *s = pdu->s;
2574
    int32_t olddirfid, newdirfid;
2575
    V9fsString old_name, new_name;
2576

    
2577
    v9fs_string_init(&old_name);
2578
    v9fs_string_init(&new_name);
2579
    err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2580
                        &old_name, &newdirfid, &new_name);
2581
    if (err < 0) {
2582
        goto out_err;
2583
    }
2584

    
2585
    v9fs_path_write_lock(s);
2586
    err = v9fs_complete_renameat(pdu, olddirfid,
2587
                                 &old_name, newdirfid, &new_name);
2588
    v9fs_path_unlock(s);
2589
    if (!err) {
2590
        err = offset;
2591
    }
2592

    
2593
out_err:
2594
    complete_pdu(s, pdu, err);
2595
    v9fs_string_free(&old_name);
2596
    v9fs_string_free(&new_name);
2597
}
2598

    
2599
static void v9fs_wstat(void *opaque)
2600
{
2601
    int32_t fid;
2602
    int err = 0;
2603
    int16_t unused;
2604
    V9fsStat v9stat;
2605
    size_t offset = 7;
2606
    struct stat stbuf;
2607
    V9fsFidState *fidp;
2608
    V9fsPDU *pdu = opaque;
2609
    V9fsState *s = pdu->s;
2610

    
2611
    v9fs_stat_init(&v9stat);
2612
    err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2613
    if (err < 0) {
2614
        goto out_nofid;
2615
    }
2616
    trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2617
                     v9stat.mode, v9stat.atime, v9stat.mtime);
2618

    
2619
    fidp = get_fid(pdu, fid);
2620
    if (fidp == NULL) {
2621
        err = -EINVAL;
2622
        goto out_nofid;
2623
    }
2624
    /* do we need to sync the file? */
2625
    if (donttouch_stat(&v9stat)) {
2626
        err = v9fs_co_fsync(pdu, fidp, 0);
2627
        goto out;
2628
    }
2629
    if (v9stat.mode != -1) {
2630
        uint32_t v9_mode;
2631
        err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
2632
        if (err < 0) {
2633
            goto out;
2634
        }
2635
        v9_mode = stat_to_v9mode(&stbuf);
2636
        if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2637
            (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2638
            /* Attempting to change the type */
2639
            err = -EIO;
2640
            goto out;
2641
        }
2642
        err = v9fs_co_chmod(pdu, &fidp->path,
2643
                            v9mode_to_mode(v9stat.mode,
2644
                                           &v9stat.extension));
2645
        if (err < 0) {
2646
            goto out;
2647
        }
2648
    }
2649
    if (v9stat.mtime != -1 || v9stat.atime != -1) {
2650
        struct timespec times[2];
2651
        if (v9stat.atime != -1) {
2652
            times[0].tv_sec = v9stat.atime;
2653
            times[0].tv_nsec = 0;
2654
        } else {
2655
            times[0].tv_nsec = UTIME_OMIT;
2656
        }
2657
        if (v9stat.mtime != -1) {
2658
            times[1].tv_sec = v9stat.mtime;
2659
            times[1].tv_nsec = 0;
2660
        } else {
2661
            times[1].tv_nsec = UTIME_OMIT;
2662
        }
2663
        err = v9fs_co_utimensat(pdu, &fidp->path, times);
2664
        if (err < 0) {
2665
            goto out;
2666
        }
2667
    }
2668
    if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2669
        err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2670
        if (err < 0) {
2671
            goto out;
2672
        }
2673
    }
2674
    if (v9stat.name.size != 0) {
2675
        err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
2676
        if (err < 0) {
2677
            goto out;
2678
        }
2679
    }
2680
    if (v9stat.length != -1) {
2681
        err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
2682
        if (err < 0) {
2683
            goto out;
2684
        }
2685
    }
2686
    err = offset;
2687
out:
2688
    put_fid(pdu, fidp);
2689
out_nofid:
2690
    v9fs_stat_free(&v9stat);
2691
    complete_pdu(s, pdu, err);
2692
}
2693

    
2694
static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2695
{
2696
    uint32_t f_type;
2697
    uint32_t f_bsize;
2698
    uint64_t f_blocks;
2699
    uint64_t f_bfree;
2700
    uint64_t f_bavail;
2701
    uint64_t f_files;
2702
    uint64_t f_ffree;
2703
    uint64_t fsid_val;
2704
    uint32_t f_namelen;
2705
    size_t offset = 7;
2706
    int32_t bsize_factor;
2707

    
2708
    /*
2709
     * compute bsize factor based on host file system block size
2710
     * and client msize
2711
     */
2712
    bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2713
    if (!bsize_factor) {
2714
        bsize_factor = 1;
2715
    }
2716
    f_type  = stbuf->f_type;
2717
    f_bsize = stbuf->f_bsize;
2718
    f_bsize *= bsize_factor;
2719
    /*
2720
     * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2721
     * adjust(divide) the number of blocks, free blocks and available
2722
     * blocks by bsize factor
2723
     */
2724
    f_blocks = stbuf->f_blocks/bsize_factor;
2725
    f_bfree  = stbuf->f_bfree/bsize_factor;
2726
    f_bavail = stbuf->f_bavail/bsize_factor;
2727
    f_files  = stbuf->f_files;
2728
    f_ffree  = stbuf->f_ffree;
2729
    fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2730
               (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2731
    f_namelen = stbuf->f_namelen;
2732

    
2733
    return pdu_marshal(pdu, offset, "ddqqqqqqd",
2734
                       f_type, f_bsize, f_blocks, f_bfree,
2735
                       f_bavail, f_files, f_ffree,
2736
                       fsid_val, f_namelen);
2737
}
2738

    
2739
static void v9fs_statfs(void *opaque)
2740
{
2741
    int32_t fid;
2742
    ssize_t retval = 0;
2743
    size_t offset = 7;
2744
    V9fsFidState *fidp;
2745
    struct statfs stbuf;
2746
    V9fsPDU *pdu = opaque;
2747
    V9fsState *s = pdu->s;
2748

    
2749
    retval = pdu_unmarshal(pdu, offset, "d", &fid);
2750
    if (retval < 0) {
2751
        goto out_nofid;
2752
    }
2753
    fidp = get_fid(pdu, fid);
2754
    if (fidp == NULL) {
2755
        retval = -ENOENT;
2756
        goto out_nofid;
2757
    }
2758
    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
2759
    if (retval < 0) {
2760
        goto out;
2761
    }
2762
    retval = v9fs_fill_statfs(s, pdu, &stbuf);
2763
    if (retval < 0) {
2764
        goto out;
2765
    }
2766
    retval += offset;
2767
out:
2768
    put_fid(pdu, fidp);
2769
out_nofid:
2770
    complete_pdu(s, pdu, retval);
2771
}
2772

    
2773
static void v9fs_mknod(void *opaque)
2774
{
2775

    
2776
    int mode;
2777
    gid_t gid;
2778
    int32_t fid;
2779
    V9fsQID qid;
2780
    int err = 0;
2781
    int major, minor;
2782
    size_t offset = 7;
2783
    V9fsString name;
2784
    struct stat stbuf;
2785
    V9fsFidState *fidp;
2786
    V9fsPDU *pdu = opaque;
2787
    V9fsState *s = pdu->s;
2788

    
2789
    v9fs_string_init(&name);
2790
    err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2791
                        &major, &minor, &gid);
2792
    if (err < 0) {
2793
        goto out_nofid;
2794
    }
2795
    trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
2796

    
2797
    fidp = get_fid(pdu, fid);
2798
    if (fidp == NULL) {
2799
        err = -ENOENT;
2800
        goto out_nofid;
2801
    }
2802
    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
2803
                        makedev(major, minor), mode, &stbuf);
2804
    if (err < 0) {
2805
        goto out;
2806
    }
2807
    stat_to_qid(&stbuf, &qid);
2808
    err = pdu_marshal(pdu, offset, "Q", &qid);
2809
    if (err < 0) {
2810
        goto out;
2811
    }
2812
    err += offset;
2813
    trace_v9fs_mknod_return(pdu->tag, pdu->id,
2814
                            qid.type, qid.version, qid.path);
2815
out:
2816
    put_fid(pdu, fidp);
2817
out_nofid:
2818
    complete_pdu(s, pdu, err);
2819
    v9fs_string_free(&name);
2820
}
2821

    
2822
/*
2823
 * Implement posix byte range locking code
2824
 * Server side handling of locking code is very simple, because 9p server in
2825
 * QEMU can handle only one client. And most of the lock handling
2826
 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2827
 * do any thing in * qemu 9p server side lock code path.
2828
 * So when a TLOCK request comes, always return success
2829
 */
2830
static void v9fs_lock(void *opaque)
2831
{
2832
    int8_t status;
2833
    V9fsFlock flock;
2834
    size_t offset = 7;
2835
    struct stat stbuf;
2836
    V9fsFidState *fidp;
2837
    int32_t fid, err = 0;
2838
    V9fsPDU *pdu = opaque;
2839
    V9fsState *s = pdu->s;
2840

    
2841
    status = P9_LOCK_ERROR;
2842
    v9fs_string_init(&flock.client_id);
2843
    err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
2844
                        &flock.flags, &flock.start, &flock.length,
2845
                        &flock.proc_id, &flock.client_id);
2846
    if (err < 0) {
2847
        goto out_nofid;
2848
    }
2849
    trace_v9fs_lock(pdu->tag, pdu->id, fid,
2850
                    flock.type, flock.start, flock.length);
2851

    
2852

    
2853
    /* We support only block flag now (that too ignored currently) */
2854
    if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
2855
        err = -EINVAL;
2856
        goto out_nofid;
2857
    }
2858
    fidp = get_fid(pdu, fid);
2859
    if (fidp == NULL) {
2860
        err = -ENOENT;
2861
        goto out_nofid;
2862
    }
2863
    err = v9fs_co_fstat(pdu, fidp, &stbuf);
2864
    if (err < 0) {
2865
        goto out;
2866
    }
2867
    status = P9_LOCK_SUCCESS;
2868
out:
2869
    put_fid(pdu, fidp);
2870
out_nofid:
2871
    err = pdu_marshal(pdu, offset, "b", status);
2872
    if (err > 0) {
2873
        err += offset;
2874
    }
2875
    trace_v9fs_lock_return(pdu->tag, pdu->id, status);
2876
    complete_pdu(s, pdu, err);
2877
    v9fs_string_free(&flock.client_id);
2878
}
2879

    
2880
/*
2881
 * When a TGETLOCK request comes, always return success because all lock
2882
 * handling is done by client's VFS layer.
2883
 */
2884
static void v9fs_getlock(void *opaque)
2885
{
2886
    size_t offset = 7;
2887
    struct stat stbuf;
2888
    V9fsFidState *fidp;
2889
    V9fsGetlock glock;
2890
    int32_t fid, err = 0;
2891
    V9fsPDU *pdu = opaque;
2892
    V9fsState *s = pdu->s;
2893

    
2894
    v9fs_string_init(&glock.client_id);
2895
    err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
2896
                        &glock.start, &glock.length, &glock.proc_id,
2897
                        &glock.client_id);
2898
    if (err < 0) {
2899
        goto out_nofid;
2900
    }
2901
    trace_v9fs_getlock(pdu->tag, pdu->id, fid,
2902
                       glock.type, glock.start, glock.length);
2903

    
2904
    fidp = get_fid(pdu, fid);
2905
    if (fidp == NULL) {
2906
        err = -ENOENT;
2907
        goto out_nofid;
2908
    }
2909
    err = v9fs_co_fstat(pdu, fidp, &stbuf);
2910
    if (err < 0) {
2911
        goto out;
2912
    }
2913
    glock.type = P9_LOCK_TYPE_UNLCK;
2914
    err = pdu_marshal(pdu, offset, "bqqds", glock.type,
2915
                          glock.start, glock.length, glock.proc_id,
2916
                          &glock.client_id);
2917
    if (err < 0) {
2918
        goto out;
2919
    }
2920
    err += offset;
2921
    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
2922
                              glock.length, glock.proc_id);
2923
out:
2924
    put_fid(pdu, fidp);
2925
out_nofid:
2926
    complete_pdu(s, pdu, err);
2927
    v9fs_string_free(&glock.client_id);
2928
}
2929

    
2930
static void v9fs_mkdir(void *opaque)
2931
{
2932
    V9fsPDU *pdu = opaque;
2933
    size_t offset = 7;
2934
    int32_t fid;
2935
    struct stat stbuf;
2936
    V9fsQID qid;
2937
    V9fsString name;
2938
    V9fsFidState *fidp;
2939
    gid_t gid;
2940
    int mode;
2941
    int err = 0;
2942

    
2943
    v9fs_string_init(&name);
2944
    err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2945
    if (err < 0) {
2946
        goto out_nofid;
2947
    }
2948
    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
2949

    
2950
    fidp = get_fid(pdu, fid);
2951
    if (fidp == NULL) {
2952
        err = -ENOENT;
2953
        goto out_nofid;
2954
    }
2955
    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
2956
    if (err < 0) {
2957
        goto out;
2958
    }
2959
    stat_to_qid(&stbuf, &qid);
2960
    err = pdu_marshal(pdu, offset, "Q", &qid);
2961
    if (err < 0) {
2962
        goto out;
2963
    }
2964
    err += offset;
2965
    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
2966
                            qid.type, qid.version, qid.path, err);
2967
out:
2968
    put_fid(pdu, fidp);
2969
out_nofid:
2970
    complete_pdu(pdu->s, pdu, err);
2971
    v9fs_string_free(&name);
2972
}
2973

    
2974
static void v9fs_xattrwalk(void *opaque)
2975
{
2976
    int64_t size;
2977
    V9fsString name;
2978
    ssize_t err = 0;
2979
    size_t offset = 7;
2980
    int32_t fid, newfid;
2981
    V9fsFidState *file_fidp;
2982
    V9fsFidState *xattr_fidp = NULL;
2983
    V9fsPDU *pdu = opaque;
2984
    V9fsState *s = pdu->s;
2985

    
2986
    v9fs_string_init(&name);
2987
    err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2988
    if (err < 0) {
2989
        goto out_nofid;
2990
    }
2991
    trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
2992

    
2993
    file_fidp = get_fid(pdu, fid);
2994
    if (file_fidp == NULL) {
2995
        err = -ENOENT;
2996
        goto out_nofid;
2997
    }
2998
    xattr_fidp = alloc_fid(s, newfid);
2999
    if (xattr_fidp == NULL) {
3000
        err = -EINVAL;
3001
        goto out;
3002
    }
3003
    v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
3004
    if (name.data == NULL) {
3005
        /*
3006
         * listxattr request. Get the size first
3007
         */
3008
        size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
3009
        if (size < 0) {
3010
            err = size;
3011
            clunk_fid(s, xattr_fidp->fid);
3012
            goto out;
3013
        }
3014
        /*
3015
         * Read the xattr value
3016
         */
3017
        xattr_fidp->fs.xattr.len = size;
3018
        xattr_fidp->fid_type = P9_FID_XATTR;
3019
        xattr_fidp->fs.xattr.copied_len = -1;
3020
        if (size) {
3021
            xattr_fidp->fs.xattr.value = g_malloc(size);
3022
            err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
3023
                                     xattr_fidp->fs.xattr.value,
3024
                                     xattr_fidp->fs.xattr.len);
3025
            if (err < 0) {
3026
                clunk_fid(s, xattr_fidp->fid);
3027
                goto out;
3028
            }
3029
        }
3030
        err = pdu_marshal(pdu, offset, "q", size);
3031
        if (err < 0) {
3032
            goto out;
3033
        }
3034
        err += offset;
3035
    } else {
3036
        /*
3037
         * specific xattr fid. We check for xattr
3038
         * presence also collect the xattr size
3039
         */
3040
        size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3041
                                 &name, NULL, 0);
3042
        if (size < 0) {
3043
            err = size;
3044
            clunk_fid(s, xattr_fidp->fid);
3045
            goto out;
3046
        }
3047
        /*
3048
         * Read the xattr value
3049
         */
3050
        xattr_fidp->fs.xattr.len = size;
3051
        xattr_fidp->fid_type = P9_FID_XATTR;
3052
        xattr_fidp->fs.xattr.copied_len = -1;
3053
        if (size) {
3054
            xattr_fidp->fs.xattr.value = g_malloc(size);
3055
            err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
3056
                                    &name, xattr_fidp->fs.xattr.value,
3057
                                    xattr_fidp->fs.xattr.len);
3058
            if (err < 0) {
3059
                clunk_fid(s, xattr_fidp->fid);
3060
                goto out;
3061
            }
3062
        }
3063
        err = pdu_marshal(pdu, offset, "q", size);
3064
        if (err < 0) {
3065
            goto out;
3066
        }
3067
        err += offset;
3068
    }
3069
    trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
3070
out:
3071
    put_fid(pdu, file_fidp);
3072
    if (xattr_fidp) {
3073
        put_fid(pdu, xattr_fidp);
3074
    }
3075
out_nofid:
3076
    complete_pdu(s, pdu, err);
3077
    v9fs_string_free(&name);
3078
}
3079

    
3080
static void v9fs_xattrcreate(void *opaque)
3081
{
3082
    int flags;
3083
    int32_t fid;
3084
    int64_t size;
3085
    ssize_t err = 0;
3086
    V9fsString name;
3087
    size_t offset = 7;
3088
    V9fsFidState *file_fidp;
3089
    V9fsFidState *xattr_fidp;
3090
    V9fsPDU *pdu = opaque;
3091
    V9fsState *s = pdu->s;
3092

    
3093
    v9fs_string_init(&name);
3094
    err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
3095
    if (err < 0) {
3096
        goto out_nofid;
3097
    }
3098
    trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
3099

    
3100
    file_fidp = get_fid(pdu, fid);
3101
    if (file_fidp == NULL) {
3102
        err = -EINVAL;
3103
        goto out_nofid;
3104
    }
3105
    /* Make the file fid point to xattr */
3106
    xattr_fidp = file_fidp;
3107
    xattr_fidp->fid_type = P9_FID_XATTR;
3108
    xattr_fidp->fs.xattr.copied_len = 0;
3109
    xattr_fidp->fs.xattr.len = size;
3110
    xattr_fidp->fs.xattr.flags = flags;
3111
    v9fs_string_init(&xattr_fidp->fs.xattr.name);
3112
    v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
3113
    xattr_fidp->fs.xattr.value = g_malloc(size);
3114
    err = offset;
3115
    put_fid(pdu, file_fidp);
3116
out_nofid:
3117
    complete_pdu(s, pdu, err);
3118
    v9fs_string_free(&name);
3119
}
3120

    
3121
static void v9fs_readlink(void *opaque)
3122
{
3123
    V9fsPDU *pdu = opaque;
3124
    size_t offset = 7;
3125
    V9fsString target;
3126
    int32_t fid;
3127
    int err = 0;
3128
    V9fsFidState *fidp;
3129

    
3130
    err = pdu_unmarshal(pdu, offset, "d", &fid);
3131
    if (err < 0) {
3132
        goto out_nofid;
3133
    }
3134
    trace_v9fs_readlink(pdu->tag, pdu->id, fid);
3135
    fidp = get_fid(pdu, fid);
3136
    if (fidp == NULL) {
3137
        err = -ENOENT;
3138
        goto out_nofid;
3139
    }
3140

    
3141
    v9fs_string_init(&target);
3142
    err = v9fs_co_readlink(pdu, &fidp->path, &target);
3143
    if (err < 0) {
3144
        goto out;
3145
    }
3146
    err = pdu_marshal(pdu, offset, "s", &target);
3147
    if (err < 0) {
3148
        v9fs_string_free(&target);
3149
        goto out;
3150
    }
3151
    err += offset;
3152
    trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
3153
    v9fs_string_free(&target);
3154
out:
3155
    put_fid(pdu, fidp);
3156
out_nofid:
3157
    complete_pdu(pdu->s, pdu, err);
3158
}
3159

    
3160
static CoroutineEntry *pdu_co_handlers[] = {
3161
    [P9_TREADDIR] = v9fs_readdir,
3162
    [P9_TSTATFS] = v9fs_statfs,
3163
    [P9_TGETATTR] = v9fs_getattr,
3164
    [P9_TSETATTR] = v9fs_setattr,
3165
    [P9_TXATTRWALK] = v9fs_xattrwalk,
3166
    [P9_TXATTRCREATE] = v9fs_xattrcreate,
3167
    [P9_TMKNOD] = v9fs_mknod,
3168
    [P9_TRENAME] = v9fs_rename,
3169
    [P9_TLOCK] = v9fs_lock,
3170
    [P9_TGETLOCK] = v9fs_getlock,
3171
    [P9_TRENAMEAT] = v9fs_renameat,
3172
    [P9_TREADLINK] = v9fs_readlink,
3173
    [P9_TUNLINKAT] = v9fs_unlinkat,
3174
    [P9_TMKDIR] = v9fs_mkdir,
3175
    [P9_TVERSION] = v9fs_version,
3176
    [P9_TLOPEN] = v9fs_open,
3177
    [P9_TATTACH] = v9fs_attach,
3178
    [P9_TSTAT] = v9fs_stat,
3179
    [P9_TWALK] = v9fs_walk,
3180
    [P9_TCLUNK] = v9fs_clunk,
3181
    [P9_TFSYNC] = v9fs_fsync,
3182
    [P9_TOPEN] = v9fs_open,
3183
    [P9_TREAD] = v9fs_read,
3184
#if 0
3185
    [P9_TAUTH] = v9fs_auth,
3186
#endif
3187
    [P9_TFLUSH] = v9fs_flush,
3188
    [P9_TLINK] = v9fs_link,
3189
    [P9_TSYMLINK] = v9fs_symlink,
3190
    [P9_TCREATE] = v9fs_create,
3191
    [P9_TLCREATE] = v9fs_lcreate,
3192
    [P9_TWRITE] = v9fs_write,
3193
    [P9_TWSTAT] = v9fs_wstat,
3194
    [P9_TREMOVE] = v9fs_remove,
3195
};
3196

    
3197
static void v9fs_op_not_supp(void *opaque)
3198
{
3199
    V9fsPDU *pdu = opaque;
3200
    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3201
}
3202

    
3203
static void v9fs_fs_ro(void *opaque)
3204
{
3205
    V9fsPDU *pdu = opaque;
3206
    complete_pdu(pdu->s, pdu, -EROFS);
3207
}
3208

    
3209
static inline bool is_read_only_op(V9fsPDU *pdu)
3210
{
3211
    switch (pdu->id) {
3212
    case P9_TREADDIR:
3213
    case P9_TSTATFS:
3214
    case P9_TGETATTR:
3215
    case P9_TXATTRWALK:
3216
    case P9_TLOCK:
3217
    case P9_TGETLOCK:
3218
    case P9_TREADLINK:
3219
    case P9_TVERSION:
3220
    case P9_TLOPEN:
3221
    case P9_TATTACH:
3222
    case P9_TSTAT:
3223
    case P9_TWALK:
3224
    case P9_TCLUNK:
3225
    case P9_TFSYNC:
3226
    case P9_TOPEN:
3227
    case P9_TREAD:
3228
    case P9_TAUTH:
3229
    case P9_TFLUSH:
3230
        return 1;
3231
    default:
3232
        return 0;
3233
    }
3234
}
3235

    
3236
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3237
{
3238
    Coroutine *co;
3239
    CoroutineEntry *handler;
3240

    
3241
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3242
        (pdu_co_handlers[pdu->id] == NULL)) {
3243
        handler = v9fs_op_not_supp;
3244
    } else {
3245
        handler = pdu_co_handlers[pdu->id];
3246
    }
3247

    
3248
    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
3249
        handler = v9fs_fs_ro;
3250
    }
3251
    co = qemu_coroutine_create(handler);
3252
    qemu_coroutine_enter(co, pdu);
3253
}
3254

    
3255
void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3256
{
3257
    V9fsState *s = (V9fsState *)vdev;
3258
    V9fsPDU *pdu;
3259
    ssize_t len;
3260

    
3261
    while ((pdu = alloc_pdu(s)) &&
3262
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3263
        uint8_t *ptr;
3264
        pdu->s = s;
3265
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3266
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3267

    
3268
        ptr = pdu->elem.out_sg[0].iov_base;
3269

    
3270
        pdu->size = le32_to_cpu(*(uint32_t *)ptr);
3271
        pdu->id = ptr[4];
3272
        pdu->tag = le16_to_cpu(*(uint16_t *)(ptr + 5));
3273
        qemu_co_queue_init(&pdu->complete);
3274
        submit_pdu(s, pdu);
3275
    }
3276
    free_pdu(s, pdu);
3277
}
3278

    
3279
static void __attribute__((__constructor__)) virtio_9p_set_fd_limit(void)
3280
{
3281
    struct rlimit rlim;
3282
    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3283
        fprintf(stderr, "Failed to get the resource limit\n");
3284
        exit(1);
3285
    }
3286
    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3287
    open_fd_rc = rlim.rlim_cur/2;
3288
}