ops.c revision 1.54 1 /* $NetBSD: ops.c,v 1.54 2012/04/18 00:57:21 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 * If nothing remain, discard the operation.
1855 */
1856 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
1857 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
1858 error = 0;
1859 goto out;
1860 }
1861
1862 #ifdef PERFUSE_DEBUG
1863 old_vap = puffs_pn_getvap((struct puffs_node *)opc);
1864
1865 if ((perfuse_diagflags & PDF_RESIZE) &&
1866 (old_vap->va_size != (u_quad_t)PUFFS_VNOVAL)) {
1867 resize_debug = 1;
1868
1869 DPRINTF(">> %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1870 (void *)opc,
1871 puffs_pn_getvap((struct puffs_node *)opc)->va_size,
1872 fsi->size);
1873 }
1874 #endif
1875
1876 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1877 goto out;
1878
1879 /*
1880 * Copy back the new values
1881 */
1882 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1883
1884 #ifdef PERFUSE_DEBUG
1885 if (resize_debug)
1886 DPRINTF("<< %s %p %" PRIu64 " -> %" PRIu64 "\n", __func__,
1887 (void *)opc, old_vap->va_size, fao->attr.size);
1888 #endif
1889
1890 fuse_attr_to_vap(ps, old_va, &fao->attr);
1891
1892 #ifdef PUFFS_KFLAG_CACHE_FS_TTL
1893 if (va_ttl != NULL) {
1894 va_ttl->tv_sec = fao->attr_valid;
1895 va_ttl->tv_nsec = fao->attr_valid_nsec;
1896 (void)memcpy(vap, old_va, sizeof(*vap));
1897 }
1898 #else /* PUFFS_KFLAG_CACHE_FS_TTL */
1899 set_expire(opc, NULL, fao);
1900 #endif /* PUFFS_KFLAG_CACHE_FS_TTL */
1901
1902 ps->ps_destroy_msg(pm);
1903
1904 out:
1905 if (pnd->pnd_flags & PND_INRESIZE) {
1906 pnd->pnd_flags &= ~PND_INRESIZE;
1907 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
1908 }
1909
1910 return error;
1911 }
1912
1913 int
1914 perfuse_node_poll(struct puffs_usermount *pu, puffs_cookie_t opc, int *events)
1915 {
1916 struct perfuse_state *ps;
1917 perfuse_msg_t *pm;
1918 struct fuse_poll_in *fpi;
1919 struct fuse_poll_out *fpo;
1920 int error;
1921
1922 ps = puffs_getspecific(pu);
1923 /*
1924 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1925 *
1926 * XXX ps_new_msg() is called with NULL creds, which will
1927 * be interpreted as FUSE superuser. We have no way to
1928 * know the requesting process' credential, but since poll
1929 * is supposed to operate on a file that has been open,
1930 * permission should have already been checked at open time.
1931 * That still may breaks on filesystems that provides odd
1932 * semantics.
1933 */
1934 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1935 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1936 fpi->fh = perfuse_get_fh(opc, FREAD);
1937 fpi->kh = 0;
1938 fpi->flags = 0;
1939
1940 #ifdef PERFUSE_DEBUG
1941 if (perfuse_diagflags & PDF_FH)
1942 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
1943 "fh = 0x%"PRIx64"\n", __func__, (void *)opc,
1944 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fpi->fh);
1945 #endif
1946 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0)
1947 return error;
1948
1949 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
1950 *events = fpo->revents;
1951
1952 ps->ps_destroy_msg(pm);
1953
1954 return 0;
1955 }
1956
1957 /* ARGSUSED0 */
1958 int
1959 perfuse_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, int flags,
1960 const struct puffs_cred *pcr)
1961 {
1962 /*
1963 * Not implemented anymore in libfuse
1964 */
1965 return ENOSYS;
1966 }
1967
1968 /* ARGSUSED2 */
1969 int
1970 perfuse_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
1971 const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi)
1972 {
1973 int op;
1974 perfuse_msg_t *pm;
1975 struct perfuse_state *ps;
1976 struct perfuse_node_data *pnd;
1977 struct fuse_fsync_in *ffi;
1978 uint64_t fh;
1979 int error;
1980
1981 pm = NULL;
1982 ps = puffs_getspecific(pu);
1983 pnd = PERFUSE_NODE_DATA(opc);
1984
1985 /*
1986 * No need to sync a removed node
1987 */
1988 if (pnd->pnd_flags & PND_REMOVED)
1989 return 0;
1990
1991 /*
1992 * We do not sync closed files. They have been
1993 * sync at inactive time already.
1994 */
1995 if (!(pnd->pnd_flags & PND_OPEN))
1996 return 0;
1997
1998 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
1999 op = FUSE_FSYNCDIR;
2000 else /* VREG but also other types such as VLNK */
2001 op = FUSE_FSYNC;
2002
2003 /*
2004 * Do not sync if there are no change to sync
2005 * XXX remove that test on files if we implement mmap
2006 */
2007 #ifdef PERFUSE_DEBUG
2008 if (perfuse_diagflags & PDF_SYNC)
2009 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
2010 __func__, (void*)opc, perfuse_node_path(opc),
2011 pnd->pnd_flags & PND_DIRTY ? "" : "not ");
2012 #endif
2013 if (!(pnd->pnd_flags & PND_DIRTY))
2014 return 0;
2015
2016 /*
2017 * It seems NetBSD can call fsync without open first
2018 * glusterfs complain in such a situation:
2019 * "FSYNC() ERR => -1 (Invalid argument)"
2020 * The file will be closed at inactive time.
2021 *
2022 * We open the directory for reading in order to sync.
2023 * This sounds rather counterintuitive, but it works.
2024 */
2025 if (!(pnd->pnd_flags & PND_WFH)) {
2026 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2027 goto out;
2028 }
2029
2030 if (op == FUSE_FSYNCDIR)
2031 fh = perfuse_get_fh(opc, FREAD);
2032 else
2033 fh = perfuse_get_fh(opc, FWRITE);
2034
2035 /*
2036 * If fsync_flags is set, meta data should not be flushed.
2037 */
2038 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), pcr);
2039 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
2040 ffi->fh = fh;
2041 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
2042
2043 #ifdef PERFUSE_DEBUG
2044 if (perfuse_diagflags & PDF_FH)
2045 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2046 __func__, (void *)opc,
2047 PERFUSE_NODE_DATA(opc)->pnd_nodeid, ffi->fh);
2048 #endif
2049
2050 if ((error = xchg_msg(pu, opc, pm,
2051 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
2052 goto out;
2053
2054 /*
2055 * No reply beyond fuse_out_header: nothing to do on success
2056 * just clear the dirty flag
2057 */
2058 pnd->pnd_flags &= ~PND_DIRTY;
2059
2060 #ifdef PERFUSE_DEBUG
2061 if (perfuse_diagflags & PDF_SYNC)
2062 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
2063 __func__, (void*)opc, perfuse_node_path(opc));
2064 #endif
2065
2066 ps->ps_destroy_msg(pm);
2067
2068 out:
2069 /*
2070 * ENOSYS is not returned to kernel,
2071 */
2072 if (error == ENOSYS)
2073 error = 0;
2074
2075 return error;
2076 }
2077
2078 /* ARGSUSED0 */
2079 int
2080 perfuse_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc,
2081 off_t oldoff, off_t newoff, const struct puffs_cred *pcr)
2082 {
2083 return 0;
2084 }
2085
2086 int
2087 perfuse_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
2088 puffs_cookie_t targ, const struct puffs_cn *pcn)
2089 {
2090 struct perfuse_state *ps;
2091 struct perfuse_node_data *pnd;
2092 perfuse_msg_t *pm;
2093 char *path;
2094 const char *name;
2095 size_t len;
2096 int error;
2097
2098 pnd = PERFUSE_NODE_DATA(opc);
2099
2100 if ((pnd->pnd_flags & PND_REMOVED) ||
2101 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
2102 return ENOENT;
2103
2104 #ifdef PERFUSE_DEBUG
2105 if (targ == NULL)
2106 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
2107
2108 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
2109 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n",
2110 __func__, (void *)opc, (void *)targ, pcn->pcn_name);
2111 #endif
2112 /*
2113 * Await for all operations on the deleted node to drain,
2114 * as the filesystem may be confused to have it deleted
2115 * during a getattr
2116 */
2117 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2118 requeue_request(pu, targ, PCQ_AFTERXCHG);
2119
2120 ps = puffs_getspecific(pu);
2121 pnd = PERFUSE_NODE_DATA(opc);
2122 name = pcn->pcn_name;
2123 len = pcn->pcn_namelen + 1;
2124
2125 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, pcn->pcn_cred);
2126 path = _GET_INPAYLOAD(ps, pm, char *);
2127 (void)strlcpy(path, name, len);
2128
2129 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2130 return error;
2131
2132 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2133 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2134 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2135
2136 /*
2137 * The parent directory needs a sync
2138 */
2139 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2140
2141 #ifdef PERFUSE_DEBUG
2142 if (perfuse_diagflags & PDF_FILENAME)
2143 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2144 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2145 pcn->pcn_name);
2146 #endif
2147 ps->ps_destroy_msg(pm);
2148
2149 return 0;
2150 }
2151
2152 int
2153 perfuse_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
2154 puffs_cookie_t targ, const struct puffs_cn *pcn)
2155 {
2156 struct perfuse_state *ps;
2157 perfuse_msg_t *pm;
2158 const char *name;
2159 size_t len;
2160 struct puffs_node *pn;
2161 struct fuse_link_in *fli;
2162 int error;
2163
2164 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2165 return ENOENT;
2166
2167 ps = puffs_getspecific(pu);
2168 pn = (struct puffs_node *)targ;
2169 name = pcn->pcn_name;
2170 len = sizeof(*fli) + pcn->pcn_namelen + 1;
2171
2172 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, pcn->pcn_cred);
2173 fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
2174 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_nodeid;
2175 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
2176
2177 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2178 return error;
2179
2180 ps->ps_destroy_msg(pm);
2181
2182 return 0;
2183 }
2184
2185 int
2186 perfuse_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc,
2187 puffs_cookie_t src, const struct puffs_cn *pcn_src,
2188 puffs_cookie_t targ_dir, puffs_cookie_t targ,
2189 const struct puffs_cn *pcn_targ)
2190 {
2191 struct perfuse_state *ps;
2192 perfuse_msg_t *pm;
2193 struct fuse_rename_in *fri;
2194 const char *newname;
2195 const char *oldname;
2196 char *np;
2197 int error;
2198 size_t len;
2199 size_t newname_len;
2200 size_t oldname_len;
2201
2202 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) ||
2203 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) ||
2204 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED))
2205 return ENOENT;
2206
2207 /*
2208 * Await for all operations on the deleted node to drain,
2209 * as the filesystem may be confused to have it deleted
2210 * during a getattr
2211 */
2212 if ((struct puffs_node *)targ != NULL) {
2213 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2214 requeue_request(pu, targ, PCQ_AFTERXCHG);
2215 } else {
2216 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG)
2217 requeue_request(pu, src, PCQ_AFTERXCHG);
2218 }
2219
2220 ps = puffs_getspecific(pu);
2221 newname = pcn_targ->pcn_name;
2222 newname_len = pcn_targ->pcn_namelen + 1;
2223 oldname = pcn_src->pcn_name;
2224 oldname_len = pcn_src->pcn_namelen + 1;
2225
2226 len = sizeof(*fri) + oldname_len + newname_len;
2227 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, pcn_targ->pcn_cred);
2228 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
2229 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid;
2230 np = (char *)(void *)(fri + 1);
2231 (void)strlcpy(np, oldname, oldname_len);
2232 np += oldname_len;
2233 (void)strlcpy(np, newname, newname_len);
2234
2235 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2236 return error;
2237
2238 if (opc != targ_dir) {
2239 struct perfuse_node_data *srcdir_pnd;
2240 struct perfuse_node_data *dstdir_pnd;
2241 struct perfuse_node_data *src_pnd;
2242
2243 srcdir_pnd = PERFUSE_NODE_DATA(opc);
2244 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir);
2245 src_pnd = PERFUSE_NODE_DATA(src);
2246
2247 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next);
2248 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next);
2249
2250 srcdir_pnd->pnd_childcount--;
2251 dstdir_pnd->pnd_childcount++;
2252
2253 src_pnd->pnd_parent = targ_dir;
2254
2255 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY;
2256 }
2257
2258 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN);
2259
2260 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2261
2262 if ((struct puffs_node *)targ != NULL)
2263 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2264
2265 #ifdef PERFUSE_DEBUG
2266 if (perfuse_diagflags & PDF_FILENAME)
2267 DPRINTF("%s: nodeid = 0x%"PRIx64" file = \"%s\" renamed \"%s\" "
2268 "nodeid = 0x%"PRIx64" -> nodeid = 0x%"PRIx64" \"%s\"\n",
2269 __func__, PERFUSE_NODE_DATA(src)->pnd_nodeid,
2270 pcn_src->pcn_name, pcn_targ->pcn_name,
2271 PERFUSE_NODE_DATA(opc)->pnd_nodeid,
2272 PERFUSE_NODE_DATA(targ_dir)->pnd_nodeid,
2273 perfuse_node_path(targ_dir));
2274 #endif
2275
2276 ps->ps_destroy_msg(pm);
2277
2278 return 0;
2279 }
2280
2281 int
2282 perfuse_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
2283 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
2284 const struct vattr *vap)
2285 {
2286 struct perfuse_state *ps;
2287 perfuse_msg_t *pm;
2288 struct fuse_mkdir_in *fmi;
2289 const char *path;
2290 size_t len;
2291
2292 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2293 return ENOENT;
2294
2295 ps = puffs_getspecific(pu);
2296 path = pcn->pcn_name;
2297 len = sizeof(*fmi) + pcn->pcn_namelen + 1;
2298
2299 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, pcn->pcn_cred);
2300 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
2301 fmi->mode = vap->va_mode;
2302 fmi->umask = 0; /* Seems unused by libfuse? */
2303 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
2304
2305 return node_mk_common(pu, opc, pni, pcn, pm);
2306 }
2307
2308
2309 int
2310 perfuse_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
2311 puffs_cookie_t targ, const struct puffs_cn *pcn)
2312 {
2313 struct perfuse_state *ps;
2314 struct perfuse_node_data *pnd;
2315 perfuse_msg_t *pm;
2316 char *path;
2317 const char *name;
2318 size_t len;
2319 int error;
2320
2321 pnd = PERFUSE_NODE_DATA(opc);
2322
2323 if ((pnd->pnd_flags & PND_REMOVED) ||
2324 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
2325 return ENOENT;
2326
2327 /*
2328 * Await for all operations on the deleted node to drain,
2329 * as the filesystem may be confused to have it deleted
2330 * during a getattr
2331 */
2332 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2333 requeue_request(pu, targ, PCQ_AFTERXCHG);
2334
2335 ps = puffs_getspecific(pu);
2336 name = pcn->pcn_name;
2337 len = pcn->pcn_namelen + 1;
2338
2339 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
2340 path = _GET_INPAYLOAD(ps, pm, char *);
2341 (void)strlcpy(path, name, len);
2342
2343 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2344 return error;
2345
2346 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2347 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2348 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2349
2350 /*
2351 * The parent directory needs a sync
2352 */
2353 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2354
2355 #ifdef PERFUSE_DEBUG
2356 if (perfuse_diagflags & PDF_FILENAME)
2357 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2358 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2359 perfuse_node_path(targ));
2360 #endif
2361 ps->ps_destroy_msg(pm);
2362
2363 return 0;
2364 }
2365
2366 /* vap is unused */
2367 /* ARGSUSED4 */
2368 int
2369 perfuse_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
2370 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
2371 const struct vattr *vap, const char *link_target)
2372 {
2373 struct perfuse_state *ps;
2374 perfuse_msg_t *pm;
2375 char *np;
2376 const char *path;
2377 size_t path_len;
2378 size_t linkname_len;
2379 size_t len;
2380
2381 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2382 return ENOENT;
2383
2384 ps = puffs_getspecific(pu);
2385 path = pcn_src->pcn_name;
2386 path_len = pcn_src->pcn_namelen + 1;
2387 linkname_len = strlen(link_target) + 1;
2388 len = path_len + linkname_len;
2389
2390 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
2391 np = _GET_INPAYLOAD(ps, pm, char *);
2392 (void)strlcpy(np, path, path_len);
2393 np += path_len;
2394 (void)strlcpy(np, link_target, linkname_len);
2395
2396 return node_mk_common(pu, opc, pni, pcn_src, pm);
2397 }
2398
2399 /* ARGSUSED4 */
2400 int
2401 perfuse_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
2402 struct dirent *dent, off_t *readoff, size_t *reslen,
2403 const struct puffs_cred *pcr, int *eofflag, off_t *cookies,
2404 size_t *ncookies)
2405 {
2406 perfuse_msg_t *pm;
2407 uint64_t fh;
2408 struct perfuse_state *ps;
2409 struct perfuse_node_data *pnd;
2410 struct fuse_read_in *fri;
2411 struct fuse_out_header *foh;
2412 struct fuse_dirent *fd;
2413 size_t foh_len;
2414 int error;
2415 size_t fd_maxlen;
2416
2417 error = 0;
2418 ps = puffs_getspecific(pu);
2419
2420 /*
2421 * readdir state is kept at node level, and several readdir
2422 * requests can be issued at the same time on the same node.
2423 * We need to queue requests so that only one is in readdir
2424 * code at the same time.
2425 */
2426 pnd = PERFUSE_NODE_DATA(opc);
2427 while (pnd->pnd_flags & PND_INREADDIR)
2428 requeue_request(pu, opc, PCQ_READDIR);
2429 pnd->pnd_flags |= PND_INREADDIR;
2430
2431 #ifdef PERFUSE_DEBUG
2432 if (perfuse_diagflags & PDF_READDIR)
2433 DPRINTF("%s: READDIR opc = %p enter critical section\n",
2434 __func__, (void *)opc);
2435 #endif
2436 /*
2437 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node
2438 */
2439 if (*readoff == 0)
2440 pnd->pnd_fd_cookie = 0;
2441
2442 /*
2443 * Do we already have the data bufered?
2444 */
2445 if (pnd->pnd_dirent != NULL)
2446 goto out;
2447 pnd->pnd_dirent_len = 0;
2448
2449 /*
2450 * It seems NetBSD can call readdir without open first
2451 * libfuse will crash if it is done that way, hence open first.
2452 */
2453 if (!(pnd->pnd_flags & PND_OPEN)) {
2454 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2455 goto out;
2456 }
2457
2458 fh = perfuse_get_fh(opc, FREAD);
2459
2460 #ifdef PERFUSE_DEBUG
2461 if (perfuse_diagflags & PDF_FH)
2462 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
2463 "rfh = 0x%"PRIx64"\n", __func__, (void *)opc,
2464 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh);
2465 #endif
2466
2467 pnd->pnd_all_fd = NULL;
2468 pnd->pnd_all_fd_len = 0;
2469 fd_maxlen = ps->ps_max_readahead - sizeof(*foh);
2470
2471 do {
2472 size_t fd_len;
2473 char *afdp;
2474
2475 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
2476
2477 /*
2478 * read_flags, lock_owner and flags are unused in libfuse
2479 */
2480 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2481 fri->fh = fh;
2482 fri->offset = pnd->pnd_fd_cookie;
2483 fri->size = (uint32_t)fd_maxlen;
2484 fri->read_flags = 0;
2485 fri->lock_owner = 0;
2486 fri->flags = 0;
2487
2488 if ((error = xchg_msg(pu, opc, pm,
2489 UNSPEC_REPLY_LEN, wait_reply)) != 0)
2490 goto out;
2491
2492 /*
2493 * There are many puffs_framebufs calls later,
2494 * therefore foh will not be valid for a long time.
2495 * Just get the length and forget it.
2496 */
2497 foh = GET_OUTHDR(ps, pm);
2498 foh_len = foh->len;
2499
2500 /*
2501 * Empty read: we reached the end of the buffer.
2502 */
2503 if (foh_len == sizeof(*foh)) {
2504 ps->ps_destroy_msg(pm);
2505 *eofflag = 1;
2506 break;
2507 }
2508
2509 /*
2510 * Check for corrupted message.
2511 */
2512 if (foh_len < sizeof(*foh) + sizeof(*fd)) {
2513 ps->ps_destroy_msg(pm);
2514 DWARNX("readdir reply too short");
2515 error = EIO;
2516 goto out;
2517 }
2518
2519
2520 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
2521 fd_len = foh_len - sizeof(*foh);
2522
2523 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
2524 pnd->pnd_all_fd_len + fd_len);
2525 if (pnd->pnd_all_fd == NULL)
2526 DERR(EX_OSERR, "%s: malloc failed", __func__);
2527
2528 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
2529 (void)memcpy(afdp, fd, fd_len);
2530
2531 pnd->pnd_all_fd_len += fd_len;
2532
2533 /*
2534 * The fd->off field is used as a cookie for
2535 * resuming the next readdir() where this one was left.
2536 */
2537 pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len);
2538
2539 ps->ps_destroy_msg(pm);
2540 } while (1 /* CONSTCOND */);
2541
2542 if (pnd->pnd_all_fd != NULL) {
2543 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd,
2544 pnd->pnd_all_fd_len) == -1)
2545 error = EIO;
2546 }
2547
2548 out:
2549 if (pnd->pnd_all_fd != NULL) {
2550 free(pnd->pnd_all_fd);
2551 pnd->pnd_all_fd = NULL;
2552 pnd->pnd_all_fd_len = 0;
2553 }
2554
2555 if (error == 0)
2556 error = readdir_buffered(opc, dent, readoff, reslen);
2557
2558 /*
2559 * Schedule queued readdir requests
2560 */
2561 pnd->pnd_flags &= ~PND_INREADDIR;
2562 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
2563
2564 #ifdef PERFUSE_DEBUG
2565 if (perfuse_diagflags & PDF_READDIR)
2566 DPRINTF("%s: READDIR opc = %p exit critical section\n",
2567 __func__, (void *)opc);
2568 #endif
2569
2570 return error;
2571 }
2572
2573 int
2574 perfuse_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
2575 const struct puffs_cred *pcr, char *linkname, size_t *linklen)
2576 {
2577 struct perfuse_state *ps;
2578 perfuse_msg_t *pm;
2579 int error;
2580 size_t len;
2581 struct fuse_out_header *foh;
2582
2583 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2584 return ENOENT;
2585
2586 ps = puffs_getspecific(pu);
2587
2588 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
2589
2590 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2591 return error;
2592
2593 foh = GET_OUTHDR(ps, pm);
2594 len = foh->len - sizeof(*foh);
2595 if (len > *linklen)
2596 DERRX(EX_PROTOCOL, "path len = %zd too long", len);
2597 if (len == 0)
2598 DERRX(EX_PROTOCOL, "path len = %zd too short", len);
2599
2600 /*
2601 * FUSE filesystems return a NUL terminated string, we
2602 * do not want to trailing \0
2603 */
2604 *linklen = len - 1;
2605 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
2606
2607 ps->ps_destroy_msg(pm);
2608
2609 return 0;
2610 }
2611
2612 int
2613 perfuse_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc)
2614 {
2615 struct perfuse_state *ps;
2616 perfuse_msg_t *pm;
2617 struct perfuse_node_data *pnd;
2618 struct fuse_forget_in *ffi;
2619 struct puffs_node *pn;
2620 struct puffs_node *pn_root;
2621
2622 if (opc == 0)
2623 return 0;
2624
2625 ps = puffs_getspecific(pu);
2626 pnd = PERFUSE_NODE_DATA(opc);
2627
2628 /*
2629 * Never forget the root.
2630 */
2631 if (pnd->pnd_nodeid == FUSE_ROOT_ID)
2632 return 0;
2633
2634 pnd->pnd_flags |= PND_RECLAIMED;
2635 pnd->pnd_puffs_nlookup--;
2636
2637 #ifdef PERFUSE_DEBUG
2638 if (perfuse_diagflags & PDF_RECLAIM)
2639 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2640 perfuse_node_path(opc), pnd->pnd_nodeid);
2641 #endif
2642
2643 pn_root = puffs_getroot(pu);
2644 pn = (struct puffs_node *)opc;
2645 while (pn != pn_root) {
2646 struct puffs_node *parent_pn;
2647
2648 pnd = PERFUSE_NODE_DATA(pn);
2649
2650 #ifdef PERFUSE_DEBUG
2651 if (perfuse_diagflags & PDF_RECLAIM)
2652 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, nlookup = %d "
2653 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n",
2654 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_nodeid,
2655 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2656 pnd->pnd_puffs_nlookup, pnd->pnd_childcount,
2657 pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2658 pnd->pnd_flags & PND_RFH ? "r" : "",
2659 pnd->pnd_flags & PND_WFH ? "w" : "",
2660 pnd->pnd_flags & PND_BUSY ? "" : " none",
2661 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2662 pnd->pnd_flags & PND_INWRITE ? " write" : "",
2663 pnd->pnd_flags & PND_INOPEN ? " open" : "");
2664 #endif
2665 if (!(pnd->pnd_flags & PND_RECLAIMED) ||
2666 (pnd->pnd_childcount != 0))
2667 return 0;
2668
2669 /*
2670 * lookup/reclaim activity differs whether name cache
2671 * is used or not.
2672 * - With namecache off, we get as many reclaims as lookups,
2673 * we therefore must keep track of pnd_puffs_nlookup
2674 * - With namecache on we have a single
2675 * reclaim for any amount of lookups. We therfore
2676 * ignore pnd_puffs_nlookup. On netbsd-5 there is a
2677 * bug and this behavior occurs whatever cache setting
2678 * we have.
2679 */
2680 #if !defined(PUFFS_KFLAG_CACHE_FS_TTL) && __NetBSD_Prereq__(5,99,0)
2681 if (pnd->pnd_puffs_nlookup != 0)
2682 return 0;
2683 #endif /* !PUFFS_KFLAG_CACHE_FS_TTL && NetBSD > 5.99.0 */
2684
2685 #ifdef PERFUSE_DEBUG
2686 if ((pnd->pnd_flags & PND_OPEN) ||
2687 !TAILQ_EMPTY(&pnd->pnd_pcq))
2688 DERRX(EX_SOFTWARE, "%s: opc = %p: still open",
2689 __func__, (void *)opc);
2690
2691 if ((pnd->pnd_flags & PND_BUSY) ||
2692 !TAILQ_EMPTY(&pnd->pnd_pcq))
2693 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
2694 __func__, (void *)opc);
2695 #endif
2696
2697 /*
2698 * Send the FORGET message
2699 *
2700 * ps_new_msg() is called with NULL creds, which will
2701 * be interpreted as FUSE superuser. This is obviously
2702 * fine since we operate with kernel creds here.
2703 */
2704 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
2705 sizeof(*ffi), NULL);
2706 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2707 ffi->nlookup = pnd->pnd_fuse_nlookup;
2708
2709 /*
2710 * No reply is expected, pm is freed in xchg_msg
2711 */
2712 (void)xchg_msg(pu, (puffs_cookie_t)pn,
2713 pm, UNSPEC_REPLY_LEN, no_reply);
2714
2715 parent_pn = pnd->pnd_parent;
2716
2717 perfuse_destroy_pn(pn);
2718
2719 pn = parent_pn;
2720 }
2721
2722 return 0;
2723 }
2724
2725 int
2726 perfuse_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
2727 {
2728 struct perfuse_state *ps;
2729 struct perfuse_node_data *pnd;
2730 int error;
2731
2732 if (opc == 0)
2733 return 0;
2734
2735 ps = puffs_getspecific(pu);
2736 pnd = PERFUSE_NODE_DATA(opc);
2737
2738 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED)))
2739 return 0;
2740
2741 /*
2742 * Make sure all operation are finished
2743 * There can be an ongoing write. Other
2744 * operation wait for all data before
2745 * the close/inactive.
2746 */
2747 while (pnd->pnd_flags & PND_INWRITE)
2748 requeue_request(pu, opc, PCQ_AFTERWRITE);
2749
2750 /*
2751 * The inactive operation may be cancelled,
2752 * If no open is in progress, set PND_INOPEN
2753 * so that a new open will be queued.
2754 */
2755 if (pnd->pnd_flags & PND_INOPEN)
2756 return 0;
2757
2758 pnd->pnd_flags |= PND_INOPEN;
2759
2760 /*
2761 * Sync data
2762 */
2763 if (pnd->pnd_flags & PND_DIRTY) {
2764 if ((error = perfuse_node_fsync(pu, opc, NULL, 0, 0, 0)) != 0)
2765 DWARN("%s: perfuse_node_fsync failed error = %d",
2766 __func__, error);
2767 }
2768
2769
2770 /*
2771 * Close handles
2772 */
2773 if (pnd->pnd_flags & PND_WFH) {
2774 if ((error = perfuse_node_close_common(pu, opc, FWRITE)) != 0)
2775 DWARN("%s: close write FH failed error = %d",
2776 __func__, error);
2777 }
2778
2779 if (pnd->pnd_flags & PND_RFH) {
2780 if ((error = perfuse_node_close_common(pu, opc, FREAD)) != 0)
2781 DWARN("%s: close read FH failed error = %d",
2782 __func__, error);
2783 }
2784
2785 /*
2786 * This will cause a reclaim to be sent
2787 */
2788 if (pnd->pnd_flags & PND_REMOVED)
2789 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
2790
2791 /*
2792 * Schedule awaiting operations
2793 */
2794 pnd->pnd_flags &= ~PND_INOPEN;
2795 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
2796
2797 return 0;
2798 }
2799
2800
2801 /* ARGSUSED0 */
2802 int
2803 perfuse_node_print(struct puffs_usermount *pu, puffs_cookie_t opc)
2804 {
2805 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2806 return 0;
2807 }
2808
2809 /* ARGSUSED0 */
2810 int
2811 perfuse_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc,
2812 int name, int *retval)
2813 {
2814 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2815 return 0;
2816 }
2817
2818 int
2819 perfuse_node_advlock(struct puffs_usermount *pu, puffs_cookie_t opc,
2820 void *id, int op, struct flock *fl, int flags)
2821 {
2822 struct perfuse_state *ps;
2823 int fop;
2824 perfuse_msg_t *pm;
2825 uint64_t fh;
2826 struct fuse_lk_in *fli;
2827 struct fuse_out_header *foh;
2828 struct fuse_lk_out *flo;
2829 uint32_t owner;
2830 size_t len;
2831 int error;
2832
2833 /*
2834 * Make sure we do have a filehandle, as the FUSE filesystem
2835 * expect one. E.g.: if we provide none, GlusterFS logs an error
2836 * "0-glusterfs-fuse: xl is NULL"
2837 *
2838 * We need the read file handle if the file is open read only,
2839 * in order to support shared locks on read-only files.
2840 * NB: The kernel always sends advlock for read-only
2841 * files at exit time when the process used lock, see
2842 * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK
2843 */
2844 if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH)
2845 return EBADF;
2846
2847 ps = puffs_getspecific(pu);
2848
2849 if (op == F_GETLK)
2850 fop = FUSE_GETLK;
2851 else
2852 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2853
2854 /*
2855 * XXX ps_new_msg() is called with NULL creds, which will
2856 * be interpreted as FUSE superuser. We have no way to
2857 * know the requesting process' credential, but since advlock()
2858 * is supposed to operate on a file that has been open(),
2859 * permission should have already been checked at open() time.
2860 */
2861 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2862 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2863 fli->fh = fh;
2864 fli->owner = (uint64_t)(vaddr_t)id;
2865 fli->lk.start = fl->l_start;
2866 fli->lk.end = fl->l_start + fl->l_len;
2867 fli->lk.type = fl->l_type;
2868 fli->lk.pid = fl->l_pid;
2869 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
2870
2871 owner = (uint32_t)(vaddr_t)id;
2872
2873 #ifdef PERFUSE_DEBUG
2874 if (perfuse_diagflags & PDF_FH)
2875 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2876 __func__, (void *)opc,
2877 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh);
2878 #endif
2879
2880 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2881 return error;
2882
2883 foh = GET_OUTHDR(ps, pm);
2884 len = foh->len - sizeof(*foh);
2885
2886 /*
2887 * Save or clear the lock
2888 */
2889 switch (op) {
2890 case F_GETLK:
2891 if (len != sizeof(*flo))
2892 DERRX(EX_SOFTWARE,
2893 "%s: Unexpected lock reply len %zd",
2894 __func__, len);
2895
2896 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
2897 fl->l_start = flo->lk.start;
2898 fl->l_len = flo->lk.end - flo->lk.start;
2899 fl->l_pid = flo->lk.pid;
2900 fl->l_type = flo->lk.type;
2901 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */
2902
2903 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
2904 break;
2905 case F_UNLCK:
2906 owner = 0;
2907 /* FALLTHROUGH */
2908 case F_SETLK:
2909 /* FALLTHROUGH */
2910 case F_SETLKW:
2911 if (error != 0)
2912 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner;
2913
2914 if (len != 0)
2915 DERRX(EX_SOFTWARE,
2916 "%s: Unexpected unlock reply len %zd",
2917 __func__, len);
2918
2919 break;
2920 default:
2921 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op);
2922 break;
2923 }
2924
2925 ps->ps_destroy_msg(pm);
2926
2927 return 0;
2928 }
2929
2930 int
2931 perfuse_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf,
2932 off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
2933 {
2934 struct perfuse_state *ps;
2935 struct perfuse_node_data *pnd;
2936 const struct vattr *vap;
2937 perfuse_msg_t *pm;
2938 struct fuse_read_in *fri;
2939 struct fuse_out_header *foh;
2940 size_t readen;
2941 int error;
2942
2943 ps = puffs_getspecific(pu);
2944 pnd = PERFUSE_NODE_DATA(opc);
2945 vap = puffs_pn_getvap((struct puffs_node *)opc);
2946
2947 /*
2948 * NetBSD turns that into a getdents(2) output
2949 * We just do a EISDIR as this feature is of little use.
2950 */
2951 if (vap->va_type == VDIR)
2952 return EISDIR;
2953
2954 if ((u_quad_t)offset + *resid > vap->va_size)
2955 DWARNX("%s %p read %lld@%zu beyond EOF %" PRIu64 "\n",
2956 __func__, (void *)opc, (long long)offset,
2957 *resid, vap->va_size);
2958
2959 do {
2960 size_t max_read;
2961
2962 max_read = ps->ps_max_readahead - sizeof(*foh);
2963 /*
2964 * flags may be set to FUSE_READ_LOCKOWNER
2965 * if lock_owner is provided.
2966 */
2967 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
2968 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2969 fri->fh = perfuse_get_fh(opc, FREAD);
2970 fri->offset = offset;
2971 fri->size = (uint32_t)MIN(*resid, max_read);
2972 fri->read_flags = 0; /* XXX Unused by libfuse? */
2973 fri->lock_owner = pnd->pnd_lock_owner;
2974 fri->flags = 0;
2975 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
2976
2977 #ifdef PERFUSE_DEBUG
2978 if (perfuse_diagflags & PDF_FH)
2979 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
2980 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
2981 #endif
2982 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
2983 if (error != 0)
2984 return error;
2985
2986 foh = GET_OUTHDR(ps, pm);
2987 readen = foh->len - sizeof(*foh);
2988
2989 #ifdef PERFUSE_DEBUG
2990 if (readen > *resid)
2991 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd",
2992 __func__, readen);
2993 #endif
2994
2995 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
2996
2997 buf += readen;
2998 offset += readen;
2999 *resid -= readen;
3000
3001 ps->ps_destroy_msg(pm);
3002 } while ((*resid != 0) && (readen != 0));
3003
3004 if (ioflag & (IO_SYNC|IO_DSYNC))
3005 ps->ps_syncreads++;
3006 else
3007 ps->ps_asyncreads++;
3008
3009 return 0;
3010 }
3011
3012 int
3013 perfuse_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf,
3014 off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
3015 {
3016 struct perfuse_state *ps;
3017 struct perfuse_node_data *pnd;
3018 struct vattr *vap;
3019 perfuse_msg_t *pm;
3020 struct fuse_write_in *fwi;
3021 struct fuse_write_out *fwo;
3022 size_t data_len;
3023 size_t payload_len;
3024 size_t written;
3025 int inresize;
3026 int error;
3027
3028 ps = puffs_getspecific(pu);
3029 pnd = PERFUSE_NODE_DATA(opc);
3030 vap = puffs_pn_getvap((struct puffs_node *)opc);
3031 written = 0;
3032 inresize = 0;
3033 error = 0;
3034
3035 if (vap->va_type == VDIR)
3036 return EISDIR;
3037
3038 /*
3039 * We need to queue write requests in order to avoid
3040 * dequeueing PCQ_AFTERWRITE when there are pending writes.
3041 */
3042 while (pnd->pnd_flags & PND_INWRITE)
3043 requeue_request(pu, opc, PCQ_WRITE);
3044 pnd->pnd_flags |= PND_INWRITE;
3045
3046 /*
3047 * Serialize size access, see comment in perfuse_node_setattr().
3048 */
3049 if ((u_quad_t)offset + *resid > vap->va_size) {
3050 while (pnd->pnd_flags & PND_INRESIZE)
3051 requeue_request(pu, opc, PCQ_RESIZE);
3052 pnd->pnd_flags |= PND_INRESIZE;
3053 inresize = 1;
3054 }
3055
3056 /*
3057 * append flag: re-read the file size so that
3058 * we get the latest value.
3059 */
3060 if (ioflag & PUFFS_IO_APPEND) {
3061 DWARNX("%s: PUFFS_IO_APPEND set, untested code", __func__);
3062
3063 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0)
3064 goto out;
3065
3066 offset = vap->va_size;
3067 }
3068
3069 #ifdef PERFUSE_DEBUG
3070 if (perfuse_diagflags & PDF_RESIZE)
3071 DPRINTF(">> %s %p %" PRIu64 "\n", __func__,
3072 (void *)opc, vap->va_size);
3073 #endif
3074
3075 do {
3076 size_t max_write;
3077 /*
3078 * There is a writepage flag when data
3079 * is aligned to page size. Use it for
3080 * everything but the data after the last
3081 * page boundary.
3082 */
3083 max_write = ps->ps_max_write - sizeof(*fwi);
3084
3085 data_len = MIN(*resid, max_write);
3086 if (data_len > (size_t)sysconf(_SC_PAGESIZE))
3087 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1);
3088
3089 payload_len = data_len + sizeof(*fwi);
3090
3091 /*
3092 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
3093 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
3094 * write_flags is set to 1 for writepage.
3095 */
3096 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
3097 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
3098 fwi->fh = perfuse_get_fh(opc, FWRITE);
3099 fwi->offset = offset;
3100 fwi->size = (uint32_t)data_len;
3101 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1;
3102 fwi->lock_owner = pnd->pnd_lock_owner;
3103 fwi->flags = 0;
3104 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
3105 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
3106 (void)memcpy((fwi + 1), buf, data_len);
3107
3108
3109 #ifdef PERFUSE_DEBUG
3110 if (perfuse_diagflags & PDF_FH)
3111 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
3112 "fh = 0x%"PRIx64"\n", __func__,
3113 (void *)opc, pnd->pnd_nodeid, fwi->fh);
3114 #endif
3115 if ((error = xchg_msg(pu, opc, pm,
3116 sizeof(*fwo), wait_reply)) != 0)
3117 goto out;
3118
3119 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
3120 written = fwo->size;
3121 #ifdef PERFUSE_DEBUG
3122 if (written > *resid)
3123 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd",
3124 __func__, written);
3125 #endif
3126 *resid -= written;
3127 offset += written;
3128 buf += written;
3129
3130 ps->ps_destroy_msg(pm);
3131 } while (*resid != 0);
3132
3133 /*
3134 * puffs_ops(3) says
3135 * "everything must be written or an error will be generated"
3136 */
3137 if (*resid != 0)
3138 error = EFBIG;
3139
3140 #ifdef PERFUSE_DEBUG
3141 if (perfuse_diagflags & PDF_RESIZE) {
3142 if (offset > (off_t)vap->va_size)
3143 DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__,
3144 (void *)opc, vap->va_size, (long long)offset);
3145 else
3146 DPRINTF("<< %s %p \n", __func__, (void *)opc);
3147 }
3148 #endif
3149
3150 /*
3151 * Update file size if we wrote beyond the end
3152 */
3153 if (offset > (off_t)vap->va_size)
3154 vap->va_size = offset;
3155
3156 if (inresize) {
3157 #ifdef PERFUSE_DEBUG
3158 if (!(pnd->pnd_flags & PND_INRESIZE))
3159 DERRX(EX_SOFTWARE, "file write grow without resize");
3160 #endif
3161 pnd->pnd_flags &= ~PND_INRESIZE;
3162 (void)dequeue_requests(ps, opc, PCQ_RESIZE, DEQUEUE_ALL);
3163 }
3164
3165
3166 /*
3167 * Statistics
3168 */
3169 if (ioflag & (IO_SYNC|IO_DSYNC))
3170 ps->ps_syncwrites++;
3171 else
3172 ps->ps_asyncwrites++;
3173
3174 /*
3175 * Remember to sync the file
3176 */
3177 pnd->pnd_flags |= PND_DIRTY;
3178
3179 #ifdef PERFUSE_DEBUG
3180 if (perfuse_diagflags & PDF_SYNC)
3181 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
3182 __func__, (void*)opc, perfuse_node_path(opc));
3183 #endif
3184
3185 out:
3186 /*
3187 * If there are no more queued write, we can resume
3188 * an operation awaiting write completion.
3189 */
3190 pnd->pnd_flags &= ~PND_INWRITE;
3191 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0)
3192 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
3193
3194 return error;
3195 }
3196
3197 /* ARGSUSED0 */
3198 void
3199 perfuse_cache_write(struct puffs_usermount *pu, puffs_cookie_t opc, size_t size,
3200 struct puffs_cacherun *runs)
3201 {
3202 return;
3203 }
3204
3205 /* ARGSUSED4 */
3206 int
3207 perfuse_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3208 int attrns, const char *attrname, size_t *attrsize, uint8_t *attr,
3209 size_t *resid, const struct puffs_cred *pcr)
3210 {
3211 struct perfuse_state *ps;
3212 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3213 perfuse_msg_t *pm;
3214 struct fuse_getxattr_in *fgi;
3215 struct fuse_getxattr_out *fgo;
3216 struct fuse_out_header *foh;
3217 size_t attrnamelen;
3218 size_t len;
3219 char *np;
3220 int error;
3221
3222 ps = puffs_getspecific(pu);
3223 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3224 attrnamelen = strlen(attrname) + 1;
3225 len = sizeof(*fgi) + attrnamelen;
3226
3227 pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr);
3228 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3229 fgi->size = (unsigned int)((resid != NULL) ? *resid : 0);
3230 np = (char *)(void *)(fgi + 1);
3231 (void)strlcpy(np, attrname, attrnamelen);
3232
3233 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3234 return error;
3235
3236 /*
3237 * We just get fuse_getattr_out with list size if we requested
3238 * a null size.
3239 */
3240 if (resid == NULL) {
3241 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3242
3243 if (attrsize != NULL)
3244 *attrsize = fgo->size;
3245
3246 ps->ps_destroy_msg(pm);
3247 return 0;
3248 }
3249
3250 /*
3251 * And with a non null requested size, we get the list just
3252 * after the header
3253 */
3254 foh = GET_OUTHDR(ps, pm);
3255 np = (char *)(void *)(foh + 1);
3256
3257 if (resid != NULL) {
3258 len = MAX(foh->len - sizeof(*foh), *resid);
3259 (void)memcpy(attr, np, len);
3260 *resid -= len;
3261 }
3262
3263 ps->ps_destroy_msg(pm);
3264
3265 return 0;
3266 }
3267
3268 int
3269 perfuse_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3270 int attrns, const char *attrname, uint8_t *attr, size_t *resid,
3271 const struct puffs_cred *pcr)
3272 {
3273 struct perfuse_state *ps;
3274 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3275 perfuse_msg_t *pm;
3276 struct fuse_setxattr_in *fsi;
3277 size_t attrnamelen;
3278 size_t len;
3279 char *np;
3280 int error;
3281
3282 ps = puffs_getspecific(pu);
3283 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3284 attrnamelen = strlen(attrname) + 1;
3285 len = sizeof(*fsi) + attrnamelen + *resid;
3286
3287 pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr);
3288 fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in);
3289 fsi->size = (unsigned int)*resid;
3290 fsi->flags = 0;
3291 np = (char *)(void *)(fsi + 1);
3292 (void)strlcpy(np, attrname, attrnamelen);
3293 np += attrnamelen;
3294 (void)memcpy(np, (char *)attr, *resid);
3295
3296 if ((error = xchg_msg(pu, opc, pm,
3297 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
3298 return error;
3299
3300 *resid = 0;
3301 ps->ps_destroy_msg(pm);
3302
3303 return 0;
3304 }
3305
3306 /* ARGSUSED2 */
3307 int
3308 perfuse_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3309 int attrns, size_t *attrsize, uint8_t *attrs, size_t *resid, int flag,
3310 const struct puffs_cred *pcr)
3311 {
3312 struct perfuse_state *ps;
3313 perfuse_msg_t *pm;
3314 struct fuse_getxattr_in *fgi;
3315 struct fuse_getxattr_out *fgo;
3316 struct fuse_out_header *foh;
3317 char *np;
3318 size_t len, puffs_len;
3319 int error;
3320
3321 ps = puffs_getspecific(pu);
3322 len = sizeof(*fgi);
3323
3324 pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr);
3325 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3326 if (resid != NULL)
3327 fgi->size = (unsigned int)*resid;
3328 else
3329 fgi->size = 0;
3330
3331 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3332 return error;
3333
3334 /*
3335 * We just get fuse_getattr_out with list size if we requested
3336 * a null size.
3337 */
3338 if (resid == NULL) {
3339 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3340
3341 if (attrsize != NULL)
3342 *attrsize = fgo->size;
3343
3344 ps->ps_destroy_msg(pm);
3345
3346 return 0;
3347 }
3348
3349 /*
3350 * And with a non null requested size, we get the list just
3351 * after the header
3352 */
3353 foh = GET_OUTHDR(ps, pm);
3354 np = (char *)(void *)(foh + 1);
3355 puffs_len = foh->len - sizeof(*foh);
3356
3357 if (attrs != NULL) {
3358 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX
3359 /*
3360 * Convert the FUSE reply to length prefixed strings
3361 * if this is what the kernel wants.
3362 */
3363 if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) {
3364 size_t i, attrlen;
3365
3366 for (i = 0; i < puffs_len; i += attrlen + 1) {
3367 attrlen = strlen(np + i);
3368 (void)memmove(np + i + 1, np + i, attrlen);
3369 *(np + i) = (uint8_t)attrlen;
3370 }
3371 }
3372 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */
3373 (void)memcpy(attrs, np, puffs_len);
3374 *resid -= puffs_len;
3375 }
3376
3377 if (attrsize != NULL)
3378 *attrsize = puffs_len;
3379
3380 ps->ps_destroy_msg(pm);
3381
3382 return 0;
3383 }
3384
3385 int
3386 perfuse_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3387 int attrns, const char *attrname, const struct puffs_cred *pcr)
3388 {
3389 struct perfuse_state *ps;
3390 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3391 perfuse_msg_t *pm;
3392 size_t attrnamelen;
3393 char *np;
3394 int error;
3395
3396 ps = puffs_getspecific(pu);
3397 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3398 attrnamelen = strlen(attrname) + 1;
3399
3400 pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr);
3401 np = _GET_INPAYLOAD(ps, pm, char *);
3402 (void)strlcpy(np, attrname, attrnamelen);
3403
3404 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
3405
3406 ps->ps_destroy_msg(pm);
3407
3408 return error;
3409 }
3410