]> git.proxmox.com Git - mirror_qemu.git/blame - hw/9pfs/virtio-9p.c
9pfs: factor out virtio_9p_push_and_notify
[mirror_qemu.git] / hw / 9pfs / virtio-9p.c
CommitLineData
9f107513
AL
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
0d09e41a
PB
14#include "hw/virtio/virtio.h"
15#include "hw/i386/pc.h"
d49b6836 16#include "qemu/error-report.h"
cd4bfbb2 17#include "qemu/iov.h"
1de7afc9 18#include "qemu/sockets.h"
9f107513
AL
19#include "virtio-9p.h"
20#include "fsdev/qemu-fsdev.h"
267ae092 21#include "9p-xattr.h"
fe52840c 22#include "coth.h"
c572f23a 23#include "trace.h"
caf71f86 24#include "migration/migration.h"
9f107513 25
7a462745
AK
26int open_fd_hw;
27int total_open_fd;
28static int open_fd_rc;
9f107513 29
fac4f111
VJ
30enum {
31 Oread = 0x00,
32 Owrite = 0x01,
33 Ordwr = 0x02,
34 Oexec = 0x03,
35 Oexcl = 0x04,
36 Otrunc = 0x10,
37 Orexec = 0x20,
38 Orclose = 0x40,
39 Oappend = 0x80,
40};
41
0e2082d9
WL
42ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
43{
44 ssize_t ret;
45 va_list ap;
46
47 va_start(ap, fmt);
fe9fa96d 48 ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap);
0e2082d9
WL
49 va_end(ap);
50
51 return ret;
52}
53
54ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
55{
56 ssize_t ret;
57 va_list ap;
58
59 va_start(ap, fmt);
fe9fa96d 60 ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap);
0e2082d9
WL
61 va_end(ap);
62
63 return ret;
64}
65
f657b17a
WL
66static void pdu_push_and_notify(V9fsPDU *pdu)
67{
0d3716b4 68 virtio_9p_push_and_notify(pdu);
f657b17a
WL
69}
70
fac4f111
VJ
71static int omode_to_uflags(int8_t mode)
72{
73 int ret = 0;
74
75 switch (mode & 3) {
76 case Oread:
77 ret = O_RDONLY;
78 break;
79 case Ordwr:
80 ret = O_RDWR;
81 break;
82 case Owrite:
83 ret = O_WRONLY;
84 break;
85 case Oexec:
86 ret = O_RDONLY;
87 break;
88 }
89
90 if (mode & Otrunc) {
91 ret |= O_TRUNC;
92 }
93
94 if (mode & Oappend) {
95 ret |= O_APPEND;
96 }
97
98 if (mode & Oexcl) {
99 ret |= O_EXCL;
100 }
101
102 return ret;
103}
104
9844081b
MK
105struct dotl_openflag_map {
106 int dotl_flag;
107 int open_flag;
108};
109
110static int dotl_to_open_flags(int flags)
111{
112 int i;
113 /*
114 * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
115 * and P9_DOTL_NOACCESS
116 */
117 int oflags = flags & O_ACCMODE;
118
119 struct dotl_openflag_map dotl_oflag_map[] = {
120 { P9_DOTL_CREATE, O_CREAT },
121 { P9_DOTL_EXCL, O_EXCL },
122 { P9_DOTL_NOCTTY , O_NOCTTY },
123 { P9_DOTL_TRUNC, O_TRUNC },
124 { P9_DOTL_APPEND, O_APPEND },
125 { P9_DOTL_NONBLOCK, O_NONBLOCK } ,
126 { P9_DOTL_DSYNC, O_DSYNC },
127 { P9_DOTL_FASYNC, FASYNC },
128 { P9_DOTL_DIRECT, O_DIRECT },
129 { P9_DOTL_LARGEFILE, O_LARGEFILE },
130 { P9_DOTL_DIRECTORY, O_DIRECTORY },
131 { P9_DOTL_NOFOLLOW, O_NOFOLLOW },
132 { P9_DOTL_NOATIME, O_NOATIME },
133 { P9_DOTL_SYNC, O_SYNC },
134 };
135
136 for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
137 if (flags & dotl_oflag_map[i].dotl_flag) {
138 oflags |= dotl_oflag_map[i].open_flag;
139 }
140 }
141
142 return oflags;
143}
144
758e8e38 145void cred_init(FsCred *credp)
131dcb25 146{
758e8e38
VJ
147 credp->fc_uid = -1;
148 credp->fc_gid = -1;
149 credp->fc_mode = -1;
150 credp->fc_rdev = -1;
131dcb25
AL
151}
152
d3ab98e6
AK
153static int get_dotl_openflags(V9fsState *s, int oflags)
154{
155 int flags;
156 /*
157 * Filter the client open flags
158 */
9844081b
MK
159 flags = dotl_to_open_flags(oflags);
160 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
d3ab98e6
AK
161 /*
162 * Ignore direct disk access hint until the server supports it.
163 */
164 flags &= ~O_DIRECT;
165 return flags;
166}
167
2289be19
AK
168void v9fs_path_init(V9fsPath *path)
169{
170 path->data = NULL;
171 path->size = 0;
172}
173
174void v9fs_path_free(V9fsPath *path)
175{
176 g_free(path->data);
177 path->data = NULL;
178 path->size = 0;
179}
180
181void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs)
182{
183 v9fs_path_free(lhs);
184 lhs->data = g_malloc(rhs->size);
185 memcpy(lhs->data, rhs->data, rhs->size);
186 lhs->size = rhs->size;
187}
188
189int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath,
190 const char *name, V9fsPath *path)
191{
192 int err;
193 err = s->ops->name_to_path(&s->ctx, dirpath, name, path);
194 if (err < 0) {
195 err = -errno;
196 }
197 return err;
198}
199
936532a4
MN
200/*
201 * Return TRUE if s1 is an ancestor of s2.
202 *
203 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
204 * As a special case, We treat s1 as ancestor of s2 if they are same!
205 */
2289be19 206static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2)
936532a4 207{
2289be19
AK
208 if (!strncmp(s1->data, s2->data, s1->size - 1)) {
209 if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') {
936532a4
MN
210 return 1;
211 }
212 }
213 return 0;
214}
215
a03f7874
AL
216static size_t v9fs_string_size(V9fsString *str)
217{
218 return str->size;
219}
220
b9cb88b0
AK
221/*
222 * returns 0 if fid got re-opened, 1 if not, < 0 on error */
bccacf6c 223static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f)
b9cb88b0
AK
224{
225 int err = 1;
226 if (f->fid_type == P9_FID_FILE) {
227 if (f->fs.fd == -1) {
228 do {
bccacf6c
AK
229 err = v9fs_co_open(pdu, f, f->open_flags);
230 } while (err == -EINTR && !pdu->cancelled);
b9cb88b0
AK
231 }
232 } else if (f->fid_type == P9_FID_DIR) {
233 if (f->fs.dir == NULL) {
234 do {
bccacf6c
AK
235 err = v9fs_co_opendir(pdu, f);
236 } while (err == -EINTR && !pdu->cancelled);
b9cb88b0
AK
237 }
238 }
239 return err;
240}
241
bccacf6c 242static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid)
286d5652 243{
7a462745 244 int err;
286d5652 245 V9fsFidState *f;
bccacf6c 246 V9fsState *s = pdu->s;
286d5652
AL
247
248 for (f = s->fid_list; f; f = f->next) {
84dfb926 249 BUG_ON(f->clunked);
286d5652 250 if (f->fid == fid) {
7a462745
AK
251 /*
252 * Update the fid ref upfront so that
253 * we don't get reclaimed when we yield
254 * in open later.
255 */
84dfb926 256 f->ref++;
7a462745
AK
257 /*
258 * check whether we need to reopen the
259 * file. We might have closed the fd
260 * while trying to free up some file
261 * descriptors.
262 */
bccacf6c 263 err = v9fs_reopen_fid(pdu, f);
b9cb88b0
AK
264 if (err < 0) {
265 f->ref--;
266 return NULL;
267 }
7a462745
AK
268 /*
269 * Mark the fid as referenced so that the LRU
270 * reclaim won't close the file descriptor
271 */
272 f->flags |= FID_REFERENCED;
286d5652
AL
273 return f;
274 }
275 }
286d5652
AL
276 return NULL;
277}
278
279static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
280{
281 V9fsFidState *f;
282
84dfb926
AK
283 for (f = s->fid_list; f; f = f->next) {
284 /* If fid is already there return NULL */
285 BUG_ON(f->clunked);
286 if (f->fid == fid) {
287 return NULL;
288 }
286d5652 289 }
7267c094 290 f = g_malloc0(sizeof(V9fsFidState));
286d5652 291 f->fid = fid;
d62dbb51 292 f->fid_type = P9_FID_NONE;
84dfb926 293 f->ref = 1;
7a462745
AK
294 /*
295 * Mark the fid as referenced so that the LRU
296 * reclaim won't close the file descriptor
297 */
298 f->flags |= FID_REFERENCED;
286d5652
AL
299 f->next = s->fid_list;
300 s->fid_list = f;
301
302 return f;
303}
304
bccacf6c 305static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp)
10b468bd
AK
306{
307 int retval = 0;
308
309 if (fidp->fs.xattr.copied_len == -1) {
310 /* getxattr/listxattr fid */
311 goto free_value;
312 }
313 /*
314 * if this is fid for setxattr. clunk should
315 * result in setxattr localcall
316 */
317 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
318 /* clunk after partial write */
319 retval = -EINVAL;
320 goto free_out;
321 }
9ed3ef26 322 if (fidp->fs.xattr.len) {
bccacf6c 323 retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name,
9ed3ef26
AK
324 fidp->fs.xattr.value,
325 fidp->fs.xattr.len,
326 fidp->fs.xattr.flags);
327 } else {
bccacf6c 328 retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name);
9ed3ef26 329 }
10b468bd
AK
330free_out:
331 v9fs_string_free(&fidp->fs.xattr.name);
332free_value:
9e288406 333 g_free(fidp->fs.xattr.value);
10b468bd
AK
334 return retval;
335}
336
bccacf6c 337static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp)
286d5652 338{
10b468bd 339 int retval = 0;
84dfb926
AK
340
341 if (fidp->fid_type == P9_FID_FILE) {
7a462745
AK
342 /* If we reclaimed the fd no need to close */
343 if (fidp->fs.fd != -1) {
cc720ddb 344 retval = v9fs_co_close(pdu, &fidp->fs);
7a462745 345 }
84dfb926 346 } else if (fidp->fid_type == P9_FID_DIR) {
95f65511 347 if (fidp->fs.dir != NULL) {
cc720ddb 348 retval = v9fs_co_closedir(pdu, &fidp->fs);
95f65511 349 }
84dfb926 350 } else if (fidp->fid_type == P9_FID_XATTR) {
bccacf6c 351 retval = v9fs_xattr_fid_clunk(pdu, fidp);
84dfb926 352 }
2289be19 353 v9fs_path_free(&fidp->path);
84dfb926
AK
354 g_free(fidp);
355 return retval;
356}
357
a911a182 358static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp)
84dfb926
AK
359{
360 BUG_ON(!fidp->ref);
361 fidp->ref--;
7a462745
AK
362 /*
363 * Don't free the fid if it is in reclaim list
364 */
84dfb926 365 if (!fidp->ref && fidp->clunked) {
e9a0152b
AK
366 if (fidp->fid == pdu->s->root_fid) {
367 /*
368 * if the clunked fid is root fid then we
369 * have unmounted the fs on the client side.
370 * delete the migration blocker. Ideally, this
371 * should be hooked to transport close notification
372 */
373 if (pdu->s->migration_blocker) {
374 migrate_del_blocker(pdu->s->migration_blocker);
375 error_free(pdu->s->migration_blocker);
376 pdu->s->migration_blocker = NULL;
377 }
378 }
a911a182 379 return free_fid(pdu, fidp);
84dfb926 380 }
a911a182 381 return 0;
84dfb926
AK
382}
383
ce421a19 384static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid)
84dfb926 385{
286d5652
AL
386 V9fsFidState **fidpp, *fidp;
387
388 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
389 if ((*fidpp)->fid == fid) {
390 break;
391 }
392 }
286d5652 393 if (*fidpp == NULL) {
ce421a19 394 return NULL;
286d5652 395 }
286d5652
AL
396 fidp = *fidpp;
397 *fidpp = fidp->next;
84dfb926 398 fidp->clunked = 1;
ce421a19 399 return fidp;
286d5652
AL
400}
401
bccacf6c 402void v9fs_reclaim_fd(V9fsPDU *pdu)
7a462745
AK
403{
404 int reclaim_count = 0;
bccacf6c 405 V9fsState *s = pdu->s;
7a462745
AK
406 V9fsFidState *f, *reclaim_list = NULL;
407
408 for (f = s->fid_list; f; f = f->next) {
409 /*
410 * Unlink fids cannot be reclaimed. Check
411 * for them and skip them. Also skip fids
412 * currently being operated on.
413 */
414 if (f->ref || f->flags & FID_NON_RECLAIMABLE) {
415 continue;
416 }
417 /*
418 * if it is a recently referenced fid
419 * we leave the fid untouched and clear the
420 * reference bit. We come back to it later
421 * in the next iteration. (a simple LRU without
422 * moving list elements around)
423 */
424 if (f->flags & FID_REFERENCED) {
425 f->flags &= ~FID_REFERENCED;
426 continue;
427 }
428 /*
429 * Add fids to reclaim list.
430 */
431 if (f->fid_type == P9_FID_FILE) {
432 if (f->fs.fd != -1) {
433 /*
434 * Up the reference count so that
435 * a clunk request won't free this fid
436 */
437 f->ref++;
438 f->rclm_lst = reclaim_list;
439 reclaim_list = f;
440 f->fs_reclaim.fd = f->fs.fd;
441 f->fs.fd = -1;
442 reclaim_count++;
443 }
95f65511
AK
444 } else if (f->fid_type == P9_FID_DIR) {
445 if (f->fs.dir != NULL) {
446 /*
447 * Up the reference count so that
448 * a clunk request won't free this fid
449 */
450 f->ref++;
451 f->rclm_lst = reclaim_list;
452 reclaim_list = f;
453 f->fs_reclaim.dir = f->fs.dir;
454 f->fs.dir = NULL;
455 reclaim_count++;
456 }
7a462745
AK
457 }
458 if (reclaim_count >= open_fd_rc) {
459 break;
460 }
461 }
462 /*
463 * Now close the fid in reclaim list. Free them if they
464 * are already clunked.
465 */
466 while (reclaim_list) {
467 f = reclaim_list;
468 reclaim_list = f->rclm_lst;
469 if (f->fid_type == P9_FID_FILE) {
cc720ddb 470 v9fs_co_close(pdu, &f->fs_reclaim);
95f65511 471 } else if (f->fid_type == P9_FID_DIR) {
cc720ddb 472 v9fs_co_closedir(pdu, &f->fs_reclaim);
7a462745
AK
473 }
474 f->rclm_lst = NULL;
475 /*
476 * Now drop the fid reference, free it
477 * if clunked.
478 */
bccacf6c 479 put_fid(pdu, f);
7a462745
AK
480 }
481}
482
bccacf6c 483static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path)
7a462745
AK
484{
485 int err;
bccacf6c 486 V9fsState *s = pdu->s;
7a462745
AK
487 V9fsFidState *fidp, head_fid;
488
489 head_fid.next = s->fid_list;
490 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
2289be19
AK
491 if (fidp->path.size != path->size) {
492 continue;
493 }
494 if (!memcmp(fidp->path.data, path->data, path->size)) {
7a462745
AK
495 /* Mark the fid non reclaimable. */
496 fidp->flags |= FID_NON_RECLAIMABLE;
b9cb88b0
AK
497
498 /* reopen the file/dir if already closed */
bccacf6c 499 err = v9fs_reopen_fid(pdu, fidp);
b9cb88b0
AK
500 if (err < 0) {
501 return -1;
502 }
503 /*
504 * Go back to head of fid list because
505 * the list could have got updated when
506 * switched to the worker thread
507 */
508 if (err == 0) {
7a462745
AK
509 fidp = &head_fid;
510 }
511 }
512 }
513 return 0;
514}
515
b41e2992
DS
516static void virtfs_reset(V9fsPDU *pdu)
517{
518 V9fsState *s = pdu->s;
519 V9fsFidState *fidp = NULL;
520
521 /* Free all fids */
522 while (s->fid_list) {
523 fidp = s->fid_list;
524 s->fid_list = fidp->next;
525
526 if (fidp->ref) {
527 fidp->clunked = 1;
528 } else {
529 free_fid(pdu, fidp);
530 }
531 }
532 if (fidp) {
533 /* One or more unclunked fids found... */
534 error_report("9pfs:%s: One or more uncluncked fids "
535 "found during reset", __func__);
536 }
b41e2992
DS
537}
538
286d5652
AL
539#define P9_QID_TYPE_DIR 0x80
540#define P9_QID_TYPE_SYMLINK 0x02
541
542#define P9_STAT_MODE_DIR 0x80000000
543#define P9_STAT_MODE_APPEND 0x40000000
544#define P9_STAT_MODE_EXCL 0x20000000
545#define P9_STAT_MODE_MOUNT 0x10000000
546#define P9_STAT_MODE_AUTH 0x08000000
547#define P9_STAT_MODE_TMP 0x04000000
548#define P9_STAT_MODE_SYMLINK 0x02000000
549#define P9_STAT_MODE_LINK 0x01000000
550#define P9_STAT_MODE_DEVICE 0x00800000
551#define P9_STAT_MODE_NAMED_PIPE 0x00200000
552#define P9_STAT_MODE_SOCKET 0x00100000
553#define P9_STAT_MODE_SETUID 0x00080000
554#define P9_STAT_MODE_SETGID 0x00040000
555#define P9_STAT_MODE_SETVTX 0x00010000
556
557#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
558 P9_STAT_MODE_SYMLINK | \
559 P9_STAT_MODE_LINK | \
560 P9_STAT_MODE_DEVICE | \
561 P9_STAT_MODE_NAMED_PIPE | \
562 P9_STAT_MODE_SOCKET)
563
564/* This is the algorithm from ufs in spfs */
565static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
566{
567 size_t size;
568
25427ec1 569 memset(&qidp->path, 0, sizeof(qidp->path));
286d5652
AL
570 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
571 memcpy(&qidp->path, &stbuf->st_ino, size);
572 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
573 qidp->type = 0;
574 if (S_ISDIR(stbuf->st_mode)) {
575 qidp->type |= P9_QID_TYPE_DIR;
576 }
577 if (S_ISLNK(stbuf->st_mode)) {
578 qidp->type |= P9_QID_TYPE_SYMLINK;
579 }
580}
581
bccacf6c 582static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp)
286d5652
AL
583{
584 struct stat stbuf;
585 int err;
586
bccacf6c 587 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
8c158561 588 if (err < 0) {
286d5652
AL
589 return err;
590 }
286d5652
AL
591 stat_to_qid(&stbuf, qidp);
592 return 0;
593}
594
dc295f83 595static V9fsPDU *pdu_alloc(V9fsState *s)
9f107513
AL
596{
597 V9fsPDU *pdu = NULL;
598
599 if (!QLIST_EMPTY(&s->free_list)) {
bccacf6c
AK
600 pdu = QLIST_FIRST(&s->free_list);
601 QLIST_REMOVE(pdu, next);
602 QLIST_INSERT_HEAD(&s->active_list, pdu, next);
9f107513
AL
603 }
604 return pdu;
605}
606
dc295f83 607static void pdu_free(V9fsPDU *pdu)
9f107513
AL
608{
609 if (pdu) {
ad38ce9e 610 V9fsState *s = pdu->s;
bccacf6c
AK
611 /*
612 * Cancelled pdu are added back to the freelist
613 * by flush request .
614 */
615 if (!pdu->cancelled) {
616 QLIST_REMOVE(pdu, next);
617 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
618 }
9f107513
AL
619 }
620}
621
ddca7f86
MK
622/*
623 * We don't do error checking for pdu_marshal/unmarshal here
624 * because we always expect to have enough space to encode
625 * error details
626 */
dc295f83 627static void pdu_complete(V9fsPDU *pdu, ssize_t len)
405a549a
AL
628{
629 int8_t id = pdu->id + 1; /* Response */
ad38ce9e 630 V9fsState *s = pdu->s;
405a549a
AL
631
632 if (len < 0) {
405a549a 633 int err = -len;
8f4d1ca5 634 len = 7;
405a549a 635
8f4d1ca5
AB
636 if (s->proto_version != V9FS_PROTO_2000L) {
637 V9fsString str;
638
639 str.data = strerror(err);
640 str.size = strlen(str.data);
641
642 len += pdu_marshal(pdu, len, "s", &str);
643 id = P9_RERROR;
644 }
405a549a 645
cf03eb2c 646 len += pdu_marshal(pdu, len, "d", err);
405a549a 647
8f4d1ca5
AB
648 if (s->proto_version == V9FS_PROTO_2000L) {
649 id = P9_RLERROR;
650 }
7999f7e1 651 trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */
405a549a
AL
652 }
653
654 /* fill out the header */
655 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
656
657 /* keep these in sync */
658 pdu->size = len;
659 pdu->id = id;
660
f657b17a 661 pdu_push_and_notify(pdu);
405a549a 662
bccacf6c
AK
663 /* Now wakeup anybody waiting in flush for this request */
664 qemu_co_queue_next(&pdu->complete);
665
dc295f83 666 pdu_free(pdu);
405a549a
AL
667}
668
bb9e3216
AL
669static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
670{
671 mode_t ret;
672
673 ret = mode & 0777;
674 if (mode & P9_STAT_MODE_DIR) {
675 ret |= S_IFDIR;
676 }
677
cf03eb2c
AB
678 if (mode & P9_STAT_MODE_SYMLINK) {
679 ret |= S_IFLNK;
680 }
681 if (mode & P9_STAT_MODE_SOCKET) {
682 ret |= S_IFSOCK;
683 }
684 if (mode & P9_STAT_MODE_NAMED_PIPE) {
685 ret |= S_IFIFO;
686 }
687 if (mode & P9_STAT_MODE_DEVICE) {
c7e587b7 688 if (extension->size && extension->data[0] == 'c') {
cf03eb2c
AB
689 ret |= S_IFCHR;
690 } else {
691 ret |= S_IFBLK;
bb9e3216
AL
692 }
693 }
694
695 if (!(ret&~0777)) {
696 ret |= S_IFREG;
697 }
698
699 if (mode & P9_STAT_MODE_SETUID) {
700 ret |= S_ISUID;
701 }
702 if (mode & P9_STAT_MODE_SETGID) {
703 ret |= S_ISGID;
704 }
705 if (mode & P9_STAT_MODE_SETVTX) {
706 ret |= S_ISVTX;
707 }
708
709 return ret;
710}
711
712static int donttouch_stat(V9fsStat *stat)
713{
714 if (stat->type == -1 &&
715 stat->dev == -1 &&
716 stat->qid.type == -1 &&
717 stat->qid.version == -1 &&
718 stat->qid.path == -1 &&
719 stat->mode == -1 &&
720 stat->atime == -1 &&
721 stat->mtime == -1 &&
722 stat->length == -1 &&
723 !stat->name.size &&
724 !stat->uid.size &&
725 !stat->gid.size &&
726 !stat->muid.size &&
727 stat->n_uid == -1 &&
728 stat->n_gid == -1 &&
729 stat->n_muid == -1) {
730 return 1;
731 }
732
733 return 0;
734}
735
ddca7f86
MK
736static void v9fs_stat_init(V9fsStat *stat)
737{
738 v9fs_string_init(&stat->name);
739 v9fs_string_init(&stat->uid);
740 v9fs_string_init(&stat->gid);
741 v9fs_string_init(&stat->muid);
742 v9fs_string_init(&stat->extension);
743}
744
bb9e3216
AL
745static void v9fs_stat_free(V9fsStat *stat)
746{
747 v9fs_string_free(&stat->name);
748 v9fs_string_free(&stat->uid);
749 v9fs_string_free(&stat->gid);
750 v9fs_string_free(&stat->muid);
751 v9fs_string_free(&stat->extension);
752}
753
754static uint32_t stat_to_v9mode(const struct stat *stbuf)
755{
756 uint32_t mode;
757
758 mode = stbuf->st_mode & 0777;
759 if (S_ISDIR(stbuf->st_mode)) {
760 mode |= P9_STAT_MODE_DIR;
761 }
762
cf03eb2c
AB
763 if (S_ISLNK(stbuf->st_mode)) {
764 mode |= P9_STAT_MODE_SYMLINK;
765 }
bb9e3216 766
cf03eb2c
AB
767 if (S_ISSOCK(stbuf->st_mode)) {
768 mode |= P9_STAT_MODE_SOCKET;
769 }
bb9e3216 770
cf03eb2c
AB
771 if (S_ISFIFO(stbuf->st_mode)) {
772 mode |= P9_STAT_MODE_NAMED_PIPE;
773 }
bb9e3216 774
cf03eb2c
AB
775 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
776 mode |= P9_STAT_MODE_DEVICE;
777 }
bb9e3216 778
cf03eb2c
AB
779 if (stbuf->st_mode & S_ISUID) {
780 mode |= P9_STAT_MODE_SETUID;
781 }
bb9e3216 782
cf03eb2c
AB
783 if (stbuf->st_mode & S_ISGID) {
784 mode |= P9_STAT_MODE_SETGID;
785 }
bb9e3216 786
cf03eb2c
AB
787 if (stbuf->st_mode & S_ISVTX) {
788 mode |= P9_STAT_MODE_SETVTX;
bb9e3216
AL
789 }
790
791 return mode;
792}
793
bccacf6c 794static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name,
bb9e3216
AL
795 const struct stat *stbuf,
796 V9fsStat *v9stat)
797{
798 int err;
799 const char *str;
800
801 memset(v9stat, 0, sizeof(*v9stat));
802
803 stat_to_qid(stbuf, &v9stat->qid);
804 v9stat->mode = stat_to_v9mode(stbuf);
805 v9stat->atime = stbuf->st_atime;
806 v9stat->mtime = stbuf->st_mtime;
807 v9stat->length = stbuf->st_size;
808
809 v9fs_string_null(&v9stat->uid);
810 v9fs_string_null(&v9stat->gid);
811 v9fs_string_null(&v9stat->muid);
812
cf03eb2c
AB
813 v9stat->n_uid = stbuf->st_uid;
814 v9stat->n_gid = stbuf->st_gid;
815 v9stat->n_muid = 0;
bb9e3216 816
cf03eb2c 817 v9fs_string_null(&v9stat->extension);
bb9e3216 818
cf03eb2c 819 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
bccacf6c 820 err = v9fs_co_readlink(pdu, name, &v9stat->extension);
7a5ca31e 821 if (err < 0) {
cf03eb2c 822 return err;
bb9e3216 823 }
cf03eb2c
AB
824 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
825 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
826 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
827 major(stbuf->st_rdev), minor(stbuf->st_rdev));
828 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
c9ba47dc
SW
829 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
830 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
bb9e3216
AL
831 }
832
833 str = strrchr(name->data, '/');
834 if (str) {
835 str += 1;
836 } else {
837 str = name->data;
838 }
839
840 v9fs_string_sprintf(&v9stat->name, "%s", str);
841
842 v9stat->size = 61 +
843 v9fs_string_size(&v9stat->name) +
844 v9fs_string_size(&v9stat->uid) +
845 v9fs_string_size(&v9stat->gid) +
846 v9fs_string_size(&v9stat->muid) +
847 v9fs_string_size(&v9stat->extension);
848 return 0;
849}
850
00ede4c2
SK
851#define P9_STATS_MODE 0x00000001ULL
852#define P9_STATS_NLINK 0x00000002ULL
853#define P9_STATS_UID 0x00000004ULL
854#define P9_STATS_GID 0x00000008ULL
855#define P9_STATS_RDEV 0x00000010ULL
856#define P9_STATS_ATIME 0x00000020ULL
857#define P9_STATS_MTIME 0x00000040ULL
858#define P9_STATS_CTIME 0x00000080ULL
859#define P9_STATS_INO 0x00000100ULL
860#define P9_STATS_SIZE 0x00000200ULL
861#define P9_STATS_BLOCKS 0x00000400ULL
862
863#define P9_STATS_BTIME 0x00000800ULL
864#define P9_STATS_GEN 0x00001000ULL
865#define P9_STATS_DATA_VERSION 0x00002000ULL
866
867#define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
868#define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
869
870
871static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
8db21ce7 872 V9fsStatDotl *v9lstat)
00ede4c2
SK
873{
874 memset(v9lstat, 0, sizeof(*v9lstat));
875
876 v9lstat->st_mode = stbuf->st_mode;
877 v9lstat->st_nlink = stbuf->st_nlink;
878 v9lstat->st_uid = stbuf->st_uid;
879 v9lstat->st_gid = stbuf->st_gid;
880 v9lstat->st_rdev = stbuf->st_rdev;
881 v9lstat->st_size = stbuf->st_size;
882 v9lstat->st_blksize = stbuf->st_blksize;
883 v9lstat->st_blocks = stbuf->st_blocks;
884 v9lstat->st_atime_sec = stbuf->st_atime;
885 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
886 v9lstat->st_mtime_sec = stbuf->st_mtime;
887 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
888 v9lstat->st_ctime_sec = stbuf->st_ctime;
889 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
890 /* Currently we only support BASIC fields in stat */
891 v9lstat->st_result_mask = P9_STATS_BASIC;
892
893 stat_to_qid(stbuf, &v9lstat->qid);
894}
895
1f5a89bf
AL
896static void print_sg(struct iovec *sg, int cnt)
897{
898 int i;
899
900 printf("sg[%d]: {", cnt);
901 for (i = 0; i < cnt; i++) {
902 if (i) {
903 printf(", ");
904 }
905 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
906 }
907 printf("}\n");
908}
909
2289be19
AK
910/* Will call this only for path name based fid */
911static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len)
8cf89e00 912{
2289be19
AK
913 V9fsPath str;
914 v9fs_path_init(&str);
915 v9fs_path_copy(&str, dst);
916 v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len);
917 v9fs_path_free(&str);
918 /* +1 to include terminating NULL */
919 dst->size++;
8cf89e00
AL
920}
921
2c74c2cb
MK
922static inline bool is_ro_export(FsContext *ctx)
923{
924 return ctx->export_flags & V9FS_RDONLY;
925}
926
ff06030f 927static void v9fs_version(void *opaque)
9f107513 928{
ddca7f86 929 ssize_t err;
ff06030f
VJ
930 V9fsPDU *pdu = opaque;
931 V9fsState *s = pdu->s;
92c1ad03
AL
932 V9fsString version;
933 size_t offset = 7;
934
ddca7f86
MK
935 v9fs_string_init(&version);
936 err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
937 if (err < 0) {
938 offset = err;
939 goto out;
940 }
c572f23a 941 trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data);
92c1ad03 942
b41e2992
DS
943 virtfs_reset(pdu);
944
84151514
MK
945 if (!strcmp(version.data, "9P2000.u")) {
946 s->proto_version = V9FS_PROTO_2000U;
947 } else if (!strcmp(version.data, "9P2000.L")) {
948 s->proto_version = V9FS_PROTO_2000L;
949 } else {
92c1ad03 950 v9fs_string_sprintf(&version, "unknown");
9f107513 951 }
92c1ad03 952
ddca7f86
MK
953 err = pdu_marshal(pdu, offset, "ds", s->msize, &version);
954 if (err < 0) {
955 offset = err;
956 goto out;
957 }
958 offset += err;
c572f23a 959 trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data);
ddca7f86 960out:
dc295f83 961 pdu_complete(pdu, offset);
92c1ad03 962 v9fs_string_free(&version);
9f107513
AL
963}
964
ff06030f 965static void v9fs_attach(void *opaque)
9f107513 966{
ff06030f
VJ
967 V9fsPDU *pdu = opaque;
968 V9fsState *s = pdu->s;
955efc47
AL
969 int32_t fid, afid, n_uname;
970 V9fsString uname, aname;
971 V9fsFidState *fidp;
955efc47 972 size_t offset = 7;
8c158561 973 V9fsQID qid;
955efc47
AL
974 ssize_t err;
975
ddca7f86
MK
976 v9fs_string_init(&uname);
977 v9fs_string_init(&aname);
978 err = pdu_unmarshal(pdu, offset, "ddssd", &fid,
979 &afid, &uname, &aname, &n_uname);
980 if (err < 0) {
981 goto out_nofid;
982 }
c572f23a 983 trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data);
955efc47
AL
984
985 fidp = alloc_fid(s, fid);
986 if (fidp == NULL) {
987 err = -EINVAL;
84dfb926 988 goto out_nofid;
9f107513 989 }
955efc47 990 fidp->uid = n_uname;
bccacf6c 991 err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path);
2289be19
AK
992 if (err < 0) {
993 err = -EINVAL;
994 clunk_fid(s, fid);
995 goto out;
996 }
bccacf6c 997 err = fid_to_qid(pdu, fidp, &qid);
8c158561 998 if (err < 0) {
955efc47 999 err = -EINVAL;
84dfb926 1000 clunk_fid(s, fid);
955efc47
AL
1001 goto out;
1002 }
ddca7f86
MK
1003 err = pdu_marshal(pdu, offset, "Q", &qid);
1004 if (err < 0) {
1005 clunk_fid(s, fid);
1006 goto out;
1007 }
1008 err += offset;
7999f7e1
AK
1009 trace_v9fs_attach_return(pdu->tag, pdu->id,
1010 qid.type, qid.version, qid.path);
4cdc0789
AK
1011 /*
1012 * disable migration if we haven't done already.
1013 * attach could get called multiple times for the same export.
1014 */
1015 if (!s->migration_blocker) {
1016 s->root_fid = fid;
f231b88d
CR
1017 error_setg(&s->migration_blocker,
1018 "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'",
1019 s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
4cdc0789
AK
1020 migrate_add_blocker(s->migration_blocker);
1021 }
955efc47 1022out:
bccacf6c 1023 put_fid(pdu, fidp);
84dfb926 1024out_nofid:
dc295f83 1025 pdu_complete(pdu, err);
955efc47
AL
1026 v9fs_string_free(&uname);
1027 v9fs_string_free(&aname);
9f107513
AL
1028}
1029
ff06030f 1030static void v9fs_stat(void *opaque)
9f107513 1031{
4da7d3fa 1032 int32_t fid;
d8e0c29e 1033 V9fsStat v9stat;
4da7d3fa 1034 ssize_t err = 0;
d8e0c29e
AK
1035 size_t offset = 7;
1036 struct stat stbuf;
1037 V9fsFidState *fidp;
1038 V9fsPDU *pdu = opaque;
4da7d3fa 1039
ddca7f86
MK
1040 err = pdu_unmarshal(pdu, offset, "d", &fid);
1041 if (err < 0) {
1042 goto out_nofid;
1043 }
c572f23a 1044 trace_v9fs_stat(pdu->tag, pdu->id, fid);
84dfb926 1045
bccacf6c 1046 fidp = get_fid(pdu, fid);
d8e0c29e 1047 if (fidp == NULL) {
4da7d3fa 1048 err = -ENOENT;
84dfb926 1049 goto out_nofid;
9f107513 1050 }
bccacf6c 1051 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
d8e0c29e
AK
1052 if (err < 0) {
1053 goto out;
1054 }
bccacf6c 1055 err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat);
d8e0c29e
AK
1056 if (err < 0) {
1057 goto out;
1058 }
ddca7f86
MK
1059 err = pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1060 if (err < 0) {
1061 v9fs_stat_free(&v9stat);
1062 goto out;
1063 }
7999f7e1
AK
1064 trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode,
1065 v9stat.atime, v9stat.mtime, v9stat.length);
ddca7f86 1066 err += offset;
d8e0c29e 1067 v9fs_stat_free(&v9stat);
4da7d3fa 1068out:
bccacf6c 1069 put_fid(pdu, fidp);
84dfb926 1070out_nofid:
dc295f83 1071 pdu_complete(pdu, err);
9f107513
AL
1072}
1073
ff06030f 1074static void v9fs_getattr(void *opaque)
00ede4c2
SK
1075{
1076 int32_t fid;
8db21ce7
AK
1077 size_t offset = 7;
1078 ssize_t retval = 0;
1079 struct stat stbuf;
00ede4c2
SK
1080 V9fsFidState *fidp;
1081 uint64_t request_mask;
8db21ce7
AK
1082 V9fsStatDotl v9stat_dotl;
1083 V9fsPDU *pdu = opaque;
1084 V9fsState *s = pdu->s;
00ede4c2 1085
ddca7f86
MK
1086 retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1087 if (retval < 0) {
1088 goto out_nofid;
1089 }
c572f23a 1090 trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask);
00ede4c2 1091
bccacf6c 1092 fidp = get_fid(pdu, fid);
00ede4c2 1093 if (fidp == NULL) {
8db21ce7 1094 retval = -ENOENT;
84dfb926 1095 goto out_nofid;
00ede4c2 1096 }
8db21ce7
AK
1097 /*
1098 * Currently we only support BASIC fields in stat, so there is no
00ede4c2
SK
1099 * need to look at request_mask.
1100 */
bccacf6c 1101 retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
8db21ce7
AK
1102 if (retval < 0) {
1103 goto out;
1104 }
1105 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
e06a765e
HPB
1106
1107 /* fill st_gen if requested and supported by underlying fs */
1108 if (request_mask & P9_STATS_GEN) {
1109 retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl);
f8b7ee38
KS
1110 switch (retval) {
1111 case 0:
1112 /* we have valid st_gen: update result mask */
1113 v9stat_dotl.st_result_mask |= P9_STATS_GEN;
1114 break;
1115 case -EINTR:
1116 /* request cancelled, e.g. by Tflush */
e06a765e 1117 goto out;
f8b7ee38
KS
1118 default:
1119 /* failed to get st_gen: not fatal, ignore */
1120 break;
e06a765e 1121 }
e06a765e 1122 }
ddca7f86
MK
1123 retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1124 if (retval < 0) {
1125 goto out;
1126 }
1127 retval += offset;
c572f23a
HPB
1128 trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask,
1129 v9stat_dotl.st_mode, v9stat_dotl.st_uid,
1130 v9stat_dotl.st_gid);
7999f7e1
AK
1131out:
1132 put_fid(pdu, fidp);
1133out_nofid:
dc295f83 1134 pdu_complete(pdu, retval);
00ede4c2
SK
1135}
1136
e4027caf
AK
1137/* Attribute flags */
1138#define P9_ATTR_MODE (1 << 0)
1139#define P9_ATTR_UID (1 << 1)
1140#define P9_ATTR_GID (1 << 2)
1141#define P9_ATTR_SIZE (1 << 3)
1142#define P9_ATTR_ATIME (1 << 4)
1143#define P9_ATTR_MTIME (1 << 5)
1144#define P9_ATTR_CTIME (1 << 6)
1145#define P9_ATTR_ATIME_SET (1 << 7)
1146#define P9_ATTR_MTIME_SET (1 << 8)
1147
1148#define P9_ATTR_MASK 127
c79ce737 1149
65c05f9a 1150static void v9fs_setattr(void *opaque)
c79ce737 1151{
65c05f9a
AK
1152 int err = 0;
1153 int32_t fid;
1154 V9fsFidState *fidp;
1155 size_t offset = 7;
1156 V9fsIattr v9iattr;
1157 V9fsPDU *pdu = opaque;
c79ce737 1158
ddca7f86
MK
1159 err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1160 if (err < 0) {
1161 goto out_nofid;
1162 }
c79ce737 1163
bccacf6c 1164 fidp = get_fid(pdu, fid);
65c05f9a
AK
1165 if (fidp == NULL) {
1166 err = -EINVAL;
84dfb926 1167 goto out_nofid;
c79ce737 1168 }
e4027caf 1169 if (v9iattr.valid & P9_ATTR_MODE) {
bccacf6c 1170 err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode);
65c05f9a
AK
1171 if (err < 0) {
1172 goto out;
c79ce737 1173 }
c79ce737 1174 }
e4027caf 1175 if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) {
c79ce737 1176 struct timespec times[2];
e4027caf
AK
1177 if (v9iattr.valid & P9_ATTR_ATIME) {
1178 if (v9iattr.valid & P9_ATTR_ATIME_SET) {
65c05f9a
AK
1179 times[0].tv_sec = v9iattr.atime_sec;
1180 times[0].tv_nsec = v9iattr.atime_nsec;
c79ce737
SK
1181 } else {
1182 times[0].tv_nsec = UTIME_NOW;
1183 }
1184 } else {
1185 times[0].tv_nsec = UTIME_OMIT;
1186 }
e4027caf
AK
1187 if (v9iattr.valid & P9_ATTR_MTIME) {
1188 if (v9iattr.valid & P9_ATTR_MTIME_SET) {
65c05f9a
AK
1189 times[1].tv_sec = v9iattr.mtime_sec;
1190 times[1].tv_nsec = v9iattr.mtime_nsec;
c79ce737
SK
1191 } else {
1192 times[1].tv_nsec = UTIME_NOW;
1193 }
1194 } else {
1195 times[1].tv_nsec = UTIME_OMIT;
1196 }
bccacf6c 1197 err = v9fs_co_utimensat(pdu, &fidp->path, times);
65c05f9a
AK
1198 if (err < 0) {
1199 goto out;
1200 }
c79ce737 1201 }
65c05f9a
AK
1202 /*
1203 * If the only valid entry in iattr is ctime we can call
1204 * chown(-1,-1) to update the ctime of the file
1205 */
e4027caf
AK
1206 if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) ||
1207 ((v9iattr.valid & P9_ATTR_CTIME)
1208 && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) {
1209 if (!(v9iattr.valid & P9_ATTR_UID)) {
65c05f9a
AK
1210 v9iattr.uid = -1;
1211 }
e4027caf 1212 if (!(v9iattr.valid & P9_ATTR_GID)) {
65c05f9a
AK
1213 v9iattr.gid = -1;
1214 }
bccacf6c 1215 err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid,
65c05f9a
AK
1216 v9iattr.gid);
1217 if (err < 0) {
1218 goto out;
1219 }
c79ce737 1220 }
e4027caf 1221 if (v9iattr.valid & (P9_ATTR_SIZE)) {
bccacf6c 1222 err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size);
65c05f9a
AK
1223 if (err < 0) {
1224 goto out;
1225 }
c79ce737 1226 }
65c05f9a 1227 err = offset;
c79ce737 1228out:
bccacf6c 1229 put_fid(pdu, fidp);
84dfb926 1230out_nofid:
dc295f83 1231 pdu_complete(pdu, err);
c79ce737
SK
1232}
1233
3cc19c0c 1234static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
ff5e54c9
AL
1235{
1236 int i;
ddca7f86 1237 ssize_t err;
3cc19c0c 1238 size_t offset = 7;
ddca7f86
MK
1239
1240 err = pdu_marshal(pdu, offset, "w", nwnames);
1241 if (err < 0) {
1242 return err;
1243 }
1244 offset += err;
3cc19c0c 1245 for (i = 0; i < nwnames; i++) {
ddca7f86
MK
1246 err = pdu_marshal(pdu, offset, "Q", &qids[i]);
1247 if (err < 0) {
1248 return err;
1249 }
1250 offset += err;
ff5e54c9 1251 }
3cc19c0c 1252 return offset;
ff5e54c9
AL
1253}
1254
ff06030f 1255static void v9fs_walk(void *opaque)
9f107513 1256{
3cc19c0c
AK
1257 int name_idx;
1258 V9fsQID *qids = NULL;
1259 int i, err = 0;
2289be19 1260 V9fsPath dpath, path;
3cc19c0c
AK
1261 uint16_t nwnames;
1262 struct stat stbuf;
1263 size_t offset = 7;
1264 int32_t fid, newfid;
1265 V9fsString *wnames = NULL;
1266 V9fsFidState *fidp;
3a93113a 1267 V9fsFidState *newfidp = NULL;
ff06030f
VJ
1268 V9fsPDU *pdu = opaque;
1269 V9fsState *s = pdu->s;
ff5e54c9 1270
ddca7f86
MK
1271 err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames);
1272 if (err < 0) {
dc295f83 1273 pdu_complete(pdu, err);
ddca7f86
MK
1274 return ;
1275 }
1276 offset += err;
ff5e54c9 1277
c572f23a
HPB
1278 trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames);
1279
3cc19c0c
AK
1280 if (nwnames && nwnames <= P9_MAXWELEM) {
1281 wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1282 qids = g_malloc0(sizeof(qids[0]) * nwnames);
1283 for (i = 0; i < nwnames; i++) {
ddca7f86
MK
1284 err = pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1285 if (err < 0) {
1286 goto out_nofid;
1287 }
1288 offset += err;
ff5e54c9 1289 }
3cc19c0c 1290 } else if (nwnames > P9_MAXWELEM) {
4f8dee2d 1291 err = -EINVAL;
84dfb926 1292 goto out_nofid;
ff5e54c9 1293 }
bccacf6c 1294 fidp = get_fid(pdu, fid);
3cc19c0c 1295 if (fidp == NULL) {
ff5e54c9 1296 err = -ENOENT;
84dfb926 1297 goto out_nofid;
ff5e54c9 1298 }
2289be19
AK
1299 v9fs_path_init(&dpath);
1300 v9fs_path_init(&path);
1301 /*
1302 * Both dpath and path initially poin to fidp.
1303 * Needed to handle request with nwnames == 0
1304 */
1305 v9fs_path_copy(&dpath, &fidp->path);
1306 v9fs_path_copy(&path, &fidp->path);
1307 for (name_idx = 0; name_idx < nwnames; name_idx++) {
bccacf6c 1308 err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path);
2289be19
AK
1309 if (err < 0) {
1310 goto out;
1311 }
bccacf6c 1312 err = v9fs_co_lstat(pdu, &path, &stbuf);
2289be19
AK
1313 if (err < 0) {
1314 goto out;
1315 }
1316 stat_to_qid(&stbuf, &qids[name_idx]);
1317 v9fs_path_copy(&dpath, &path);
1318 }
ff5e54c9 1319 if (fid == newfid) {
3cc19c0c 1320 BUG_ON(fidp->fid_type != P9_FID_NONE);
2289be19 1321 v9fs_path_copy(&fidp->path, &path);
ff5e54c9 1322 } else {
3cc19c0c
AK
1323 newfidp = alloc_fid(s, newfid);
1324 if (newfidp == NULL) {
ff5e54c9
AL
1325 err = -EINVAL;
1326 goto out;
1327 }
3cc19c0c 1328 newfidp->uid = fidp->uid;
2289be19 1329 v9fs_path_copy(&newfidp->path, &path);
9f107513 1330 }
3cc19c0c 1331 err = v9fs_walk_marshal(pdu, nwnames, qids);
7999f7e1 1332 trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids);
ff5e54c9 1333out:
bccacf6c 1334 put_fid(pdu, fidp);
84dfb926 1335 if (newfidp) {
bccacf6c 1336 put_fid(pdu, newfidp);
84dfb926 1337 }
2289be19
AK
1338 v9fs_path_free(&dpath);
1339 v9fs_path_free(&path);
84dfb926 1340out_nofid:
dc295f83 1341 pdu_complete(pdu, err);
3cc19c0c
AK
1342 if (nwnames && nwnames <= P9_MAXWELEM) {
1343 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1344 v9fs_string_free(&wnames[name_idx]);
1345 }
1346 g_free(wnames);
1347 g_free(qids);
1348 }
9f107513
AL
1349}
1350
bccacf6c 1351static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path)
5e94c103
MK
1352{
1353 struct statfs stbuf;
1354 int32_t iounit = 0;
bccacf6c 1355 V9fsState *s = pdu->s;
5e94c103
MK
1356
1357 /*
1358 * iounit should be multiples of f_bsize (host filesystem block size
1359 * and as well as less than (client msize - P9_IOHDRSZ))
1360 */
bccacf6c 1361 if (!v9fs_co_statfs(pdu, path, &stbuf)) {
5e94c103
MK
1362 iounit = stbuf.f_bsize;
1363 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1364 }
5e94c103
MK
1365 if (!iounit) {
1366 iounit = s->msize - P9_IOHDRSZ;
1367 }
1368 return iounit;
1369}
1370
857bc158 1371static void v9fs_open(void *opaque)
5e94c103 1372{
857bc158 1373 int flags;
857bc158
AK
1374 int32_t fid;
1375 int32_t mode;
1376 V9fsQID qid;
7999f7e1 1377 int iounit = 0;
857bc158
AK
1378 ssize_t err = 0;
1379 size_t offset = 7;
1380 struct stat stbuf;
1381 V9fsFidState *fidp;
1382 V9fsPDU *pdu = opaque;
1383 V9fsState *s = pdu->s;
5e94c103 1384
857bc158 1385 if (s->proto_version == V9FS_PROTO_2000L) {
ddca7f86 1386 err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
857bc158 1387 } else {
67d6fa53
BH
1388 uint8_t modebyte;
1389 err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte);
1390 mode = modebyte;
ddca7f86
MK
1391 }
1392 if (err < 0) {
1393 goto out_nofid;
857bc158 1394 }
c572f23a
HPB
1395 trace_v9fs_open(pdu->tag, pdu->id, fid, mode);
1396
bccacf6c 1397 fidp = get_fid(pdu, fid);
857bc158
AK
1398 if (fidp == NULL) {
1399 err = -ENOENT;
84dfb926 1400 goto out_nofid;
a6568fe2 1401 }
857bc158 1402 BUG_ON(fidp->fid_type != P9_FID_NONE);
a6568fe2 1403
bccacf6c 1404 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
857bc158 1405 if (err < 0) {
a6568fe2
AL
1406 goto out;
1407 }
857bc158
AK
1408 stat_to_qid(&stbuf, &qid);
1409 if (S_ISDIR(stbuf.st_mode)) {
bccacf6c 1410 err = v9fs_co_opendir(pdu, fidp);
857bc158
AK
1411 if (err < 0) {
1412 goto out;
1413 }
1414 fidp->fid_type = P9_FID_DIR;
ddca7f86
MK
1415 err = pdu_marshal(pdu, offset, "Qd", &qid, 0);
1416 if (err < 0) {
1417 goto out;
1418 }
1419 err += offset;
a6568fe2 1420 } else {
771e9d4c 1421 if (s->proto_version == V9FS_PROTO_2000L) {
d3ab98e6 1422 flags = get_dotl_openflags(s, mode);
771e9d4c 1423 } else {
857bc158 1424 flags = omode_to_uflags(mode);
771e9d4c 1425 }
2c74c2cb
MK
1426 if (is_ro_export(&s->ctx)) {
1427 if (mode & O_WRONLY || mode & O_RDWR ||
1428 mode & O_APPEND || mode & O_TRUNC) {
1429 err = -EROFS;
1430 goto out;
1431 }
2c74c2cb 1432 }
bccacf6c 1433 err = v9fs_co_open(pdu, fidp, flags);
857bc158
AK
1434 if (err < 0) {
1435 goto out;
1436 }
1437 fidp->fid_type = P9_FID_FILE;
7a462745
AK
1438 fidp->open_flags = flags;
1439 if (flags & O_EXCL) {
1440 /*
1441 * We let the host file system do O_EXCL check
1442 * We should not reclaim such fd
1443 */
1444 fidp->flags |= FID_NON_RECLAIMABLE;
1445 }
bccacf6c 1446 iounit = get_iounit(pdu, &fidp->path);
ddca7f86
MK
1447 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1448 if (err < 0) {
1449 goto out;
1450 }
1451 err += offset;
a6568fe2 1452 }
7999f7e1
AK
1453 trace_v9fs_open_return(pdu->tag, pdu->id,
1454 qid.type, qid.version, qid.path, iounit);
a6568fe2 1455out:
bccacf6c 1456 put_fid(pdu, fidp);
84dfb926 1457out_nofid:
dc295f83 1458 pdu_complete(pdu, err);
a6568fe2
AL
1459}
1460
ff06030f 1461static void v9fs_lcreate(void *opaque)
c1568af5
VJ
1462{
1463 int32_t dfid, flags, mode;
1464 gid_t gid;
c1568af5 1465 ssize_t err = 0;
36f8981f 1466 ssize_t offset = 7;
36f8981f
VJ
1467 V9fsString name;
1468 V9fsFidState *fidp;
1469 struct stat stbuf;
1470 V9fsQID qid;
1471 int32_t iounit;
1472 V9fsPDU *pdu = opaque;
c1568af5 1473
ddca7f86
MK
1474 v9fs_string_init(&name);
1475 err = pdu_unmarshal(pdu, offset, "dsddd", &dfid,
1476 &name, &flags, &mode, &gid);
1477 if (err < 0) {
1478 goto out_nofid;
1479 }
c572f23a 1480 trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid);
c1568af5 1481
bccacf6c 1482 fidp = get_fid(pdu, dfid);
36f8981f 1483 if (fidp == NULL) {
c1568af5 1484 err = -ENOENT;
84dfb926 1485 goto out_nofid;
c1568af5 1486 }
c1568af5 1487
d3ab98e6 1488 flags = get_dotl_openflags(pdu->s, flags);
bccacf6c 1489 err = v9fs_co_open2(pdu, fidp, &name, gid,
02cb7f3a 1490 flags | O_CREAT, mode, &stbuf);
36f8981f
VJ
1491 if (err < 0) {
1492 goto out;
1493 }
1494 fidp->fid_type = P9_FID_FILE;
7a462745
AK
1495 fidp->open_flags = flags;
1496 if (flags & O_EXCL) {
1497 /*
1498 * We let the host file system do O_EXCL check
1499 * We should not reclaim such fd
1500 */
1501 fidp->flags |= FID_NON_RECLAIMABLE;
1502 }
bccacf6c 1503 iounit = get_iounit(pdu, &fidp->path);
36f8981f 1504 stat_to_qid(&stbuf, &qid);
ddca7f86
MK
1505 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1506 if (err < 0) {
1507 goto out;
1508 }
1509 err += offset;
7999f7e1
AK
1510 trace_v9fs_lcreate_return(pdu->tag, pdu->id,
1511 qid.type, qid.version, qid.path, iounit);
c1568af5 1512out:
bccacf6c 1513 put_fid(pdu, fidp);
84dfb926 1514out_nofid:
dc295f83 1515 pdu_complete(pdu, err);
36f8981f 1516 v9fs_string_free(&name);
c1568af5
VJ
1517}
1518
ff06030f 1519static void v9fs_fsync(void *opaque)
b41e95d3 1520{
4e9ad444 1521 int err;
b41e95d3 1522 int32_t fid;
4e9ad444 1523 int datasync;
b41e95d3
VJ
1524 size_t offset = 7;
1525 V9fsFidState *fidp;
4e9ad444 1526 V9fsPDU *pdu = opaque;
b41e95d3 1527
ddca7f86
MK
1528 err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1529 if (err < 0) {
1530 goto out_nofid;
1531 }
c572f23a
HPB
1532 trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync);
1533
bccacf6c 1534 fidp = get_fid(pdu, fid);
b41e95d3
VJ
1535 if (fidp == NULL) {
1536 err = -ENOENT;
84dfb926 1537 goto out_nofid;
b41e95d3 1538 }
bccacf6c 1539 err = v9fs_co_fsync(pdu, fidp, datasync);
4e9ad444
AK
1540 if (!err) {
1541 err = offset;
1542 }
bccacf6c 1543 put_fid(pdu, fidp);
84dfb926 1544out_nofid:
dc295f83 1545 pdu_complete(pdu, err);
b41e95d3
VJ
1546}
1547
ff06030f 1548static void v9fs_clunk(void *opaque)
a6568fe2 1549{
c540ee51 1550 int err;
bbd5697b
AL
1551 int32_t fid;
1552 size_t offset = 7;
84dfb926 1553 V9fsFidState *fidp;
c540ee51
AK
1554 V9fsPDU *pdu = opaque;
1555 V9fsState *s = pdu->s;
bbd5697b 1556
ddca7f86
MK
1557 err = pdu_unmarshal(pdu, offset, "d", &fid);
1558 if (err < 0) {
1559 goto out_nofid;
1560 }
c572f23a 1561 trace_v9fs_clunk(pdu->tag, pdu->id, fid);
84dfb926 1562
ce421a19 1563 fidp = clunk_fid(s, fid);
84dfb926
AK
1564 if (fidp == NULL) {
1565 err = -ENOENT;
1566 goto out_nofid;
1567 }
ce421a19
AK
1568 /*
1569 * Bump the ref so that put_fid will
1570 * free the fid.
1571 */
1572 fidp->ref++;
a911a182
AK
1573 err = put_fid(pdu, fidp);
1574 if (!err) {
1575 err = offset;
1576 }
84dfb926 1577out_nofid:
dc295f83 1578 pdu_complete(pdu, err);
9f107513
AL
1579}
1580
2f008a8c
AK
1581static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1582 uint64_t off, uint32_t max_count)
a9231555 1583{
ddca7f86 1584 ssize_t err;
d208a0e0
AK
1585 size_t offset = 7;
1586 int read_count;
1587 int64_t xattr_len;
a9231555 1588
d208a0e0
AK
1589 xattr_len = fidp->fs.xattr.len;
1590 read_count = xattr_len - off;
1591 if (read_count > max_count) {
1592 read_count = max_count;
1593 } else if (read_count < 0) {
1594 /*
1595 * read beyond XATTR value
1596 */
1597 read_count = 0;
a9231555 1598 }
ddca7f86
MK
1599 err = pdu_marshal(pdu, offset, "d", read_count);
1600 if (err < 0) {
1601 return err;
1602 }
1603 offset += err;
1604 err = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset,
1605 ((char *)fidp->fs.xattr.value) + off,
1606 read_count);
1607 if (err < 0) {
1608 return err;
1609 }
1610 offset += err;
d208a0e0 1611 return offset;
a9231555
AL
1612}
1613
bccacf6c 1614static int v9fs_do_readdir_with_stat(V9fsPDU *pdu,
2f008a8c 1615 V9fsFidState *fidp, uint32_t max_count)
a9231555 1616{
2289be19 1617 V9fsPath path;
d208a0e0
AK
1618 V9fsStat v9stat;
1619 int len, err = 0;
1620 int32_t count = 0;
1621 struct stat stbuf;
1622 off_t saved_dir_pos;
5f524c1e 1623 struct dirent *dent, *result;
a9231555 1624
d208a0e0 1625 /* save the directory position */
bccacf6c 1626 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
d208a0e0
AK
1627 if (saved_dir_pos < 0) {
1628 return saved_dir_pos;
a9231555 1629 }
5f524c1e
HPB
1630
1631 dent = g_malloc(sizeof(struct dirent));
1632
d208a0e0 1633 while (1) {
2289be19 1634 v9fs_path_init(&path);
bccacf6c 1635 err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
5f524c1e 1636 if (err || !result) {
d208a0e0
AK
1637 break;
1638 }
bccacf6c 1639 err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path);
d208a0e0
AK
1640 if (err < 0) {
1641 goto out;
1642 }
bccacf6c 1643 err = v9fs_co_lstat(pdu, &path, &stbuf);
2289be19
AK
1644 if (err < 0) {
1645 goto out;
1646 }
bccacf6c 1647 err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat);
d208a0e0
AK
1648 if (err < 0) {
1649 goto out;
a9231555 1650 }
d208a0e0
AK
1651 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1652 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1653 if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1654 /* Ran out of buffer. Set dir back to old position and return */
bccacf6c 1655 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
d208a0e0 1656 v9fs_stat_free(&v9stat);
2289be19 1657 v9fs_path_free(&path);
5f524c1e 1658 g_free(dent);
d208a0e0
AK
1659 return count;
1660 }
1661 count += len;
1662 v9fs_stat_free(&v9stat);
2289be19 1663 v9fs_path_free(&path);
d208a0e0 1664 saved_dir_pos = dent->d_off;
a9231555 1665 }
a9231555 1666out:
5f524c1e 1667 g_free(dent);
2289be19 1668 v9fs_path_free(&path);
d208a0e0
AK
1669 if (err < 0) {
1670 return err;
fa32ef88 1671 }
d208a0e0 1672 return count;
fa32ef88
AK
1673}
1674
302a0d3e
SH
1675/*
1676 * Create a QEMUIOVector for a sub-region of PDU iovecs
1677 *
1678 * @qiov: uninitialized QEMUIOVector
1679 * @skip: number of bytes to skip from beginning of PDU
1680 * @size: number of bytes to include
1681 * @is_write: true - write, false - read
1682 *
1683 * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up
1684 * with qemu_iovec_destroy().
1685 */
1686static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
1b093c48 1687 size_t skip, size_t size,
302a0d3e
SH
1688 bool is_write)
1689{
1690 QEMUIOVector elem;
1691 struct iovec *iov;
1692 unsigned int niov;
1693
592707af 1694 virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write);
302a0d3e
SH
1695
1696 qemu_iovec_init_external(&elem, iov, niov);
1697 qemu_iovec_init(qiov, niov);
1b093c48 1698 qemu_iovec_concat(qiov, &elem, skip, size);
302a0d3e
SH
1699}
1700
ff06030f 1701static void v9fs_read(void *opaque)
9f107513 1702{
a9231555 1703 int32_t fid;
2f008a8c 1704 uint64_t off;
a9231555 1705 ssize_t err = 0;
d208a0e0
AK
1706 int32_t count = 0;
1707 size_t offset = 7;
2f008a8c 1708 uint32_t max_count;
d208a0e0
AK
1709 V9fsFidState *fidp;
1710 V9fsPDU *pdu = opaque;
1711 V9fsState *s = pdu->s;
a9231555 1712
ddca7f86
MK
1713 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1714 if (err < 0) {
1715 goto out_nofid;
1716 }
c572f23a 1717 trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count);
84dfb926 1718
bccacf6c 1719 fidp = get_fid(pdu, fid);
d208a0e0 1720 if (fidp == NULL) {
a9231555 1721 err = -EINVAL;
84dfb926 1722 goto out_nofid;
a9231555 1723 }
d208a0e0 1724 if (fidp->fid_type == P9_FID_DIR) {
a9231555 1725
d208a0e0 1726 if (off == 0) {
bccacf6c 1727 v9fs_co_rewinddir(pdu, fidp);
a9231555 1728 }
bccacf6c 1729 count = v9fs_do_readdir_with_stat(pdu, fidp, max_count);
d208a0e0
AK
1730 if (count < 0) {
1731 err = count;
1732 goto out;
56d15a53 1733 }
ddca7f86
MK
1734 err = pdu_marshal(pdu, offset, "d", count);
1735 if (err < 0) {
1736 goto out;
1737 }
1738 err += offset + count;
d208a0e0 1739 } else if (fidp->fid_type == P9_FID_FILE) {
302a0d3e
SH
1740 QEMUIOVector qiov_full;
1741 QEMUIOVector qiov;
d208a0e0 1742 int32_t len;
d208a0e0 1743
302a0d3e
SH
1744 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false);
1745 qemu_iovec_init(&qiov, qiov_full.niov);
d208a0e0 1746 do {
302a0d3e 1747 qemu_iovec_reset(&qiov);
1b093c48 1748 qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count);
d208a0e0 1749 if (0) {
302a0d3e 1750 print_sg(qiov.iov, qiov.niov);
d208a0e0
AK
1751 }
1752 /* Loop in case of EINTR */
1753 do {
302a0d3e 1754 len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off);
d208a0e0
AK
1755 if (len >= 0) {
1756 off += len;
1757 count += len;
1758 }
bccacf6c 1759 } while (len == -EINTR && !pdu->cancelled);
d208a0e0
AK
1760 if (len < 0) {
1761 /* IO error return the error */
1762 err = len;
1763 goto out;
1764 }
d208a0e0 1765 } while (count < max_count && len > 0);
ddca7f86
MK
1766 err = pdu_marshal(pdu, offset, "d", count);
1767 if (err < 0) {
1768 goto out;
1769 }
1770 err += offset + count;
302a0d3e
SH
1771 qemu_iovec_destroy(&qiov);
1772 qemu_iovec_destroy(&qiov_full);
d208a0e0
AK
1773 } else if (fidp->fid_type == P9_FID_XATTR) {
1774 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
a9231555
AL
1775 } else {
1776 err = -EINVAL;
9f107513 1777 }
7999f7e1 1778 trace_v9fs_read_return(pdu->tag, pdu->id, count, err);
a9231555 1779out:
bccacf6c 1780 put_fid(pdu, fidp);
84dfb926 1781out_nofid:
dc295f83 1782 pdu_complete(pdu, err);
9f107513
AL
1783}
1784
5e4eaa79 1785static size_t v9fs_readdir_data_size(V9fsString *name)
c18e2f94 1786{
5e4eaa79
AK
1787 /*
1788 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1789 * size of type (1) + size of name.size (2) + strlen(name.data)
1790 */
1791 return 24 + v9fs_string_size(name);
c18e2f94
SK
1792}
1793
bccacf6c 1794static int v9fs_do_readdir(V9fsPDU *pdu,
5e4eaa79 1795 V9fsFidState *fidp, int32_t max_count)
c18e2f94 1796{
c18e2f94 1797 size_t size;
5e4eaa79
AK
1798 V9fsQID qid;
1799 V9fsString name;
1800 int len, err = 0;
1801 int32_t count = 0;
1802 off_t saved_dir_pos;
5f524c1e 1803 struct dirent *dent, *result;
c18e2f94 1804
5e4eaa79 1805 /* save the directory position */
bccacf6c 1806 saved_dir_pos = v9fs_co_telldir(pdu, fidp);
5e4eaa79
AK
1807 if (saved_dir_pos < 0) {
1808 return saved_dir_pos;
1809 }
5f524c1e
HPB
1810
1811 dent = g_malloc(sizeof(struct dirent));
1812
5e4eaa79 1813 while (1) {
bccacf6c 1814 err = v9fs_co_readdir_r(pdu, fidp, dent, &result);
5f524c1e 1815 if (err || !result) {
5e4eaa79
AK
1816 break;
1817 }
1818 v9fs_string_init(&name);
1819 v9fs_string_sprintf(&name, "%s", dent->d_name);
1820 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
c18e2f94 1821 /* Ran out of buffer. Set dir back to old position and return */
bccacf6c 1822 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
5e4eaa79 1823 v9fs_string_free(&name);
5f524c1e 1824 g_free(dent);
5e4eaa79 1825 return count;
c18e2f94 1826 }
5e4eaa79
AK
1827 /*
1828 * Fill up just the path field of qid because the client uses
c18e2f94
SK
1829 * only that. To fill the entire qid structure we will have
1830 * to stat each dirent found, which is expensive
1831 */
5e4eaa79
AK
1832 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1833 memcpy(&qid.path, &dent->d_ino, size);
c18e2f94 1834 /* Fill the other fields with dummy values */
5e4eaa79
AK
1835 qid.type = 0;
1836 qid.version = 0;
c18e2f94 1837
5e4eaa79
AK
1838 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1839 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1840 &qid, dent->d_off,
1841 dent->d_type, &name);
ddca7f86
MK
1842 if (len < 0) {
1843 v9fs_co_seekdir(pdu, fidp, saved_dir_pos);
1844 v9fs_string_free(&name);
1845 g_free(dent);
1846 return len;
1847 }
5e4eaa79
AK
1848 count += len;
1849 v9fs_string_free(&name);
1850 saved_dir_pos = dent->d_off;
1851 }
5f524c1e 1852 g_free(dent);
5e4eaa79
AK
1853 if (err < 0) {
1854 return err;
1855 }
1856 return count;
c18e2f94
SK
1857}
1858
ff06030f 1859static void v9fs_readdir(void *opaque)
c18e2f94
SK
1860{
1861 int32_t fid;
5e4eaa79
AK
1862 V9fsFidState *fidp;
1863 ssize_t retval = 0;
c18e2f94 1864 size_t offset = 7;
2f008a8c
AK
1865 uint64_t initial_offset;
1866 int32_t count;
1867 uint32_t max_count;
5e4eaa79 1868 V9fsPDU *pdu = opaque;
c18e2f94 1869
ddca7f86
MK
1870 retval = pdu_unmarshal(pdu, offset, "dqd", &fid,
1871 &initial_offset, &max_count);
1872 if (retval < 0) {
1873 goto out_nofid;
1874 }
c572f23a
HPB
1875 trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count);
1876
bccacf6c 1877 fidp = get_fid(pdu, fid);
84dfb926
AK
1878 if (fidp == NULL) {
1879 retval = -EINVAL;
1880 goto out_nofid;
1881 }
1882 if (!fidp->fs.dir) {
5e4eaa79 1883 retval = -EINVAL;
c18e2f94
SK
1884 goto out;
1885 }
5e4eaa79 1886 if (initial_offset == 0) {
bccacf6c 1887 v9fs_co_rewinddir(pdu, fidp);
c18e2f94 1888 } else {
bccacf6c 1889 v9fs_co_seekdir(pdu, fidp, initial_offset);
c18e2f94 1890 }
bccacf6c 1891 count = v9fs_do_readdir(pdu, fidp, max_count);
5e4eaa79
AK
1892 if (count < 0) {
1893 retval = count;
1894 goto out;
1895 }
ddca7f86
MK
1896 retval = pdu_marshal(pdu, offset, "d", count);
1897 if (retval < 0) {
1898 goto out;
1899 }
1900 retval += count + offset;
7999f7e1 1901 trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval);
c18e2f94 1902out:
bccacf6c 1903 put_fid(pdu, fidp);
84dfb926 1904out_nofid:
dc295f83 1905 pdu_complete(pdu, retval);
c18e2f94
SK
1906}
1907
d7a90491 1908static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
2f008a8c 1909 uint64_t off, uint32_t count,
d7a90491 1910 struct iovec *sg, int cnt)
10b468bd
AK
1911{
1912 int i, to_copy;
1913 ssize_t err = 0;
1914 int write_count;
1915 int64_t xattr_len;
d7a90491 1916 size_t offset = 7;
10b468bd 1917
d7a90491
AK
1918
1919 xattr_len = fidp->fs.xattr.len;
1920 write_count = xattr_len - off;
1921 if (write_count > count) {
1922 write_count = count;
10b468bd
AK
1923 } else if (write_count < 0) {
1924 /*
1925 * write beyond XATTR value len specified in
1926 * xattrcreate
1927 */
1928 err = -ENOSPC;
1929 goto out;
1930 }
ddca7f86
MK
1931 err = pdu_marshal(pdu, offset, "d", write_count);
1932 if (err < 0) {
1933 return err;
1934 }
1935 err += offset;
d7a90491 1936 fidp->fs.xattr.copied_len += write_count;
10b468bd
AK
1937 /*
1938 * Now copy the content from sg list
1939 */
d7a90491
AK
1940 for (i = 0; i < cnt; i++) {
1941 if (write_count > sg[i].iov_len) {
1942 to_copy = sg[i].iov_len;
10b468bd
AK
1943 } else {
1944 to_copy = write_count;
1945 }
d7a90491 1946 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
10b468bd 1947 /* updating vs->off since we are not using below */
d7a90491 1948 off += to_copy;
10b468bd
AK
1949 write_count -= to_copy;
1950 }
1951out:
d7a90491 1952 return err;
10b468bd
AK
1953}
1954
ff06030f 1955static void v9fs_write(void *opaque)
9f107513 1956{
d7a90491
AK
1957 ssize_t err;
1958 int32_t fid;
2f008a8c
AK
1959 uint64_t off;
1960 uint32_t count;
d7a90491
AK
1961 int32_t len = 0;
1962 int32_t total = 0;
1963 size_t offset = 7;
1964 V9fsFidState *fidp;
ff06030f
VJ
1965 V9fsPDU *pdu = opaque;
1966 V9fsState *s = pdu->s;
302a0d3e
SH
1967 QEMUIOVector qiov_full;
1968 QEMUIOVector qiov;
8449360c 1969
ddca7f86
MK
1970 err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count);
1971 if (err < 0) {
dc295f83 1972 pdu_complete(pdu, err);
0289a412 1973 return;
ddca7f86
MK
1974 }
1975 offset += err;
302a0d3e
SH
1976 v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true);
1977 trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov);
84dfb926 1978
bccacf6c 1979 fidp = get_fid(pdu, fid);
d7a90491 1980 if (fidp == NULL) {
8449360c 1981 err = -EINVAL;
84dfb926 1982 goto out_nofid;
9f107513 1983 }
d7a90491
AK
1984 if (fidp->fid_type == P9_FID_FILE) {
1985 if (fidp->fs.fd == -1) {
10b468bd
AK
1986 err = -EINVAL;
1987 goto out;
1988 }
d7a90491 1989 } else if (fidp->fid_type == P9_FID_XATTR) {
10b468bd
AK
1990 /*
1991 * setxattr operation
1992 */
302a0d3e
SH
1993 err = v9fs_xattr_write(s, pdu, fidp, off, count,
1994 qiov_full.iov, qiov_full.niov);
d7a90491 1995 goto out;
10b468bd 1996 } else {
8449360c
AL
1997 err = -EINVAL;
1998 goto out;
1999 }
302a0d3e 2000 qemu_iovec_init(&qiov, qiov_full.niov);
d7a90491 2001 do {
302a0d3e 2002 qemu_iovec_reset(&qiov);
1b093c48 2003 qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total);
d7a90491 2004 if (0) {
302a0d3e 2005 print_sg(qiov.iov, qiov.niov);
56d15a53 2006 }
d7a90491
AK
2007 /* Loop in case of EINTR */
2008 do {
302a0d3e 2009 len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off);
d7a90491
AK
2010 if (len >= 0) {
2011 off += len;
2012 total += len;
2013 }
bccacf6c 2014 } while (len == -EINTR && !pdu->cancelled);
d7a90491
AK
2015 if (len < 0) {
2016 /* IO error return the error */
2017 err = len;
302a0d3e 2018 goto out_qiov;
d7a90491 2019 }
d7a90491 2020 } while (total < count && len > 0);
302a0d3e
SH
2021
2022 offset = 7;
ddca7f86
MK
2023 err = pdu_marshal(pdu, offset, "d", total);
2024 if (err < 0) {
2025 goto out;
2026 }
2027 err += offset;
7999f7e1 2028 trace_v9fs_write_return(pdu->tag, pdu->id, total, err);
302a0d3e
SH
2029out_qiov:
2030 qemu_iovec_destroy(&qiov);
8449360c 2031out:
bccacf6c 2032 put_fid(pdu, fidp);
84dfb926 2033out_nofid:
302a0d3e 2034 qemu_iovec_destroy(&qiov_full);
dc295f83 2035 pdu_complete(pdu, err);
9f107513
AL
2036}
2037
baaa86d9 2038static void v9fs_create(void *opaque)
5e94c103 2039{
baaa86d9
VJ
2040 int32_t fid;
2041 int err = 0;
2042 size_t offset = 7;
2043 V9fsFidState *fidp;
2044 V9fsQID qid;
2045 int32_t perm;
2046 int8_t mode;
2289be19 2047 V9fsPath path;
baaa86d9
VJ
2048 struct stat stbuf;
2049 V9fsString name;
2050 V9fsString extension;
baaa86d9
VJ
2051 int iounit;
2052 V9fsPDU *pdu = opaque;
c494dd6f 2053
2289be19 2054 v9fs_path_init(&path);
ddca7f86
MK
2055 v9fs_string_init(&name);
2056 v9fs_string_init(&extension);
2057 err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
2058 &perm, &mode, &extension);
2059 if (err < 0) {
2060 goto out_nofid;
2061 }
c572f23a
HPB
2062 trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode);
2063
bccacf6c 2064 fidp = get_fid(pdu, fid);
baaa86d9
VJ
2065 if (fidp == NULL) {
2066 err = -EINVAL;
84dfb926 2067 goto out_nofid;
c494dd6f 2068 }
baaa86d9 2069 if (perm & P9_STAT_MODE_DIR) {
bccacf6c 2070 err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777,
02cb7f3a 2071 fidp->uid, -1, &stbuf);
baaa86d9
VJ
2072 if (err < 0) {
2073 goto out;
2074 }
bccacf6c 2075 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2289be19
AK
2076 if (err < 0) {
2077 goto out;
2078 }
2079 v9fs_path_copy(&fidp->path, &path);
bccacf6c 2080 err = v9fs_co_opendir(pdu, fidp);
baaa86d9
VJ
2081 if (err < 0) {
2082 goto out;
2083 }
2084 fidp->fid_type = P9_FID_DIR;
2085 } else if (perm & P9_STAT_MODE_SYMLINK) {
bccacf6c 2086 err = v9fs_co_symlink(pdu, fidp, &name,
02cb7f3a 2087 extension.data, -1 , &stbuf);
baaa86d9 2088 if (err < 0) {
baaa86d9
VJ
2089 goto out;
2090 }
bccacf6c 2091 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2289be19
AK
2092 if (err < 0) {
2093 goto out;
2094 }
2095 v9fs_path_copy(&fidp->path, &path);
baaa86d9 2096 } else if (perm & P9_STAT_MODE_LINK) {
2289be19 2097 int32_t ofid = atoi(extension.data);
bccacf6c 2098 V9fsFidState *ofidp = get_fid(pdu, ofid);
2289be19 2099 if (ofidp == NULL) {
baaa86d9
VJ
2100 err = -EINVAL;
2101 goto out;
2102 }
bccacf6c
AK
2103 err = v9fs_co_link(pdu, ofidp, fidp, &name);
2104 put_fid(pdu, ofidp);
2289be19
AK
2105 if (err < 0) {
2106 goto out;
2107 }
bccacf6c 2108 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
baaa86d9 2109 if (err < 0) {
2289be19 2110 fidp->fid_type = P9_FID_NONE;
baaa86d9 2111 goto out;
c494dd6f 2112 }
2289be19 2113 v9fs_path_copy(&fidp->path, &path);
bccacf6c 2114 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
02cb7f3a
AK
2115 if (err < 0) {
2116 fidp->fid_type = P9_FID_NONE;
2117 goto out;
2118 }
baaa86d9 2119 } else if (perm & P9_STAT_MODE_DEVICE) {
c494dd6f
AL
2120 char ctype;
2121 uint32_t major, minor;
2122 mode_t nmode = 0;
2123
baaa86d9 2124 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
c494dd6f 2125 err = -errno;
baaa86d9 2126 goto out;
c494dd6f
AL
2127 }
2128
2129 switch (ctype) {
2130 case 'c':
2131 nmode = S_IFCHR;
2132 break;
2133 case 'b':
2134 nmode = S_IFBLK;
2135 break;
2136 default:
2137 err = -EIO;
baaa86d9
VJ
2138 goto out;
2139 }
c1568af5 2140
baaa86d9 2141 nmode |= perm & 0777;
bccacf6c 2142 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
02cb7f3a 2143 makedev(major, minor), nmode, &stbuf);
baaa86d9
VJ
2144 if (err < 0) {
2145 goto out;
2146 }
bccacf6c 2147 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2289be19
AK
2148 if (err < 0) {
2149 goto out;
2150 }
2151 v9fs_path_copy(&fidp->path, &path);
baaa86d9 2152 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
bccacf6c 2153 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
02cb7f3a 2154 0, S_IFIFO | (perm & 0777), &stbuf);
baaa86d9
VJ
2155 if (err < 0) {
2156 goto out;
2157 }
bccacf6c 2158 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2289be19
AK
2159 if (err < 0) {
2160 goto out;
2161 }
2162 v9fs_path_copy(&fidp->path, &path);
baaa86d9 2163 } else if (perm & P9_STAT_MODE_SOCKET) {
bccacf6c 2164 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1,
02cb7f3a 2165 0, S_IFSOCK | (perm & 0777), &stbuf);
baaa86d9
VJ
2166 if (err < 0) {
2167 goto out;
2168 }
bccacf6c 2169 err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path);
2289be19
AK
2170 if (err < 0) {
2171 goto out;
2172 }
2173 v9fs_path_copy(&fidp->path, &path);
baaa86d9 2174 } else {
bccacf6c 2175 err = v9fs_co_open2(pdu, fidp, &name, -1,
02cb7f3a 2176 omode_to_uflags(mode)|O_CREAT, perm, &stbuf);
baaa86d9
VJ
2177 if (err < 0) {
2178 goto out;
2179 }
2180 fidp->fid_type = P9_FID_FILE;
7a462745
AK
2181 fidp->open_flags = omode_to_uflags(mode);
2182 if (fidp->open_flags & O_EXCL) {
2183 /*
2184 * We let the host file system do O_EXCL check
2185 * We should not reclaim such fd
2186 */
2187 fidp->flags |= FID_NON_RECLAIMABLE;
2188 }
c494dd6f 2189 }
bccacf6c 2190 iounit = get_iounit(pdu, &fidp->path);
baaa86d9 2191 stat_to_qid(&stbuf, &qid);
ddca7f86
MK
2192 err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2193 if (err < 0) {
2194 goto out;
2195 }
2196 err += offset;
7999f7e1
AK
2197 trace_v9fs_create_return(pdu->tag, pdu->id,
2198 qid.type, qid.version, qid.path, iounit);
c494dd6f 2199out:
bccacf6c 2200 put_fid(pdu, fidp);
84dfb926 2201out_nofid:
dc295f83 2202 pdu_complete(pdu, err);
baaa86d9
VJ
2203 v9fs_string_free(&name);
2204 v9fs_string_free(&extension);
2289be19 2205 v9fs_path_free(&path);
9f107513
AL
2206}
2207
ff06030f 2208static void v9fs_symlink(void *opaque)
08c60fc9 2209{
ff06030f 2210 V9fsPDU *pdu = opaque;
3fa2a8d1
VJ
2211 V9fsString name;
2212 V9fsString symname;
3fa2a8d1
VJ
2213 V9fsFidState *dfidp;
2214 V9fsQID qid;
2215 struct stat stbuf;
08c60fc9 2216 int32_t dfid;
08c60fc9
VJ
2217 int err = 0;
2218 gid_t gid;
3fa2a8d1 2219 size_t offset = 7;
08c60fc9 2220
ddca7f86
MK
2221 v9fs_string_init(&name);
2222 v9fs_string_init(&symname);
2223 err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2224 if (err < 0) {
2225 goto out_nofid;
2226 }
c572f23a 2227 trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid);
08c60fc9 2228
bccacf6c 2229 dfidp = get_fid(pdu, dfid);
3fa2a8d1 2230 if (dfidp == NULL) {
08c60fc9 2231 err = -EINVAL;
84dfb926 2232 goto out_nofid;
08c60fc9 2233 }
bccacf6c 2234 err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf);
3fa2a8d1
VJ
2235 if (err < 0) {
2236 goto out;
2237 }
2238 stat_to_qid(&stbuf, &qid);
ddca7f86
MK
2239 err = pdu_marshal(pdu, offset, "Q", &qid);
2240 if (err < 0) {
2241 goto out;
2242 }
2243 err += offset;
7999f7e1
AK
2244 trace_v9fs_symlink_return(pdu->tag, pdu->id,
2245 qid.type, qid.version, qid.path);
08c60fc9 2246out:
bccacf6c 2247 put_fid(pdu, dfidp);
84dfb926 2248out_nofid:
dc295f83 2249 pdu_complete(pdu, err);
3fa2a8d1
VJ
2250 v9fs_string_free(&name);
2251 v9fs_string_free(&symname);
08c60fc9
VJ
2252}
2253
ff06030f 2254static void v9fs_flush(void *opaque)
9f107513 2255{
ddca7f86 2256 ssize_t err;
bccacf6c
AK
2257 int16_t tag;
2258 size_t offset = 7;
2259 V9fsPDU *cancel_pdu;
ff06030f
VJ
2260 V9fsPDU *pdu = opaque;
2261 V9fsState *s = pdu->s;
bccacf6c 2262
ddca7f86
MK
2263 err = pdu_unmarshal(pdu, offset, "w", &tag);
2264 if (err < 0) {
dc295f83 2265 pdu_complete(pdu, err);
ddca7f86
MK
2266 return;
2267 }
c572f23a 2268 trace_v9fs_flush(pdu->tag, pdu->id, tag);
bccacf6c
AK
2269
2270 QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
2271 if (cancel_pdu->tag == tag) {
2272 break;
2273 }
2274 }
2275 if (cancel_pdu) {
2276 cancel_pdu->cancelled = 1;
2277 /*
2278 * Wait for pdu to complete.
2279 */
2280 qemu_co_queue_wait(&cancel_pdu->complete);
2281 cancel_pdu->cancelled = 0;
dc295f83 2282 pdu_free(cancel_pdu);
bccacf6c 2283 }
dc295f83 2284 pdu_complete(pdu, 7);
9f107513
AL
2285}
2286
ff06030f 2287static void v9fs_link(void *opaque)
b2c224be 2288{
ff06030f 2289 V9fsPDU *pdu = opaque;
b2c224be
VJ
2290 int32_t dfid, oldfid;
2291 V9fsFidState *dfidp, *oldfidp;
3a93113a 2292 V9fsString name;
b2c224be
VJ
2293 size_t offset = 7;
2294 int err = 0;
2295
ddca7f86
MK
2296 v9fs_string_init(&name);
2297 err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2298 if (err < 0) {
2299 goto out_nofid;
2300 }
c572f23a 2301 trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data);
b2c224be 2302
bccacf6c 2303 dfidp = get_fid(pdu, dfid);
b2c224be 2304 if (dfidp == NULL) {
ffd66876 2305 err = -ENOENT;
84dfb926 2306 goto out_nofid;
b2c224be
VJ
2307 }
2308
bccacf6c 2309 oldfidp = get_fid(pdu, oldfid);
b2c224be 2310 if (oldfidp == NULL) {
ffd66876 2311 err = -ENOENT;
b2c224be
VJ
2312 goto out;
2313 }
bccacf6c 2314 err = v9fs_co_link(pdu, oldfidp, dfidp, &name);
ffd66876
VJ
2315 if (!err) {
2316 err = offset;
b2c224be 2317 }
b2c224be 2318out:
bccacf6c 2319 put_fid(pdu, dfidp);
84dfb926 2320out_nofid:
b2c224be 2321 v9fs_string_free(&name);
dc295f83 2322 pdu_complete(pdu, err);
b2c224be
VJ
2323}
2324
532decb7 2325/* Only works with path name based fid */
ff06030f 2326static void v9fs_remove(void *opaque)
9f107513 2327{
5bae1900 2328 int32_t fid;
5bae1900 2329 int err = 0;
ae1ef571
VJ
2330 size_t offset = 7;
2331 V9fsFidState *fidp;
2332 V9fsPDU *pdu = opaque;
5bae1900 2333
ddca7f86
MK
2334 err = pdu_unmarshal(pdu, offset, "d", &fid);
2335 if (err < 0) {
2336 goto out_nofid;
2337 }
c572f23a 2338 trace_v9fs_remove(pdu->tag, pdu->id, fid);
5bae1900 2339
bccacf6c 2340 fidp = get_fid(pdu, fid);
ae1ef571 2341 if (fidp == NULL) {
5bae1900 2342 err = -EINVAL;
84dfb926 2343 goto out_nofid;
9f107513 2344 }
532decb7 2345 /* if fs driver is not path based, return EOPNOTSUPP */
c98f1d4a 2346 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
532decb7
AK
2347 err = -EOPNOTSUPP;
2348 goto out_err;
2349 }
7a462745
AK
2350 /*
2351 * IF the file is unlinked, we cannot reopen
2352 * the file later. So don't reclaim fd
2353 */
bccacf6c 2354 err = v9fs_mark_fids_unreclaim(pdu, &fidp->path);
7a462745
AK
2355 if (err < 0) {
2356 goto out_err;
2357 }
bccacf6c 2358 err = v9fs_co_remove(pdu, &fidp->path);
ae1ef571
VJ
2359 if (!err) {
2360 err = offset;
2361 }
7a462745 2362out_err:
ae1ef571 2363 /* For TREMOVE we need to clunk the fid even on failed remove */
84dfb926 2364 clunk_fid(pdu->s, fidp->fid);
bccacf6c 2365 put_fid(pdu, fidp);
84dfb926 2366out_nofid:
dc295f83 2367 pdu_complete(pdu, err);
9f107513
AL
2368}
2369
7834cf77
AK
2370static void v9fs_unlinkat(void *opaque)
2371{
2372 int err = 0;
2373 V9fsString name;
2374 int32_t dfid, flags;
2375 size_t offset = 7;
2289be19 2376 V9fsPath path;
7834cf77
AK
2377 V9fsFidState *dfidp;
2378 V9fsPDU *pdu = opaque;
7834cf77 2379
ddca7f86
MK
2380 v9fs_string_init(&name);
2381 err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags);
2382 if (err < 0) {
2383 goto out_nofid;
2384 }
bccacf6c 2385 dfidp = get_fid(pdu, dfid);
7834cf77
AK
2386 if (dfidp == NULL) {
2387 err = -EINVAL;
2388 goto out_nofid;
2389 }
7834cf77
AK
2390 /*
2391 * IF the file is unlinked, we cannot reopen
2392 * the file later. So don't reclaim fd
2393 */
2289be19 2394 v9fs_path_init(&path);
bccacf6c 2395 err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path);
2289be19
AK
2396 if (err < 0) {
2397 goto out_err;
2398 }
bccacf6c 2399 err = v9fs_mark_fids_unreclaim(pdu, &path);
7834cf77
AK
2400 if (err < 0) {
2401 goto out_err;
2402 }
bccacf6c 2403 err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags);
7834cf77
AK
2404 if (!err) {
2405 err = offset;
2406 }
2407out_err:
bccacf6c 2408 put_fid(pdu, dfidp);
2289be19 2409 v9fs_path_free(&path);
7834cf77 2410out_nofid:
dc295f83 2411 pdu_complete(pdu, err);
7834cf77
AK
2412 v9fs_string_free(&name);
2413}
2414
2289be19
AK
2415
2416/* Only works with path name based fid */
bccacf6c 2417static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp,
930b1e17 2418 int32_t newdirfid, V9fsString *name)
8cf89e00 2419{
930b1e17 2420 char *end;
c7b4b0b3 2421 int err = 0;
2289be19
AK
2422 V9fsPath new_path;
2423 V9fsFidState *tfidp;
bccacf6c 2424 V9fsState *s = pdu->s;
84dfb926 2425 V9fsFidState *dirfidp = NULL;
c7b4b0b3 2426 char *old_name, *new_name;
8cf89e00 2427
2289be19 2428 v9fs_path_init(&new_path);
930b1e17 2429 if (newdirfid != -1) {
bccacf6c 2430 dirfidp = get_fid(pdu, newdirfid);
c7b4b0b3
MK
2431 if (dirfidp == NULL) {
2432 err = -ENOENT;
84dfb926 2433 goto out_nofid;
c7b4b0b3 2434 }
d62dbb51 2435 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
bccacf6c 2436 v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path);
c7b4b0b3 2437 } else {
930b1e17 2438 old_name = fidp->path.data;
8cf89e00
AL
2439 end = strrchr(old_name, '/');
2440 if (end) {
2441 end++;
2442 } else {
2443 end = old_name;
2444 }
7267c094 2445 new_name = g_malloc0(end - old_name + name->size + 1);
c7b4b0b3 2446 strncat(new_name, old_name, end - old_name);
930b1e17 2447 strncat(new_name + (end - old_name), name->data, name->size);
bccacf6c 2448 v9fs_co_name_to_path(pdu, NULL, new_name, &new_path);
2289be19 2449 g_free(new_name);
c7b4b0b3 2450 }
bccacf6c 2451 err = v9fs_co_rename(pdu, &fidp->path, &new_path);
2289be19
AK
2452 if (err < 0) {
2453 goto out;
2454 }
2455 /*
2456 * Fixup fid's pointing to the old name to
2457 * start pointing to the new name
2458 */
2459 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2460 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2461 /* replace the name */
2462 v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data));
8cf89e00
AL
2463 }
2464 }
c7b4b0b3 2465out:
84dfb926 2466 if (dirfidp) {
bccacf6c 2467 put_fid(pdu, dirfidp);
84dfb926 2468 }
2289be19 2469 v9fs_path_free(&new_path);
84dfb926 2470out_nofid:
c7b4b0b3
MK
2471 return err;
2472}
2473
532decb7 2474/* Only works with path name based fid */
ff06030f 2475static void v9fs_rename(void *opaque)
c7b4b0b3
MK
2476{
2477 int32_t fid;
c7b4b0b3 2478 ssize_t err = 0;
930b1e17
AK
2479 size_t offset = 7;
2480 V9fsString name;
2481 int32_t newdirfid;
2482 V9fsFidState *fidp;
2483 V9fsPDU *pdu = opaque;
2484 V9fsState *s = pdu->s;
c7b4b0b3 2485
ddca7f86
MK
2486 v9fs_string_init(&name);
2487 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2488 if (err < 0) {
2489 goto out_nofid;
2490 }
bccacf6c 2491 fidp = get_fid(pdu, fid);
930b1e17 2492 if (fidp == NULL) {
c7b4b0b3 2493 err = -ENOENT;
84dfb926 2494 goto out_nofid;
c7b4b0b3 2495 }
930b1e17 2496 BUG_ON(fidp->fid_type != P9_FID_NONE);
532decb7 2497 /* if fs driver is not path based, return EOPNOTSUPP */
c98f1d4a 2498 if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) {
532decb7
AK
2499 err = -EOPNOTSUPP;
2500 goto out;
2501 }
2502 v9fs_path_write_lock(s);
bccacf6c 2503 err = v9fs_complete_rename(pdu, fidp, newdirfid, &name);
532decb7 2504 v9fs_path_unlock(s);
930b1e17
AK
2505 if (!err) {
2506 err = offset;
2507 }
532decb7 2508out:
bccacf6c 2509 put_fid(pdu, fidp);
84dfb926 2510out_nofid:
dc295f83 2511 pdu_complete(pdu, err);
930b1e17 2512 v9fs_string_free(&name);
c7b4b0b3
MK
2513}
2514
bccacf6c 2515static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir,
2289be19
AK
2516 V9fsString *old_name, V9fsPath *newdir,
2517 V9fsString *new_name)
2518{
2519 V9fsFidState *tfidp;
2520 V9fsPath oldpath, newpath;
bccacf6c 2521 V9fsState *s = pdu->s;
2289be19
AK
2522
2523
2524 v9fs_path_init(&oldpath);
2525 v9fs_path_init(&newpath);
bccacf6c
AK
2526 v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath);
2527 v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath);
2289be19
AK
2528
2529 /*
2530 * Fixup fid's pointing to the old name to
2531 * start pointing to the new name
2532 */
2533 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2534 if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) {
2535 /* replace the name */
2536 v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data));
2537 }
2538 }
2539 v9fs_path_free(&oldpath);
2540 v9fs_path_free(&newpath);
2541}
2542
bccacf6c 2543static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid,
89bf6593
AK
2544 V9fsString *old_name, int32_t newdirfid,
2545 V9fsString *new_name)
2546{
2547 int err = 0;
bccacf6c 2548 V9fsState *s = pdu->s;
89bf6593
AK
2549 V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL;
2550
bccacf6c 2551 olddirfidp = get_fid(pdu, olddirfid);
89bf6593
AK
2552 if (olddirfidp == NULL) {
2553 err = -ENOENT;
2554 goto out;
2555 }
89bf6593 2556 if (newdirfid != -1) {
bccacf6c 2557 newdirfidp = get_fid(pdu, newdirfid);
89bf6593
AK
2558 if (newdirfidp == NULL) {
2559 err = -ENOENT;
2560 goto out;
2561 }
89bf6593 2562 } else {
bccacf6c 2563 newdirfidp = get_fid(pdu, olddirfid);
89bf6593
AK
2564 }
2565
bccacf6c 2566 err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name,
2289be19
AK
2567 &newdirfidp->path, new_name);
2568 if (err < 0) {
2569 goto out;
89bf6593 2570 }
c98f1d4a 2571 if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) {
532decb7 2572 /* Only for path based fid we need to do the below fixup */
bccacf6c 2573 v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name,
532decb7
AK
2574 &newdirfidp->path, new_name);
2575 }
89bf6593
AK
2576out:
2577 if (olddirfidp) {
bccacf6c 2578 put_fid(pdu, olddirfidp);
89bf6593
AK
2579 }
2580 if (newdirfidp) {
bccacf6c 2581 put_fid(pdu, newdirfidp);
89bf6593 2582 }
89bf6593
AK
2583 return err;
2584}
2585
2586static void v9fs_renameat(void *opaque)
2587{
2588 ssize_t err = 0;
2589 size_t offset = 7;
2590 V9fsPDU *pdu = opaque;
2591 V9fsState *s = pdu->s;
2592 int32_t olddirfid, newdirfid;
2593 V9fsString old_name, new_name;
2594
ddca7f86
MK
2595 v9fs_string_init(&old_name);
2596 v9fs_string_init(&new_name);
2597 err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid,
2598 &old_name, &newdirfid, &new_name);
2599 if (err < 0) {
2600 goto out_err;
2601 }
89bf6593 2602
532decb7 2603 v9fs_path_write_lock(s);
bccacf6c
AK
2604 err = v9fs_complete_renameat(pdu, olddirfid,
2605 &old_name, newdirfid, &new_name);
532decb7 2606 v9fs_path_unlock(s);
89bf6593
AK
2607 if (!err) {
2608 err = offset;
2609 }
ddca7f86
MK
2610
2611out_err:
dc295f83 2612 pdu_complete(pdu, err);
89bf6593
AK
2613 v9fs_string_free(&old_name);
2614 v9fs_string_free(&new_name);
2615}
2616
b81d685e 2617static void v9fs_wstat(void *opaque)
8cf89e00 2618{
b81d685e
AK
2619 int32_t fid;
2620 int err = 0;
2621 int16_t unused;
2622 V9fsStat v9stat;
2623 size_t offset = 7;
2624 struct stat stbuf;
2625 V9fsFidState *fidp;
2626 V9fsPDU *pdu = opaque;
8cf89e00 2627
ddca7f86
MK
2628 v9fs_stat_init(&v9stat);
2629 err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2630 if (err < 0) {
2631 goto out_nofid;
2632 }
c572f23a
HPB
2633 trace_v9fs_wstat(pdu->tag, pdu->id, fid,
2634 v9stat.mode, v9stat.atime, v9stat.mtime);
84dfb926 2635
bccacf6c 2636 fidp = get_fid(pdu, fid);
b81d685e
AK
2637 if (fidp == NULL) {
2638 err = -EINVAL;
84dfb926 2639 goto out_nofid;
8cf89e00 2640 }
b81d685e
AK
2641 /* do we need to sync the file? */
2642 if (donttouch_stat(&v9stat)) {
bccacf6c 2643 err = v9fs_co_fsync(pdu, fidp, 0);
8cf89e00
AL
2644 goto out;
2645 }
b81d685e
AK
2646 if (v9stat.mode != -1) {
2647 uint32_t v9_mode;
bccacf6c 2648 err = v9fs_co_lstat(pdu, &fidp->path, &stbuf);
b81d685e
AK
2649 if (err < 0) {
2650 goto out;
2651 }
2652 v9_mode = stat_to_v9mode(&stbuf);
2653 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2654 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2655 /* Attempting to change the type */
2656 err = -EIO;
2657 goto out;
2658 }
bccacf6c 2659 err = v9fs_co_chmod(pdu, &fidp->path,
b81d685e
AK
2660 v9mode_to_mode(v9stat.mode,
2661 &v9stat.extension));
2662 if (err < 0) {
2663 goto out;
2664 }
2665 }
2666 if (v9stat.mtime != -1 || v9stat.atime != -1) {
8fc39ae4 2667 struct timespec times[2];
b81d685e
AK
2668 if (v9stat.atime != -1) {
2669 times[0].tv_sec = v9stat.atime;
8fc39ae4
SK
2670 times[0].tv_nsec = 0;
2671 } else {
2672 times[0].tv_nsec = UTIME_OMIT;
2673 }
b81d685e
AK
2674 if (v9stat.mtime != -1) {
2675 times[1].tv_sec = v9stat.mtime;
8fc39ae4
SK
2676 times[1].tv_nsec = 0;
2677 } else {
2678 times[1].tv_nsec = UTIME_OMIT;
2679 }
bccacf6c 2680 err = v9fs_co_utimensat(pdu, &fidp->path, times);
b81d685e
AK
2681 if (err < 0) {
2682 goto out;
8cf89e00
AL
2683 }
2684 }
b81d685e 2685 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
bccacf6c 2686 err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid);
b81d685e 2687 if (err < 0) {
8cf89e00 2688 goto out;
b81d685e 2689 }
8cf89e00 2690 }
b81d685e 2691 if (v9stat.name.size != 0) {
bccacf6c 2692 err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name);
b81d685e
AK
2693 if (err < 0) {
2694 goto out;
2695 }
8cf89e00 2696 }
b81d685e 2697 if (v9stat.length != -1) {
bccacf6c 2698 err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length);
b81d685e
AK
2699 if (err < 0) {
2700 goto out;
2701 }
8cf89e00 2702 }
b81d685e 2703 err = offset;
8cf89e00 2704out:
bccacf6c 2705 put_fid(pdu, fidp);
84dfb926 2706out_nofid:
b81d685e 2707 v9fs_stat_free(&v9stat);
dc295f83 2708 pdu_complete(pdu, err);
9f107513
AL
2709}
2710
88a4763e
AK
2711static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2712{
2713 uint32_t f_type;
2714 uint32_t f_bsize;
2715 uint64_t f_blocks;
2716 uint64_t f_bfree;
2717 uint64_t f_bavail;
2718 uint64_t f_files;
2719 uint64_t f_ffree;
2720 uint64_t fsid_val;
2721 uint32_t f_namelen;
2722 size_t offset = 7;
5e94c103
MK
2723 int32_t bsize_factor;
2724
5e94c103
MK
2725 /*
2726 * compute bsize factor based on host file system block size
2727 * and client msize
2728 */
88a4763e 2729 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
5e94c103
MK
2730 if (!bsize_factor) {
2731 bsize_factor = 1;
2732 }
88a4763e
AK
2733 f_type = stbuf->f_type;
2734 f_bsize = stbuf->f_bsize;
2735 f_bsize *= bsize_factor;
5e94c103
MK
2736 /*
2737 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2738 * adjust(divide) the number of blocks, free blocks and available
2739 * blocks by bsize factor
2740 */
88a4763e
AK
2741 f_blocks = stbuf->f_blocks/bsize_factor;
2742 f_bfree = stbuf->f_bfree/bsize_factor;
2743 f_bavail = stbuf->f_bavail/bsize_factor;
2744 f_files = stbuf->f_files;
2745 f_ffree = stbuf->f_ffree;
2746 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2747 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2748 f_namelen = stbuf->f_namelen;
be940c87 2749
88a4763e
AK
2750 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2751 f_type, f_bsize, f_blocks, f_bfree,
2752 f_bavail, f_files, f_ffree,
2753 fsid_val, f_namelen);
be940c87
MK
2754}
2755
ff06030f 2756static void v9fs_statfs(void *opaque)
be940c87 2757{
88a4763e
AK
2758 int32_t fid;
2759 ssize_t retval = 0;
2760 size_t offset = 7;
2761 V9fsFidState *fidp;
2762 struct statfs stbuf;
ff06030f
VJ
2763 V9fsPDU *pdu = opaque;
2764 V9fsState *s = pdu->s;
be940c87 2765
ddca7f86
MK
2766 retval = pdu_unmarshal(pdu, offset, "d", &fid);
2767 if (retval < 0) {
2768 goto out_nofid;
2769 }
bccacf6c 2770 fidp = get_fid(pdu, fid);
88a4763e
AK
2771 if (fidp == NULL) {
2772 retval = -ENOENT;
84dfb926 2773 goto out_nofid;
be940c87 2774 }
bccacf6c 2775 retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf);
88a4763e
AK
2776 if (retval < 0) {
2777 goto out;
2778 }
ddca7f86
MK
2779 retval = v9fs_fill_statfs(s, pdu, &stbuf);
2780 if (retval < 0) {
2781 goto out;
2782 }
2783 retval += offset;
be940c87 2784out:
bccacf6c 2785 put_fid(pdu, fidp);
84dfb926 2786out_nofid:
dc295f83 2787 pdu_complete(pdu, retval);
be940c87
MK
2788}
2789
ff06030f 2790static void v9fs_mknod(void *opaque)
5268cecc 2791{
1b733fed
AK
2792
2793 int mode;
2794 gid_t gid;
5268cecc 2795 int32_t fid;
1b733fed 2796 V9fsQID qid;
5268cecc 2797 int err = 0;
5268cecc 2798 int major, minor;
1b733fed
AK
2799 size_t offset = 7;
2800 V9fsString name;
2801 struct stat stbuf;
1b733fed
AK
2802 V9fsFidState *fidp;
2803 V9fsPDU *pdu = opaque;
5268cecc 2804
ddca7f86
MK
2805 v9fs_string_init(&name);
2806 err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2807 &major, &minor, &gid);
2808 if (err < 0) {
2809 goto out_nofid;
2810 }
c572f23a 2811 trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor);
5268cecc 2812
bccacf6c 2813 fidp = get_fid(pdu, fid);
5268cecc
MK
2814 if (fidp == NULL) {
2815 err = -ENOENT;
84dfb926 2816 goto out_nofid;
5268cecc 2817 }
bccacf6c 2818 err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid,
02cb7f3a 2819 makedev(major, minor), mode, &stbuf);
1b733fed
AK
2820 if (err < 0) {
2821 goto out;
2822 }
2823 stat_to_qid(&stbuf, &qid);
ddca7f86
MK
2824 err = pdu_marshal(pdu, offset, "Q", &qid);
2825 if (err < 0) {
2826 goto out;
2827 }
2828 err += offset;
7999f7e1
AK
2829 trace_v9fs_mknod_return(pdu->tag, pdu->id,
2830 qid.type, qid.version, qid.path);
5268cecc 2831out:
bccacf6c 2832 put_fid(pdu, fidp);
84dfb926 2833out_nofid:
dc295f83 2834 pdu_complete(pdu, err);
1b733fed 2835 v9fs_string_free(&name);
5268cecc
MK
2836}
2837
82cc3ee8
MK
2838/*
2839 * Implement posix byte range locking code
2840 * Server side handling of locking code is very simple, because 9p server in
2841 * QEMU can handle only one client. And most of the lock handling
2842 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2843 * do any thing in * qemu 9p server side lock code path.
2844 * So when a TLOCK request comes, always return success
2845 */
ff06030f 2846static void v9fs_lock(void *opaque)
82cc3ee8 2847{
0c27bf2a 2848 int8_t status;
ddca7f86 2849 V9fsFlock flock;
0c27bf2a
AK
2850 size_t offset = 7;
2851 struct stat stbuf;
2852 V9fsFidState *fidp;
2853 int32_t fid, err = 0;
ff06030f 2854 V9fsPDU *pdu = opaque;
82cc3ee8 2855
ddca7f86
MK
2856 status = P9_LOCK_ERROR;
2857 v9fs_string_init(&flock.client_id);
2858 err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type,
2859 &flock.flags, &flock.start, &flock.length,
2860 &flock.proc_id, &flock.client_id);
2861 if (err < 0) {
2862 goto out_nofid;
2863 }
c572f23a 2864 trace_v9fs_lock(pdu->tag, pdu->id, fid,
ddca7f86 2865 flock.type, flock.start, flock.length);
c572f23a 2866
82cc3ee8
MK
2867
2868 /* We support only block flag now (that too ignored currently) */
ddca7f86 2869 if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) {
82cc3ee8 2870 err = -EINVAL;
84dfb926 2871 goto out_nofid;
82cc3ee8 2872 }
bccacf6c 2873 fidp = get_fid(pdu, fid);
0c27bf2a 2874 if (fidp == NULL) {
82cc3ee8 2875 err = -ENOENT;
84dfb926 2876 goto out_nofid;
82cc3ee8 2877 }
cc720ddb 2878 err = v9fs_co_fstat(pdu, fidp, &stbuf);
82cc3ee8 2879 if (err < 0) {
82cc3ee8
MK
2880 goto out;
2881 }
0c27bf2a 2882 status = P9_LOCK_SUCCESS;
82cc3ee8 2883out:
bccacf6c 2884 put_fid(pdu, fidp);
84dfb926 2885out_nofid:
ddca7f86
MK
2886 err = pdu_marshal(pdu, offset, "b", status);
2887 if (err > 0) {
2888 err += offset;
2889 }
c572f23a 2890 trace_v9fs_lock_return(pdu->tag, pdu->id, status);
dc295f83 2891 pdu_complete(pdu, err);
ddca7f86 2892 v9fs_string_free(&flock.client_id);
82cc3ee8
MK
2893}
2894
8f354003
MK
2895/*
2896 * When a TGETLOCK request comes, always return success because all lock
2897 * handling is done by client's VFS layer.
2898 */
ff06030f 2899static void v9fs_getlock(void *opaque)
8f354003 2900{
e4e414a4
AK
2901 size_t offset = 7;
2902 struct stat stbuf;
2903 V9fsFidState *fidp;
ddca7f86 2904 V9fsGetlock glock;
e4e414a4 2905 int32_t fid, err = 0;
ff06030f 2906 V9fsPDU *pdu = opaque;
8f354003 2907
ddca7f86
MK
2908 v9fs_string_init(&glock.client_id);
2909 err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type,
2910 &glock.start, &glock.length, &glock.proc_id,
2911 &glock.client_id);
2912 if (err < 0) {
2913 goto out_nofid;
2914 }
c572f23a 2915 trace_v9fs_getlock(pdu->tag, pdu->id, fid,
ddca7f86 2916 glock.type, glock.start, glock.length);
c572f23a 2917
bccacf6c 2918 fidp = get_fid(pdu, fid);
e4e414a4 2919 if (fidp == NULL) {
8f354003 2920 err = -ENOENT;
84dfb926 2921 goto out_nofid;
8f354003 2922 }
cc720ddb 2923 err = v9fs_co_fstat(pdu, fidp, &stbuf);
8f354003 2924 if (err < 0) {
8f354003
MK
2925 goto out;
2926 }
ddca7f86
MK
2927 glock.type = P9_LOCK_TYPE_UNLCK;
2928 err = pdu_marshal(pdu, offset, "bqqds", glock.type,
2929 glock.start, glock.length, glock.proc_id,
2930 &glock.client_id);
2931 if (err < 0) {
2932 goto out;
2933 }
2934 err += offset;
2935 trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start,
2936 glock.length, glock.proc_id);
8f354003 2937out:
bccacf6c 2938 put_fid(pdu, fidp);
84dfb926 2939out_nofid:
dc295f83 2940 pdu_complete(pdu, err);
ddca7f86 2941 v9fs_string_free(&glock.client_id);
8f354003
MK
2942}
2943
ff06030f 2944static void v9fs_mkdir(void *opaque)
b67592ea 2945{
ff06030f 2946 V9fsPDU *pdu = opaque;
e84861f7 2947 size_t offset = 7;
b67592ea 2948 int32_t fid;
e84861f7 2949 struct stat stbuf;
e84861f7 2950 V9fsQID qid;
02cb7f3a 2951 V9fsString name;
b67592ea
MK
2952 V9fsFidState *fidp;
2953 gid_t gid;
2954 int mode;
e84861f7 2955 int err = 0;
b67592ea 2956
ddca7f86
MK
2957 v9fs_string_init(&name);
2958 err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2959 if (err < 0) {
2960 goto out_nofid;
2961 }
c572f23a
HPB
2962 trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid);
2963
bccacf6c 2964 fidp = get_fid(pdu, fid);
b67592ea
MK
2965 if (fidp == NULL) {
2966 err = -ENOENT;
84dfb926 2967 goto out_nofid;
b67592ea 2968 }
bccacf6c 2969 err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf);
e84861f7
VJ
2970 if (err < 0) {
2971 goto out;
2972 }
2973 stat_to_qid(&stbuf, &qid);
ddca7f86
MK
2974 err = pdu_marshal(pdu, offset, "Q", &qid);
2975 if (err < 0) {
2976 goto out;
2977 }
2978 err += offset;
7999f7e1
AK
2979 trace_v9fs_mkdir_return(pdu->tag, pdu->id,
2980 qid.type, qid.version, qid.path, err);
b67592ea 2981out:
bccacf6c 2982 put_fid(pdu, fidp);
84dfb926 2983out_nofid:
dc295f83 2984 pdu_complete(pdu, err);
e84861f7 2985 v9fs_string_free(&name);
b67592ea
MK
2986}
2987
ff06030f 2988static void v9fs_xattrwalk(void *opaque)
fa32ef88 2989{
670185a6
AK
2990 int64_t size;
2991 V9fsString name;
fa32ef88 2992 ssize_t err = 0;
670185a6 2993 size_t offset = 7;
fa32ef88 2994 int32_t fid, newfid;
670185a6 2995 V9fsFidState *file_fidp;
84dfb926 2996 V9fsFidState *xattr_fidp = NULL;
670185a6
AK
2997 V9fsPDU *pdu = opaque;
2998 V9fsState *s = pdu->s;
fa32ef88 2999
ddca7f86
MK
3000 v9fs_string_init(&name);
3001 err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
3002 if (err < 0) {
3003 goto out_nofid;
3004 }
c572f23a
HPB
3005 trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data);
3006
bccacf6c 3007 file_fidp = get_fid(pdu, fid);
670185a6 3008 if (file_fidp == NULL) {
fa32ef88 3009 err = -ENOENT;
84dfb926 3010 goto out_nofid;
fa32ef88 3011 }
670185a6
AK
3012 xattr_fidp = alloc_fid(s, newfid);
3013 if (xattr_fidp == NULL) {
fa32ef88
AK
3014 err = -EINVAL;
3015 goto out;
3016 }
2289be19 3017 v9fs_path_copy(&xattr_fidp->path, &file_fidp->path);
ddca7f86 3018 if (name.data == NULL) {
fa32ef88
AK
3019 /*
3020 * listxattr request. Get the size first
3021 */
bccacf6c 3022 size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0);
670185a6
AK
3023 if (size < 0) {
3024 err = size;
84dfb926 3025 clunk_fid(s, xattr_fidp->fid);
670185a6 3026 goto out;
fa32ef88 3027 }
670185a6
AK
3028 /*
3029 * Read the xattr value
3030 */
3031 xattr_fidp->fs.xattr.len = size;
3032 xattr_fidp->fid_type = P9_FID_XATTR;
3033 xattr_fidp->fs.xattr.copied_len = -1;
3034 if (size) {
7267c094 3035 xattr_fidp->fs.xattr.value = g_malloc(size);
bccacf6c 3036 err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
670185a6
AK
3037 xattr_fidp->fs.xattr.value,
3038 xattr_fidp->fs.xattr.len);
3039 if (err < 0) {
84dfb926 3040 clunk_fid(s, xattr_fidp->fid);
670185a6
AK
3041 goto out;
3042 }
3043 }
ddca7f86
MK
3044 err = pdu_marshal(pdu, offset, "q", size);
3045 if (err < 0) {
3046 goto out;
3047 }
3048 err += offset;
fa32ef88
AK
3049 } else {
3050 /*
3051 * specific xattr fid. We check for xattr
3052 * presence also collect the xattr size
3053 */
bccacf6c 3054 size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
670185a6
AK
3055 &name, NULL, 0);
3056 if (size < 0) {
3057 err = size;
84dfb926 3058 clunk_fid(s, xattr_fidp->fid);
670185a6 3059 goto out;
fa32ef88 3060 }
670185a6
AK
3061 /*
3062 * Read the xattr value
3063 */
3064 xattr_fidp->fs.xattr.len = size;
3065 xattr_fidp->fid_type = P9_FID_XATTR;
3066 xattr_fidp->fs.xattr.copied_len = -1;
3067 if (size) {
7267c094 3068 xattr_fidp->fs.xattr.value = g_malloc(size);
bccacf6c 3069 err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
670185a6
AK
3070 &name, xattr_fidp->fs.xattr.value,
3071 xattr_fidp->fs.xattr.len);
3072 if (err < 0) {
84dfb926 3073 clunk_fid(s, xattr_fidp->fid);
670185a6
AK
3074 goto out;
3075 }
3076 }
ddca7f86
MK
3077 err = pdu_marshal(pdu, offset, "q", size);
3078 if (err < 0) {
3079 goto out;
3080 }
3081 err += offset;
fa32ef88 3082 }
7999f7e1 3083 trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size);
fa32ef88 3084out:
bccacf6c 3085 put_fid(pdu, file_fidp);
84dfb926 3086 if (xattr_fidp) {
bccacf6c 3087 put_fid(pdu, xattr_fidp);
84dfb926
AK
3088 }
3089out_nofid:
dc295f83 3090 pdu_complete(pdu, err);
670185a6 3091 v9fs_string_free(&name);
fa32ef88
AK
3092}
3093
ff06030f 3094static void v9fs_xattrcreate(void *opaque)
10b468bd
AK
3095{
3096 int flags;
3097 int32_t fid;
f10ff58d 3098 int64_t size;
10b468bd 3099 ssize_t err = 0;
f10ff58d
AK
3100 V9fsString name;
3101 size_t offset = 7;
3102 V9fsFidState *file_fidp;
3103 V9fsFidState *xattr_fidp;
3104 V9fsPDU *pdu = opaque;
10b468bd 3105
ddca7f86
MK
3106 v9fs_string_init(&name);
3107 err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags);
3108 if (err < 0) {
3109 goto out_nofid;
3110 }
c572f23a 3111 trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags);
10b468bd 3112
bccacf6c 3113 file_fidp = get_fid(pdu, fid);
f10ff58d 3114 if (file_fidp == NULL) {
10b468bd 3115 err = -EINVAL;
84dfb926 3116 goto out_nofid;
10b468bd 3117 }
10b468bd 3118 /* Make the file fid point to xattr */
f10ff58d
AK
3119 xattr_fidp = file_fidp;
3120 xattr_fidp->fid_type = P9_FID_XATTR;
3121 xattr_fidp->fs.xattr.copied_len = 0;
3122 xattr_fidp->fs.xattr.len = size;
3123 xattr_fidp->fs.xattr.flags = flags;
3124 v9fs_string_init(&xattr_fidp->fs.xattr.name);
3125 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
6528499f 3126 xattr_fidp->fs.xattr.value = g_malloc(size);
f10ff58d 3127 err = offset;
bccacf6c 3128 put_fid(pdu, file_fidp);
84dfb926 3129out_nofid:
dc295f83 3130 pdu_complete(pdu, err);
f10ff58d 3131 v9fs_string_free(&name);
10b468bd 3132}
fa32ef88 3133
ff06030f 3134static void v9fs_readlink(void *opaque)
df0973a4 3135{
ff06030f 3136 V9fsPDU *pdu = opaque;
7a5ca31e
VJ
3137 size_t offset = 7;
3138 V9fsString target;
df0973a4 3139 int32_t fid;
df0973a4
MK
3140 int err = 0;
3141 V9fsFidState *fidp;
3142
ddca7f86
MK
3143 err = pdu_unmarshal(pdu, offset, "d", &fid);
3144 if (err < 0) {
3145 goto out_nofid;
3146 }
c572f23a 3147 trace_v9fs_readlink(pdu->tag, pdu->id, fid);
bccacf6c 3148 fidp = get_fid(pdu, fid);
df0973a4
MK
3149 if (fidp == NULL) {
3150 err = -ENOENT;
84dfb926 3151 goto out_nofid;
df0973a4
MK
3152 }
3153
7a5ca31e 3154 v9fs_string_init(&target);
bccacf6c 3155 err = v9fs_co_readlink(pdu, &fidp->path, &target);
7a5ca31e
VJ
3156 if (err < 0) {
3157 goto out;
3158 }
ddca7f86
MK
3159 err = pdu_marshal(pdu, offset, "s", &target);
3160 if (err < 0) {
3161 v9fs_string_free(&target);
3162 goto out;
3163 }
3164 err += offset;
7999f7e1 3165 trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data);
7a5ca31e 3166 v9fs_string_free(&target);
df0973a4 3167out:
bccacf6c 3168 put_fid(pdu, fidp);
84dfb926 3169out_nofid:
dc295f83 3170 pdu_complete(pdu, err);
df0973a4
MK
3171}
3172
ff06030f 3173static CoroutineEntry *pdu_co_handlers[] = {
c18e2f94 3174 [P9_TREADDIR] = v9fs_readdir,
be940c87 3175 [P9_TSTATFS] = v9fs_statfs,
00ede4c2 3176 [P9_TGETATTR] = v9fs_getattr,
c79ce737 3177 [P9_TSETATTR] = v9fs_setattr,
fa32ef88 3178 [P9_TXATTRWALK] = v9fs_xattrwalk,
10b468bd 3179 [P9_TXATTRCREATE] = v9fs_xattrcreate,
5268cecc 3180 [P9_TMKNOD] = v9fs_mknod,
c7b4b0b3 3181 [P9_TRENAME] = v9fs_rename,
82cc3ee8 3182 [P9_TLOCK] = v9fs_lock,
8f354003 3183 [P9_TGETLOCK] = v9fs_getlock,
89bf6593 3184 [P9_TRENAMEAT] = v9fs_renameat,
df0973a4 3185 [P9_TREADLINK] = v9fs_readlink,
7834cf77 3186 [P9_TUNLINKAT] = v9fs_unlinkat,
b67592ea 3187 [P9_TMKDIR] = v9fs_mkdir,
9f107513 3188 [P9_TVERSION] = v9fs_version,
771e9d4c 3189 [P9_TLOPEN] = v9fs_open,
9f107513
AL
3190 [P9_TATTACH] = v9fs_attach,
3191 [P9_TSTAT] = v9fs_stat,
3192 [P9_TWALK] = v9fs_walk,
3193 [P9_TCLUNK] = v9fs_clunk,
b41e95d3 3194 [P9_TFSYNC] = v9fs_fsync,
9f107513
AL
3195 [P9_TOPEN] = v9fs_open,
3196 [P9_TREAD] = v9fs_read,
3197#if 0
3198 [P9_TAUTH] = v9fs_auth,
3199#endif
3200 [P9_TFLUSH] = v9fs_flush,
b2c224be 3201 [P9_TLINK] = v9fs_link,
08c60fc9 3202 [P9_TSYMLINK] = v9fs_symlink,
9f107513 3203 [P9_TCREATE] = v9fs_create,
c1568af5 3204 [P9_TLCREATE] = v9fs_lcreate,
9f107513
AL
3205 [P9_TWRITE] = v9fs_write,
3206 [P9_TWSTAT] = v9fs_wstat,
3207 [P9_TREMOVE] = v9fs_remove,
3208};
3209
ff06030f 3210static void v9fs_op_not_supp(void *opaque)
5c3234c6 3211{
ff06030f 3212 V9fsPDU *pdu = opaque;
dc295f83 3213 pdu_complete(pdu, -EOPNOTSUPP);
5c3234c6
AK
3214}
3215
2c74c2cb
MK
3216static void v9fs_fs_ro(void *opaque)
3217{
3218 V9fsPDU *pdu = opaque;
dc295f83 3219 pdu_complete(pdu, -EROFS);
2c74c2cb
MK
3220}
3221
3222static inline bool is_read_only_op(V9fsPDU *pdu)
3223{
3224 switch (pdu->id) {
3225 case P9_TREADDIR:
3226 case P9_TSTATFS:
3227 case P9_TGETATTR:
3228 case P9_TXATTRWALK:
3229 case P9_TLOCK:
3230 case P9_TGETLOCK:
3231 case P9_TREADLINK:
3232 case P9_TVERSION:
3233 case P9_TLOPEN:
3234 case P9_TATTACH:
3235 case P9_TSTAT:
3236 case P9_TWALK:
3237 case P9_TCLUNK:
3238 case P9_TFSYNC:
3239 case P9_TOPEN:
3240 case P9_TREAD:
3241 case P9_TAUTH:
3242 case P9_TFLUSH:
3243 return 1;
3244 default:
3245 return 0;
3246 }
3247}
3248
dc295f83 3249static void pdu_submit(V9fsPDU *pdu)
9f107513 3250{
ff06030f
VJ
3251 Coroutine *co;
3252 CoroutineEntry *handler;
ad38ce9e 3253 V9fsState *s = pdu->s;
9f107513 3254
ff06030f
VJ
3255 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
3256 (pdu_co_handlers[pdu->id] == NULL)) {
5c3234c6
AK
3257 handler = v9fs_op_not_supp;
3258 } else {
ff06030f 3259 handler = pdu_co_handlers[pdu->id];
5c3234c6 3260 }
2c74c2cb
MK
3261
3262 if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) {
3263 handler = v9fs_fs_ro;
3264 }
ff06030f
VJ
3265 co = qemu_coroutine_create(handler);
3266 qemu_coroutine_enter(co, pdu);
9f107513
AL
3267}
3268
f4f61d27 3269void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
9f107513
AL
3270{
3271 V9fsState *s = (V9fsState *)vdev;
3272 V9fsPDU *pdu;
3273 ssize_t len;
3274
dc295f83 3275 while ((pdu = pdu_alloc(s)) &&
9f107513 3276 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
cd4bfbb2
MT
3277 struct {
3278 uint32_t size_le;
3279 uint8_t id;
3280 uint16_t tag_le;
3281 } QEMU_PACKED out;
3282 int len;
3283
9f107513 3284 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
cd4bfbb2
MT
3285 QEMU_BUILD_BUG_ON(sizeof out != 7);
3286
3287 len = iov_to_buf(pdu->elem.out_sg, pdu->elem.out_num, 0,
3288 &out, sizeof out);
3289 BUG_ON(len != sizeof out);
3290
3291 pdu->size = le32_to_cpu(out.size_le);
9f107513 3292
cd4bfbb2
MT
3293 pdu->id = out.id;
3294 pdu->tag = le16_to_cpu(out.tag_le);
9f107513 3295
bccacf6c 3296 qemu_co_queue_init(&pdu->complete);
dc295f83 3297 pdu_submit(pdu);
9f107513 3298 }
dc295f83 3299 pdu_free(pdu);
9f107513 3300}
7a462745 3301
60653b28 3302static void __attribute__((__constructor__)) virtio_9p_set_fd_limit(void)
7a462745
AK
3303{
3304 struct rlimit rlim;
3305 if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
3306 fprintf(stderr, "Failed to get the resource limit\n");
3307 exit(1);
3308 }
3309 open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3);
3310 open_fd_rc = rlim.rlim_cur/2;
3311}