Statistics
| Branch: | Revision:

root / hw / 9pfs / virtio-9p.c @ 4d5b97da

History | View | Annotate | Download (84.5 kB)

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

    
14
#include "hw/virtio.h"
15
#include "hw/pc.h"
16
#include "qemu_socket.h"
17
#include "hw/virtio-pci.h"
18
#include "virtio-9p.h"
19
#include "fsdev/qemu-fsdev.h"
20
#include "virtio-9p-xattr.h"
21
#include "virtio-9p-coth.h"
22
#include "trace.h"
23
#include "migration.h"
24

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

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

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

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

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

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

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

    
72
    return ret;
73
}
74

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

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

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

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

    
112
    return oflags;
113
}
114

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

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

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

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

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

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

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

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

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

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

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

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

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

    
272
    return f;
273
}
274

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

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

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

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

    
330
static void put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
331
{
332
    BUG_ON(!fidp->ref);
333
    fidp->ref--;
334
    /*
335
     * Don't free the fid if it is in reclaim list
336
     */
337
    if (!fidp->ref && fidp->clunked) {
338
        if (fidp->fid == pdu->s->root_fid) {
339
            /*
340
             * if the clunked fid is root fid then we
341
             * have unmounted the fs on the client side.
342
             * delete the migration blocker. Ideally, this
343
             * should be hooked to transport close notification
344
             */
345
            if (pdu->s->migration_blocker) {
346
                migrate_del_blocker(pdu->s->migration_blocker);
347
                error_free(pdu->s->migration_blocker);
348
                pdu->s->migration_blocker = NULL;
349
            }
350
        }
351
        free_fid(pdu, fidp);
352
    }
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(&s->vdev, 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 && 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
        if (retval < 0) {
1084
            goto out;
1085
        }
1086
        v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1087
    }
1088
    retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1089
    if (retval < 0) {
1090
        goto out;
1091
    }
1092
    retval += offset;
1093
    trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1094
                              v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1095
                              v9stat_dotl.st_gid);
1096
out:
1097
    put_fid(pdu, fidp);
1098
out_nofid:
1099
    complete_pdu(s, pdu, retval);
