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