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