1100
}
1101

    
1102
/* Attribute flags */
1103
#define P9_ATTR_MODE       (1 << 0)
1104
#define P9_ATTR_UID        (1 << 1)
1105
#define P9_ATTR_GID        (1 << 2)
1106
#define P9_ATTR_SIZE       (1 << 3)
1107
#define P9_ATTR_ATIME      (1 << 4)
1108
#define P9_ATTR_MTIME      (1 << 5)
1109
#define P9_ATTR_CTIME      (1 << 6)
1110
#define P9_ATTR_ATIME_SET  (1 << 7)
1111
#define P9_ATTR_MTIME_SET  (1 << 8)
1112

    
1113
#define P9_ATTR_MASK    127
1114

    
1115
static void v9fs_setattr(void *opaque)
1116
{
1117
    int err = 0;
1118
    int32_t fid;
1119
    V9fsFidState *fidp;
1120
    size_t offset = 7;
1121
    V9fsIattr v9iattr;
1122
    V9fsPDU *pdu = opaque;
1123
    V9fsState *s = pdu->s;
1124

    
1125
    err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1126
    if (err < 0) {
1127
        goto out_nofid;
1128
    }
1129

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

    
1200
static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1201
{
1202
    int i;
1203
    ssize_t err;
1204
    size_t offset = 7;
1205

    
1206
    err = pdu_marshal(pdu, offset, "w", nwnames);
1207
    if (err < 0) {
1208
        return err;
1209
    }
1210
    offset += err;
1211
    for (i = 0; i < nwnames; i++) {
1212
        err = pdu_marshal(pdu, offset, "Q", &qids[i]);
1213
        if (err < 0) {
1214
            return err;
1215
        }
1216
        offset += err;
1217
    }
1218
    return offset;
1219
}
1220

    
1221
static void v9fs_walk(void *opaque)
1222
{
1223
    int name_idx;
1224
    V9fsQID *qids = NULL;
1225
    int i, err = 0;
1226
    V9fsPath dpath, path;
1227
    uint16_t nwnames;
1228
    struct stat stbuf;
1229
    size_t offset = 7;
1230
    int32_t fid, newfid;
1231
    V9fsString *wnames = NULL;
1232
    V9fsFidState *fidp;
1233
    V9fsFidState *newfidp = NULL;
1234
    V9fsPDU *pdu = opaque;
1235
    V9fsState *s = pdu->s;
1236

    
1237
    err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
1238
    if (err < 0) {
1239
        complete_pdu(s, pdu, err);
1240
        return ;
1241
    }
1242
    offset += err;
1243

    
1244
    trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1245

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

    
1317
static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
1318
{
1319
    struct statfs stbuf;
1320
    int32_t iounit = 0;
1321
    V9fsState *s = pdu->s;
1322

    
1323
    /*
1324
     * iounit should be multiples of f_bsize (host filesystem block size
1325
     * and as well as less than (client msize - P9_IOHDRSZ))
1326
     */
1327
    if (!v9fs_co_statfs(pdu, path, &stbuf)) {
1328
        iounit = stbuf.f_bsize;
1329
        iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1330
    }
1331
    if (!iounit) {
1332
        iounit = s->msize - P9_IOHDRSZ;
1333
    }
1334
    return iounit;
1335
}
1336

    
1337
static void v9fs_open(void *opaque)
1338
{
1339
    int flags;
1340
    int32_t fid;
1341
    int32_t mode;
1342
    V9fsQID qid;
1343
    int iounit = 0;
1344
    ssize_t err = 0;
1345
    size_t offset = 7;
1346
    struct stat stbuf;
1347
    V9fsFidState *fidp;
1348
    V9fsPDU *pdu = opaque;
1349
    V9fsState *s = pdu->s;
1350

    
1351
    if (s->proto_version == V9FS_PROTO_2000L) {
1352
        err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1353
    } else {
1354
        uint8_t modebyte;
1355
        err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
1356
        mode = modebyte;
1357
    }
1358
    if (err < 0) {
1359
        goto out_nofid;
1360
    }
1361
    trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1362

    
1363
    fidp = get_fid(pdu, fid);
1364
    if (fidp == NULL) {
1365
        err = -ENOENT;
1366
        goto out_nofid;
1367
    }
1368
    BUG_ON(fidp->fid_type != P9_FID_NONE);
1369

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

    
1427
static void v9fs_lcreate(void *opaque)
1428
{
1429
    int32_t dfid, flags, mode;
1430
    gid_t gid;
1431
    ssize_t err = 0;
1432
    ssize_t offset = 7;
1433
    V9fsString name;
1434
    V9fsFidState *fidp;
1435
    struct stat stbuf;
1436
    V9fsQID qid;
1437
    int32_t iounit;
1438
    V9fsPDU *pdu = opaque;
1439

    
1440
    v9fs_string_init(&name);
1441
    err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
1442
                        &name, &flags, &mode, &gid);
1443
    if (err < 0) {
1444
        goto out_nofid;
1445
    }
1446
    trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
1447

    
1448
    fidp = get_fid(pdu, dfid);
1449
    if (fidp == NULL) {
1450
        err = -ENOENT;
1451
        goto out_nofid;
1452
    }
1453

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

    
1485
static void v9fs_fsync(void *opaque)
1486
{
1487
    int err;
1488
    int32_t fid;
1489
    int datasync;
1490
    size_t offset = 7;
1491
    V9fsFidState *fidp;
1492
    V9fsPDU *pdu = opaque;
1493
    V9fsState *s = pdu->s;
1494

    
1495
    err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1496
    if (err < 0) {
1497
        goto out_nofid;
1498
    }
1499
    trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1500

    
1501
    fidp = get_fid(pdu, fid);
1502
    if (fidp == NULL) {
1503
        err = -ENOENT;
1504
        goto out_nofid;
1505
    }
1506
    err = v9fs_co_fsync(pdu, fidp, datasync);
1507
    if (!err) {
1508
        err = offset;
1509
    }
1510
    put_fid(pdu, fidp);
1511
out_nofid:
1512
    complete_pdu(s, pdu, err);
1513
}
1514

    
1515
static void v9fs_clunk(void *opaque)
1516
{
1517
    int err;
1518
    int32_t fid;
1519
    size_t offset = 7;
1520
    V9fsFidState *fidp;
1521
    V9fsPDU *pdu = opaque;
1522
    V9fsState *s = pdu->s;
1523

    
1524
    err = pdu_unmarshal(pdu, offset, "d", &fid);
1525
    if (err < 0) {
1526
        goto out_nofid;
1527
    }
1528
    trace_v9fs_clunk(pdu->tag, pdu->id, fid);
1529

    
1530
    fidp = clunk_fid(s, fid);
1531
    if (fidp == NULL) {
1532
        err = -ENOENT;
1533
        goto out_nofid;
1534
    }
1535
    /*
1536
     * Bump the ref so that put_fid will
1537
     * free the fid.
1538
     */
1539
    fidp->ref++;
1540
    err = offset;
1541

    
1542
    put_fid(pdu, fidp);
1543
out_nofid:
1544
    complete_pdu(s, pdu, err);
1545
}
1546

    
1547
static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1548
                           uint64_t off, uint32_t max_count)
1549
{
1550
    ssize_t err;
1551
    size_t offset = 7;
1552
    int read_count;
1553
    int64_t xattr_len;
1554

    
1555
    xattr_len = fidp->fs.xattr.len;
1556
    read_count = xattr_len - off;
1557
    if (read_count > max_count) {
1558
        read_count = max_count;
1559
    } else if (read_count < 0) {
1560
        /*
1561
         * read beyond XATTR value
1562
         */
1563
        read_count = 0;
1564
    }
1565
    err = pdu_marshal(pdu, offset, "d", read_count);
1566
    if (err < 0) {
1567
        return err;
1568
    }
1569
    offset += err;
1570
    err = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
1571
                    ((char *)fidp->fs.xattr.value) + off,
1572
                    read_count);
1573
    if (err < 0) {
1574
        return err;
1575
    }
1576
    offset += err;
1577
    return offset;
1578
}
1579

    
1580
static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
1581
                                     V9fsFidState *fidp, uint32_t max_count)
