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