ops.c revision 1.1 1 /* $NetBSD: ops.c,v 1.1 2010/08/25 07:16:00 manu Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Emmanuel Dreyfus. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <libgen.h>
32 #include <errno.h>
33 #include <err.h>
34 #include <sysexits.h>
35 #include <syslog.h>
36 #include <puffs.h>
37 #include <sys/vnode.h>
38 #include <sys/socket.h>
39 #include <machine/vmparam.h>
40
41 #include "perfuse_priv.h"
42 #include "fuse.h"
43
44 static void fuse_attr_to_vap(struct perfuse_state *,
45 struct vattr *, struct fuse_attr *);
46 static int node_lookup_dir_nodot(struct puffs_usermount *,
47 puffs_cookie_t, char *, size_t, struct puffs_node **);
48 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
49 const char*, struct puffs_node **);
50 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
51 struct puffs_newinfo *, perfuse_msg_t *);
52 static const char *basename_r(const char *);
53 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
54 struct fuse_dirent *, size_t);
55 static int readdir_buffered(struct perfuse_state *, puffs_cookie_t,
56 struct dirent *, off_t *, size_t *, const struct puffs_cred *,
57 int *, off_t *, size_t *);
58 static void requeue_request(struct puffs_usermount *,
59 puffs_cookie_t opc, enum perfuse_qtype);
60 static void dequeue_requests(struct perfuse_state *,
61 puffs_cookie_t opc, enum perfuse_qtype, int);
62 #define DEQUEUE_ALL 0
63
64 /*
65 * From <sys/vnode>, inside #ifdef _KERNEL section
66 */
67 #define IO_SYNC (0x40|IO_DSYNC)
68 #define IO_DSYNC 0x00200
69 #define IO_DIRECT 0x02000
70
71 /*
72 * From <fcntl>, inside #ifdef _KERNEL section
73 */
74 #define F_WAIT 0x010
75 #define F_FLOCK 0x020
76
77 /*
78 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
79 */
80 const enum vtype iftovt_tab[16] = {
81 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
82 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
83 };
84 const int vttoif_tab[9] = {
85 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
86 S_IFSOCK, S_IFIFO, S_IFMT,
87 };
88
89 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
90 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
91
92
93 static void
94 fuse_attr_to_vap(ps, vap, fa)
95 struct perfuse_state *ps;
96 struct vattr *vap;
97 struct fuse_attr *fa;
98 {
99 vap->va_type = IFTOVT(fa->mode);
100 vap->va_mode = fa->mode;
101 vap->va_nlink = fa->nlink;
102 vap->va_uid = fa->uid;
103 vap->va_gid = fa->gid;
104 vap->va_fsid = ps->ps_fsid;
105 vap->va_fileid = fa->ino;
106 vap->va_size = fa->size;
107 vap->va_blocksize = fa->blksize;
108 vap->va_atime.tv_sec = (long)fa->atime;
109 vap->va_atime.tv_nsec = fa->atimensec;
110 vap->va_mtime.tv_sec = (long)fa->mtime;
111 vap->va_mtime.tv_nsec = fa->mtimensec;
112 vap->va_ctime.tv_sec = (long)fa->ctime;
113 vap->va_ctime.tv_nsec = fa->ctimensec;
114 vap->va_birthtime.tv_sec = 0;
115 vap->va_birthtime.tv_nsec = 0;
116 vap->va_gen = 0;
117 vap->va_flags = 0;
118 vap->va_rdev = fa->rdev;
119 vap->va_bytes = fa->size;
120 vap->va_filerev = 0;
121 vap->va_vaflags = 0;
122
123 if (vap->va_blocksize == 0)
124 vap->va_blocksize = DEV_BSIZE;
125
126 if (vap->va_size == (size_t)-1) /* XXX */
127 vap->va_size = 0;
128
129 return;
130 }
131
132
133 /*
134 * Lookup name in directory opc
135 * We take special care of name being . or ..
136 * These are returned by readdir and deserve tweaks.
137 */
138 static int
139 node_lookup_dir_nodot(pu, opc, name, namelen, pnp)
140 struct puffs_usermount *pu;
141 puffs_cookie_t opc;
142 char *name;
143 size_t namelen;
144 struct puffs_node **pnp;
145 {
146 char *path;
147 struct puffs_node *dpn = (struct puffs_node *)opc;
148 int error;
149
150 /*
151 * is easy as we already know it
152 */
153 if (strncmp(name, ".", namelen) == 0) {
154 *pnp = (struct puffs_node *)opc;
155 return 0;
156 }
157
158 /*
159 * For .. we just forget the name part
160 */
161 if (strncmp(name, "..", namelen) == 0)
162 namelen = 0;
163
164 namelen = PNPLEN(dpn) + 1 + namelen + 1;
165 if ((path = malloc(namelen)) == NULL)
166 DERR(EX_OSERR, "malloc failed");
167 (void)snprintf(path, namelen, "%s/%s", (char *)PNPATH(dpn), name);
168
169 error = node_lookup_common(pu, opc, path, pnp);
170
171 free(path);
172
173 return error;
174 }
175
176 static int
177 node_lookup_common(pu, opc, path, pnp)
178 struct puffs_usermount *pu;
179 puffs_cookie_t opc;
180 const char *path;
181 struct puffs_node **pnp;
182 {
183 struct perfuse_state *ps;
184 perfuse_msg_t *pm;
185 struct fuse_entry_out *feo;
186 struct puffs_node *pn;
187 size_t len;
188 int error;
189
190 ps = puffs_getspecific(pu);
191
192 path = basename_r(path);
193 len = strlen(path) + 1;
194
195 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, NULL);
196 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len);
197
198 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0)
199 goto out;
200
201 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
202
203 pn = perfuse_new_pn(pu, opc);
204 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
205
206 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
207
208 if (pnp != NULL)
209 *pnp = pn;
210
211 out:
212 ps->ps_destroy_msg(pm);
213
214 return error;
215 }
216
217
218 /*
219 * Common final code for methods that create objects:
220 * perfuse_node_mkdir
221 * perfuse_node_mknod
222 * perfuse_node_symlink
223 */
224 static int
225 node_mk_common(pu, opc, pni, pm)
226 struct puffs_usermount *pu;
227 puffs_cookie_t opc;
228 struct puffs_newinfo *pni;
229 perfuse_msg_t *pm;
230 {
231 struct perfuse_state *ps;
232 struct puffs_node *pn;
233 struct fuse_entry_out *feo;
234 int error;
235
236 ps = puffs_getspecific(pu);
237
238 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*feo))) != 0)
239 goto out;
240
241 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
242 if (feo->nodeid == PERFUSE_UNKNOWN_INO)
243 DERRX(EX_SOFTWARE, "%s: no ino", __func__);
244
245 pn = perfuse_new_pn(pu, opc);
246 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
247
248 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
249 puffs_newinfo_setcookie(pni, pn);
250
251 out:
252 ps->ps_destroy_msg(pm);
253
254 return error;
255 }
256
257 static const char *
258 basename_r(string)
259 const char *string;
260 {
261 char *result;
262
263 if ((result = rindex(string, '/')) == NULL)
264 return string;
265
266 /*
267 * We are finished if this is not a trailing /
268 */
269 if (result[1] != '\0')
270 return result + 1;
271
272
273 /*
274 * Go back until we found something else than a /
275 */
276 while (result != string) {
277 result--;
278 if (result[0] != '/')
279 break;
280 }
281
282 if (result == string)
283 return string;
284
285 if ((result = rindex(string, '/')) == NULL)
286 return string;
287
288 return result + 1;
289
290 }
291
292 static ssize_t
293 fuse_to_dirent(pu, opc, fd, fd_len)
294 struct puffs_usermount *pu;
295 puffs_cookie_t opc;
296 struct fuse_dirent *fd;
297 size_t fd_len;
298 {
299 struct dirent *dents;
300 size_t dents_len;
301 ssize_t written;
302 uint64_t fd_offset;
303 struct fuse_dirent *fd_base;
304 size_t len;
305
306 fd_base = fd;
307 fd_offset = 0;
308 written = 0;
309 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
310 dents_len = PERFUSE_NODE_DATA(opc)->pnd_dirent_len;
311
312 do {
313 char *ndp;
314 size_t reclen;
315
316 reclen = _DIRENT_RECLEN(dents, fd->namelen);
317
318 /*
319 * Check we do not overflow the output buffer
320 * struct fuse_dirent is bigger than struct dirent,
321 * so we should always use fd_len and never reallocate
322 * later.
323 * If we have to reallocate,try to double the buffer
324 * each time so that we do not have to do it too often.
325 */
326 if (written + reclen > dents_len) {
327 if (dents_len == 0)
328 dents_len = fd_len;
329 else
330 dents_len =
331 MAX(2 * dents_len, written + reclen);
332
333 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
334 if ((dents = realloc(dents, dents_len)) == NULL)
335 DERR(EX_OSERR, "malloc failed");
336
337 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents;
338 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len;
339
340 /*
341 * (void *) for delint
342 */
343 ndp = (char *)(void *)dents + written;
344 dents = (struct dirent *)(void *)ndp;
345 }
346
347
348
349 /*
350 * Filesystem was mounted without -o use_ino
351 * Perform a lookup to find it.
352 * XXX still broken
353 */
354 if (fd->ino == PERFUSE_UNKNOWN_INO) {
355 struct puffs_node *pn;
356
357 if (node_lookup_dir_nodot(pu, opc, fd->name,
358 fd->namelen, &pn) != 0)
359 DERRX(EX_SOFTWARE,
360 "node_lookup_dir_nodot failed");
361
362 fd->ino = PERFUSE_NODE_DATA(pn)->pnd_ino;
363 }
364
365 dents->d_fileno = fd->ino;
366 dents->d_reclen = reclen;
367 dents->d_namlen = fd->namelen;
368 dents->d_type = fd->type;
369 strlcpy(dents->d_name, fd->name, fd->namelen + 1);
370
371 #ifdef PERFUSE_DEBUG
372 if (perfuse_diagflags & PDF_READDIR)
373 DPRINTF("%s: translated \"%s\" ino = %lld\n",
374 __func__, dents->d_name, dents->d_fileno);
375 #endif
376
377 dents = _DIRENT_NEXT(dents);
378 written += reclen;
379
380 /*
381 * Move to the next record.
382 * fd->off seems unreliable, for instance, flusterfs
383 * does not clear the unused bits, and we get
384 * 0xffffffffb9b95040 instead of just 0x40. Use
385 * record alignement instead.
386 */
387 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
388 #ifdef PERFUSE_DEBUG
389 if (perfuse_diagflags & PDF_READDIR)
390 DPRINTF("%s: record at %lld/0x%llx length = %d/0x%x. "
391 "next record at %lld/0x%llx, max %d/0x%x\n",
392 __func__, fd_offset, fd_offset, len, len,
393 fd_offset + len, fd_offset + len,
394 fd_len, fd_len);
395 #endif
396 fd_offset += len;
397
398 /*
399 * Check if next record is still within the packet
400 * If it is not, we reached the end of the buffer.
401 */
402 if (fd_offset >= fd_len)
403 break;
404
405 /*
406 * (void *) for delint
407 */
408 ndp = (char *)(void *)fd_base + (size_t)fd_offset;
409 fd = (struct fuse_dirent *)(void *)ndp;
410
411 } while (1 /* CONSTCOND */);
412
413 /*
414 * Adjust the dirent output length
415 */
416 if (written != -1)
417 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written;
418
419 return written;
420 }
421
422 /* ARGSUSED0 */
423 static int
424 readdir_buffered(ps, opc, dent, readoff,
425 reslen, pcr, eofflag, cookies, ncookies)
426 struct perfuse_state *ps;
427 puffs_cookie_t opc;
428 struct dirent *dent;
429 off_t *readoff;
430 size_t *reslen;
431 const struct puffs_cred *pcr;
432 int *eofflag;
433 off_t *cookies;
434 size_t *ncookies;
435 {
436 struct dirent *fromdent;
437 struct perfuse_node_data *pnd;
438 char *ndp;
439
440 pnd = PERFUSE_NODE_DATA(opc);
441
442 while (*readoff < pnd->pnd_dirent_len) {
443 /*
444 * (void *) for delint
445 */
446 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff;
447 fromdent = (struct dirent *)(void *)ndp;
448
449 if (*reslen < _DIRENT_SIZE(fromdent))
450 break;
451
452 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
453 *readoff += _DIRENT_SIZE(fromdent);
454 *reslen -= _DIRENT_SIZE(fromdent);
455
456 dent = _DIRENT_NEXT(dent);
457 }
458
459 #ifdef PERFUSE_DEBUG
460 if (perfuse_diagflags & PDF_READDIR)
461 DPRINTF("%s: readoff = %lld, pnd->pnd_dirent_len = %d\n",
462 __func__, *readoff, pnd->pnd_dirent_len);
463 #endif
464 if (*readoff >= pnd->pnd_dirent_len) {
465 free(pnd->pnd_dirent);
466 pnd->pnd_dirent = NULL;
467 pnd->pnd_dirent_len = 0;
468 *eofflag = 1;
469 }
470
471 return 0;
472 }
473
474 /* ARGSUSED0 */
475 static void
476 requeue_request(pu, opc, type)
477 struct puffs_usermount *pu;
478 puffs_cookie_t opc;
479 enum perfuse_qtype type;
480 {
481 struct perfuse_cc_queue pcq;
482 struct perfuse_node_data *pnd;
483 #ifdef PERFUSE_DEBUG
484 struct perfuse_state *ps;
485
486 ps = perfuse_getspecific(pu);
487 #endif
488
489 /*
490 * XXX Add a lock he day we go multithreaded
491 */
492 pnd = PERFUSE_NODE_DATA(opc);
493 pcq.pcq_type = type;
494 pcq.pcq_cc = puffs_cc_getcc(pu);
495 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next);
496
497 #ifdef PERFUSE_DEBUG
498
499 if (perfuse_diagflags & PDF_REQUEUE)
500 DPRINTF("%s: REQUEUE opc = %p, pcc = %p\n",
501 __func__, (void *)opc, pcq.pcq_cc);
502 #endif
503
504 puffs_cc_yield(pcq.pcq_cc);
505
506 #ifdef PERFUSE_DEBUG
507 if (perfuse_diagflags & PDF_REQUEUE)
508 DPRINTF("%s: RESUME opc = %p, pcc = %p\n",
509 __func__, (void *)opc, pcq.pcq_cc);
510 #endif
511
512 return;
513 }
514
515 /* ARGSUSED0 */
516 static void
517 dequeue_requests(ps, opc, type, max)
518 struct perfuse_state *ps;
519 puffs_cookie_t opc;
520 enum perfuse_qtype type;
521 int max;
522 {
523 struct perfuse_cc_queue *pcq;
524 struct perfuse_node_data *pnd;
525 int dequeued;
526
527 /*
528 * XXX Add a lock he day we go multithreaded
529 */
530 pnd = PERFUSE_NODE_DATA(opc);
531 dequeued = 0;
532 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) {
533 if (pcq->pcq_type != type)
534 continue;
535
536 puffs_cc_schedule(pcq->pcq_cc);
537 TAILQ_REMOVE(&pnd->pnd_pcq, pcq, pcq_next);
538
539 #ifdef PERFUSE_DEBUG
540 if (perfuse_diagflags & PDF_REQUEUE)
541 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p\n",
542 __func__, (void *)opc, pcq->pcq_cc);
543 #endif
544
545 if (++dequeued == max)
546 break;
547 }
548
549 #ifdef PERFUSE_DEBUG
550 if (perfuse_diagflags & PDF_REQUEUE)
551 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc);
552 #endif
553
554 return;
555 }
556
557 void
558 perfuse_fs_init(pu)
559 struct puffs_usermount *pu;
560 {
561 struct perfuse_state *ps;
562 perfuse_msg_t *pm;
563 struct fuse_init_in *fii;
564 struct fuse_init_out *fio;
565 int error;
566
567 ps = puffs_getspecific(pu);
568
569 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0)
570 DERR(EX_OSERR, "puffs_mount failed");
571
572 /*
573 * Linux 2.6.34.1 sends theses flags:
574 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC
575 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK
576 *
577 * Linux also sets max_readahead at 32 pages (128 kB)
578 */
579 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL);
580 fii = GET_INPAYLOAD(ps, pm, fuse_init_in);
581 fii->major = FUSE_KERNEL_VERSION;
582 fii->minor = FUSE_KERNEL_MINOR_VERSION;
583 fii->max_readahead = 32 * PAGE_SIZE;
584 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC);
585
586 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fio))) != 0)
587 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error);
588
589 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out);
590 ps->ps_max_readahead = fio->max_readahead;
591 ps->ps_max_write = fio->max_write;
592
593 ps->ps_destroy_msg(pm);
594
595 return;
596 }
597
598 int
599 perfuse_fs_unmount(pu, flags)
600 struct puffs_usermount *pu;
601 int flags;
602 {
603 perfuse_msg_t *pm;
604 struct perfuse_state *ps;
605 puffs_cookie_t opc;
606 int error;
607
608 ps = puffs_getspecific(pu);
609
610 opc = (puffs_cookie_t)puffs_getroot(pu);
611 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL);
612
613 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0) {
614 DWARN("unmount %s", ps->ps_target);
615 if (!(flags & MNT_FORCE))
616 goto out;
617 }
618
619 DPRINTF("%s unmounted, exit\n", ps->ps_target);
620
621 exit(0);
622 out:
623 ps->ps_destroy_msg(pm);
624
625 return error;
626 }
627
628 int
629 perfuse_fs_statvfs(pu, svfsb)
630 struct puffs_usermount *pu;
631 struct statvfs *svfsb;
632 {
633 struct perfuse_state *ps;
634 perfuse_msg_t *pm;
635 puffs_cookie_t opc;
636 struct fuse_statfs_out *fso;
637 int error;
638
639 ps = puffs_getspecific(pu);
640 opc = (puffs_cookie_t)puffs_getroot(pu);
641 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
642
643 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fso))) != 0)
644 goto out;
645
646 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
647 svfsb->f_flag = ps->ps_mountflags;
648 svfsb->f_bsize = fso->st.bsize;
649 svfsb->f_frsize = fso->st.frsize;
650 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize;
651 svfsb->f_blocks = fso->st.blocks;
652 svfsb->f_bfree = fso->st.bfree;
653 svfsb->f_bavail = fso->st.bavail;
654 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail;
655 svfsb->f_files = fso->st.files;
656 svfsb->f_ffree = fso->st.ffree;
657 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */
658 svfsb->f_fresvd = 0; /* files reserved for root */
659
660 svfsb->f_syncreads = ps->ps_syncreads;
661 svfsb->f_syncwrites = ps->ps_syncwrites;
662
663 svfsb->f_asyncreads = ps->ps_asyncreads;
664 svfsb->f_asyncwrites = ps->ps_asyncwrites;
665
666 svfsb->f_fsidx.__fsid_val[0] = ps->ps_fsid;
667 svfsb->f_fsidx.__fsid_val[1] = 0;
668 svfsb->f_fsid = ps->ps_fsid;
669 svfsb->f_namemax = MAXPATHLEN; /* XXX */
670 svfsb->f_owner = ps->ps_uid;
671
672 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN);
673
674 if (ps->ps_filesystemtype != NULL)
675 (void)strlcpy(svfsb->f_fstypename,
676 ps->ps_filesystemtype, _VFS_NAMELEN);
677 else
678 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN);
679
680 if (ps->ps_source != NULL)
681 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN);
682 else
683 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN);
684 out:
685 ps->ps_destroy_msg(pm);
686
687 return error;
688 }
689
690 int
691 perfuse_fs_sync(pu, waitfor, pcr)
692 struct puffs_usermount *pu;
693 int waitfor;
694 const struct puffs_cred *pcr;
695 {
696 /*
697 * FUSE does not seem to have a FS sync callback.
698 * Maybe do not even register this callback
699 */
700 return puffs_fsnop_sync(pu, waitfor, pcr);
701 }
702
703 /* ARGSUSED0 */
704 int
705 perfuse_fs_fhtonode(pu, fid, fidsize, pni)
706 struct puffs_usermount *pu;
707 void *fid;
708 size_t fidsize;
709 struct puffs_newinfo *pni;
710 {
711 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
712 return 0;
713 }
714
715 /* ARGSUSED0 */
716 int
717 perfuse_fs_nodetofh(pu, cookie, fid, fidsize)
718 struct puffs_usermount *pu;
719 puffs_cookie_t cookie;
720 void *fid;
721 size_t *fidsize;
722 {
723 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
724 return 0;
725 }
726
727 #if 0
728 /* ARGSUSED0 */
729 void
730 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname)
731 struct puffs_usermount *pu;
732 int cmd,
733 puffs_cookie_t *cookie;
734 int flags;
735 int namespace;
736 const char *attrname;
737 {
738 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
739 return 0;
740 }
741 #endif /* 0 */
742
743 /* ARGSUSED0 */
744 void
745 perfuse_fs_suspend(pu, status)
746 struct puffs_usermount *pu;
747 int status;
748 {
749 return;
750 }
751
752
753
754 int
755 perfuse_node_lookup(pu, opc, pni, pcn)
756 struct puffs_usermount *pu;
757 puffs_cookie_t opc;
758 struct puffs_newinfo *pni;
759 const struct puffs_cn *pcn;
760 {
761 struct puffs_node *pn;
762 int error;
763
764 /*
765 * XXX This is borrowed from librefuse,
766 * and __UNCONST is said to be fixed.
767 */
768 pn = puffs_pn_nodewalk(pu, puffs_path_walkcmp,
769 __UNCONST(&pcn->pcn_po_full));
770
771 if (pn == NULL) {
772 error = node_lookup_common(pu, opc, (char *)PCNPATH(pcn), &pn);
773 if (error != 0)
774 return error;
775 }
776
777 /*
778 * If that node had a pending reclaim, wipe it out.
779 */
780 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
781
782 puffs_newinfo_setcookie(pni, pn);
783 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
784 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size);
785 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev);
786
787 return 0;
788 }
789
790 int
791 perfuse_node_create(pu, opc, pni, pcn, vap)
792 struct puffs_usermount *pu;
793 puffs_cookie_t opc;
794 struct puffs_newinfo *pni;
795 const struct puffs_cn *pcn;
796 const struct vattr *vap;
797 {
798 perfuse_msg_t *pm;
799 struct perfuse_state *ps;
800 struct fuse_create_in *fci;
801 struct fuse_entry_out *feo;
802 struct fuse_open_out *foo;
803 struct puffs_node *pn;
804 const char *name;
805 size_t namelen;
806 size_t len;
807 int error;
808
809 /*
810 * If create is unimplemented: Check that it does not
811 * already exists, and if not, do mknod and open
812 */
813 ps = puffs_getspecific(pu);
814 if (ps->ps_flags & PS_NO_CREAT) {
815 error = node_lookup_common(pu, opc, (char*)PCNPATH(pcn), &pn);
816 if (error == 0)
817 return EEXIST;
818
819 error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
820 if (error != 0)
821 return error;
822
823 error = perfuse_node_open(pu, opc, FREAD|FWRITE, pcn->pcn_cred);
824 if (error != 0)
825 return error;
826
827
828 return 0;
829 }
830
831 name = basename_r((char *)PCNPATH(pcn));
832 namelen = strlen(name) + 1;
833 len = sizeof(*fci) + namelen;
834
835 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred);
836 fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
837 fci->flags = 0; /* No flags seems available */
838 fci->mode = vap->va_mode;
839 fci->umask = 0; /* Seems unused bu libfuse */
840 (void)strlcpy((char*)(void *)(fci + 1), name, namelen);
841
842 len = sizeof(*feo) + sizeof(*foo);
843 if ((error = XCHG_MSG(ps, pu, pm, len)) != 0)
844 goto out;
845
846 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
847 foo = (struct fuse_open_out *)(void *)(feo + 1);
848 if (feo->nodeid == PERFUSE_UNKNOWN_INO)
849 DERRX(EX_SOFTWARE, "%s: no ino", __func__);
850
851 /*
852 * Save the file handle and inode in node private data
853 * so that we can reuse it later
854 */
855 pn = perfuse_new_pn(pu, opc);
856 perfuse_new_fh((puffs_cookie_t)pn, foo->fh);
857 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
858
859 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
860 puffs_newinfo_setcookie(pni, pn);
861
862 out:
863 ps->ps_destroy_msg(pm);
864
865 /*
866 * create is unimplmented, remember it for later,
867 * and start over using mknod and open instead.
868 */
869 if (error == ENOSYS) {
870 ps->ps_flags |= PS_NO_CREAT;
871 return perfuse_node_create(pu, opc, pni, pcn, vap);
872 }
873
874 return error;
875 }
876
877
878 int
879 perfuse_node_mknod(pu, opc, pni, pcn, vap)
880 struct puffs_usermount *pu;
881 puffs_cookie_t opc;
882 struct puffs_newinfo *pni;
883 const struct puffs_cn *pcn;
884 const struct vattr *vap;
885 {
886 struct perfuse_state *ps;
887 perfuse_msg_t *pm;
888 struct fuse_mknod_in *fmi;
889 const char* path;
890 size_t len;
891
892 ps = puffs_getspecific(pu);
893 path = basename_r((char *)PCNPATH(pcn));
894 len = sizeof(*fmi) + strlen(path) + 1;
895
896 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred);
897 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in);
898 fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
899 fmi->rdev = vap->va_rdev;
900 fmi->umask = 0; /* Seems unused bu libfuse */
901 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
902
903 return node_mk_common(pu, opc, pni, pm);
904 }
905
906
907 int
908 perfuse_node_open(pu, opc, mode, pcr)
909 struct puffs_usermount *pu;
910 puffs_cookie_t opc;
911 int mode;
912 const struct puffs_cred *pcr;
913 {
914 struct perfuse_state *ps;
915 perfuse_msg_t *pm;
916 int op;
917 struct fuse_open_in *foi;
918 struct fuse_open_out *foo;
919 struct puffs_node *pn;
920 int error;
921
922 ps = puffs_getspecific(pu);
923
924 pn = (struct puffs_node *)opc;
925 if (puffs_pn_getvap(pn)->va_type == VDIR)
926 op = FUSE_OPENDIR;
927 else
928 op = FUSE_OPEN;
929
930 /*
931 * libfuse docs say O_CREAT should not be set.
932 */
933 mode &= ~O_CREAT;
934
935 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
936 foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
937 foi->flags = mode & ~O_ACCMODE;
938 switch (mode & (FREAD|FWRITE)) {
939 case FREAD|FWRITE:
940 foi->flags |= O_RDWR;
941 break;
942 case FREAD:
943 foi->flags |= O_RDONLY;
944 break;
945 case FWRITE:
946 foi->flags |= O_WRONLY;
947 break;
948 default:
949 break;
950 }
951 foi->unused = 0;
952
953 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*foo))) != 0)
954 goto out;
955
956 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
957
958 /*
959 * Save the file handle in node private data
960 * so that we can reuse it later
961 */
962 perfuse_new_fh((puffs_cookie_t)pn, foo->fh);
963 #ifdef PERFUSE_DEBUG
964 if (perfuse_diagflags & PDF_FH)
965 DPRINTF("%s: fh = %lld\n", __func__, foo->fh);
966 #endif
967 out:
968 ps->ps_destroy_msg(pm);
969
970 return error;
971 }
972
973 /* ARGSUSED2 */
974 int
975 perfuse_node_close(pu, opc, flags, pcr)
976 struct puffs_usermount *pu;
977 puffs_cookie_t opc;
978 int flags;
979 const struct puffs_cred *pcr;
980 {
981 struct perfuse_state *ps;
982 perfuse_msg_t *pm;
983 int op;
984 uint64_t fh;
985 struct fuse_release_in *fri;
986 struct puffs_node *pn;
987 int error;
988
989 ps = puffs_getspecific(pu);
990
991 pn = (struct puffs_node *)opc;
992
993 if ((fh = perfuse_get_fh((puffs_cookie_t)pn)) == FUSE_UNKNOWN_FH)
994 return EBADF;
995
996 /*
997 * Destroy the filehandle before sending the
998 * request to the FUSE filesystem, otherwise
999 * we may get a second close() while we wait
1000 * for the reply, and we would end up closing
1001 * the same fh twice instead of closng both.
1002 */
1003 perfuse_destroy_fh(pn, fh);
1004
1005 #ifdef PERFUSE_DEBUG
1006 if (perfuse_diagflags & PDF_FH)
1007 DPRINTF("%s: fh = %lld\n", __func__, fh);
1008 #endif
1009
1010 if (puffs_pn_getvap(pn)->va_type == VDIR)
1011 op = FUSE_RELEASEDIR;
1012 else
1013 op = FUSE_RELEASE;
1014
1015 /*
1016 * release_flags may be set to FUSE_RELEASE_FLUSH
1017 * to flush locks. lock_owner must be set in that case
1018 */
1019 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
1020 fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
1021 fri->fh = fh;
1022 fri->flags = 0;
1023 fri->release_flags = 0;
1024 fri->lock_owner = PERFUSE_NODE_DATA(pn)->pnd_lock_owner;
1025 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
1026
1027 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0)
1028 goto out;
1029
1030 out:
1031 if (error != 0)
1032 DWARNX("%s: freed fh = %lld but filesystem returned error = %d",
1033 __func__, fh, error);
1034
1035 ps->ps_destroy_msg(pm);
1036
1037 return error;
1038 }
1039
1040 int
1041 perfuse_node_access(pu, opc, mode, pcr)
1042 struct puffs_usermount *pu;
1043 puffs_cookie_t opc;
1044 int mode;
1045 const struct puffs_cred *pcr;
1046 {
1047 perfuse_msg_t *pm;
1048 struct perfuse_state *ps;
1049 struct fuse_access_in *fai;
1050 int error;
1051
1052 /*
1053 * If we previously detected the filesystem does not
1054 * implement access(), short-circuit the call and skip
1055 * to libpffs access() emulation.
1056 */
1057 ps = puffs_getspecific(pu);
1058 if (ps->ps_flags & PS_NO_ACCESS) {
1059 error = ENOSYS;
1060 } else {
1061 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr);
1062 fai = GET_INPAYLOAD(ps, pm, fuse_access_in);
1063 fai->mask = mode;
1064
1065 error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN);
1066 ps->ps_destroy_msg(pm);
1067 }
1068
1069 if (error == ENOSYS) {
1070 struct fuse_getattr_in *fgi;
1071 struct fuse_attr_out *fao;
1072
1073 ps->ps_flags |= PS_NO_ACCESS;
1074
1075 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR,
1076 sizeof(*fgi), NULL);
1077 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1078 fgi->getattr_flags = 0;
1079 fgi->dummy = 0;
1080 fgi->fh = 0;
1081
1082 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0) {
1083 ps->ps_destroy_msg(pm);
1084 goto out;
1085 }
1086
1087 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1088
1089 error = puffs_access(VREG, fao->attr.mode, fao->attr.uid,
1090 fao->attr.gid, (mode_t)mode, pcr);
1091
1092 ps->ps_destroy_msg(pm);
1093 }
1094
1095 out:
1096 return error;
1097 }
1098
1099 int
1100 perfuse_node_getattr(pu, opc, vap, pcr)
1101 struct puffs_usermount *pu;
1102 puffs_cookie_t opc;
1103 struct vattr *vap;
1104 const struct puffs_cred *pcr;
1105 {
1106 perfuse_msg_t *pm;
1107 struct perfuse_state *ps;
1108 struct fuse_getattr_in *fgi;
1109 struct fuse_attr_out *fao;
1110 int error;
1111
1112 ps = puffs_getspecific(pu);
1113
1114 /*
1115 * FUSE_GETATTR_FH must be set in fgi->flags
1116 * if we use for fgi->fh, but we do not.
1117 */
1118 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
1119 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1120 fgi->getattr_flags = 0;
1121 fgi->dummy = 0;
1122 fgi->fh = 0;
1123
1124 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fao))) != 0)
1125 goto out;
1126
1127 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1128
1129 /*
1130 * The message from filesystem has a cache timeout
1131 * XXX this is ignored yet, is that right?
1132 *
1133 * We also set birthtime, flags, filerev,vaflags to 0.
1134 * This seems the best bet, since the information is
1135 * not available from filesystem.
1136 */
1137 fuse_attr_to_vap(ps, vap, &fao->attr);
1138
1139 out:
1140 ps->ps_destroy_msg(pm);
1141
1142 return error;
1143 }
1144
1145 int
1146 perfuse_node_setattr(pu, opc, vap, pcr)
1147 struct puffs_usermount *pu;
1148 puffs_cookie_t opc;
1149 const struct vattr *vap;
1150 const struct puffs_cred *pcr;
1151 {
1152 perfuse_msg_t *pm;
1153 uint64_t fh;
1154 struct perfuse_state *ps;
1155 struct fuse_setattr_in *fsi;
1156 int error;
1157
1158 ps = puffs_getspecific(pu);
1159
1160 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
1161 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
1162 fsi->valid = 0;
1163
1164 if ((fh = perfuse_get_fh(opc)) != FUSE_UNKNOWN_FH) {
1165 fsi->fh = fh;
1166 fsi->valid |= FUSE_FATTR_FH;
1167 }
1168
1169 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
1170 fsi->size = vap->va_size;
1171 fsi->valid |= FUSE_FATTR_SIZE;
1172 }
1173
1174 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
1175 fsi->atime = vap->va_atime.tv_sec;;
1176 fsi->atimensec = vap->va_atime.tv_nsec;;
1177 fsi->valid |= (FUSE_FATTR_ATIME|FUSE_FATTR_ATIME_NOW);
1178 }
1179
1180 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
1181 fsi->mtime = vap->va_mtime.tv_sec;;
1182 fsi->mtimensec = vap->va_mtime.tv_nsec;;
1183 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_MTIME_NOW);
1184 }
1185
1186 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
1187 fsi->mode = vap->va_mode;
1188 fsi->valid |= FUSE_FATTR_MODE;
1189 }
1190
1191 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
1192 fsi->uid = vap->va_uid;
1193 fsi->valid |= FUSE_FATTR_UID;
1194 }
1195
1196 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
1197 fsi->gid = vap->va_gid;
1198 fsi->valid |= FUSE_FATTR_GID;
1199 }
1200
1201 if (PERFUSE_NODE_DATA(opc)->pnd_lock_owner != 0) {
1202 fsi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
1203 fsi->valid |= FUSE_FATTR_LOCKOWNER;
1204 }
1205
1206 /*
1207 * A fuse_attr_out is returned, but we ignore it.
1208 */
1209 error = XCHG_MSG(ps, pu, pm, sizeof(struct fuse_attr_out));
1210
1211 ps->ps_destroy_msg(pm);
1212
1213 return error;
1214 }
1215
1216 int
1217 perfuse_node_poll(pu, opc, events)
1218 struct puffs_usermount *pu;
1219 puffs_cookie_t opc;
1220 int *events;
1221 {
1222 struct perfuse_state *ps;
1223 perfuse_msg_t *pm;
1224 struct fuse_poll_in *fpi;
1225 struct fuse_poll_out *fpo;
1226 int error;
1227
1228 ps = puffs_getspecific(pu);
1229 /*
1230 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1231 */
1232 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1233 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1234 fpi->fh = perfuse_get_fh(opc);
1235 fpi->kh = 0;
1236 fpi->flags = 0;
1237
1238 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fpo))) != 0)
1239 goto out;
1240
1241 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
1242 *events = fpo->revents;
1243 out:
1244 ps->ps_destroy_msg(pm);
1245
1246 return error;
1247 }
1248
1249 /* ARGSUSED0 */
1250 int
1251 perfuse_node_mmap(pu, opc, flags, pcr)
1252 struct puffs_usermount *pu;
1253 puffs_cookie_t opc;
1254 int flags;
1255 const struct puffs_cred *pcr;
1256 {
1257 /*
1258 * Not implemented anymore in libfuse
1259 */
1260 return ENOSYS;
1261 }
1262
1263 /* ARGSUSED2 */
1264 int
1265 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi)
1266 struct puffs_usermount *pu;
1267 puffs_cookie_t opc;
1268 const struct puffs_cred *pcr;
1269 int flags;
1270 off_t offlo;
1271 off_t offhi;
1272 {
1273 perfuse_msg_t *pm;
1274 struct perfuse_state *ps;
1275 struct fuse_fsync_in *ffi;
1276 int error;
1277
1278 /*
1279 * If we previously detected it as unimplemented,
1280 * skip the call to the filesystem.
1281 */
1282 ps = puffs_getspecific(pu);
1283 if (ps->ps_flags == PS_NO_FSYNC)
1284 return ENOSYS;
1285
1286 /*
1287 * If fsync_flags is set, meta data should not be flushed.
1288 */
1289 pm = ps->ps_new_msg(pu, opc, FUSE_FSYNC, sizeof(*ffi), NULL);
1290 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
1291 ffi->fh = perfuse_get_fh(opc);
1292 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
1293
1294 if ((error = XCHG_MSG(ps, pu, pm, NO_PAYLOAD_REPLY_LEN)) != 0)
1295 goto out;
1296
1297 /*
1298 * No reply beyond fuse_out_header: nothing to do on success.
1299 */
1300 out:
1301 if (error == ENOSYS)
1302 ps->ps_flags |= PS_NO_FSYNC;
1303
1304 ps->ps_destroy_msg(pm);
1305
1306 return error;
1307 }
1308
1309 /* ARGSUSED0 */
1310 int
1311 perfuse_node_seek(pu, opc, oldoff, newoff, pcr)
1312 struct puffs_usermount *pu;
1313 puffs_cookie_t opc;
1314 off_t oldoff;
1315 off_t newoff;
1316 const struct puffs_cred *pcr;
1317 {
1318 /*
1319 * XXX what should I do with oldoff?
1320 * XXX where is the newoffset returned?
1321 * XXX the held seek pointer seems just unused
1322 */
1323 PERFUSE_NODE_DATA(opc)->pnd_offset = newoff;
1324
1325 return 0;
1326 }
1327
1328 int
1329 perfuse_node_remove(pu, opc, targ, pcn)
1330 struct puffs_usermount *pu;
1331 puffs_cookie_t opc;
1332 puffs_cookie_t targ;
1333 const struct puffs_cn *pcn;
1334 {
1335 struct perfuse_state *ps;
1336 perfuse_msg_t *pm;
1337 struct puffs_node *pn;
1338 char *path;
1339 const char *name;
1340 size_t len;
1341 int error;
1342
1343 ps = puffs_getspecific(pu);
1344
1345 if (targ == NULL)
1346 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
1347
1348 pn = (struct puffs_node *)targ;
1349 name = basename_r((char *)PNPATH(pn));
1350 len = strlen(name) + 1;
1351
1352 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
1353 path = _GET_INPAYLOAD(ps, pm, char *);
1354 (void)strlcpy(path, name, len);
1355
1356 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1357 goto out;
1358
1359 if (puffs_inval_namecache_dir(pu, opc) != 0)
1360 DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
1361
1362 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0)
1363 DERR(EX_OSERR, "puffs_inval_namecache_node failed");
1364
1365 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
1366
1367 /*
1368 * Reclaim should take care of decreasing pnd_childcount
1369 */
1370 out:
1371 ps->ps_destroy_msg(pm);
1372
1373 return error;
1374 }
1375
1376 int
1377 perfuse_node_link(pu, opc, targ, pcn)
1378 struct puffs_usermount *pu;
1379 puffs_cookie_t opc;
1380 puffs_cookie_t targ;
1381 const struct puffs_cn *pcn;
1382 {
1383 struct perfuse_state *ps;
1384 perfuse_msg_t *pm;
1385 const char *name;
1386 size_t len;
1387 struct puffs_node *pn;
1388 struct fuse_link_in *fli;
1389 int error;
1390
1391 ps = puffs_getspecific(pu);
1392 pn = (struct puffs_node *)targ;
1393 name = basename_r((char *)PCNPATH(pcn));
1394 len = sizeof(*fli) + strlen(name) + 1;
1395
1396 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred);
1397 fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
1398 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_ino;
1399 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
1400
1401 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN);
1402
1403 ps->ps_destroy_msg(pm);
1404
1405 return error;
1406 }
1407
1408 /* targ is unused since the name is in pcn_targ */
1409 /* ARGSUSED5 */
1410 int
1411 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ)
1412 struct puffs_usermount *pu;
1413 puffs_cookie_t opc;
1414 puffs_cookie_t src;
1415 const struct puffs_cn *pcn_src;
1416 puffs_cookie_t targ_dir;
1417 puffs_cookie_t targ;
1418 const struct puffs_cn *pcn_targ;
1419 {
1420 struct perfuse_state *ps;
1421 perfuse_msg_t *pm;
1422 struct fuse_rename_in *fri;
1423 const char *newname;
1424 const char *oldname;
1425 char *np;
1426 int error;
1427 size_t len;
1428 size_t newname_len;
1429 size_t oldname_len;
1430
1431 ps = puffs_getspecific(pu);
1432 newname = basename_r((char *)PCNPATH(pcn_targ));
1433 newname_len = strlen(newname) + 1;
1434 oldname = basename_r((char *)PCNPATH(pcn_src));
1435 oldname_len = strlen(oldname) + 1;
1436
1437 len = sizeof(*fri) + oldname_len + newname_len;
1438 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_src->pcn_cred);
1439 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
1440 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_ino;
1441 np = (char *)(void *)(fri + 1);
1442 (void)strlcpy(np, oldname, oldname_len);
1443 np += oldname_len;
1444 (void)strlcpy(np, newname, newname_len);
1445
1446 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1447 goto out;
1448
1449 /*
1450 * Update source and destination directories child count
1451 * Update moved object parent directory
1452 */
1453 PERFUSE_NODE_DATA(opc)->pnd_childcount--;
1454 PERFUSE_NODE_DATA(targ_dir)->pnd_childcount++;
1455 PERFUSE_NODE_DATA(src)->pnd_parent = targ_dir;
1456
1457 out:
1458 ps->ps_destroy_msg(pm);
1459
1460 return error;
1461 }
1462
1463 int
1464 perfuse_node_mkdir(pu, opc, pni, pcn, vap)
1465 struct puffs_usermount *pu;
1466 puffs_cookie_t opc;
1467 struct puffs_newinfo *pni;
1468 const struct puffs_cn *pcn;
1469 const struct vattr *vap;
1470 {
1471 struct perfuse_state *ps;
1472 perfuse_msg_t *pm;
1473 struct fuse_mkdir_in *fmi;
1474 const char *path;
1475 size_t len;
1476
1477 ps = puffs_getspecific(pu);
1478 path = basename_r((char *)PCNPATH(pcn));
1479 len = sizeof(*fmi) + strlen(path) + 1;
1480
1481 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred);
1482 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
1483 fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
1484 fmi->umask = 0; /* Seems unused bu libfuse? */
1485 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
1486
1487 return node_mk_common(pu, opc, pni, pm);
1488 }
1489
1490
1491 int
1492 perfuse_node_rmdir(pu, opc, targ, pcn)
1493 struct puffs_usermount *pu;
1494 puffs_cookie_t opc;
1495 puffs_cookie_t targ;
1496 const struct puffs_cn *pcn;
1497 {
1498 struct perfuse_state *ps;
1499 perfuse_msg_t *pm;
1500 struct puffs_node *pn;
1501 char *path;
1502 const char *name;
1503 size_t len;
1504 int error;
1505
1506 ps = puffs_getspecific(pu);
1507 pn = (struct puffs_node *)targ;
1508 name = basename_r((char *)PNPATH(pn));
1509 len = strlen(name) + 1;
1510
1511 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
1512 path = _GET_INPAYLOAD(ps, pm, char *);
1513 (void)strlcpy(path, name, len);
1514
1515 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1516 goto out;
1517
1518 if (puffs_inval_namecache_dir(pu, opc) != 0)
1519 DERR(EX_OSERR, "puffs_inval_namecache_dir failed");
1520
1521 if (puffs_inval_pagecache_node(pu, (puffs_cookie_t)pn) != 0)
1522 DERR(EX_OSERR, "puffs_inval_namecache_node failed");
1523
1524 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
1525 out:
1526 ps->ps_destroy_msg(pm);
1527
1528 return error;
1529 }
1530
1531 /* vap is unused */
1532 /* ARGSUSED4 */
1533 int
1534 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
1535 struct puffs_usermount *pu;
1536 puffs_cookie_t opc;
1537 struct puffs_newinfo *pni;
1538 const struct puffs_cn *pcn_src;
1539 const struct vattr *vap;
1540 const char *link_target;
1541 {
1542 struct perfuse_state *ps;
1543 perfuse_msg_t *pm;
1544 char *np;
1545 const char *path;
1546 size_t path_len;
1547 size_t linkname_len;
1548 size_t len;
1549
1550 ps = puffs_getspecific(pu);
1551 path = basename_r((char *)PCNPATH(pcn_src));
1552 path_len = strlen(path) + 1;
1553 linkname_len = strlen(link_target) + 1;
1554 len = path_len + linkname_len;
1555
1556 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
1557 np = _GET_INPAYLOAD(ps, pm, char *);
1558 (void)strlcpy(np, path, path_len);
1559 np += path_len;
1560 (void)strlcpy(np, link_target, linkname_len);
1561
1562 return node_mk_common(pu, opc, pni, pm);
1563 }
1564
1565 int
1566 perfuse_node_readdir(pu, opc, dent, readoff,
1567 reslen, pcr, eofflag, cookies, ncookies)
1568 struct puffs_usermount *pu;
1569 puffs_cookie_t opc;
1570 struct dirent *dent;
1571 off_t *readoff;
1572 size_t *reslen;
1573 const struct puffs_cred *pcr;
1574 int *eofflag;
1575 off_t *cookies;
1576 size_t *ncookies;
1577 {
1578 perfuse_msg_t *pm;
1579 uint64_t fh;
1580 struct perfuse_state *ps;
1581 struct perfuse_node_data *pnd;
1582 struct fuse_read_in *fri;
1583 struct fuse_out_header *foh;
1584 struct fuse_dirent *fd;
1585 size_t foh_len;
1586 int error;
1587 int open_self;
1588 uint64_t fd_offset;
1589
1590 pm = NULL;
1591 error = 0;
1592 open_self = 0;
1593 ps = puffs_getspecific(pu);
1594
1595 /*
1596 * readdir state is kept at node level, and several readdir
1597 * requests can be issued at the same time on the same node.
1598 * We need to queue requests so that only one is in readdir
1599 * code at the same time.
1600 */
1601 pnd = PERFUSE_NODE_DATA(opc);
1602 while (pnd->pnd_flags & PND_INREADDIR)
1603 requeue_request(pu, opc, PCQ_READDIR);
1604 pnd->pnd_flags |= PND_INREADDIR;
1605
1606 #ifdef PERFUSE_DEBUG
1607 if (perfuse_diagflags & PDF_READDIR)
1608 DPRINTF("%s: READDIR opc = %p enter critical section\n",
1609 __func__, (void *)opc);
1610 #endif
1611 /*
1612 * Do we already have the data bufered?
1613 */
1614 if (pnd->pnd_dirent != NULL)
1615 goto out;
1616 pnd->pnd_dirent_len = 0;
1617
1618 /*
1619 * It seems NetBSD can call readdir without open first
1620 * libfuse will crash if it is done that way, hence open first.
1621 */
1622 if ((fh = perfuse_get_fh(opc)) == FUSE_UNKNOWN_FH) {
1623 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
1624 goto out;
1625 open_self = 1;
1626
1627 if ((fh = perfuse_get_fh(opc)) == FUSE_UNKNOWN_FH)
1628 DERRX(EX_SOFTWARE, "open directory without fh");
1629 }
1630
1631 pnd->pnd_all_fd = NULL;
1632 pnd->pnd_all_fd_len = 0;
1633 fd_offset = 0;
1634
1635 do {
1636 size_t fd_len;
1637 char *afdp;
1638
1639 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
1640
1641 /*
1642 * read_flags, lock_owner and flags are unused in libfuse
1643 *
1644 * XXX if fri->size is too big (bigger than PAGE_SIZE?), * we get strange bugs. ktrace shows 16 bytes or garbage
1645 * at the end of sent frames, but perfused does not receive
1646 * that data. The data length is hoverver the same, which
1647 * cause perfused to use the last 16 bytes of the frame
1648 * as the frame header of the next frame.
1649 *
1650 * This may be a kernel bug.
1651 */
1652 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
1653 fri->fh = fh;
1654 fri->offset = fd_offset;
1655 fri->size = PAGE_SIZE - sizeof(struct fuse_out_header);
1656 fri->read_flags = 0;
1657 fri->lock_owner = 0;
1658 fri->flags = 0;
1659
1660 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1661 goto out;
1662
1663 /*
1664 * There are many puffs_framebufs calls later,
1665 * therefore foh will not be valid for a long time.
1666 * Just get the length and forget it.
1667 */
1668 foh = GET_OUTHDR(ps, pm);
1669 foh_len = foh->len;
1670
1671 /*
1672 * It seems that the only way to discover the end
1673 * of the buffer is to get an empty read
1674 */
1675 if (foh_len == sizeof(*foh))
1676 break;
1677
1678 /*
1679 * Corrupted message.
1680 */
1681 if (foh_len < sizeof(*foh) + sizeof(*fd)) {
1682 DWARNX("readdir reply too short");
1683 error = EIO;
1684 goto out;
1685 }
1686
1687
1688 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
1689 fd_len = foh_len - sizeof(*foh);
1690
1691 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
1692 pnd->pnd_all_fd_len + fd_len);
1693 if (pnd->pnd_all_fd == NULL)
1694 DERR(EX_OSERR, "malloc failed");
1695
1696 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
1697 (void)memcpy(afdp, fd, fd_len);
1698
1699 pnd->pnd_all_fd_len += fd_len;
1700 fd_offset += fd_len;
1701
1702 ps->ps_destroy_msg(pm);
1703 pm = NULL;
1704 } while (1 /* CONSTCOND */);
1705
1706 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, pnd->pnd_all_fd_len) == -1)
1707 error = EIO;
1708
1709 out:
1710 if (pnd->pnd_all_fd != NULL) {
1711 free(pnd->pnd_all_fd);
1712 pnd->pnd_all_fd = NULL;
1713 pnd->pnd_all_fd_len = 0;
1714 }
1715
1716 if (pm != NULL)
1717 ps->ps_destroy_msg(pm);
1718
1719 /*
1720 * If we opened the directory ourselves, close now
1721 * errors are ignored.
1722 */
1723 if (open_self)
1724 (void)perfuse_node_close(pu, opc, 0, pcr);
1725
1726 if (error == 0)
1727 error = readdir_buffered(ps, opc, dent, readoff,
1728 reslen, pcr, eofflag, cookies, ncookies);
1729
1730 /*
1731 * Schedule queued readdir requests
1732 */
1733 dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
1734 pnd->pnd_flags &= ~PND_INREADDIR;
1735
1736 #ifdef PERFUSE_DEBUG
1737 if (perfuse_diagflags & PDF_READDIR)
1738 DPRINTF("%s: READDIR opc = %p exit critical section\n",
1739 __func__, (void *)opc);
1740 #endif
1741
1742 return error;
1743 }
1744
1745 int
1746 perfuse_node_readlink(pu, opc, pcr, linkname, linklen)
1747 struct puffs_usermount *pu;
1748 puffs_cookie_t opc;
1749 const struct puffs_cred *pcr;
1750 char *linkname;
1751 size_t *linklen;
1752 {
1753 struct perfuse_state *ps;
1754 perfuse_msg_t *pm;
1755 int error;
1756 size_t len;
1757 struct fuse_out_header *foh;
1758
1759 ps = puffs_getspecific(pu);
1760
1761 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
1762
1763 if ((error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN)) != 0)
1764 goto out;
1765
1766 foh = GET_OUTHDR(ps, pm);
1767 len = foh->len - sizeof(*foh) + 1;
1768 if (len > *linklen)
1769 DERRX(EX_PROTOCOL, "path len = %d too long", len);
1770
1771 *linklen = len;
1772 (void)strlcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
1773 out:
1774 ps->ps_destroy_msg(pm);
1775
1776 return error;
1777 }
1778
1779 int
1780 perfuse_node_reclaim(pu, opc)
1781 struct puffs_usermount *pu;
1782 puffs_cookie_t opc;
1783 {
1784 struct perfuse_state *ps;
1785 perfuse_msg_t *pm;
1786 struct fuse_forget_in *ffi;
1787 struct puffs_node *pn;
1788 struct puffs_node *pn_root;
1789
1790 ps = puffs_getspecific(pu);
1791
1792 /*
1793 * Make sure open files are properly closed when reclaimed.
1794 */
1795 while (perfuse_get_fh(opc) != FUSE_UNKNOWN_FH)
1796 (void)perfuse_node_close(pu, opc, 0, NULL);
1797
1798 /*
1799 * Never forget the root.
1800 */
1801 if (PERFUSE_NODE_DATA(opc)->pnd_ino == FUSE_ROOT_ID)
1802 return 0;
1803
1804 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_RECLAIMED;
1805
1806 #ifdef PERFUSE_DEBUG
1807 if (perfuse_diagflags & PDF_RECLAIM)
1808 DPRINTF("%s (nodeid %lld) reclaimed\n",
1809 (char *)PNPATH((struct puffs_node *)opc),
1810 PERFUSE_NODE_DATA(opc)->pnd_ino);
1811 #endif
1812
1813 pn_root = puffs_getroot(pu);
1814 pn = (struct puffs_node *)opc;
1815 while (pn != pn_root) {
1816 struct puffs_node *parent_pn;
1817
1818 #ifdef PERFUSE_DEBUG
1819 if (perfuse_diagflags & PDF_RECLAIM)
1820 DPRINTF("%s (nodeid %lld) is %sreclaimed, has childcount %d\n",
1821 (char *)PNPATH(pn),
1822 PERFUSE_NODE_DATA(pn)->pnd_ino,
1823 PERFUSE_NODE_DATA(pn)->pnd_flags & PND_RECLAIMED
1824 ? "" : "not ",
1825 PERFUSE_NODE_DATA(pn)->pnd_childcount);
1826 #endif
1827 if (!(PERFUSE_NODE_DATA(pn)->pnd_flags & PND_RECLAIMED) ||
1828 (PERFUSE_NODE_DATA(pn)->pnd_childcount != 0))
1829 return 0;
1830
1831 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
1832 sizeof(*ffi), NULL);
1833 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
1834 ffi->nlookup = PERFUSE_NODE_DATA(pn)->pnd_nlookup;
1835
1836 /*
1837 * No reply is expected, pm is freed in XCHG_MSG
1838 */
1839 (void)XCHG_MSG_NOREPLY(ps, pu, pm, UNSPEC_REPLY_LEN);
1840
1841 parent_pn = PERFUSE_NODE_DATA(pn)->pnd_parent;
1842
1843 perfuse_destroy_pn(pn);
1844 puffs_pn_put(pn);
1845
1846 pn = parent_pn;
1847 }
1848
1849 return 0;
1850 }
1851
1852 /* ARGSUSED0 */
1853 int
1854 perfuse_node_inactive(pu, opc)
1855 struct puffs_usermount *pu;
1856 puffs_cookie_t opc;
1857 {
1858 return 0;
1859 }
1860
1861
1862 /* ARGSUSED0 */
1863 int
1864 perfuse_node_print(pu, opc)
1865 struct puffs_usermount *pu;
1866 puffs_cookie_t opc;
1867 {
1868 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1869 return 0;
1870 }
1871
1872 /* ARGSUSED0 */
1873 int
1874 perfuse_node_pathconf(pu, opc, name, retval)
1875 struct puffs_usermount *pu;
1876 puffs_cookie_t opc;
1877 int name;
1878 int *retval;
1879 {
1880 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1881 return 0;
1882 }
1883
1884 /* id is unused */
1885 /* ARGSUSED2 */
1886 int
1887 perfuse_node_advlock(pu, opc, id, op, fl, flags)
1888 struct puffs_usermount *pu;
1889 puffs_cookie_t opc;
1890 void *id;
1891 int op;
1892 struct flock *fl;
1893 int flags;
1894 {
1895 struct perfuse_state *ps;
1896 int fop;
1897 perfuse_msg_t *pm;
1898 struct fuse_lk_in *fli;
1899 struct fuse_lk_out *flo;
1900 int error;
1901
1902 ps = puffs_getspecific(pu);
1903
1904 if (op == F_GETLK)
1905 fop = FUSE_GETLK;
1906 else
1907 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
1908
1909 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
1910 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
1911 fli->fh = perfuse_get_fh(opc);
1912 fli->owner = fl->l_pid;
1913 fli->lk.start = fl->l_start;
1914 fli->lk.end = fl->l_start + fl->l_len;
1915 fli->lk.type = fl->l_type;
1916 fli->lk.pid = fl->l_pid;
1917 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
1918
1919 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*flo))) != 0)
1920 goto out;
1921
1922 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
1923 fl->l_start = flo->lk.start;
1924 fl->l_len = flo->lk.end - flo->lk.start;
1925 fl->l_pid = flo->lk.pid;
1926 fl->l_type = flo->lk.type;
1927 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */
1928
1929 /*
1930 * Save or clear the lock
1931 */
1932 switch (op) {
1933 case F_SETLK:
1934 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
1935 break;
1936 case F_UNLCK:
1937 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = 0;
1938 break;
1939 default:
1940 break;
1941 }
1942
1943 out:
1944 ps->ps_destroy_msg(pm);
1945
1946 return error;
1947 }
1948
1949 int
1950 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
1951 struct puffs_usermount *pu;
1952 puffs_cookie_t opc;
1953 uint8_t *buf;
1954 off_t offset;
1955 size_t *resid;
1956 const struct puffs_cred *pcr;
1957 int ioflag;
1958 {
1959 struct perfuse_state *ps;
1960 perfuse_msg_t *pm;
1961 struct fuse_read_in *fri;
1962 struct fuse_out_header *foh;
1963 size_t readen;
1964 size_t requested;
1965 int error;
1966
1967 ps = puffs_getspecific(pu);
1968 pm = NULL;
1969
1970 requested = *resid;
1971 if ((ps->ps_readahead + requested) > ps->ps_max_readahead) {
1972 if (perfuse_diagflags & PDF_REQUEUE)
1973 DPRINTF("readahead = %d\n", ps->ps_readahead);
1974 requeue_request(pu, opc, PCQ_READ);
1975 }
1976 ps->ps_readahead += requested;
1977
1978 do {
1979 /*
1980 * flags may be set to FUSE_READ_LOCKOWNER
1981 * if lock_owner is provided.
1982 *
1983 * XXX See comment about fri->size in perfuse_node_readdir
1984 * We encounter the same bug here.
1985 */
1986 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
1987 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
1988 fri->fh = perfuse_get_fh(opc);
1989 fri->offset = offset;
1990 fri->size = MIN(*resid, PAGE_SIZE - sizeof(*foh));
1991 fri->read_flags = 0; /* XXX Unused by libfuse? */
1992 fri->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
1993 fri->flags = 0;
1994 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
1995
1996 error = XCHG_MSG(ps, pu, pm, UNSPEC_REPLY_LEN);
1997
1998 if (error != 0)
1999 goto out;
2000
2001 foh = GET_OUTHDR(ps, pm);
2002 readen = foh->len - sizeof(*foh);
2003
2004 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
2005
2006 buf += readen;
2007 offset += readen;
2008 *resid -= readen;
2009
2010 ps->ps_destroy_msg(pm);
2011 pm = NULL;
2012 } while ((*resid != 0) && (readen != 0));
2013
2014 if (ioflag & (IO_SYNC|IO_DSYNC))
2015 ps->ps_syncreads++;
2016 else
2017 ps->ps_asyncreads++;
2018
2019 out:
2020 if (pm != NULL)
2021 ps->ps_destroy_msg(pm);
2022
2023 ps->ps_readahead -= requested;
2024 dequeue_requests(ps, opc, PCQ_READ, 1);
2025
2026 return error;
2027 }
2028
2029 int
2030 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
2031 struct puffs_usermount *pu;
2032 puffs_cookie_t opc;
2033 uint8_t *buf;
2034 off_t offset;
2035 size_t *resid;
2036 const struct puffs_cred *pcr;
2037 int ioflag;
2038 {
2039 struct perfuse_state *ps;
2040 perfuse_msg_t *pm;
2041 struct fuse_write_in *fwi;
2042 struct fuse_write_out *fwo;
2043 size_t data_len;
2044 size_t payload_len;
2045 size_t written;
2046 size_t requested;
2047 int error;
2048
2049 ps = puffs_getspecific(pu);
2050 pm = NULL;
2051 written = 0;
2052
2053 requested = *resid;
2054 if ((ps->ps_write + requested) > ps->ps_max_write) {
2055 if (perfuse_diagflags & PDF_REQUEUE)
2056 DPRINTF("write = %d\n", ps->ps_write);
2057 requeue_request(pu, opc, PCQ_WRITE);
2058 }
2059 ps->ps_write += requested;
2060
2061 do {
2062 /*
2063 * It seems libfuse does not expects big chunks, so
2064 * send it page per page. The writepage feature is
2065 * probably there to minmize data movement.
2066 * XXX use ps->ps_maxwrite?
2067 */
2068 data_len = MIN(*resid, PAGE_SIZE);
2069 payload_len = data_len + sizeof(*fwi);
2070
2071 /*
2072 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
2073 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
2074 * write_flags is set to 1 for writepage.
2075 */
2076 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
2077 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
2078 fwi->fh = perfuse_get_fh(opc);
2079 fwi->offset = offset;
2080 fwi->size = data_len;
2081 fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1;
2082 fwi->lock_owner = PERFUSE_NODE_DATA(opc)->pnd_lock_owner;
2083 fwi->flags = 0;
2084 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
2085 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
2086 (void)memcpy((fwi + 1), buf + written, data_len);
2087
2088 if ((error = XCHG_MSG(ps, pu, pm, sizeof(*fwo))) != 0)
2089 goto out;
2090
2091 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
2092 written = fwo->size;
2093 *resid -= written;
2094 offset += written;
2095 buf += written;
2096
2097 ps->ps_destroy_msg(pm);
2098 pm = NULL;
2099 } while (*resid != 0);
2100
2101 /*
2102 * puffs_ops(3) says
2103 * "everything must be written or an error will be generated"
2104 */
2105 if (*resid != 0)
2106 error = EFBIG;
2107
2108 if (ioflag & (IO_SYNC|IO_DSYNC))
2109 ps->ps_syncwrites++;
2110 else
2111 ps->ps_asyncwrites++;
2112
2113 out:
2114 if (pm != NULL)
2115 ps->ps_destroy_msg(pm);
2116
2117 ps->ps_write -= requested;
2118 dequeue_requests(ps, opc, PCQ_WRITE, 1);
2119
2120 return error;
2121 }
2122
2123 /* ARGSUSED0 */
2124 void
2125 perfuse_cache_write(pu, opc, size, runs)
2126 struct puffs_usermount *pu;
2127 puffs_cookie_t opc;
2128 size_t size;
2129 struct puffs_cacherun *runs;
2130 {
2131 return;
2132 }
2133
2134