1582
{
1583
    V9fsPath path;
1584
    V9fsStat v9stat;
1585
    int len, err = 0;
1586
    int32_t count = 0;
1587
    struct stat stbuf;
1588
    off_t saved_dir_pos;
1589
    struct dirent *dent, *result;
1590

    
1591
    /* save the directory position */
1592
    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1593
    if (saved_dir_pos < 0) {
1594
        return saved_dir_pos;
1595
    }
1596

    
1597
    dent = g_malloc(sizeof(struct dirent));
1598

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

    
1641
/*
1642
 * Create a QEMUIOVector for a sub-region of PDU iovecs
1643
 *
1644
 * @qiov:       uninitialized QEMUIOVector
1645
 * @skip:       number of bytes to skip from beginning of PDU
1646
 * @size:       number of bytes to include
1647
 * @is_write:   true - write, false - read
1648
 *
1649
 * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
1650
 * with qemu_iovec_destroy().
1651
 */
1652
static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
1653
                                    size_t skip, size_t size,
1654
                                    bool is_write)
1655
{
1656
    QEMUIOVector elem;
1657
    struct iovec *iov;
1658
    unsigned int niov;
1659

    
1660
    if (is_write) {
1661
        iov = pdu->elem.out_sg;
1662
        niov = pdu->elem.out_num;
1663
    } else {
1664
        iov = pdu->elem.in_sg;
1665
        niov = pdu->elem.in_num;
1666
    }
1667

    
1668
    qemu_iovec_init_external(&elem, iov, niov);
1669
    qemu_iovec_init(qiov, niov);
1670
    qemu_iovec_concat(qiov, &elem, skip, size);
1671
}
1672

    
1673
static void v9fs_read(void *opaque)
1674
{
1675
    int32_t fid;
1676
    uint64_t off;
1677
    ssize_t err = 0;
1678
    int32_t count = 0;
1679
    size_t offset = 7;
1680
    uint32_t max_count;
1681
    V9fsFidState *fidp;
1682
    V9fsPDU *pdu = opaque;
1683
    V9fsState *s = pdu->s;
1684

    
1685
    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1686
    if (err < 0) {
1687
        goto out_nofid;
1688
    }
1689
    trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
1690

    
1691
    fidp = get_fid(pdu, fid);
1692
    if (fidp == NULL) {
1693
        err = -EINVAL;
1694
        goto out_nofid;
1695
    }
1696
    if (fidp->fid_type == P9_FID_DIR) {
1697

    
1698
        if (off == 0) {
1699
            v9fs_co_rewinddir(pdu, fidp);
1700
        }
1701
        count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
1702
        if (count < 0) {
1703
            err = count;
1704
            goto out;
1705
        }
1706
        err = pdu_marshal(pdu, offset, "d", count);
1707
        if (err < 0) {
1708
            goto out;
1709
        }
1710
        err += offset + count;
1711
    } else if (fidp->fid_type == P9_FID_FILE) {
1712
        QEMUIOVector qiov_full;
1713
        QEMUIOVector qiov;
1714
        int32_t len;
1715

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

    
1757
static size_t v9fs_readdir_data_size(V9fsString *name)
1758
{
1759
    /*
1760
     * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1761
     * size of type (1) + size of name.size (2) + strlen(name.data)
1762
     */
1763
    return 24 + v9fs_string_size(name);
1764
}
1765

    
1766
static int v9fs_do_readdir(V9fsPDU *pdu,
1767
                           V9fsFidState *fidp, int32_t max_count)
1768
{
1769
    size_t size;
1770
    V9fsQID qid;
1771
    V9fsString name;
1772
    int len, err = 0;
1773
    int32_t count = 0;
1774
    off_t saved_dir_pos;
1775
    struct dirent *dent, *result;
1776

    
1777
    /* save the directory position */
1778
    saved_dir_pos = v9fs_co_telldir(pdu, fidp);
1779
    if (saved_dir_pos < 0) {
1780
        return saved_dir_pos;
1781
    }
1782

    
1783
    dent = g_malloc(sizeof(struct dirent));
1784

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

    
1810
        /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1811
        len = pdu_marshal(pdu, 11 + count, "Qqbs",
1812
                          &qid, dent->d_off,
1813
                          dent->d_type, &name);
1814
        if (len < 0) {
1815
            v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1816
            v9fs_string_free(&name);
1817
            g_free(dent);
1818
            return len;
1819
        }
1820
        count += len;
1821
        v9fs_string_free(&name);
1822
        saved_dir_pos = dent->d_off;
1823
    }
1824
    g_free(dent);
1825
    if (err < 0) {
1826
        return err;
1827
    }
1828
    return count;
1829
}
1830

    
1831
static void v9fs_readdir(void *opaque)
1832
{
1833
    int32_t fid;
1834
    V9fsFidState *fidp;
1835
    ssize_t retval = 0;
1836
    size_t offset = 7;
1837
    uint64_t initial_offset;
1838
    int32_t count;
1839
    uint32_t max_count;
1840
    V9fsPDU *pdu = opaque;
1841
    V9fsState *s = pdu->s;
1842

    
1843
    retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
1844
                           &initial_offset, &max_count);
1845
    if (retval < 0) {
1846
        goto out_nofid;
1847
    }
1848
    trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1849

    
1850
    fidp = get_fid(pdu, fid);
1851
    if (fidp == NULL) {
1852
        retval = -EINVAL;
1853
        goto out_nofid;
1854
    }
1855
    if (!fidp->fs.dir) {
1856
        retval = -EINVAL;
1857
        goto out;
1858
    }
1859
    if (initial_offset == 0) {
1860
        v9fs_co_rewinddir(pdu, fidp);
1861
    } else {
1862
        v9fs_co_seekdir(pdu, fidp, initial_offset);
1863
    }
1864
    count = v9fs_do_readdir(pdu, fidp, max_count);
1865
    if (count < 0) {
1866
        retval = count;
1867
        goto out;
1868
    }
1869
    retval = pdu_marshal(pdu, offset, "d", count);
1870
    if (retval < 0) {
1871
        goto out;
1872
    }
1873
    retval += count + offset;
1874
    trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
1875
out:
1876
    put_fid(pdu, fidp);
1877
out_nofid:
1878
    complete_pdu(s, pdu, retval);
1879
}
1880

    
1881
static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1882
                            uint64_t off, uint32_t count,
