]> git.proxmox.com Git - qemu.git/blob - hw/9pfs/virtio-9p.c
hw/9pfs: Add reference counting for fid
[qemu.git] / hw / 9pfs / virtio-9p.c
1 /*
2 * Virtio 9p backend
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
12 */
13
14 #include "hw/virtio.h"
15 #include "hw/pc.h"
16 #include "qemu_socket.h"
17 #include "hw/virtio-pci.h"
18 #include "virtio-9p.h"
19 #include "fsdev/qemu-fsdev.h"
20 #include "virtio-9p-debug.h"
21 #include "virtio-9p-xattr.h"
22 #include "virtio-9p-coth.h"
23
24 int debug_9p_pdu;
25
26 enum {
27 Oread = 0x00,
28 Owrite = 0x01,
29 Ordwr = 0x02,
30 Oexec = 0x03,
31 Oexcl = 0x04,
32 Otrunc = 0x10,
33 Orexec = 0x20,
34 Orclose = 0x40,
35 Oappend = 0x80,
36 };
37
38 static int omode_to_uflags(int8_t mode)
39 {
40 int ret = 0;
41
42 switch (mode & 3) {
43 case Oread:
44 ret = O_RDONLY;
45 break;
46 case Ordwr:
47 ret = O_RDWR;
48 break;
49 case Owrite:
50 ret = O_WRONLY;
51 break;
52 case Oexec:
53 ret = O_RDONLY;
54 break;
55 }
56
57 if (mode & Otrunc) {
58 ret |= O_TRUNC;
59 }
60
61 if (mode & Oappend) {
62 ret |= O_APPEND;
63 }
64
65 if (mode & Oexcl) {
66 ret |= O_EXCL;
67 }
68
69 return ret;
70 }
71
72 void cred_init(FsCred *credp)
73 {
74 credp->fc_uid = -1;
75 credp->fc_gid = -1;
76 credp->fc_mode = -1;
77 credp->fc_rdev = -1;
78 }
79
80 static void v9fs_string_init(V9fsString *str)
81 {
82 str->data = NULL;
83 str->size = 0;
84 }
85
86 static void v9fs_string_free(V9fsString *str)
87 {
88 g_free(str->data);
89 str->data = NULL;
90 str->size = 0;
91 }
92
93 static void v9fs_string_null(V9fsString *str)
94 {
95 v9fs_string_free(str);
96 }
97
98 static int number_to_string(void *arg, char type)
99 {
100 unsigned int ret = 0;
101
102 switch (type) {
103 case 'u': {
104 unsigned int num = *(unsigned int *)arg;
105
106 do {
107 ret++;
108 num = num/10;
109 } while (num);
110 break;
111 }
112 case 'U': {
113 unsigned long num = *(unsigned long *)arg;
114 do {
115 ret++;
116 num = num/10;
117 } while (num);
118 break;
119 }
120 default:
121 printf("Number_to_string: Unknown number format\n");
122 return -1;
123 }
124
125 return ret;
126 }
127
128 static int GCC_FMT_ATTR(2, 0)
129 v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
130 {
131 va_list ap2;
132 char *iter = (char *)fmt;
133 int len = 0;
134 int nr_args = 0;
135 char *arg_char_ptr;
136 unsigned int arg_uint;
137 unsigned long arg_ulong;
138
139 /* Find the number of %'s that denotes an argument */
140 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
141 nr_args++;
142 iter++;
143 }
144
145 len = strlen(fmt) - 2*nr_args;
146
147 if (!nr_args) {
148 goto alloc_print;
149 }
150
151 va_copy(ap2, ap);
152
153 iter = (char *)fmt;
154
155 /* Now parse the format string */
156 for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
157 iter++;
158 switch (*iter) {
159 case 'u':
160 arg_uint = va_arg(ap2, unsigned int);
161 len += number_to_string((void *)&arg_uint, 'u');
162 break;
163 case 'l':
164 if (*++iter == 'u') {
165 arg_ulong = va_arg(ap2, unsigned long);
166 len += number_to_string((void *)&arg_ulong, 'U');
167 } else {
168 return -1;
169 }
170 break;
171 case 's':
172 arg_char_ptr = va_arg(ap2, char *);
173 len += strlen(arg_char_ptr);
174 break;
175 case 'c':
176 len += 1;
177 break;
178 default:
179 fprintf(stderr,
180 "v9fs_string_alloc_printf:Incorrect format %c", *iter);
181 return -1;
182 }
183 iter++;
184 }
185
186 alloc_print:
187 *strp = g_malloc((len + 1) * sizeof(**strp));
188
189 return vsprintf(*strp, fmt, ap);
190 }
191
192 static void GCC_FMT_ATTR(2, 3)
193 v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
194 {
195 va_list ap;
196 int err;
197
198 v9fs_string_free(str);
199
200 va_start(ap, fmt);
201 err = v9fs_string_alloc_printf(&str->data, fmt, ap);
202 BUG_ON(err == -1);
203 va_end(ap);
204
205 str->size = err;
206 }
207
208 static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
209 {
210 v9fs_string_free(lhs);
211 v9fs_string_sprintf(lhs, "%s", rhs->data);
212 }
213
214 /*
215 * Return TRUE if s1 is an ancestor of s2.
216 *
217 * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d".
218 * As a special case, We treat s1 as ancestor of s2 if they are same!
219 */
220 static int v9fs_path_is_ancestor(V9fsString *s1, V9fsString *s2)
221 {
222 if (!strncmp(s1->data, s2->data, s1->size)) {
223 if (s2->data[s1->size] == '\0' || s2->data[s1->size] == '/') {
224 return 1;
225 }
226 }
227 return 0;
228 }
229
230 static size_t v9fs_string_size(V9fsString *str)
231 {
232 return str->size;
233 }
234
235 static V9fsFidState *get_fid(V9fsState *s, int32_t fid)
236 {
237 V9fsFidState *f;
238
239 for (f = s->fid_list; f; f = f->next) {
240 BUG_ON(f->clunked);
241 if (f->fid == fid) {
242 f->ref++;
243 return f;
244 }
245 }
246 return NULL;
247 }
248
249 static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
250 {
251 V9fsFidState *f;
252
253 for (f = s->fid_list; f; f = f->next) {
254 /* If fid is already there return NULL */
255 BUG_ON(f->clunked);
256 if (f->fid == fid) {
257 return NULL;
258 }
259 }
260 f = g_malloc0(sizeof(V9fsFidState));
261 f->fid = fid;
262 f->fid_type = P9_FID_NONE;
263 f->ref = 1;
264 f->next = s->fid_list;
265 s->fid_list = f;
266
267 return f;
268 }
269
270 static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
271 {
272 int retval = 0;
273
274 if (fidp->fs.xattr.copied_len == -1) {
275 /* getxattr/listxattr fid */
276 goto free_value;
277 }
278 /*
279 * if this is fid for setxattr. clunk should
280 * result in setxattr localcall
281 */
282 if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
283 /* clunk after partial write */
284 retval = -EINVAL;
285 goto free_out;
286 }
287 if (fidp->fs.xattr.len) {
288 retval = v9fs_co_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
289 fidp->fs.xattr.value,
290 fidp->fs.xattr.len,
291 fidp->fs.xattr.flags);
292 } else {
293 retval = v9fs_co_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
294 }
295 free_out:
296 v9fs_string_free(&fidp->fs.xattr.name);
297 free_value:
298 if (fidp->fs.xattr.value) {
299 g_free(fidp->fs.xattr.value);
300 }
301 return retval;
302 }
303
304 static int free_fid(V9fsState *s, V9fsFidState *fidp)
305 {
306 int retval = 0;
307
308 if (fidp->fid_type == P9_FID_FILE) {
309 retval = v9fs_co_close(s, fidp);
310 } else if (fidp->fid_type == P9_FID_DIR) {
311 retval = v9fs_co_closedir(s, fidp);
312 } else if (fidp->fid_type == P9_FID_XATTR) {
313 retval = v9fs_xattr_fid_clunk(s, fidp);
314 }
315 v9fs_string_free(&fidp->path);
316 g_free(fidp);
317 return retval;
318 }
319
320 static void put_fid(V9fsState *s, V9fsFidState *fidp)
321 {
322 BUG_ON(!fidp->ref);
323 fidp->ref--;
324 if (!fidp->ref && fidp->clunked) {
325 free_fid(s, fidp);
326 }
327 }
328
329 static int clunk_fid(V9fsState *s, int32_t fid)
330 {
331 V9fsFidState **fidpp, *fidp;
332
333 for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
334 if ((*fidpp)->fid == fid) {
335 break;
336 }
337 }
338
339 if (*fidpp == NULL) {
340 return -ENOENT;
341 }
342 fidp = *fidpp;
343 *fidpp = fidp->next;
344 fidp->clunked = 1;
345 return 0;
346 }
347
348 #define P9_QID_TYPE_DIR 0x80
349 #define P9_QID_TYPE_SYMLINK 0x02
350
351 #define P9_STAT_MODE_DIR 0x80000000
352 #define P9_STAT_MODE_APPEND 0x40000000
353 #define P9_STAT_MODE_EXCL 0x20000000
354 #define P9_STAT_MODE_MOUNT 0x10000000
355 #define P9_STAT_MODE_AUTH 0x08000000
356 #define P9_STAT_MODE_TMP 0x04000000
357 #define P9_STAT_MODE_SYMLINK 0x02000000
358 #define P9_STAT_MODE_LINK 0x01000000
359 #define P9_STAT_MODE_DEVICE 0x00800000
360 #define P9_STAT_MODE_NAMED_PIPE 0x00200000
361 #define P9_STAT_MODE_SOCKET 0x00100000
362 #define P9_STAT_MODE_SETUID 0x00080000
363 #define P9_STAT_MODE_SETGID 0x00040000
364 #define P9_STAT_MODE_SETVTX 0x00010000
365
366 #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
367 P9_STAT_MODE_SYMLINK | \
368 P9_STAT_MODE_LINK | \
369 P9_STAT_MODE_DEVICE | \
370 P9_STAT_MODE_NAMED_PIPE | \
371 P9_STAT_MODE_SOCKET)
372
373 /* This is the algorithm from ufs in spfs */
374 static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
375 {
376 size_t size;
377
378 size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
379 memcpy(&qidp->path, &stbuf->st_ino, size);
380 qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
381 qidp->type = 0;
382 if (S_ISDIR(stbuf->st_mode)) {
383 qidp->type |= P9_QID_TYPE_DIR;
384 }
385 if (S_ISLNK(stbuf->st_mode)) {
386 qidp->type |= P9_QID_TYPE_SYMLINK;
387 }
388 }
389
390 static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
391 {
392 struct stat stbuf;
393 int err;
394
395 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
396 if (err < 0) {
397 return err;
398 }
399 stat_to_qid(&stbuf, qidp);
400 return 0;
401 }
402
403 static V9fsPDU *alloc_pdu(V9fsState *s)
404 {
405 V9fsPDU *pdu = NULL;
406
407 if (!QLIST_EMPTY(&s->free_list)) {
408 pdu = QLIST_FIRST(&s->free_list);
409 QLIST_REMOVE(pdu, next);
410 }
411 return pdu;
412 }
413
414 static void free_pdu(V9fsState *s, V9fsPDU *pdu)
415 {
416 if (pdu) {
417 if (debug_9p_pdu) {
418 pprint_pdu(pdu);
419 }
420 QLIST_INSERT_HEAD(&s->free_list, pdu, next);
421 }
422 }
423
424 size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
425 size_t offset, size_t size, int pack)
426 {
427 int i = 0;
428 size_t copied = 0;
429
430 for (i = 0; size && i < sg_count; i++) {
431 size_t len;
432 if (offset >= sg[i].iov_len) {
433 /* skip this sg */
434 offset -= sg[i].iov_len;
435 continue;
436 } else {
437 len = MIN(sg[i].iov_len - offset, size);
438 if (pack) {
439 memcpy(sg[i].iov_base + offset, addr, len);
440 } else {
441 memcpy(addr, sg[i].iov_base + offset, len);
442 }
443 size -= len;
444 copied += len;
445 addr += len;
446 if (size) {
447 offset = 0;
448 continue;
449 }
450 }
451 }
452
453 return copied;
454 }
455
456 static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
457 {
458 return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
459 offset, size, 0);
460 }
461
462 static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
463 size_t size)
464 {
465 return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
466 offset, size, 1);
467 }
468
469 static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
470 {
471 size_t pos = 0;
472 int i, j;
473 struct iovec *src_sg;
474 unsigned int num;
475
476 if (rx) {
477 src_sg = pdu->elem.in_sg;
478 num = pdu->elem.in_num;
479 } else {
480 src_sg = pdu->elem.out_sg;
481 num = pdu->elem.out_num;
482 }
483
484 j = 0;
485 for (i = 0; i < num; i++) {
486 if (offset <= pos) {
487 sg[j].iov_base = src_sg[i].iov_base;
488 sg[j].iov_len = src_sg[i].iov_len;
489 j++;
490 } else if (offset < (src_sg[i].iov_len + pos)) {
491 sg[j].iov_base = src_sg[i].iov_base;
492 sg[j].iov_len = src_sg[i].iov_len;
493 sg[j].iov_base += (offset - pos);
494 sg[j].iov_len -= (offset - pos);
495 j++;
496 }
497 pos += src_sg[i].iov_len;
498 }
499
500 return j;
501 }
502
503 static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
504 {
505 size_t old_offset = offset;
506 va_list ap;
507 int i;
508
509 va_start(ap, fmt);
510 for (i = 0; fmt[i]; i++) {
511 switch (fmt[i]) {
512 case 'b': {
513 uint8_t *valp = va_arg(ap, uint8_t *);
514 offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
515 break;
516 }
517 case 'w': {
518 uint16_t val, *valp;
519 valp = va_arg(ap, uint16_t *);
520 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
521 *valp = le16_to_cpu(val);
522 break;
523 }
524 case 'd': {
525 uint32_t val, *valp;
526 valp = va_arg(ap, uint32_t *);
527 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
528 *valp = le32_to_cpu(val);
529 break;
530 }
531 case 'q': {
532 uint64_t val, *valp;
533 valp = va_arg(ap, uint64_t *);
534 offset += pdu_unpack(&val, pdu, offset, sizeof(val));
535 *valp = le64_to_cpu(val);
536 break;
537 }
538 case 'v': {
539 struct iovec *iov = va_arg(ap, struct iovec *);
540 int *iovcnt = va_arg(ap, int *);
541 *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
542 break;
543 }
544 case 's': {
545 V9fsString *str = va_arg(ap, V9fsString *);
546 offset += pdu_unmarshal(pdu, offset, "w", &str->size);
547 /* FIXME: sanity check str->size */
548 str->data = g_malloc(str->size + 1);
549 offset += pdu_unpack(str->data, pdu, offset, str->size);
550 str->data[str->size] = 0;
551 break;
552 }
553 case 'Q': {
554 V9fsQID *qidp = va_arg(ap, V9fsQID *);
555 offset += pdu_unmarshal(pdu, offset, "bdq",
556 &qidp->type, &qidp->version, &qidp->path);
557 break;
558 }
559 case 'S': {
560 V9fsStat *statp = va_arg(ap, V9fsStat *);
561 offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
562 &statp->size, &statp->type, &statp->dev,
563 &statp->qid, &statp->mode, &statp->atime,
564 &statp->mtime, &statp->length,
565 &statp->name, &statp->uid, &statp->gid,
566 &statp->muid, &statp->extension,
567 &statp->n_uid, &statp->n_gid,
568 &statp->n_muid);
569 break;
570 }
571 case 'I': {
572 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
573 offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
574 &iattr->valid, &iattr->mode,
575 &iattr->uid, &iattr->gid, &iattr->size,
576 &iattr->atime_sec, &iattr->atime_nsec,
577 &iattr->mtime_sec, &iattr->mtime_nsec);
578 break;
579 }
580 default:
581 break;
582 }
583 }
584
585 va_end(ap);
586
587 return offset - old_offset;
588 }
589
590 static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
591 {
592 size_t old_offset = offset;
593 va_list ap;
594 int i;
595
596 va_start(ap, fmt);
597 for (i = 0; fmt[i]; i++) {
598 switch (fmt[i]) {
599 case 'b': {
600 uint8_t val = va_arg(ap, int);
601 offset += pdu_pack(pdu, offset, &val, sizeof(val));
602 break;
603 }
604 case 'w': {
605 uint16_t val;
606 cpu_to_le16w(&val, va_arg(ap, int));
607 offset += pdu_pack(pdu, offset, &val, sizeof(val));
608 break;
609 }
610 case 'd': {
611 uint32_t val;
612 cpu_to_le32w(&val, va_arg(ap, uint32_t));
613 offset += pdu_pack(pdu, offset, &val, sizeof(val));
614 break;
615 }
616 case 'q': {
617 uint64_t val;
618 cpu_to_le64w(&val, va_arg(ap, uint64_t));
619 offset += pdu_pack(pdu, offset, &val, sizeof(val));
620 break;
621 }
622 case 'v': {
623 struct iovec *iov = va_arg(ap, struct iovec *);
624 int *iovcnt = va_arg(ap, int *);
625 *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
626 break;
627 }
628 case 's': {
629 V9fsString *str = va_arg(ap, V9fsString *);
630 offset += pdu_marshal(pdu, offset, "w", str->size);
631 offset += pdu_pack(pdu, offset, str->data, str->size);
632 break;
633 }
634 case 'Q': {
635 V9fsQID *qidp = va_arg(ap, V9fsQID *);
636 offset += pdu_marshal(pdu, offset, "bdq",
637 qidp->type, qidp->version, qidp->path);
638 break;
639 }
640 case 'S': {
641 V9fsStat *statp = va_arg(ap, V9fsStat *);
642 offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
643 statp->size, statp->type, statp->dev,
644 &statp->qid, statp->mode, statp->atime,
645 statp->mtime, statp->length, &statp->name,
646 &statp->uid, &statp->gid, &statp->muid,
647 &statp->extension, statp->n_uid,
648 statp->n_gid, statp->n_muid);
649 break;
650 }
651 case 'A': {
652 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
653 offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
654 statp->st_result_mask,
655 &statp->qid, statp->st_mode,
656 statp->st_uid, statp->st_gid,
657 statp->st_nlink, statp->st_rdev,
658 statp->st_size, statp->st_blksize, statp->st_blocks,
659 statp->st_atime_sec, statp->st_atime_nsec,
660 statp->st_mtime_sec, statp->st_mtime_nsec,
661 statp->st_ctime_sec, statp->st_ctime_nsec,
662 statp->st_btime_sec, statp->st_btime_nsec,
663 statp->st_gen, statp->st_data_version);
664 break;
665 }
666 default:
667 break;
668 }
669 }
670 va_end(ap);
671
672 return offset - old_offset;
673 }
674
675 static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
676 {
677 int8_t id = pdu->id + 1; /* Response */
678
679 if (len < 0) {
680 int err = -len;
681 len = 7;
682
683 if (s->proto_version != V9FS_PROTO_2000L) {
684 V9fsString str;
685
686 str.data = strerror(err);
687 str.size = strlen(str.data);
688
689 len += pdu_marshal(pdu, len, "s", &str);
690 id = P9_RERROR;
691 }
692
693 len += pdu_marshal(pdu, len, "d", err);
694
695 if (s->proto_version == V9FS_PROTO_2000L) {
696 id = P9_RLERROR;
697 }
698 }
699
700 /* fill out the header */
701 pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
702
703 /* keep these in sync */
704 pdu->size = len;
705 pdu->id = id;
706
707 /* push onto queue and notify */
708 virtqueue_push(s->vq, &pdu->elem, len);
709
710 /* FIXME: we should batch these completions */
711 virtio_notify(&s->vdev, s->vq);
712
713 free_pdu(s, pdu);
714 }
715
716 static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
717 {
718 mode_t ret;
719
720 ret = mode & 0777;
721 if (mode & P9_STAT_MODE_DIR) {
722 ret |= S_IFDIR;
723 }
724
725 if (mode & P9_STAT_MODE_SYMLINK) {
726 ret |= S_IFLNK;
727 }
728 if (mode & P9_STAT_MODE_SOCKET) {
729 ret |= S_IFSOCK;
730 }
731 if (mode & P9_STAT_MODE_NAMED_PIPE) {
732 ret |= S_IFIFO;
733 }
734 if (mode & P9_STAT_MODE_DEVICE) {
735 if (extension && extension->data[0] == 'c') {
736 ret |= S_IFCHR;
737 } else {
738 ret |= S_IFBLK;
739 }
740 }
741
742 if (!(ret&~0777)) {
743 ret |= S_IFREG;
744 }
745
746 if (mode & P9_STAT_MODE_SETUID) {
747 ret |= S_ISUID;
748 }
749 if (mode & P9_STAT_MODE_SETGID) {
750 ret |= S_ISGID;
751 }
752 if (mode & P9_STAT_MODE_SETVTX) {
753 ret |= S_ISVTX;
754 }
755
756 return ret;
757 }
758
759 static int donttouch_stat(V9fsStat *stat)
760 {
761 if (stat->type == -1 &&
762 stat->dev == -1 &&
763 stat->qid.type == -1 &&
764 stat->qid.version == -1 &&
765 stat->qid.path == -1 &&
766 stat->mode == -1 &&
767 stat->atime == -1 &&
768 stat->mtime == -1 &&
769 stat->length == -1 &&
770 !stat->name.size &&
771 !stat->uid.size &&
772 !stat->gid.size &&
773 !stat->muid.size &&
774 stat->n_uid == -1 &&
775 stat->n_gid == -1 &&
776 stat->n_muid == -1) {
777 return 1;
778 }
779
780 return 0;
781 }
782
783 static void v9fs_stat_free(V9fsStat *stat)
784 {
785 v9fs_string_free(&stat->name);
786 v9fs_string_free(&stat->uid);
787 v9fs_string_free(&stat->gid);
788 v9fs_string_free(&stat->muid);
789 v9fs_string_free(&stat->extension);
790 }
791
792 static uint32_t stat_to_v9mode(const struct stat *stbuf)
793 {
794 uint32_t mode;
795
796 mode = stbuf->st_mode & 0777;
797 if (S_ISDIR(stbuf->st_mode)) {
798 mode |= P9_STAT_MODE_DIR;
799 }
800
801 if (S_ISLNK(stbuf->st_mode)) {
802 mode |= P9_STAT_MODE_SYMLINK;
803 }
804
805 if (S_ISSOCK(stbuf->st_mode)) {
806 mode |= P9_STAT_MODE_SOCKET;
807 }
808
809 if (S_ISFIFO(stbuf->st_mode)) {
810 mode |= P9_STAT_MODE_NAMED_PIPE;
811 }
812
813 if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
814 mode |= P9_STAT_MODE_DEVICE;
815 }
816
817 if (stbuf->st_mode & S_ISUID) {
818 mode |= P9_STAT_MODE_SETUID;
819 }
820
821 if (stbuf->st_mode & S_ISGID) {
822 mode |= P9_STAT_MODE_SETGID;
823 }
824
825 if (stbuf->st_mode & S_ISVTX) {
826 mode |= P9_STAT_MODE_SETVTX;
827 }
828
829 return mode;
830 }
831
832 static int stat_to_v9stat(V9fsState *s, V9fsString *name,
833 const struct stat *stbuf,
834 V9fsStat *v9stat)
835 {
836 int err;
837 const char *str;
838
839 memset(v9stat, 0, sizeof(*v9stat));
840
841 stat_to_qid(stbuf, &v9stat->qid);
842 v9stat->mode = stat_to_v9mode(stbuf);
843 v9stat->atime = stbuf->st_atime;
844 v9stat->mtime = stbuf->st_mtime;
845 v9stat->length = stbuf->st_size;
846
847 v9fs_string_null(&v9stat->uid);
848 v9fs_string_null(&v9stat->gid);
849 v9fs_string_null(&v9stat->muid);
850
851 v9stat->n_uid = stbuf->st_uid;
852 v9stat->n_gid = stbuf->st_gid;
853 v9stat->n_muid = 0;
854
855 v9fs_string_null(&v9stat->extension);
856
857 if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
858 err = v9fs_co_readlink(s, name, &v9stat->extension);
859 if (err < 0) {
860 return err;
861 }
862 } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
863 v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
864 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
865 major(stbuf->st_rdev), minor(stbuf->st_rdev));
866 } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
867 v9fs_string_sprintf(&v9stat->extension, "%s %lu",
868 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
869 }
870
871 str = strrchr(name->data, '/');
872 if (str) {
873 str += 1;
874 } else {
875 str = name->data;
876 }
877
878 v9fs_string_sprintf(&v9stat->name, "%s", str);
879
880 v9stat->size = 61 +
881 v9fs_string_size(&v9stat->name) +
882 v9fs_string_size(&v9stat->uid) +
883 v9fs_string_size(&v9stat->gid) +
884 v9fs_string_size(&v9stat->muid) +
885 v9fs_string_size(&v9stat->extension);
886 return 0;
887 }
888
889 #define P9_STATS_MODE 0x00000001ULL
890 #define P9_STATS_NLINK 0x00000002ULL
891 #define P9_STATS_UID 0x00000004ULL
892 #define P9_STATS_GID 0x00000008ULL
893 #define P9_STATS_RDEV 0x00000010ULL
894 #define P9_STATS_ATIME 0x00000020ULL
895 #define P9_STATS_MTIME 0x00000040ULL
896 #define P9_STATS_CTIME 0x00000080ULL
897 #define P9_STATS_INO 0x00000100ULL
898 #define P9_STATS_SIZE 0x00000200ULL
899 #define P9_STATS_BLOCKS 0x00000400ULL
900
901 #define P9_STATS_BTIME 0x00000800ULL
902 #define P9_STATS_GEN 0x00001000ULL
903 #define P9_STATS_DATA_VERSION 0x00002000ULL
904
905 #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */
906 #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
907
908
909 static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
910 V9fsStatDotl *v9lstat)
911 {
912 memset(v9lstat, 0, sizeof(*v9lstat));
913
914 v9lstat->st_mode = stbuf->st_mode;
915 v9lstat->st_nlink = stbuf->st_nlink;
916 v9lstat->st_uid = stbuf->st_uid;
917 v9lstat->st_gid = stbuf->st_gid;
918 v9lstat->st_rdev = stbuf->st_rdev;
919 v9lstat->st_size = stbuf->st_size;
920 v9lstat->st_blksize = stbuf->st_blksize;
921 v9lstat->st_blocks = stbuf->st_blocks;
922 v9lstat->st_atime_sec = stbuf->st_atime;
923 v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
924 v9lstat->st_mtime_sec = stbuf->st_mtime;
925 v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
926 v9lstat->st_ctime_sec = stbuf->st_ctime;
927 v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
928 /* Currently we only support BASIC fields in stat */
929 v9lstat->st_result_mask = P9_STATS_BASIC;
930
931 stat_to_qid(stbuf, &v9lstat->qid);
932 }
933
934 static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
935 {
936 while (len && *iovcnt) {
937 if (len < sg->iov_len) {
938 sg->iov_len -= len;
939 sg->iov_base += len;
940 len = 0;
941 } else {
942 len -= sg->iov_len;
943 sg++;
944 *iovcnt -= 1;
945 }
946 }
947
948 return sg;
949 }
950
951 static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
952 {
953 int i;
954 int total = 0;
955
956 for (i = 0; i < *cnt; i++) {
957 if ((total + sg[i].iov_len) > cap) {
958 sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
959 i++;
960 break;
961 }
962 total += sg[i].iov_len;
963 }
964
965 *cnt = i;
966
967 return sg;
968 }
969
970 static void print_sg(struct iovec *sg, int cnt)
971 {
972 int i;
973
974 printf("sg[%d]: {", cnt);
975 for (i = 0; i < cnt; i++) {
976 if (i) {
977 printf(", ");
978 }
979 printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
980 }
981 printf("}\n");
982 }
983
984 static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
985 {
986 V9fsString str;
987 v9fs_string_init(&str);
988 v9fs_string_copy(&str, dst);
989 v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
990 v9fs_string_free(&str);
991 }
992
993 static void v9fs_version(void *opaque)
994 {
995 V9fsPDU *pdu = opaque;
996 V9fsState *s = pdu->s;
997 V9fsString version;
998 size_t offset = 7;
999
1000 pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1001
1002 if (!strcmp(version.data, "9P2000.u")) {
1003 s->proto_version = V9FS_PROTO_2000U;
1004 } else if (!strcmp(version.data, "9P2000.L")) {
1005 s->proto_version = V9FS_PROTO_2000L;
1006 } else {
1007 v9fs_string_sprintf(&version, "unknown");
1008 }
1009
1010 offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1011 complete_pdu(s, pdu, offset);
1012
1013 v9fs_string_free(&version);
1014 return;
1015 }
1016
1017 static void v9fs_attach(void *opaque)
1018 {
1019 V9fsPDU *pdu = opaque;
1020 V9fsState *s = pdu->s;
1021 int32_t fid, afid, n_uname;
1022 V9fsString uname, aname;
1023 V9fsFidState *fidp;
1024 size_t offset = 7;
1025 V9fsQID qid;
1026 ssize_t err;
1027
1028 pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1029
1030 fidp = alloc_fid(s, fid);
1031 if (fidp == NULL) {
1032 err = -EINVAL;
1033 goto out_nofid;
1034 }
1035 fidp->uid = n_uname;
1036 v9fs_string_sprintf(&fidp->path, "%s", "/");
1037 err = fid_to_qid(s, fidp, &qid);
1038 if (err < 0) {
1039 err = -EINVAL;
1040 clunk_fid(s, fid);
1041 goto out;
1042 }
1043 offset += pdu_marshal(pdu, offset, "Q", &qid);
1044 err = offset;
1045 out:
1046 put_fid(s, fidp);
1047 out_nofid:
1048 complete_pdu(s, pdu, err);
1049 v9fs_string_free(&uname);
1050 v9fs_string_free(&aname);
1051 }
1052
1053 static void v9fs_stat(void *opaque)
1054 {
1055 int32_t fid;
1056 V9fsStat v9stat;
1057 ssize_t err = 0;
1058 size_t offset = 7;
1059 struct stat stbuf;
1060 V9fsFidState *fidp;
1061 V9fsPDU *pdu = opaque;
1062 V9fsState *s = pdu->s;
1063
1064 pdu_unmarshal(pdu, offset, "d", &fid);
1065
1066 fidp = get_fid(s, fid);
1067 if (fidp == NULL) {
1068 err = -ENOENT;
1069 goto out_nofid;
1070 }
1071 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1072 if (err < 0) {
1073 goto out;
1074 }
1075 err = stat_to_v9stat(s, &fidp->path, &stbuf, &v9stat);
1076 if (err < 0) {
1077 goto out;
1078 }
1079 offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat);
1080 err = offset;
1081 v9fs_stat_free(&v9stat);
1082 out:
1083 put_fid(s, fidp);
1084 out_nofid:
1085 complete_pdu(s, pdu, err);
1086 }
1087
1088 static void v9fs_getattr(void *opaque)
1089 {
1090 int32_t fid;
1091 size_t offset = 7;
1092 ssize_t retval = 0;
1093 struct stat stbuf;
1094 V9fsFidState *fidp;
1095 uint64_t request_mask;
1096 V9fsStatDotl v9stat_dotl;
1097 V9fsPDU *pdu = opaque;
1098 V9fsState *s = pdu->s;
1099
1100 pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
1101
1102 fidp = get_fid(s, fid);
1103 if (fidp == NULL) {
1104 retval = -ENOENT;
1105 goto out_nofid;
1106 }
1107 /*
1108 * Currently we only support BASIC fields in stat, so there is no
1109 * need to look at request_mask.
1110 */
1111 retval = v9fs_co_lstat(s, &fidp->path, &stbuf);
1112 if (retval < 0) {
1113 goto out;
1114 }
1115 stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
1116 retval = offset;
1117 retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl);
1118 out:
1119 put_fid(s, fidp);
1120 out_nofid:
1121 complete_pdu(s, pdu, retval);
1122 }
1123
1124 /* From Linux kernel code */
1125 #define ATTR_MODE (1 << 0)
1126 #define ATTR_UID (1 << 1)
1127 #define ATTR_GID (1 << 2)
1128 #define ATTR_SIZE (1 << 3)
1129 #define ATTR_ATIME (1 << 4)
1130 #define ATTR_MTIME (1 << 5)
1131 #define ATTR_CTIME (1 << 6)
1132 #define ATTR_MASK 127
1133 #define ATTR_ATIME_SET (1 << 7)
1134 #define ATTR_MTIME_SET (1 << 8)
1135
1136 static void v9fs_setattr(void *opaque)
1137 {
1138 int err = 0;
1139 int32_t fid;
1140 V9fsFidState *fidp;
1141 size_t offset = 7;
1142 V9fsIattr v9iattr;
1143 V9fsPDU *pdu = opaque;
1144 V9fsState *s = pdu->s;
1145
1146 pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr);
1147
1148 fidp = get_fid(s, fid);
1149 if (fidp == NULL) {
1150 err = -EINVAL;
1151 goto out_nofid;
1152 }
1153 if (v9iattr.valid & ATTR_MODE) {
1154 err = v9fs_co_chmod(s, &fidp->path, v9iattr.mode);
1155 if (err < 0) {
1156 goto out;
1157 }
1158 }
1159 if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1160 struct timespec times[2];
1161 if (v9iattr.valid & ATTR_ATIME) {
1162 if (v9iattr.valid & ATTR_ATIME_SET) {
1163 times[0].tv_sec = v9iattr.atime_sec;
1164 times[0].tv_nsec = v9iattr.atime_nsec;
1165 } else {
1166 times[0].tv_nsec = UTIME_NOW;
1167 }
1168 } else {
1169 times[0].tv_nsec = UTIME_OMIT;
1170 }
1171 if (v9iattr.valid & ATTR_MTIME) {
1172 if (v9iattr.valid & ATTR_MTIME_SET) {
1173 times[1].tv_sec = v9iattr.mtime_sec;
1174 times[1].tv_nsec = v9iattr.mtime_nsec;
1175 } else {
1176 times[1].tv_nsec = UTIME_NOW;
1177 }
1178 } else {
1179 times[1].tv_nsec = UTIME_OMIT;
1180 }
1181 err = v9fs_co_utimensat(s, &fidp->path, times);
1182 if (err < 0) {
1183 goto out;
1184 }
1185 }
1186 /*
1187 * If the only valid entry in iattr is ctime we can call
1188 * chown(-1,-1) to update the ctime of the file
1189 */
1190 if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1191 ((v9iattr.valid & ATTR_CTIME)
1192 && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1193 if (!(v9iattr.valid & ATTR_UID)) {
1194 v9iattr.uid = -1;
1195 }
1196 if (!(v9iattr.valid & ATTR_GID)) {
1197 v9iattr.gid = -1;
1198 }
1199 err = v9fs_co_chown(s, &fidp->path, v9iattr.uid,
1200 v9iattr.gid);
1201 if (err < 0) {
1202 goto out;
1203 }
1204 }
1205 if (v9iattr.valid & (ATTR_SIZE)) {
1206 err = v9fs_co_truncate(s, &fidp->path, v9iattr.size);
1207 if (err < 0) {
1208 goto out;
1209 }
1210 }
1211 err = offset;
1212 out:
1213 put_fid(s, fidp);
1214 out_nofid:
1215 complete_pdu(s, pdu, err);
1216 }
1217
1218 static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids)
1219 {
1220 int i;
1221 size_t offset = 7;
1222 offset += pdu_marshal(pdu, offset, "w", nwnames);
1223 for (i = 0; i < nwnames; i++) {
1224 offset += pdu_marshal(pdu, offset, "Q", &qids[i]);
1225 }
1226 return offset;
1227 }
1228
1229 static void v9fs_walk(void *opaque)
1230 {
1231 int name_idx;
1232 V9fsQID *qids = NULL;
1233 int i, err = 0;
1234 V9fsString path;
1235 uint16_t nwnames;
1236 struct stat stbuf;
1237 size_t offset = 7;
1238 int32_t fid, newfid;
1239 V9fsString *wnames = NULL;
1240 V9fsFidState *fidp;
1241 V9fsFidState *newfidp = NULL;;
1242 V9fsPDU *pdu = opaque;
1243 V9fsState *s = pdu->s;
1244
1245 offset += pdu_unmarshal(pdu, offset, "ddw", &fid,
1246 &newfid, &nwnames);
1247
1248 if (nwnames && nwnames <= P9_MAXWELEM) {
1249 wnames = g_malloc0(sizeof(wnames[0]) * nwnames);
1250 qids = g_malloc0(sizeof(qids[0]) * nwnames);
1251 for (i = 0; i < nwnames; i++) {
1252 offset += pdu_unmarshal(pdu, offset, "s", &wnames[i]);
1253 }
1254
1255 } else if (nwnames > P9_MAXWELEM) {
1256 err = -EINVAL;
1257 goto out_nofid;
1258 }
1259 fidp = get_fid(s, fid);
1260 if (fidp == NULL) {
1261 err = -ENOENT;
1262 goto out_nofid;
1263 }
1264 if (fid == newfid) {
1265 BUG_ON(fidp->fid_type != P9_FID_NONE);
1266 v9fs_string_init(&path);
1267 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1268 v9fs_string_sprintf(&path, "%s/%s",
1269 fidp->path.data, wnames[name_idx].data);
1270 v9fs_string_copy(&fidp->path, &path);
1271
1272 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1273 if (err < 0) {
1274 v9fs_string_free(&path);
1275 goto out;
1276 }
1277 stat_to_qid(&stbuf, &qids[name_idx]);
1278 }
1279 v9fs_string_free(&path);
1280 } else {
1281 newfidp = alloc_fid(s, newfid);
1282 if (newfidp == NULL) {
1283 err = -EINVAL;
1284 goto out;
1285 }
1286 newfidp->uid = fidp->uid;
1287 v9fs_string_init(&path);
1288 v9fs_string_copy(&newfidp->path, &fidp->path);
1289 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1290 v9fs_string_sprintf(&path, "%s/%s", newfidp->path.data,
1291 wnames[name_idx].data);
1292 v9fs_string_copy(&newfidp->path, &path);
1293 err = v9fs_co_lstat(s, &newfidp->path, &stbuf);
1294 if (err < 0) {
1295 clunk_fid(s, newfidp->fid);
1296 v9fs_string_free(&path);
1297 goto out;
1298 }
1299 stat_to_qid(&stbuf, &qids[name_idx]);
1300 }
1301 v9fs_string_free(&path);
1302 }
1303 err = v9fs_walk_marshal(pdu, nwnames, qids);
1304 out:
1305 put_fid(s, fidp);
1306 if (newfidp) {
1307 put_fid(s, newfidp);
1308 }
1309 out_nofid:
1310 complete_pdu(s, pdu, err);
1311 if (nwnames && nwnames <= P9_MAXWELEM) {
1312 for (name_idx = 0; name_idx < nwnames; name_idx++) {
1313 v9fs_string_free(&wnames[name_idx]);
1314 }
1315 g_free(wnames);
1316 g_free(qids);
1317 }
1318 }
1319
1320 static int32_t get_iounit(V9fsState *s, V9fsString *name)
1321 {
1322 struct statfs stbuf;
1323 int32_t iounit = 0;
1324
1325 /*
1326 * iounit should be multiples of f_bsize (host filesystem block size
1327 * and as well as less than (client msize - P9_IOHDRSZ))
1328 */
1329 if (!v9fs_co_statfs(s, name, &stbuf)) {
1330 iounit = stbuf.f_bsize;
1331 iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
1332 }
1333 if (!iounit) {
1334 iounit = s->msize - P9_IOHDRSZ;
1335 }
1336 return iounit;
1337 }
1338
1339 static void v9fs_open(void *opaque)
1340 {
1341 int flags;
1342 int iounit;
1343 int32_t fid;
1344 int32_t mode;
1345 V9fsQID qid;
1346 ssize_t err = 0;
1347 size_t offset = 7;
1348 struct stat stbuf;
1349 V9fsFidState *fidp;
1350 V9fsPDU *pdu = opaque;
1351 V9fsState *s = pdu->s;
1352
1353 if (s->proto_version == V9FS_PROTO_2000L) {
1354 pdu_unmarshal(pdu, offset, "dd", &fid, &mode);
1355 } else {
1356 pdu_unmarshal(pdu, offset, "db", &fid, &mode);
1357 }
1358 fidp = get_fid(s, fid);
1359 if (fidp == NULL) {
1360 err = -ENOENT;
1361 goto out_nofid;
1362 }
1363 BUG_ON(fidp->fid_type != P9_FID_NONE);
1364
1365 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
1366 if (err < 0) {
1367 goto out;
1368 }
1369 stat_to_qid(&stbuf, &qid);
1370 if (S_ISDIR(stbuf.st_mode)) {
1371 err = v9fs_co_opendir(s, fidp);
1372 if (err < 0) {
1373 goto out;
1374 }
1375 fidp->fid_type = P9_FID_DIR;
1376 offset += pdu_marshal(pdu, offset, "Qd", &qid, 0);
1377 err = offset;
1378 } else {
1379 if (s->proto_version == V9FS_PROTO_2000L) {
1380 flags = mode;
1381 flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
1382 /* Ignore direct disk access hint until the server supports it. */
1383 flags &= ~O_DIRECT;
1384 } else {
1385 flags = omode_to_uflags(mode);
1386 }
1387 err = v9fs_co_open(s, fidp, flags);
1388 if (err < 0) {
1389 goto out;
1390 }
1391 fidp->fid_type = P9_FID_FILE;
1392 iounit = get_iounit(s, &fidp->path);
1393 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1394 err = offset;
1395 }
1396 out:
1397 put_fid(s, fidp);
1398 out_nofid:
1399 complete_pdu(s, pdu, err);
1400 }
1401
1402 static void v9fs_lcreate(void *opaque)
1403 {
1404 int32_t dfid, flags, mode;
1405 gid_t gid;
1406 ssize_t err = 0;
1407 ssize_t offset = 7;
1408 V9fsString fullname;
1409 V9fsString name;
1410 V9fsFidState *fidp;
1411 struct stat stbuf;
1412 V9fsQID qid;
1413 int32_t iounit;
1414 V9fsPDU *pdu = opaque;
1415
1416 v9fs_string_init(&fullname);
1417 pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags,
1418 &mode, &gid);
1419
1420 fidp = get_fid(pdu->s, dfid);
1421 if (fidp == NULL) {
1422 err = -ENOENT;
1423 goto out_nofid;
1424 }
1425 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
1426
1427 /* Ignore direct disk access hint until the server supports it. */
1428 flags &= ~O_DIRECT;
1429
1430 err = v9fs_co_open2(pdu->s, fidp, fullname.data, gid, flags, mode);
1431 if (err < 0) {
1432 goto out;
1433 }
1434 fidp->fid_type = P9_FID_FILE;
1435 iounit = get_iounit(pdu->s, &fullname);
1436
1437 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1438 if (err < 0) {
1439 fidp->fid_type = P9_FID_NONE;
1440 if (fidp->fs.fd > 0) {
1441 close(fidp->fs.fd);
1442 }
1443 goto out;
1444 }
1445 v9fs_string_copy(&fidp->path, &fullname);
1446 stat_to_qid(&stbuf, &qid);
1447 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
1448 err = offset;
1449 out:
1450 put_fid(pdu->s, fidp);
1451 out_nofid:
1452 complete_pdu(pdu->s, pdu, err);
1453 v9fs_string_free(&name);
1454 v9fs_string_free(&fullname);
1455 }
1456
1457 static void v9fs_fsync(void *opaque)
1458 {
1459 int err;
1460 int32_t fid;
1461 int datasync;
1462 size_t offset = 7;
1463 V9fsFidState *fidp;
1464 V9fsPDU *pdu = opaque;
1465 V9fsState *s = pdu->s;
1466
1467 pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
1468 fidp = get_fid(s, fid);
1469 if (fidp == NULL) {
1470 err = -ENOENT;
1471 goto out_nofid;
1472 }
1473 err = v9fs_co_fsync(s, fidp, datasync);
1474 if (!err) {
1475 err = offset;
1476 }
1477 put_fid(s, fidp);
1478 out_nofid:
1479 complete_pdu(s, pdu, err);
1480 }
1481
1482 static void v9fs_clunk(void *opaque)
1483 {
1484 int err;
1485 int32_t fid;
1486 size_t offset = 7;
1487 V9fsFidState *fidp;
1488 V9fsPDU *pdu = opaque;
1489 V9fsState *s = pdu->s;
1490
1491 pdu_unmarshal(pdu, offset, "d", &fid);
1492
1493 fidp = get_fid(s, fid);
1494 if (fidp == NULL) {
1495 err = -ENOENT;
1496 goto out_nofid;
1497 }
1498 err = clunk_fid(s, fidp->fid);
1499 if (err < 0) {
1500 goto out;
1501 }
1502 err = offset;
1503 out:
1504 put_fid(s, fidp);
1505 out_nofid:
1506 complete_pdu(s, pdu, err);
1507 }
1508
1509 static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu,
1510 V9fsFidState *fidp, int64_t off, int32_t max_count)
1511 {
1512 size_t offset = 7;
1513 int read_count;
1514 int64_t xattr_len;
1515
1516 xattr_len = fidp->fs.xattr.len;
1517 read_count = xattr_len - off;
1518 if (read_count > max_count) {
1519 read_count = max_count;
1520 } else if (read_count < 0) {
1521 /*
1522 * read beyond XATTR value
1523 */
1524 read_count = 0;
1525 }
1526 offset += pdu_marshal(pdu, offset, "d", read_count);
1527 offset += pdu_pack(pdu, offset,
1528 ((char *)fidp->fs.xattr.value) + off,
1529 read_count);
1530 return offset;
1531 }
1532
1533 static int v9fs_do_readdir_with_stat(V9fsState *s, V9fsPDU *pdu,
1534 V9fsFidState *fidp, int32_t max_count)
1535 {
1536 V9fsString name;
1537 V9fsStat v9stat;
1538 int len, err = 0;
1539 int32_t count = 0;
1540 struct stat stbuf;
1541 off_t saved_dir_pos;
1542 struct dirent *dent, *result;
1543
1544 /* save the directory position */
1545 saved_dir_pos = v9fs_co_telldir(s, fidp);
1546 if (saved_dir_pos < 0) {
1547 return saved_dir_pos;
1548 }
1549
1550 dent = g_malloc(sizeof(struct dirent));
1551
1552 while (1) {
1553 v9fs_string_init(&name);
1554 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1555 if (err || !result) {
1556 break;
1557 }
1558 v9fs_string_sprintf(&name, "%s/%s", fidp->path.data, dent->d_name);
1559 err = v9fs_co_lstat(s, &name, &stbuf);
1560 if (err < 0) {
1561 goto out;
1562 }
1563 err = stat_to_v9stat(s, &name, &stbuf, &v9stat);
1564 if (err < 0) {
1565 goto out;
1566 }
1567 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1568 len = pdu_marshal(pdu, 11 + count, "S", &v9stat);
1569 if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) {
1570 /* Ran out of buffer. Set dir back to old position and return */
1571 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1572 v9fs_stat_free(&v9stat);
1573 v9fs_string_free(&name);
1574 g_free(dent);
1575 return count;
1576 }
1577 count += len;
1578 v9fs_stat_free(&v9stat);
1579 v9fs_string_free(&name);
1580 saved_dir_pos = dent->d_off;
1581 }
1582 out:
1583 g_free(dent);
1584 v9fs_string_free(&name);
1585 if (err < 0) {
1586 return err;
1587 }
1588 return count;
1589 }
1590
1591 static void v9fs_read(void *opaque)
1592 {
1593 int32_t fid;
1594 int64_t off;
1595 ssize_t err = 0;
1596 int32_t count = 0;
1597 size_t offset = 7;
1598 int32_t max_count;
1599 V9fsFidState *fidp;
1600 V9fsPDU *pdu = opaque;
1601 V9fsState *s = pdu->s;
1602
1603 pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count);
1604
1605 fidp = get_fid(s, fid);
1606 if (fidp == NULL) {
1607 err = -EINVAL;
1608 goto out_nofid;
1609 }
1610 if (fidp->fid_type == P9_FID_DIR) {
1611
1612 if (off == 0) {
1613 v9fs_co_rewinddir(s, fidp);
1614 }
1615 count = v9fs_do_readdir_with_stat(s, pdu, fidp, max_count);
1616 if (count < 0) {
1617 err = count;
1618 goto out;
1619 }
1620 err = offset;
1621 err += pdu_marshal(pdu, offset, "d", count);
1622 err += count;
1623 } else if (fidp->fid_type == P9_FID_FILE) {
1624 int32_t cnt;
1625 int32_t len;
1626 struct iovec *sg;
1627 struct iovec iov[128]; /* FIXME: bad, bad, bad */
1628
1629 sg = iov;
1630 pdu_marshal(pdu, offset + 4, "v", sg, &cnt);
1631 sg = cap_sg(sg, max_count, &cnt);
1632 do {
1633 if (0) {
1634 print_sg(sg, cnt);
1635 }
1636 /* Loop in case of EINTR */
1637 do {
1638 len = v9fs_co_preadv(s, fidp, sg, cnt, off);
1639 if (len >= 0) {
1640 off += len;
1641 count += len;
1642 }
1643 } while (len == -EINTR);
1644 if (len < 0) {
1645 /* IO error return the error */
1646 err = len;
1647 goto out;
1648 }
1649 sg = adjust_sg(sg, len, &cnt);
1650 } while (count < max_count && len > 0);
1651 err = offset;
1652 err += pdu_marshal(pdu, offset, "d", count);
1653 err += count;
1654 } else if (fidp->fid_type == P9_FID_XATTR) {
1655 err = v9fs_xattr_read(s, pdu, fidp, off, max_count);
1656 } else {
1657 err = -EINVAL;
1658 }
1659 out:
1660 put_fid(s, fidp);
1661 out_nofid:
1662 complete_pdu(s, pdu, err);
1663 }
1664
1665 static size_t v9fs_readdir_data_size(V9fsString *name)
1666 {
1667 /*
1668 * Size of each dirent on the wire: size of qid (13) + size of offset (8)
1669 * size of type (1) + size of name.size (2) + strlen(name.data)
1670 */
1671 return 24 + v9fs_string_size(name);
1672 }
1673
1674 static int v9fs_do_readdir(V9fsState *s, V9fsPDU *pdu,
1675 V9fsFidState *fidp, int32_t max_count)
1676 {
1677 size_t size;
1678 V9fsQID qid;
1679 V9fsString name;
1680 int len, err = 0;
1681 int32_t count = 0;
1682 off_t saved_dir_pos;
1683 struct dirent *dent, *result;
1684
1685 /* save the directory position */
1686 saved_dir_pos = v9fs_co_telldir(s, fidp);
1687 if (saved_dir_pos < 0) {
1688 return saved_dir_pos;
1689 }
1690
1691 dent = g_malloc(sizeof(struct dirent));
1692
1693 while (1) {
1694 err = v9fs_co_readdir_r(s, fidp, dent, &result);
1695 if (err || !result) {
1696 break;
1697 }
1698 v9fs_string_init(&name);
1699 v9fs_string_sprintf(&name, "%s", dent->d_name);
1700 if ((count + v9fs_readdir_data_size(&name)) > max_count) {
1701 /* Ran out of buffer. Set dir back to old position and return */
1702 v9fs_co_seekdir(s, fidp, saved_dir_pos);
1703 v9fs_string_free(&name);
1704 g_free(dent);
1705 return count;
1706 }
1707 /*
1708 * Fill up just the path field of qid because the client uses
1709 * only that. To fill the entire qid structure we will have
1710 * to stat each dirent found, which is expensive
1711 */
1712 size = MIN(sizeof(dent->d_ino), sizeof(qid.path));
1713 memcpy(&qid.path, &dent->d_ino, size);
1714 /* Fill the other fields with dummy values */
1715 qid.type = 0;
1716 qid.version = 0;
1717
1718 /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */
1719 len = pdu_marshal(pdu, 11 + count, "Qqbs",
1720 &qid, dent->d_off,
1721 dent->d_type, &name);
1722 count += len;
1723 v9fs_string_free(&name);
1724 saved_dir_pos = dent->d_off;
1725 }
1726 g_free(dent);
1727 if (err < 0) {
1728 return err;
1729 }
1730 return count;
1731 }
1732
1733 static void v9fs_readdir(void *opaque)
1734 {
1735 int32_t fid;
1736 V9fsFidState *fidp;
1737 ssize_t retval = 0;
1738 size_t offset = 7;
1739 int64_t initial_offset;
1740 int32_t count, max_count;
1741 V9fsPDU *pdu = opaque;
1742 V9fsState *s = pdu->s;
1743
1744 pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count);
1745
1746 fidp = get_fid(s, fid);
1747 if (fidp == NULL) {
1748 retval = -EINVAL;
1749 goto out_nofid;
1750 }
1751 if (!fidp->fs.dir) {
1752 retval = -EINVAL;
1753 goto out;
1754 }
1755 if (initial_offset == 0) {
1756 v9fs_co_rewinddir(s, fidp);
1757 } else {
1758 v9fs_co_seekdir(s, fidp, initial_offset);
1759 }
1760 count = v9fs_do_readdir(s, pdu, fidp, max_count);
1761 if (count < 0) {
1762 retval = count;
1763 goto out;
1764 }
1765 retval = offset;
1766 retval += pdu_marshal(pdu, offset, "d", count);
1767 retval += count;
1768 out:
1769 put_fid(s, fidp);
1770 out_nofid:
1771 complete_pdu(s, pdu, retval);
1772 }
1773
1774 static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
1775 int64_t off, int32_t count,
1776 struct iovec *sg, int cnt)
1777 {
1778 int i, to_copy;
1779 ssize_t err = 0;
1780 int write_count;
1781 int64_t xattr_len;
1782 size_t offset = 7;
1783
1784
1785 xattr_len = fidp->fs.xattr.len;
1786 write_count = xattr_len - off;
1787 if (write_count > count) {
1788 write_count = count;
1789 } else if (write_count < 0) {
1790 /*
1791 * write beyond XATTR value len specified in
1792 * xattrcreate
1793 */
1794 err = -ENOSPC;
1795 goto out;
1796 }
1797 offset += pdu_marshal(pdu, offset, "d", write_count);
1798 err = offset;
1799 fidp->fs.xattr.copied_len += write_count;
1800 /*
1801 * Now copy the content from sg list
1802 */
1803 for (i = 0; i < cnt; i++) {
1804 if (write_count > sg[i].iov_len) {
1805 to_copy = sg[i].iov_len;
1806 } else {
1807 to_copy = write_count;
1808 }
1809 memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy);
1810 /* updating vs->off since we are not using below */
1811 off += to_copy;
1812 write_count -= to_copy;
1813 }
1814 out:
1815 return err;
1816 }
1817
1818 static void v9fs_write(void *opaque)
1819 {
1820 int cnt;
1821 ssize_t err;
1822 int32_t fid;
1823 int64_t off;
1824 int32_t count;
1825 int32_t len = 0;
1826 int32_t total = 0;
1827 size_t offset = 7;
1828 V9fsFidState *fidp;
1829 struct iovec iov[128]; /* FIXME: bad, bad, bad */
1830 struct iovec *sg = iov;
1831 V9fsPDU *pdu = opaque;
1832 V9fsState *s = pdu->s;
1833
1834 pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt);
1835
1836 fidp = get_fid(s, fid);
1837 if (fidp == NULL) {
1838 err = -EINVAL;
1839 goto out_nofid;
1840 }
1841 if (fidp->fid_type == P9_FID_FILE) {
1842 if (fidp->fs.fd == -1) {
1843 err = -EINVAL;
1844 goto out;
1845 }
1846 } else if (fidp->fid_type == P9_FID_XATTR) {
1847 /*
1848 * setxattr operation
1849 */
1850 err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt);
1851 goto out;
1852 } else {
1853 err = -EINVAL;
1854 goto out;
1855 }
1856 sg = cap_sg(sg, count, &cnt);
1857 do {
1858 if (0) {
1859 print_sg(sg, cnt);
1860 }
1861 /* Loop in case of EINTR */
1862 do {
1863 len = v9fs_co_pwritev(s, fidp, sg, cnt, off);
1864 if (len >= 0) {
1865 off += len;
1866 total += len;
1867 }
1868 } while (len == -EINTR);
1869 if (len < 0) {
1870 /* IO error return the error */
1871 err = len;
1872 goto out;
1873 }
1874 sg = adjust_sg(sg, len, &cnt);
1875 } while (total < count && len > 0);
1876 offset += pdu_marshal(pdu, offset, "d", total);
1877 err = offset;
1878 out:
1879 put_fid(s, fidp);
1880 out_nofid:
1881 complete_pdu(s, pdu, err);
1882 }
1883
1884 static void v9fs_create(void *opaque)
1885 {
1886 int32_t fid;
1887 int err = 0;
1888 size_t offset = 7;
1889 V9fsFidState *fidp;
1890 V9fsQID qid;
1891 int32_t perm;
1892 int8_t mode;
1893 struct stat stbuf;
1894 V9fsString name;
1895 V9fsString extension;
1896 V9fsString fullname;
1897 int iounit;
1898 V9fsPDU *pdu = opaque;
1899
1900 v9fs_string_init(&fullname);
1901
1902 pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name,
1903 &perm, &mode, &extension);
1904
1905 fidp = get_fid(pdu->s, fid);
1906 if (fidp == NULL) {
1907 err = -EINVAL;
1908 goto out_nofid;
1909 }
1910
1911 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
1912 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1913 if (!err) {
1914 err = -EEXIST;
1915 goto out;
1916 } else if (err != -ENOENT) {
1917 goto out;
1918 }
1919 if (perm & P9_STAT_MODE_DIR) {
1920 err = v9fs_co_mkdir(pdu->s, fullname.data, perm & 0777,
1921 fidp->uid, -1);
1922 if (err < 0) {
1923 goto out;
1924 }
1925 err = v9fs_co_opendir(pdu->s, fidp);
1926 if (err < 0) {
1927 goto out;
1928 }
1929 fidp->fid_type = P9_FID_DIR;
1930 } else if (perm & P9_STAT_MODE_SYMLINK) {
1931 err = v9fs_co_symlink(pdu->s, fidp, extension.data,
1932 fullname.data, -1);
1933 if (err < 0) {
1934 goto out;
1935 }
1936 } else if (perm & P9_STAT_MODE_LINK) {
1937 int32_t nfid = atoi(extension.data);
1938 V9fsFidState *nfidp = get_fid(pdu->s, nfid);
1939 if (nfidp == NULL) {
1940 err = -EINVAL;
1941 goto out;
1942 }
1943 err = v9fs_co_link(pdu->s, &nfidp->path, &fullname);
1944 if (err < 0) {
1945 put_fid(pdu->s, nfidp);
1946 goto out;
1947 }
1948 put_fid(pdu->s, nfidp);
1949 } else if (perm & P9_STAT_MODE_DEVICE) {
1950 char ctype;
1951 uint32_t major, minor;
1952 mode_t nmode = 0;
1953
1954 if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) {
1955 err = -errno;
1956 goto out;
1957 }
1958
1959 switch (ctype) {
1960 case 'c':
1961 nmode = S_IFCHR;
1962 break;
1963 case 'b':
1964 nmode = S_IFBLK;
1965 break;
1966 default:
1967 err = -EIO;
1968 goto out;
1969 }
1970
1971 nmode |= perm & 0777;
1972 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
1973 makedev(major, minor), nmode);
1974 if (err < 0) {
1975 goto out;
1976 }
1977 } else if (perm & P9_STAT_MODE_NAMED_PIPE) {
1978 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
1979 0, S_IFIFO | (perm & 0777));
1980 if (err < 0) {
1981 goto out;
1982 }
1983 } else if (perm & P9_STAT_MODE_SOCKET) {
1984 err = v9fs_co_mknod(pdu->s, &fullname, fidp->uid, -1,
1985 0, S_IFSOCK | (perm & 0777));
1986 if (err < 0) {
1987 goto out;
1988 }
1989 } else {
1990 err = v9fs_co_open2(pdu->s, fidp, fullname.data, -1,
1991 omode_to_uflags(mode)|O_CREAT, perm);
1992 if (err < 0) {
1993 goto out;
1994 }
1995 fidp->fid_type = P9_FID_FILE;
1996 }
1997 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
1998 if (err < 0) {
1999 fidp->fid_type = P9_FID_NONE;
2000 if (fidp->fs.fd) {
2001 close(fidp->fs.fd);
2002 }
2003 goto out;
2004 }
2005 iounit = get_iounit(pdu->s, &fidp->path);
2006 v9fs_string_copy(&fidp->path, &fullname);
2007 stat_to_qid(&stbuf, &qid);
2008 offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit);
2009 err = offset;
2010 out:
2011 put_fid(pdu->s, fidp);
2012 out_nofid:
2013 complete_pdu(pdu->s, pdu, err);
2014 v9fs_string_free(&name);
2015 v9fs_string_free(&extension);
2016 v9fs_string_free(&fullname);
2017 }
2018
2019 static void v9fs_symlink(void *opaque)
2020 {
2021 V9fsPDU *pdu = opaque;
2022 V9fsString name;
2023 V9fsString symname;
2024 V9fsString fullname;
2025 V9fsFidState *dfidp;
2026 V9fsQID qid;
2027 struct stat stbuf;
2028 int32_t dfid;
2029 int err = 0;
2030 gid_t gid;
2031 size_t offset = 7;
2032
2033 v9fs_string_init(&fullname);
2034 pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid);
2035
2036 dfidp = get_fid(pdu->s, dfid);
2037 if (dfidp == NULL) {
2038 err = -EINVAL;
2039 goto out_nofid;
2040 }
2041
2042 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2043 err = v9fs_co_symlink(pdu->s, dfidp, symname.data, fullname.data, gid);
2044 if (err < 0) {
2045 goto out;
2046 }
2047 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2048 if (err < 0) {
2049 goto out;
2050 }
2051 stat_to_qid(&stbuf, &qid);
2052 offset += pdu_marshal(pdu, offset, "Q", &qid);
2053 err = offset;
2054 out:
2055 put_fid(pdu->s, dfidp);
2056 out_nofid:
2057 complete_pdu(pdu->s, pdu, err);
2058 v9fs_string_free(&name);
2059 v9fs_string_free(&symname);
2060 v9fs_string_free(&fullname);
2061 }
2062
2063 static void v9fs_flush(void *opaque)
2064 {
2065 V9fsPDU *pdu = opaque;
2066 V9fsState *s = pdu->s;
2067 /* A nop call with no return */
2068 complete_pdu(s, pdu, 7);
2069 return;
2070 }
2071
2072 static void v9fs_link(void *opaque)
2073 {
2074 V9fsPDU *pdu = opaque;
2075 V9fsState *s = pdu->s;
2076 int32_t dfid, oldfid;
2077 V9fsFidState *dfidp, *oldfidp;
2078 V9fsString name, fullname;
2079 size_t offset = 7;
2080 int err = 0;
2081
2082 v9fs_string_init(&fullname);
2083
2084 pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
2085
2086 dfidp = get_fid(s, dfid);
2087 if (dfidp == NULL) {
2088 err = -ENOENT;
2089 goto out_nofid;
2090 }
2091
2092 oldfidp = get_fid(s, oldfid);
2093 if (oldfidp == NULL) {
2094 err = -ENOENT;
2095 goto out;
2096 }
2097
2098 v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
2099 err = v9fs_co_link(s, &oldfidp->path, &fullname);
2100 if (!err) {
2101 err = offset;
2102 }
2103 v9fs_string_free(&fullname);
2104
2105 out:
2106 put_fid(s, dfidp);
2107 out_nofid:
2108 v9fs_string_free(&name);
2109 complete_pdu(s, pdu, err);
2110 }
2111
2112 static void v9fs_remove(void *opaque)
2113 {
2114 int32_t fid;
2115 int err = 0;
2116 size_t offset = 7;
2117 V9fsFidState *fidp;
2118 V9fsPDU *pdu = opaque;
2119
2120 pdu_unmarshal(pdu, offset, "d", &fid);
2121
2122 fidp = get_fid(pdu->s, fid);
2123 if (fidp == NULL) {
2124 err = -EINVAL;
2125 goto out_nofid;
2126 }
2127 err = v9fs_co_remove(pdu->s, &fidp->path);
2128 if (!err) {
2129 err = offset;
2130 }
2131
2132 /* For TREMOVE we need to clunk the fid even on failed remove */
2133 clunk_fid(pdu->s, fidp->fid);
2134 put_fid(pdu->s, fidp);
2135 out_nofid:
2136 complete_pdu(pdu->s, pdu, err);
2137 }
2138
2139 static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp,
2140 int32_t newdirfid, V9fsString *name)
2141 {
2142 char *end;
2143 int err = 0;
2144 V9fsFidState *dirfidp = NULL;
2145 char *old_name, *new_name;
2146
2147 if (newdirfid != -1) {
2148 dirfidp = get_fid(s, newdirfid);
2149 if (dirfidp == NULL) {
2150 err = -ENOENT;
2151 goto out_nofid;
2152 }
2153 BUG_ON(dirfidp->fid_type != P9_FID_NONE);
2154
2155 new_name = g_malloc0(dirfidp->path.size + name->size + 2);
2156
2157 strcpy(new_name, dirfidp->path.data);
2158 strcat(new_name, "/");
2159 strcat(new_name + dirfidp->path.size, name->data);
2160 } else {
2161 old_name = fidp->path.data;
2162 end = strrchr(old_name, '/');
2163 if (end) {
2164 end++;
2165 } else {
2166 end = old_name;
2167 }
2168 new_name = g_malloc0(end - old_name + name->size + 1);
2169
2170 strncat(new_name, old_name, end - old_name);
2171 strncat(new_name + (end - old_name), name->data, name->size);
2172 }
2173
2174 v9fs_string_free(name);
2175 name->data = new_name;
2176 name->size = strlen(new_name);
2177
2178 if (strcmp(new_name, fidp->path.data) != 0) {
2179 err = v9fs_co_rename(s, &fidp->path, name);
2180 if (err < 0) {
2181 goto out;
2182 }
2183 V9fsFidState *tfidp;
2184 /*
2185 * Fixup fid's pointing to the old name to
2186 * start pointing to the new name
2187 */
2188 for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) {
2189 if (fidp == tfidp) {
2190 /*
2191 * we replace name of this fid towards the end
2192 * so that our below strcmp will work
2193 */
2194 continue;
2195 }
2196 if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) {
2197 /* replace the name */
2198 v9fs_fix_path(&tfidp->path, name, strlen(fidp->path.data));
2199 }
2200 }
2201 v9fs_string_copy(&fidp->path, name);
2202 }
2203 out:
2204 if (dirfidp) {
2205 put_fid(s, dirfidp);
2206 }
2207 out_nofid:
2208 return err;
2209 }
2210
2211 static void v9fs_rename(void *opaque)
2212 {
2213 int32_t fid;
2214 ssize_t err = 0;
2215 size_t offset = 7;
2216 V9fsString name;
2217 int32_t newdirfid;
2218 V9fsFidState *fidp;
2219 V9fsPDU *pdu = opaque;
2220 V9fsState *s = pdu->s;
2221
2222 pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name);
2223
2224 fidp = get_fid(s, fid);
2225 if (fidp == NULL) {
2226 err = -ENOENT;
2227 goto out_nofid;
2228 }
2229 BUG_ON(fidp->fid_type != P9_FID_NONE);
2230
2231 err = v9fs_complete_rename(s, fidp, newdirfid, &name);
2232 if (!err) {
2233 err = offset;
2234 }
2235 put_fid(s, fidp);
2236 out_nofid:
2237 complete_pdu(s, pdu, err);
2238 v9fs_string_free(&name);
2239 }
2240
2241 static void v9fs_wstat(void *opaque)
2242 {
2243 int32_t fid;
2244 int err = 0;
2245 int16_t unused;
2246 V9fsStat v9stat;
2247 size_t offset = 7;
2248 struct stat stbuf;
2249 V9fsFidState *fidp;
2250 V9fsPDU *pdu = opaque;
2251 V9fsState *s = pdu->s;
2252
2253 pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat);
2254
2255 fidp = get_fid(s, fid);
2256 if (fidp == NULL) {
2257 err = -EINVAL;
2258 goto out_nofid;
2259 }
2260 /* do we need to sync the file? */
2261 if (donttouch_stat(&v9stat)) {
2262 err = v9fs_co_fsync(s, fidp, 0);
2263 goto out;
2264 }
2265 if (v9stat.mode != -1) {
2266 uint32_t v9_mode;
2267 err = v9fs_co_lstat(s, &fidp->path, &stbuf);
2268 if (err < 0) {
2269 goto out;
2270 }
2271 v9_mode = stat_to_v9mode(&stbuf);
2272 if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2273 (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2274 /* Attempting to change the type */
2275 err = -EIO;
2276 goto out;
2277 }
2278 err = v9fs_co_chmod(s, &fidp->path,
2279 v9mode_to_mode(v9stat.mode,
2280 &v9stat.extension));
2281 if (err < 0) {
2282 goto out;
2283 }
2284 }
2285 if (v9stat.mtime != -1 || v9stat.atime != -1) {
2286 struct timespec times[2];
2287 if (v9stat.atime != -1) {
2288 times[0].tv_sec = v9stat.atime;
2289 times[0].tv_nsec = 0;
2290 } else {
2291 times[0].tv_nsec = UTIME_OMIT;
2292 }
2293 if (v9stat.mtime != -1) {
2294 times[1].tv_sec = v9stat.mtime;
2295 times[1].tv_nsec = 0;
2296 } else {
2297 times[1].tv_nsec = UTIME_OMIT;
2298 }
2299 err = v9fs_co_utimensat(s, &fidp->path, times);
2300 if (err < 0) {
2301 goto out;
2302 }
2303 }
2304 if (v9stat.n_gid != -1 || v9stat.n_uid != -1) {
2305 err = v9fs_co_chown(s, &fidp->path, v9stat.n_uid, v9stat.n_gid);
2306 if (err < 0) {
2307 goto out;
2308 }
2309 }
2310 if (v9stat.name.size != 0) {
2311 err = v9fs_complete_rename(s, fidp, -1, &v9stat.name);
2312 if (err < 0) {
2313 goto out;
2314 }
2315 }
2316 if (v9stat.length != -1) {
2317 err = v9fs_co_truncate(s, &fidp->path, v9stat.length);
2318 if (err < 0) {
2319 goto out;
2320 }
2321 }
2322 err = offset;
2323 out:
2324 put_fid(s, fidp);
2325 out_nofid:
2326 v9fs_stat_free(&v9stat);
2327 complete_pdu(s, pdu, err);
2328 }
2329
2330 static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf)
2331 {
2332 uint32_t f_type;
2333 uint32_t f_bsize;
2334 uint64_t f_blocks;
2335 uint64_t f_bfree;
2336 uint64_t f_bavail;
2337 uint64_t f_files;
2338 uint64_t f_ffree;
2339 uint64_t fsid_val;
2340 uint32_t f_namelen;
2341 size_t offset = 7;
2342 int32_t bsize_factor;
2343
2344 /*
2345 * compute bsize factor based on host file system block size
2346 * and client msize
2347 */
2348 bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize;
2349 if (!bsize_factor) {
2350 bsize_factor = 1;
2351 }
2352 f_type = stbuf->f_type;
2353 f_bsize = stbuf->f_bsize;
2354 f_bsize *= bsize_factor;
2355 /*
2356 * f_bsize is adjusted(multiplied) by bsize factor, so we need to
2357 * adjust(divide) the number of blocks, free blocks and available
2358 * blocks by bsize factor
2359 */
2360 f_blocks = stbuf->f_blocks/bsize_factor;
2361 f_bfree = stbuf->f_bfree/bsize_factor;
2362 f_bavail = stbuf->f_bavail/bsize_factor;
2363 f_files = stbuf->f_files;
2364 f_ffree = stbuf->f_ffree;
2365 fsid_val = (unsigned int) stbuf->f_fsid.__val[0] |
2366 (unsigned long long)stbuf->f_fsid.__val[1] << 32;
2367 f_namelen = stbuf->f_namelen;
2368
2369 return pdu_marshal(pdu, offset, "ddqqqqqqd",
2370 f_type, f_bsize, f_blocks, f_bfree,
2371 f_bavail, f_files, f_ffree,
2372 fsid_val, f_namelen);
2373 }
2374
2375 static void v9fs_statfs(void *opaque)
2376 {
2377 int32_t fid;
2378 ssize_t retval = 0;
2379 size_t offset = 7;
2380 V9fsFidState *fidp;
2381 struct statfs stbuf;
2382 V9fsPDU *pdu = opaque;
2383 V9fsState *s = pdu->s;
2384
2385 pdu_unmarshal(pdu, offset, "d", &fid);
2386 fidp = get_fid(s, fid);
2387 if (fidp == NULL) {
2388 retval = -ENOENT;
2389 goto out_nofid;
2390 }
2391 retval = v9fs_co_statfs(s, &fidp->path, &stbuf);
2392 if (retval < 0) {
2393 goto out;
2394 }
2395 retval = offset;
2396 retval += v9fs_fill_statfs(s, pdu, &stbuf);
2397 out:
2398 put_fid(s, fidp);
2399 out_nofid:
2400 complete_pdu(s, pdu, retval);
2401 return;
2402 }
2403
2404 static void v9fs_mknod(void *opaque)
2405 {
2406
2407 int mode;
2408 gid_t gid;
2409 int32_t fid;
2410 V9fsQID qid;
2411 int err = 0;
2412 int major, minor;
2413 size_t offset = 7;
2414 V9fsString name;
2415 struct stat stbuf;
2416 V9fsString fullname;
2417 V9fsFidState *fidp;
2418 V9fsPDU *pdu = opaque;
2419 V9fsState *s = pdu->s;
2420
2421 v9fs_string_init(&fullname);
2422 pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode,
2423 &major, &minor, &gid);
2424
2425 fidp = get_fid(s, fid);
2426 if (fidp == NULL) {
2427 err = -ENOENT;
2428 goto out_nofid;
2429 }
2430 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2431 err = v9fs_co_mknod(s, &fullname, fidp->uid, gid,
2432 makedev(major, minor), mode);
2433 if (err < 0) {
2434 goto out;
2435 }
2436 err = v9fs_co_lstat(s, &fullname, &stbuf);
2437 if (err < 0) {
2438 goto out;
2439 }
2440 stat_to_qid(&stbuf, &qid);
2441 err = offset;
2442 err += pdu_marshal(pdu, offset, "Q", &qid);
2443 out:
2444 put_fid(s, fidp);
2445 out_nofid:
2446 complete_pdu(s, pdu, err);
2447 v9fs_string_free(&fullname);
2448 v9fs_string_free(&name);
2449 }
2450
2451 /*
2452 * Implement posix byte range locking code
2453 * Server side handling of locking code is very simple, because 9p server in
2454 * QEMU can handle only one client. And most of the lock handling
2455 * (like conflict, merging) etc is done by the VFS layer itself, so no need to
2456 * do any thing in * qemu 9p server side lock code path.
2457 * So when a TLOCK request comes, always return success
2458 */
2459 static void v9fs_lock(void *opaque)
2460 {
2461 int8_t status;
2462 V9fsFlock *flock;
2463 size_t offset = 7;
2464 struct stat stbuf;
2465 V9fsFidState *fidp;
2466 int32_t fid, err = 0;
2467 V9fsPDU *pdu = opaque;
2468 V9fsState *s = pdu->s;
2469
2470 flock = g_malloc(sizeof(*flock));
2471 pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type,
2472 &flock->flags, &flock->start, &flock->length,
2473 &flock->proc_id, &flock->client_id);
2474 status = P9_LOCK_ERROR;
2475
2476 /* We support only block flag now (that too ignored currently) */
2477 if (flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
2478 err = -EINVAL;
2479 goto out_nofid;
2480 }
2481 fidp = get_fid(s, fid);
2482 if (fidp == NULL) {
2483 err = -ENOENT;
2484 goto out_nofid;
2485 }
2486 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2487 if (err < 0) {
2488 goto out;
2489 }
2490 status = P9_LOCK_SUCCESS;
2491 out:
2492 put_fid(s, fidp);
2493 out_nofid:
2494 err = offset;
2495 err += pdu_marshal(pdu, offset, "b", status);
2496 complete_pdu(s, pdu, err);
2497 g_free(flock);
2498 }
2499
2500 /*
2501 * When a TGETLOCK request comes, always return success because all lock
2502 * handling is done by client's VFS layer.
2503 */
2504 static void v9fs_getlock(void *opaque)
2505 {
2506 size_t offset = 7;
2507 struct stat stbuf;
2508 V9fsFidState *fidp;
2509 V9fsGetlock *glock;
2510 int32_t fid, err = 0;
2511 V9fsPDU *pdu = opaque;
2512 V9fsState *s = pdu->s;
2513
2514 glock = g_malloc(sizeof(*glock));
2515 pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock->type,
2516 &glock->start, &glock->length, &glock->proc_id,
2517 &glock->client_id);
2518
2519 fidp = get_fid(s, fid);
2520 if (fidp == NULL) {
2521 err = -ENOENT;
2522 goto out_nofid;
2523 }
2524 err = v9fs_co_fstat(s, fidp->fs.fd, &stbuf);
2525 if (err < 0) {
2526 goto out;
2527 }
2528 glock->type = F_UNLCK;
2529 offset += pdu_marshal(pdu, offset, "bqqds", glock->type,
2530 glock->start, glock->length, glock->proc_id,
2531 &glock->client_id);
2532 err = offset;
2533 out:
2534 put_fid(s, fidp);
2535 out_nofid:
2536 complete_pdu(s, pdu, err);
2537 g_free(glock);
2538 }
2539
2540 static void v9fs_mkdir(void *opaque)
2541 {
2542 V9fsPDU *pdu = opaque;
2543 size_t offset = 7;
2544 int32_t fid;
2545 struct stat stbuf;
2546 V9fsString name, fullname;
2547 V9fsQID qid;
2548 V9fsFidState *fidp;
2549 gid_t gid;
2550 int mode;
2551 int err = 0;
2552
2553 v9fs_string_init(&fullname);
2554 pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid);
2555
2556 fidp = get_fid(pdu->s, fid);
2557 if (fidp == NULL) {
2558 err = -ENOENT;
2559 goto out_nofid;
2560 }
2561 v9fs_string_sprintf(&fullname, "%s/%s", fidp->path.data, name.data);
2562 err = v9fs_co_mkdir(pdu->s, fullname.data, mode, fidp->uid, gid);
2563 if (err < 0) {
2564 goto out;
2565 }
2566 err = v9fs_co_lstat(pdu->s, &fullname, &stbuf);
2567 if (err < 0) {
2568 goto out;
2569 }
2570 stat_to_qid(&stbuf, &qid);
2571 offset += pdu_marshal(pdu, offset, "Q", &qid);
2572 err = offset;
2573 out:
2574 put_fid(pdu->s, fidp);
2575 out_nofid:
2576 complete_pdu(pdu->s, pdu, err);
2577 v9fs_string_free(&fullname);
2578 v9fs_string_free(&name);
2579 }
2580
2581 static void v9fs_xattrwalk(void *opaque)
2582 {
2583 int64_t size;
2584 V9fsString name;
2585 ssize_t err = 0;
2586 size_t offset = 7;
2587 int32_t fid, newfid;
2588 V9fsFidState *file_fidp;
2589 V9fsFidState *xattr_fidp = NULL;
2590 V9fsPDU *pdu = opaque;
2591 V9fsState *s = pdu->s;
2592
2593 pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name);
2594 file_fidp = get_fid(s, fid);
2595 if (file_fidp == NULL) {
2596 err = -ENOENT;
2597 goto out_nofid;
2598 }
2599 xattr_fidp = alloc_fid(s, newfid);
2600 if (xattr_fidp == NULL) {
2601 err = -EINVAL;
2602 goto out;
2603 }
2604 v9fs_string_copy(&xattr_fidp->path, &file_fidp->path);
2605 if (name.data[0] == 0) {
2606 /*
2607 * listxattr request. Get the size first
2608 */
2609 size = v9fs_co_llistxattr(s, &xattr_fidp->path, NULL, 0);
2610 if (size < 0) {
2611 err = size;
2612 clunk_fid(s, xattr_fidp->fid);
2613 goto out;
2614 }
2615 /*
2616 * Read the xattr value
2617 */
2618 xattr_fidp->fs.xattr.len = size;
2619 xattr_fidp->fid_type = P9_FID_XATTR;
2620 xattr_fidp->fs.xattr.copied_len = -1;
2621 if (size) {
2622 xattr_fidp->fs.xattr.value = g_malloc(size);
2623 err = v9fs_co_llistxattr(s, &xattr_fidp->path,
2624 xattr_fidp->fs.xattr.value,
2625 xattr_fidp->fs.xattr.len);
2626 if (err < 0) {
2627 clunk_fid(s, xattr_fidp->fid);
2628 goto out;
2629 }
2630 }
2631 offset += pdu_marshal(pdu, offset, "q", size);
2632 err = offset;
2633 } else {
2634 /*
2635 * specific xattr fid. We check for xattr
2636 * presence also collect the xattr size
2637 */
2638 size = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2639 &name, NULL, 0);
2640 if (size < 0) {
2641 err = size;
2642 clunk_fid(s, xattr_fidp->fid);
2643 goto out;
2644 }
2645 /*
2646 * Read the xattr value
2647 */
2648 xattr_fidp->fs.xattr.len = size;
2649 xattr_fidp->fid_type = P9_FID_XATTR;
2650 xattr_fidp->fs.xattr.copied_len = -1;
2651 if (size) {
2652 xattr_fidp->fs.xattr.value = g_malloc(size);
2653 err = v9fs_co_lgetxattr(s, &xattr_fidp->path,
2654 &name, xattr_fidp->fs.xattr.value,
2655 xattr_fidp->fs.xattr.len);
2656 if (err < 0) {
2657 clunk_fid(s, xattr_fidp->fid);
2658 goto out;
2659 }
2660 }
2661 offset += pdu_marshal(pdu, offset, "q", size);
2662 err = offset;
2663 }
2664 out:
2665 put_fid(s, file_fidp);
2666 if (xattr_fidp) {
2667 put_fid(s, xattr_fidp);
2668 }
2669 out_nofid:
2670 complete_pdu(s, pdu, err);
2671 v9fs_string_free(&name);
2672 }
2673
2674 static void v9fs_xattrcreate(void *opaque)
2675 {
2676 int flags;
2677 int32_t fid;
2678 int64_t size;
2679 ssize_t err = 0;
2680 V9fsString name;
2681 size_t offset = 7;
2682 V9fsFidState *file_fidp;
2683 V9fsFidState *xattr_fidp;
2684 V9fsPDU *pdu = opaque;
2685 V9fsState *s = pdu->s;
2686
2687 pdu_unmarshal(pdu, offset, "dsqd",
2688 &fid, &name, &size, &flags);
2689
2690 file_fidp = get_fid(s, fid);
2691 if (file_fidp == NULL) {
2692 err = -EINVAL;
2693 goto out_nofid;
2694 }
2695 /* Make the file fid point to xattr */
2696 xattr_fidp = file_fidp;
2697 xattr_fidp->fid_type = P9_FID_XATTR;
2698 xattr_fidp->fs.xattr.copied_len = 0;
2699 xattr_fidp->fs.xattr.len = size;
2700 xattr_fidp->fs.xattr.flags = flags;
2701 v9fs_string_init(&xattr_fidp->fs.xattr.name);
2702 v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name);
2703 if (size) {
2704 xattr_fidp->fs.xattr.value = g_malloc(size);
2705 } else {
2706 xattr_fidp->fs.xattr.value = NULL;
2707 }
2708 err = offset;
2709 put_fid(s, file_fidp);
2710 out_nofid:
2711 complete_pdu(s, pdu, err);
2712 v9fs_string_free(&name);
2713 }
2714
2715 static void v9fs_readlink(void *opaque)
2716 {
2717 V9fsPDU *pdu = opaque;
2718 size_t offset = 7;
2719 V9fsString target;
2720 int32_t fid;
2721 int err = 0;
2722 V9fsFidState *fidp;
2723
2724 pdu_unmarshal(pdu, offset, "d", &fid);
2725 fidp = get_fid(pdu->s, fid);
2726 if (fidp == NULL) {
2727 err = -ENOENT;
2728 goto out_nofid;
2729 }
2730
2731 v9fs_string_init(&target);
2732 err = v9fs_co_readlink(pdu->s, &fidp->path, &target);
2733 if (err < 0) {
2734 goto out;
2735 }
2736 offset += pdu_marshal(pdu, offset, "s", &target);
2737 err = offset;
2738 v9fs_string_free(&target);
2739 out:
2740 put_fid(pdu->s, fidp);
2741 out_nofid:
2742 complete_pdu(pdu->s, pdu, err);
2743 }
2744
2745 static CoroutineEntry *pdu_co_handlers[] = {
2746 [P9_TREADDIR] = v9fs_readdir,
2747 [P9_TSTATFS] = v9fs_statfs,
2748 [P9_TGETATTR] = v9fs_getattr,
2749 [P9_TSETATTR] = v9fs_setattr,
2750 [P9_TXATTRWALK] = v9fs_xattrwalk,
2751 [P9_TXATTRCREATE] = v9fs_xattrcreate,
2752 [P9_TMKNOD] = v9fs_mknod,
2753 [P9_TRENAME] = v9fs_rename,
2754 [P9_TLOCK] = v9fs_lock,
2755 [P9_TGETLOCK] = v9fs_getlock,
2756 [P9_TREADLINK] = v9fs_readlink,
2757 [P9_TMKDIR] = v9fs_mkdir,
2758 [P9_TVERSION] = v9fs_version,
2759 [P9_TLOPEN] = v9fs_open,
2760 [P9_TATTACH] = v9fs_attach,
2761 [P9_TSTAT] = v9fs_stat,
2762 [P9_TWALK] = v9fs_walk,
2763 [P9_TCLUNK] = v9fs_clunk,
2764 [P9_TFSYNC] = v9fs_fsync,
2765 [P9_TOPEN] = v9fs_open,
2766 [P9_TREAD] = v9fs_read,
2767 #if 0
2768 [P9_TAUTH] = v9fs_auth,
2769 #endif
2770 [P9_TFLUSH] = v9fs_flush,
2771 [P9_TLINK] = v9fs_link,
2772 [P9_TSYMLINK] = v9fs_symlink,
2773 [P9_TCREATE] = v9fs_create,
2774 [P9_TLCREATE] = v9fs_lcreate,
2775 [P9_TWRITE] = v9fs_write,
2776 [P9_TWSTAT] = v9fs_wstat,
2777 [P9_TREMOVE] = v9fs_remove,
2778 };
2779
2780 static void v9fs_op_not_supp(void *opaque)
2781 {
2782 V9fsPDU *pdu = opaque;
2783 complete_pdu(pdu->s, pdu, -EOPNOTSUPP);
2784 }
2785
2786 static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
2787 {
2788 Coroutine *co;
2789 CoroutineEntry *handler;
2790
2791 if (debug_9p_pdu) {
2792 pprint_pdu(pdu);
2793 }
2794 if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) ||
2795 (pdu_co_handlers[pdu->id] == NULL)) {
2796 handler = v9fs_op_not_supp;
2797 } else {
2798 handler = pdu_co_handlers[pdu->id];
2799 }
2800 co = qemu_coroutine_create(handler);
2801 qemu_coroutine_enter(co, pdu);
2802 }
2803
2804 void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
2805 {
2806 V9fsState *s = (V9fsState *)vdev;
2807 V9fsPDU *pdu;
2808 ssize_t len;
2809
2810 while ((pdu = alloc_pdu(s)) &&
2811 (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
2812 uint8_t *ptr;
2813 pdu->s = s;
2814 BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
2815 BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
2816
2817 ptr = pdu->elem.out_sg[0].iov_base;
2818
2819 memcpy(&pdu->size, ptr, 4);
2820 pdu->id = ptr[4];
2821 memcpy(&pdu->tag, ptr + 5, 2);
2822 submit_pdu(s, pdu);
2823 }
2824 free_pdu(s, pdu);
2825 }