ops.c revision 1.21 1 /* $NetBSD: ops.c,v 1.21 2010/10/11 01:08:26 manu Exp $ */
2
3 /*-
4 * Copyright (c) 2010 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/vnode.h>
38 #include <sys/socket.h>
39 #include <machine/vmparam.h>
40
41 #include "perfuse_priv.h"
42 #include "fuse.h"
43
44 extern int perfuse_diagflags;
45
46 static int xchg_msg(struct puffs_usermount *, puffs_cookie_t,
47 perfuse_msg_t *, size_t, enum perfuse_xchg_pb_reply);
48 static int no_access(puffs_cookie_t, const struct puffs_cred *, mode_t);
49 static void fuse_attr_to_vap(struct perfuse_state *,
50 struct vattr *, struct fuse_attr *);
51 static int node_lookup_dir_nodot(struct puffs_usermount *,
52 puffs_cookie_t, char *, size_t, struct puffs_node **);
53 static int node_lookup_common(struct puffs_usermount *, puffs_cookie_t,
54 const char*, struct puffs_node **);
55 static int node_mk_common(struct puffs_usermount *, puffs_cookie_t,
56 struct puffs_newinfo *, const struct puffs_cn *pcn, perfuse_msg_t *);
57 static ssize_t fuse_to_dirent(struct puffs_usermount *, puffs_cookie_t,
58 struct fuse_dirent *, size_t);
59 static int readdir_buffered(puffs_cookie_t, struct dirent *, off_t *,
60 size_t *, const struct puffs_cred *, int *, off_t *, size_t *);
61 static void requeue_request(struct puffs_usermount *,
62 puffs_cookie_t opc, enum perfuse_qtype);
63 static int dequeue_requests(struct perfuse_state *,
64 puffs_cookie_t opc, enum perfuse_qtype, int);
65 #define DEQUEUE_ALL 0
66
67 /*
68 * From <sys/vnode>, inside #ifdef _KERNEL section
69 */
70 #define IO_SYNC (0x40|IO_DSYNC)
71 #define IO_DSYNC 0x00200
72 #define IO_DIRECT 0x02000
73
74 /*
75 * From <fcntl>, inside #ifdef _KERNEL section
76 */
77 #define F_WAIT 0x010
78 #define F_FLOCK 0x020
79 #define OFLAGS(fflags) ((fflags) - 1)
80
81 /*
82 * Borrowed from src/sys/kern/vfs_subr.c and src/sys/sys/vnode.h
83 */
84 const enum vtype iftovt_tab[16] = {
85 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
86 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
87 };
88 const int vttoif_tab[9] = {
89 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK,
90 S_IFSOCK, S_IFIFO, S_IFMT,
91 };
92
93 #define IFTOVT(mode) (iftovt_tab[((mode) & S_IFMT) >> 12])
94 #define VTTOIF(indx) (vttoif_tab[(int)(indx)])
95
96 int
97 perfuse_node_close_common(pu, opc, mode)
98 struct puffs_usermount *pu;
99 puffs_cookie_t opc;
100 int mode;
101 {
102 struct perfuse_state *ps;
103 perfuse_msg_t *pm;
104 int op;
105 uint64_t fh;
106 struct fuse_release_in *fri;
107 struct perfuse_node_data *pnd;
108 struct puffs_node *pn;
109 int error;
110
111 ps = puffs_getspecific(pu);
112 pn = (struct puffs_node *)opc;
113 pnd = PERFUSE_NODE_DATA(pn);
114
115 if (puffs_pn_getvap(pn)->va_type == VDIR) {
116 op = FUSE_RELEASEDIR;
117 mode = FREAD;
118 } else {
119 op = FUSE_RELEASE;
120 }
121
122 /*
123 * Destroy the filehandle before sending the
124 * request to the FUSE filesystem, otherwise
125 * we may get a second close() while we wait
126 * for the reply, and we would end up closing
127 * the same fh twice instead of closng both.
128 */
129 fh = perfuse_get_fh(opc, mode);
130 perfuse_destroy_fh(pn, fh);
131
132 /*
133 * release_flags may be set to FUSE_RELEASE_FLUSH
134 * to flush locks. lock_owner must be set in that case
135 */
136 pm = ps->ps_new_msg(pu, opc, op, sizeof(*fri), NULL);
137 fri = GET_INPAYLOAD(ps, pm, fuse_release_in);
138 fri->fh = fh;
139 fri->flags = 0;
140 fri->release_flags = 0;
141 fri->lock_owner = pnd->pnd_lock_owner;
142 fri->flags = (fri->lock_owner != 0) ? FUSE_RELEASE_FLUSH : 0;
143
144 #ifdef PERFUSE_DEBUG
145 if (perfuse_diagflags & PDF_FH)
146 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
147 __func__, (void *)opc, pnd->pnd_ino, fri->fh);
148 #endif
149
150 if ((error = xchg_msg(pu, opc, pm,
151 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
152 goto out;
153
154 ps->ps_destroy_msg(pm);
155
156 error = 0;
157
158 out:
159 if (error != 0)
160 DERRX(EX_SOFTWARE, "%s: freed fh = 0x%"PRIx64" but filesystem "
161 "returned error = %d", __func__, fh, error);
162
163 return error;
164 }
165
166 /* ARGSUSED1 */
167 static int
168 xchg_msg(pu, opc, pm, len, wait)
169 struct puffs_usermount *pu;
170 puffs_cookie_t opc;
171 perfuse_msg_t *pm;
172 size_t len;
173 enum perfuse_xchg_pb_reply wait;
174 {
175 struct perfuse_state *ps;
176 struct perfuse_node_data *pnd;
177 int error;
178
179 ps = puffs_getspecific(pu);
180 pnd = NULL;
181 if ((struct puffs_node *)opc != NULL)
182 pnd = PERFUSE_NODE_DATA(opc);
183
184 #ifdef PERFUSE_DEBUG
185 if ((perfuse_diagflags & PDF_FILENAME) && (opc != 0))
186 DPRINTF("file = \"%s\" flags = 0x%x\n",
187 perfuse_node_path(opc),
188 PERFUSE_NODE_DATA(opc)->pnd_flags);
189 #endif
190 if (pnd)
191 pnd->pnd_flags |= PND_INXCHG;
192
193 error = ps->ps_xchg_msg(pu, pm, len, wait);
194
195 if (pnd) {
196 pnd->pnd_flags &= ~PND_INXCHG;
197 (void)dequeue_requests(ps, opc, PCQ_AFTERXCHG, DEQUEUE_ALL);
198 }
199
200 return error;
201 }
202
203 static int
204 no_access(opc, pcr, mode)
205 puffs_cookie_t opc;
206 const struct puffs_cred *pcr;
207 mode_t mode;
208 {
209 struct puffs_node *pn;
210 struct vattr *va;
211
212 /*
213 * pcr is NULL for self open through fsync or readdir.
214 * In both case, access control is useless, as it was
215 * done before, at open time.
216 */
217 if (pcr == NULL)
218 return 0;
219
220 /*
221 * pcr is NULL for self open through fsync or readdir.
222 * In both case, access control is useless, as it was
223 * done before, at open time.
224 */
225 if (pcr == NULL)
226 return 0;
227
228 pn = (struct puffs_node *)opc;
229 va = puffs_pn_getvap(pn);
230 return puffs_access(va->va_type, va->va_mode,
231 va->va_uid, va->va_gid,
232 mode, pcr);
233 }
234
235 static void
236 fuse_attr_to_vap(ps, vap, fa)
237 struct perfuse_state *ps;
238 struct vattr *vap;
239 struct fuse_attr *fa;
240 {
241 vap->va_type = IFTOVT(fa->mode);
242 vap->va_mode = fa->mode;
243 vap->va_nlink = fa->nlink;
244 vap->va_uid = fa->uid;
245 vap->va_gid = fa->gid;
246 vap->va_fsid = ps->ps_fsid;
247 vap->va_fileid = fa->ino;
248 vap->va_size = fa->size;
249 vap->va_blocksize = fa->blksize;
250 vap->va_atime.tv_sec = (time_t)fa->atime;
251 vap->va_atime.tv_nsec = (long) fa->atimensec;
252 vap->va_mtime.tv_sec = (time_t)fa->mtime;
253 vap->va_mtime.tv_nsec = (long)fa->mtimensec;
254 vap->va_ctime.tv_sec = (time_t)fa->ctime;
255 vap->va_ctime.tv_nsec = (long)fa->ctimensec;
256 vap->va_birthtime.tv_sec = 0;
257 vap->va_birthtime.tv_nsec = 0;
258 vap->va_gen = 0;
259 vap->va_flags = 0;
260 vap->va_rdev = fa->rdev;
261 vap->va_bytes = fa->size;
262 vap->va_filerev = (u_quad_t)PUFFS_VNOVAL;
263 vap->va_vaflags = 0;
264
265 if (vap->va_blocksize == 0)
266 vap->va_blocksize = DEV_BSIZE;
267
268 if (vap->va_size == (size_t)PUFFS_VNOVAL) /* XXX */
269 vap->va_size = 0;
270
271 return;
272 }
273
274
275 /*
276 * Lookup name in directory opc
277 * We take special care of name being . or ..
278 * These are returned by readdir and deserve tweaks.
279 */
280 static int
281 node_lookup_dir_nodot(pu, opc, name, namelen, pnp)
282 struct puffs_usermount *pu;
283 puffs_cookie_t opc;
284 char *name;
285 size_t namelen;
286 struct puffs_node **pnp;
287 {
288 char *path;
289 struct puffs_node *dpn = (struct puffs_node *)opc;
290 int error;
291
292 /*
293 * is easy as we already know it
294 */
295 if (strncmp(name, ".", namelen) == 0) {
296 *pnp = (struct puffs_node *)opc;
297 return 0;
298 }
299
300 /*
301 * For .. we just forget the name part
302 */
303 if (strncmp(name, "..", namelen) == 0)
304 namelen = 0;
305
306 namelen = PNPLEN(dpn) + 1 + namelen + 1;
307 if ((path = malloc(namelen)) == NULL)
308 DERR(EX_OSERR, "malloc failed");
309 (void)snprintf(path, namelen, "%s/%s",
310 perfuse_node_path((puffs_cookie_t)dpn), name);
311
312 error = node_lookup_common(pu, opc, path, pnp);
313
314 free(path);
315
316 return error;
317 }
318
319 static int
320 node_lookup_common(pu, opc, path, pnp)
321 struct puffs_usermount *pu;
322 puffs_cookie_t opc;
323 const char *path;
324 struct puffs_node **pnp;
325 {
326 struct perfuse_state *ps;
327 struct perfuse_node_data *pnd;
328 perfuse_msg_t *pm;
329 struct fuse_entry_out *feo;
330 struct puffs_node *pn;
331 size_t len;
332 int error;
333
334 ps = puffs_getspecific(pu);
335
336 #ifdef PERFUSE_DEBUG
337 if (perfuse_diagflags & PDF_FILENAME)
338 DPRINTF("%s: opc = %p, file = \"%s\" looking up \"%s\"\n",
339 __func__, (void *)opc, perfuse_node_path(opc), path);
340 #endif
341 /*
342 * Is the node already known?
343 */
344 TAILQ_FOREACH(pnd, &PERFUSE_NODE_DATA(opc)->pnd_children, pnd_next) {
345 if ((pnd->pnd_flags & PND_REMOVED) ||
346 (strcmp(pnd->pnd_name, path) != 0))
347 continue;
348
349 /*
350 * We have a match
351 */
352 if (pnp != NULL)
353 *pnp = (struct puffs_node *)(pnd->pnd_pn);
354
355 #ifdef PERFUSE_DEBUG
356 if (perfuse_diagflags & PDF_FILENAME)
357 DPRINTF("%s: opc = %p, file = \"%s\" found "
358 "cookie = %p, ino = %"PRId64" for \"%s\"\n",
359 __func__, (void *)opc, perfuse_node_path(opc),
360 (void *)pnd->pnd_pn, pnd->pnd_ino, path);
361 #endif
362 return 0;
363 }
364
365 len = strlen(path) + 1;
366
367 pm = ps->ps_new_msg(pu, opc, FUSE_LOOKUP, len, NULL);
368 (void)strlcpy(_GET_INPAYLOAD(ps, pm, char *), path, len);
369
370 if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0)
371 goto out;
372
373 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
374
375 pn = perfuse_new_pn(pu, path, opc);
376 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
377
378 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
379 pn->pn_va.va_gen = (u_long)(feo->generation);
380
381 if (pnp != NULL)
382 *pnp = pn;
383
384 #ifdef PERFUSE_DEBUG
385 if (perfuse_diagflags & PDF_FILENAME)
386 DPRINTF("%s: opc = %p, looked up opc = %p, ino = %"PRId64" "
387 "file = \"%s\"\n", __func__, (void *)opc, pn,
388 feo->nodeid, path);
389 #endif
390 out:
391 ps->ps_destroy_msg(pm);
392
393 return error;
394 }
395
396
397 /*
398 * Common final code for methods that create objects:
399 * perfuse_node_mkdir
400 * perfuse_node_mknod
401 * perfuse_node_symlink
402 */
403 static int
404 node_mk_common(pu, opc, pni, pcn, pm)
405 struct puffs_usermount *pu;
406 puffs_cookie_t opc;
407 struct puffs_newinfo *pni;
408 const struct puffs_cn *pcn;
409 perfuse_msg_t *pm;
410 {
411 struct perfuse_state *ps;
412 struct puffs_node *pn;
413 struct fuse_entry_out *feo;
414 struct fuse_setattr_in *fsi;
415 int error;
416
417 ps = puffs_getspecific(pu);
418
419 if ((error = xchg_msg(pu, opc, pm, sizeof(*feo), wait_reply)) != 0)
420 goto out;
421
422 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
423 if (feo->nodeid == PERFUSE_UNKNOWN_INO)
424 DERRX(EX_SOFTWARE, "%s: no ino", __func__);
425
426 pn = perfuse_new_pn(pu, pcn->pcn_name, opc);
427 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
428
429 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
430 pn->pn_va.va_gen = (u_long)(feo->generation);
431
432 puffs_newinfo_setcookie(pni, pn);
433
434 #ifdef PERFUSE_DEBUG
435 if (perfuse_diagflags & PDF_FILENAME)
436 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
437 "ino = %"PRId64"\n",
438 __func__, (void *)pn, pcn->pcn_name,
439 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid);
440 #endif
441 ps->ps_destroy_msg(pm);
442
443 /*
444 * Set owner and group
445 */
446 (void)puffs_cred_getuid(pcn->pcn_cred, &pn->pn_va.va_uid);
447 (void)puffs_cred_getgid(pcn->pcn_cred, &pn->pn_va.va_gid);
448
449 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn,
450 FUSE_SETATTR, sizeof(*fsi), NULL);
451 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
452 fsi->uid = pn->pn_va.va_uid;
453 fsi->gid = pn->pn_va.va_gid;
454 fsi->valid = FUSE_FATTR_UID|FUSE_FATTR_GID;
455
456 /*
457 * A fuse_attr_out is returned, but we ignore it.
458 */
459 error = xchg_msg(pu, (puffs_cookie_t)pn,
460 pm, sizeof(struct fuse_attr_out), wait_reply);
461
462 /*
463 * The parent directory needs a sync
464 */
465 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
466
467 out:
468 ps->ps_destroy_msg(pm);
469
470 return error;
471 }
472
473 static ssize_t
474 fuse_to_dirent(pu, opc, fd, fd_len)
475 struct puffs_usermount *pu;
476 puffs_cookie_t opc;
477 struct fuse_dirent *fd;
478 size_t fd_len;
479 {
480 struct dirent *dents;
481 size_t dents_len;
482 ssize_t written;
483 uint64_t fd_offset;
484 struct fuse_dirent *fd_base;
485 size_t len;
486
487 fd_base = fd;
488 fd_offset = 0;
489 written = 0;
490 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
491 dents_len = (size_t)PERFUSE_NODE_DATA(opc)->pnd_dirent_len;
492
493 do {
494 char *ndp;
495 size_t reclen;
496
497 reclen = _DIRENT_RECLEN(dents, fd->namelen);
498
499 /*
500 * Check we do not overflow the output buffer
501 * struct fuse_dirent is bigger than struct dirent,
502 * so we should always use fd_len and never reallocate
503 * later.
504 * If we have to reallocate,try to double the buffer
505 * each time so that we do not have to do it too often.
506 */
507 if (written + reclen > dents_len) {
508 if (dents_len == 0)
509 dents_len = fd_len;
510 else
511 dents_len =
512 MAX(2 * dents_len, written + reclen);
513
514 dents = PERFUSE_NODE_DATA(opc)->pnd_dirent;
515 if ((dents = realloc(dents, dents_len)) == NULL)
516 DERR(EX_OSERR, "malloc failed");
517
518 PERFUSE_NODE_DATA(opc)->pnd_dirent = dents;
519 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = dents_len;
520
521 /*
522 * (void *) for delint
523 */
524 ndp = (char *)(void *)dents + written;
525 dents = (struct dirent *)(void *)ndp;
526 }
527
528
529
530 /*
531 * Filesystem was mounted without -o use_ino
532 * Perform a lookup to find it.
533 * XXX still broken
534 */
535 if (fd->ino == PERFUSE_UNKNOWN_INO) {
536 struct puffs_node *pn;
537
538 if (node_lookup_dir_nodot(pu, opc, fd->name,
539 fd->namelen, &pn) != 0)
540 DERRX(EX_SOFTWARE,
541 "node_lookup_dir_nodot failed");
542
543 fd->ino = PERFUSE_NODE_DATA(pn)->pnd_ino;
544 }
545
546 dents->d_fileno = fd->ino;
547 dents->d_reclen = (unsigned short)reclen;
548 dents->d_namlen = fd->namelen;
549 dents->d_type = fd->type;
550 strlcpy(dents->d_name, fd->name, fd->namelen + 1);
551
552 #ifdef PERFUSE_DEBUG
553 if (perfuse_diagflags & PDF_READDIR)
554 DPRINTF("%s: translated \"%s\" ino = %"PRId64"\n",
555 __func__, dents->d_name, dents->d_fileno);
556 #endif
557
558 dents = _DIRENT_NEXT(dents);
559 written += reclen;
560
561 /*
562 * Move to the next record.
563 * fd->off seems unreliable, for instance, flusterfs
564 * does not clear the unused bits, and we get
565 * 0xffffffffb9b95040 instead of just 0x40. Use
566 * record alignement instead.
567 */
568 len = FUSE_DIRENT_ALIGN(sizeof(*fd) + fd->namelen);
569 #ifdef PERFUSE_DEBUG
570 if (perfuse_diagflags & PDF_READDIR)
571 DPRINTF("%s: record at %"PRId64"/0x%"PRIx64" "
572 "length = %zd/0x%zx. "
573 "next record at %"PRId64"/0x%"PRIx64" "
574 "max %zd/0x%zx\n",
575 __func__, fd_offset, fd_offset, len, len,
576 fd_offset + len, fd_offset + len,
577 fd_len, fd_len);
578 #endif
579 fd_offset += len;
580
581 /*
582 * Check if next record is still within the packet
583 * If it is not, we reached the end of the buffer.
584 */
585 if (fd_offset >= fd_len)
586 break;
587
588 /*
589 * (void *) for delint
590 */
591 ndp = (char *)(void *)fd_base + (size_t)fd_offset;
592 fd = (struct fuse_dirent *)(void *)ndp;
593
594 } while (1 /* CONSTCOND */);
595
596 /*
597 * Adjust the dirent output length
598 */
599 if (written != -1)
600 PERFUSE_NODE_DATA(opc)->pnd_dirent_len = written;
601
602 return written;
603 }
604
605 /* ARGSUSED4 */
606 static int
607 readdir_buffered(opc, dent, readoff,
608 reslen, pcr, eofflag, cookies, ncookies)
609 puffs_cookie_t opc;
610 struct dirent *dent;
611 off_t *readoff;
612 size_t *reslen;
613 const struct puffs_cred *pcr;
614 int *eofflag;
615 off_t *cookies;
616 size_t *ncookies;
617 {
618 struct dirent *fromdent;
619 struct perfuse_node_data *pnd;
620 char *ndp;
621
622 pnd = PERFUSE_NODE_DATA(opc);
623
624 while (*readoff < pnd->pnd_dirent_len) {
625 /*
626 * (void *) for delint
627 */
628 ndp = (char *)(void *)pnd->pnd_dirent + (size_t)*readoff;
629 fromdent = (struct dirent *)(void *)ndp;
630
631 if (*reslen < _DIRENT_SIZE(fromdent))
632 break;
633
634 memcpy(dent, fromdent, _DIRENT_SIZE(fromdent));
635 *readoff += _DIRENT_SIZE(fromdent);
636 *reslen -= _DIRENT_SIZE(fromdent);
637
638 dent = _DIRENT_NEXT(dent);
639 }
640
641 #ifdef PERFUSE_DEBUG
642 if (perfuse_diagflags & PDF_READDIR)
643 DPRINTF("%s: readoff = %"PRId64", "
644 "pnd->pnd_dirent_len = %"PRId64"\n",
645 __func__, *readoff, pnd->pnd_dirent_len);
646 #endif
647 if (*readoff >= pnd->pnd_dirent_len) {
648 free(pnd->pnd_dirent);
649 pnd->pnd_dirent = NULL;
650 pnd->pnd_dirent_len = 0;
651 *eofflag = 1;
652 }
653
654 return 0;
655 }
656
657 static void
658 requeue_request(pu, opc, type)
659 struct puffs_usermount *pu;
660 puffs_cookie_t opc;
661 enum perfuse_qtype type;
662 {
663 struct perfuse_cc_queue pcq;
664 struct perfuse_node_data *pnd;
665 #ifdef PERFUSE_DEBUG
666 struct perfuse_state *ps;
667
668 ps = perfuse_getspecific(pu);
669 #endif
670
671 pnd = PERFUSE_NODE_DATA(opc);
672 pcq.pcq_type = type;
673 pcq.pcq_cc = puffs_cc_getcc(pu);
674 TAILQ_INSERT_TAIL(&pnd->pnd_pcq, &pcq, pcq_next);
675
676 #ifdef PERFUSE_DEBUG
677 if (perfuse_diagflags & PDF_REQUEUE)
678 DPRINTF("%s: REQUEUE opc = %p, pcc = %p (%s)\n",
679 __func__, (void *)opc, pcq.pcq_cc,
680 perfuse_qtypestr[type]);
681 #endif
682
683 puffs_cc_yield(pcq.pcq_cc);
684 TAILQ_REMOVE(&pnd->pnd_pcq, &pcq, pcq_next);
685
686 #ifdef PERFUSE_DEBUG
687 if (perfuse_diagflags & PDF_REQUEUE)
688 DPRINTF("%s: RESUME opc = %p, pcc = %p (%s)\n",
689 __func__, (void *)opc, pcq.pcq_cc,
690 perfuse_qtypestr[type]);
691 #endif
692
693 return;
694 }
695
696 /* ARGSUSED0 */
697 static int
698 dequeue_requests(ps, opc, type, max)
699 struct perfuse_state *ps;
700 puffs_cookie_t opc;
701 enum perfuse_qtype type;
702 int max;
703 {
704 struct perfuse_cc_queue *pcq;
705 struct perfuse_node_data *pnd;
706 int dequeued;
707
708 pnd = PERFUSE_NODE_DATA(opc);
709 dequeued = 0;
710 TAILQ_FOREACH(pcq, &pnd->pnd_pcq, pcq_next) {
711 if (pcq->pcq_type != type)
712 continue;
713
714 #ifdef PERFUSE_DEBUG
715 if (perfuse_diagflags & PDF_REQUEUE)
716 DPRINTF("%s: SCHEDULE opc = %p, pcc = %p (%s)\n",
717 __func__, (void *)opc, pcq->pcq_cc,
718 perfuse_qtypestr[type]);
719 #endif
720 puffs_cc_schedule(pcq->pcq_cc);
721
722 if (++dequeued == max)
723 break;
724 }
725
726 #ifdef PERFUSE_DEBUG
727 if (perfuse_diagflags & PDF_REQUEUE)
728 DPRINTF("%s: DONE opc = %p\n", __func__, (void *)opc);
729 #endif
730
731 return dequeued;
732 }
733
734 void
735 perfuse_fs_init(pu)
736 struct puffs_usermount *pu;
737 {
738 struct perfuse_state *ps;
739 perfuse_msg_t *pm;
740 struct fuse_init_in *fii;
741 struct fuse_init_out *fio;
742 int error;
743
744 ps = puffs_getspecific(pu);
745
746 if (puffs_mount(pu, ps->ps_target, ps->ps_mountflags, ps->ps_root) != 0)
747 DERR(EX_OSERR, "puffs_mount failed");
748
749 /*
750 * Linux 2.6.34.1 sends theses flags:
751 * FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC
752 * FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK
753 *
754 * Linux also sets max_readahead at 32 pages (128 kB)
755 */
756 pm = ps->ps_new_msg(pu, 0, FUSE_INIT, sizeof(*fii), NULL);
757 fii = GET_INPAYLOAD(ps, pm, fuse_init_in);
758 fii->major = FUSE_KERNEL_VERSION;
759 fii->minor = FUSE_KERNEL_MINOR_VERSION;
760 fii->max_readahead = 32 * PAGE_SIZE;
761 fii->flags = (FUSE_ASYNC_READ|FUSE_POSIX_LOCKS|FUSE_ATOMIC_O_TRUNC);
762
763 if ((error = xchg_msg(pu, 0, pm, sizeof(*fio), wait_reply)) != 0)
764 DERRX(EX_SOFTWARE, "init message exchange failed (%d)", error);
765
766 fio = GET_OUTPAYLOAD(ps, pm, fuse_init_out);
767 ps->ps_max_readahead = fio->max_readahead;
768 ps->ps_max_write = fio->max_write;
769
770 ps->ps_destroy_msg(pm);
771
772 return;
773 }
774
775 int
776 perfuse_fs_unmount(pu, flags)
777 struct puffs_usermount *pu;
778 int flags;
779 {
780 perfuse_msg_t *pm;
781 struct perfuse_state *ps;
782 puffs_cookie_t opc;
783 int error;
784
785 ps = puffs_getspecific(pu);
786
787 opc = (puffs_cookie_t)puffs_getroot(pu);
788 pm = ps->ps_new_msg(pu, opc, FUSE_DESTROY, 0, NULL);
789
790 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0){
791 DWARN("unmount %s", ps->ps_target);
792 if (!(flags & MNT_FORCE))
793 goto out;
794 }
795
796 DPRINTF("%s unmounted, exit\n", ps->ps_target);
797
798 exit(0);
799 out:
800 ps->ps_destroy_msg(pm);
801
802 return error;
803 }
804
805 int
806 perfuse_fs_statvfs(pu, svfsb)
807 struct puffs_usermount *pu;
808 struct statvfs *svfsb;
809 {
810 struct perfuse_state *ps;
811 perfuse_msg_t *pm;
812 puffs_cookie_t opc;
813 struct fuse_statfs_out *fso;
814 int error;
815
816 ps = puffs_getspecific(pu);
817 opc = (puffs_cookie_t)puffs_getroot(pu);
818 pm = ps->ps_new_msg(pu, opc, FUSE_STATFS, 0, NULL);
819
820 if ((error = xchg_msg(pu, opc, pm, sizeof(*fso), wait_reply)) != 0)
821 goto out;
822
823 fso = GET_OUTPAYLOAD(ps, pm, fuse_statfs_out);
824 svfsb->f_flag = ps->ps_mountflags;
825 svfsb->f_bsize = fso->st.bsize;
826 svfsb->f_frsize = fso->st.frsize;
827 svfsb->f_iosize = ((struct puffs_node *)opc)->pn_va.va_blocksize;
828 svfsb->f_blocks = fso->st.blocks;
829 svfsb->f_bfree = fso->st.bfree;
830 svfsb->f_bavail = fso->st.bavail;
831 svfsb->f_bresvd = fso->st.bfree - fso->st.bavail;
832 svfsb->f_files = fso->st.files;
833 svfsb->f_ffree = fso->st.ffree;
834 svfsb->f_favail = fso->st.ffree;/* files not reserved for root */
835 svfsb->f_fresvd = 0; /* files reserved for root */
836
837 svfsb->f_syncreads = ps->ps_syncreads;
838 svfsb->f_syncwrites = ps->ps_syncwrites;
839
840 svfsb->f_asyncreads = ps->ps_asyncreads;
841 svfsb->f_asyncwrites = ps->ps_asyncwrites;
842
843 svfsb->f_fsidx.__fsid_val[0] = (int32_t)ps->ps_fsid;
844 svfsb->f_fsidx.__fsid_val[1] = 0;
845 svfsb->f_fsid = ps->ps_fsid;
846 svfsb->f_namemax = MAXPATHLEN; /* XXX */
847 svfsb->f_owner = ps->ps_owner_uid;
848
849 (void)strlcpy(svfsb->f_mntonname, ps->ps_target, _VFS_NAMELEN);
850
851 if (ps->ps_filesystemtype != NULL)
852 (void)strlcpy(svfsb->f_fstypename,
853 ps->ps_filesystemtype, _VFS_NAMELEN);
854 else
855 (void)strlcpy(svfsb->f_fstypename, "fuse", _VFS_NAMELEN);
856
857 if (ps->ps_source != NULL)
858 strlcpy(svfsb->f_mntfromname, ps->ps_source, _VFS_NAMELEN);
859 else
860 strlcpy(svfsb->f_mntfromname, _PATH_FUSE, _VFS_NAMELEN);
861 out:
862 ps->ps_destroy_msg(pm);
863
864 return error;
865 }
866
867 int
868 perfuse_fs_sync(pu, waitfor, pcr)
869 struct puffs_usermount *pu;
870 int waitfor;
871 const struct puffs_cred *pcr;
872 {
873 /*
874 * FUSE does not seem to have a FS sync callback.
875 * Maybe do not even register this callback
876 */
877 return puffs_fsnop_sync(pu, waitfor, pcr);
878 }
879
880 /* ARGSUSED0 */
881 int
882 perfuse_fs_fhtonode(pu, fid, fidsize, pni)
883 struct puffs_usermount *pu;
884 void *fid;
885 size_t fidsize;
886 struct puffs_newinfo *pni;
887 {
888 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
889 return 0;
890 }
891
892 /* ARGSUSED0 */
893 int
894 perfuse_fs_nodetofh(pu, cookie, fid, fidsize)
895 struct puffs_usermount *pu;
896 puffs_cookie_t cookie;
897 void *fid;
898 size_t *fidsize;
899 {
900 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
901 return 0;
902 }
903
904 #if 0
905 /* ARGSUSED0 */
906 void
907 perfuse_fs_extattrctl(pu, cmd, cookie, flags, namespace, attrname)
908 struct puffs_usermount *pu;
909 int cmd,
910 puffs_cookie_t *cookie;
911 int flags;
912 int namespace;
913 const char *attrname;
914 {
915 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
916 return 0;
917 }
918 #endif /* 0 */
919
920 /* ARGSUSED0 */
921 void
922 perfuse_fs_suspend(pu, status)
923 struct puffs_usermount *pu;
924 int status;
925 {
926 return;
927 }
928
929
930
931 int
932 perfuse_node_lookup(pu, opc, pni, pcn)
933 struct puffs_usermount *pu;
934 puffs_cookie_t opc;
935 struct puffs_newinfo *pni;
936 const struct puffs_cn *pcn;
937 {
938 struct puffs_node *pn;
939 int error;
940
941 error = 0;
942
943 /*
944 * Special case for ..
945 */
946 if (strcmp(pcn->pcn_name, "..") == 0)
947 pn = PERFUSE_NODE_DATA(opc)->pnd_parent;
948 else
949 error = node_lookup_common(pu, (puffs_cookie_t)opc,
950 pcn->pcn_name, &pn);
951
952 if (error != 0)
953 return error;
954
955 if (PERFUSE_NODE_DATA(pn)->pnd_flags & PND_REMOVED)
956 return ENOENT;
957
958 /*
959 * If that node had a pending reclaim, wipe it out.
960 */
961 PERFUSE_NODE_DATA(pn)->pnd_flags &= ~PND_RECLAIMED;
962
963 puffs_newinfo_setcookie(pni, pn);
964 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
965 puffs_newinfo_setsize(pni, (voff_t)pn->pn_va.va_size);
966 puffs_newinfo_setrdev(pni, pn->pn_va.va_rdev);
967
968 return error;
969 }
970
971 int
972 perfuse_node_create(pu, opc, pni, pcn, vap)
973 struct puffs_usermount *pu;
974 puffs_cookie_t opc;
975 struct puffs_newinfo *pni;
976 const struct puffs_cn *pcn;
977 const struct vattr *vap;
978 {
979 perfuse_msg_t *pm;
980 struct perfuse_state *ps;
981 struct fuse_create_in *fci;
982 struct fuse_entry_out *feo;
983 struct fuse_open_out *foo;
984 struct puffs_node *pn;
985 const char *name;
986 size_t namelen;
987 size_t len;
988 int error;
989
990 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
991 return ENOENT;
992
993 #if notyet
994 /*
995 * XXX create needs -WX on the parent directory. No pcr is
996 * given here, we cannot enforce this.
997 */
998 if (no_access(opc, pcr, PUFFS_VWRITE|PUFFS_VEXEC))
999 return EACCES;
1000 #endif
1001
1002 /*
1003 * If create is unimplemented: Check that it does not
1004 * already exists, and if not, do mknod and open
1005 */
1006 ps = puffs_getspecific(pu);
1007 if (ps->ps_flags & PS_NO_CREAT) {
1008 error = node_lookup_common(pu, opc, pcn->pcn_name, &pn);
1009 if (error == 0)
1010 return EEXIST;
1011
1012 error = perfuse_node_mknod(pu, opc, pni, pcn, vap);
1013 if (error != 0)
1014 return error;
1015
1016 error = node_lookup_common(pu, opc, pcn->pcn_name, &pn);
1017 if (error != 0)
1018 return error;
1019
1020 /*
1021 * FUSE does the open at create time, while
1022 * NetBSD will open in a subsequent operation.
1023 * We need to open now, in order to retain FUSE
1024 * semantics, but we have no credentials to use
1025 * since the PUFFS interface gives no pcr here.
1026 *
1027 * open with NULL pcr will skip permission checks.
1028 * There is no security hole, since we know we
1029 * can open this file: we just created it. The
1030 * calling process will not get a file descriptor
1031 * before the kernel sends the open operation,
1032 * which will have a pcr, anyway.
1033 */
1034 opc = (puffs_cookie_t)pn;
1035 error = perfuse_node_open(pu, opc, FWRITE, NULL);
1036 if (error != 0)
1037 return error;
1038
1039 return 0;
1040 }
1041
1042 name = pcn->pcn_name;
1043 namelen = pcn->pcn_namelen + 1;
1044 len = sizeof(*fci) + namelen;
1045
1046 /*
1047 * flags should use O_WRONLY instead of O_RDWR, but it
1048 * breaks when the caller tries to read from file.
1049 *
1050 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1051 */
1052 pm = ps->ps_new_msg(pu, opc, FUSE_CREATE, len, NULL);
1053 fci = GET_INPAYLOAD(ps, pm, fuse_create_in);
1054 fci->flags = O_CREAT | O_TRUNC | O_RDWR;
1055 fci->mode = vap->va_mode | VTTOIF(vap->va_type);
1056 fci->umask = 0; /* Seems unused by libfuse */
1057 (void)strlcpy((char*)(void *)(fci + 1), name, namelen);
1058
1059 len = sizeof(*feo) + sizeof(*foo);
1060 if ((error = xchg_msg(pu, opc, pm, len, wait_reply)) != 0)
1061 goto out;
1062
1063 feo = GET_OUTPAYLOAD(ps, pm, fuse_entry_out);
1064 foo = (struct fuse_open_out *)(void *)(feo + 1);
1065 if (feo->nodeid == PERFUSE_UNKNOWN_INO)
1066 DERRX(EX_SOFTWARE, "%s: no ino", __func__);
1067
1068 /*
1069 * Save the file handle and inode in node private data
1070 * so that we can reuse it later
1071 */
1072 pn = perfuse_new_pn(pu, name, opc);
1073 perfuse_new_fh((puffs_cookie_t)pn, foo->fh, FWRITE);
1074 PERFUSE_NODE_DATA(pn)->pnd_ino = feo->nodeid;
1075
1076 fuse_attr_to_vap(ps, &pn->pn_va, &feo->attr);
1077 pn->pn_va.va_gen = (u_long)(feo->generation);
1078
1079 puffs_newinfo_setcookie(pni, pn);
1080
1081 /*
1082 * The parent directory needs a sync
1083 */
1084 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
1085
1086 #ifdef PERFUSE_DEBUG
1087 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1088 DPRINTF("%s: opc = %p, file = \"%s\", flags = 0x%x "
1089 "ino = %"PRId64", wfh = 0x%"PRIx64"\n",
1090 __func__, (void *)pn, pcn->pcn_name,
1091 PERFUSE_NODE_DATA(pn)->pnd_flags, feo->nodeid, foo->fh);
1092 #endif
1093
1094 out:
1095 ps->ps_destroy_msg(pm);
1096
1097 /*
1098 * create is unimplmented, remember it for later,
1099 * and start over using mknod and open instead.
1100 */
1101 if (error == ENOSYS) {
1102 ps->ps_flags |= PS_NO_CREAT;
1103 return perfuse_node_create(pu, opc, pni, pcn, vap);
1104 }
1105
1106 return error;
1107 }
1108
1109
1110 int
1111 perfuse_node_mknod(pu, opc, pni, pcn, vap)
1112 struct puffs_usermount *pu;
1113 puffs_cookie_t opc;
1114 struct puffs_newinfo *pni;
1115 const struct puffs_cn *pcn;
1116 const struct vattr *vap;
1117 {
1118 struct perfuse_state *ps;
1119 perfuse_msg_t *pm;
1120 struct fuse_mknod_in *fmi;
1121 const char* path;
1122 size_t len;
1123
1124 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1125 return ENOENT;
1126
1127 /*
1128 * Only superuser can mknod objects other than
1129 * directories, files, socks, fifo and links.
1130 *
1131 * Create an object require -WX permission in the parent directory
1132 *
1133 * XXX The PUFFS interface gives us no pcr here, we cannot perfom
1134 * access control.
1135 */
1136 switch (vap->va_type) {
1137 case VDIR: /* FALLTHROUGH */
1138 case VREG: /* FALLTHROUGH */
1139 case VFIFO: /* FALLTHROUGH */
1140 case VSOCK: /* FALLTHROUGH */
1141 #if notyet
1142 if (no_access(opc, pcr, PUFFS_VWRITE|PUFFS_VEXEC))
1143 return EACCES;
1144 #endif
1145 break;
1146 default: /* VNON, VBLK, VCHR, VBAD */
1147 #if notyet
1148 if (!puffs_cred_isjuggernaut(pcr))
1149 return EACCES;
1150 #endif
1151 break;
1152 }
1153
1154
1155 ps = puffs_getspecific(pu);
1156 path = pcn->pcn_name;
1157 len = sizeof(*fmi) + pcn->pcn_namelen + 1;
1158
1159 /*
1160 * mode must contain file type (ie: S_IFREG), use VTTOIF(vap->va_type)
1161 */
1162 pm = ps->ps_new_msg(pu, opc, FUSE_MKNOD, len, NULL);
1163 fmi = GET_INPAYLOAD(ps, pm, fuse_mknod_in);
1164 fmi->mode = vap->va_mode | VTTOIF(vap->va_type);
1165 fmi->rdev = (uint32_t)vap->va_rdev;
1166 fmi->umask = 0; /* Seems unused bu libfuse */
1167 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
1168
1169 return node_mk_common(pu, opc, pni, pcn, pm);
1170 }
1171
1172
1173 int
1174 perfuse_node_open(pu, opc, mode, pcr)
1175 struct puffs_usermount *pu;
1176 puffs_cookie_t opc;
1177 int mode;
1178 const struct puffs_cred *pcr;
1179 {
1180 struct perfuse_state *ps;
1181 struct perfuse_node_data *pnd;
1182 perfuse_msg_t *pm;
1183 mode_t pmode;
1184 mode_t fmode;
1185 int op;
1186 struct fuse_open_in *foi;
1187 struct fuse_open_out *foo;
1188 struct puffs_node *pn;
1189 int error;
1190
1191 ps = puffs_getspecific(pu);
1192 pn = (struct puffs_node *)opc;
1193 pnd = PERFUSE_NODE_DATA(opc);
1194 pm = NULL;
1195 error = 0;
1196
1197 if (pnd->pnd_flags & PND_REMOVED)
1198 return ENOENT;
1199
1200 if (puffs_pn_getvap(pn)->va_type == VDIR) {
1201 op = FUSE_OPENDIR;
1202 pmode = PUFFS_VREAD;
1203 } else {
1204 op = FUSE_OPEN;
1205 if (mode & FWRITE)
1206 pmode = PUFFS_VWRITE|PUFFS_VREAD;
1207 else
1208 pmode = PUFFS_VREAD;
1209 }
1210
1211 /*
1212 * Opening a directory require R-- on the directory
1213 * Opening a file requires R-- for reading, -W- for writing
1214 * In both cases, R-- is required on the parent.
1215 */
1216 if ((no_access((puffs_cookie_t)pnd->pnd_parent, pcr, PUFFS_VREAD)) ||
1217 (no_access(opc, pcr, pmode))) {
1218 error = EACCES;
1219 goto out;
1220 }
1221
1222 /*
1223 * libfuse docs say O_CREAT should not be set.
1224 */
1225 mode &= ~O_CREAT;
1226
1227 /*
1228 * Do not open twice, and do not reopen for reading
1229 * if we already have write handle.
1230 */
1231 if (((mode & FREAD) && (pnd->pnd_flags & PND_RFH)) ||
1232 ((mode & FREAD) && (pnd->pnd_flags & PND_WFH)) ||
1233 ((mode & FWRITE) && (pnd->pnd_flags & PND_WFH))) {
1234 error = 0;
1235 goto out;
1236 }
1237
1238 /*
1239 * Queue open on a node so that we do not open
1240 * twice. This would be better with read and
1241 * write distinguished.
1242 */
1243 while (pnd->pnd_flags & PND_INOPEN)
1244 requeue_request(pu, opc, PCQ_OPEN);
1245 pnd->pnd_flags |= PND_INOPEN;
1246
1247 /*
1248 * Convert PUFFS mode to FUSE mode: convert FREAD/FWRITE
1249 * to O_RDONLY/O_WRONLY while perserving the other options.
1250 */
1251 fmode = mode & ~(FREAD|FWRITE);
1252 fmode |= (mode & FWRITE) ? O_RDWR : O_RDONLY;
1253
1254 pm = ps->ps_new_msg(pu, opc, op, sizeof(*foi), pcr);
1255 foi = GET_INPAYLOAD(ps, pm, fuse_open_in);
1256 foi->flags = fmode;
1257 foi->unused = 0;
1258
1259 if ((error = xchg_msg(pu, opc, pm, sizeof(*foo), wait_reply)) != 0)
1260 goto out;
1261
1262 foo = GET_OUTPAYLOAD(ps, pm, fuse_open_out);
1263
1264 /*
1265 * Save the file handle in node private data
1266 * so that we can reuse it later
1267 */
1268 perfuse_new_fh(opc, foo->fh, mode);
1269
1270 #ifdef PERFUSE_DEBUG
1271 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1272 DPRINTF("%s: opc = %p, file = \"%s\", "
1273 "ino = %"PRId64", %s%sfh = 0x%"PRIx64"\n",
1274 __func__, (void *)opc, perfuse_node_path(opc),
1275 pnd->pnd_ino, mode & FREAD ? "r" : "",
1276 mode & FWRITE ? "w" : "", foo->fh);
1277 #endif
1278
1279 out:
1280 if (pm != NULL)
1281 ps->ps_destroy_msg(pm);
1282
1283 pnd->pnd_flags &= ~PND_INOPEN;
1284 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
1285
1286 return error;
1287 }
1288
1289 /* ARGSUSED0 */
1290 int
1291 perfuse_node_close(pu, opc, flags, pcr)
1292 struct puffs_usermount *pu;
1293 puffs_cookie_t opc;
1294 int flags;
1295 const struct puffs_cred *pcr;
1296 {
1297 struct perfuse_node_data *pnd;
1298
1299 pnd = PERFUSE_NODE_DATA(opc);
1300
1301 if (!(pnd->pnd_flags & PND_OPEN))
1302 return EBADF;
1303
1304 /*
1305 * Actual close is postponed at inactive time.
1306 */
1307 return 0;
1308 }
1309
1310 /*
1311 * XXX
1312 * This fails as unprivilegied, it should not: touch testa/testx/a
1313 * d-wx-wx-wx 2 root wheel 512 Oct 5 04:32 testa/testx
1314 * -rwxrwxrwx 1 root wheel 0 Oct 5 04:39 testa/testx/a
1315 */
1316 int
1317 perfuse_node_access(pu, opc, mode, pcr)
1318 struct puffs_usermount *pu;
1319 puffs_cookie_t opc;
1320 int mode;
1321 const struct puffs_cred *pcr;
1322 {
1323 perfuse_msg_t *pm;
1324 struct perfuse_state *ps;
1325 struct fuse_access_in *fai;
1326 int error;
1327
1328 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1329 return ENOENT;
1330
1331 /*
1332 * If we previously detected the filesystem does not
1333 * implement access(), short-circuit the call and skip
1334 * to libpffs access() emulation.
1335 */
1336 ps = puffs_getspecific(pu);
1337 if (ps->ps_flags & PS_NO_ACCESS) {
1338 error = ENOSYS;
1339 } else {
1340 pm = ps->ps_new_msg(pu, opc, FUSE_ACCESS, sizeof(*fai), pcr);
1341 fai = GET_INPAYLOAD(ps, pm, fuse_access_in);
1342 fai->mask = mode;
1343
1344 error = xchg_msg(pu, opc, pm, NO_PAYLOAD_REPLY_LEN, wait_reply);
1345 ps->ps_destroy_msg(pm);
1346 }
1347
1348 if (error == ENOSYS) {
1349 struct fuse_getattr_in *fgi;
1350 struct fuse_attr_out *fao;
1351
1352 ps->ps_flags |= PS_NO_ACCESS;
1353
1354 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR,
1355 sizeof(*fgi), NULL);
1356 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1357 fgi->getattr_flags = 0;
1358 fgi->dummy = 0;
1359 fgi->fh = 0;
1360
1361 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) {
1362 fgi->fh = perfuse_get_fh(opc, FREAD);
1363 fgi->getattr_flags |= FUSE_GETATTR_FH;
1364 }
1365
1366 #ifdef PERFUSE_DEBUG
1367 if (perfuse_diagflags & PDF_FH)
1368 DPRINTF("%s: opc = %p, ino = %"PRId64", "
1369 "fh = 0x%"PRIx64"\n", __func__, (void *)opc,
1370 PERFUSE_NODE_DATA(opc)->pnd_ino, fgi->fh);
1371 #endif
1372 if ((error = xchg_msg(pu, opc, pm,
1373 sizeof(*fao), wait_reply)) != 0) {
1374 ps->ps_destroy_msg(pm);
1375 goto out;
1376 }
1377
1378 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1379
1380 error = puffs_access(VREG, fao->attr.mode, fao->attr.uid,
1381 fao->attr.gid, (mode_t)mode, pcr);
1382
1383
1384 fuse_attr_to_vap(ps,
1385 &((struct puffs_node *)opc)->pn_va,
1386 &fao->attr);
1387
1388 ps->ps_destroy_msg(pm);
1389 }
1390
1391 out:
1392 return error;
1393 }
1394
1395 int
1396 perfuse_node_getattr(pu, opc, vap, pcr)
1397 struct puffs_usermount *pu;
1398 puffs_cookie_t opc;
1399 struct vattr *vap;
1400 const struct puffs_cred *pcr;
1401 {
1402 perfuse_msg_t *pm;
1403 struct perfuse_state *ps;
1404 struct fuse_getattr_in *fgi;
1405 struct fuse_attr_out *fao;
1406 int error;
1407
1408 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1409 return ENOENT;
1410
1411 /*
1412 * getattr requires --X on the parent directory
1413 * no right is required on the object.
1414 */
1415 if (no_access(PERFUSE_NODE_DATA(opc)->pnd_parent, pcr, PUFFS_VEXEC))
1416 return EACCES;
1417
1418 ps = puffs_getspecific(pu);
1419
1420 /*
1421 * FUSE_GETATTR_FH must be set in fgi->flags
1422 * if we use for fgi->fh
1423 */
1424 pm = ps->ps_new_msg(pu, opc, FUSE_GETATTR, sizeof(*fgi), pcr);
1425 fgi = GET_INPAYLOAD(ps, pm, fuse_getattr_in);
1426 fgi->getattr_flags = 0;
1427 fgi->dummy = 0;
1428 fgi->fh = 0;
1429
1430 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_OPEN) {
1431 fgi->fh = perfuse_get_fh(opc, FREAD);
1432 fgi->getattr_flags |= FUSE_GETATTR_FH;
1433 }
1434
1435 if ((error = xchg_msg(pu, opc, pm, sizeof(*fao), wait_reply)) != 0)
1436 goto out;
1437
1438 fao = GET_OUTPAYLOAD(ps, pm, fuse_attr_out);
1439
1440 /*
1441 * The message from filesystem has a cache timeout
1442 * XXX this is ignored yet, is that right?
1443 *
1444 * We also set birthtime, flags, filerev,vaflags to 0.
1445 * This seems the best bet, since the information is
1446 * not available from filesystem.
1447 */
1448 fuse_attr_to_vap(ps, vap, &fao->attr);
1449
1450 out:
1451 ps->ps_destroy_msg(pm);
1452
1453 return error;
1454 }
1455
1456 int
1457 perfuse_node_setattr(pu, opc, vap, pcr)
1458 struct puffs_usermount *pu;
1459 puffs_cookie_t opc;
1460 const struct vattr *vap;
1461 const struct puffs_cred *pcr;
1462 {
1463 perfuse_msg_t *pm;
1464 uint64_t fh;
1465 struct perfuse_state *ps;
1466 struct perfuse_node_data *pnd;
1467 struct fuse_setattr_in *fsi;
1468 struct vattr *old_va;
1469 int error;
1470
1471 ps = puffs_getspecific(pu);
1472 pnd = PERFUSE_NODE_DATA(opc);
1473 pm = NULL;
1474
1475 /*
1476 * The only operation we can do once the file is removed
1477 * is to resize it, and we can do it only if it is open.
1478 * Do not even send the operation to the filesystem: the
1479 * file is not there anymore.
1480 */
1481 if (pnd->pnd_flags & PND_REMOVED) {
1482 if (!(pnd->pnd_flags & PND_OPEN))
1483 return ENOENT;
1484
1485 error = 0;
1486 goto out;
1487 }
1488
1489 old_va = puffs_pn_getvap((struct puffs_node *)opc);
1490
1491 /*
1492 * Check for permission to change size
1493 */
1494 if ((vap->va_size != (u_quad_t)PUFFS_VNOVAL) &&
1495 no_access(opc, pcr, PUFFS_VWRITE))
1496 return EACCES;
1497
1498 /*
1499 * Check for permission to change dates
1500 */
1501 if (((vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1502 (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL)) &&
1503 (puffs_access_times(old_va->va_uid, old_va->va_gid,
1504 old_va->va_mode, 0, pcr) != 0))
1505 return EACCES;
1506
1507 /*
1508 * Check for permission to change owner and group
1509 */
1510 if (((vap->va_uid != (uid_t)PUFFS_VNOVAL) ||
1511 (vap->va_gid != (gid_t)PUFFS_VNOVAL)) &&
1512 (puffs_access_chown(old_va->va_uid, old_va->va_gid,
1513 vap->va_uid, vap->va_gid, pcr)) != 0)
1514 return EACCES;
1515
1516 /*
1517 * Check for permission to change permissions
1518 */
1519 if ((vap->va_mode != (mode_t)PUFFS_VNOVAL) &&
1520 (puffs_access_chmod(old_va->va_uid, old_va->va_gid,
1521 old_va->va_type, vap->va_mode, pcr)) != 0)
1522 return EACCES;
1523
1524 /*
1525 * It seems troublesome to resize a file while
1526 * a write is just beeing done. Wait for
1527 * it to finish.
1528 */
1529 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL)
1530 while (pnd->pnd_flags & PND_INWRITE)
1531 requeue_request(pu, opc, PCQ_AFTERWRITE);
1532
1533 pm = ps->ps_new_msg(pu, opc, FUSE_SETATTR, sizeof(*fsi), pcr);
1534 fsi = GET_INPAYLOAD(ps, pm, fuse_setattr_in);
1535 fsi->valid = 0;
1536
1537 /*
1538 * Get a fh if the node is open for writing
1539 */
1540 if (pnd->pnd_flags & PND_WFH) {
1541 fh = perfuse_get_fh(opc, FWRITE);
1542 fsi->fh = fh;
1543 fsi->valid |= FUSE_FATTR_FH;
1544 }
1545
1546 if (vap->va_size != (u_quad_t)PUFFS_VNOVAL) {
1547 fsi->size = vap->va_size;
1548 fsi->valid |= FUSE_FATTR_SIZE;
1549 }
1550
1551 /*
1552 * Setting mtime without atime or vice verse leads to
1553 * dates being reset to Epoch on glusterfs. If one
1554 * is missing, use the old value.
1555 */
1556 if ((vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) ||
1557 (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL)) {
1558
1559 if (vap->va_atime.tv_sec != (time_t)PUFFS_VNOVAL) {
1560 fsi->atime = vap->va_atime.tv_sec;
1561 fsi->atimensec = (uint32_t)vap->va_atime.tv_nsec;
1562 } else {
1563 fsi->atime = old_va->va_atime.tv_sec;
1564 fsi->atimensec = (uint32_t)old_va->va_atime.tv_nsec;
1565 }
1566
1567 if (vap->va_mtime.tv_sec != (time_t)PUFFS_VNOVAL) {
1568 fsi->mtime = vap->va_mtime.tv_sec;
1569 fsi->mtimensec = (uint32_t)vap->va_mtime.tv_nsec;
1570 } else {
1571 fsi->mtime = old_va->va_mtime.tv_sec;
1572 fsi->mtimensec = (uint32_t)old_va->va_mtime.tv_nsec;
1573 }
1574
1575 fsi->valid |= (FUSE_FATTR_MTIME|FUSE_FATTR_ATIME);
1576 }
1577
1578 if (vap->va_mode != (mode_t)PUFFS_VNOVAL) {
1579 fsi->mode = vap->va_mode;
1580 fsi->valid |= FUSE_FATTR_MODE;
1581 }
1582
1583 if (vap->va_uid != (uid_t)PUFFS_VNOVAL) {
1584 fsi->uid = vap->va_uid;
1585 fsi->valid |= FUSE_FATTR_UID;
1586 }
1587
1588 if (vap->va_gid != (gid_t)PUFFS_VNOVAL) {
1589 fsi->gid = vap->va_gid;
1590 fsi->valid |= FUSE_FATTR_GID;
1591 }
1592
1593 if (pnd->pnd_lock_owner != 0) {
1594 fsi->lock_owner = pnd->pnd_lock_owner;
1595 fsi->valid |= FUSE_FATTR_LOCKOWNER;
1596 }
1597
1598 /*
1599 * If nothing remain, discard the operation.
1600 */
1601 if (!(fsi->valid & (FUSE_FATTR_SIZE|FUSE_FATTR_ATIME|FUSE_FATTR_MTIME|
1602 FUSE_FATTR_MODE|FUSE_FATTR_UID|FUSE_FATTR_GID))) {
1603 error = 0;
1604 goto out;
1605 }
1606
1607 /*
1608 * A fuse_attr_out is returned, but we ignore it.
1609 */
1610 error = xchg_msg(pu, opc, pm, sizeof(struct fuse_attr_out), wait_reply);
1611
1612 out:
1613
1614 if (pm != NULL)
1615 ps->ps_destroy_msg(pm);
1616
1617 return error;
1618 }
1619
1620 int
1621 perfuse_node_poll(pu, opc, events)
1622 struct puffs_usermount *pu;
1623 puffs_cookie_t opc;
1624 int *events;
1625 {
1626 struct perfuse_state *ps;
1627 perfuse_msg_t *pm;
1628 struct fuse_poll_in *fpi;
1629 struct fuse_poll_out *fpo;
1630 int error;
1631
1632 ps = puffs_getspecific(pu);
1633 /*
1634 * kh is set if FUSE_POLL_SCHEDULE_NOTIFY is set.
1635 */
1636 pm = ps->ps_new_msg(pu, opc, FUSE_POLL, sizeof(*fpi), NULL);
1637 fpi = GET_INPAYLOAD(ps, pm, fuse_poll_in);
1638 fpi->fh = perfuse_get_fh(opc, FREAD);
1639 fpi->kh = 0;
1640 fpi->flags = 0;
1641
1642 #ifdef PERFUSE_DEBUG
1643 if (perfuse_diagflags & PDF_FH)
1644 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
1645 __func__, (void *)opc,
1646 PERFUSE_NODE_DATA(opc)->pnd_ino, fpi->fh);
1647 #endif
1648 if ((error = xchg_msg(pu, opc, pm, sizeof(*fpo), wait_reply)) != 0)
1649 goto out;
1650
1651 fpo = GET_OUTPAYLOAD(ps, pm, fuse_poll_out);
1652 *events = fpo->revents;
1653 out:
1654 ps->ps_destroy_msg(pm);
1655
1656 return error;
1657 }
1658
1659 /* ARGSUSED0 */
1660 int
1661 perfuse_node_mmap(pu, opc, flags, pcr)
1662 struct puffs_usermount *pu;
1663 puffs_cookie_t opc;
1664 int flags;
1665 const struct puffs_cred *pcr;
1666 {
1667 /*
1668 * Not implemented anymore in libfuse
1669 */
1670 return ENOSYS;
1671 }
1672
1673 /* ARGSUSED2 */
1674 int
1675 perfuse_node_fsync(pu, opc, pcr, flags, offlo, offhi)
1676 struct puffs_usermount *pu;
1677 puffs_cookie_t opc;
1678 const struct puffs_cred *pcr;
1679 int flags;
1680 off_t offlo;
1681 off_t offhi;
1682 {
1683 int op;
1684 perfuse_msg_t *pm;
1685 struct perfuse_state *ps;
1686 struct perfuse_node_data *pnd;
1687 struct fuse_fsync_in *ffi;
1688 uint64_t fh;
1689 int error;
1690
1691 pm = NULL;
1692 ps = puffs_getspecific(pu);
1693 pnd = PERFUSE_NODE_DATA(opc);
1694
1695 /*
1696 * No need to sync a removed node
1697 */
1698 if (pnd->pnd_flags & PND_REMOVED)
1699 return 0;
1700
1701 /*
1702 * We do not sync closed files. They have been
1703 * sync at inactive time already.
1704 */
1705 if (!(pnd->pnd_flags & PND_OPEN))
1706 return 0;
1707
1708 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
1709 op = FUSE_FSYNCDIR;
1710 else /* VREG but also other types such as VLNK */
1711 op = FUSE_FSYNC;
1712
1713 /*
1714 * Do not sync if there are no change to sync
1715 * XXX remove that test on files if we implement mmap
1716 */
1717 #ifdef PERFUSE_DEBUG
1718 if (perfuse_diagflags & PDF_SYNC)
1719 DPRINTF("%s: TEST opc = %p, file = \"%s\" is %sdirty\n",
1720 __func__, (void*)opc, perfuse_node_path(opc),
1721 pnd->pnd_flags & PND_DIRTY ? "" : "not ");
1722 #endif
1723 if (!(pnd->pnd_flags & PND_DIRTY))
1724 return 0;
1725
1726 /*
1727 * It seems NetBSD can call fsync without open first
1728 * glusterfs complain in such a situation:
1729 * "FSYNC() ERR => -1 (Invalid argument)"
1730 * The file will be closed at inactive time.
1731 *
1732 * We open the directory for reading in order to sync.
1733 * This sounds rather counterintuitive, but it works.
1734 */
1735 if (!(pnd->pnd_flags & PND_WFH)) {
1736 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
1737 goto out;
1738 }
1739
1740 if (op == FUSE_FSYNCDIR)
1741 fh = perfuse_get_fh(opc, FREAD);
1742 else
1743 fh = perfuse_get_fh(opc, FWRITE);
1744
1745 /*
1746 * If fsync_flags is set, meta data should not be flushed.
1747 */
1748 pm = ps->ps_new_msg(pu, opc, op, sizeof(*ffi), NULL);
1749 ffi = GET_INPAYLOAD(ps, pm, fuse_fsync_in);
1750 ffi->fh = fh;
1751 ffi->fsync_flags = (flags & FFILESYNC) ? 0 : 1;
1752
1753 #ifdef PERFUSE_DEBUG
1754 if (perfuse_diagflags & PDF_FH)
1755 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
1756 __func__, (void *)opc,
1757 PERFUSE_NODE_DATA(opc)->pnd_ino, ffi->fh);
1758 #endif
1759
1760 if ((error = xchg_msg(pu, opc, pm,
1761 NO_PAYLOAD_REPLY_LEN, wait_reply)) != 0)
1762 goto out;
1763
1764 /*
1765 * No reply beyond fuse_out_header: nothing to do on success
1766 * just clear the dirty flag
1767 */
1768 pnd->pnd_flags &= ~PND_DIRTY;
1769
1770 #ifdef PERFUSE_DEBUG
1771 if (perfuse_diagflags & PDF_SYNC)
1772 DPRINTF("%s: CLEAR opc = %p, file = \"%s\"\n",
1773 __func__, (void*)opc, perfuse_node_path(opc));
1774 #endif
1775
1776 out:
1777 /*
1778 * ENOSYS is not returned to kernel,
1779 */
1780 if (error == ENOSYS)
1781 error = 0;
1782
1783 if (pm != NULL)
1784 ps->ps_destroy_msg(pm);
1785
1786 return error;
1787 }
1788
1789 /* ARGSUSED0 */
1790 int
1791 perfuse_node_seek(pu, opc, oldoff, newoff, pcr)
1792 struct puffs_usermount *pu;
1793 puffs_cookie_t opc;
1794 off_t oldoff;
1795 off_t newoff;
1796 const struct puffs_cred *pcr;
1797 {
1798 return 0;
1799 }
1800
1801 int
1802 perfuse_node_remove(pu, opc, targ, pcn)
1803 struct puffs_usermount *pu;
1804 puffs_cookie_t opc;
1805 puffs_cookie_t targ;
1806 const struct puffs_cn *pcn;
1807 {
1808 struct perfuse_state *ps;
1809 struct perfuse_node_data *pnd;
1810 perfuse_msg_t *pm;
1811 char *path;
1812 const char *name;
1813 size_t len;
1814 int error;
1815
1816 pnd = PERFUSE_NODE_DATA(opc);
1817
1818 if ((pnd->pnd_flags & PND_REMOVED) ||
1819 (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_REMOVED))
1820 return ENOENT;
1821
1822 #if notyet
1823 /*
1824 * remove requires -WX on the parent directory
1825 * no right required on the object.
1826 *
1827 * XXX PUFFS interface gives no pcr here
1828 */
1829 if (no_access((puffs_cookie_t)pnd->pnd_parent, pcr,
1830 PUFFS_VWRITE|PUFFS_VEXEC))
1831 return EACCES;
1832 #endif
1833
1834 #ifdef PERFUSE_DEBUG
1835 if (targ == NULL)
1836 DERRX(EX_SOFTWARE, "%s: targ is NULL", __func__);
1837
1838 if (perfuse_diagflags & (PDF_FH|PDF_FILENAME))
1839 DPRINTF("%s: opc = %p, remove opc = %p, file = \"%s\"\n",
1840 __func__, (void *)opc, (void *)targ, pcn->pcn_name);
1841 #endif
1842 /*
1843 * Await for all operations on the deleted node to drain,
1844 * as the filesystem may be confused to have it deleted
1845 * during a getattr
1846 */
1847 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
1848 requeue_request(pu, targ, PCQ_AFTERXCHG);
1849
1850 ps = puffs_getspecific(pu);
1851 pnd = PERFUSE_NODE_DATA(opc);
1852 name = pcn->pcn_name;
1853 len = pcn->pcn_namelen + 1;
1854
1855 pm = ps->ps_new_msg(pu, opc, FUSE_UNLINK, len, NULL);
1856 path = _GET_INPAYLOAD(ps, pm, char *);
1857 (void)strlcpy(path, name, len);
1858
1859 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
1860 goto out;
1861
1862 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
1863 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
1864 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
1865
1866 /*
1867 * The parent directory needs a sync
1868 */
1869 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
1870
1871 #ifdef PERFUSE_DEBUG
1872 if (perfuse_diagflags & PDF_FILENAME)
1873 DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n",
1874 __func__, PERFUSE_NODE_DATA(targ)->pnd_ino,
1875 pcn->pcn_name);
1876 #endif
1877 out:
1878 ps->ps_destroy_msg(pm);
1879
1880 return error;
1881 }
1882
1883 int
1884 perfuse_node_link(pu, opc, targ, pcn)
1885 struct puffs_usermount *pu;
1886 puffs_cookie_t opc;
1887 puffs_cookie_t targ;
1888 const struct puffs_cn *pcn;
1889 {
1890 struct perfuse_state *ps;
1891 perfuse_msg_t *pm;
1892 const char *name;
1893 size_t len;
1894 struct puffs_node *pn;
1895 struct fuse_link_in *fli;
1896 int error;
1897
1898 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
1899 return ENOENT;
1900
1901 #if notyet
1902 /*
1903 * Create an object require -W- permission in the parent directory
1904 *
1905 * XXX PUFFS interface gives no pcr here
1906 */
1907 if (no_access(opc, pcr, PUFFS_VWRITE))
1908 return EACCES;
1909 #endif
1910
1911
1912 ps = puffs_getspecific(pu);
1913 pn = (struct puffs_node *)targ;
1914 name = pcn->pcn_name;
1915 len = sizeof(*fli) + pcn->pcn_namelen + 1;
1916
1917 pm = ps->ps_new_msg(pu, opc, FUSE_LINK, len, NULL);
1918 fli = GET_INPAYLOAD(ps, pm, fuse_link_in);
1919 fli->oldnodeid = PERFUSE_NODE_DATA(pn)->pnd_ino;
1920 (void)strlcpy((char *)(void *)(fli + 1), name, len - sizeof(*fli));
1921
1922 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
1923
1924 ps->ps_destroy_msg(pm);
1925
1926 return error;
1927 }
1928
1929 int
1930 perfuse_node_rename(pu, opc, src, pcn_src, targ_dir, targ, pcn_targ)
1931 struct puffs_usermount *pu;
1932 puffs_cookie_t opc;
1933 puffs_cookie_t src;
1934 const struct puffs_cn *pcn_src;
1935 puffs_cookie_t targ_dir;
1936 puffs_cookie_t targ;
1937 const struct puffs_cn *pcn_targ;
1938 {
1939 struct perfuse_state *ps;
1940 perfuse_msg_t *pm;
1941 struct fuse_rename_in *fri;
1942 const char *newname;
1943 const char *oldname;
1944 char *np;
1945 int error;
1946 size_t len;
1947 size_t newname_len;
1948 size_t oldname_len;
1949
1950 if ((PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED) ||
1951 (PERFUSE_NODE_DATA(src)->pnd_flags & PND_REMOVED) ||
1952 (PERFUSE_NODE_DATA(targ_dir)->pnd_flags & PND_REMOVED))
1953 return ENOENT;
1954
1955 #if notyet
1956 /*
1957 * move requires -WX on source and destination directory
1958 *
1959 * XXX PUFFS interface gives no pcr here
1960 */
1961 if (no_access(opc, pcr_src, PUFFS_VWRITE|PUFFS_VEXEC) ||
1962 no_access(targ_dir, pcr_targ, PUFFS_VWRITE|PUFFS_VEXEC))
1963 return EACCES;
1964 #endif
1965
1966 /*
1967 * Await for all operations on the deleted node to drain,
1968 * as the filesystem may be confused to have it deleted
1969 * during a getattr
1970 */
1971 if ((struct puffs_node *)targ != NULL) {
1972 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
1973 requeue_request(pu, targ, PCQ_AFTERXCHG);
1974 } else {
1975 while (PERFUSE_NODE_DATA(src)->pnd_flags & PND_INXCHG)
1976 requeue_request(pu, src, PCQ_AFTERXCHG);
1977 }
1978
1979 ps = puffs_getspecific(pu);
1980 newname = pcn_targ->pcn_name;
1981 newname_len = pcn_targ->pcn_namelen + 1;
1982 oldname = pcn_src->pcn_name;
1983 oldname_len = pcn_src->pcn_namelen + 1;
1984
1985 len = sizeof(*fri) + oldname_len + newname_len;
1986 pm = ps->ps_new_msg(pu, opc, FUSE_RENAME, len, NULL);
1987 fri = GET_INPAYLOAD(ps, pm, fuse_rename_in);
1988 fri->newdir = PERFUSE_NODE_DATA(targ_dir)->pnd_ino;
1989 np = (char *)(void *)(fri + 1);
1990 (void)strlcpy(np, oldname, oldname_len);
1991 np += oldname_len;
1992 (void)strlcpy(np, newname, newname_len);
1993
1994 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
1995 goto out;
1996
1997 if (opc != targ_dir) {
1998 struct perfuse_node_data *srcdir_pnd;
1999 struct perfuse_node_data *dstdir_pnd;
2000 struct perfuse_node_data *src_pnd;
2001
2002 srcdir_pnd = PERFUSE_NODE_DATA(opc);
2003 dstdir_pnd = PERFUSE_NODE_DATA(targ_dir);
2004 src_pnd = PERFUSE_NODE_DATA(src);
2005
2006 TAILQ_REMOVE(&srcdir_pnd->pnd_children, src_pnd, pnd_next);
2007 TAILQ_INSERT_TAIL(&dstdir_pnd->pnd_children, src_pnd, pnd_next);
2008
2009 srcdir_pnd->pnd_childcount--;
2010 dstdir_pnd->pnd_childcount++;
2011
2012 src_pnd->pnd_parent = targ_dir;
2013
2014 PERFUSE_NODE_DATA(targ_dir)->pnd_flags |= PND_DIRTY;
2015 }
2016
2017 (void)strlcpy(PERFUSE_NODE_DATA(src)->pnd_name, newname, MAXPATHLEN);
2018
2019 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2020
2021 if ((struct puffs_node *)targ != NULL)
2022 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2023
2024 #ifdef PERFUSE_DEBUG
2025 if (perfuse_diagflags & PDF_FILENAME)
2026 DPRINTF("%s: nodeid = %"PRId64" file = \"%s\" renamed \"%s\" "
2027 "nodeid = %"PRId64" -> nodeid = %"PRId64" \"%s\"\n",
2028 __func__, PERFUSE_NODE_DATA(src)->pnd_ino,
2029 pcn_src->pcn_name, pcn_targ->pcn_name,
2030 PERFUSE_NODE_DATA(opc)->pnd_ino,
2031 PERFUSE_NODE_DATA(targ_dir)->pnd_ino,
2032 perfuse_node_path(targ_dir));
2033 #endif
2034
2035 out:
2036 if (pm != NULL)
2037 ps->ps_destroy_msg(pm);
2038
2039 return error;
2040 }
2041
2042 int
2043 perfuse_node_mkdir(pu, opc, pni, pcn, vap)
2044 struct puffs_usermount *pu;
2045 puffs_cookie_t opc;
2046 struct puffs_newinfo *pni;
2047 const struct puffs_cn *pcn;
2048 const struct vattr *vap;
2049 {
2050 struct perfuse_state *ps;
2051 perfuse_msg_t *pm;
2052 struct fuse_mkdir_in *fmi;
2053 const char *path;
2054 size_t len;
2055
2056 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2057 return ENOENT;
2058
2059 #if notyet
2060 /*
2061 * Create an object require -WX permission in the parent directory
2062 *
2063 * XXX PUFFS interface gives no pcr here
2064 */
2065 if (no_access(opc, pcrx, PUFFS_VWRITE|PUFFS_VEXEC))
2066 return EACCES;
2067 #endif
2068
2069 ps = puffs_getspecific(pu);
2070 path = pcn->pcn_name;
2071 len = sizeof(*fmi) + pcn->pcn_namelen + 1;
2072
2073 pm = ps->ps_new_msg(pu, opc, FUSE_MKDIR, len, NULL);
2074 fmi = GET_INPAYLOAD(ps, pm, fuse_mkdir_in);
2075 fmi->mode = vap->va_mode;
2076 fmi->umask = 0; /* Seems unused by libfuse? */
2077 (void)strlcpy((char *)(void *)(fmi + 1), path, len - sizeof(*fmi));
2078
2079 return node_mk_common(pu, opc, pni, pcn, pm);
2080 }
2081
2082
2083 int
2084 perfuse_node_rmdir(pu, opc, targ, pcn)
2085 struct puffs_usermount *pu;
2086 puffs_cookie_t opc;
2087 puffs_cookie_t targ;
2088 const struct puffs_cn *pcn;
2089 {
2090 struct perfuse_state *ps;
2091 struct perfuse_node_data *pnd;
2092 perfuse_msg_t *pm;
2093 char *path;
2094 const char *name;
2095 size_t len;
2096 int error;
2097
2098 pnd = PERFUSE_NODE_DATA(opc);
2099 if (pnd->pnd_flags & PND_REMOVED)
2100 return ENOENT;
2101
2102
2103 #if notyet
2104 /*
2105 * remove requires -WX on the parent directory
2106 * no right required on the object.
2107 *
2108 * XXX PUFFS interface gives no pcr here
2109 */
2110 if (no_access((puffs_cookie_t)pnd->pnd_parent, pcr,
2111 PUFFS_VWRITE|PUFFS_VEXEC))
2112 return EACCES;
2113 #endif
2114
2115 /*
2116 * Await for all operations on the deleted node to drain,
2117 * as the filesystem may be confused to have it deleted
2118 * during a getattr
2119 */
2120 while (PERFUSE_NODE_DATA(targ)->pnd_flags & PND_INXCHG)
2121 requeue_request(pu, targ, PCQ_AFTERXCHG);
2122
2123 ps = puffs_getspecific(pu);
2124 name = pcn->pcn_name;
2125 len = pcn->pcn_namelen + 1;
2126
2127 pm = ps->ps_new_msg(pu, opc, FUSE_RMDIR, len, NULL);
2128 path = _GET_INPAYLOAD(ps, pm, char *);
2129 (void)strlcpy(path, name, len);
2130
2131 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2132 goto out;
2133
2134 PERFUSE_NODE_DATA(targ)->pnd_flags |= PND_REMOVED;
2135 if (!(PERFUSE_NODE_DATA(targ)->pnd_flags & PND_OPEN))
2136 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
2137
2138 /*
2139 * The parent directory needs a sync
2140 */
2141 PERFUSE_NODE_DATA(opc)->pnd_flags |= PND_DIRTY;
2142
2143 #ifdef PERFUSE_DEBUG
2144 if (perfuse_diagflags & PDF_FILENAME)
2145 DPRINTF("%s: remove nodeid = %"PRId64" file = \"%s\"\n",
2146 __func__, PERFUSE_NODE_DATA(targ)->pnd_ino,
2147 perfuse_node_path(targ));
2148 #endif
2149 out:
2150 ps->ps_destroy_msg(pm);
2151
2152 return error;
2153 }
2154
2155 /* vap is unused */
2156 /* ARGSUSED4 */
2157 int
2158 perfuse_node_symlink(pu, opc, pni, pcn_src, vap, link_target)
2159 struct puffs_usermount *pu;
2160 puffs_cookie_t opc;
2161 struct puffs_newinfo *pni;
2162 const struct puffs_cn *pcn_src;
2163 const struct vattr *vap;
2164 const char *link_target;
2165 {
2166 struct perfuse_state *ps;
2167 perfuse_msg_t *pm;
2168 char *np;
2169 const char *path;
2170 size_t path_len;
2171 size_t linkname_len;
2172 size_t len;
2173
2174 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2175 return ENOENT;
2176
2177 #if notyet
2178 /*
2179 * Create an object require -W- permission in the parent directory
2180 *
2181 * XXX PUFFS interface gives no pcr here
2182 */
2183 if (no_access(opc, pcr_src, PUFFS_VWRITE))
2184 return EACCES;
2185 #endif
2186
2187 ps = puffs_getspecific(pu);
2188 path = pcn_src->pcn_name;
2189 path_len = pcn_src->pcn_namelen + 1;
2190 linkname_len = strlen(link_target) + 1;
2191 len = path_len + linkname_len;
2192
2193 pm = ps->ps_new_msg(pu, opc, FUSE_SYMLINK, len, NULL);
2194 np = _GET_INPAYLOAD(ps, pm, char *);
2195 (void)strlcpy(np, path, path_len);
2196 np += path_len;
2197 (void)strlcpy(np, link_target, linkname_len);
2198
2199 return node_mk_common(pu, opc, pni, pcn_src, pm);
2200 }
2201
2202 int
2203 perfuse_node_readdir(pu, opc, dent, readoff,
2204 reslen, pcr, eofflag, cookies, ncookies)
2205 struct puffs_usermount *pu;
2206 puffs_cookie_t opc;
2207 struct dirent *dent;
2208 off_t *readoff;
2209 size_t *reslen;
2210 const struct puffs_cred *pcr;
2211 int *eofflag;
2212 off_t *cookies;
2213 size_t *ncookies;
2214 {
2215 perfuse_msg_t *pm;
2216 uint64_t fh;
2217 struct perfuse_state *ps;
2218 struct perfuse_node_data *pnd;
2219 struct fuse_read_in *fri;
2220 struct fuse_out_header *foh;
2221 struct fuse_dirent *fd;
2222 size_t foh_len;
2223 int error;
2224 uint64_t fd_offset;
2225 size_t fd_maxlen;
2226
2227 pm = NULL;
2228 error = 0;
2229 ps = puffs_getspecific(pu);
2230
2231 /*
2232 * readdir state is kept at node level, and several readdir
2233 * requests can be issued at the same time on the same node.
2234 * We need to queue requests so that only one is in readdir
2235 * code at the same time.
2236 */
2237 pnd = PERFUSE_NODE_DATA(opc);
2238 while (pnd->pnd_flags & PND_INREADDIR)
2239 requeue_request(pu, opc, PCQ_READDIR);
2240 pnd->pnd_flags |= PND_INREADDIR;
2241
2242 #ifdef PERFUSE_DEBUG
2243 if (perfuse_diagflags & PDF_READDIR)
2244 DPRINTF("%s: READDIR opc = %p enter critical section\n",
2245 __func__, (void *)opc);
2246 #endif
2247 /*
2248 * Do we already have the data bufered?
2249 */
2250 if (pnd->pnd_dirent != NULL)
2251 goto out;
2252 pnd->pnd_dirent_len = 0;
2253
2254 /*
2255 * It seems NetBSD can call readdir without open first
2256 * libfuse will crash if it is done that way, hence open first.
2257 */
2258 if (!(pnd->pnd_flags & PND_OPEN)) {
2259 if ((error = perfuse_node_open(pu, opc, FREAD, pcr)) != 0)
2260 goto out;
2261 }
2262
2263 fh = perfuse_get_fh(opc, FREAD);
2264
2265 #ifdef PERFUSE_DEBUG
2266 if (perfuse_diagflags & PDF_FH)
2267 DPRINTF("%s: opc = %p, ino = %"PRId64", rfh = 0x%"PRIx64"\n",
2268 __func__, (void *)opc,
2269 PERFUSE_NODE_DATA(opc)->pnd_ino, fh);
2270 #endif
2271
2272 pnd->pnd_all_fd = NULL;
2273 pnd->pnd_all_fd_len = 0;
2274 fd_offset = 0;
2275 fd_maxlen = ps->ps_max_readahead - sizeof(*foh);
2276
2277 do {
2278 size_t fd_len;
2279 char *afdp;
2280
2281 pm = ps->ps_new_msg(pu, opc, FUSE_READDIR, sizeof(*fri), pcr);
2282
2283 /*
2284 * read_flags, lock_owner and flags are unused in libfuse
2285 */
2286 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2287 fri->fh = fh;
2288 fri->offset = fd_offset;
2289 fri->size = fd_maxlen;
2290 fri->read_flags = 0;
2291 fri->lock_owner = 0;
2292 fri->flags = 0;
2293
2294 if ((error = xchg_msg(pu, opc, pm,
2295 UNSPEC_REPLY_LEN, wait_reply)) != 0)
2296 goto out;
2297
2298 /*
2299 * There are many puffs_framebufs calls later,
2300 * therefore foh will not be valid for a long time.
2301 * Just get the length and forget it.
2302 */
2303 foh = GET_OUTHDR(ps, pm);
2304 foh_len = foh->len;
2305
2306 /*
2307 * Empty read: we reached the end of the buffer.
2308 */
2309 if (foh_len == sizeof(*foh))
2310 break;
2311
2312 /*
2313 * Corrupted message.
2314 */
2315 if (foh_len < sizeof(*foh) + sizeof(*fd)) {
2316 DWARNX("readdir reply too short");
2317 error = EIO;
2318 goto out;
2319 }
2320
2321
2322 fd = GET_OUTPAYLOAD(ps, pm, fuse_dirent);
2323 fd_len = foh_len - sizeof(*foh);
2324
2325 pnd->pnd_all_fd = realloc(pnd->pnd_all_fd,
2326 pnd->pnd_all_fd_len + fd_len);
2327 if (pnd->pnd_all_fd == NULL)
2328 DERR(EX_OSERR, "malloc failed");
2329
2330 afdp = (char *)(void *)pnd->pnd_all_fd + pnd->pnd_all_fd_len;
2331 (void)memcpy(afdp, fd, fd_len);
2332
2333 pnd->pnd_all_fd_len += fd_len;
2334 fd_offset += fd_len;
2335
2336 ps->ps_destroy_msg(pm);
2337 pm = NULL;
2338
2339 /*
2340 * If the buffer was not completely filled,
2341 * that is, if there is room for the biggest
2342 * struct dirent possible, then we are done:
2343 * no need to issue another READDIR to see
2344 * an empty reply.
2345 */
2346 } while (foh_len >= fd_maxlen - (sizeof(*fd) + MAXPATHLEN));
2347
2348 if (fuse_to_dirent(pu, opc, pnd->pnd_all_fd, pnd->pnd_all_fd_len) == -1)
2349 error = EIO;
2350
2351 out:
2352 if (pnd->pnd_all_fd != NULL) {
2353 free(pnd->pnd_all_fd);
2354 pnd->pnd_all_fd = NULL;
2355 pnd->pnd_all_fd_len = 0;
2356 }
2357
2358 if (pm != NULL)
2359 ps->ps_destroy_msg(pm);
2360
2361 if (error == 0)
2362 error = readdir_buffered(opc, dent, readoff,
2363 reslen, pcr, eofflag, cookies, ncookies);
2364
2365 /*
2366 * Schedule queued readdir requests
2367 */
2368 pnd->pnd_flags &= ~PND_INREADDIR;
2369 (void)dequeue_requests(ps, opc, PCQ_READDIR, DEQUEUE_ALL);
2370
2371 #ifdef PERFUSE_DEBUG
2372 if (perfuse_diagflags & PDF_READDIR)
2373 DPRINTF("%s: READDIR opc = %p exit critical section\n",
2374 __func__, (void *)opc);
2375 #endif
2376
2377 return error;
2378 }
2379
2380 int
2381 perfuse_node_readlink(pu, opc, pcr, linkname, linklen)
2382 struct puffs_usermount *pu;
2383 puffs_cookie_t opc;
2384 const struct puffs_cred *pcr;
2385 char *linkname;
2386 size_t *linklen;
2387 {
2388 struct perfuse_state *ps;
2389 perfuse_msg_t *pm;
2390 int error;
2391 size_t len;
2392 struct fuse_out_header *foh;
2393
2394 if (PERFUSE_NODE_DATA(opc)->pnd_flags & PND_REMOVED)
2395 return ENOENT;
2396
2397 /*
2398 * R-- required on parent, R-- required on link
2399 */
2400 if (no_access((puffs_cookie_t)PERFUSE_NODE_DATA(opc)->pnd_parent,
2401 pcr, PUFFS_VREAD) ||
2402 no_access(opc, pcr, PUFFS_VREAD))
2403 return EACCES;
2404
2405 ps = puffs_getspecific(pu);
2406
2407 pm = ps->ps_new_msg(pu, opc, FUSE_READLINK, 0, pcr);
2408
2409 if ((error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply)) != 0)
2410 goto out;
2411
2412 foh = GET_OUTHDR(ps, pm);
2413 len = foh->len - sizeof(*foh) + 1;
2414 if (len > *linklen)
2415 DERRX(EX_PROTOCOL, "path len = %zd too long", len);
2416
2417 *linklen = len;
2418 (void)strlcpy(linkname, _GET_OUTPAYLOAD(ps, pm, char *), len);
2419 out:
2420 ps->ps_destroy_msg(pm);
2421
2422 return error;
2423 }
2424
2425 int
2426 perfuse_node_reclaim(pu, opc)
2427 struct puffs_usermount *pu;
2428 puffs_cookie_t opc;
2429 {
2430 struct perfuse_state *ps;
2431 perfuse_msg_t *pm;
2432 struct perfuse_node_data *pnd;
2433 struct fuse_forget_in *ffi;
2434 struct puffs_node *pn;
2435 struct puffs_node *pn_root;
2436
2437 ps = puffs_getspecific(pu);
2438 pnd = PERFUSE_NODE_DATA(opc);
2439
2440 /*
2441 * Never forget the root.
2442 */
2443 if (pnd->pnd_ino == FUSE_ROOT_ID)
2444 return 0;
2445
2446 pnd->pnd_flags |= PND_RECLAIMED;
2447
2448 #ifdef PERFUSE_DEBUG
2449 if (perfuse_diagflags & PDF_RECLAIM)
2450 DPRINTF("%s (nodeid %"PRId64") reclaimed\n",
2451 perfuse_node_path(opc), pnd->pnd_ino);
2452 #endif
2453
2454 pn_root = puffs_getroot(pu);
2455 pn = (struct puffs_node *)opc;
2456 while (pn != pn_root) {
2457 struct puffs_node *parent_pn;
2458
2459 pnd = PERFUSE_NODE_DATA(pn);
2460
2461 #ifdef PERFUSE_DEBUG
2462 if (perfuse_diagflags & PDF_RECLAIM)
2463 DPRINTF("%s (nodeid %"PRId64") is %sreclaimed, "
2464 "has childcount %d %s%s%s%s, pending ops:%s%s%s\n",
2465 perfuse_node_path((puffs_cookie_t)pn), pnd->pnd_ino,
2466 pnd->pnd_flags & PND_RECLAIMED ? "" : "not ",
2467 pnd->pnd_childcount,
2468 pnd->pnd_flags & PND_OPEN ? "open " : "not open",
2469 pnd->pnd_flags & PND_RFH ? "r" : "",
2470 pnd->pnd_flags & PND_WFH ? "w" : "",
2471 pnd->pnd_flags & PND_BUSY ? "" : " none",
2472 pnd->pnd_flags & PND_INREADDIR ? " readdir" : "",
2473 pnd->pnd_flags & PND_INWRITE ? " write" : "",
2474 pnd->pnd_flags & PND_INOPEN ? " open" : "");
2475 #endif
2476
2477 if (!(pnd->pnd_flags & PND_RECLAIMED) ||
2478 (pnd->pnd_childcount != 0))
2479 return 0;
2480
2481 #ifdef PERFUSE_DEBUG
2482 if ((pnd->pnd_flags & PND_OPEN) ||
2483 !TAILQ_EMPTY(&pnd->pnd_pcq))
2484 DERRX(EX_SOFTWARE, "%s: opc = %p: still open",
2485 __func__, (void *)opc);
2486
2487 if ((pnd->pnd_flags & PND_BUSY) ||
2488 !TAILQ_EMPTY(&pnd->pnd_pcq))
2489 DERRX(EX_SOFTWARE, "%s: opc = %p: ongoing operations",
2490 __func__, (void *)opc);
2491 #endif
2492
2493 /*
2494 * Send the FORGET message
2495 */
2496 pm = ps->ps_new_msg(pu, (puffs_cookie_t)pn, FUSE_FORGET,
2497 sizeof(*ffi), NULL);
2498 ffi = GET_INPAYLOAD(ps, pm, fuse_forget_in);
2499 ffi->nlookup = pnd->pnd_nlookup;
2500
2501 /*
2502 * No reply is expected, pm is freed in xchg_msg
2503 */
2504 (void)xchg_msg(pu, (puffs_cookie_t)pn,
2505 pm, UNSPEC_REPLY_LEN, no_reply);
2506
2507 parent_pn = pnd->pnd_parent;
2508
2509 perfuse_destroy_pn(pu, pn);
2510
2511 pn = parent_pn;
2512 }
2513
2514 return 0;
2515 }
2516
2517 int
2518 perfuse_node_inactive(pu, opc)
2519 struct puffs_usermount *pu;
2520 puffs_cookie_t opc;
2521 {
2522 struct perfuse_state *ps;
2523 struct perfuse_node_data *pnd;
2524
2525 ps = puffs_getspecific(pu);
2526 pnd = PERFUSE_NODE_DATA(opc);
2527
2528 if (!(pnd->pnd_flags & (PND_OPEN|PND_REMOVED)))
2529 return 0;
2530
2531 /*
2532 * Make sure all operation are finished
2533 * There can be an ongoing write. Other
2534 * operation wait for all data before
2535 * the close/inactive.
2536 */
2537 while (pnd->pnd_flags & PND_INWRITE)
2538 requeue_request(pu, opc, PCQ_AFTERWRITE);
2539
2540 /*
2541 * The inactive operation may be cancelled.
2542 * If no open is in progress, set PND_INOPEN
2543 * so that a new open will be queued.
2544 */
2545 if (pnd->pnd_flags & PND_INOPEN)
2546 return 0;
2547
2548 pnd->pnd_flags |= PND_INOPEN;
2549
2550 /*
2551 * Sync data
2552 */
2553 if (pnd->pnd_flags & PND_DIRTY)
2554 (void)perfuse_node_fsync(pu, opc, NULL, 0, 0, 0);
2555
2556 /*
2557 * Close handles
2558 */
2559 if (pnd->pnd_flags & PND_WFH)
2560 (void)perfuse_node_close_common(pu, opc, FWRITE);
2561
2562 if (pnd->pnd_flags & PND_RFH)
2563 (void)perfuse_node_close_common(pu, opc, FREAD);
2564
2565 /*
2566 * This will cause a reclaim to be sent
2567 */
2568 if (pnd->pnd_flags & PND_REMOVED)
2569 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
2570
2571 /*
2572 * Schedule awaiting operations
2573 */
2574 pnd->pnd_flags &= ~PND_INOPEN;
2575 (void)dequeue_requests(ps, opc, PCQ_OPEN, DEQUEUE_ALL);
2576
2577 return 0;
2578 }
2579
2580
2581 /* ARGSUSED0 */
2582 int
2583 perfuse_node_print(pu, opc)
2584 struct puffs_usermount *pu;
2585 puffs_cookie_t opc;
2586 {
2587 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2588 return 0;
2589 }
2590
2591 /* ARGSUSED0 */
2592 int
2593 perfuse_node_pathconf(pu, opc, name, retval)
2594 struct puffs_usermount *pu;
2595 puffs_cookie_t opc;
2596 int name;
2597 int *retval;
2598 {
2599 DERRX(EX_SOFTWARE, "%s: UNIMPLEMENTED (FATAL)", __func__);
2600 return 0;
2601 }
2602
2603 /* id is unused */
2604 /* ARGSUSED2 */
2605 int
2606 perfuse_node_advlock(pu, opc, id, op, fl, flags)
2607 struct puffs_usermount *pu;
2608 puffs_cookie_t opc;
2609 void *id;
2610 int op;
2611 struct flock *fl;
2612 int flags;
2613 {
2614 struct perfuse_state *ps;
2615 int fop;
2616 perfuse_msg_t *pm;
2617 struct fuse_lk_in *fli;
2618 struct fuse_lk_out *flo;
2619 int error;
2620
2621 ps = puffs_getspecific(pu);
2622
2623 if (op == F_GETLK)
2624 fop = FUSE_GETLK;
2625 else
2626 fop = (flags & F_WAIT) ? FUSE_SETLKW : FUSE_SETLK;
2627
2628 pm = ps->ps_new_msg(pu, opc, fop, sizeof(*fli), NULL);
2629 fli = GET_INPAYLOAD(ps, pm, fuse_lk_in);
2630 fli->fh = perfuse_get_fh(opc, FWRITE);
2631 fli->owner = fl->l_pid;
2632 fli->lk.start = fl->l_start;
2633 fli->lk.end = fl->l_start + fl->l_len;
2634 fli->lk.type = fl->l_type;
2635 fli->lk.pid = fl->l_pid;
2636 fli->lk_flags = (flags & F_FLOCK) ? FUSE_LK_FLOCK : 0;
2637
2638 #ifdef PERFUSE_DEBUG
2639 if (perfuse_diagflags & PDF_FH)
2640 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2641 __func__, (void *)opc,
2642 PERFUSE_NODE_DATA(opc)->pnd_ino, fli->fh);
2643 #endif
2644
2645 if ((error = xchg_msg(pu, opc, pm, sizeof(*flo), wait_reply)) != 0)
2646 goto out;
2647
2648 flo = GET_OUTPAYLOAD(ps, pm, fuse_lk_out);
2649 fl->l_start = flo->lk.start;
2650 fl->l_len = flo->lk.end - flo->lk.start;
2651 fl->l_pid = flo->lk.pid;
2652 fl->l_type = flo->lk.type;
2653 fl->l_whence = SEEK_SET; /* libfuse hardcodes it */
2654
2655 /*
2656 * Save or clear the lock
2657 */
2658 switch (op) {
2659 case F_SETLK:
2660 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = flo->lk.pid;
2661 break;
2662 case F_UNLCK:
2663 PERFUSE_NODE_DATA(opc)->pnd_lock_owner = 0;
2664 break;
2665 default:
2666 break;
2667 }
2668
2669 out:
2670 ps->ps_destroy_msg(pm);
2671
2672 return error;
2673 }
2674
2675 int
2676 perfuse_node_read(pu, opc, buf, offset, resid, pcr, ioflag)
2677 struct puffs_usermount *pu;
2678 puffs_cookie_t opc;
2679 uint8_t *buf;
2680 off_t offset;
2681 size_t *resid;
2682 const struct puffs_cred *pcr;
2683 int ioflag;
2684 {
2685 struct perfuse_state *ps;
2686 struct perfuse_node_data *pnd;
2687 perfuse_msg_t *pm;
2688 struct fuse_read_in *fri;
2689 struct fuse_out_header *foh;
2690 size_t readen;
2691 int error;
2692
2693 ps = puffs_getspecific(pu);
2694 pnd = PERFUSE_NODE_DATA(opc);
2695 pm = NULL;
2696
2697 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
2698 return EBADF;
2699
2700 do {
2701 size_t max_read;
2702
2703 max_read = ps->ps_max_readahead - sizeof(*foh);
2704 /*
2705 * flags may be set to FUSE_READ_LOCKOWNER
2706 * if lock_owner is provided.
2707 */
2708 pm = ps->ps_new_msg(pu, opc, FUSE_READ, sizeof(*fri), pcr);
2709 fri = GET_INPAYLOAD(ps, pm, fuse_read_in);
2710 fri->fh = perfuse_get_fh(opc, FREAD);
2711 fri->offset = offset;
2712 fri->size = (uint32_t)MIN(*resid, max_read);
2713 fri->read_flags = 0; /* XXX Unused by libfuse? */
2714 fri->lock_owner = pnd->pnd_lock_owner;
2715 fri->flags = 0;
2716 fri->flags |= (fri->lock_owner != 0) ? FUSE_READ_LOCKOWNER : 0;
2717
2718 #ifdef PERFUSE_DEBUG
2719 if (perfuse_diagflags & PDF_FH)
2720 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2721 __func__, (void *)opc, pnd->pnd_ino, fri->fh);
2722 #endif
2723 error = xchg_msg(pu, opc, pm, UNSPEC_REPLY_LEN, wait_reply);
2724
2725 if (error != 0)
2726 goto out;
2727
2728 foh = GET_OUTHDR(ps, pm);
2729 readen = foh->len - sizeof(*foh);
2730
2731 #ifdef PERFUSE_DEBUG
2732 if (readen > *resid)
2733 DERRX(EX_SOFTWARE, "%s: Unexpected big read %zd",
2734 __func__, readen);
2735 #endif
2736
2737 (void)memcpy(buf, _GET_OUTPAYLOAD(ps, pm, char *), readen);
2738
2739 buf += readen;
2740 offset += readen;
2741 *resid -= readen;
2742
2743 ps->ps_destroy_msg(pm);
2744 pm = NULL;
2745 } while ((*resid != 0) && (readen != 0));
2746
2747 if (ioflag & (IO_SYNC|IO_DSYNC))
2748 ps->ps_syncreads++;
2749 else
2750 ps->ps_asyncreads++;
2751
2752 out:
2753 if (pm != NULL)
2754 ps->ps_destroy_msg(pm);
2755
2756 return error;
2757 }
2758
2759 int
2760 perfuse_node_write(pu, opc, buf, offset, resid, pcr, ioflag)
2761 struct puffs_usermount *pu;
2762 puffs_cookie_t opc;
2763 uint8_t *buf;
2764 off_t offset;
2765 size_t *resid;
2766 const struct puffs_cred *pcr;
2767 int ioflag;
2768 {
2769 struct perfuse_state *ps;
2770 struct perfuse_node_data *pnd;
2771 perfuse_msg_t *pm;
2772 struct fuse_write_in *fwi;
2773 struct fuse_write_out *fwo;
2774 size_t data_len;
2775 size_t payload_len;
2776 size_t written;
2777 int error;
2778
2779 ps = puffs_getspecific(pu);
2780 pnd = PERFUSE_NODE_DATA(opc);
2781 written = 0;
2782
2783 if (puffs_pn_getvap((struct puffs_node *)opc)->va_type == VDIR)
2784 return EBADF;
2785
2786 /*
2787 * We need to queue write requests in order to avoid
2788 * dequeueing PCQ_AFTERWRITE when there are pending writes.
2789 */
2790 while (pnd->pnd_flags & PND_INWRITE)
2791 requeue_request(pu, opc, PCQ_WRITE);
2792 pnd->pnd_flags |= PND_INWRITE;
2793
2794 /*
2795 * append flag: we may have to read file size first.
2796 */
2797 if (ioflag & PUFFS_IO_APPEND)
2798 offset = ((struct puffs_node *)opc)->pn_va.va_size;
2799
2800 pm = NULL;
2801
2802 do {
2803 size_t max_write;
2804 /*
2805 * There is a writepage flag when data
2806 * is PAGE_SIZE-aligned. Use it for
2807 * everything but the data after the last
2808 * page boundary.
2809 */
2810 max_write = ps->ps_max_write - sizeof(*fwi);
2811
2812 data_len = MIN(*resid, max_write);
2813 if (data_len > PAGE_SIZE)
2814 data_len = data_len & ~(PAGE_SIZE - 1);
2815
2816 payload_len = data_len + sizeof(*fwi);
2817
2818 /*
2819 * flags may be set to FUSE_WRITE_CACHE (XXX usage?)
2820 * or FUSE_WRITE_LOCKOWNER, if lock_owner is provided.
2821 * write_flags is set to 1 for writepage.
2822 */
2823 pm = ps->ps_new_msg(pu, opc, FUSE_WRITE, payload_len, pcr);
2824 fwi = GET_INPAYLOAD(ps, pm, fuse_write_in);
2825 fwi->fh = perfuse_get_fh(opc, FWRITE);
2826 fwi->offset = offset;
2827 fwi->size = (uint32_t)data_len;
2828 fwi->write_flags = (fwi->size % PAGE_SIZE) ? 0 : 1;
2829 fwi->lock_owner = pnd->pnd_lock_owner;
2830 fwi->flags = 0;
2831 fwi->flags |= (fwi->lock_owner != 0) ? FUSE_WRITE_LOCKOWNER : 0;
2832 fwi->flags |= (ioflag & IO_DIRECT) ? 0 : FUSE_WRITE_CACHE;
2833 (void)memcpy((fwi + 1), buf, data_len);
2834
2835
2836 #ifdef PERFUSE_DEBUG
2837 if (perfuse_diagflags & PDF_FH)
2838 DPRINTF("%s: opc = %p, ino = %"PRId64", fh = 0x%"PRIx64"\n",
2839 __func__, (void *)opc, pnd->pnd_ino, fwi->fh);
2840 #endif
2841 if ((error = xchg_msg(pu, opc, pm,
2842 sizeof(*fwo), wait_reply)) != 0)
2843 goto out;
2844
2845 fwo = GET_OUTPAYLOAD(ps, pm, fuse_write_out);
2846 written = fwo->size;
2847 #ifdef PERFUSE_DEBUG
2848 if (written > *resid)
2849 DERRX(EX_SOFTWARE, "%s: Unexpected big write %zd",
2850 __func__, written);
2851 #endif
2852 *resid -= written;
2853 offset += written;
2854 buf += written;
2855
2856 ps->ps_destroy_msg(pm);
2857 pm = NULL;
2858 } while (*resid != 0);
2859
2860 /*
2861 * puffs_ops(3) says
2862 * "everything must be written or an error will be generated"
2863 */
2864 if (*resid != 0)
2865 error = EFBIG;
2866
2867 if (ioflag & (IO_SYNC|IO_DSYNC))
2868 ps->ps_syncwrites++;
2869 else
2870 ps->ps_asyncwrites++;
2871
2872 /*
2873 * Remember to sync the file
2874 */
2875 pnd->pnd_flags |= PND_DIRTY;
2876
2877 #ifdef PERFUSE_DEBUG
2878 if (perfuse_diagflags & PDF_SYNC)
2879 DPRINTF("%s: DIRTY opc = %p, file = \"%s\"\n",
2880 __func__, (void*)opc, perfuse_node_path(opc));
2881 #endif
2882 out:
2883 if (pm != NULL)
2884 ps->ps_destroy_msg(pm);
2885
2886 /*
2887 * If there are no more queued write, we can resume
2888 * an operation awaiting write completion.
2889 */
2890 pnd->pnd_flags &= ~PND_INWRITE;
2891 if (dequeue_requests(ps, opc, PCQ_WRITE, 1) == 0)
2892 (void)dequeue_requests(ps, opc, PCQ_AFTERWRITE, DEQUEUE_ALL);
2893
2894 return error;
2895 }
2896
2897 /* ARGSUSED0 */
2898 void
2899 perfuse_cache_write(pu, opc, size, runs)
2900 struct puffs_usermount *pu;
2901 puffs_cookie_t opc;
2902 size_t size;
2903 struct puffs_cacherun *runs;
2904 {
2905 return;
2906 }
2907
2908