1883
                            struct iovec *sg, int cnt)
1884
{
1885
    int i, to_copy;
1886
    ssize_t err = 0;
1887
    int write_count;
1888
    int64_t xattr_len;
1889
    size_t offset = 7;
1890

    
1891

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

    
1928
static void v9fs_write(void *opaque)
1929
{
1930
    ssize_t err;
1931
    int32_t fid;
1932
    uint64_t off;
1933
    uint32_t count;
1934
    int32_t len = 0;
1935
    int32_t total = 0;
1936
    size_t offset = 7;
1937
    V9fsFidState *fidp;
1938
    V9fsPDU *pdu = opaque;
1939
    V9fsState *s = pdu->s;
1940
    QEMUIOVector qiov_full;
1941
    QEMUIOVector qiov;
1942

    
1943
    err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
1944
    if (err < 0) {
1945
        return complete_pdu(s, pdu, err);
1946
    }
1947
    offset += err;
1948
    v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
1949
    trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
1950

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

    
1994
    offset = 7;
1995
    err = pdu_marshal(pdu, offset, "d", total);
1996
    if (err < 0) {
1997
        goto out;
1998
    }
1999
    err += offset;
2000
    trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
2001
out_qiov:
2002
    qemu_iovec_destroy(&qiov);
2003
out:
2004
    put_fid(pdu, fidp);
2005
out_nofid:
2006
    qemu_iovec_destroy(&qiov_full);
2007
    complete_pdu(s, pdu, err);
2008
}
2009

    
2010
static void v9fs_create(void *opaque)
2011
{
2012
    int32_t fid;
2013
    int err = 0;
2014
    size_t offset = 7;
2015
    V9fsFidState *fidp;
2016
    V9fsQID qid;
2017
    int32_t perm;
2018
    int8_t mode;
2019
    V9fsPath path;
2020
    struct stat stbuf;
2021
    V9fsString name;
2022
    V9fsString extension;
2023
    int iounit;
2024
    V9fsPDU *pdu = opaque;
2025

    
2026
    v9fs_path_init(&path);
2027
    v9fs_string_init(&name);
2028
    v9fs_string_init(&extension);
2029
    err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2030
                        &perm, &mode, &extension);
2031
    if (err < 0) {
2032
        goto out_nofid;
2033
    }
2034
    trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2035

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

    
2096
        if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
2097
            err = -errno;
2098
            goto out;
2099
        }
2100

    
2101
        switch (ctype) {
2102
        case 'c':
2103
            nmode = S_IFCHR;
2104
            break;
2105
        case 'b':
2106
            nmode = S_IFBLK;
2107
            break;
2108
        default:
2109
            err = -EIO;
2110
            goto out;
2111
        }
