ops.c revision 1.50.2.13 1 /* $NetBSD: ops.c,v 1.50.2.13 2014/11/04 01:52:53 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 /*
2346 * Attempt to rmdir dir/.. shoud raise ENOTEMPTY
2347 */
2348 if (PERFUSE_NODE_DATA(targ)->pnd_nodeid == pnd->pnd_parent_nodeid)
2349 return ENOTEMPTY;
2350
2351 node_ref(opc);
2352 node_ref(targ);
2353
2354 /*
2355 * Await for all operations on the deleted node to drain,
2356 * as the filesystem may be confused to have it deleted
2357 * during a getattr
2358 */
2359 while (PERFUSE_NODE_DATA(targ)->pnd_inxchg)
2360 requeue_request(pu, targ, PCQ_AFTERXCHG);
2361
2362 ps = puffs_getspecific(pu);
2363 name = pcn->pcn_name;
2364 len = pcn->pcn_namelen + 1;
2365
2366 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, pcn->pcn_cred);
2367 path = _GET_INPAYLOAD(ps, pm, char *);
2368 (void)strlcpy(path, name, len);
2369
2370 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2371 goto out;
2372
2373 perfuse_cache_flush(targ);
2374 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2375
2376 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2377 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2378
2379 /*
2380 * The parent directory needs a sync
2381 */
2382 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2383
2384 #ifdef PERFUSE_DEBUG
2385 if (perfuse_diagflags & PDF_FILENAME)
2386 DPRINTF("%s: remove nodeid = 0x%"PRIx64" file = \"%s\"\n",
2387 __func__, PERFUSE_NODE_DATA(targ)->pnd_nodeid,
2388 perfuse_node_path(ps, targ));
2389 #endif
2390 ps->ps_destroy_msg(pm);
2391 error = 0;
2392
2393 out:
2394 node_rele(opc);
2395 node_rele(targ);
2396 return error;
2397 }
2398
2399 /* vap is unused */
2400 /* ARGSUSED4 */
2401 int
2402 perfuse_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
2403 struct puffs_newinfo *pni, const struct puffs_cn *pcn_src,
2404 const struct vattr *vap, const char *link_target)
2405 {
2406 struct perfuse_state *ps;
2407 perfuse_msg_t *pm;
2408 char *np;
2409 const char *path;
2410 size_t path_len;
2411 size_t linkname_len;
2412 size_t len;
2413 int error;
2414
2415 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2416 return ENOENT;
2417
2418 node_ref(opc);
2419 ps = puffs_getspecific(pu);
2420 path = pcn_src->pcn_name;
2421 path_len = pcn_src->pcn_namelen + 1;
2422 linkname_len = strlen(link_target) + 1;
2423 len = path_len + linkname_len;
2424
2425 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, pcn_src->pcn_cred);
2426 np = _GET_INPAYLOAD(ps, pm, char *);
2427 (void)strlcpy(np, path, path_len);
2428 np += path_len;
2429 (void)strlcpy(np, link_target, linkname_len);
2430
2431 error = node_mk_common(pu, opc, pni, pcn_src, pm);
2432
2433 node_rele(opc);
2434 return error;
2435 }
2436
2437 /* ARGSUSED4 */
2438 int
2439 perfuse_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
2440 struct dirent *dent, off_t *readoff, size_t *reslen,
2441 const struct puffs_cred *pcr, int *eofflag, off_t *cookies,
2442 size_t *ncookies)
2443 {
2444 perfuse_msg_t *pm;
2445 uint64_t fh;
2446 struct perfuse_state *ps;
2447 struct perfuse_node_data *pnd;
2448 struct fuse_read_in *fri;
2449 struct fuse_out_header *foh;
2450 struct fuse_dirent *fd;
2451 size_t foh_len;
2452 int error;
2453 size_t fd_maxlen;
2454
2455 error = 0;
2456 node_ref(opc);
2457 ps = puffs_getspecific(pu);
2458
2459 /*
2460 * readdir state is kept at node level, and several readdir
2461 * requests can be issued at the same time on the same node.
2462 * We need to queue requests so that only one is in readdir
2463 * code at the same time.
2464 */
2465 pnd = PERFUSE_NODE_DATA(opc);
2466 while (pnd->pnd_flags & PND_INREADDIR)
2467 requeue_request(pu, opc, PCQ_READDIR);
2468 pnd->pnd_flags |= PND_INREADDIR;
2469
2470 #ifdef PERFUSE_DEBUG
2471 if (perfuse_diagflags & PDF_READDIR)
2472 DPRINTF("%s: READDIR opc = %p enter critical section\n",
2473 __func__, (void *)opc);
2474 #endif
2475 /*
2476 * Re-initialize pnd->pnd_fd_cookie on the first readdir for a node
2477 */
2478 if (*readoff == 0)
2479 pnd->pnd_fd_cookie = 0;
2480
2481 /*
2482 * Do we already have the data bufered?
2483 */
2484 if (pnd->pnd_dirent != NULL)
2485 goto out;
2486 pnd->pnd_dirent_len = 0;
2487
2488 /*
2489 * It seems NetBSD can call readdir without open first
2490 * libfuse will crash if it is done that way, hence open first.
2491 */
2492 if (!(pnd->pnd_flags & PND_OPEN)) {
2493 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2494 goto out;
2495 }
2496
2497 fh = perfuse_get_fh(opc, FREAD);
2498
2499 #ifdef PERFUSE_DEBUG
2500 if (perfuse_diagflags & PDF_FH)
2501 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
2502 "rfh = 0x%"PRIx64"\n", __func__, (void *)opc,
2503 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fh);
2504 #endif
2505
2506 pnd->pnd_all_fd = NULL;
2507 pnd->pnd_all_fd_len = 0;
2508 fd_maxlen = ps->ps_max_readahead - sizeof(*foh);
2509
2510 do {
2511 size_t fd_len;
2512 char *afdp;
2513
2514 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
2515
2516 /*
2517 * read_flags, lock_owner and flags are unused in libfuse
2518 */
2519 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2520 fri->fh = fh;
2521 fri->offset = pnd->pnd_fd_cookie;
2522 fri->size = (uint32_t)fd_maxlen;
2523 fri->read_flags = 0;
2524 fri->lock_owner = 0;
2525 fri->flags = 0;
2526
2527 if ((error = xchg_msg(pu, opc, pm,
2528 UNSPEC_REPLY_LEN, wait_reply)) != 0)
2529 goto out;
2530
2531 /*
2532 * There are many puffs_framebufs calls later,
2533 * therefore foh will not be valid for a long time.
2534 * Just get the length and forget it.
2535 */
2536 foh = GET_OUTHDR(ps, pm);
2537 foh_len = foh->len;
2538
2539 /*
2540 * Empty read: we reached the end of the buffer.
2541 */
2542 if (foh_len == sizeof(*foh)) {
2543 ps->ps_destroy_msg(pm);
2544 *eofflag = 1;
2545 break;
2546 }
2547
2548 /*
2549 * Check for corrupted message.
2550 */
2551 if (foh_len < sizeof(*foh) + sizeof(*fd)) {
2552 ps->ps_destroy_msg(pm);
2553 DWARNX("readdir reply too short");
2554 error = EIO;
2555 goto out;
2556 }
2557
2558
2559 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
2560 fd_len = foh_len - sizeof(*foh);
2561
2562 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
2563 pnd->pnd_all_fd_len + fd_len);
2564 if (pnd->pnd_all_fd == NULL)
2565 DERR(EX_OSERR, "%s: malloc failed", __func__);
2566
2567 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
2568 (void)memcpy(afdp, fd, fd_len);
2569
2570 pnd->pnd_all_fd_len += fd_len;
2571
2572 /*
2573 * The fd->off field is used as a cookie for
2574 * resuming the next readdir() where this one was left.
2575 */
2576 pnd->pnd_fd_cookie = readdir_last_cookie(fd, fd_len);
2577
2578 ps->ps_destroy_msg(pm);
2579 } while (1 /* CONSTCOND */);
2580
2581 if (pnd->pnd_all_fd != NULL) {
2582 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd,
2583 pnd->pnd_all_fd_len) == -1)
2584 error = EIO;
2585 }
2586
2587 out:
2588 if (pnd->pnd_all_fd != NULL) {
2589 free(pnd->pnd_all_fd);
2590 pnd->pnd_all_fd = NULL;
2591 pnd->pnd_all_fd_len = 0;
2592 }
2593
2594 if (error == 0)
2595 readdir_buffered(opc, dent, readoff, reslen);
2596
2597 /*
2598 * Schedule queued readdir requests
2599 */
2600 pnd->pnd_flags &= ~PND_INREADDIR;
2601 (void)dequeue_requests(opc, PCQ_READDIR, DEQUEUE_ALL);
2602
2603 #ifdef PERFUSE_DEBUG
2604 if (perfuse_diagflags & PDF_READDIR)
2605 DPRINTF("%s: READDIR opc = %p exit critical section\n",
2606 __func__, (void *)opc);
2607 #endif
2608
2609 node_rele(opc);
2610 return error;
2611 }
2612
2613 int
2614 perfuse_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
2615 const struct puffs_cred *pcr, char *linkname, size_t *linklen)
2616 {
2617 struct perfuse_state *ps;
2618 perfuse_msg_t *pm;
2619 int error;
2620 size_t len;
2621 struct fuse_out_header *foh;
2622
2623 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2624 return ENOENT;
2625
2626 node_ref(opc);
2627 ps = puffs_getspecific(pu);
2628
2629 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
2630
2631 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2632 goto out;
2633
2634 foh = GET_OUTHDR(ps, pm);
2635 len = foh->len - sizeof(*foh);
2636 if (len > *linklen)
2637 DERRX(EX_PROTOCOL, "path len = %zd too long", len);
2638 if (len == 0)
2639 DERRX(EX_PROTOCOL, "path len = %zd too short", len);
2640
2641 (void)memcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
2642
2643 /*
2644 * FUSE filesystems return a NUL terminated string, we
2645 * do not want the trailing \0
2646 */
2647 while (len > 0 && linkname[len - 1] == '\0')
2648 len--;
2649
2650 *linklen = len;
2651
2652 ps->ps_destroy_msg(pm);
2653 error = 0;
2654
2655 out:
2656 node_rele(opc);
2657 return error;
2658 }
2659
2660 int
2661 perfuse_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc)
2662 {
2663 struct perfuse_state *ps;
2664 perfuse_msg_t *pm;
2665 struct perfuse_node_data *pnd;
2666 struct fuse_forget_in *ffi;
2667 int nlookup;
2668 struct timespec now;
2669
2670 if (opc == 0)
2671 return 0;
2672
2673 ps = puffs_getspecific(pu);
2674 pnd = PERFUSE_NODE_DATA(opc);
2675
2676 /*
2677 * Never forget the root.
2678 */
2679 if (pnd->pnd_nodeid == FUSE_ROOT_ID)
2680 return 0;
2681
2682 /*
2683 * There is a race condition between reclaim and lookup.
2684 * When looking up an already known node, the kernel cannot
2685 * hold a reference on the result until it gets the PUFFS
2686 * reply. It mayy therefore reclaim the node after the
2687 * userland looked it up, and before it gets the reply.
2688 * On rely, the kernel re-creates the node, but at that
2689 * time the node has been reclaimed in userland.
2690 *
2691 * In order to avoid this, we refuse reclaiming nodes that
2692 * are too young since the last lookup - and that we do
2693 * not have removed on our own, of course.
2694 */
2695 if (clock_gettime(CLOCK_REALTIME, &now) != 0)
2696 DERR(EX_OSERR, "clock_gettime failed");
2697
2698 if (timespeccmp(&pnd->pnd_cn_expire, &now, >) &&
2699 !(pnd->pnd_flags & PND_REMOVED)) {
2700 if (!(pnd->pnd_flags & PND_NODELEAK)) {
2701 ps->ps_nodeleakcount++;
2702 pnd->pnd_flags |= PND_NODELEAK;
2703 }
2704 DWARNX("possible leaked node:: opc = %p \"%s\"",
2705 opc, pnd->pnd_name);
2706 return 0;
2707 }
2708
2709 node_ref(opc);
2710 pnd->pnd_flags |= PND_RECLAIMED;
2711 pnd->pnd_puffs_nlookup--;
2712 nlookup = pnd->pnd_puffs_nlookup;
2713
2714 #ifdef PERFUSE_DEBUG
2715 if (perfuse_diagflags & PDF_RECLAIM)
2716 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2717 perfuse_node_path(ps, opc), pnd->pnd_nodeid);
2718 #endif
2719
2720 #ifdef PERFUSE_DEBUG
2721 if (perfuse_diagflags & PDF_RECLAIM)
2722 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, nlookup = %d "
2723 "%s%s%s%s, pending ops:%s%s%s\n",
2724 perfuse_node_path(ps, opc), pnd->pnd_nodeid,
2725 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2726 pnd->pnd_puffs_nlookup,
2727 pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2728 pnd->pnd_flags & PND_RFH ? "r" : "",
2729 pnd->pnd_flags & PND_WFH ? "w" : "",
2730 pnd->pnd_flags & PND_BUSY ? "" : " none",
2731 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2732 pnd->pnd_flags & PND_INWRITE ? " write" : "",
2733 pnd->pnd_flags & PND_INOPEN ? " open" : "");
2734 #endif
2735 /*
2736 * Make sure it is not looked up again
2737 */
2738 if (!(pnd->pnd_flags & PND_REMOVED))
2739 perfuse_cache_flush(opc);
2740
2741 /*
2742 * Purge any activity on the node, while checking
2743 * that it remains eligible for a reclaim.
2744 */
2745 while (pnd->pnd_ref > 1)
2746 requeue_request(pu, opc, PCQ_REF);
2747
2748 /*
2749 * reclaim cancel?
2750 */
2751 if (pnd->pnd_puffs_nlookup > nlookup) {
2752 pnd->pnd_flags &= ~PND_RECLAIMED;
2753 perfuse_node_cache(ps, opc);
2754 node_rele(opc);
2755 return 0;
2756 }
2757
2758
2759 #ifdef PERFUSE_DEBUG
2760 if ((pnd->pnd_flags & PND_OPEN) ||
2761 !TAILQ_EMPTY(&pnd->pnd_pcq))
2762 DERRX(EX_SOFTWARE, "%s: opc = %p \"%s\": still open",
2763 __func__, opc, pnd->pnd_name);
2764
2765 if ((pnd->pnd_flags & PND_BUSY) ||
2766 !TAILQ_EMPTY(&pnd->pnd_pcq))
2767 DERRX(EX_SOFTWARE, "%s: opc = %p: queued operations",
2768 __func__, opc);
2769
2770 if (pnd->pnd_inxchg != 0)
2771 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
2772 __func__, opc);
2773 #endif
2774
2775 /*
2776 * Send the FORGET message
2777 *
2778 * ps_new_msg() is called with NULL creds, which will
2779 * be interpreted as FUSE superuser. This is obviously
2780 * fine since we operate with kernel creds here.
2781 */
2782 pm = ps->ps_new_msg(pu, opc, FUSE_FORGET,
2783 sizeof(*ffi), NULL);
2784 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2785 ffi->nlookup = pnd->pnd_fuse_nlookup;
2786
2787 /*
2788 * No reply is expected, pm is freed in xchg_msg
2789 */
2790 (void)xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, no_reply);
2791
2792 perfuse_destroy_pn(pu, opc);
2793
2794 return 0;
2795 }
2796
2797 int
2798 perfuse_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
2799 {
2800 struct perfuse_node_data *pnd;
2801 int error;
2802
2803 if (opc == 0)
2804 return 0;
2805
2806 node_ref(opc);
2807 pnd = PERFUSE_NODE_DATA(opc);
2808
2809 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED)))
2810 goto out;
2811
2812 /*
2813 * Make sure all operation are finished
2814 * There can be an ongoing write. Other
2815 * operation wait for all data before
2816 * the close/inactive.
2817 */
2818 while (pnd->pnd_flags & PND_INWRITE)
2819 requeue_request(pu, opc, PCQ_AFTERWRITE);
2820
2821 /*
2822 * The inactive operation may be cancelled,
2823 * If no open is in progress, set PND_INOPEN
2824 * so that a new open will be queued.
2825 */
2826 if (pnd->pnd_flags & PND_INOPEN)
2827 goto out;
2828
2829 pnd->pnd_flags |= PND_INOPEN;
2830
2831 /*
2832 * Sync data
2833 */
2834 if (pnd->pnd_flags & PND_DIRTY) {
2835 if ((error = perfuse_node_fsync(pu, opc, NULL, 0, 0, 0)) != 0)
2836 DWARN("%s: perfuse_node_fsync failed error = %d",
2837 __func__, error);
2838 }
2839
2840
2841 /*
2842 * Close handles
2843 */
2844 if (pnd->pnd_flags & PND_WFH) {
2845 if ((error = perfuse_node_close_common(pu, opc, FWRITE)) != 0)
2846 DWARN("%s: close write FH failed error = %d",
2847 __func__, error);
2848 }
2849
2850 if (pnd->pnd_flags & PND_RFH) {
2851 if ((error = perfuse_node_close_common(pu, opc, FREAD)) != 0)
2852 DWARN("%s: close read FH failed error = %d",
2853 __func__, error);
2854 }
2855
2856 /*
2857 * This will cause a reclaim to be sent
2858 */
2859 if (pnd->pnd_flags & PND_REMOVED)
2860 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
2861
2862 /*
2863 * Schedule awaiting operations
2864 */
2865 pnd->pnd_flags &= ~PND_INOPEN;
2866 (void)dequeue_requests(opc, PCQ_OPEN, DEQUEUE_ALL);
2867
2868 /*
2869 * errors are ignored, since the kernel ignores the return code.
2870 */
2871 out:
2872 node_rele(opc);
2873 return 0;
2874 }
2875
2876
2877 /* ARGSUSED0 */
2878 int
2879 perfuse_node_print(struct puffs_usermount *pu, puffs_cookie_t opc)
2880 {
2881 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2882 return 0;
2883 }
2884
2885 int
2886 perfuse_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc,
2887 int name, register_t *retval)
2888 {
2889 perfuse_msg_t *pm;
2890 struct perfuse_state *ps;
2891 struct fuse_statfs_out *fso;
2892 int error = 0;
2893
2894 /*
2895 * Static values copied from UFS
2896 * in src/sys/ufs/ufs/ufs_vnops.c
2897 */
2898 switch (name) {
2899 case _PC_LINK_MAX:
2900 *retval = LINK_MAX;
2901 break;
2902 case _PC_PATH_MAX:
2903 *retval = PATH_MAX;
2904 break;
2905 case _PC_PIPE_BUF:
2906 *retval = PIPE_BUF;
2907 break;
2908 case _PC_CHOWN_RESTRICTED:
2909 *retval = 1;
2910 break;
2911 case _PC_NO_TRUNC:
2912 *retval = 1;
2913 break;
2914 case _PC_SYNC_IO:
2915 *retval = 1;
2916 break;
2917 case _PC_FILESIZEBITS:
2918 *retval = 42;
2919 break;
2920 case _PC_SYMLINK_MAX:
2921 *retval = MAXPATHLEN;
2922 break;
2923 case _PC_2_SYMLINKS:
2924 *retval = 1;
2925 break;
2926 case _PC_NAME_MAX:
2927 ps = puffs_getspecific(pu);
2928 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
2929
2930 error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply);
2931 if (error != 0)
2932 return error;
2933
2934 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
2935 *retval = fso->st.namelen;
2936
2937 ps->ps_destroy_msg(pm);
2938
2939 break;
2940 default:
2941 DWARN("Unimplemented pathconf for name = %d", name);
2942 error = ENOSYS;
2943 break;
2944 }
2945
2946 return error;
2947 }
2948
2949 int
2950 perfuse_node_advlock(struct puffs_usermount *pu, puffs_cookie_t opc,
2951 void *id, int op, struct flock *fl, int flags)
2952 {
2953 struct perfuse_state *ps;
2954 int fop;
2955 perfuse_msg_t *pm;
2956 uint64_t fh;
2957 struct fuse_lk_in *fli;
2958 struct fuse_out_header *foh;
2959 struct fuse_lk_out *flo;
2960 uint32_t owner;
2961 size_t len;
2962 int error;
2963
2964 node_ref(opc);
2965
2966 /*
2967 * Make sure we do have a filehandle, as the FUSE filesystem
2968 * expect one. E.g.: if we provide none, GlusterFS logs an error
2969 * "0-glusterfs-fuse: xl is NULL"
2970 *
2971 * We need the read file handle if the file is open read only,
2972 * in order to support shared locks on read-only files.
2973 * NB: The kernel always sends advlock for read-only
2974 * files at exit time when the process used lock, see
2975 * sys_exit -> exit1 -> fd_free -> fd_close -> VOP_ADVLOCK
2976 */
2977 if ((fh = perfuse_get_fh(opc, FREAD)) == FUSE_UNKNOWN_FH) {
2978 error = EBADF;
2979 goto out;
2980 }
2981
2982 ps = puffs_getspecific(pu);
2983
2984 if (op == F_GETLK)
2985 fop = FUSE_GETLK;
2986 else
2987 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2988
2989 /*
2990 * XXX ps_new_msg() is called with NULL creds, which will
2991 * be interpreted as FUSE superuser. We have no way to
2992 * know the requesting process' credential, but since advlock()
2993 * is supposed to operate on a file that has been open(),
2994 * permission should have already been checked at open() time.
2995 */
2996 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2997 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2998 fli->fh = fh;
2999 fli->owner = (uint64_t)(vaddr_t)id;
3000 fli->lk.start = fl->l_start;
3001 fli->lk.end = fl->l_start + fl->l_len;
3002 fli->lk.type = fl->l_type;
3003 fli->lk.pid = fl->l_pid;
3004 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
3005
3006 owner = (uint32_t)(vaddr_t)id;
3007
3008 #ifdef PERFUSE_DEBUG
3009 if (perfuse_diagflags & PDF_FH)
3010 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
3011 __func__, (void *)opc,
3012 PERFUSE_NODE_DATA(opc)->pnd_nodeid, fli->fh);
3013 #endif
3014
3015 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3016 goto out;
3017
3018 foh = GET_OUTHDR(ps, pm);
3019 len = foh->len - sizeof(*foh);
3020
3021 /*
3022 * Save or clear the lock
3023 */
3024 switch (op) {
3025 case F_GETLK:
3026 if (len != sizeof(*flo))
3027 DERRX(EX_SOFTWARE,
3028 "%s: Unexpected lock reply len %zd",
3029 __func__, len);
3030
3031 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
3032 fl->l_start = flo->lk.start;
3033 fl->l_len = flo->lk.end - flo->lk.start;
3034 fl->l_pid = flo->lk.pid;
3035 fl->l_type = flo->lk.type;
3036 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */
3037
3038 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
3039 break;
3040 case F_UNLCK:
3041 owner = 0;
3042 /* FALLTHROUGH */
3043 case F_SETLK:
3044 /* FALLTHROUGH */
3045 case F_SETLKW:
3046 if (error != 0)
3047 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = owner;
3048
3049 if (len != 0)
3050 DERRX(EX_SOFTWARE,
3051 "%s: Unexpected unlock reply len %zd",
3052 __func__, len);
3053
3054 break;
3055 default:
3056 DERRX(EX_SOFTWARE, "%s: Unexpected op %d", __func__, op);
3057 break;
3058 }
3059
3060 ps->ps_destroy_msg(pm);
3061 error = 0;
3062
3063 out:
3064 node_rele(opc);
3065 return error;
3066 }
3067
3068 int
3069 perfuse_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf,
3070 off_t offset, size_t *resid, const struct puffs_cred *pcr, int ioflag)
3071 {
3072 struct perfuse_state *ps;
3073 struct perfuse_node_data *pnd;
3074 const struct vattr *vap;
3075 perfuse_msg_t *pm;
3076 struct fuse_read_in *fri;
3077 struct fuse_out_header *foh;
3078 size_t readen;
3079 int error;
3080
3081 ps = puffs_getspecific(pu);
3082 pnd = PERFUSE_NODE_DATA(opc);
3083 vap = puffs_pn_getvap((struct puffs_node *)opc);
3084
3085 /*
3086 * NetBSD turns that into a getdents(2) output
3087 * We just do a EISDIR as this feature is of little use.
3088 */
3089 if (vap->va_type == VDIR)
3090 return EISDIR;
3091
3092 do {
3093 size_t max_read;
3094
3095 max_read = ps->ps_max_readahead - sizeof(*foh);
3096 /*
3097 * flags may be set to FUSE_READ_LOCKOWNER
3098 * if lock_owner is provided.
3099 */
3100 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
3101 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
3102 fri->fh = perfuse_get_fh(opc, FREAD);
3103 fri->offset = offset;
3104 fri->size = (uint32_t)MIN(*resid, max_read);
3105 fri->read_flags = 0; /* XXX Unused by libfuse? */
3106 fri->lock_owner = pnd->pnd_lock_owner;
3107 fri->flags = 0;
3108 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
3109
3110 #ifdef PERFUSE_DEBUG
3111 if (perfuse_diagflags & PDF_FH)
3112 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", fh = 0x%"PRIx64"\n",
3113 __func__, (void *)opc, pnd->pnd_nodeid, fri->fh);
3114 #endif
3115 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
3116 if (error != 0)
3117 return error;
3118
3119 foh = GET_OUTHDR(ps, pm);
3120 readen = foh->len - sizeof(*foh);
3121
3122 #ifdef PERFUSE_DEBUG
3123 if (readen > *resid)
3124 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd",
3125 __func__, readen);
3126 #endif
3127
3128 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
3129
3130 buf += readen;
3131 offset += readen;
3132 *resid -= readen;
3133
3134 ps->ps_destroy_msg(pm);
3135 } while ((*resid != 0) && (readen != 0));
3136
3137 if (ioflag & (IO_SYNC|IO_DSYNC))
3138 ps->ps_syncreads++;
3139 else
3140 ps->ps_asyncreads++;
3141
3142 return 0;
3143 }
3144
3145 int
3146 perfuse_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
3147 uint8_t *buf, off_t offset, size_t *resid,
3148 const struct puffs_cred *pcr, int ioflag)
3149 {
3150 return perfuse_node_write2(pu, opc, buf, offset, resid, pcr, ioflag, 0);
3151 }
3152
3153 /* ARGSUSED7 */
3154 int
3155 perfuse_node_write2(struct puffs_usermount *pu, puffs_cookie_t opc,
3156 uint8_t *buf, off_t offset, size_t *resid,
3157 const struct puffs_cred *pcr, int ioflag, int xflag)
3158 {
3159 struct perfuse_state *ps;
3160 struct perfuse_node_data *pnd;
3161 struct vattr *vap;
3162 perfuse_msg_t *pm;
3163 struct fuse_write_in *fwi;
3164 struct fuse_write_out *fwo;
3165 size_t data_len;
3166 size_t payload_len;
3167 size_t written;
3168 int inresize;
3169 int error;
3170
3171 ps = puffs_getspecific(pu);
3172 pnd = PERFUSE_NODE_DATA(opc);
3173 vap = puffs_pn_getvap((struct puffs_node *)opc);
3174 written = 0;
3175 inresize = 0;
3176 error = 0;
3177
3178 if (vap->va_type == VDIR)
3179 return EISDIR;
3180
3181 node_ref(opc);
3182
3183 /*
3184 * We need to queue write requests in order to avoid
3185 * dequeueing PCQ_AFTERWRITE when there are pending writes.
3186 */
3187 while (pnd->pnd_flags & PND_INWRITE)
3188 requeue_request(pu, opc, PCQ_WRITE);
3189 pnd->pnd_flags |= PND_INWRITE;
3190
3191 /*
3192 * append flag: re-read the file size so that
3193 * we get the latest value.
3194 */
3195 if (ioflag & PUFFS_IO_APPEND) {
3196 if ((error = perfuse_node_getattr(pu, opc, vap, pcr)) != 0)
3197 goto out;
3198
3199 offset = vap->va_size;
3200 }
3201
3202 /*
3203 * Serialize size access, see comment in perfuse_node_setattr().
3204 */
3205 if ((u_quad_t)offset + *resid > vap->va_size) {
3206 while (pnd->pnd_flags & PND_INRESIZE)
3207 requeue_request(pu, opc, PCQ_RESIZE);
3208 pnd->pnd_flags |= PND_INRESIZE;
3209 inresize = 1;
3210 }
3211
3212 #ifdef PERFUSE_DEBUG
3213 if (perfuse_diagflags & PDF_RESIZE)
3214 DPRINTF(">> %s %p %" PRIu64 "\n", __func__,
3215 (void *)opc, vap->va_size);
3216 #endif
3217
3218 do {
3219 size_t max_write;
3220 /*
3221 * There is a writepage flag when data
3222 * is aligned to page size. Use it for
3223 * everything but the data after the last
3224 * page boundary.
3225 */
3226 max_write = ps->ps_max_write - sizeof(*fwi);
3227
3228 data_len = MIN(*resid, max_write);
3229 if (data_len > (size_t)sysconf(_SC_PAGESIZE))
3230 data_len = data_len & ~(sysconf(_SC_PAGESIZE) - 1);
3231
3232 payload_len = data_len + sizeof(*fwi);
3233
3234 /*
3235 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
3236 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
3237 * write_flags is set to 1 for writepage.
3238 */
3239 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
3240 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
3241 fwi->fh = perfuse_get_fh(opc, FWRITE);
3242 fwi->offset = offset;
3243 fwi->size = (uint32_t)data_len;
3244 fwi->write_flags = (fwi->size % sysconf(_SC_PAGESIZE)) ? 0 : 1;
3245 fwi->lock_owner = pnd->pnd_lock_owner;
3246 fwi->flags = 0;
3247 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
3248 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
3249 (void)memcpy((fwi + 1), buf, data_len);
3250
3251
3252 #ifdef PERFUSE_DEBUG
3253 if (perfuse_diagflags & PDF_FH)
3254 DPRINTF("%s: opc = %p, nodeid = 0x%"PRIx64", "
3255 "fh = 0x%"PRIx64"\n", __func__,
3256 (void *)opc, pnd->pnd_nodeid, fwi->fh);
3257 #endif
3258 if ((error = xchg_msg(pu, opc, pm,
3259 sizeof(*fwo), wait_reply)) != 0)
3260 goto out;
3261
3262 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
3263 written = fwo->size;
3264 ps->ps_destroy_msg(pm);
3265
3266 #ifdef PERFUSE_DEBUG
3267 if (written > *resid)
3268 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd",
3269 __func__, written);
3270 #endif
3271 *resid -= written;
3272 offset += written;
3273 buf += written;
3274
3275 } while (*resid != 0);
3276
3277 /*
3278 * puffs_ops(3) says
3279 * "everything must be written or an error will be generated"
3280 */
3281 if (*resid != 0)
3282 error = EFBIG;
3283
3284 #ifdef PERFUSE_DEBUG
3285 if (perfuse_diagflags & PDF_RESIZE) {
3286 if (offset > (off_t)vap->va_size)
3287 DPRINTF("<< %s %p %" PRIu64 " -> %lld\n", __func__,
3288 (void *)opc, vap->va_size, (long long)offset);
3289 else
3290 DPRINTF("<< %s %p \n", __func__, (void *)opc);
3291 }
3292 #endif
3293
3294 /*
3295 * Update file size if we wrote beyond the end
3296 */
3297 if (offset > (off_t)vap->va_size)
3298 vap->va_size = offset;
3299
3300 if (inresize) {
3301 #ifdef PERFUSE_DEBUG
3302 if (!(pnd->pnd_flags & PND_INRESIZE))
3303 DERRX(EX_SOFTWARE, "file write grow without resize");
3304 #endif
3305 pnd->pnd_flags &= ~PND_INRESIZE;
3306 (void)dequeue_requests(opc, PCQ_RESIZE, DEQUEUE_ALL);
3307 }
3308
3309
3310 /*
3311 * Statistics
3312 */
3313 if (ioflag & (IO_SYNC|IO_DSYNC))
3314 ps->ps_syncwrites++;
3315 else
3316 ps->ps_asyncwrites++;
3317
3318 /*
3319 * Remember to sync the file
3320 */
3321 pnd->pnd_flags |= PND_DIRTY;
3322
3323 #ifdef PERFUSE_DEBUG
3324 if (perfuse_diagflags & PDF_SYNC)
3325 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
3326 __func__, (void*)opc, perfuse_node_path(ps, opc));
3327 #endif
3328
3329 out:
3330 /*
3331 * VOP_PUTPAGE causes FAF write where kernel does not
3332 * check operation result. At least warn if it failed.
3333 */
3334 #ifdef PUFFS_WRITE_FAF
3335 if (error && (xflag & PUFFS_WRITE_FAF))
3336 DWARN("Data loss caused by FAF write failed on \"%s\"",
3337 pnd->pnd_name);
3338 #endif /* PUFFS_WRITE_FAF */
3339
3340 /*
3341 * If there are no more queued write, we can resume
3342 * an operation awaiting write completion.
3343 */
3344 pnd->pnd_flags &= ~PND_INWRITE;
3345 if (dequeue_requests(opc, PCQ_WRITE, 1) == 0)
3346 (void)dequeue_requests(opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
3347
3348 node_rele(opc);
3349 return error;
3350 }
3351
3352 /* ARGSUSED0 */
3353 void
3354 perfuse_cache_write(struct puffs_usermount *pu, puffs_cookie_t opc, size_t size,
3355 struct puffs_cacherun *runs)
3356 {
3357 return;
3358 }
3359
3360 /* ARGSUSED4 */
3361 int
3362 perfuse_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3363 int attrns, const char *attrname, size_t *attrsize, uint8_t *attr,
3364 size_t *resid, const struct puffs_cred *pcr)
3365 {
3366 struct perfuse_state *ps;
3367 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3368 perfuse_msg_t *pm;
3369 struct fuse_getxattr_in *fgi;
3370 struct fuse_getxattr_out *fgo;
3371 struct fuse_out_header *foh;
3372 size_t attrnamelen;
3373 size_t len;
3374 char *np;
3375 int error;
3376
3377 /* system namespace attrs are not accessible to non root users */
3378 if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr))
3379 return EPERM;
3380
3381 node_ref(opc);
3382 ps = puffs_getspecific(pu);
3383 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3384 attrnamelen = strlen(attrname) + 1;
3385 len = sizeof(*fgi) + attrnamelen;
3386
3387 pm = ps->ps_new_msg(pu, opc, FUSE_GETXATTR, len, pcr);
3388 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3389 fgi->size = (unsigned int)((resid != NULL) ? *resid : 0);
3390 np = (char *)(void *)(fgi + 1);
3391 (void)strlcpy(np, attrname, attrnamelen);
3392
3393 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3394 goto out;
3395
3396 /*
3397 * We just get fuse_getattr_out with list size if we requested
3398 * a null size.
3399 */
3400 if (resid == NULL) {
3401 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3402
3403 if (attrsize != NULL)
3404 *attrsize = fgo->size;
3405
3406 ps->ps_destroy_msg(pm);
3407 error = 0;
3408 goto out;
3409 }
3410
3411 /*
3412 * And with a non null requested size, we get the list just
3413 * after the header
3414 */
3415 foh = GET_OUTHDR(ps, pm);
3416 np = (char *)(void *)(foh + 1);
3417 len = foh->len - sizeof(*foh);
3418
3419 if (attrsize != NULL)
3420 *attrsize = len;
3421
3422 if (resid != NULL) {
3423 if (*resid < len) {
3424 error = ERANGE;
3425 ps->ps_destroy_msg(pm);
3426 goto out;
3427 }
3428
3429 (void)memcpy(attr, np, len);
3430 *resid -= len;
3431 }
3432
3433 ps->ps_destroy_msg(pm);
3434 error = 0;
3435
3436 out:
3437 node_rele(opc);
3438 return error;
3439 }
3440
3441 int
3442 perfuse_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3443 int attrns, const char *attrname, uint8_t *attr, size_t *resid,
3444 const struct puffs_cred *pcr)
3445 {
3446 struct perfuse_state *ps;
3447 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3448 perfuse_msg_t *pm;
3449 struct fuse_setxattr_in *fsi;
3450 size_t attrnamelen;
3451 size_t len;
3452 char *np;
3453 int error;
3454
3455 /* system namespace attrs are not accessible to non root users */
3456 if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr))
3457 return EPERM;
3458
3459 node_ref(opc);
3460 ps = puffs_getspecific(pu);
3461 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3462 attrnamelen = strlen(attrname) + 1;
3463 len = sizeof(*fsi) + attrnamelen + *resid;
3464
3465 pm = ps->ps_new_msg(pu, opc, FUSE_SETXATTR, len, pcr);
3466 fsi = GET_INPAYLOAD(ps, pm, fuse_setxattr_in);
3467 fsi->size = (unsigned int)*resid;
3468 fsi->flags = 0;
3469 np = (char *)(void *)(fsi + 1);
3470 (void)strlcpy(np, attrname, attrnamelen);
3471 np += attrnamelen;
3472 (void)memcpy(np, (char *)attr, *resid);
3473
3474 if ((error = xchg_msg(pu, opc, pm,
3475 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
3476 goto out;
3477
3478 ps->ps_destroy_msg(pm);
3479 *resid = 0;
3480 error = 0;
3481
3482 out:
3483 node_rele(opc);
3484 return error;
3485 }
3486
3487 /* ARGSUSED2 */
3488 int
3489 perfuse_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3490 int attrns, size_t *attrsize, uint8_t *attrs, size_t *resid, int flag,
3491 const struct puffs_cred *pcr)
3492 {
3493 struct perfuse_state *ps;
3494 perfuse_msg_t *pm;
3495 struct fuse_getxattr_in *fgi;
3496 struct fuse_getxattr_out *fgo;
3497 struct fuse_out_header *foh;
3498 char *np;
3499 size_t len, puffs_len, i, attrlen, outlen;
3500 int error;
3501
3502 /* system namespace attrs are not accessible to non root users */
3503 if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr))
3504 return EPERM;
3505
3506 node_ref(opc);
3507
3508 ps = puffs_getspecific(pu);
3509 len = sizeof(*fgi);
3510
3511 pm = ps->ps_new_msg(pu, opc, FUSE_LISTXATTR, len, pcr);
3512 fgi = GET_INPAYLOAD(ps, pm, fuse_getxattr_in);
3513 if (resid != NULL)
3514 fgi->size = (unsigned int)*resid;
3515 else
3516 fgi->size = 0;
3517
3518 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
3519 goto out;
3520
3521 /*
3522 * We just get fuse_getattr_out with list size if we requested
3523 * a null size.
3524 */
3525 if (resid == NULL) {
3526 fgo = GET_OUTPAYLOAD(ps, pm, fuse_getxattr_out);
3527
3528 if (attrsize != NULL)
3529 *attrsize = fgo->size;
3530
3531 ps->ps_destroy_msg(pm);
3532
3533 error = 0;
3534 goto out;
3535 }
3536
3537 /*
3538 * And with a non null requested size, we get the list just
3539 * after the header
3540 */
3541 foh = GET_OUTHDR(ps, pm);
3542 np = (char *)(void *)(foh + 1);
3543 puffs_len = foh->len - sizeof(*foh);
3544
3545 if (attrsize != NULL)
3546 *attrsize = puffs_len;
3547
3548 if (attrs != NULL) {
3549 if (*resid < puffs_len) {
3550 error = ERANGE;
3551 ps->ps_destroy_msg(pm);
3552 goto out;
3553 }
3554
3555 outlen = 0;
3556
3557 for (i = 0; i < puffs_len; i += attrlen + 1) {
3558 attrlen = strlen(np + i);
3559
3560 /*
3561 * Filter attributes per namespace
3562 */
3563 if (!perfuse_ns_match(attrns, np + i))
3564 continue;
3565
3566 #ifdef PUFFS_EXTATTR_LIST_LENPREFIX
3567 /*
3568 * Convert the FUSE reply to length prefixed strings
3569 * if this is what the kernel wants.
3570 */
3571 if (flag & PUFFS_EXTATTR_LIST_LENPREFIX) {
3572 (void)memcpy(attrs + outlen + 1,
3573 np + i, attrlen);
3574 *(attrs + outlen) = (uint8_t)attrlen;
3575 } else
3576 #endif /* PUFFS_EXTATTR_LIST_LENPREFIX */
3577 (void)memcpy(attrs + outlen, np + i, attrlen + 1);
3578 outlen += attrlen + 1;
3579 }
3580
3581 *resid -= outlen;
3582 }
3583
3584 ps->ps_destroy_msg(pm);
3585 error = 0;
3586
3587 out:
3588 node_rele(opc);
3589 return error;
3590 }
3591
3592 int
3593 perfuse_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
3594 int attrns, const char *attrname, const struct puffs_cred *pcr)
3595 {
3596 struct perfuse_state *ps;
3597 char fuse_attrname[LINUX_XATTR_NAME_MAX + 1];
3598 perfuse_msg_t *pm;
3599 size_t attrnamelen;
3600 char *np;
3601 int error;
3602
3603 /* system namespace attrs are not accessible to non root users */
3604 if (attrns == EXTATTR_NAMESPACE_SYSTEM && !puffs_cred_isjuggernaut(pcr))
3605 return EPERM;
3606
3607 node_ref(opc);
3608
3609 ps = puffs_getspecific(pu);
3610 attrname = perfuse_native_ns(attrns, attrname, fuse_attrname);
3611 attrnamelen = strlen(attrname) + 1;
3612
3613 pm = ps->ps_new_msg(pu, opc, FUSE_REMOVEXATTR, attrnamelen, pcr);
3614 np = _GET_INPAYLOAD(ps, pm, char *);
3615 (void)strlcpy(np, attrname, attrnamelen);
3616
3617 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
3618
3619 ps->ps_destroy_msg(pm);
3620
3621 node_rele(opc);
3622 return error;
3623 }
3624