Thu Mar 8 14:58:58 2012 UTC ()
The kernel can lookup the same node multiple time and will reclaim as
many times it looked up. All reclaims but the last one must be ignored,
otherwise we discard a node which will still get operations. We therefore
have to keep track of lookup/reclaim count and hnour reclaims only when
the count reaches zero.


(manu)
diff -r1.50 -r1.51 src/lib/libperfuse/ops.c
diff -r1.25 -r1.26 src/lib/libperfuse/perfuse_priv.h
diff -r1.15 -r1.16 src/lib/libperfuse/subr.c

cvs diff -r1.50 -r1.51 src/lib/libperfuse/ops.c (switch to unified diff)

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

cvs diff -r1.25 -r1.26 src/lib/libperfuse/perfuse_priv.h (switch to unified diff)

--- src/lib/libperfuse/perfuse_priv.h 2012/01/29 06:22:02 1.25
+++ src/lib/libperfuse/perfuse_priv.h 2012/03/08 14:58:57 1.26
@@ -1,262 +1,263 @@ @@ -1,262 +1,263 @@
1/* $NetBSD: perfuse_priv.h,v 1.25 2012/01/29 06:22:02 manu Exp $ */ 1/* $NetBSD: perfuse_priv.h,v 1.26 2012/03/08 14:58:57 manu Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. 4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
5 *  5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 *  14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */  26 */
27 27
28#ifndef _PERFUSE_PRIV_H_ 28#ifndef _PERFUSE_PRIV_H_
29#define _PERFUSE_PRIV_H_ 29#define _PERFUSE_PRIV_H_
30 30
31#include <syslog.h> 31#include <syslog.h>
32#include <paths.h> 32#include <paths.h>
33#include <err.h> 33#include <err.h>
34#include <sysexits.h> 34#include <sysexits.h>
35#include <puffs.h> 35#include <puffs.h>
36 36
37#include "perfuse_if.h" 37#include "perfuse_if.h"
38#include "fuse.h" 38#include "fuse.h"
39 39
40#define PERFUSE_TRACECOUNT_MAX 4096 40#define PERFUSE_TRACECOUNT_MAX 4096
41#define PERFUSE_TRACEPATH_MAX 256 41#define PERFUSE_TRACEPATH_MAX 256
42struct perfuse_trace { 42struct perfuse_trace {
43 int pt_opcode; 43 int pt_opcode;
44 char pt_path[PERFUSE_TRACEPATH_MAX]; 44 char pt_path[PERFUSE_TRACEPATH_MAX];
45 char pt_extra[BUFSIZ]; 45 char pt_extra[BUFSIZ];
46 int pt_error; 46 int pt_error;
47 enum { inxchg, done } pt_status; 47 enum { inxchg, done } pt_status;
48 struct timespec pt_start; 48 struct timespec pt_start;
49 struct timespec pt_end; 49 struct timespec pt_end;
50 TAILQ_ENTRY(perfuse_trace) pt_list; 50 TAILQ_ENTRY(perfuse_trace) pt_list;
51}; 51};
52 52
53struct perfuse_state { 53struct perfuse_state {
54 void *ps_private; /* Private field for libperfuse user */ 54 void *ps_private; /* Private field for libperfuse user */
55 struct puffs_usermount *ps_pu; 55 struct puffs_usermount *ps_pu;
56 struct puffs_node *ps_root; 56 struct puffs_node *ps_root;
57 uid_t ps_owner_uid; 57 uid_t ps_owner_uid;
58 int ps_flags; 58 int ps_flags;
59#define PS_NO_ACCESS 0x0001 /* access is unimplemented; */ 59#define PS_NO_ACCESS 0x0001 /* access is unimplemented; */
60#define PS_NO_CREAT 0x0004 /* create is unimplemented */ 60#define PS_NO_CREAT 0x0004 /* create is unimplemented */
61#define PS_INLOOP 0x0008 /* puffs mainloop started */ 61#define PS_INLOOP 0x0008 /* puffs mainloop started */
62 uint64_t ps_fsid; 62 uint64_t ps_fsid;
63 uint32_t ps_max_readahead; 63 uint32_t ps_max_readahead;
64 uint32_t ps_max_write; 64 uint32_t ps_max_write;
65 uint64_t ps_syncreads; 65 uint64_t ps_syncreads;
66 uint64_t ps_syncwrites; 66 uint64_t ps_syncwrites;
67 uint64_t ps_asyncreads; 67 uint64_t ps_asyncreads;
68 uint64_t ps_asyncwrites; 68 uint64_t ps_asyncwrites;
69 char *ps_source; 69 char *ps_source;
70 char *ps_target; 70 char *ps_target;
71 char *ps_filesystemtype; 71 char *ps_filesystemtype;
72 int ps_mountflags; 72 int ps_mountflags;
73 uint64_t ps_unique; 73 uint64_t ps_unique;
74 perfuse_new_msg_fn ps_new_msg; 74 perfuse_new_msg_fn ps_new_msg;
75 perfuse_xchg_msg_fn ps_xchg_msg; 75 perfuse_xchg_msg_fn ps_xchg_msg;
76 perfuse_destroy_msg_fn ps_destroy_msg; 76 perfuse_destroy_msg_fn ps_destroy_msg;
77 perfuse_get_inhdr_fn ps_get_inhdr; 77 perfuse_get_inhdr_fn ps_get_inhdr;
78 perfuse_get_inpayload_fn ps_get_inpayload; 78 perfuse_get_inpayload_fn ps_get_inpayload;
79 perfuse_get_outhdr_fn ps_get_outhdr; 79 perfuse_get_outhdr_fn ps_get_outhdr;
80 perfuse_get_outpayload_fn ps_get_outpayload; 80 perfuse_get_outpayload_fn ps_get_outpayload;
81 perfuse_umount_fn ps_umount; 81 perfuse_umount_fn ps_umount;
82 TAILQ_HEAD(,perfuse_trace) ps_trace; 82 TAILQ_HEAD(,perfuse_trace) ps_trace;
83 uint64_t ps_tracecount; 83 uint64_t ps_tracecount;
84}; 84};
85 85
86 86
87enum perfuse_qtype {  87enum perfuse_qtype {
88 PCQ_READDIR,  88 PCQ_READDIR,
89 PCQ_READ, 89 PCQ_READ,
90 PCQ_WRITE, 90 PCQ_WRITE,
91 PCQ_AFTERWRITE, 91 PCQ_AFTERWRITE,
92 PCQ_OPEN, 92 PCQ_OPEN,
93 PCQ_AFTERXCHG, 93 PCQ_AFTERXCHG,
94 PCQ_RESIZE 94 PCQ_RESIZE
95}; 95};
96 96
97#ifdef PERFUSE_DEBUG 97#ifdef PERFUSE_DEBUG
98extern const char *perfuse_qtypestr[]; 98extern const char *perfuse_qtypestr[];
99#endif 99#endif
100 100
101struct perfuse_cc_queue { 101struct perfuse_cc_queue {
102 enum perfuse_qtype pcq_type; 102 enum perfuse_qtype pcq_type;
103 struct puffs_cc *pcq_cc; 103 struct puffs_cc *pcq_cc;
104 TAILQ_ENTRY(perfuse_cc_queue) pcq_next; 104 TAILQ_ENTRY(perfuse_cc_queue) pcq_next;
105}; 105};
106 106
107struct perfuse_node_data { 107struct perfuse_node_data {
108 uint64_t pnd_rfh; 108 uint64_t pnd_rfh;
109 uint64_t pnd_wfh; 109 uint64_t pnd_wfh;
110 uint64_t pnd_nodeid; /* nodeid, this is not inode */ 110 uint64_t pnd_nodeid; /* nodeid, this is not inode */
111 uint64_t pnd_nlookup; /* vnode refcount */ 111 uint64_t pnd_fuse_nlookup; /* vnode refcount */
 112 int pnd_puffs_nlookup; /* vnode refcount */
112 uint64_t pnd_lock_owner; 113 uint64_t pnd_lock_owner;
113 struct dirent *pnd_dirent; /* native buffer for readdir */ 114 struct dirent *pnd_dirent; /* native buffer for readdir */
114 off_t pnd_dirent_len; 115 off_t pnd_dirent_len;
115 struct fuse_dirent *pnd_all_fd; /* FUSE buffer for readdir */ 116 struct fuse_dirent *pnd_all_fd; /* FUSE buffer for readdir */
116 size_t pnd_all_fd_len; 117 size_t pnd_all_fd_len;
117 uint64_t pnd_fd_cookie; /* opaque readdir ref from fs */ 118 uint64_t pnd_fd_cookie; /* opaque readdir ref from fs */
118 TAILQ_HEAD(,perfuse_cc_queue) pnd_pcq; /* queued requests */ 119 TAILQ_HEAD(,perfuse_cc_queue) pnd_pcq; /* queued requests */
119 int pnd_flags; 120 int pnd_flags;
120#define PND_RECLAIMED 0x001 /* reclaim pending */ 121#define PND_RECLAIMED 0x001 /* reclaim pending */
121#define PND_INREADDIR 0x002 /* readdir in progress */ 122#define PND_INREADDIR 0x002 /* readdir in progress */
122#define PND_DIRTY 0x004 /* There is some data to sync */ 123#define PND_DIRTY 0x004 /* There is some data to sync */
123#define PND_RFH 0x008 /* Read FH allocated */ 124#define PND_RFH 0x008 /* Read FH allocated */
124#define PND_WFH 0x010 /* Write FH allocated */ 125#define PND_WFH 0x010 /* Write FH allocated */
125#define PND_REMOVED 0x020 /* Node was removed */ 126#define PND_REMOVED 0x020 /* Node was removed */
126#define PND_INWRITE 0x040 /* write in progress */ 127#define PND_INWRITE 0x040 /* write in progress */
127#define PND_INOPEN 0x100 /* open in progress */ 128#define PND_INOPEN 0x100 /* open in progress */
128#define PND_INXCHG 0x400 /* FUSE exchange in progress */ 129#define PND_INXCHG 0x400 /* FUSE exchange in progress */
129#define PND_INRESIZE 0x800 /* resize in progress */ 130#define PND_INRESIZE 0x800 /* resize in progress */
130 131
131#define PND_OPEN (PND_RFH|PND_WFH) /* File is open */ 132#define PND_OPEN (PND_RFH|PND_WFH) /* File is open */
132#define PND_BUSY (PND_INREADDIR|PND_INWRITE|PND_INOPEN) 133#define PND_BUSY (PND_INREADDIR|PND_INWRITE|PND_INOPEN)
133 puffs_cookie_t pnd_parent; 134 puffs_cookie_t pnd_parent;
134 int pnd_childcount; 135 int pnd_childcount;
135 TAILQ_ENTRY(perfuse_node_data) pnd_next; 136 TAILQ_ENTRY(perfuse_node_data) pnd_next;
136 puffs_cookie_t pnd_pn; 137 puffs_cookie_t pnd_pn;
137 char pnd_name[MAXPATHLEN]; /* node name */ 138 char pnd_name[MAXPATHLEN]; /* node name */
138 TAILQ_HEAD(,perfuse_node_data) pnd_children; 139 TAILQ_HEAD(,perfuse_node_data) pnd_children;
139 struct timespec pnd_entry_expire; 140 struct timespec pnd_entry_expire;
140 struct timespec pnd_attr_expire; 141 struct timespec pnd_attr_expire;
141}; 142};
142 143
143#define PERFUSE_NODE_DATA(opc) \ 144#define PERFUSE_NODE_DATA(opc) \
144 ((struct perfuse_node_data *)puffs_pn_getpriv((struct puffs_node *)opc)) 145 ((struct perfuse_node_data *)puffs_pn_getpriv((struct puffs_node *)opc))
145 146
146 147
147#define UNSPEC_REPLY_LEN PERFUSE_UNSPEC_REPLY_LEN /* shorter! */ 148#define UNSPEC_REPLY_LEN PERFUSE_UNSPEC_REPLY_LEN /* shorter! */
148#define NO_PAYLOAD_REPLY_LEN 0 149#define NO_PAYLOAD_REPLY_LEN 0
149 150
150#define GET_INHDR(ps, pm) ps->ps_get_inhdr(pm) 151#define GET_INHDR(ps, pm) ps->ps_get_inhdr(pm)
151#define GET_INPAYLOAD(ps, pm, type) \ 152#define GET_INPAYLOAD(ps, pm, type) \
152 (struct type *)(void *)ps->ps_get_inpayload(pm) 153 (struct type *)(void *)ps->ps_get_inpayload(pm)
153#define _GET_INPAYLOAD(ps, pm, type) (type)ps->ps_get_inpayload(pm) 154#define _GET_INPAYLOAD(ps, pm, type) (type)ps->ps_get_inpayload(pm)
154#define GET_OUTHDR(ps, pm) ps->ps_get_outhdr(pm) 155#define GET_OUTHDR(ps, pm) ps->ps_get_outhdr(pm)
155#define GET_OUTPAYLOAD(ps, pm, type) \ 156#define GET_OUTPAYLOAD(ps, pm, type) \
156 (struct type *)(void *)ps->ps_get_outpayload(pm) 157 (struct type *)(void *)ps->ps_get_outpayload(pm)
157#define _GET_OUTPAYLOAD(ps, pm, type) (type)ps->ps_get_outpayload(pm) 158#define _GET_OUTPAYLOAD(ps, pm, type) (type)ps->ps_get_outpayload(pm)
158 159
159__BEGIN_DECLS 160__BEGIN_DECLS
160 161
161struct puffs_node *perfuse_new_pn(struct puffs_usermount *, const char *, 162struct puffs_node *perfuse_new_pn(struct puffs_usermount *, const char *,
162 struct puffs_node *); 163 struct puffs_node *);
163void perfuse_destroy_pn(struct puffs_node *); 164void perfuse_destroy_pn(struct puffs_node *);
164void perfuse_new_fh(puffs_cookie_t, uint64_t, int); 165void perfuse_new_fh(puffs_cookie_t, uint64_t, int);
165void perfuse_destroy_fh(puffs_cookie_t, uint64_t); 166void perfuse_destroy_fh(puffs_cookie_t, uint64_t);
166uint64_t perfuse_get_fh(puffs_cookie_t, int); 167uint64_t perfuse_get_fh(puffs_cookie_t, int);
167uint64_t perfuse_next_unique(struct puffs_usermount *); 168uint64_t perfuse_next_unique(struct puffs_usermount *);
168char *perfuse_node_path(puffs_cookie_t); 169char *perfuse_node_path(puffs_cookie_t);
169int perfuse_node_close_common(struct puffs_usermount *, puffs_cookie_t, int); 170int perfuse_node_close_common(struct puffs_usermount *, puffs_cookie_t, int);
170const char *perfuse_native_ns(const int, const char *, char *); 171const char *perfuse_native_ns(const int, const char *, char *);
171 172
172char *perfuse_fs_mount(int, ssize_t); 173char *perfuse_fs_mount(int, ssize_t);
173 174
174 175
175/* 176/*
176 * ops.c - filesystem operations 177 * ops.c - filesystem operations
177 */ 178 */
178int perfuse_fs_unmount(struct puffs_usermount *, int); 179int perfuse_fs_unmount(struct puffs_usermount *, int);
179int perfuse_fs_statvfs(struct puffs_usermount *, struct statvfs *); 180int perfuse_fs_statvfs(struct puffs_usermount *, struct statvfs *);
180int perfuse_fs_sync(struct puffs_usermount *, int, 181int perfuse_fs_sync(struct puffs_usermount *, int,
181 const struct puffs_cred *); 182 const struct puffs_cred *);
182int perfuse_fs_fhtonode(struct puffs_usermount *, void *, size_t, 183int perfuse_fs_fhtonode(struct puffs_usermount *, void *, size_t,
183 struct puffs_newinfo *); 184 struct puffs_newinfo *);
184int perfuse_fs_nodetofh(struct puffs_usermount *, puffs_cookie_t, 185int perfuse_fs_nodetofh(struct puffs_usermount *, puffs_cookie_t,
185 void *, size_t *); 186 void *, size_t *);
186void perfuse_fs_suspend(struct puffs_usermount *, int); 187void perfuse_fs_suspend(struct puffs_usermount *, int);
187int perfuse_node_lookup(struct puffs_usermount *, 188int perfuse_node_lookup(struct puffs_usermount *,
188 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *); 189 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *);
189int perfuse_node_create(struct puffs_usermount *, 190int perfuse_node_create(struct puffs_usermount *,
190 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *, 191 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
191 const struct vattr *); 192 const struct vattr *);
192int perfuse_node_mknod(struct puffs_usermount *, 193int perfuse_node_mknod(struct puffs_usermount *,
193 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *, 194 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
194 const struct vattr *); 195 const struct vattr *);
195int perfuse_node_open(struct puffs_usermount *, 196int perfuse_node_open(struct puffs_usermount *,
196 puffs_cookie_t, int, const struct puffs_cred *); 197 puffs_cookie_t, int, const struct puffs_cred *);
197int perfuse_node_close(struct puffs_usermount *, 198int perfuse_node_close(struct puffs_usermount *,
198 puffs_cookie_t, int, const struct puffs_cred *); 199 puffs_cookie_t, int, const struct puffs_cred *);
199int perfuse_node_access(struct puffs_usermount *, 200int perfuse_node_access(struct puffs_usermount *,
200 puffs_cookie_t, int, const struct puffs_cred *); 201 puffs_cookie_t, int, const struct puffs_cred *);
201int perfuse_node_getattr(struct puffs_usermount *, 202int perfuse_node_getattr(struct puffs_usermount *,
202 puffs_cookie_t, struct vattr *, const struct puffs_cred *); 203 puffs_cookie_t, struct vattr *, const struct puffs_cred *);
203int perfuse_node_setattr(struct puffs_usermount *, 204int perfuse_node_setattr(struct puffs_usermount *,
204 puffs_cookie_t, const struct vattr *, const struct puffs_cred *); 205 puffs_cookie_t, const struct vattr *, const struct puffs_cred *);
205int perfuse_node_poll(struct puffs_usermount *, puffs_cookie_t, int *); 206int perfuse_node_poll(struct puffs_usermount *, puffs_cookie_t, int *);
206int perfuse_node_mmap(struct puffs_usermount *, 207int perfuse_node_mmap(struct puffs_usermount *,
207 puffs_cookie_t, vm_prot_t, const struct puffs_cred *); 208 puffs_cookie_t, vm_prot_t, const struct puffs_cred *);
208int perfuse_node_fsync(struct puffs_usermount *, 209int perfuse_node_fsync(struct puffs_usermount *,
209 puffs_cookie_t, const struct puffs_cred *, int, off_t, off_t); 210 puffs_cookie_t, const struct puffs_cred *, int, off_t, off_t);
210int perfuse_node_seek(struct puffs_usermount *, 211int perfuse_node_seek(struct puffs_usermount *,
211 puffs_cookie_t, off_t, off_t, const struct puffs_cred *); 212 puffs_cookie_t, off_t, off_t, const struct puffs_cred *);
212int perfuse_node_remove(struct puffs_usermount *, 213int perfuse_node_remove(struct puffs_usermount *,
213 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); 214 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
214int perfuse_node_link(struct puffs_usermount *, 215int perfuse_node_link(struct puffs_usermount *,
215 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); 216 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
216int perfuse_node_rename(struct puffs_usermount *, 217int perfuse_node_rename(struct puffs_usermount *,
217 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *, 218 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *,
218 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); 219 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
219int perfuse_node_mkdir(struct puffs_usermount *, 220int perfuse_node_mkdir(struct puffs_usermount *,
220 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *, 221 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
221 const struct vattr *); 222 const struct vattr *);
222int perfuse_node_rmdir(struct puffs_usermount *, 223int perfuse_node_rmdir(struct puffs_usermount *,
223 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *); 224 puffs_cookie_t, puffs_cookie_t, const struct puffs_cn *);
224int perfuse_node_symlink(struct puffs_usermount *, 225int perfuse_node_symlink(struct puffs_usermount *,
225 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *, 226 puffs_cookie_t, struct puffs_newinfo *, const struct puffs_cn *,
226 const struct vattr *, const char *); 227 const struct vattr *, const char *);
227int perfuse_node_readdir(struct puffs_usermount *, 228int perfuse_node_readdir(struct puffs_usermount *,
228 puffs_cookie_t, struct dirent *, off_t *, size_t *, 229 puffs_cookie_t, struct dirent *, off_t *, size_t *,
229 const struct puffs_cred *, int *, off_t *, size_t *); 230 const struct puffs_cred *, int *, off_t *, size_t *);
230int perfuse_node_readlink(struct puffs_usermount *, 231int perfuse_node_readlink(struct puffs_usermount *,
231 puffs_cookie_t, const struct puffs_cred *, char *, size_t *); 232 puffs_cookie_t, const struct puffs_cred *, char *, size_t *);
232int perfuse_node_reclaim(struct puffs_usermount *, puffs_cookie_t); 233int perfuse_node_reclaim(struct puffs_usermount *, puffs_cookie_t);
233int perfuse_node_inactive(struct puffs_usermount *, puffs_cookie_t); 234int perfuse_node_inactive(struct puffs_usermount *, puffs_cookie_t);
234int perfuse_node_print(struct puffs_usermount *, puffs_cookie_t); 235int perfuse_node_print(struct puffs_usermount *, puffs_cookie_t);
235int perfuse_node_pathconf(struct puffs_usermount *, 236int perfuse_node_pathconf(struct puffs_usermount *,
236 puffs_cookie_t, int, int *); 237 puffs_cookie_t, int, int *);
237int perfuse_node_advlock(struct puffs_usermount *, 238int perfuse_node_advlock(struct puffs_usermount *,
238 puffs_cookie_t, void *, int, struct flock *, int); 239 puffs_cookie_t, void *, int, struct flock *, int);
239int perfuse_node_read(struct puffs_usermount *, puffs_cookie_t, 240int perfuse_node_read(struct puffs_usermount *, puffs_cookie_t,
240 uint8_t *, off_t, size_t *, const struct puffs_cred *, int); 241 uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
241int perfuse_node_write(struct puffs_usermount *, puffs_cookie_t, 242int perfuse_node_write(struct puffs_usermount *, puffs_cookie_t,
242 uint8_t *, off_t, size_t *, const struct puffs_cred *, int); 243 uint8_t *, off_t, size_t *, const struct puffs_cred *, int);
243void perfuse_cache_write(struct puffs_usermount *, 244void perfuse_cache_write(struct puffs_usermount *,
244 puffs_cookie_t, size_t, struct puffs_cacherun *); 245 puffs_cookie_t, size_t, struct puffs_cacherun *);
245int perfuse_node_getextattr(struct puffs_usermount *, puffs_cookie_t, 246int perfuse_node_getextattr(struct puffs_usermount *, puffs_cookie_t,
246 int, const char *, size_t *, uint8_t *, size_t *,  247 int, const char *, size_t *, uint8_t *, size_t *,
247 const struct puffs_cred *); 248 const struct puffs_cred *);
248int perfuse_node_setextattr(struct puffs_usermount *, puffs_cookie_t, 249int perfuse_node_setextattr(struct puffs_usermount *, puffs_cookie_t,
249 int, const char *, uint8_t *, size_t *, const struct puffs_cred *); 250 int, const char *, uint8_t *, size_t *, const struct puffs_cred *);
250int perfuse_node_listextattr(struct puffs_usermount *, puffs_cookie_t, 251int perfuse_node_listextattr(struct puffs_usermount *, puffs_cookie_t,
251 int, size_t *, uint8_t *, size_t *, int, const struct puffs_cred *); 252 int, size_t *, uint8_t *, size_t *, int, const struct puffs_cred *);
252int perfuse_node_deleteextattr(struct puffs_usermount *, puffs_cookie_t, 253int perfuse_node_deleteextattr(struct puffs_usermount *, puffs_cookie_t,
253 int, const char *, const struct puffs_cred *); 254 int, const char *, const struct puffs_cred *);
254 255
255struct perfuse_trace *perfuse_trace_begin(struct perfuse_state *,  256struct perfuse_trace *perfuse_trace_begin(struct perfuse_state *,
256 puffs_cookie_t, perfuse_msg_t *); 257 puffs_cookie_t, perfuse_msg_t *);
257void perfuse_trace_end(struct perfuse_state *, struct perfuse_trace *, int); 258void perfuse_trace_end(struct perfuse_state *, struct perfuse_trace *, int);
258char *perfuse_opdump_in(struct perfuse_state *, perfuse_msg_t *); 259char *perfuse_opdump_in(struct perfuse_state *, perfuse_msg_t *);
259 260
260__END_DECLS 261__END_DECLS
261 262
262#endif /* _PERFUSE_PRIV_H_ */ 263#endif /* _PERFUSE_PRIV_H_ */

cvs diff -r1.15 -r1.16 src/lib/libperfuse/subr.c (switch to unified diff)

--- src/lib/libperfuse/subr.c 2012/01/29 06:22:02 1.15
+++ src/lib/libperfuse/subr.c 2012/03/08 14:58:57 1.16
@@ -1,296 +1,297 @@ @@ -1,296 +1,297 @@
1/* $NetBSD: subr.c,v 1.15 2012/01/29 06:22:02 manu Exp $ */ 1/* $NetBSD: subr.c,v 1.16 2012/03/08 14:58:57 manu Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved. 4 * Copyright (c) 2010-2011 Emmanuel Dreyfus. All rights reserved.
5 *  5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 *  14 *
15 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 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 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 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 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 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */  26 */
27 27
28#include <stdio.h> 28#include <stdio.h>
29#include <stdlib.h> 29#include <stdlib.h>
30#include <err.h> 30#include <err.h>
31#include <errno.h> 31#include <errno.h>
32#include <sysexits.h> 32#include <sysexits.h>
33#include <syslog.h> 33#include <syslog.h>
34#include <puffs.h> 34#include <puffs.h>
35#include <paths.h> 35#include <paths.h>
36#include <sys/extattr.h> 36#include <sys/extattr.h>
37 37
38#include "perfuse_priv.h" 38#include "perfuse_priv.h"
39 39
40struct perfuse_ns_map { 40struct perfuse_ns_map {
41 const char *pnm_ns; 41 const char *pnm_ns;
42 const size_t pnm_nslen; 42 const size_t pnm_nslen;
43 const int pnm_native_ns; 43 const int pnm_native_ns;
44}; 44};
45 45
46#define PERFUSE_NS_MAP(ns, native_ns) \ 46#define PERFUSE_NS_MAP(ns, native_ns) \
47 { ns ".", sizeof(ns), native_ns } 47 { ns ".", sizeof(ns), native_ns }
48 48
49static size_t node_path(puffs_cookie_t, char *, size_t); 49static size_t node_path(puffs_cookie_t, char *, size_t);
50 50
51struct puffs_node * 51struct puffs_node *
52perfuse_new_pn(pu, name, parent) 52perfuse_new_pn(pu, name, parent)
53 struct puffs_usermount *pu; 53 struct puffs_usermount *pu;
54 const char *name; 54 const char *name;
55 struct puffs_node *parent; 55 struct puffs_node *parent;
56{ 56{
57 struct puffs_node *pn; 57 struct puffs_node *pn;
58 struct perfuse_node_data *pnd; 58 struct perfuse_node_data *pnd;
59 59
60 if ((pnd = malloc(sizeof(*pnd))) == NULL) 60 if ((pnd = malloc(sizeof(*pnd))) == NULL)
61 DERR(EX_OSERR, "%s: malloc failed", __func__); 61 DERR(EX_OSERR, "%s: malloc failed", __func__);
62 62
63 if ((pn = puffs_pn_new(pu, pnd)) == NULL) 63 if ((pn = puffs_pn_new(pu, pnd)) == NULL)
64 DERR(EX_SOFTWARE, "%s: puffs_pn_new failed", __func__); 64 DERR(EX_SOFTWARE, "%s: puffs_pn_new failed", __func__);
65 65
66 (void)memset(pnd, 0, sizeof(*pnd)); 66 (void)memset(pnd, 0, sizeof(*pnd));
67 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 67 pnd->pnd_rfh = FUSE_UNKNOWN_FH;
68 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 68 pnd->pnd_wfh = FUSE_UNKNOWN_FH;
69 pnd->pnd_nodeid = PERFUSE_UNKNOWN_NODEID; 69 pnd->pnd_nodeid = PERFUSE_UNKNOWN_NODEID;
70 pnd->pnd_nlookup = 1; 70 pnd->pnd_fuse_nlookup = 1;
 71 pnd->pnd_puffs_nlookup = 1;
71 pnd->pnd_parent = parent; 72 pnd->pnd_parent = parent;
72 pnd->pnd_pn = (puffs_cookie_t)pn; 73 pnd->pnd_pn = (puffs_cookie_t)pn;
73 (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN); 74 (void)strlcpy(pnd->pnd_name, name, MAXPATHLEN);
74 TAILQ_INIT(&pnd->pnd_pcq); 75 TAILQ_INIT(&pnd->pnd_pcq);
75 TAILQ_INIT(&pnd->pnd_children); 76 TAILQ_INIT(&pnd->pnd_children);
76 77
77 if (parent != NULL) { 78 if (parent != NULL) {
78 struct perfuse_node_data *parent_pnd; 79 struct perfuse_node_data *parent_pnd;
79 80
80 parent_pnd = PERFUSE_NODE_DATA(parent); 81 parent_pnd = PERFUSE_NODE_DATA(parent);
81 TAILQ_INSERT_TAIL(&parent_pnd->pnd_children, pnd, pnd_next); 82 TAILQ_INSERT_TAIL(&parent_pnd->pnd_children, pnd, pnd_next);
82 83
83 parent_pnd->pnd_childcount++; 84 parent_pnd->pnd_childcount++;
84 } 85 }
85 86
86 return pn; 87 return pn;
87} 88}
88 89
89void 90void
90perfuse_destroy_pn(pn) 91perfuse_destroy_pn(pn)
91 struct puffs_node *pn; 92 struct puffs_node *pn;
92{ 93{
93 struct perfuse_node_data *pnd; 94 struct perfuse_node_data *pnd;
94 95
95 pnd = PERFUSE_NODE_DATA(pn); 96 pnd = PERFUSE_NODE_DATA(pn);
96 97
97 if (pnd->pnd_parent != NULL) { 98 if (pnd->pnd_parent != NULL) {
98 struct perfuse_node_data *parent_pnd; 99 struct perfuse_node_data *parent_pnd;
99 100
100 parent_pnd = PERFUSE_NODE_DATA(pnd->pnd_parent); 101 parent_pnd = PERFUSE_NODE_DATA(pnd->pnd_parent);
101 TAILQ_REMOVE(&parent_pnd->pnd_children, pnd, pnd_next); 102 TAILQ_REMOVE(&parent_pnd->pnd_children, pnd, pnd_next);
102 } 103 }
103 104
104 if ((pnd = puffs_pn_getpriv(pn)) != NULL) { 105 if ((pnd = puffs_pn_getpriv(pn)) != NULL) {
105 if (pnd->pnd_parent != NULL) 106 if (pnd->pnd_parent != NULL)
106 PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--; 107 PERFUSE_NODE_DATA(pnd->pnd_parent)->pnd_childcount--;
107 108
108 if (pnd->pnd_dirent != NULL) 109 if (pnd->pnd_dirent != NULL)
109 free(pnd->pnd_dirent); 110 free(pnd->pnd_dirent);
110 111
111 if (pnd->pnd_all_fd != NULL) 112 if (pnd->pnd_all_fd != NULL)
112 free(pnd->pnd_all_fd); 113 free(pnd->pnd_all_fd);
113#ifdef PERFUSE_DEBUG 114#ifdef PERFUSE_DEBUG
114 if (pnd->pnd_flags & PND_OPEN) 115 if (pnd->pnd_flags & PND_OPEN)
115 DERRX(EX_SOFTWARE, "%s: file open", __func__); 116 DERRX(EX_SOFTWARE, "%s: file open", __func__);
116 117
117 if (!TAILQ_EMPTY(&pnd->pnd_pcq)) 118 if (!TAILQ_EMPTY(&pnd->pnd_pcq))
118 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__); 119 DERRX(EX_SOFTWARE, "%s: non empty pnd_pcq", __func__);
119 120
120 if (pnd == NULL) 121 if (pnd == NULL)
121 DERRX(EX_SOFTWARE, "%s: pnd == NULL ???", __func__); 122 DERRX(EX_SOFTWARE, "%s: pnd == NULL ???", __func__);
122#endif /* PERFUSE_DEBUG */ 123#endif /* PERFUSE_DEBUG */
123 124
124 free(pnd); 125 free(pnd);
125 } 126 }
126 127
127 puffs_pn_put(pn); 128 puffs_pn_put(pn);
128 129
129 return; 130 return;
130} 131}
131 132
132 133
133void 134void
134perfuse_new_fh(opc, fh, mode) 135perfuse_new_fh(opc, fh, mode)
135 puffs_cookie_t opc; 136 puffs_cookie_t opc;
136 uint64_t fh; 137 uint64_t fh;
137 int mode; 138 int mode;
138{ 139{
139 struct perfuse_node_data *pnd; 140 struct perfuse_node_data *pnd;
140 141
141 pnd = PERFUSE_NODE_DATA(opc); 142 pnd = PERFUSE_NODE_DATA(opc);
142 143
143 if (mode & FWRITE) { 144 if (mode & FWRITE) {
144 if (pnd->pnd_flags & PND_WFH) 145 if (pnd->pnd_flags & PND_WFH)
145 DERRX(EX_SOFTWARE, "%s: opc = %p, write fh already set", 146 DERRX(EX_SOFTWARE, "%s: opc = %p, write fh already set",
146 __func__, (void *)opc);  147 __func__, (void *)opc);
147 pnd->pnd_wfh = fh; 148 pnd->pnd_wfh = fh;
148 pnd->pnd_flags |= PND_WFH; 149 pnd->pnd_flags |= PND_WFH;
149 }  150 }
150 151
151 if (mode & FREAD) { 152 if (mode & FREAD) {
152 if (pnd->pnd_flags & PND_RFH) 153 if (pnd->pnd_flags & PND_RFH)
153 DERRX(EX_SOFTWARE, "%s: opc = %p, read fh already set", 154 DERRX(EX_SOFTWARE, "%s: opc = %p, read fh already set",
154 __func__, (void *)opc);  155 __func__, (void *)opc);
155 pnd->pnd_rfh = fh; 156 pnd->pnd_rfh = fh;
156 pnd->pnd_flags |= PND_RFH; 157 pnd->pnd_flags |= PND_RFH;
157 } 158 }
158 159
159 return; 160 return;
160} 161}
161 162
162void 163void
163perfuse_destroy_fh(opc, fh) 164perfuse_destroy_fh(opc, fh)
164 puffs_cookie_t opc; 165 puffs_cookie_t opc;
165 uint64_t fh;  166 uint64_t fh;
166{ 167{
167 struct perfuse_node_data *pnd; 168 struct perfuse_node_data *pnd;
168 169
169 pnd = PERFUSE_NODE_DATA(opc); 170 pnd = PERFUSE_NODE_DATA(opc);
170 171
171 if (fh == pnd->pnd_rfh) { 172 if (fh == pnd->pnd_rfh) {
172 if (!(pnd->pnd_flags & PND_RFH) && (fh != FUSE_UNKNOWN_FH)) 173 if (!(pnd->pnd_flags & PND_RFH) && (fh != FUSE_UNKNOWN_FH))
173 DERRX(EX_SOFTWARE,  174 DERRX(EX_SOFTWARE,
174 "%s: opc = %p, unset rfh = %"PRIx64"", 175 "%s: opc = %p, unset rfh = %"PRIx64"",
175 __func__, (void *)opc, fh);  176 __func__, (void *)opc, fh);
176 pnd->pnd_rfh = FUSE_UNKNOWN_FH; 177 pnd->pnd_rfh = FUSE_UNKNOWN_FH;
177 pnd->pnd_flags &= ~PND_RFH; 178 pnd->pnd_flags &= ~PND_RFH;
178 } 179 }
179 180
180 if (fh == pnd->pnd_wfh) { 181 if (fh == pnd->pnd_wfh) {
181 if (!(pnd->pnd_flags & PND_WFH) && (fh != FUSE_UNKNOWN_FH)) 182 if (!(pnd->pnd_flags & PND_WFH) && (fh != FUSE_UNKNOWN_FH))
182 DERRX(EX_SOFTWARE, 183 DERRX(EX_SOFTWARE,
183 "%s: opc = %p, unset wfh = %"PRIx64"", 184 "%s: opc = %p, unset wfh = %"PRIx64"",
184 __func__, (void *)opc, fh);  185 __func__, (void *)opc, fh);
185 pnd->pnd_wfh = FUSE_UNKNOWN_FH; 186 pnd->pnd_wfh = FUSE_UNKNOWN_FH;
186 pnd->pnd_flags &= ~PND_WFH; 187 pnd->pnd_flags &= ~PND_WFH;
187 }  188 }
188 189
189 return; 190 return;
190} 191}
191 192
192uint64_t 193uint64_t
193perfuse_get_fh(opc, mode) 194perfuse_get_fh(opc, mode)
194 puffs_cookie_t opc; 195 puffs_cookie_t opc;
195 int mode; 196 int mode;
196{ 197{
197 struct perfuse_node_data *pnd; 198 struct perfuse_node_data *pnd;
198 199
199 pnd = PERFUSE_NODE_DATA(opc); 200 pnd = PERFUSE_NODE_DATA(opc);
200 201
201 if (mode & FWRITE) { 202 if (mode & FWRITE) {
202 if (pnd->pnd_flags & PND_WFH) 203 if (pnd->pnd_flags & PND_WFH)
203 return pnd->pnd_wfh; 204 return pnd->pnd_wfh;
204 } 205 }
205 206
206 if (mode & FREAD) { 207 if (mode & FREAD) {
207 if (pnd->pnd_flags & PND_RFH) 208 if (pnd->pnd_flags & PND_RFH)
208 return pnd->pnd_rfh; 209 return pnd->pnd_rfh;
209 210
210 if (pnd->pnd_flags & PND_WFH) 211 if (pnd->pnd_flags & PND_WFH)
211 return pnd->pnd_wfh; 212 return pnd->pnd_wfh;
212 213
213 } 214 }
214 215
215 return FUSE_UNKNOWN_FH; 216 return FUSE_UNKNOWN_FH;
216} 217}
217 218
218static size_t 219static size_t
219node_path(opc, buf, buflen) 220node_path(opc, buf, buflen)
220 puffs_cookie_t opc; 221 puffs_cookie_t opc;
221 char *buf; 222 char *buf;
222 size_t buflen; 223 size_t buflen;
223{ 224{
224 struct perfuse_node_data *pnd; 225 struct perfuse_node_data *pnd;
225 size_t written; 226 size_t written;
226  227
227 pnd = PERFUSE_NODE_DATA(opc); 228 pnd = PERFUSE_NODE_DATA(opc);
228 if (pnd->pnd_parent == opc) 229 if (pnd->pnd_parent == opc)
229 return 0; 230 return 0;
230 231
231 written = node_path(pnd->pnd_parent, buf, buflen); 232 written = node_path(pnd->pnd_parent, buf, buflen);
232 buf += written; 233 buf += written;
233 buflen -= written; 234 buflen -= written;
234  235
235 return written + snprintf(buf, buflen, "/%s", pnd->pnd_name); 236 return written + snprintf(buf, buflen, "/%s", pnd->pnd_name);
236} 237}
237 238
238char * 239char *
239perfuse_node_path(opc) 240perfuse_node_path(opc)
240 puffs_cookie_t opc; 241 puffs_cookie_t opc;
241{ 242{
242 static char buf[MAXPATHLEN + 1]; 243 static char buf[MAXPATHLEN + 1];
243 244
244 if (node_path(opc, buf, sizeof(buf)) == 0) 245 if (node_path(opc, buf, sizeof(buf)) == 0)
245 sprintf(buf, "/"); 246 sprintf(buf, "/");
246 247
247 return buf; 248 return buf;
248} 249}
249 250
250const char * 251const char *
251perfuse_native_ns(attrnamespace, attrname, fuse_attrname) 252perfuse_native_ns(attrnamespace, attrname, fuse_attrname)
252 const int attrnamespace; 253 const int attrnamespace;
253 const char *attrname; 254 const char *attrname;
254 char *fuse_attrname; 255 char *fuse_attrname;
255{ 256{
256 const struct perfuse_ns_map *pnm; 257 const struct perfuse_ns_map *pnm;
257 const struct perfuse_ns_map perfuse_ns_map[] = { 258 const struct perfuse_ns_map perfuse_ns_map[] = {
258 PERFUSE_NS_MAP("trusted", EXTATTR_NAMESPACE_SYSTEM), 259 PERFUSE_NS_MAP("trusted", EXTATTR_NAMESPACE_SYSTEM),
259 PERFUSE_NS_MAP("security", EXTATTR_NAMESPACE_SYSTEM), 260 PERFUSE_NS_MAP("security", EXTATTR_NAMESPACE_SYSTEM),
260 PERFUSE_NS_MAP("system", EXTATTR_NAMESPACE_SYSTEM), 261 PERFUSE_NS_MAP("system", EXTATTR_NAMESPACE_SYSTEM),
261 PERFUSE_NS_MAP("user", EXTATTR_NAMESPACE_USER), 262 PERFUSE_NS_MAP("user", EXTATTR_NAMESPACE_USER),
262 { NULL, 0, EXTATTR_NAMESPACE_USER }, 263 { NULL, 0, EXTATTR_NAMESPACE_USER },
263 }; 264 };
264 265
265 /* 266 /*
266 * If attribute has a reserved Linux namespace (e.g.: trusted.foo) 267 * If attribute has a reserved Linux namespace (e.g.: trusted.foo)
267 * and that namespace matches the requested native namespace 268 * and that namespace matches the requested native namespace
268 * we have nothing to do.  269 * we have nothing to do.
269 * Otherwise we have either: 270 * Otherwise we have either:
270 * (system|trusted|security).* with user namespace: prepend user. 271 * (system|trusted|security).* with user namespace: prepend user.
271 * anything else with system napespace: prepend system. 272 * anything else with system napespace: prepend system.
272 */ 273 */
273 for (pnm = perfuse_ns_map; pnm->pnm_ns; pnm++) { 274 for (pnm = perfuse_ns_map; pnm->pnm_ns; pnm++) {
274 if (strncmp(attrname, pnm->pnm_ns, pnm->pnm_nslen) != 0)  275 if (strncmp(attrname, pnm->pnm_ns, pnm->pnm_nslen) != 0)
275 continue; 276 continue;
276 277
277 if (attrnamespace == pnm->pnm_native_ns) 278 if (attrnamespace == pnm->pnm_native_ns)
278 return attrname; 279 return attrname;
279 280
280 /* (system|trusted|security).* with user namespace */ 281 /* (system|trusted|security).* with user namespace */
281 if (attrnamespace == EXTATTR_NAMESPACE_USER) { 282 if (attrnamespace == EXTATTR_NAMESPACE_USER) {
282 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX,  283 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX,
283 "user.%s", attrname); 284 "user.%s", attrname);
284 return (const char *)fuse_attrname; 285 return (const char *)fuse_attrname;
285 } 286 }
286 } 287 }
287 288
288 /* anything else with system napespace */ 289 /* anything else with system napespace */
289 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) { 290 if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM) {
290 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX,  291 (void)snprintf(fuse_attrname, LINUX_XATTR_NAME_MAX,
291 "system.%s", attrname); 292 "system.%s", attrname);
292 return (const char *)fuse_attrname; 293 return (const char *)fuse_attrname;
293 } 294 }
294 295
295 return (const char *)attrname; 296 return (const char *)attrname;
296} 297}