2112

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

    
2180
static void v9fs_symlink(void *opaque)
2181
{
2182
    V9fsPDU *pdu = opaque;
2183
    V9fsString name;
2184
    V9fsString symname;
2185
    V9fsFidState *dfidp;
2186
    V9fsQID qid;
2187
    struct stat stbuf;
2188
    int32_t dfid;
2189
    int err = 0;
2190
    gid_t gid;
2191
    size_t offset = 7;
2192

    
2193
    v9fs_string_init(&name);
2194
    v9fs_string_init(&symname);
2195
    err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2196
    if (err < 0) {
2197
        goto out_nofid;
2198
    }
2199
    trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
2200

    
2201
    dfidp = get_fid(pdu, dfid);
2202
    if (dfidp == NULL) {
2203
        err = -EINVAL;
2204
        goto out_nofid;
2205
    }
2206
    err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
2207
    if (err < 0) {
2208
        goto out;
2209
    }
2210
    stat_to_qid(&stbuf, &qid);
2211
    err =  pdu_marshal(pdu, offset, "Q", &qid);
2212
    if (err < 0) {
2213
        goto out;
2214
    }
2215
    err += offset;
2216
    trace_v9fs_symlink_return(pdu->tag, pdu->id,
2217
                              qid.type, qid.version, qid.path);
2218
out:
2219
    put_fid(pdu, dfidp);
2220
out_nofid:
2221
    complete_pdu(pdu->s, pdu, err);
2222
    v9fs_string_free(&name);
2223
    v9fs_string_free(&symname);
2224
}
2225

    
2226
static void v9fs_flush(void *opaque)
2227
{
2228
    ssize_t err;
2229
    int16_t tag;
2230
    size_t offset = 7;
2231
    V9fsPDU *cancel_pdu;
2232
    V9fsPDU *pdu = opaque;
2233
    V9fsState *s = pdu->s;
2234

    
2235
    err = pdu_unmarshal(pdu, offset, "w", &tag);
2236
    if (err < 0) {
2237
        complete_pdu(s, pdu, err);
2238
        return;
2239
    }
2240
    trace_v9fs_flush(pdu->tag, pdu->id, tag);
2241

    
2242
    QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2243
        if (cancel_pdu->tag == tag) {
2244
            break;
2245
        }
2246
    }
2247
    if (cancel_pdu) {
2248
        cancel_pdu->cancelled = 1;
2249
        /*
2250
         * Wait for pdu to complete.
2251
         */
2252
        qemu_co_queue_wait(&cancel_pdu->complete);
2253
        cancel_pdu->cancelled = 0;
2254
        free_pdu(pdu->s, cancel_pdu);
2255
    }
2256
    complete_pdu(s, pdu, 7);
2257
}
2258

    
2259
static void v9fs_link(void *opaque)
2260
{
2261
    V9fsPDU *pdu = opaque;
2262
    V9fsState *s = pdu->s;
2263
    int32_t dfid, oldfid;
2264
    V9fsFidState *dfidp, *oldfidp;
2265
    V9fsString name;
2266
    size_t offset = 7;
2267
    int err = 0;
2268

    
2269
    v9fs_string_init(&name);
2270
    err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2271
    if (err < 0) {
2272
        goto out_nofid;
2273
    }
2274
    trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
2275

    
2276
    dfidp = get_fid(pdu, dfid);
2277
    if (dfidp == NULL) {
2278
        err = -ENOENT;
2279
        goto out_nofid;
2280
    }
2281

    
2282
    oldfidp = get_fid(pdu, oldfid);
2283
    if (oldfidp == NULL) {
2284
        err = -ENOENT;
2285
        goto out;
2286
    }
2287
    err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
2288
    if (!err) {
2289
        err = offset;
2290
    }
2291
out:
2292
    put_fid(pdu, dfidp);
2293
out_nofid:
2294
    v9fs_string_free(&name);
2295
    complete_pdu(s, pdu, err);
2296
}
2297

    
2298
/* Only works with path name based fid */
2299
static void v9fs_remove(void *opaque)
2300
{
2301
    int32_t fid;
2302
    int err = 0;
2303
    size_t offset = 7;
2304
    V9fsFidState *fidp;
2305
    V9fsPDU *pdu = opaque;
2306

    
2307
    err = pdu_unmarshal(pdu, offset, "d", &fid);
2308
    if (err < 0) {
2309
        goto out_nofid;
2310
    }
2311
    trace_v9fs_remove(pdu->tag, pdu->id, fid);
2312

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

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

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

    
2388

    
2389
/* Only works with path name based fid */
2390
static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
2391
                                int32_t newdirfid, V9fsString *name)
2392
{
2393
    char *end;
2394
    int err = 0;
2395
    V9fsPath new_path;
2396
    V9fsFidState *tfidp;
2397
    V9fsState *s = pdu->s;
2398
    V9fsFidState *dirfidp = NULL;
2399
    char *old_name, *new_name;
2400

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

    
2447
/* Only works with path name based fid */
2448
static void v9fs_rename(void *opaque)
2449
{
2450
    int32_t fid;
2451
    ssize_t err = 0;
2452
    size_t offset = 7;
2453
    V9fsString name;
2454
    int32_t newdirfid;
2455
    V9fsFidState *fidp;
2456
    V9fsPDU *pdu = opaque;
2457
    V9fsState *s = pdu->s;
2458

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

    
2488
static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2489
                               V9fsString *old_name, V9fsPath *newdir,
2490
                               V9fsString *new_name)
2491
{
2492
    V9fsFidState *tfidp;
2493
    V9fsPath oldpath, newpath;
2494
    V9fsState *s = pdu->s;
2495

    
2496

    
2497
    v9fs_path_init(&oldpath);
2498
    v9fs_path_init(&newpath);
2499
    v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2500
    v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2501

    
2502
    /*
2503
     * Fixup fid's pointing to the old name to
2504
     * start pointing to the new name
2505
     */
2506
    for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2507
        if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2508
            /* replace the name */
2509
            v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2510
        }
2511
    }
