ops.c revision 1.49 1 /* $NetBSD: ops.c,v 1.49 2011/12/28 17:33:53 manu Exp $ */
2
3 /*-
4 * Copyright (c) 2010-2011 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/socket.h>
38 #include <sys/socket.h>
39 #include <sys/extattr.h>
40 #include <sys/time.h>
41 #include <machine/vmparam.h>
42
43 #include "perfuse_priv.h"
44 #include "fuse.h"
45
46 extern int perfuse_diagflags;
47
48 #if 0
49 static void print_node(const char *, puffs_cookie_t);
50 #endif
51 static void set_expire(puffs_cookie_t, struct fuse_entry_out *,
52 struct fuse_attr_out *);
53 static int attr_expired(puffs_cookie_t);
54 static int entry_expired(puffs_cookie_t);
55 static int xchg_msg(struct puffs_usermount *, puffs_cookie_t,
56 perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply);
57 static int mode_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
58 static int sticky_access(struct puffs_node *, const struct puffs_cred *);
59 static void fuse_attr_to_vap(struct perfuse_state *,
60 struct vattr *, struct fuse_attr *);
61 static int node_lookup_dir_nodot(struct puffs_usermount *,
62 puffs_cookie_t, char *, size_t, struct puffs_node **);
63 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
64 const char *, const struct puffs_cred *, struct puffs_node **);
65 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
66 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *);
67 static int node_mk_common_final(struct puffs_usermount *, puffs_cookie_t,
68 struct puffs_node *, const struct puffs_cn *pcn);
69 static uint64_t readdir_last_cookie(struct fuse_dirent *, size_t);
70 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
71 struct fuse_dirent *, size_t);
72 static int readdir_buffered(puffs_cookie_t, struct dirent *, off_t *,
73 size_t *);
74 static void requeue_request(struct puffs_usermount *,
75 puffs_cookie_t opc, enum perfuse_qtype);
76 static int dequeue_requests(struct perfuse_state *,
77 puffs_cookie_t opc, enum perfuse_qtype, int);
78 #define DEQUEUE_ALL 0
79
80 /*
81 * From <sys/vnode>, inside #ifdef _KERNEL section
82 */
83 #define IO_SYNC (0x40|IO_DSYNC)
84 #define IO_DSYNC 0x00200
85 #define IO_DIRECT 0x02000
86
87 /*
88 * From <fcntl>, inside #ifdef _KERNEL section
89 */
90 #define F_WAIT 0x010
91 #define F_FLOCK 0x020
92 #define OFLAGS(fflags) ((fflags) - 1)
93
94 /*
95 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
96 */
97 const enum vtype iftovt_tab[16] = {
98 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
99 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
100 };
101 const int vttoif_tab[9] = {
102 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
103 S_IFSOCK, S_IFIFO, S_IFMT,
104 };
105
106 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
107 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
108
109 #if 0
110 static void
111 print_node(func, opc)
112 const char *func;
113 puffs_cookie_t opc;
114 {
115 struct puffs_node *pn;
116 struct perfuse_node_data *pnd;
117 struct vattr *vap;
118
119 pn = (struct puffs_node *)opc;
120 pnd = PERFUSE_NODE_DATA(opc);
121 vap = &pn->pn_va;
122
123 printf("%s: \"%s\", opc = %p, nodeid = 0x%"PRIx64" ino = %"PRIu64"\n",
124 func, pnd->pnd_name, opc, pnd->pnd_nodeid, vap->va_fileid);
125
126 return;
127 }
128 #endif /* PERFUSE_DEBUG */
129
130 int
131 perfuse_node_close_common(pu, opc, mode)
132 struct puffs_usermount *pu;
133 puffs_cookie_t opc;
134 int mode;
135 {
136 struct perfuse_state *ps;
137 perfuse_msg_t *pm;
138 int op;
139 uint64_t fh;
140 struct fuse_release_in *fri;
141 struct perfuse_node_data *pnd;
142 struct puffs_node *pn;
143 int error;
144
145 ps = puffs_getspecific(pu);
146 pn = (struct puffs_node *)opc;
147 pnd = PERFUSE_NODE_DATA(pn);
148
149 if (puffs_pn_getvap(pn)->va_type == VDIR) {
150 op = FUSE_RELEASEDIR;
151 mode = FREAD;
152 } else {
153 op = FUSE_RELEASE;
154 }
155
156 /*
157 * Destroy the filehandle before sending the
158 * request to the FUSE filesystem, otherwise
159 * we may get a second close() while we wait
160 * for the reply, and we would end up closing
161 * the same fh twice instead of closng both.
162 */
163 fh = perfuse_get_fh(opc, mode);
164 perfuse_destroy_fh(pn, fh);
165
166 /*
167 * release_flags may be set to FUSE_RELEASE_FLUSH
168 * to flush locks. lock_owner must be set in that case
169 *
170 * ps_new_msg() is called with NULL creds, which will
171 * be interpreted as FUSE superuser. We come here from the
172 * inactive method, which provides no creds, but obviously
173 * runs with kernel privilege.
174 */
175 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
176 fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
177 fri->fh = fh;
178 fri->flags = 0;
179 fri->release_flags = 0;
180 fri->lock_owner = pnd->pnd_lock_owner;
181 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
182
183 #ifdef PERFUSE_DEBUG
184 if (perfuse_diagflags & PDF_FH)
185 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
186 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
187 #endif
188
189 if ((error = xchg_msg(pu, opc, pm,
190 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
191 DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem "
192 "returned error = %d", __func__, fh, error);
193
194 ps->ps_destroy_msg(pm);
195
196 return 0;
197 }
198
199 static int
200 xchg_msg(pu, opc, pm, len, wait)
201 struct puffs_usermount *pu;
202 puffs_cookie_t opc;
203 perfuse_msg_t *pm;
204 size_t len;
205 enum perfuse_xchg_pb_reply wait;
206 {
207 struct perfuse_state *ps;
208 struct perfuse_node_data *pnd;
209 struct perfuse_trace *pt = NULL;
210 int opcode;
211 int error;
212
213 ps = puffs_getspecific(pu);
214 pnd = NULL;
215 if ((struct puffs_node *)opc != NULL)
216 pnd = PERFUSE_NODE_DATA(opc);
217
218 #ifdef PERFUSE_DEBUG
219 if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0))
220 DPRINTF("file = \"%s\", ino = %"PRIu64" flags = 0x%x\n",
221 perfuse_node_path(opc),
222 ((struct puffs_node *)opc)->pn_va.va_fileid,
223 PERFUSE_NODE_DATA(opc)->pnd_flags);
224 #endif
225 if (pnd)
226 pnd->pnd_flags |= PND_INXCHG;
227
228 /*
229 * Record FUSE call start if requested
230 */
231 opcode = ps->ps_get_inhdr(pm)->opcode;
232 if (perfuse_diagflags & PDF_TRACE) {
233 if ((pt = malloc(sizeof(*pt))) == NULL)
234 DERR(EX_OSERR, "malloc failed");
235
236 pt->pt_opcode = opcode;
237 pt->pt_status = inxchg;
238
239 if (opc == 0)
240 (void)strcpy(pt->pt_path, "");
241 else
242 (void)strlcpy(pt->pt_path,
243 perfuse_node_path(opc),
244 sizeof(pt->pt_path));
245
246 (void)strlcpy(pt->pt_extra,
247 perfuse_opdump_in(ps, pm),
248 sizeof(pt->pt_extra));
249
250 if (clock_gettime(CLOCK_REALTIME, &pt->pt_start) != 0)
251 DERR(EX_OSERR, "clock_gettime failed");
252
253 TAILQ_INSERT_TAIL(&ps->ps_trace, pt, pt_list);
254 ps->ps_tracecount++;
255 }
256
257 /*
258 * Do actual FUSE exchange
259 */
260 if ((error = ps->ps_xchg_msg(pu, pm, len, wait)) != 0)
261 ps->ps_destroy_msg(pm);
262
263 /*
264 * Record FUSE call end if requested
265 */
266 if (perfuse_diagflags & PDF_TRACE) {
267 if (clock_gettime(CLOCK_REALTIME, &pt->pt_end) != 0)
268 DERR(EX_OSERR, "clock_gettime failed");
269
270 pt->pt_status = done;
271 pt->pt_error = error;
272 while (ps->ps_tracecount > PERFUSE_TRACECOUNT_MAX) {
273 struct perfuse_trace *fpt = TAILQ_FIRST(&ps->ps_trace);
274
275 if (fpt->pt_status != done)
276 break;
277
278 TAILQ_REMOVE(&ps->ps_trace, fpt, pt_list);
279 ps->ps_tracecount--;
280 free(fpt);
281 }
282 }
283
284 if (pnd) {
285 pnd->pnd_flags &= ~PND_INXCHG;
286 (void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL);
287 }
288
289 return error;
290 }
291
292 static int
293 mode_access(opc, pcr, mode)
294 puffs_cookie_t opc;
295 const struct puffs_cred *pcr;
296 mode_t mode;
297 {
298 struct puffs_node *pn;
299 struct vattr *va;
300
301 /*
302 * pcr is NULL for self open through fsync or readdir.
303 * In both case, access control is useless, as it was
304 * done before, at open time.
305 */
306 if (pcr == NULL)
307 return 0;
308
309 pn = (struct puffs_node *)opc;
310 va = puffs_pn_getvap(pn);
311 return puffs_access(va->va_type, va->va_mode,
312 va->va_uid, va->va_gid,
313 mode, pcr);
314 }
315
316 static int
317 sticky_access(targ, pcr)
318 struct puffs_node *targ;
319 const struct puffs_cred *pcr;
320 {
321 uid_t uid;
322 struct puffs_node *tdir;
323 int sticky, owner;
324
325 tdir = PERFUSE_NODE_DATA(targ)->pnd_parent;
326
327 /*
328 * This covers the case where the kernel requests a DELETE
329 * or RENAME on its own, and where puffs_cred_getuid would
330 * return -1. While such a situation should not happen,
331 * we allow it here.
332 *
333 * This also allows root to tamper with other users' files
334 * that have the sticky bit.
335 */
336 if (puffs_cred_isjuggernaut(pcr))
337 return 0;
338
339 if (puffs_cred_getuid(pcr, &uid) != 0)
340 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__);
341
342 sticky = puffs_pn_getvap(tdir)->va_mode & S_ISTXT;
343 owner = puffs_pn_getvap(targ)->va_uid == uid;
344
345 if (sticky && !owner)
346 return EACCES;
347
348 return 0;
349 }
350
351
352 static void
353 fuse_attr_to_vap(ps, vap, fa)
354 struct perfuse_state *ps;
355 struct vattr *vap;
356 struct fuse_attr *fa;
357 {
358 vap->va_type = IFTOVT(fa->mode);
359 vap->va_mode = fa->mode & ALLPERMS;
360 vap->va_nlink = fa->nlink;
361 vap->va_uid = fa->uid;
362 vap->va_gid = fa->gid;
363 vap->va_fsid = (long)ps->ps_fsid;
364 vap->va_fileid = fa->ino;
365 vap->va_size = fa->size;
366 vap->va_blocksize = fa->blksize;
367 vap->va_atime.tv_sec = (time_t)fa->atime;
368 vap->va_atime.tv_nsec = (long) fa->atimensec;
369 vap->va_mtime.tv_sec = (time_t)fa->mtime;
370 vap->va_mtime.tv_nsec = (long)fa->mtimensec;
371 vap->va_ctime.tv_sec = (time_t)fa->ctime;
372 vap->va_ctime.tv_nsec = (long)fa->ctimensec;
373 vap->va_birthtime.tv_sec = 0;
374 vap->va_birthtime.tv_nsec = 0;
375 vap->va_gen = 0;
376 vap->va_flags = 0;
377 vap->va_rdev = fa->rdev;
378 vap->va_bytes = fa->size;
379 vap->va_filerev = (u_quad_t)PUFFS_VNOVAL;
380 vap->va_vaflags = 0;
381
382 if (vap->va_blocksize == 0)
383 vap->va_blocksize = DEV_BSIZE;
384
385 if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */
386 vap->va_size = 0;
387
388 return;
389 }
390
391 static void
392 set_expire(opc, feo, fao)
393 puffs_cookie_t opc;
394 struct fuse_entry_out *feo;
395 struct fuse_attr_out *fao;
396 {
397 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
398 struct timespec entry_ts;
399 struct timespec attr_ts;
400 struct timespec now;
401
402 if ((feo == NULL) && (fao == NULL))
403 DERRX(EX_SOFTWARE, "%s: feo and fao NULL", __func__);
404
405 if ((feo != NULL) && (fao != NULL))
406 DERRX(EX_SOFTWARE, "%s: feo and fao != NULL", __func__);
407
408 if (clock_gettime(CLOCK_REALTIME, &now) != 0)
409 DERR(EX_OSERR, "clock_gettime failed");
410
411 if (feo != NULL) {
412 entry_ts.tv_sec = (time_t)feo->entry_valid;
413 entry_ts.tv_nsec = (long)feo->entry_valid_nsec;
414
415 timespecadd(&now, &entry_ts, &pnd->pnd_entry_expire);
416
417 attr_ts.tv_sec = (time_t)feo->attr_valid;
418 attr_ts.tv_nsec = (long)feo->attr_valid_nsec;
419
420 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire);
421 }
422
423 if (fao != NULL) {
424 attr_ts.tv_sec = (time_t)fao->attr_valid;
425 attr_ts.tv_nsec = (long)fao->attr_valid_nsec;
426
427 timespecadd(&now, &attr_ts, &pnd->pnd_attr_expire);
428 }
429
430 return;
431 }
432
433 static int
434 attr_expired(opc)
435 puffs_cookie_t opc;
436 {
437 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
438 struct timespec now;
439
440 if (clock_gettime(CLOCK_REALTIME, &now) != 0)
441 DERR(EX_OSERR, "clock_gettime failed");
442
443 return timespeccmp(&pnd->pnd_attr_expire, &now, <);
444 }
445
446 static int
447 entry_expired(opc)
448 puffs_cookie_t opc;
449 {
450 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
451 struct timespec expire = pnd->pnd_entry_expire;
452 struct timespec now;
453
454 if (clock_gettime(CLOCK_REALTIME, &now) != 0)
455 DERR(EX_OSERR, "clock_gettime failed");
456
457 return timespeccmp(&expire, &now, <);
458 }
459
460
461 /*
462 * Lookup name in directory opc
463 * We take special care of name being . or ..
464 * These are returned by readdir and deserve tweaks.
465 */
466 static int
467 node_lookup_dir_nodot(pu, opc, name, namelen, pnp)
468 struct puffs_usermount *pu;
469 puffs_cookie_t opc;
470 char *name;
471 size_t namelen;
472 struct puffs_node **pnp;
473 {
474 /*
475 * "dot" is easy as we already know it
476 */
477 if (strncmp(name, ".", namelen) == 0) {
478 *pnp = (struct puffs_node *)opc;
479 return 0;
480 }
481
482 /*
483 * "dotdot" is also known
484 */
485 if (strncmp(name, "..", namelen) == 0) {
486 *pnp = PERFUSE_NODE_DATA(opc)->pnd_parent;
487 return 0;
488 }
489
490 return node_lookup_common(pu, opc, name, NULL, pnp);
491 }
492
493 static int
494 node_lookup_common(pu, opc, path, pcr, pnp)
495 struct puffs_usermount *pu;
496 puffs_cookie_t opc;
497 const char *path;
498 const struct puffs_cred *pcr;
499 struct puffs_node **pnp;
500 {
501 struct perfuse_state *ps;
502 struct perfuse_node_data *oldpnd;
503 perfuse_msg_t *pm;
504 struct fuse_entry_out *feo;
505 struct puffs_node *pn;
506 size_t len;
507 int error;
508
509 /*
510 * Prevent further lookups if the parent was removed
511 */
512 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
513 return ESTALE;
514
515 if (pnp == NULL)
516 DERRX(EX_SOFTWARE, "pnp must be != NULL");
517
518 ps = puffs_getspecific(pu);
519
520 #ifdef PERFUSE_DEBUG
521 if (perfuse_diagflags & PDF_FILENAME)
522 DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n",
523 __func__, (void *)opc, perfuse_node_path(opc), path);
524 #endif
525 /*
526 * Is the node already known?
527 */
528 TAILQ_FOREACH(oldpnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) {
529 if ((oldpnd->pnd_flags & PND_REMOVED) ||
530 (strcmp(oldpnd->pnd_name, path) != 0))
531 continue;
532
533 #ifdef PERFUSE_DEBUG
534 if (perfuse_diagflags & PDF_FILENAME)
535 DPRINTF("%s: opc = %p, file = \"%s\" found "
536 "cookie = %p, nodeid = 0x%"PRIx64" "
537 "for \"%s\"\n", __func__,
538 (void *)opc, perfuse_node_path(opc),
539 (void *)oldpnd->pnd_pn, oldpnd->pnd_nodeid,
540 path);
541 #endif
542 break;
543 }
544
545 /*
546 * Check for cached name
547 */
548 if ((oldpnd != NULL) && !entry_expired(oldpnd->pnd_pn)) {
549 *pnp = oldpnd->pnd_pn;
550 return 0;
551 }
552
553 len = strlen(path) + 1;
554
555 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, pcr);
556 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len);
557
558 error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply);
559
560 switch (error) {
561 case 0:
562 break;
563 case ENOENT:
564 if (oldpnd != NULL) {
565 oldpnd->pnd_flags |= PND_REMOVED;
566 #ifdef PERFUSE_DEBUG
567 if (perfuse_diagflags & PDF_FILENAME)
568 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" "
569 "file = \"%s\" removed\n", __func__,
570 oldpnd->pnd_pn, oldpnd->pnd_nodeid,
571 oldpnd->pnd_name);
572 #endif
573 }
574 /* FALLTHROUGH */
575 default:
576 return error;
577 /* NOTREACHED */
578 break;
579 }
580
581 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
582
583 if (oldpnd != NULL) {
584 if (oldpnd->pnd_nodeid == feo->nodeid) {
585 oldpnd->pnd_nlookup++;
586 *pnp = oldpnd->pnd_pn;
587
588 ps->ps_destroy_msg(pm);
589 return 0;
590 } else {
591 oldpnd->pnd_flags |= PND_REMOVED;
592 #ifdef PERFUSE_DEBUG
593 if (perfuse_diagflags & PDF_FILENAME)
594 DPRINTF("%s: opc = %p nodeid = 0x%"PRIx64" "
595 "file = \"%s\" replaced\n", __func__,
596 oldpnd->pnd_pn, oldpnd->pnd_nodeid,
597 oldpnd->pnd_name);
598 #endif
599 }
600 }
601
602 pn = perfuse_new_pn(pu, path, opc);
603 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
604
605 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
606 pn->pn_va.va_gen = (u_long)(feo->generation);
607 set_expire((puffs_cookie_t)pn, feo, NULL);
608
609 *pnp = pn;
610
611 #ifdef PERFUSE_DEBUG
612 if (perfuse_diagflags & PDF_FILENAME)
613 DPRINTF("%s: opc = %p, looked up opc = %p, "
614 "nodeid = 0x%"PRIx64" file = \"%s\"\n", __func__,
615 (void *)opc, pn, feo->nodeid, path);
616 #endif
617
618 ps->ps_destroy_msg(pm);
619
620 return 0;
621 }
622
623
624 /*
625 * Common code for methods that create objects:
626 * perfuse_node_mkdir
627 * perfuse_node_mknod
628 * perfuse_node_symlink
629 */
630 static int
631 node_mk_common(pu, opc, pni, pcn, pm)
632 struct puffs_usermount *pu;
633 puffs_cookie_t opc;
634 struct puffs_newinfo *pni;
635 const struct puffs_cn *pcn;
636 perfuse_msg_t *pm;
637 {
638 struct perfuse_state *ps;
639 struct puffs_node *pn;
640 struct fuse_entry_out *feo;
641 int error;
642
643 ps = puffs_getspecific(pu);
644
645 if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0)
646 return error;
647
648 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
649 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID)
650 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__);
651
652 pn = perfuse_new_pn(pu, pcn->pcn_name, opc);
653 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
654
655 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
656 pn->pn_va.va_gen = (u_long)(feo->generation);
657 set_expire((puffs_cookie_t)pn, feo, NULL);
658
659 puffs_newinfo_setcookie(pni, pn);
660
661 #ifdef PERFUSE_DEBUG
662 if (perfuse_diagflags & PDF_FILENAME)
663 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
664 "nodeid = 0x%"PRIx64"\n",
665 __func__, (void *)pn, pcn->pcn_name,
666 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid);
667 #endif
668 ps->ps_destroy_msg(pm);
669
670 return node_mk_common_final(pu, opc, pn, pcn);
671 }
672
673 /*
674 * Common final code for methods that create objects:
675 * perfuse_node_mkdir via node_mk_common
676 * perfuse_node_mknod via node_mk_common
677 * perfuse_node_symlink via node_mk_common
678 * perfuse_node_create
679 */
680 static int
681 node_mk_common_final(pu, opc, pn, pcn)
682 struct puffs_usermount *pu;
683 puffs_cookie_t opc;
684 struct puffs_node *pn;
685 const struct puffs_cn *pcn;
686 {
687 struct perfuse_state *ps;
688 perfuse_msg_t *pm;
689 struct fuse_setattr_in *fsi;
690 struct fuse_attr_out *fao;
691 int error;
692
693 ps = puffs_getspecific(pu);
694
695 /*
696 * Set owner and group. The kernel cannot create a file
697 * on its own (puffs_cred_getuid would return -1), right?
698 */
699 if (puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid) != 0)
700 DERRX(EX_SOFTWARE, "puffs_cred_getuid fails in %s", __func__);
701 if (puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid) != 0)
702 DERRX(EX_SOFTWARE, "puffs_cred_getgid fails in %s", __func__);
703
704 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn,
705 FUSE_SETATTR, sizeof(*fsi), pcn->pcn_cred);
706 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
707 fsi->uid = pn->pn_va.va_uid;
708 fsi->gid = pn->pn_va.va_gid;
709 fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID;
710
711 if ((error = xchg_msg(pu, (puffs_cookie_t)pn, pm,
712 sizeof(*fao), wait_reply)) != 0)
713 return error;
714
715 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
716 fuse_attr_to_vap(ps, &pn->pn_va, &fao->attr);
717 set_expire((puffs_cookie_t)pn, NULL, fao);
718
719 /*
720 * The parent directory needs a sync
721 */
722 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
723
724 ps->ps_destroy_msg(pm);
725
726 return 0;
727 }
728
729 static uint64_t
730 readdir_last_cookie(fd, fd_len)
731 struct fuse_dirent *fd;
732 size_t fd_len;
733 {
734 size_t len;
735 size_t seen = 0;
736 char *ndp;
737
738 do {
739 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
740 seen += len;
741
742 if (seen >= fd_len)
743 break;
744
745 ndp = (char *)(void *)fd + (size_t)len;
746 fd = (struct fuse_dirent *)(void *)ndp;
747 } while (1 /* CONSTCOND */);
748
749 return fd->off;
750 }
751
752 static ssize_t
753 fuse_to_dirent(pu, opc, fd, fd_len)
754 struct puffs_usermount *pu;
755 puffs_cookie_t opc;
756 struct fuse_dirent *fd;
757 size_t fd_len;
758 {
759 struct dirent *dents;
760 size_t dents_len;
761 ssize_t written;
762 uint64_t fd_offset;
763 struct fuse_dirent *fd_base;
764 size_t len;
765
766 fd_base = fd;
767 fd_offset = 0;
768 written = 0;
769 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
770 dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len;
771
772 do {
773 char *ndp;
774 size_t reclen;
775
776 reclen = _DIRENT_RECLEN(dents, fd->namelen);
777
778 /*
779 * Check we do not overflow the output buffer
780 * struct fuse_dirent is bigger than struct dirent,
781 * so we should always use fd_len and never reallocate
782 * later.
783 * If we have to reallocate,try to double the buffer
784 * each time so that we do not have to do it too often.
785 */
786 if (written + reclen > dents_len) {
787 if (dents_len == 0)
788 dents_len = fd_len;
789 else
790 dents_len =
791 MAX(2 * dents_len, written + reclen);
792
793 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
794 if ((dents = realloc(dents, dents_len)) == NULL)
795 DERR(EX_OSERR, "%s: malloc failed", __func__);
796
797 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents;
798 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len;
799
800 /*
801 * (void *) for delint
802 */
803 ndp = (char *)(void *)dents + written;
804 dents = (struct dirent *)(void *)ndp;
805 }
806
807 /*
808 * Filesystem was mounted without -o use_ino
809 * Perform a lookup to find it.
810 */
811 if (fd->ino == PERFUSE_UNKNOWN_INO) {
812 struct puffs_node *pn;
813
814 if (node_lookup_dir_nodot(pu, opc, fd->name,
815 fd->namelen, &pn) != 0) {
816 DWARNX("node_lookup_dir_nodot failed");
817 } else {
818 fd->ino = pn->pn_va.va_fileid;
819 }
820 }
821
822 dents->d_fileno = fd->ino;
823 dents->d_reclen = (unsigned short)reclen;
824 dents->d_namlen = fd->namelen;
825 dents->d_type = fd->type;
826 strlcpy(dents->d_name, fd->name, fd->namelen + 1);
827
828 #ifdef PERFUSE_DEBUG
829 if (perfuse_diagflags & PDF_READDIR)
830 DPRINTF("%s: translated \"%s\" ino = %"PRIu64"\n",
831 __func__, dents->d_name, dents->d_fileno);
832 #endif
833
834 dents = _DIRENT_NEXT(dents);
835 written += reclen;
836
837 /*
838 * Move to the next record.
839 * fd->off is not the offset, it is an opaque cookie
840 * given by the filesystem to keep state across multiple
841 * readdir() operation.
842 * Use record alignement instead.
843 */
844 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
845 #ifdef PERFUSE_DEBUG
846 if (perfuse_diagflags & PDF_READDIR)
847 DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" "
848 "length = %zd/0x%zx. "
849 "next record at %"PRId64"/0x%"PRIx64" "
850 "max %zd/0x%zx\n",
851 __func__, fd_offset, fd_offset, len, len,
852 fd_offset + len, fd_offset + len,
853 fd_len, fd_len);
854 #endif
855 fd_offset += len;
856
857 /*
858 * Check if next record is still within the packet
859 * If it is not, we reached the end of the buffer.
860 */
861 if (fd_offset >= fd_len)
862 break;
863
864 /*
865 * (void *) for delint
866 */
867 ndp = (char *)(void *)fd_base + (size_t)fd_offset;
868 fd = (struct fuse_dirent *)(void *)ndp;
869
870 } while (1 /* CONSTCOND */);
871
872 /*
873 * Adjust the dirent output length
874 */
875 if (written != -1)
876 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written;
877
878 return written;
879 }
880
881 static int
882 readdir_buffered(opc, dent, readoff, reslen)
883 puffs_cookie_t opc;
884 struct dirent *dent;
885 off_t *readoff;
886 size_t *reslen;
887 {
888 struct dirent *fromdent;
889 struct perfuse_node_data *pnd;
890 char *ndp;
891
892 pnd = PERFUSE_NODE_DATA(opc);
893
894 while (*readoff < pnd->pnd_dirent_len) {
895 /*
896 * (void *) for delint
897 */
898 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff;
899 fromdent = (struct dirent *)(void *)ndp;
900
901 if (*reslen < _DIRENT_SIZE(fromdent))
902 break;
903
904 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
905 *readoff += _DIRENT_SIZE(fromdent);
906 *reslen -= _DIRENT_SIZE(fromdent);
907
908 dent = _DIRENT_NEXT(dent);
909 }
910
911 #ifdef PERFUSE_DEBUG
912 if (perfuse_diagflags & PDF_READDIR)
913 DPRINTF("%s: readoff = %"PRId64", "
914 "pnd->pnd_dirent_len = %"PRId64"\n",
915 __func__, *readoff, pnd->pnd_dirent_len);
916 #endif
917 if (*readoff >= pnd->pnd_dirent_len) {
918 free(pnd->pnd_dirent);
919 pnd->pnd_dirent = NULL;
920 pnd->pnd_dirent_len = 0;
921 }
922
923 return 0;
924 }
925
926 static void
927 requeue_request(pu, opc, type)
928 struct puffs_usermount *pu;
929 puffs_cookie_t opc;
930 enum perfuse_qtype type;
931 {
932 struct perfuse_cc_queue pcq;
933 struct perfuse_node_data *pnd;
934 #ifdef PERFUSE_DEBUG
935 struct perfuse_state *ps;
936
937 ps = perfuse_getspecific(pu);
938 #endif
939
940 pnd = PERFUSE_NODE_DATA(opc);
941 pcq.pcq_type = type;
942 pcq.pcq_cc = puffs_cc_getcc(pu);
943 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next);
944
945 #ifdef PERFUSE_DEBUG
946 if (perfuse_diagflags & PDF_REQUEUE)
947 DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n",
948 __func__, (void *)opc, pcq.pcq_cc,
949 perfuse_qtypestr[type]);
950 #endif
951
952 puffs_cc_yield(pcq.pcq_cc);
953 TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next);
954
955 #ifdef PERFUSE_DEBUG
956 if (perfuse_diagflags & PDF_REQUEUE)
957 DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n",
958 __func__, (void *)opc, pcq.pcq_cc,
959 perfuse_qtypestr[type]);
960 #endif
961
962 return;
963 }
964
965 /* ARGSUSED0 */
966 static int
967 dequeue_requests(ps, opc, type, max)
968 struct perfuse_state *ps;
969 puffs_cookie_t opc;
970 enum perfuse_qtype type;
971 int max;
972 {
973 struct perfuse_cc_queue *pcq;
974 struct perfuse_node_data *pnd;
975 int dequeued;
976
977 pnd = PERFUSE_NODE_DATA(opc);
978 dequeued = 0;
979 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) {
980 if (pcq->pcq_type != type)
981 continue;
982
983 #ifdef PERFUSE_DEBUG
984 if (perfuse_diagflags & PDF_REQUEUE)
985 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n",
986 __func__, (void *)opc, pcq->pcq_cc,
987 perfuse_qtypestr[type]);
988 #endif
989 puffs_cc_schedule(pcq->pcq_cc);
990
991 if (++dequeued == max)
992 break;
993 }
994
995 #ifdef PERFUSE_DEBUG
996 if (perfuse_diagflags & PDF_REQUEUE)
997 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc);
998 #endif
999
1000 return dequeued;
1001 }
1002
1003 void
1004 perfuse_fs_init(pu)
1005 struct puffs_usermount *pu;
1006 {
1007 struct perfuse_state *ps;
1008 perfuse_msg_t *pm;
1009 struct fuse_init_in *fii;
1010 struct fuse_init_out *fio;
1011 int error;
1012
1013 ps = puffs_getspecific(pu);
1014
1015 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0)
1016 DERR(EX_OSERR, "%s: puffs_mount failed", __func__);
1017
1018 /*
1019 * Linux 2.6.34.1 sends theses flags:
1020 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC
1021 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK
1022 *
1023 * Linux also sets max_readahead at 32 pages (128 kB)
1024 *
1025 * ps_new_msg() is called with NULL creds, which will
1026 * be interpreted as FUSE superuser.
1027 */
1028 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL);
1029 fii = GET_INPAYLOAD(ps, pm, fuse_init_in);
1030 fii->major = FUSE_KERNEL_VERSION;
1031 fii->minor = FUSE_KERNEL_MINOR_VERSION;
1032 fii->max_readahead = (unsigned int)(32 * sysconf(_SC_PAGESIZE));
1033 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC);
1034
1035 if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0)
1036 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error);
1037
1038 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out);
1039 ps->ps_max_readahead = fio->max_readahead;
1040 ps->ps_max_write = fio->max_write;
1041
1042 ps->ps_destroy_msg(pm);
1043
1044 return;
1045 }
1046
1047 int
1048 perfuse_fs_unmount(pu, flags)
1049 struct puffs_usermount *pu;
1050 int flags;
1051 {
1052 perfuse_msg_t *pm;
1053 struct perfuse_state *ps;
1054 puffs_cookie_t opc;
1055 int error;
1056
1057 ps = puffs_getspecific(pu);
1058 opc = (puffs_cookie_t)puffs_getroot(pu);
1059
1060 /*
1061 * ps_new_msg() is called with NULL creds, which will
1062 * be interpreted as FUSE superuser.
1063 */
1064 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL);
1065
1066 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){
1067 DWARN("unmount %s", ps->ps_target);
1068 if (!(flags & MNT_FORCE))
1069 return error;
1070 else
1071 error = 0;
1072 } else {
1073 ps->ps_destroy_msg(pm);
1074 }
1075
1076 ps->ps_umount(pu);
1077
1078 if (perfuse_diagflags & PDF_MISC)
1079 DPRINTF("%s unmounted, exit\n", ps->ps_target);
1080
1081 return 0;
1082 }
1083
1084 int
1085 perfuse_fs_statvfs(pu, svfsb)
1086 struct puffs_usermount *pu;
1087 struct statvfs *svfsb;
1088 {
1089 struct perfuse_state *ps;
1090 perfuse_msg_t *pm;
1091 puffs_cookie_t opc;
1092 struct fuse_statfs_out *fso;
1093 int error;
1094
1095 ps = puffs_getspecific(pu);
1096 opc = (puffs_cookie_t)puffs_getroot(pu);
1097
1098 /*
1099 * ps_new_msg() is called with NULL creds, which will
1100 * be interpreted as FUSE superuser.
1101 */
1102 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
1103
1104 if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0)
1105 return error;
1106
1107 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
1108 svfsb->f_flag = ps->ps_mountflags;
1109 svfsb->f_bsize = fso->st.bsize;
1110 svfsb->f_frsize = fso->st.frsize;
1111 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize;
1112 svfsb->f_blocks = fso->st.blocks;
1113 svfsb->f_bfree = fso->st.bfree;
1114 svfsb->f_bavail = fso->st.bavail;
1115 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail;
1116 svfsb->f_files = fso->st.files;
1117 svfsb->f_ffree = fso->st.ffree;
1118 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */
1119 svfsb->f_fresvd = 0; /* files reserved for root */
1120
1121 svfsb->f_syncreads = ps->ps_syncreads;
1122 svfsb->f_syncwrites = ps->ps_syncwrites;
1123
1124 svfsb->f_asyncreads = ps->ps_asyncreads;
1125 svfsb->f_asyncwrites = ps->ps_asyncwrites;
1126
1127 (void)memcpy(&svfsb->f_fsidx, &ps->ps_fsid, sizeof(ps->ps_fsid));
1128 svfsb->f_fsid = (unsigned long)ps->ps_fsid;
1129 svfsb->f_namemax = MAXPATHLEN; /* XXX */
1130 svfsb->f_owner = ps->ps_owner_uid;
1131
1132 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN);
1133
1134 if (ps->ps_filesystemtype != NULL)
1135 (void)strlcpy(svfsb->f_fstypename,
1136 ps->ps_filesystemtype, _VFS_NAMELEN);
1137 else
1138 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN);
1139
1140 if (ps->ps_source != NULL)
1141 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN);
1142 else
1143 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN);
1144
1145 ps->ps_destroy_msg(pm);
1146
1147 return 0;
1148 }
1149
1150 int
1151 perfuse_fs_sync(pu, waitfor, pcr)
1152 struct puffs_usermount *pu;
1153 int waitfor;
1154 const struct puffs_cred *pcr;
1155 {
1156 /*
1157 * FUSE does not seem to have a FS sync callback.
1158 * Maybe do not even register this callback
1159 */
1160 return puffs_fsnop_sync(pu, waitfor, pcr);
1161 }
1162
1163 /* ARGSUSED0 */
1164 int
1165 perfuse_fs_fhtonode(pu, fid, fidsize, pni)
1166 struct puffs_usermount *pu;
1167 void *fid;
1168 size_t fidsize;
1169 struct puffs_newinfo *pni;
1170 {
1171 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1172 return 0;
1173 }
1174
1175 /* ARGSUSED0 */
1176 int
1177 perfuse_fs_nodetofh(pu, cookie, fid, fidsize)
1178 struct puffs_usermount *pu;
1179 puffs_cookie_t cookie;
1180 void *fid;
1181 size_t *fidsize;
1182 {
1183 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1184 return 0;
1185 }
1186
1187 #if 0
1188 /* ARGSUSED0 */
1189 void
1190 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname)
1191 struct puffs_usermount *pu;
1192 int cmd,
1193 puffs_cookie_t *cookie;
1194 int flags;
1195 int namespace;
1196 const char *attrname;
1197 {
1198 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
1199 return 0;
1200 }
1201 #endif /* 0 */
1202
1203 /* ARGSUSED0 */
1204 void
1205 perfuse_fs_suspend(pu, status)
1206 struct puffs_usermount *pu;
1207 int status;
1208 {
1209 return;
1210 }
1211
1212
1213
1214 int
1215 perfuse_node_lookup(pu, opc, pni, pcn)
1216 struct puffs_usermount *pu;
1217 puffs_cookie_t opc;
1218 struct puffs_newinfo *pni;
1219 const struct puffs_cn *pcn;
1220 {
1221 struct puffs_node *pn;
1222 mode_t mode;
1223 int error;
1224
1225 /*
1226 * Check permissions
1227 */
1228 switch(pcn->pcn_nameiop) {
1229 case NAMEI_DELETE: /* FALLTHROUGH */
1230 case NAMEI_RENAME: /* FALLTHROUGH */
1231 case NAMEI_CREATE:
1232 if (pcn->pcn_flags & NAMEI_ISLASTCN)
1233 mode = PUFFS_VEXEC|PUFFS_VWRITE;
1234 else
1235 mode = PUFFS_VEXEC;
1236 break;
1237 case NAMEI_LOOKUP: /* FALLTHROUGH */
1238 default:
1239 mode = PUFFS_VEXEC;
1240 break;
1241 }
1242
1243 if ((error = mode_access(opc, pcn->pcn_cred, mode)) != 0)
1244 return error;
1245
1246 /*
1247 * Special case for ..
1248 */
1249 if (strcmp(pcn->pcn_name, "..") == 0)
1250 pn = PERFUSE_NODE_DATA(opc)->pnd_parent;
1251 else
1252 error = node_lookup_common(pu, (puffs_cookie_t)opc,
1253 pcn->pcn_name, pcn->pcn_cred, &pn);
1254 if (error != 0)
1255 return error;
1256
1257 /*
1258 * Kernel would kill us if the filesystem returned the parent
1259 * itself. If we want to live, hide that!
1260 */
1261 if ((opc == (puffs_cookie_t)pn) && (strcmp(pcn->pcn_name, ".") != 0)) {
1262 DWARNX("lookup returned parent");
1263 return ESTALE;
1264 }
1265
1266 /*
1267 * Removed node
1268 */
1269 if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED)
1270 return ENOENT;
1271
1272 /*
1273 * Check for sticky bit. Unfortunately there is no way to
1274 * do this before creating the puffs_node, since we require
1275 * this operation to get the node owner.
1276 */
1277 switch (pcn->pcn_nameiop) {
1278 case NAMEI_DELETE: /* FALLTHROUGH */
1279 case NAMEI_RENAME:
1280 error = sticky_access(pn, pcn->pcn_cred);
1281 if (error != 0) {
1282 /*
1283 * kernel will never know about it and will
1284 * not reclaim it. The filesystem needs to
1285 * clean it up anyway, therefore mimick a forget.
1286 */
1287 PERFUSE_NODE_DATA(pn)->pnd_flags |= PND_RECLAIMED;
1288 (void)perfuse_node_reclaim(pu, (puffs_cookie_t)pn);
1289 return error;
1290 }
1291 break;
1292 default:
1293 break;
1294 }
1295
1296 /*
1297 * If that node had a pending reclaim, wipe it out.
1298 */
1299 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
1300
1301 puffs_newinfo_setcookie(pni, pn);
1302 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
1303 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size);
1304 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev);
1305
1306 return error;
1307 }
1308
1309 int
1310 perfuse_node_create(pu, opc, pni, pcn, vap)
1311 struct puffs_usermount *pu;
1312 puffs_cookie_t opc;
1313 struct puffs_newinfo *pni;
1314 const struct puffs_cn *pcn;
1315 const struct vattr *vap;
1316 {
1317 perfuse_msg_t *pm;
1318 struct perfuse_state *ps;
1319 struct fuse_create_in *fci;
1320 struct fuse_entry_out *feo;
1321 struct fuse_open_out *foo;
1322 struct puffs_node *pn;
1323 const char *name;
1324 size_t namelen;
1325 size_t len;
1326 int error;
1327
1328 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1329 return ENOENT;
1330
1331 /*
1332 * If create is unimplemented: Check that it does not
1333 * already exists, and if not, do mknod and open
1334 */
1335 ps = puffs_getspecific(pu);
1336 if (ps->ps_flags & PS_NO_CREAT) {
1337 error = node_lookup_common(pu, opc, pcn->pcn_name,
1338 pcn->pcn_cred, &pn);
1339 if (error == 0)
1340 return EEXIST;
1341
1342 error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
1343 if (error != 0)
1344 return error;
1345
1346 error = node_lookup_common(pu, opc, pcn->pcn_name,
1347 pcn->pcn_cred, &pn);
1348 if (error != 0)
1349 return error;
1350
1351 /*
1352 * FUSE does the open at create time, while
1353 * NetBSD will open in a subsequent operation.
1354 * We need to open now, in order to retain FUSE
1355 * semantics. The calling process will not get
1356 * a file descriptor before the kernel sends
1357 * the open operation.
1358 */
1359 opc = (puffs_cookie_t)pn;
1360 error = perfuse_node_open(pu, opc, FWRITE, pcn->pcn_cred);
1361 if (error != 0)
1362 return error;
1363
1364 return 0;
1365 }
1366
1367 name = pcn->pcn_name;
1368 namelen = pcn->pcn_namelen + 1;
1369 len = sizeof(*fci) + namelen;
1370
1371 /*
1372 * flags should use O_WRONLY instead of O_RDWR, but it
1373 * breaks when the caller tries to read from file.
1374 *
1375 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1376 */
1377 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, pcn->pcn_cred);
1378 fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
1379 fci->flags = O_CREAT | O_TRUNC | O_RDWR;
1380 fci->mode = vap->va_mode | VTTOIF(vap->va_type);
1381 fci->umask = 0; /* Seems unused by libfuse */
1382 (void)strlcpy((char*)(void *)(fci + 1), name, namelen);
1383
1384 len = sizeof(*feo) + sizeof(*foo);
1385 if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0) {
1386 /*
1387 * create is unimplmented, remember it for later,
1388 * and start over using mknod and open instead.
1389 */
1390 if (error == ENOSYS) {
1391 ps->ps_flags |= PS_NO_CREAT;
1392 return perfuse_node_create(pu, opc, pni, pcn, vap);
1393 }
1394
1395 return error;
1396 }
1397
1398 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
1399 foo = (struct fuse_open_out *)(void *)(feo + 1);
1400 if (feo->nodeid == PERFUSE_UNKNOWN_NODEID)
1401 DERRX(EX_SOFTWARE, "%s: no nodeid", __func__);
1402
1403 /*
1404 * Save the file handle and inode in node private data
1405 * so that we can reuse it later
1406 */
1407 pn = perfuse_new_pn(pu, name, opc);
1408 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE);
1409 PERFUSE_NODE_DATA(pn)->pnd_nodeid = feo->nodeid;
1410
1411 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
1412 pn->pn_va.va_gen = (u_long)(feo->generation);
1413 set_expire((puffs_cookie_t)pn, feo, NULL);
1414
1415 puffs_newinfo_setcookie(pni, pn);
1416
1417 #ifdef PERFUSE_DEBUG
1418 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1419 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
1420 "nodeid = 0x%"PRIx64", wfh = 0x%"PRIx64"\n",
1421 __func__, (void *)pn, pcn->pcn_name,
1422 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid,
1423 foo->fh);
1424 #endif
1425
1426 ps->ps_destroy_msg(pm);
1427
1428 return node_mk_common_final(pu, opc, pn, pcn);
1429 }
1430
1431
1432 int
1433 perfuse_node_mknod(pu, opc, pni, pcn, vap)
1434 struct puffs_usermount *pu;
1435 puffs_cookie_t opc;
1436 struct puffs_newinfo *pni;
1437 const struct puffs_cn *pcn;
1438 const struct vattr *vap;
1439 {
1440 struct perfuse_state *ps;
1441 perfuse_msg_t *pm;
1442 struct fuse_mknod_in *fmi;
1443 const char* path;
1444 size_t len;
1445
1446 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1447 return ENOENT;
1448
1449 /*
1450 * Only superuser can mknod objects other than
1451 * directories, files, socks, fifo and links.
1452 *
1453 * Create an object require -WX permission in the parent directory
1454 */
1455 switch (vap->va_type) {
1456 case VDIR: /* FALLTHROUGH */
1457 case VREG: /* FALLTHROUGH */
1458 case VFIFO: /* FALLTHROUGH */
1459 case VSOCK:
1460 break;
1461 default: /* VNON, VBLK, VCHR, VBAD */
1462 if (!puffs_cred_isjuggernaut(pcn->pcn_cred))
1463 return EACCES;
1464 break;
1465 }
1466
1467
1468 ps = puffs_getspecific(pu);
1469 path = pcn->pcn_name;
1470 len = sizeof(*fmi) + pcn->pcn_namelen + 1;
1471
1472 /*
1473 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1474 */
1475 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, pcn->pcn_cred);
1476 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in);
1477 fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
1478 fmi->rdev = (uint32_t)vap->va_rdev;
1479 fmi->umask = 0; /* Seems unused bu libfuse */
1480 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
1481
1482 return node_mk_common(pu, opc, pni, pcn, pm);
1483 }
1484
1485
1486 int
1487 perfuse_node_open(pu, opc, mode, pcr)
1488 struct puffs_usermount *pu;
1489 puffs_cookie_t opc;
1490 int mode;
1491 const struct puffs_cred *pcr;
1492 {
1493 struct perfuse_state *ps;
1494 struct perfuse_node_data *pnd;
1495 perfuse_msg_t *pm;
1496 mode_t fmode;
1497 int op;
1498 struct fuse_open_in *foi;
1499 struct fuse_open_out *foo;
1500 struct puffs_node *pn;
1501 int error;
1502
1503 ps = puffs_getspecific(pu);
1504 pn = (struct puffs_node *)opc;
1505 pnd = PERFUSE_NODE_DATA(opc);
1506 error = 0;
1507
1508 if (pnd->pnd_flags & PND_REMOVED)
1509 return ENOENT;
1510
1511 if (puffs_pn_getvap(pn)->va_type == VDIR)
1512 op = FUSE_OPENDIR;
1513 else
1514 op = FUSE_OPEN;
1515
1516 /*
1517 * libfuse docs says
1518 * - O_CREAT and O_EXCL should never be set.
1519 * - O_TRUNC may be used if mount option atomic_o_trunc is used XXX
1520 *
1521 * O_APPEND makes no sense since FUSE always sends
1522 * the file offset for write operations. If the
1523 * filesystem uses pwrite(), O_APPEND would cause
1524 * the offset to be ignored and cause file corruption.
1525 */
1526 mode &= ~(O_CREAT|O_EXCL|O_APPEND);
1527
1528 /*
1529 * Do not open twice, and do not reopen for reading
1530 * if we already have write handle.
1531 */
1532 if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) ||
1533 ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) ||
1534 ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH)))
1535 goto out;
1536
1537 /*
1538 * Queue open on a node so that we do not open
1539 * twice. This would be better with read and
1540 * write distinguished.
1541 */
1542 while (pnd->pnd_flags & PND_INOPEN)
1543 requeue_request(pu, opc, PCQ_OPEN);
1544 pnd->pnd_flags |= PND_INOPEN;
1545
1546 /*
1547 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE
1548 * to O_RDONLY/O_WRONLY while perserving the other options.
1549 */
1550 fmode = mode & ~(FREAD|FWRITE);
1551 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY;
1552
1553 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
1554 foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
1555 foi->flags = fmode;
1556 foi->unused = 0;
1557
1558 if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0)
1559 goto out;
1560
1561 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
1562
1563 /*
1564 * Save the file handle in node private data
1565 * so that we can reuse it later
1566 */
1567 perfuse_new_fh(opc, foo->fh, mode);
1568
1569 #ifdef PERFUSE_DEBUG
1570 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1571 DPRINTF("%s: opc = %p, file = \"%s\", "
1572 "nodeid = 0x%"PRIx64", %s%sfh = 0x%"PRIx64"\n",
1573 __func__, (void *)opc, perfuse_node_path(opc),
1574 pnd->pnd_nodeid, mode & FREAD ? "r" : "",
1575 mode & FWRITE ? "w" : "", foo->fh);
1576 #endif
1577
1578 ps->ps_destroy_msg(pm);
1579 out:
1580
1581 pnd->pnd_flags &= ~PND_INOPEN;
1582 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
1583
1584 return error;
1585 }
1586
1587 /* ARGSUSED0 */
1588 int
1589 perfuse_node_close(pu, opc, flags, pcr)
1590 struct puffs_usermount *pu;
1591 puffs_cookie_t opc;
1592 int flags;
1593 const struct puffs_cred *pcr;
1594 {
1595 struct perfuse_node_data *pnd;
1596
1597 pnd = PERFUSE_NODE_DATA(opc);
1598
1599 if (!(pnd->pnd_flags & PND_OPEN))
1600 return EBADF;
1601
1602 /*
1603 * Actual close is postponed at inactive time.
1604 */
1605 return 0;
1606 }
1607
1608 int
1609 perfuse_node_access(pu, opc, mode, pcr)
1610 struct puffs_usermount *pu;
1611 puffs_cookie_t opc;
1612 int mode;
1613 const struct puffs_cred *pcr;
1614 {
1615 perfuse_msg_t *pm;
1616 struct perfuse_state *ps;
1617 struct fuse_access_in *fai;
1618 int error;
1619
1620 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1621 return ENOENT;
1622
1623 /*
1624 * If we previously detected the filesystem does not
1625 * implement access(), short-circuit the call and skip
1626 * to libpuffs access() emulation.
1627 */
1628 ps = puffs_getspecific(pu);
1629 if (ps->ps_flags & PS_NO_ACCESS) {
1630 const struct vattr *vap;
1631
1632 vap = puffs_pn_getvap((struct puffs_node *)opc);
1633
1634 error = puffs_access(IFTOVT(vap->va_mode),
1635 vap->va_mode & ACCESSPERMS,
1636 vap->va_uid, vap->va_gid,
1637 (mode_t)mode, pcr);
1638 return error;
1639 }
1640
1641 /*
1642 * Plain access call
1643 */
1644 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr);
1645 fai = GET_INPAYLOAD(ps, pm, fuse_access_in);
1646 fai->mask = 0;
1647 fai->mask |= (mode & PUFFS_VREAD) ? R_OK : 0;
1648 fai->mask |= (mode & PUFFS_VWRITE) ? W_OK : 0;
1649 fai->mask |= (mode & PUFFS_VEXEC) ? X_OK : 0;
1650
1651 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
1652
1653 ps->ps_destroy_msg(pm);
1654
1655 /*
1656 * If unimplemented, start over with emulation
1657 */
1658 if (error == ENOSYS) {
1659 ps->ps_flags |= PS_NO_ACCESS;
1660 return perfuse_node_access(pu, opc, mode, pcr);
1661 }
1662
1663 return error;
1664 }
1665
1666 int
1667 perfuse_node_getattr(pu, opc, vap, pcr)
1668 struct puffs_usermount *pu;
1669 puffs_cookie_t opc;
1670 struct vattr *vap;
1671 const struct puffs_cred *pcr;
1672 {
1673 perfuse_msg_t *pm = NULL;
1674 struct perfuse_state *ps;
1675 struct perfuse_node_data *pnd = PERFUSE_NODE_DATA(opc);
1676 struct fuse_getattr_in *fgi;
1677 struct fuse_attr_out *fao;
1678 int error = 0;
1679
1680 if (pnd->pnd_flags & PND_REMOVED)
1681 return ENOENT;
1682
1683 /*
1684 * Serialize size access, see comment in perfuse_node_setattr().
1685 */
1686 while (pnd->pnd_flags & PND_INRESIZE)
1687 requeue_request(pu, opc, PCQ_RESIZE);
1688 pnd->pnd_flags |= PND_INRESIZE;
1689
1690 ps = puffs_getspecific(pu);
1691
1692 /*
1693 * Check for cached attributes
1694 * This still require serialized access to size.
1695 */
1696 if (!attr_expired(opc)) {
1697 (void)memcpy(vap, puffs_pn_getvap((struct puffs_node *)opc),
1698 sizeof(*vap));
1699 goto out;
1700 }
1701
1702 /*
1703 * FUSE_GETATTR_FH must be set in fgi->flags
1704 * if we use for fgi->fh
1705 */
1706 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
1707 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1708 fgi->getattr_flags = 0;
1709 fgi->dummy = 0;
1710 fgi->fh = 0;
1711
1712 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) {
1713 fgi->fh = perfuse_get_fh(opc, FREAD);
1714 fgi->getattr_flags |= FUSE_GETATTR_FH;
1715 }
1716
1717 #ifdef PERFUSE_DEBUG
1718 if (perfuse_diagflags & PDF_RESIZE)
1719 DPRINTF(">> %s %p %" PRIu64 "\n", __func__, (void *)opc,
1720 vap->va_size);
1721 #endif
1722
1723 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1724 goto out;
1725
1726 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1727
1728 #ifdef PERFUSE_DEBUG
1729 if (perfuse_diagflags & PDF_RESIZE)
1730 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1731 (void *)opc, vap->va_size, fao->attr.size);
1732 #endif
1733
1734 /*
1735 * We set birthtime, flags, filerev,vaflags to 0.
1736 * This seems the best bet, since the information is
1737 * not available from filesystem.
1738 */
1739 fuse_attr_to_vap(ps, vap, &fao->attr);
1740 set_expire(opc, NULL, fao);
1741
1742 ps->ps_destroy_msg(pm);
1743 out:
1744
1745 pnd->pnd_flags &= ~PND_INRESIZE;
1746 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
1747
1748 return error;
1749 }
1750
1751 int
1752 perfuse_node_setattr(pu, opc, vap, pcr)
1753 struct puffs_usermount *pu;
1754 puffs_cookie_t opc;
1755 const struct vattr *vap;
1756 const struct puffs_cred *pcr;
1757 {
1758 perfuse_msg_t *pm;
1759 uint64_t fh;
1760 struct perfuse_state *ps;
1761 struct perfuse_node_data *pnd;
1762 struct fuse_setattr_in *fsi;
1763 struct fuse_attr_out *fao;
1764 struct vattr *old_va;
1765 int error;
1766 #ifdef PERFUSE_DEBUG
1767 struct vattr *old_vap;
1768 int resize_debug = 0;
1769 #endif
1770
1771 ps = puffs_getspecific(pu);
1772 pnd = PERFUSE_NODE_DATA(opc);
1773
1774 /*
1775 * The only operation we can do once the file is removed
1776 * is to resize it, and we can do it only if it is open.
1777 * Do not even send the operation to the filesystem: the
1778 * file is not there anymore.
1779 */
1780 if (pnd->pnd_flags & PND_REMOVED) {
1781 if (!(pnd->pnd_flags & PND_OPEN))
1782 return ENOENT;
1783
1784 error = 0;
1785 goto out;
1786 }
1787
1788 old_va = puffs_pn_getvap((struct puffs_node *)opc);
1789
1790 /*
1791 * Check for permission to change size
1792 */
1793 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1794 (error = mode_access(opc, pcr, PUFFS_VWRITE)) != 0)
1795 return error;
1796
1797 /*
1798 * Check for permission to change dates
1799 */
1800 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1801 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
1802 (puffs_access_times(old_va->va_uid, old_va->va_gid,
1803 old_va->va_mode, 0, pcr) != 0))
1804 return EACCES;
1805
1806 /*
1807 * Check for permission to change owner and group
1808 */
1809 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
1810 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
1811 (puffs_access_chown(old_va->va_uid, old_va->va_gid,
1812 vap->va_uid, vap->va_gid, pcr)) != 0)
1813 return EACCES;
1814
1815 /*
1816 * Check for permission to change permissions
1817 */
1818 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
1819 (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
1820 old_va->va_type, vap->va_mode, pcr)) != 0)
1821 return EACCES;
1822
1823 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
1824 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
1825 fsi->valid = 0;
1826
1827 /*
1828 * Get a fh if the node is open for writing
1829 */
1830 if (pnd->pnd_flags & PND_WFH) {
1831 fh = perfuse_get_fh(opc, FWRITE);
1832 fsi->fh = fh;
1833 fsi->valid |= FUSE_FATTR_FH;
1834 }
1835
1836 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
1837 fsi->size = vap->va_size;
1838 fsi->valid |= FUSE_FATTR_SIZE;
1839
1840 /*
1841 * Serialize anything that can touch file size
1842 * to avoid reordered GETATTR and SETATTR.
1843 * Out of order SETATTR can report stale size,
1844 * which will cause the kernel to truncate the file.
1845 */
1846 while (pnd->pnd_flags & PND_INRESIZE)
1847 requeue_request(pu, opc, PCQ_RESIZE);
1848 pnd->pnd_flags |= PND_INRESIZE;
1849 }
1850
1851 /*
1852 * Setting mtime without atime or vice versa leads to
1853 * dates being reset to Epoch on glusterfs. If one
1854 * is missing, use the old value.
1855 */
1856 if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1857 (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) {
1858
1859 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
1860 fsi->atime = vap->va_atime.tv_sec;
1861 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;
1862 } else {
1863 fsi->atime = old_va->va_atime.tv_sec;
1864 fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec;
1865 }
1866
1867 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
1868 fsi->mtime = vap->va_mtime.tv_sec;
1869 fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;
1870 } else {
1871 fsi->mtime = old_va->va_mtime.tv_sec;
1872 fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec;
1873 }
1874
1875 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME);
1876 }
1877
1878 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
1879 fsi->mode = vap->va_mode;
1880 fsi->valid |= FUSE_FATTR_MODE;
1881 }
1882
1883 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
1884 fsi->uid = vap->va_uid;
1885 fsi->valid |= FUSE_FATTR_UID;
1886 }
1887
1888 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
1889 fsi->gid = vap->va_gid;
1890 fsi->valid |= FUSE_FATTR_GID;
1891 }
1892
1893 if (pnd->pnd_lock_owner != 0) {
1894 fsi->lock_owner = pnd->pnd_lock_owner;
1895 fsi->valid |= FUSE_FATTR_LOCKOWNER;
1896 }
1897
1898 /*
1899 * ftruncate() sends only va_size, and metadata cache
1900 * flush adds va_atime and va_mtime. Some FUSE
1901 * filesystems will attempt to detect ftruncate by
1902 * checking for FATTR_SIZE being set without
1903 * FATTR_UID|FATTR_GID|FATTR_ATIME|FATTR_MTIME|FATTR_MODE
1904 *
1905 * Try to adapt and remove FATTR_ATIME|FATTR_MTIME
1906 * if we suspect a ftruncate().
1907 */
1908 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1909 ((vap->va_mode == (mode_t)PUFFS_VNOVAL) &&
1910 (vap->va_uid == (uid_t)PUFFS_VNOVAL) &&
1911 (vap->va_gid == (gid_t)PUFFS_VNOVAL))) {
1912 fsi->atime = 0;
1913 fsi->atimensec = 0;
1914 fsi->mtime = 0;
1915 fsi->mtimensec = 0;
1916 fsi->valid &= ~(FUSE_FATTR_ATIME|FUSE_FATTR_MTIME);
1917 }
1918
1919 /*
1920 * If nothing remain, discard the operation.
1921 */
1922 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
1923 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
1924 error = 0;
1925 goto out;
1926 }
1927
1928 #ifdef PERFUSE_DEBUG
1929 old_vap = puffs_pn_getvap((struct puffs_node *)opc);
1930
1931 if ((perfuse_diagflags & PDF_RESIZE) &&
1932 (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) {
1933 resize_debug = 1;
1934
1935 DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1936 (void *)opc,
1937 puffs_pn_getvap((struct puffs_node *)opc)->va_size,
1938 fsi->size);
1939 }
1940 #endif
1941
1942 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1943 goto out;
1944
1945 /*
1946 * Copy back the new values
1947 */
1948 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1949
1950 #ifdef PERFUSE_DEBUG
1951 if (resize_debug)
1952 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1953 (void *)opc, old_vap->va_size, fao->attr.size);
1954 #endif
1955
1956 fuse_attr_to_vap(ps, old_va, &fao->attr);
1957 set_expire(opc, NULL, fao);
1958
1959 ps->ps_destroy_msg(pm);
1960
1961 out:
1962 if (pnd->pnd_flags & PND_INRESIZE) {
1963 pnd->pnd_flags &= ~PND_INRESIZE;
1964 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
1965 }
1966
1967 return error;
1968 }
1969
1970 int
1971 perfuse_node_poll(pu, opc, events)
1972 struct puffs_usermount *pu;
1973 puffs_cookie_t opc;
1974 int *events;
1975 {
1976 struct perfuse_state *ps;
1977 perfuse_msg_t *pm;
1978 struct fuse_poll_in *fpi;
1979 struct fuse_poll_out *fpo;
1980 int error;
1981
1982 ps = puffs_getspecific(pu);
1983 /*
1984 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1985 *
1986 * XXX ps_new_msg() is called with NULL creds, which will
1987 * be interpreted as FUSE superuser. We have no way to
1988 * know the requesting process' credential, but since poll
1989 * is supposed to operate on a file that has been open,
1990 * permission should have already been checked at open time.
1991 * That still may breaks on filesystems that provides odd
1992 * semantics.
1993 */
1994 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1995 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1996 fpi->fh = perfuse_get_fh(opc, FREAD);
1997 fpi->kh = 0;
1998 fpi->flags = 0;
1999
2000 #ifdef PERFUSE_DEBUG
2001 if (perfuse_diagflags & PDF_FH)
2002 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
2003 "fh = 0x%"PRIx64"\n", __func__, (void *)opc,
2004 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh);
2005 #endif
2006 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0)
2007 return error;
2008
2009 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
2010 *events = fpo->revents;
2011
2012 ps->ps_destroy_msg(pm);
2013
2014 return 0;
2015 }
2016
2017 /* ARGSUSED0 */
2018 int
2019 perfuse_node_mmap(pu, opc, flags, pcr)
2020 struct puffs_usermount *pu;
2021 puffs_cookie_t opc;
2022 int flags;
2023 const struct puffs_cred *pcr;
2024 {
2025 /*
2026 * Not implemented anymore in libfuse
2027 */
2028 return ENOSYS;
2029 }
2030
2031 /* ARGSUSED2 */
2032 int
2033 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi)
2034 struct puffs_usermount *pu;
2035 puffs_cookie_t opc;
2036 const struct puffs_cred *pcr;
2037 int flags;
2038 off_t offlo;
2039 off_t offhi;
2040 {
2041 int op;
2042 perfuse_msg_t *pm;
2043 struct perfuse_state *ps;
2044 struct perfuse_node_data *pnd;
2045 struct fuse_fsync_in *ffi;
2046 uint64_t fh;
2047 int error;
2048
2049 pm = NULL;
2050 ps = puffs_getspecific(pu);
2051 pnd = PERFUSE_NODE_DATA(opc);
2052
2053 /*
2054 * No need to sync a removed node
2055 */
2056 if (pnd->pnd_flags & PND_REMOVED)
2057 return 0;
2058
2059 /*
2060 * We do not sync closed files. They have been
2061 * sync at inactive time already.
2062 */
2063 if (!(pnd->pnd_flags & PND_OPEN))
2064 return 0;
2065
2066 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
2067 op = FUSE_FSYNCDIR;
2068 else /* VREG but also other types such as VLNK */
2069 op = FUSE_FSYNC;
2070
2071 /*
2072 * Do not sync if there are no change to sync
2073 * XXX remove that test on files if we implement mmap
2074 */
2075 #ifdef PERFUSE_DEBUG
2076 if (perfuse_diagflags & PDF_SYNC)
2077 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
2078 __func__, (void*)opc, perfuse_node_path(opc),
2079 pnd->pnd_flags & PND_DIRTY ? "" : "not ");
2080 #endif
2081 if (!(pnd->pnd_flags & PND_DIRTY))
2082 return 0;
2083
2084 /*
2085 * It seems NetBSD can call fsync without open first
2086 * glusterfs complain in such a situation:
2087 * "FSYNC() ERR => -1 (Invalid argument)"
2088 * The file will be closed at inactive time.
2089 *
2090 * We open the directory for reading in order to sync.
2091 * This sounds rather counterintuitive, but it works.
2092 */
2093 if (!(pnd->pnd_flags & PND_WFH)) {
2094 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2095 goto out;
2096 }
2097
2098 if (op == FUSE_FSYNCDIR)
2099 fh = perfuse_get_fh(opc, FREAD);
2100 else
2101 fh = perfuse_get_fh(opc, FWRITE);
2102
2103 /*
2104 * If fsync_flags is set, meta data should not be flushed.
2105 */
2106 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr);
2107 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
2108 ffi->fh = fh;
2109 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
2110
2111 #ifdef PERFUSE_DEBUG
2112 if (perfuse_diagflags & PDF_FH)
2113 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2114 __func__, (void *)opc,
2115 PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh);
2116 #endif
2117
2118 if ((error = xchg_msg(pu, opc, pm,
2119 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
2120 goto out;
2121
2122 /*
2123 * No reply beyond fuse_out_header: nothing to do on success
2124 * just clear the dirty flag
2125 */
2126 pnd->pnd_flags &= ~PND_DIRTY;
2127
2128 #ifdef PERFUSE_DEBUG
2129 if (perfuse_diagflags & PDF_SYNC)
2130 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
2131 __func__, (void*)opc, perfuse_node_path(opc));
2132 #endif
2133
2134 ps->ps_destroy_msg(pm);
2135
2136 out:
2137 /*
2138 * ENOSYS is not returned to kernel,
2139 */
2140 if (error == ENOSYS)
2141 error = 0;
2142
2143 return error;
2144 }
2145
2146 /* ARGSUSED0 */
2147 int
2148 perfuse_node_seek(pu, opc, oldoff, newoff, pcr)
2149 struct puffs_usermount *pu;
2150 puffs_cookie_t opc;
2151 off_t oldoff;
2152 off_t newoff;
2153 const struct puffs_cred *pcr;
2154 {
2155 return 0;
2156 }
2157
2158 int
2159 perfuse_node_remove(pu, opc, targ, pcn)
2160 struct puffs_usermount *pu;
2161 puffs_cookie_t opc;
2162 puffs_cookie_t targ;
2163 const struct puffs_cn *pcn;
2164 {
2165 struct perfuse_state *ps;
2166 struct perfuse_node_data *pnd;
2167 perfuse_msg_t *pm;
2168 char *path;
2169 const char *name;
2170 size_t len;
2171 int error;
2172
2173 pnd = PERFUSE_NODE_DATA(opc);
2174
2175 if ((pnd->pnd_flags & PND_REMOVED) ||
2176 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
2177 return ENOENT;
2178
2179 #ifdef PERFUSE_DEBUG
2180 if (targ == NULL)
2181 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
2182
2183 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
2184 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n",
2185 __func__, (void *)opc, (void *)targ, pcn->pcn_name);
2186 #endif
2187 /*
2188 * Await for all operations on the deleted node to drain,
2189 * as the filesystem may be confused to have it deleted
2190 * during a getattr
2191 */
2192 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2193 requeue_request(pu, targ, PCQ_AFTERXCHG);
2194
2195 ps = puffs_getspecific(pu);
2196 pnd = PERFUSE_NODE_DATA(opc);
2197 name = pcn->pcn_name;
2198 len = pcn->pcn_namelen + 1;
2199
2200 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
2201 path = _GET_INPAYLOAD(ps, pm, char *);
2202 (void)strlcpy(path, name, len);
2203
2204 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2205 return error;
2206
2207 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2208 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2209 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2210
2211 /*
2212 * The parent directory needs a sync
2213 */
2214 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2215
2216 #ifdef PERFUSE_DEBUG
2217 if (perfuse_diagflags & PDF_FILENAME)
2218 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2219 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2220 pcn->pcn_name);
2221 #endif
2222 ps->ps_destroy_msg(pm);
2223
2224 return 0;
2225 }
2226
2227 int
2228 perfuse_node_link(pu, opc, targ, pcn)
2229 struct puffs_usermount *pu;
2230 puffs_cookie_t opc;
2231 puffs_cookie_t targ;
2232 const struct puffs_cn *pcn;
2233 {
2234 struct perfuse_state *ps;
2235 perfuse_msg_t *pm;
2236 const char *name;
2237 size_t len;
2238 struct puffs_node *pn;
2239 struct fuse_link_in *fli;
2240 int error;
2241
2242 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2243 return ENOENT;
2244
2245 ps = puffs_getspecific(pu);
2246 pn = (struct puffs_node *)targ;
2247 name = pcn->pcn_name;
2248 len = sizeof(*fli) + pcn->pcn_namelen + 1;
2249
2250 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred);
2251 fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
2252 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid;
2253 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
2254
2255 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2256 return error;
2257
2258 ps->ps_destroy_msg(pm);
2259
2260 return 0;
2261 }
2262
2263 int
2264 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ)
2265 struct puffs_usermount *pu;
2266 puffs_cookie_t opc;
2267 puffs_cookie_t src;
2268 const struct puffs_cn *pcn_src;
2269 puffs_cookie_t targ_dir;
2270 puffs_cookie_t targ;
2271 const struct puffs_cn *pcn_targ;
2272 {
2273 struct perfuse_state *ps;
2274 perfuse_msg_t *pm;
2275 struct fuse_rename_in *fri;
2276 const char *newname;
2277 const char *oldname;
2278 char *np;
2279 int error;
2280 size_t len;
2281 size_t newname_len;
2282 size_t oldname_len;
2283
2284 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) ||
2285 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) ||
2286 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED))
2287 return ENOENT;
2288
2289 /*
2290 * Await for all operations on the deleted node to drain,
2291 * as the filesystem may be confused to have it deleted
2292 * during a getattr
2293 */
2294 if ((struct puffs_node *)targ != NULL) {
2295 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2296 requeue_request(pu, targ, PCQ_AFTERXCHG);
2297 } else {
2298 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG)
2299 requeue_request(pu, src, PCQ_AFTERXCHG);
2300 }
2301
2302 ps = puffs_getspecific(pu);
2303 newname = pcn_targ->pcn_name;
2304 newname_len = pcn_targ->pcn_namelen + 1;
2305 oldname = pcn_src->pcn_name;
2306 oldname_len = pcn_src->pcn_namelen + 1;
2307
2308 len = sizeof(*fri) + oldname_len + newname_len;
2309 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred);
2310 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
2311 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid;
2312 np = (char *)(void *)(fri + 1);
2313 (void)strlcpy(np, oldname, oldname_len);
2314 np += oldname_len;
2315 (void)strlcpy(np, newname, newname_len);
2316
2317 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2318 return error;
2319
2320 if (opc != targ_dir) {
2321 struct perfuse_node_data *srcdir_pnd;
2322 struct perfuse_node_data *dstdir_pnd;
2323 struct perfuse_node_data *src_pnd;
2324
2325 srcdir_pnd = PERFUSE_NODE_DATA(opc);
2326 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir);
2327 src_pnd = PERFUSE_NODE_DATA(src);
2328
2329 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next);
2330 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next);
2331
2332 srcdir_pnd->pnd_childcount--;
2333 dstdir_pnd->pnd_childcount++;
2334
2335 src_pnd->pnd_parent = targ_dir;
2336
2337 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY;
2338 }
2339
2340 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN);
2341
2342 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2343
2344 if ((struct puffs_node *)targ != NULL)
2345 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2346
2347 #ifdef PERFUSE_DEBUG
2348 if (perfuse_diagflags & PDF_FILENAME)
2349 DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" "
2350 "nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n",
2351 __func__, PERFUSE_NODE_DATA(src)->pnd_nodeid,
2352 pcn_src->pcn_name, pcn_targ->pcn_name,
2353 PERFUSE_NODE_DATA(opc)->pnd_nodeid,
2354 PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid,
2355 perfuse_node_path(targ_dir));
2356 #endif
2357
2358 ps->ps_destroy_msg(pm);
2359
2360 return 0;
2361 }
2362
2363 int
2364 perfuse_node_mkdir(pu, opc, pni, pcn, vap)
2365 struct puffs_usermount *pu;
2366 puffs_cookie_t opc;
2367 struct puffs_newinfo *pni;
2368 const struct puffs_cn *pcn;
2369 const struct vattr *vap;
2370 {
2371 struct perfuse_state *ps;
2372 perfuse_msg_t *pm;
2373 struct fuse_mkdir_in *fmi;
2374 const char *path;
2375 size_t len;
2376
2377 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2378 return ENOENT;
2379
2380 ps = puffs_getspecific(pu);
2381 path = pcn->pcn_name;
2382 len = sizeof(*fmi) + pcn->pcn_namelen + 1;
2383
2384 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred);
2385 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
2386 fmi->mode = vap->va_mode;
2387 fmi->umask = 0; /* Seems unused by libfuse? */
2388 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
2389
2390 return node_mk_common(pu, opc, pni, pcn, pm);
2391 }
2392
2393
2394 int
2395 perfuse_node_rmdir(pu, opc, targ, pcn)
2396 struct puffs_usermount *pu;
2397 puffs_cookie_t opc;
2398 puffs_cookie_t targ;
2399 const struct puffs_cn *pcn;
2400 {
2401 struct perfuse_state *ps;
2402 struct perfuse_node_data *pnd;
2403 perfuse_msg_t *pm;
2404 char *path;
2405 const char *name;
2406 size_t len;
2407 int error;
2408
2409 pnd = PERFUSE_NODE_DATA(opc);
2410
2411 if ((pnd->pnd_flags & PND_REMOVED) ||
2412 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
2413 return ENOENT;
2414
2415 /*
2416 * Await for all operations on the deleted node to drain,
2417 * as the filesystem may be confused to have it deleted
2418 * during a getattr
2419 */
2420 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2421 requeue_request(pu, targ, PCQ_AFTERXCHG);
2422
2423 ps = puffs_getspecific(pu);
2424 name = pcn->pcn_name;
2425 len = pcn->pcn_namelen + 1;
2426
2427 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
2428 path = _GET_INPAYLOAD(ps, pm, char *);
2429 (void)strlcpy(path, name, len);
2430
2431 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2432 return error;
2433
2434 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2435 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2436 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2437
2438 /*
2439 * The parent directory needs a sync
2440 */
2441 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2442
2443 #ifdef PERFUSE_DEBUG
2444 if (perfuse_diagflags & PDF_FILENAME)
2445 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2446 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2447 perfuse_node_path(targ));
2448 #endif
2449 ps->ps_destroy_msg(pm);
2450
2451 return 0;
2452 }
2453
2454 /* vap is unused */
2455 /* ARGSUSED4 */
2456 int
2457 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
2458 struct puffs_usermount *pu;
2459 puffs_cookie_t opc;
2460 struct puffs_newinfo *pni;
2461 const struct puffs_cn *pcn_src;
2462 const struct vattr *vap;
2463 const char *link_target;
2464 {
2465 struct perfuse_state *ps;
2466 perfuse_msg_t *pm;
2467 char *np;
2468 const char *path;
2469 size_t path_len;
2470 size_t linkname_len;
2471 size_t len;
2472
2473 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2474 return ENOENT;
2475
2476 ps = puffs_getspecific(pu);
2477 path = pcn_src->pcn_name;
2478 path_len = pcn_src->pcn_namelen + 1;
2479 linkname_len = strlen(link_target) + 1;
2480 len = path_len + linkname_len;
2481
2482 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
2483 np = _GET_INPAYLOAD(ps, pm, char *);
2484 (void)strlcpy(np, path, path_len);
2485 np += path_len;
2486 (void)strlcpy(np, link_target, linkname_len);
2487
2488 return node_mk_common(pu, opc, pni, pcn_src, pm);
2489 }
2490
2491 /* ARGSUSED4 */
2492 int
2493 perfuse_node_readdir(pu, opc, dent, readoff,
2494 reslen, pcr, eofflag, cookies, ncookies)
2495 struct puffs_usermount *pu;
2496 puffs_cookie_t opc;
2497 struct dirent *dent;
2498 off_t *readoff;
2499 size_t *reslen;
2500 const struct puffs_cred *pcr;
2501 int *eofflag;
2502 off_t *cookies;
2503 size_t *ncookies;
2504 {
2505 perfuse_msg_t *pm;
2506 uint64_t fh;
2507 struct perfuse_state *ps;
2508 struct perfuse_node_data *pnd;
2509 struct fuse_read_in *fri;
2510 struct fuse_out_header *foh;
2511 struct fuse_dirent *fd;
2512 size_t foh_len;
2513 int error;
2514 size_t fd_maxlen;
2515
2516 error = 0;
2517 ps = puffs_getspecific(pu);
2518
2519 /*
2520 * readdir state is kept at node level, and several readdir
2521 * requests can be issued at the same time on the same node.
2522 * We need to queue requests so that only one is in readdir
2523 * code at the same time.
2524 */
2525 pnd = PERFUSE_NODE_DATA(opc);
2526 while (pnd->pnd_flags & PND_INREADDIR)
2527 requeue_request(pu, opc, PCQ_READDIR);
2528 pnd->pnd_flags |= PND_INREADDIR;
2529
2530 #ifdef PERFUSE_DEBUG
2531 if (perfuse_diagflags & PDF_READDIR)
2532 DPRINTF("%s: READDIR opc = %p enter critical section\n",
2533 __func__, (void *)opc);
2534 #endif
2535 /*
2536 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node
2537 */
2538 if (*readoff == 0)
2539 pnd->pnd_fd_cookie = 0;
2540
2541 /*
2542 * Do we already have the data bufered?
2543 */
2544 if (pnd->pnd_dirent != NULL)
2545 goto out;
2546 pnd->pnd_dirent_len = 0;
2547
2548 /*
2549 * It seems NetBSD can call readdir without open first
2550 * libfuse will crash if it is done that way, hence open first.
2551 */
2552 if (!(pnd->pnd_flags & PND_OPEN)) {
2553 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2554 goto out;
2555 }
2556
2557 fh = perfuse_get_fh(opc, FREAD);
2558
2559 #ifdef PERFUSE_DEBUG
2560 if (perfuse_diagflags & PDF_FH)
2561 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
2562 "rfh = 0x%"PRIx64"\n", __func__, (void *)opc,
2563 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh);
2564 #endif
2565
2566 pnd->pnd_all_fd = NULL;
2567 pnd->pnd_all_fd_len = 0;
2568 fd_maxlen = ps->ps_max_readahead - sizeof(*foh);
2569
2570 do {
2571 size_t fd_len;
2572 char *afdp;
2573
2574 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
2575
2576 /*
2577 * read_flags, lock_owner and flags are unused in libfuse
2578 */
2579 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2580 fri->fh = fh;
2581 fri->offset = pnd->pnd_fd_cookie;
2582 fri->size = (uint32_t)fd_maxlen;
2583 fri->read_flags = 0;
2584 fri->lock_owner = 0;
2585 fri->flags = 0;
2586
2587 if ((error = xchg_msg(pu, opc, pm,
2588 UNSPEC_REPLY_LEN, wait_reply)) != 0)
2589 goto out;
2590
2591 /*
2592 * There are many puffs_framebufs calls later,
2593 * therefore foh will not be valid for a long time.
2594 * Just get the length and forget it.
2595 */
2596 foh = GET_OUTHDR(ps, pm);
2597 foh_len = foh->len;
2598
2599 /*
2600 * Empty read: we reached the end of the buffer.
2601 */
2602 if (foh_len == sizeof(*foh)) {
2603 ps->ps_destroy_msg(pm);
2604 *eofflag = 1;
2605 break;
2606 }
2607
2608 /*
2609 * Check for corrupted message.
2610 */
2611 if (foh_len < sizeof(*foh) + sizeof(*fd)) {
2612 ps->ps_destroy_msg(pm);
2613 DWARNX("readdir reply too short");
2614 error = EIO;
2615 goto out;
2616 }
2617
2618
2619 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
2620 fd_len = foh_len - sizeof(*foh);
2621
2622 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
2623 pnd->pnd_all_fd_len + fd_len);
2624 if (pnd->pnd_all_fd == NULL)
2625 DERR(EX_OSERR, "%s: malloc failed", __func__);
2626
2627 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
2628 (void)memcpy(afdp, fd, fd_len);
2629
2630 pnd->pnd_all_fd_len += fd_len;
2631
2632 /*
2633 * The fd->off field is used as a cookie for
2634 * resuming the next readdir() where this one was left.
2635 */
2636 pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len);
2637
2638 ps->ps_destroy_msg(pm);
2639 } while (1 /* CONSTCOND */);
2640
2641 if (pnd->pnd_all_fd != NULL) {
2642 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd,
2643 pnd->pnd_all_fd_len) == -1)
2644 error = EIO;
2645 }
2646
2647 out:
2648 if (pnd->pnd_all_fd != NULL) {
2649 free(pnd->pnd_all_fd);
2650 pnd->pnd_all_fd = NULL;
2651 pnd->pnd_all_fd_len = 0;
2652 }
2653
2654 if (error == 0)
2655 error = readdir_buffered(opc, dent, readoff, reslen);
2656
2657 /*
2658 * Schedule queued readdir requests
2659 */
2660 pnd->pnd_flags &= ~PND_INREADDIR;
2661 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
2662
2663 #ifdef PERFUSE_DEBUG
2664 if (perfuse_diagflags & PDF_READDIR)
2665 DPRINTF("%s: READDIR opc = %p exit critical section\n",
2666 __func__, (void *)opc);
2667 #endif
2668
2669 return error;
2670 }
2671
2672 int
2673 perfuse_node_readlink(pu, opc, pcr, linkname, linklen)
2674 struct puffs_usermount *pu;
2675 puffs_cookie_t opc;
2676 const struct puffs_cred *pcr;
2677 char *linkname;
2678 size_t *linklen;
2679 {
2680 struct perfuse_state *ps;
2681 perfuse_msg_t *pm;
2682 int error;
2683 size_t len;
2684 struct fuse_out_header *foh;
2685
2686 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2687 return ENOENT;
2688
2689 ps = puffs_getspecific(pu);
2690
2691 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
2692
2693 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2694 return error;
2695
2696 foh = GET_OUTHDR(ps, pm);
2697 len = foh->len - sizeof(*foh);
2698 if (len > *linklen)
2699 DERRX(EX_PROTOCOL, "path len = %zd too long", len);
2700 if (len == 0)
2701 DERRX(EX_PROTOCOL, "path len = %zd too short", len);
2702
2703 /*
2704 * FUSE filesystems return a NUL terminated string, we
2705 * do not want to trailing \0
2706 */
2707 *linklen = len - 1;
2708 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
2709
2710 ps->ps_destroy_msg(pm);
2711
2712 return 0;
2713 }
2714
2715 int
2716 perfuse_node_reclaim(pu, opc)
2717 struct puffs_usermount *pu;
2718 puffs_cookie_t opc;
2719 {
2720 struct perfuse_state *ps;
2721 perfuse_msg_t *pm;
2722 struct perfuse_node_data *pnd;
2723 struct fuse_forget_in *ffi;
2724 struct puffs_node *pn;
2725 struct puffs_node *pn_root;
2726
2727 ps = puffs_getspecific(pu);
2728 pnd = PERFUSE_NODE_DATA(opc);
2729
2730 /*
2731 * Never forget the root.
2732 */
2733 if (pnd->pnd_nodeid == FUSE_ROOT_ID)
2734 return 0;
2735
2736 pnd->pnd_flags |= PND_RECLAIMED;
2737
2738 #ifdef PERFUSE_DEBUG
2739 if (perfuse_diagflags & PDF_RECLAIM)
2740 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2741 perfuse_node_path(opc), pnd->pnd_nodeid);
2742 #endif
2743
2744 pn_root = puffs_getroot(pu);
2745 pn = (struct puffs_node *)opc;
2746 while (pn != pn_root) {
2747 struct puffs_node *parent_pn;
2748
2749 pnd = PERFUSE_NODE_DATA(pn);
2750
2751 #ifdef PERFUSE_DEBUG
2752 if (perfuse_diagflags & PDF_RECLAIM)
2753 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
2754 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n",
2755 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_nodeid,
2756 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2757 pnd->pnd_childcount,
2758 pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2759 pnd->pnd_flags & PND_RFH ? "r" : "",
2760 pnd->pnd_flags & PND_WFH ? "w" : "",
2761 pnd->pnd_flags & PND_BUSY ? "" : " none",
2762 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2763 pnd->pnd_flags & PND_INWRITE ? " write" : "",
2764 pnd->pnd_flags & PND_INOPEN ? " open" : "");
2765 #endif
2766
2767 if (!(pnd->pnd_flags & PND_RECLAIMED) ||
2768 (pnd->pnd_childcount != 0))
2769 return 0;
2770
2771 #ifdef PERFUSE_DEBUG
2772 if ((pnd->pnd_flags & PND_OPEN) ||
2773 !TAILQ_EMPTY(&pnd->pnd_pcq))
2774 DERRX(EX_SOFTWARE, "%s: opc = %p: still open",
2775 __func__, (void *)opc);
2776
2777 if ((pnd->pnd_flags & PND_BUSY) ||
2778 !TAILQ_EMPTY(&pnd->pnd_pcq))
2779 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
2780 __func__, (void *)opc);
2781 #endif
2782
2783 /*
2784 * Send the FORGET message
2785 *
2786 * ps_new_msg() is called with NULL creds, which will
2787 * be interpreted as FUSE superuser. This is obviously
2788 * fine since we operate with kernel creds here.
2789 */
2790 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
2791 sizeof(*ffi), NULL);
2792 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2793 ffi->nlookup = pnd->pnd_nlookup;
2794
2795 /*
2796 * No reply is expected, pm is freed in xchg_msg
2797 */
2798 (void)xchg_msg(pu, (puffs_cookie_t)pn,
2799 pm, UNSPEC_REPLY_LEN, no_reply);
2800
2801 parent_pn = pnd->pnd_parent;
2802
2803 perfuse_destroy_pn(pn);
2804
2805 pn = parent_pn;
2806 }
2807
2808 return 0;
2809 }
2810
2811 int
2812 perfuse_node_inactive(pu, opc)
2813 struct puffs_usermount *pu;
2814 puffs_cookie_t opc;
2815 {
2816 struct perfuse_state *ps;
2817 struct perfuse_node_data *pnd;
2818
2819 ps = puffs_getspecific(pu);
2820 pnd = PERFUSE_NODE_DATA(opc);
2821
2822 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED)))
2823 return 0;
2824
2825 /*
2826 * Make sure all operation are finished
2827 * There can be an ongoing write. Other
2828 * operation wait for all data before
2829 * the close/inactive.
2830 */
2831 while (pnd->pnd_flags & PND_INWRITE)
2832 requeue_request(pu, opc, PCQ_AFTERWRITE);
2833
2834 /*
2835 * The inactive operation may be cancelled.
2836 * If no open is in progress, set PND_INOPEN
2837 * so that a new open will be queued.
2838 */
2839 if (pnd->pnd_flags & PND_INOPEN)
2840 return 0;
2841
2842 pnd->pnd_flags |= PND_INOPEN;
2843
2844 /*
2845 * Sync data
2846 */
2847 if (pnd->pnd_flags & PND_DIRTY)
2848 (void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0);
2849
2850 /*
2851 * Close handles
2852 */
2853 if (pnd->pnd_flags & PND_WFH)
2854 (void)perfuse_node_close_common(pu, opc, FWRITE);
2855
2856 if (pnd->pnd_flags & PND_RFH)
2857 (void)perfuse_node_close_common(pu, opc, FREAD);
2858
2859 /*
2860 * This will cause a reclaim to be sent
2861 */
2862 if (pnd->pnd_flags & PND_REMOVED)
2863 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
2864
2865 /*
2866 * Schedule awaiting operations
2867 */
2868 pnd->pnd_flags &= ~PND_INOPEN;
2869 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
2870
2871 return 0;
2872 }
2873
2874
2875 /* ARGSUSED0 */
2876 int
2877 perfuse_node_print(pu, opc)
2878 struct puffs_usermount *pu;
2879 puffs_cookie_t opc;
2880 {
2881 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2882 return 0;
2883 }
2884
2885 /* ARGSUSED0 */
2886 int
2887 perfuse_node_pathconf(pu, opc, name, retval)
2888 struct puffs_usermount *pu;
2889 puffs_cookie_t opc;
2890 int name;
2891 int *retval;
2892 {
2893 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2894 return 0;
2895 }
2896
2897 int
2898 perfuse_node_advlock(pu, opc, id, op, fl, flags)
2899 struct puffs_usermount *pu;
2900 puffs_cookie_t opc;
2901 void *id;
2902 int op;
2903 struct flock *fl;
2904 int flags;
2905 {
2906 struct perfuse_state *ps;
2907 int fop;
2908 perfuse_msg_t *pm;
2909 uint64_t fh;
2910 struct fuse_lk_in *fli;
2911 struct fuse_out_header *foh;
2912 struct fuse_lk_out *flo;
2913 uint32_t owner;
2914 size_t len;
2915 int error;
2916
2917 /*
2918 * Make sure we do have a filehandle, as the FUSE filesystem
2919 * expect one. E.g.: if we provide none, GlusterFS logs an error
2920 * "0-glusterfs-fuse: xl is NULL"
2921 *
2922 * We need the read file handle if the file is open read only,
2923 * in order to support shared locks on read-only files.
2924 * NB: The kernel always sends advlock for read-only
2925 * files at exit time when the process used lock, see
2926 * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK
2927 */
2928 if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH)
2929 return EBADF;
2930
2931 ps = puffs_getspecific(pu);
2932
2933 if (op == F_GETLK)
2934 fop = FUSE_GETLK;
2935 else
2936 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2937
2938 /*
2939 * XXX ps_new_msg() is called with NULL creds, which will
2940 * be interpreted as FUSE superuser. We have no way to
2941 * know the requesting process' credential, but since advlock()
2942 * is supposed to operate on a file that has been open(),
2943 * permission should have already been checked at open() time.
2944 */
2945 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2946 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2947 fli->fh = fh;
2948 fli->owner = (uint64_t)(vaddr_t)id;
2949 fli->lk.start = fl->l_start;
2950 fli->lk.end = fl->l_start + fl->l_len;
2951 fli->lk.type = fl->l_type;
2952 fli->lk.pid = fl->l_pid;
2953 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
2954
2955 owner = (uint32_t)(vaddr_t)id;
2956
2957 #ifdef PERFUSE_DEBUG
2958 if (perfuse_diagflags & PDF_FH)
2959 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2960 __func__, (void *)opc,
2961 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh);
2962 #endif
2963
2964 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2965 return error;
2966
2967 foh = GET_OUTHDR(ps, pm);
2968 len = foh->len - sizeof(*foh);
2969
2970 /*
2971 * Save or clear the lock
2972 */
2973 switch (op) {
2974 case F_GETLK:
2975 if (len != sizeof(*flo))
2976 DERRX(EX_SOFTWARE,
2977 "%s: Unexpected lock reply len %zd",
2978 __func__, len);
2979
2980 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
2981 fl->l_start = flo->lk.start;
2982 fl->l_len = flo->lk.end - flo->lk.start;
2983 fl->l_pid = flo->lk.pid;
2984 fl->l_type = flo->lk.type;
2985 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */
2986
2987 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
2988 break;
2989 case F_UNLCK:
2990 owner = 0;
2991 /* FALLTHROUGH */
2992 case F_SETLK:
2993 /* FALLTHROUGH */
2994 case F_SETLKW:
2995 if (error != 0)
2996 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner;
2997
2998 if (len != 0)
2999 DERRX(EX_SOFTWARE,
3000 "%s: Unexpected unlock reply len %zd",
3001 __func__, len);
3002
3003 break;
3004 default:
3005 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op);
3006 break;
3007 }
3008
3009 ps->ps_destroy_msg(pm);
3010
3011 return 0;
3012 }
3013
3014 int
3015 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
3016 struct puffs_usermount *pu;
3017 puffs_cookie_t opc;
3018 uint8_t *buf;
3019 off_t offset;
3020 size_t *resid;
3021 const struct puffs_cred *pcr;
3022 int ioflag;
3023 {
3024 struct perfuse_state *ps;
3025 struct perfuse_node_data *pnd;
3026 const struct vattr *vap;
3027 perfuse_msg_t *pm;
3028 struct fuse_read_in *fri;
3029 struct fuse_out_header *foh;
3030 size_t readen;
3031 int error;
3032
3033 ps = puffs_getspecific(pu);
3034 pnd = PERFUSE_NODE_DATA(opc);
3035 vap = puffs_pn_getvap((struct puffs_node *)opc);
3036
3037 /*
3038 * NetBSD turns that into a getdents(2) output
3039 * We just do a EISDIR as this feature is of little use.
3040 */
3041 if (vap->va_type == VDIR)
3042 return EISDIR;
3043
3044 if ((u_quad_t)offset + *resid > vap->va_size)
3045 DWARNX("%s %p read %lld@%zu beyond EOF %" PRIu64 "\n",
3046 __func__, (void *)opc, (long long)offset,
3047 *resid, vap->va_size);
3048
3049 do {
3050 size_t max_read;
3051
3052 max_read = ps->ps_max_readahead - sizeof(*foh);
3053 /*
3054 * flags may be set to FUSE_READ_LOCKOWNER
3055 * if lock_owner is provided.
3056 */
3057 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
3058 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
3059 fri->fh = perfuse_get_fh(opc, FREAD);
3060 fri->offset = offset;
3061 fri->size = (uint32_t)MIN(*resid, max_read);
3062 fri->read_flags = 0; /* XXX Unused by libfuse? */
3063 fri->lock_owner = pnd->pnd_lock_owner;
3064 fri->flags = 0;
3065 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
3066
3067 #ifdef PERFUSE_DEBUG
3068 if (perfuse_diagflags & PDF_FH)
3069 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
3070 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
3071 #endif
3072 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
3073 if (error != 0)
3074 return error;
3075
3076 foh = GET_OUTHDR(ps, pm);
3077 readen = foh->len - sizeof(*foh);
3078
3079 #ifdef PERFUSE_DEBUG
3080 if (readen > *resid)
3081 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd",
3082 __func__, readen);
3083 #endif
3084
3085 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
3086
3087 buf += readen;
3088 offset += readen;
3089 *resid -= readen;
3090
3091 ps->ps_destroy_msg(pm);
3092 } while ((*resid != 0) && (readen != 0));
3093
3094 if (ioflag & (IO_SYNC|IO_DSYNC))
3095 ps->ps_syncreads++;
3096 else
3097 ps->ps_asyncreads++;
3098
3099 return 0;
3100 }
3101
3102 int
3103 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
3104 struct puffs_usermount *pu;
3105 puffs_cookie_t opc;
3106 uint8_t *buf;
3107 off_t offset;
3108 size_t *resid;
3109 const struct puffs_cred *pcr;
3110 int ioflag;
3111 {
3112 struct perfuse_state *ps;
3113 struct perfuse_node_data *pnd;
3114 struct vattr *vap;
3115 perfuse_msg_t *pm;
3116 struct fuse_write_in *fwi;
3117 struct fuse_write_out *fwo;
3118 size_t data_len;
3119 size_t payload_len;
3120 size_t written;
3121 int inresize;
3122 int error;
3123
3124 ps = puffs_getspecific(pu);
3125 pnd = PERFUSE_NODE_DATA(opc);
3126 vap = puffs_pn_getvap((struct puffs_node *)opc);
3127 written = 0;
3128 inresize = 0;
3129 error = 0;
3130
3131 if (vap->va_type == VDIR)
3132 return EISDIR;
3133
3134 /*
3135 * We need to queue write requests in order to avoid
3136 * dequeueing PCQ_AFTERWRITE when there are pending writes.
3137 */
3138 while (pnd->pnd_flags & PND_INWRITE)
3139 requeue_request(pu, opc, PCQ_WRITE);
3140 pnd->pnd_flags |= PND_INWRITE;
3141
3142 /*
3143 * Serialize size access, see comment in perfuse_node_setattr().
3144 */
3145 if ((u_quad_t)offset + *resid > vap->va_size) {
3146 while (pnd->pnd_flags & PND_INRESIZE)
3147 requeue_request(pu, opc, PCQ_RESIZE);
3148 pnd->pnd_flags |= PND_INRESIZE;
3149 inresize = 1;
3150 }
3151
3152 /*
3153 * append flag: re-read the file size so that
3154 * we get the latest value.
3155 */
3156 if (ioflag & PUFFS_IO_APPEND) {
3157 DWARNX("%s: PUFFS_IO_APPEND set, untested code", __func__);
3158
3159 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0)
3160 goto out;
3161
3162 offset = vap->va_size;
3163 }
3164
3165 #ifdef PERFUSE_DEBUG
3166 if (perfuse_diagflags & PDF_RESIZE)
3167 DPRINTF(">> %s %p %" PRIu64 "\n", __func__,
3168 (void *)opc, vap->va_size);
3169 #endif
3170
3171 do {
3172 size_t max_write;
3173 /*
3174 * There is a writepage flag when data
3175 * is aligned to page size. Use it for
3176 * everything but the data after the last
3177 * page boundary.
3178 */
3179 max_write = ps->ps_max_write - sizeof(*fwi);
3180
3181 data_len = MIN(*resid, max_write);
3182 if (data_len > (size_t)sysconf(_SC_PAGESIZE))
3183 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1);
3184
3185 payload_len = data_len + sizeof(*fwi);
3186
3187 /*
3188 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
3189 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
3190 * write_flags is set to 1 for writepage.
3191 */
3192 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
3193 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
3194 fwi->fh = perfuse_get_fh(opc, FWRITE);
3195 fwi->offset = offset;
3196 fwi->size = (uint32_t)data_len;
3197 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1;
3198 fwi->lock_owner = pnd->pnd_lock_owner;
3199 fwi->flags = 0;
3200 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
3201 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
3202 (void)memcpy((fwi + 1), buf, data_len);
3203
3204
3205 #ifdef PERFUSE_DEBUG
3206 if (perfuse_diagflags & PDF_FH)
3207 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
3208 "fh = 0x%"PRIx64"\n", __func__,
3209 (void *)opc, pnd->pnd_nodeid, fwi->fh);
3210 #endif
3211 if ((error = xchg_msg(pu, opc, pm,
3212 sizeof(*fwo), wait_reply)) != 0)
3213 goto out;
3214
3215 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
3216 written = fwo->size;
3217 #ifdef PERFUSE_DEBUG
3218 if (written > *resid)
3219 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd",
3220 __func__, written);
3221 #endif
3222 *resid -= written;
3223 offset += written;
3224 buf += written;
3225
3226 ps->ps_destroy_msg(pm);
3227 } while (*resid != 0);
3228
3229 /*
3230 * puffs_ops(3) says
3231 * "everything must be written or an error will be generated"
3232 */
3233 if (*resid != 0)
3234 error = EFBIG;
3235
3236 #ifdef PERFUSE_DEBUG
3237 if (perfuse_diagflags & PDF_RESIZE) {
3238 if (offset > (off_t)vap->va_size)
3239 DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__,
3240 (void *)opc, vap->va_size, (long long)offset);
3241 else
3242 DPRINTF("<< %s %p \n", __func__, (void *)opc);
3243 }
3244 #endif
3245
3246 /*
3247 * Update file size if we wrote beyond the end
3248 */
3249 if (offset > (off_t)vap->va_size)
3250 vap->va_size = offset;
3251
3252 if (inresize) {
3253 #ifdef PERFUSE_DEBUG
3254 if (!(pnd->pnd_flags & PND_INRESIZE))
3255 DERRX(EX_SOFTWARE, "file write grow without resize");
3256 #endif
3257 pnd->pnd_flags &= ~PND_INRESIZE;
3258 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
3259 }
3260
3261
3262 /*
3263 * Statistics
3264 */
3265 if (ioflag & (IO_SYNC|IO_DSYNC))
3266 ps->ps_syncwrites++;
3267 else
3268 ps->ps_asyncwrites++;
3269
3270 /*
3271 * Remember to sync the file
3272 */
3273 pnd->pnd_flags |= PND_DIRTY;
3274
3275 #ifdef PERFUSE_DEBUG
3276 if (perfuse_diagflags & PDF_SYNC)
3277 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
3278 __func__, (void*)opc, perfuse_node_path(opc));
3279 #endif
3280
3281 out:
3282 /*
3283 * If there are no more queued write, we can resume
3284 * an operation awaiting write completion.
3285 */
3286 pnd->pnd_flags &= ~PND_INWRITE;
3287 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0)
3288 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
3289
3290 return error;
3291 }
3292
3293 /* ARGSUSED0 */
3294 void
3295 perfuse_cache_write(pu, opc, size, runs)
3296 struct puffs_usermount *pu;
3297 puffs_cookie_t opc;
3298 size_t size;
3299 struct puffs_cacherun *runs;
3300 {
3301 return;
3302 }
3303
3304 /* ARGSUSED4 */
3305 int
3306 perfuse_node_getextattr(pu, opc, attrns, attrname, attrsize, attr, resid, pcr)
3307 struct puffs_usermount *pu;
3308 puffs_cookie_t opc;
3309 int attrns;
3310 const char *attrname;
3311 size_t *attrsize;
3312 uint8_t *attr;
3313 size_t *resid;
3314 const struct puffs_cred *pcr;
3315 {
3316 struct perfuse_state *ps;
3317 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3318 perfuse_msg_t *pm;
3319 struct fuse_getxattr_in *fgi;
3320 struct fuse_getxattr_out *fgo;
3321 struct fuse_out_header *foh;
3322 size_t attrnamelen;
3323 size_t len;
3324 char *np;
3325 int error;
3326
3327 ps = puffs_getspecific(pu);
3328 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3329 attrnamelen = strlen(attrname) + 1;
3330 len = sizeof(*fgi) + attrnamelen;
3331
3332 pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr);
3333 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3334 fgi->size = (unsigned int)((resid != NULL) ? *resid : 0);
3335 np = (char *)(void *)(fgi + 1);
3336 (void)strlcpy(np, attrname, attrnamelen);
3337
3338 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3339 return error;
3340
3341 /*
3342 * We just get fuse_getattr_out with list size if we requested
3343 * a null size.
3344 */
3345 if (resid == NULL) {
3346 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3347
3348 if (attrsize != NULL)
3349 *attrsize = fgo->size;
3350
3351 ps->ps_destroy_msg(pm);
3352 return 0;
3353 }
3354
3355 /*
3356 * And with a non null requested size, we get the list just
3357 * after the header
3358 */
3359 foh = GET_OUTHDR(ps, pm);
3360 np = (char *)(void *)(foh + 1);
3361
3362 if (resid != NULL) {
3363 len = MAX(foh->len - sizeof(*foh), *resid);
3364 (void)memcpy(attr, np, len);
3365 *resid -= len;
3366 }
3367
3368 ps->ps_destroy_msg(pm);
3369
3370 return 0;
3371 }
3372
3373 int
3374 perfuse_node_setextattr(pu, opc, attrns, attrname, attr, resid, pcr)
3375 struct puffs_usermount *pu;
3376 puffs_cookie_t opc;
3377 int attrns;
3378 const char *attrname;
3379 uint8_t *attr;
3380 size_t *resid;
3381 const struct puffs_cred *pcr;
3382 {
3383 struct perfuse_state *ps;
3384 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3385 perfuse_msg_t *pm;
3386 struct fuse_setxattr_in *fsi;
3387 size_t attrnamelen;
3388 size_t len;
3389 char *np;
3390 int error;
3391
3392 ps = puffs_getspecific(pu);
3393 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3394 attrnamelen = strlen(attrname) + 1;
3395 len = sizeof(*fsi) + attrnamelen + *resid;
3396
3397 pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr);
3398 fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in);
3399 fsi->size = (unsigned int)*resid;
3400 fsi->flags = 0;
3401 np = (char *)(void *)(fsi + 1);
3402 (void)strlcpy(np, attrname, attrnamelen);
3403 np += attrnamelen;
3404 (void)memcpy(np, (char *)attr, *resid);
3405
3406 if ((error = xchg_msg(pu, opc, pm,
3407 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
3408 return error;
3409
3410 *resid = 0;
3411 ps->ps_destroy_msg(pm);
3412
3413 return 0;
3414 }
3415
3416 /* ARGSUSED2 */
3417 int
3418 perfuse_node_listextattr(pu, opc, attrns, attrsize, attrs, resid, flag, pcr)
3419 struct puffs_usermount *pu;
3420 puffs_cookie_t opc;
3421 int attrns;
3422 size_t *attrsize;
3423 uint8_t *attrs;
3424 size_t *resid;
3425 int flag;
3426 const struct puffs_cred *pcr;
3427 {
3428 struct perfuse_state *ps;
3429 perfuse_msg_t *pm;
3430 struct fuse_getxattr_in *fgi;
3431 struct fuse_getxattr_out *fgo;
3432 struct fuse_out_header *foh;
3433 char *np;
3434 size_t len, puffs_len;
3435 int error;
3436
3437 ps = puffs_getspecific(pu);
3438 len = sizeof(*fgi);
3439
3440 pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr);
3441 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3442 if (resid != NULL)
3443 fgi->size = (unsigned int)*resid;
3444 else
3445 fgi->size = 0;
3446
3447 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3448 return error;
3449
3450 /*
3451 * We just get fuse_getattr_out with list size if we requested
3452 * a null size.
3453 */
3454 if (resid == NULL) {
3455 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3456
3457 if (attrsize != NULL)
3458 *attrsize = fgo->size;
3459
3460 ps->ps_destroy_msg(pm);
3461
3462 return 0;
3463 }
3464
3465 /*
3466 * And with a non null requested size, we get the list just
3467 * after the header
3468 */
3469 foh = GET_OUTHDR(ps, pm);
3470 np = (char *)(void *)(foh + 1);
3471 puffs_len = foh->len - sizeof(*foh);
3472
3473 if (attrs != NULL) {
3474 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX
3475 /*
3476 * Convert the FUSE reply to length prefixed strings
3477 * if this is what the kernel wants.
3478 */
3479 if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) {
3480 size_t i, attrlen;
3481
3482 for (i = 0; i < puffs_len; i += attrlen + 1) {
3483 attrlen = strlen(np + i);
3484 (void)memmove(np + i + 1, np + i, attrlen);
3485 *(np + i) = (uint8_t)attrlen;
3486 }
3487 }
3488 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */
3489 (void)memcpy(attrs, np, puffs_len);
3490 *resid -= puffs_len;
3491 }
3492
3493 if (attrsize != NULL)
3494 *attrsize = puffs_len;
3495
3496 ps->ps_destroy_msg(pm);
3497
3498 return 0;
3499 }
3500
3501 int
3502 perfuse_node_deleteextattr(pu, opc, attrns, attrname, pcr)
3503 struct puffs_usermount *pu;
3504 puffs_cookie_t opc;
3505 int attrns;
3506 const char *attrname;
3507 const struct puffs_cred *pcr;
3508 {
3509 struct perfuse_state *ps;
3510 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3511 perfuse_msg_t *pm;
3512 size_t attrnamelen;
3513 char *np;
3514 int error;
3515
3516 ps = puffs_getspecific(pu);
3517 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3518 attrnamelen = strlen(attrname) + 1;
3519
3520 pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr);
3521 np = _GET_INPAYLOAD(ps, pm, char *);
3522 (void)strlcpy(np, attrname, attrnamelen);
3523
3524 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
3525
3526 ps->ps_destroy_msg(pm);
3527
3528 return error;
3529 }
3530