2512
    v9fs_path_free(&oldpath);
2513
    v9fs_path_free(&newpath);
2514
}
2515

    
2516
static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
2517
                                  V9fsString *old_name, int32_t newdirfid,
2518
                                  V9fsString *new_name)
2519
{
2520
    int err = 0;
2521
    V9fsState *s = pdu->s;
2522
    V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2523

    
2524
    olddirfidp = get_fid(pdu, olddirfid);
2525
    if (olddirfidp == NULL) {
2526
        err = -ENOENT;
2527
        goto out;
2528
    }
2529
    if (newdirfid != -1) {
2530
        newdirfidp = get_fid(pdu, newdirfid);
2531
        if (newdirfidp == NULL) {
2532
            err = -ENOENT;
2533
            goto out;
2534
        }
2535
    } else {
2536
        newdirfidp = get_fid(pdu, olddirfid);
2537
    }
2538

    
2539
    err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2540
                           &newdirfidp->path, new_name);
2541
    if (err < 0) {
2542
        goto out;
2543
    }
2544
    if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
2545
        /* Only for path based fid  we need to do the below fixup */
2546
        v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
2547
                           &newdirfidp->path, new_name);
2548
    }
2549
out:
2550
    if (olddirfidp) {
2551
        put_fid(pdu, olddirfidp);
2552
    }
2553
    if (newdirfidp) {
2554
        put_fid(pdu, newdirfidp);
2555
    }
2556
    return err;
2557
}
2558

    
2559
static void v9fs_renameat(void *opaque)
2560
{
2561
    ssize_t err = 0;
2562
    size_t offset = 7;
2563
    V9fsPDU *pdu = opaque;
2564
    V9fsState *s = pdu->s;
2565
    int32_t olddirfid, newdirfid;
2566
    V9fsString old_name, new_name;
2567

    
2568
    v9fs_string_init(&old_name);
2569
    v9fs_string_init(&new_name);
2570
    err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2571
                        &old_name, &newdirfid, &new_name);
2572
    if (err < 0) {
2573
        goto out_err;
2574
    }
2575

    
2576
    v9fs_path_write_lock(s);
2577
    err = v9fs_complete_renameat(pdu, olddirfid,
2578
                                 &old_name, newdirfid, &new_name);
2579
    v9fs_path_unlock(s);
2580
    if (!err) {
2581
        err = offset;
2582
    }
2583

    
2584
out_err:
2585
    complete_pdu(s, pdu, err);
2586
    v9fs_string_free(&old_name);
2587
    v9fs_string_free(&new_name);
2588
}
2589

    
2590
static void v9fs_wstat(void *opaque)
2591
{
2592
    int32_t fid;
2593
    int err = 0;
2594
    int16_t unused;
2595
    V9fsStat v9stat;
2596
    size_t offset = 7;
2597
    struct stat stbuf;
2598
    V9fsFidState *fidp;
2599
    V9fsPDU *pdu = opaque;
2600
    V9fsState *s = pdu->s;
2601

    
2602
    v9fs_stat_init(&v9stat);
2603
    err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2604
    if (err < 0) {
2605
        goto out_nofid;
2606
    }
2607
    trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2608
                     v9stat.mode, v9stat.atime, v9stat.mtime);
2609

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

    
2685
static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2686
{
2687
    uint32_t f_type;
2688
    uint32_t f_bsize;
2689
    uint64_t f_blocks;
2690
    uint64_t f_bfree;
2691
    uint64_t f_bavail;
2692
    uint64_t f_files;
2693
    uint64_t f_ffree;
2694
    uint64_t fsid_val;
2695
    uint32_t f_namelen;
2696
    size_t offset = 7;
2697
    int32_t bsize_factor;
2698

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

    
2724
    return pdu_marshal(pdu, offset, "ddqqqqqqd",
2725
                       f_type, f_bsize, f_blocks, f_bfree,
2726
                       f_bavail, f_files, f_ffree,
2727
                       fsid_val, f_namelen);
2728
}
2729

    
2730
static void v9fs_statfs(void *opaque)
2731
{
2732
    int32_t fid;
2733
    ssize_t retval = 0;
2734
    size_t offset = 7;
2735
    V9fsFidState *fidp;
2736
    struct statfs stbuf;
2737
    V9fsPDU *pdu = opaque;
2738
    V9fsState *s = pdu->s;
2739

    
2740
    retval = pdu_unmarshal(pdu, offset, "d", &fid);
2741
    if (retval < 0) {
2742
        goto out_nofid;
2743
    }
2744
    fidp = get_fid(pdu, fid);
2745
    if (fidp == NULL) {
2746
        retval = -ENOENT;
2747
        goto out_nofid;
2748
    }
2749
    retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
2750
    if (retval < 0) {
2751
        goto out;
2752
    }
2753
    retval = v9fs_fill_statfs(s, pdu, &stbuf);
2754
    if (retval < 0) {
2755
        goto out;
2756
    }
2757
    retval += offset;
2758
out:
2759
    put_fid(pdu, fidp);
2760
out_nofid:
2761
    complete_pdu(s, pdu, retval);
2762
}
2763

    
2764
static void v9fs_mknod(void *opaque)
2765
{
2766

    
2767
    int mode;
2768
    gid_t gid;
2769
    int32_t fid;
2770
    V9fsQID qid;
2771
    int err = 0;
2772
    int major, minor;
2773
    size_t offset = 7;
2774
    V9fsString name;
2775
    struct stat stbuf;
2776
    V9fsFidState *fidp;
2777
    V9fsPDU *pdu = opaque;
2778
    V9fsState *s = pdu->s;
2779

    
2780
    v9fs_string_init(&name);
2781
    err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2782
                        &major, &minor, &gid);
2783
    if (err < 0) {
2784
        goto out_nofid;
2785
    }
2786
    trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
2787

    
2788
    fidp = get_fid(pdu, fid);
2789
    if (fidp == NULL) {
2790
        err = -ENOENT;
2791
        goto out_nofid;
2792
    }
2793
    err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
2794
                        makedev(major, minor), mode, &stbuf);
2795
    if (err < 0) {
2796
        goto out;
2797
    }
2798
    stat_to_qid(&stbuf, &qid);
2799
    err = pdu_marshal(pdu, offset, "Q", &qid);
2800
    if (err < 0) {
2801
        goto out;
2802
    }
2803
    err += offset;
2804
    trace_v9fs_mknod_return(pdu->tag, pdu->id,
2805
                            qid.type, qid.version, qid.path);
2806
out:
2807
    put_fid(pdu, fidp);
2808
out_nofid:
2809
    complete_pdu(s, pdu, err);
2810
    v9fs_string_free(&name);
2811
}
2812

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

    
2832
    status = P9_LOCK_ERROR;
2833
    v9fs_string_init(&flock.client_id);
2834
    err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
2835
                        &flock.flags, &flock.start, &flock.length,
2836
                        &flock.proc_id, &flock.client_id);
2837
    if (err < 0) {
2838
        goto out_nofid;
2839
    }
2840
    trace_v9fs_lock(pdu->tag, pdu->id, fid,
2841
                    flock.type, flock.start, flock.length);
2842

    
2843

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

    
2871
/*
2872
 * When a TGETLOCK request comes, always return success because all lock
2873
 * handling is done by client's VFS layer.
2874
 */
2875
static void v9fs_getlock(void *opaque)
2876
{
2877
    size_t offset = 7;
2878
    struct stat stbuf;
2879
    V9fsFidState *fidp;
2880
    V9fsGetlock glock;
2881
    int32_t fid, err = 0;
2882
    V9fsPDU *pdu = opaque;
2883
    V9fsState *s = pdu->s;
2884

    
2885
    v9fs_string_init(&glock.client_id);
2886
    err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
2887
                        &glock.start, &glock.length, &glock.proc_id,
2888
                        &glock.client_id);
2889
    if (err < 0) {
2890
        goto out_nofid;
2891
    }
2892
    trace_v9fs_getlock(pdu->tag, pdu->id, fid,
2893
                       glock.type, glock.start, glock.length);
2894

    
2895
    fidp = get_fid(pdu, fid);
2896
    if (fidp == NULL) {
2897
        err = -ENOENT;
2898
        goto out_nofid;
2899
    }
2900
    err = v9fs_co_fstat(pdu, fidp, &stbuf);
2901
    if (err < 0) {
2902
        goto out;
2903
    }
2904
    glock.type = P9_LOCK_TYPE_UNLCK;
2905
    err = pdu_marshal(pdu, offset, "bqqds", glock.type,
2906
                          glock.start, glock.length, glock.proc_id,
2907
                          &glock.client_id);
2908
    if (err < 0) {
2909
        goto out;
2910
    }
2911
    err += offset;
2912
    trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
2913
                              glock.length, glock.proc_id);
2914
out:
2915
    put_fid(pdu, fidp);
2916
out_nofid:
2917
    complete_pdu(s, pdu, err);
2918
    v9fs_string_free(&glock.client_id);
2919
}
2920

    
2921
static void v9fs_mkdir(void *opaque)
2922
{
2923
    V9fsPDU *pdu = opaque;
2924
    size_t offset = 7;
2925
    int32_t fid;
2926
    struct stat stbuf;
2927
    V9fsQID qid;
2928
    V9fsString name;
2929
    V9fsFidState *fidp;
2930
    gid_t gid;
2931
    int mode;
2932
    int err = 0;
2933

    
2934
    v9fs_string_init(&name);
2935
    err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2936
    if (err < 0) {
2937
        goto out_nofid;
2938
    }
2939
    trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
2940

    
2941
    fidp = get_fid(pdu, fid);
2942
    if (fidp == NULL) {
2943
        err = -ENOENT;
2944
        goto out_nofid;
2945
    }
2946
    err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
2947
    if (err < 0) {
2948
        goto out;
2949
    }
2950
    stat_to_qid(&stbuf, &qid);
2951
    err = pdu_marshal(pdu, offset, "Q", &qid);
2952
    if (err < 0) {
2953
        goto out;
2954
    }
2955
    err += offset;
2956
    trace_v9fs_mkdir_return(pdu->tag, pdu->id,
2957
                            qid.type, qid.version, qid.path, err);
2958
out:
2959
    put_fid(pdu, fidp);
2960
out_nofid:
2961
    complete_pdu(pdu->s, pdu, err);
2962
    v9fs_string_free(&name);
2963
}
2964

    
2965
static void v9fs_xattrwalk(void *opaque)
2966
{
2967
    int64_t size;
2968
    V9fsString name;
2969
    ssize_t err = 0;
2970
    size_t offset = 7;
2971
    int32_t fid, newfid;
2972
    V9fsFidState *file_fidp;
2973
    V9fsFidState *xattr_fidp = NULL;
2974
    V9fsPDU *pdu = opaque;
2975
    V9fsState *s = pdu->s;
2976

    
2977
    v9fs_string_init(&name);
2978
    err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2979
    if (err < 0) {
2980
        goto out_nofid;
2981
    }
2982
    trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
2983

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

    
3071
static void v9fs_xattrcreate(void *opaque)
3072
{
3073
    int flags;
3074
    int32_t fid;
3075
    int64_t size;
3076
    ssize_t err = 0;
3077
    V9fsString name;
3078
    size_t offset = 7;
3079
    V9fsFidState *file_fidp;
3080
    V9fsFidState *xattr_fidp;
3081
    V9fsPDU *pdu = opaque;
3082
    V9fsState *s = pdu->s;
3083

    
3084
    v9fs_string_init(&name);
3085
    err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
3086
    if (err < 0) {
3087
        goto out_nofid;
3088
    }
3089
    trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
3090

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

    
3116
static void v9fs_readlink(void *opaque)
3117
{
3118
    V9fsPDU *pdu = opaque;
3119
    size_t offset = 7;
3120
    V9fsString target;
3121
    int32_t fid;
3122
    int err = 0;
3123
    V9fsFidState *fidp;
3124

    
3125
    err = pdu_unmarshal(pdu, offset, "d", &fid);
3126
    if (err < 0) {
3127
        goto out_nofid;
3128
    }
3129
    trace_v9fs_readlink(pdu->tag, pdu->id, fid);
3130
    fidp = get_fid(pdu, fid);
3131
    if (fidp == NULL) {
3132
        err = -ENOENT;
3133
        goto out_nofid;
3134
    }
3135

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

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

    
3192
static void v9fs_op_not_supp(void *opaque)
3193
{
3194
    V9fsPDU *pdu = opaque;
3195
    complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
3196
}
3197

    
3198
static void v9fs_fs_ro(void *opaque)
3199
{
3200
    V9fsPDU *pdu = opaque;
3201
    complete_pdu(pdu->s, pdu, -EROFS);
3202
}
3203

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

    
3231
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
3232
{
3233
    Coroutine *co;
3234
    CoroutineEntry *handler;
3235

    
3236
    if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3237
        (pdu_co_handlers[pdu->id] == NULL)) {
3238
        handler = v9fs_op_not_supp;
3239
    } else {
3240
        handler = pdu_co_handlers[pdu->id];
3241
    }
3242

    
3243
    if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
3244
        handler = v9fs_fs_ro;
3245
    }
3246
    co = qemu_coroutine_create(handler);
3247
    qemu_coroutine_enter(co, pdu);
3248
}
3249

    
3250
void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
3251
{
3252
    V9fsState *s = (V9fsState *)vdev;
3253
    V9fsPDU *pdu;
3254
    ssize_t len;
3255

    
3256
    while ((pdu = alloc_pdu(s)) &&
3257
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
3258
        uint8_t *ptr;
3259
        pdu->s = s;
3260
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
3261
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
3262

    
3263
        ptr = pdu->elem.out_sg[0].iov_base;
3264

    
3265
        pdu->size = le32_to_cpu(*(uint32_t *)ptr);
3266
        pdu->id = ptr[4];
3267
        pdu->tag = le16_to_cpu(*(uint16_t *)(ptr + 5));
3268
        qemu_co_queue_init(&pdu->complete);
3269
        submit_pdu(s, pdu);
3270
    }
3271
    free_pdu(s, pdu);
3272
}
3273

    
3274
void virtio_9p_set_fd_limit(void)
3275
{
3276
    struct rlimit rlim;
3277
    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3278
        fprintf(stderr, "Failed to get the resource limit\n");
3279
        exit(1);
3280
    }
3281
    open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3282
    open_fd_rc = rlim.rlim_cur/2;
3283
}