puffs_vnops.c revision 1.147 1 /* $NetBSD: puffs_vnops.c,v 1.147 2010/07/14 14:07:37 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: puffs_vnops.c,v 1.147 2010/07/14 14:07:37 pooka Exp $");
34
35 #include <sys/param.h>
36 #include <sys/buf.h>
37 #include <sys/malloc.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/vnode.h>
41 #include <sys/proc.h>
42
43 #include <uvm/uvm.h>
44
45 #include <fs/puffs/puffs_msgif.h>
46 #include <fs/puffs/puffs_sys.h>
47
48 #include <miscfs/fifofs/fifo.h>
49 #include <miscfs/genfs/genfs.h>
50 #include <miscfs/specfs/specdev.h>
51
52 int puffs_vnop_lookup(void *);
53 int puffs_vnop_create(void *);
54 int puffs_vnop_access(void *);
55 int puffs_vnop_mknod(void *);
56 int puffs_vnop_open(void *);
57 int puffs_vnop_close(void *);
58 int puffs_vnop_getattr(void *);
59 int puffs_vnop_setattr(void *);
60 int puffs_vnop_reclaim(void *);
61 int puffs_vnop_readdir(void *);
62 int puffs_vnop_poll(void *);
63 int puffs_vnop_fsync(void *);
64 int puffs_vnop_seek(void *);
65 int puffs_vnop_remove(void *);
66 int puffs_vnop_mkdir(void *);
67 int puffs_vnop_rmdir(void *);
68 int puffs_vnop_link(void *);
69 int puffs_vnop_readlink(void *);
70 int puffs_vnop_symlink(void *);
71 int puffs_vnop_rename(void *);
72 int puffs_vnop_read(void *);
73 int puffs_vnop_write(void *);
74 int puffs_vnop_fcntl(void *);
75 int puffs_vnop_ioctl(void *);
76 int puffs_vnop_inactive(void *);
77 int puffs_vnop_print(void *);
78 int puffs_vnop_pathconf(void *);
79 int puffs_vnop_advlock(void *);
80 int puffs_vnop_strategy(void *);
81 int puffs_vnop_bmap(void *);
82 int puffs_vnop_mmap(void *);
83 int puffs_vnop_getpages(void *);
84 int puffs_vnop_abortop(void *);
85 int puffs_vnop_getextattr(void *);
86 int puffs_vnop_setextattr(void *);
87 int puffs_vnop_listextattr(void *);
88 int puffs_vnop_deleteextattr(void *);
89
90 int puffs_vnop_spec_read(void *);
91 int puffs_vnop_spec_write(void *);
92 int puffs_vnop_fifo_read(void *);
93 int puffs_vnop_fifo_write(void *);
94
95 int puffs_vnop_checkop(void *);
96
97 #define puffs_vnop_lock genfs_lock
98 #define puffs_vnop_unlock genfs_unlock
99 #define puffs_vnop_islocked genfs_islocked
100
101 int (**puffs_vnodeop_p)(void *);
102 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
103 { &vop_default_desc, vn_default_error },
104 { &vop_lookup_desc, puffs_vnop_lookup }, /* REAL lookup */
105 { &vop_create_desc, puffs_vnop_checkop }, /* create */
106 { &vop_mknod_desc, puffs_vnop_checkop }, /* mknod */
107 { &vop_open_desc, puffs_vnop_open }, /* REAL open */
108 { &vop_close_desc, puffs_vnop_checkop }, /* close */
109 { &vop_access_desc, puffs_vnop_access }, /* REAL access */
110 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */
111 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */
112 { &vop_read_desc, puffs_vnop_checkop }, /* read */
113 { &vop_write_desc, puffs_vnop_checkop }, /* write */
114 { &vop_fsync_desc, puffs_vnop_fsync }, /* REAL fsync */
115 { &vop_seek_desc, puffs_vnop_checkop }, /* seek */
116 { &vop_remove_desc, puffs_vnop_checkop }, /* remove */
117 { &vop_link_desc, puffs_vnop_checkop }, /* link */
118 { &vop_rename_desc, puffs_vnop_checkop }, /* rename */
119 { &vop_mkdir_desc, puffs_vnop_checkop }, /* mkdir */
120 { &vop_rmdir_desc, puffs_vnop_checkop }, /* rmdir */
121 { &vop_symlink_desc, puffs_vnop_checkop }, /* symlink */
122 { &vop_readdir_desc, puffs_vnop_checkop }, /* readdir */
123 { &vop_readlink_desc, puffs_vnop_checkop }, /* readlink */
124 { &vop_getpages_desc, puffs_vnop_checkop }, /* getpages */
125 { &vop_putpages_desc, genfs_putpages }, /* REAL putpages */
126 { &vop_pathconf_desc, puffs_vnop_checkop }, /* pathconf */
127 { &vop_advlock_desc, puffs_vnop_checkop }, /* advlock */
128 { &vop_strategy_desc, puffs_vnop_strategy }, /* REAL strategy */
129 { &vop_revoke_desc, genfs_revoke }, /* REAL revoke */
130 { &vop_abortop_desc, puffs_vnop_abortop }, /* REAL abortop */
131 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */
132 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */
133 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */
134 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */
135 { &vop_bmap_desc, puffs_vnop_bmap }, /* REAL bmap */
136 { &vop_print_desc, puffs_vnop_print }, /* REAL print */
137 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */
138 { &vop_bwrite_desc, genfs_nullop }, /* REAL bwrite */
139 { &vop_mmap_desc, puffs_vnop_mmap }, /* REAL mmap */
140 { &vop_poll_desc, puffs_vnop_poll }, /* REAL poll */
141 { &vop_getextattr_desc, puffs_vnop_getextattr }, /* getextattr */
142 { &vop_setextattr_desc, puffs_vnop_setextattr }, /* setextattr */
143 { &vop_listextattr_desc, puffs_vnop_listextattr }, /* listextattr */
144 { &vop_deleteextattr_desc, puffs_vnop_deleteextattr },/* deleteextattr */
145 #if 0
146 { &vop_openextattr_desc, puffs_vnop_checkop }, /* openextattr */
147 { &vop_closeextattr_desc, puffs_vnop_checkop }, /* closeextattr */
148 #endif
149 { &vop_kqfilter_desc, genfs_eopnotsupp }, /* kqfilter XXX */
150 { NULL, NULL }
151 };
152 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
153 { &puffs_vnodeop_p, puffs_vnodeop_entries };
154
155
156 int (**puffs_specop_p)(void *);
157 const struct vnodeopv_entry_desc puffs_specop_entries[] = {
158 { &vop_default_desc, vn_default_error },
159 { &vop_lookup_desc, spec_lookup }, /* lookup, ENOTDIR */
160 { &vop_create_desc, spec_create }, /* genfs_badop */
161 { &vop_mknod_desc, spec_mknod }, /* genfs_badop */
162 { &vop_open_desc, spec_open }, /* spec_open */
163 { &vop_close_desc, spec_close }, /* spec_close */
164 { &vop_access_desc, puffs_vnop_checkop }, /* access */
165 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */
166 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */
167 { &vop_read_desc, puffs_vnop_spec_read }, /* update, read */
168 { &vop_write_desc, puffs_vnop_spec_write }, /* update, write */
169 { &vop_ioctl_desc, spec_ioctl }, /* spec_ioctl */
170 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
171 { &vop_poll_desc, spec_poll }, /* spec_poll */
172 { &vop_kqfilter_desc, spec_kqfilter }, /* spec_kqfilter */
173 { &vop_revoke_desc, spec_revoke }, /* genfs_revoke */
174 { &vop_mmap_desc, spec_mmap }, /* spec_mmap */
175 { &vop_fsync_desc, spec_fsync }, /* vflushbuf */
176 { &vop_seek_desc, spec_seek }, /* genfs_nullop */
177 { &vop_remove_desc, spec_remove }, /* genfs_badop */
178 { &vop_link_desc, spec_link }, /* genfs_badop */
179 { &vop_rename_desc, spec_rename }, /* genfs_badop */
180 { &vop_mkdir_desc, spec_mkdir }, /* genfs_badop */
181 { &vop_rmdir_desc, spec_rmdir }, /* genfs_badop */
182 { &vop_symlink_desc, spec_symlink }, /* genfs_badop */
183 { &vop_readdir_desc, spec_readdir }, /* genfs_badop */
184 { &vop_readlink_desc, spec_readlink }, /* genfs_badop */
185 { &vop_abortop_desc, spec_abortop }, /* genfs_badop */
186 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */
187 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */
188 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */
189 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */
190 { &vop_bmap_desc, spec_bmap }, /* dummy */
191 { &vop_strategy_desc, spec_strategy }, /* dev strategy */
192 { &vop_print_desc, puffs_vnop_print }, /* REAL print */
193 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */
194 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
195 { &vop_advlock_desc, spec_advlock }, /* lf_advlock */
196 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
197 { &vop_getpages_desc, spec_getpages }, /* genfs_getpages */
198 { &vop_putpages_desc, spec_putpages }, /* genfs_putpages */
199 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */
200 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */
201 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */
202 { &vop_deleteextattr_desc, puffs_vnop_checkop },/* deleteextattr */
203 #if 0
204 { &vop_openextattr_desc, _openextattr }, /* openextattr */
205 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
206 #endif
207 { NULL, NULL }
208 };
209 const struct vnodeopv_desc puffs_specop_opv_desc =
210 { &puffs_specop_p, puffs_specop_entries };
211
212
213 int (**puffs_fifoop_p)(void *);
214 const struct vnodeopv_entry_desc puffs_fifoop_entries[] = {
215 { &vop_default_desc, vn_default_error },
216 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup, ENOTDIR */
217 { &vop_create_desc, vn_fifo_bypass }, /* genfs_badop */
218 { &vop_mknod_desc, vn_fifo_bypass }, /* genfs_badop */
219 { &vop_open_desc, vn_fifo_bypass }, /* open */
220 { &vop_close_desc, vn_fifo_bypass }, /* close */
221 { &vop_access_desc, puffs_vnop_checkop }, /* access */
222 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */
223 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */
224 { &vop_read_desc, puffs_vnop_fifo_read }, /* read, update */
225 { &vop_write_desc, puffs_vnop_fifo_write }, /* write, update */
226 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */
227 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
228 { &vop_poll_desc, vn_fifo_bypass }, /* poll */
229 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */
230 { &vop_revoke_desc, vn_fifo_bypass }, /* genfs_revoke */
231 { &vop_mmap_desc, vn_fifo_bypass }, /* genfs_badop */
232 { &vop_fsync_desc, vn_fifo_bypass }, /* genfs_nullop*/
233 { &vop_seek_desc, vn_fifo_bypass }, /* genfs_badop */
234 { &vop_remove_desc, vn_fifo_bypass }, /* genfs_badop */
235 { &vop_link_desc, vn_fifo_bypass }, /* genfs_badop */
236 { &vop_rename_desc, vn_fifo_bypass }, /* genfs_badop */
237 { &vop_mkdir_desc, vn_fifo_bypass }, /* genfs_badop */
238 { &vop_rmdir_desc, vn_fifo_bypass }, /* genfs_badop */
239 { &vop_symlink_desc, vn_fifo_bypass }, /* genfs_badop */
240 { &vop_readdir_desc, vn_fifo_bypass }, /* genfs_badop */
241 { &vop_readlink_desc, vn_fifo_bypass }, /* genfs_badop */
242 { &vop_abortop_desc, vn_fifo_bypass }, /* genfs_badop */
243 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */
244 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */
245 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */
246 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */
247 { &vop_bmap_desc, vn_fifo_bypass }, /* dummy */
248 { &vop_strategy_desc, vn_fifo_bypass }, /* genfs_badop */
249 { &vop_print_desc, puffs_vnop_print }, /* REAL print */
250 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */
251 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */
252 { &vop_advlock_desc, vn_fifo_bypass }, /* genfs_einval */
253 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
254 { &vop_putpages_desc, vn_fifo_bypass }, /* genfs_null_putpages*/
255 #if 0
256 { &vop_openextattr_desc, _openextattr }, /* openextattr */
257 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
258 #endif
259 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */
260 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */
261 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */
262 { &vop_deleteextattr_desc, puffs_vnop_checkop }, /* deleteextattr */
263 { NULL, NULL }
264 };
265 const struct vnodeopv_desc puffs_fifoop_opv_desc =
266 { &puffs_fifoop_p, puffs_fifoop_entries };
267
268
269 /* "real" vnode operations */
270 int (**puffs_msgop_p)(void *);
271 const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
272 { &vop_default_desc, vn_default_error },
273 { &vop_create_desc, puffs_vnop_create }, /* create */
274 { &vop_mknod_desc, puffs_vnop_mknod }, /* mknod */
275 { &vop_open_desc, puffs_vnop_open }, /* open */
276 { &vop_close_desc, puffs_vnop_close }, /* close */
277 { &vop_access_desc, puffs_vnop_access }, /* access */
278 { &vop_getattr_desc, puffs_vnop_getattr }, /* getattr */
279 { &vop_setattr_desc, puffs_vnop_setattr }, /* setattr */
280 { &vop_read_desc, puffs_vnop_read }, /* read */
281 { &vop_write_desc, puffs_vnop_write }, /* write */
282 { &vop_seek_desc, puffs_vnop_seek }, /* seek */
283 { &vop_remove_desc, puffs_vnop_remove }, /* remove */
284 { &vop_link_desc, puffs_vnop_link }, /* link */
285 { &vop_rename_desc, puffs_vnop_rename }, /* rename */
286 { &vop_mkdir_desc, puffs_vnop_mkdir }, /* mkdir */
287 { &vop_rmdir_desc, puffs_vnop_rmdir }, /* rmdir */
288 { &vop_symlink_desc, puffs_vnop_symlink }, /* symlink */
289 { &vop_readdir_desc, puffs_vnop_readdir }, /* readdir */
290 { &vop_readlink_desc, puffs_vnop_readlink }, /* readlink */
291 { &vop_print_desc, puffs_vnop_print }, /* print */
292 { &vop_islocked_desc, puffs_vnop_islocked }, /* islocked */
293 { &vop_pathconf_desc, puffs_vnop_pathconf }, /* pathconf */
294 { &vop_advlock_desc, puffs_vnop_advlock }, /* advlock */
295 { &vop_getpages_desc, puffs_vnop_getpages }, /* getpages */
296 { NULL, NULL }
297 };
298 const struct vnodeopv_desc puffs_msgop_opv_desc =
299 { &puffs_msgop_p, puffs_msgop_entries };
300
301
302 #define ERROUT(err) \
303 do { \
304 error = err; \
305 goto out; \
306 } while (/*CONSTCOND*/0)
307
308 /*
309 * This is a generic vnode operation handler. It checks if the necessary
310 * operations for the called vnode operation are implemented by userspace
311 * and either returns a dummy return value or proceeds to call the real
312 * vnode operation from puffs_msgop_v.
313 *
314 * XXX: this should described elsewhere and autogenerated, the complexity
315 * of the vnode operations vectors and their interrelationships is also
316 * getting a bit out of hand. Another problem is that we need this same
317 * information in the fs server code, so keeping the two in sync manually
318 * is not a viable (long term) plan.
319 */
320
321 /* not supported, handle locking protocol */
322 #define CHECKOP_NOTSUPP(op) \
323 case VOP_##op##_DESCOFFSET: \
324 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
325 return genfs_eopnotsupp(v); \
326 break
327
328 /* always succeed, no locking */
329 #define CHECKOP_SUCCESS(op) \
330 case VOP_##op##_DESCOFFSET: \
331 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
332 return 0; \
333 break
334
335 int
336 puffs_vnop_checkop(void *v)
337 {
338 struct vop_generic_args /* {
339 struct vnodeop_desc *a_desc;
340 spooky mystery contents;
341 } */ *ap = v;
342 struct vnodeop_desc *desc = ap->a_desc;
343 struct puffs_mount *pmp;
344 struct vnode *vp;
345 int offset, rv;
346
347 offset = ap->a_desc->vdesc_vp_offsets[0];
348 #ifdef DIAGNOSTIC
349 if (offset == VDESC_NO_OFFSET)
350 panic("puffs_checkop: no vnode, why did you call me?");
351 #endif
352 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
353 pmp = MPTOPUFFSMP(vp->v_mount);
354
355 DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n",
356 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp));
357
358 if (!ALLOPS(pmp)) {
359 switch (desc->vdesc_offset) {
360 CHECKOP_NOTSUPP(CREATE);
361 CHECKOP_NOTSUPP(MKNOD);
362 CHECKOP_NOTSUPP(GETATTR);
363 CHECKOP_NOTSUPP(SETATTR);
364 CHECKOP_NOTSUPP(READ);
365 CHECKOP_NOTSUPP(WRITE);
366 CHECKOP_NOTSUPP(FCNTL);
367 CHECKOP_NOTSUPP(IOCTL);
368 CHECKOP_NOTSUPP(REMOVE);
369 CHECKOP_NOTSUPP(LINK);
370 CHECKOP_NOTSUPP(RENAME);
371 CHECKOP_NOTSUPP(MKDIR);
372 CHECKOP_NOTSUPP(RMDIR);
373 CHECKOP_NOTSUPP(SYMLINK);
374 CHECKOP_NOTSUPP(READDIR);
375 CHECKOP_NOTSUPP(READLINK);
376 CHECKOP_NOTSUPP(PRINT);
377 CHECKOP_NOTSUPP(PATHCONF);
378 CHECKOP_NOTSUPP(ADVLOCK);
379 CHECKOP_NOTSUPP(GETEXTATTR);
380 CHECKOP_NOTSUPP(SETEXTATTR);
381 CHECKOP_NOTSUPP(LISTEXTATTR);
382 CHECKOP_NOTSUPP(DELETEEXTATTR);
383
384 CHECKOP_SUCCESS(ACCESS);
385 CHECKOP_SUCCESS(CLOSE);
386 CHECKOP_SUCCESS(SEEK);
387
388 case VOP_GETPAGES_DESCOFFSET:
389 if (!EXISTSOP(pmp, READ))
390 return genfs_eopnotsupp(v);
391 break;
392
393 default:
394 panic("puffs_checkop: unhandled vnop %d",
395 desc->vdesc_offset);
396 }
397 }
398
399 rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v);
400
401 DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n",
402 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv));
403
404 return rv;
405 }
406
407 static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
408 struct componentname *);
409 static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
410 struct componentname *);
411 static void callinactive(struct puffs_mount *, puffs_cookie_t, int);
412 static void callreclaim(struct puffs_mount *, puffs_cookie_t);
413 static int flushvncache(struct vnode *, off_t, off_t, bool);
414
415
416 #define PUFFS_ABORT_LOOKUP 1
417 #define PUFFS_ABORT_CREATE 2
418 #define PUFFS_ABORT_MKNOD 3
419 #define PUFFS_ABORT_MKDIR 4
420 #define PUFFS_ABORT_SYMLINK 5
421
422 /*
423 * Press the pani^Wabort button! Kernel resource allocation failed.
424 */
425 static void
426 puffs_abortbutton(struct puffs_mount *pmp, int what,
427 puffs_cookie_t dck, puffs_cookie_t ck, struct componentname *cnp)
428 {
429
430 switch (what) {
431 case PUFFS_ABORT_CREATE:
432 case PUFFS_ABORT_MKNOD:
433 case PUFFS_ABORT_SYMLINK:
434 callremove(pmp, dck, ck, cnp);
435 break;
436 case PUFFS_ABORT_MKDIR:
437 callrmdir(pmp, dck, ck, cnp);
438 break;
439 }
440
441 callinactive(pmp, ck, 0);
442 callreclaim(pmp, ck);
443 }
444
445 /*
446 * Begin vnode operations.
447 *
448 * A word from the keymaster about locks: generally we don't want
449 * to use the vnode locks at all: it creates an ugly dependency between
450 * the userlandia file server and the kernel. But we'll play along with
451 * the kernel vnode locks for now. However, even currently we attempt
452 * to release locks as early as possible. This is possible for some
453 * operations which a) don't need a locked vnode after the userspace op
454 * and b) return with the vnode unlocked. Theoretically we could
455 * unlock-do op-lock for others and order the graph in userspace, but I
456 * don't want to think of the consequences for the time being.
457 */
458
459 int
460 puffs_vnop_lookup(void *v)
461 {
462 struct vop_lookup_args /* {
463 const struct vnodeop_desc *a_desc;
464 struct vnode *a_dvp;
465 struct vnode **a_vpp;
466 struct componentname *a_cnp;
467 } */ *ap = v;
468 PUFFS_MSG_VARS(vn, lookup);
469 struct puffs_mount *pmp;
470 struct componentname *cnp;
471 struct vnode *vp, *dvp;
472 struct puffs_node *dpn;
473 int isdot;
474 int error;
475
476 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
477 cnp = ap->a_cnp;
478 dvp = ap->a_dvp;
479 *ap->a_vpp = NULL;
480
481 /* r/o fs? we check create later to handle EEXIST */
482 if ((cnp->cn_flags & ISLASTCN)
483 && (dvp->v_mount->mnt_flag & MNT_RDONLY)
484 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
485 return EROFS;
486
487 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
488
489 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
490 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
491
492 /*
493 * Check if someone fed it into the cache
494 */
495 if (PUFFS_USE_NAMECACHE(pmp)) {
496 error = cache_lookup(dvp, ap->a_vpp, cnp);
497
498 if (error >= 0)
499 return error;
500 }
501
502 if (isdot) {
503 /* deal with rename lookup semantics */
504 if (cnp->cn_nameiop == RENAME && (cnp->cn_flags & ISLASTCN))
505 return EISDIR;
506
507 vp = ap->a_dvp;
508 vref(vp);
509 *ap->a_vpp = vp;
510 return 0;
511 }
512
513 PUFFS_MSG_ALLOC(vn, lookup);
514 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
515 cnp, PUFFS_USE_FULLPNBUF(pmp));
516
517 if (cnp->cn_flags & ISDOTDOT)
518 VOP_UNLOCK(dvp);
519
520 puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
521 PUFFS_VN_LOOKUP, VPTOPNC(dvp));
522 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
523 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
524
525 /*
526 * In case of error, there is no new vnode to play with, so be
527 * happy with the NULL value given to vpp in the beginning.
528 * Also, check if this really was an error or the target was not
529 * present. Either treat it as a non-error for CREATE/RENAME or
530 * enter the component into the negative name cache (if desired).
531 */
532 if (error) {
533 error = checkerr(pmp, error, __func__);
534 if (error == ENOENT) {
535 /* don't allow to create files on r/o fs */
536 if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
537 && cnp->cn_nameiop == CREATE) {
538 error = EROFS;
539
540 /* adjust values if we are creating */
541 } else if ((cnp->cn_flags & ISLASTCN)
542 && (cnp->cn_nameiop == CREATE
543 || cnp->cn_nameiop == RENAME)) {
544 cnp->cn_flags |= SAVENAME;
545 error = EJUSTRETURN;
546
547 /* save negative cache entry */
548 } else {
549 if ((cnp->cn_flags & MAKEENTRY)
550 && PUFFS_USE_NAMECACHE(pmp))
551 cache_enter(dvp, NULL, cnp);
552 }
553 }
554 goto out;
555 }
556
557 /*
558 * Check that we don't get our parent node back, that would cause
559 * a pretty obvious deadlock.
560 */
561 dpn = dvp->v_data;
562 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
563 puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
564 "lookup produced parent cookie", lookup_msg->pvnr_newnode);
565 error = EPROTO;
566 goto out;
567 }
568
569 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, 1, &vp);
570 if (error == PUFFS_NOSUCHCOOKIE) {
571 error = puffs_getvnode(dvp->v_mount,
572 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
573 lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp);
574 if (error) {
575 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
576 lookup_msg->pvnr_newnode, ap->a_cnp);
577 goto out;
578 }
579 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
580 } else if (error) {
581 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
582 lookup_msg->pvnr_newnode, ap->a_cnp);
583 goto out;
584 }
585
586 *ap->a_vpp = vp;
587
588 if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp))
589 cache_enter(dvp, vp, cnp);
590
591 /* XXX */
592 if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
593 cnp->cn_flags &= ~REQUIREDIR;
594 if (lookup_msg->pvnr_cn.pkcn_consume)
595 cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume,
596 strlen(cnp->cn_nameptr) - cnp->cn_namelen);
597
598 /*
599 * We need the name in remove and rmdir (well, rename too, but
600 * SAVESTART takes care of that)
601 */
602 if (cnp->cn_nameiop == DELETE)
603 cnp->cn_flags |= SAVENAME;
604
605 out:
606 if (cnp->cn_flags & ISDOTDOT)
607 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
608
609 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
610 PUFFS_MSG_RELEASE(lookup);
611 return error;
612 }
613
614 #define REFPN_AND_UNLOCKVP(a, b) \
615 do { \
616 mutex_enter(&b->pn_mtx); \
617 puffs_referencenode(b); \
618 mutex_exit(&b->pn_mtx); \
619 VOP_UNLOCK(a); \
620 } while (/*CONSTCOND*/0)
621
622 #define REFPN(b) \
623 do { \
624 mutex_enter(&b->pn_mtx); \
625 puffs_referencenode(b); \
626 mutex_exit(&b->pn_mtx); \
627 } while (/*CONSTCOND*/0)
628
629 #define RELEPN_AND_VP(a, b) \
630 do { \
631 puffs_releasenode(b); \
632 vrele(a); \
633 } while (/*CONSTCOND*/0)
634
635 int
636 puffs_vnop_create(void *v)
637 {
638 struct vop_create_args /* {
639 const struct vnodeop_desc *a_desc;
640 struct vnode *a_dvp;
641 struct vnode **a_vpp;
642 struct componentname *a_cnp;
643 struct vattr *a_vap;
644 } */ *ap = v;
645 PUFFS_MSG_VARS(vn, create);
646 struct vnode *dvp = ap->a_dvp;
647 struct puffs_node *dpn = VPTOPP(dvp);
648 struct componentname *cnp = ap->a_cnp;
649 struct mount *mp = dvp->v_mount;
650 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
651 int error;
652
653 DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
654 dvp, ap->a_cnp->cn_nameptr));
655
656 PUFFS_MSG_ALLOC(vn, create);
657 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
658 cnp, PUFFS_USE_FULLPNBUF(pmp));
659 create_msg->pvnr_va = *ap->a_vap;
660 puffs_msg_setinfo(park_create, PUFFSOP_VN,
661 PUFFS_VN_CREATE, VPTOPNC(dvp));
662 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_create, dvp->v_data, NULL, error);
663
664 error = checkerr(pmp, error, __func__);
665 if (error)
666 goto out;
667
668 error = puffs_newnode(mp, dvp, ap->a_vpp,
669 create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0);
670 if (error)
671 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie,
672 create_msg->pvnr_newnode, cnp);
673
674 out:
675 vput(dvp);
676 if (error || (cnp->cn_flags & SAVESTART) == 0)
677 PNBUF_PUT(cnp->cn_pnbuf);
678
679 DPRINTF(("puffs_create: return %d\n", error));
680 PUFFS_MSG_RELEASE(create);
681 return error;
682 }
683
684 int
685 puffs_vnop_mknod(void *v)
686 {
687 struct vop_mknod_args /* {
688 const struct vnodeop_desc *a_desc;
689 struct vnode *a_dvp;
690 struct vnode **a_vpp;
691 struct componentname *a_cnp;
692 struct vattr *a_vap;
693 } */ *ap = v;
694 PUFFS_MSG_VARS(vn, mknod);
695 struct vnode *dvp = ap->a_dvp;
696 struct puffs_node *dpn = VPTOPP(dvp);
697 struct componentname *cnp = ap->a_cnp;
698 struct mount *mp = dvp->v_mount;
699 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
700 int error;
701
702 PUFFS_MSG_ALLOC(vn, mknod);
703 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
704 cnp, PUFFS_USE_FULLPNBUF(pmp));
705 mknod_msg->pvnr_va = *ap->a_vap;
706 puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
707 PUFFS_VN_MKNOD, VPTOPNC(dvp));
708
709 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);
710
711 error = checkerr(pmp, error, __func__);
712 if (error)
713 goto out;
714
715 error = puffs_newnode(mp, dvp, ap->a_vpp,
716 mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type,
717 ap->a_vap->va_rdev);
718 if (error)
719 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
720 mknod_msg->pvnr_newnode, cnp);
721
722 out:
723 vput(dvp);
724 PUFFS_MSG_RELEASE(mknod);
725 if (error || (cnp->cn_flags & SAVESTART) == 0)
726 PNBUF_PUT(cnp->cn_pnbuf);
727 return error;
728 }
729
730 int
731 puffs_vnop_open(void *v)
732 {
733 struct vop_open_args /* {
734 const struct vnodeop_desc *a_desc;
735 struct vnode *a_vp;
736 int a_mode;
737 kauth_cred_t a_cred;
738 } */ *ap = v;
739 PUFFS_MSG_VARS(vn, open);
740 struct vnode *vp = ap->a_vp;
741 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
742 int mode = ap->a_mode;
743 int error;
744
745 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
746
747 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
748 ERROUT(EROFS);
749
750 if (!EXISTSOP(pmp, OPEN))
751 ERROUT(0);
752
753 PUFFS_MSG_ALLOC(vn, open);
754 open_msg->pvnr_mode = mode;
755 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
756 puffs_msg_setinfo(park_open, PUFFSOP_VN,
757 PUFFS_VN_OPEN, VPTOPNC(vp));
758
759 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
760 error = checkerr(pmp, error, __func__);
761
762 out:
763 DPRINTF(("puffs_open: returning %d\n", error));
764 PUFFS_MSG_RELEASE(open);
765 return error;
766 }
767
768 int
769 puffs_vnop_close(void *v)
770 {
771 struct vop_close_args /* {
772 const struct vnodeop_desc *a_desc;
773 struct vnode *a_vp;
774 int a_fflag;
775 kauth_cred_t a_cred;
776 } */ *ap = v;
777 PUFFS_MSG_VARS(vn, close);
778 struct vnode *vp = ap->a_vp;
779 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
780
781 PUFFS_MSG_ALLOC(vn, close);
782 puffs_msg_setfaf(park_close);
783 close_msg->pvnr_fflag = ap->a_fflag;
784 puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred);
785 puffs_msg_setinfo(park_close, PUFFSOP_VN,
786 PUFFS_VN_CLOSE, VPTOPNC(vp));
787
788 puffs_msg_enqueue(pmp, park_close);
789 PUFFS_MSG_RELEASE(close);
790 return 0;
791 }
792
793 int
794 puffs_vnop_access(void *v)
795 {
796 struct vop_access_args /* {
797 const struct vnodeop_desc *a_desc;
798 struct vnode *a_vp;
799 int a_mode;
800 kauth_cred_t a_cred;
801 } */ *ap = v;
802 PUFFS_MSG_VARS(vn, access);
803 struct vnode *vp = ap->a_vp;
804 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
805 int mode = ap->a_mode;
806 int error;
807
808 if (mode & VWRITE) {
809 switch (vp->v_type) {
810 case VDIR:
811 case VLNK:
812 case VREG:
813 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
814 || !EXISTSOP(pmp, WRITE))
815 return EROFS;
816 break;
817 default:
818 break;
819 }
820 }
821
822 if (!EXISTSOP(pmp, ACCESS))
823 return 0;
824
825 PUFFS_MSG_ALLOC(vn, access);
826 access_msg->pvnr_mode = ap->a_mode;
827 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
828 puffs_msg_setinfo(park_access, PUFFSOP_VN,
829 PUFFS_VN_ACCESS, VPTOPNC(vp));
830
831 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
832 error = checkerr(pmp, error, __func__);
833 PUFFS_MSG_RELEASE(access);
834
835 return error;
836 }
837
838 int
839 puffs_vnop_getattr(void *v)
840 {
841 struct vop_getattr_args /* {
842 const struct vnodeop_desc *a_desc;
843 struct vnode *a_vp;
844 struct vattr *a_vap;
845 kauth_cred_t a_cred;
846 } */ *ap = v;
847 PUFFS_MSG_VARS(vn, getattr);
848 struct vnode *vp = ap->a_vp;
849 struct mount *mp = vp->v_mount;
850 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
851 struct vattr *vap, *rvap;
852 struct puffs_node *pn = VPTOPP(vp);
853 int error = 0;
854
855 REFPN(pn);
856 vap = ap->a_vap;
857
858 PUFFS_MSG_ALLOC(vn, getattr);
859 vattr_null(&getattr_msg->pvnr_va);
860 puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
861 puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
862 PUFFS_VN_GETATTR, VPTOPNC(vp));
863
864 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
865 error = checkerr(pmp, error, __func__);
866 if (error)
867 goto out;
868
869 rvap = &getattr_msg->pvnr_va;
870 /*
871 * Don't listen to the file server regarding special device
872 * size info, the file server doesn't know anything about them.
873 */
874 if (vp->v_type == VBLK || vp->v_type == VCHR)
875 rvap->va_size = vp->v_size;
876
877 /* Ditto for blocksize (ufs comment: this doesn't belong here) */
878 if (vp->v_type == VBLK)
879 rvap->va_blocksize = BLKDEV_IOSIZE;
880 else if (vp->v_type == VCHR)
881 rvap->va_blocksize = MAXBSIZE;
882
883 (void) memcpy(vap, rvap, sizeof(struct vattr));
884 vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
885
886 if (pn->pn_stat & PNODE_METACACHE_ATIME)
887 vap->va_atime = pn->pn_mc_atime;
888 if (pn->pn_stat & PNODE_METACACHE_CTIME)
889 vap->va_ctime = pn->pn_mc_ctime;
890 if (pn->pn_stat & PNODE_METACACHE_MTIME)
891 vap->va_mtime = pn->pn_mc_mtime;
892 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
893 vap->va_size = pn->pn_mc_size;
894 } else {
895 if (rvap->va_size != VNOVAL
896 && vp->v_type != VBLK && vp->v_type != VCHR) {
897 uvm_vnp_setsize(vp, rvap->va_size);
898 pn->pn_serversize = rvap->va_size;
899 }
900 }
901
902 out:
903 puffs_releasenode(pn);
904 PUFFS_MSG_RELEASE(getattr);
905 return error;
906 }
907
908 #define SETATTR_CHSIZE 0x01
909 #define SETATTR_ASYNC 0x02
910 static int
911 dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags)
912 {
913 PUFFS_MSG_VARS(vn, setattr);
914 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
915 struct puffs_node *pn = vp->v_data;
916 int error = 0;
917
918 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
919 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
920 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
921 || vap->va_mode != (mode_t)VNOVAL))
922 return EROFS;
923
924 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
925 && vp->v_type == VREG && vap->va_size != VNOVAL)
926 return EROFS;
927
928 /*
929 * Flush metacache first. If we are called with some explicit
930 * parameters, treat them as information overriding metacache
931 * information.
932 */
933 if (pn->pn_stat & PNODE_METACACHE_MASK) {
934 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
935 && vap->va_atime.tv_sec == VNOVAL)
936 vap->va_atime = pn->pn_mc_atime;
937 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
938 && vap->va_ctime.tv_sec == VNOVAL)
939 vap->va_ctime = pn->pn_mc_ctime;
940 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
941 && vap->va_mtime.tv_sec == VNOVAL)
942 vap->va_mtime = pn->pn_mc_mtime;
943 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
944 && vap->va_size == VNOVAL)
945 vap->va_size = pn->pn_mc_size;
946
947 pn->pn_stat &= ~PNODE_METACACHE_MASK;
948 }
949
950 PUFFS_MSG_ALLOC(vn, setattr);
951 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
952 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
953 puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
954 PUFFS_VN_SETATTR, VPTOPNC(vp));
955 if (flags & SETATTR_ASYNC)
956 puffs_msg_setfaf(park_setattr);
957
958 puffs_msg_enqueue(pmp, park_setattr);
959 if ((flags & SETATTR_ASYNC) == 0)
960 error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
961 PUFFS_MSG_RELEASE(setattr);
962 if ((flags & SETATTR_ASYNC) == 0) {
963 error = checkerr(pmp, error, __func__);
964 if (error)
965 return error;
966 } else {
967 error = 0;
968 }
969
970 if (vap->va_size != VNOVAL) {
971 pn->pn_serversize = vap->va_size;
972 if (flags & SETATTR_CHSIZE)
973 uvm_vnp_setsize(vp, vap->va_size);
974 }
975
976 return 0;
977 }
978
979 int
980 puffs_vnop_setattr(void *v)
981 {
982 struct vop_getattr_args /* {
983 const struct vnodeop_desc *a_desc;
984 struct vnode *a_vp;
985 struct vattr *a_vap;
986 kauth_cred_t a_cred;
987 } */ *ap = v;
988
989 return dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
990 }
991
992 static __inline int
993 doinact(struct puffs_mount *pmp, int iaflag)
994 {
995
996 if (EXISTSOP(pmp, INACTIVE))
997 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
998 if (iaflag || ALLOPS(pmp))
999 return 1;
1000 else
1001 return 0;
1002 else
1003 return 1;
1004 else
1005 return 0;
1006 }
1007
1008 static void
1009 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
1010 {
1011 int error;
1012 PUFFS_MSG_VARS(vn, inactive);
1013
1014 if (doinact(pmp, iaflag)) {
1015 PUFFS_MSG_ALLOC(vn, inactive);
1016 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1017 PUFFS_VN_INACTIVE, ck);
1018
1019 PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
1020 PUFFS_MSG_RELEASE(inactive);
1021 }
1022 }
1023
1024 /* XXX: callinactive can't setback */
1025 int
1026 puffs_vnop_inactive(void *v)
1027 {
1028 struct vop_inactive_args /* {
1029 const struct vnodeop_desc *a_desc;
1030 struct vnode *a_vp;
1031 } */ *ap = v;
1032 PUFFS_MSG_VARS(vn, inactive);
1033 struct vnode *vp = ap->a_vp;
1034 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1035 struct puffs_node *pnode;
1036 int error;
1037
1038 pnode = vp->v_data;
1039
1040 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
1041 flushvncache(vp, 0, 0, false);
1042 PUFFS_MSG_ALLOC(vn, inactive);
1043 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1044 PUFFS_VN_INACTIVE, VPTOPNC(vp));
1045
1046 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_inactive, vp->v_data,
1047 NULL, error);
1048 PUFFS_MSG_RELEASE(inactive);
1049 }
1050 pnode->pn_stat &= ~PNODE_DOINACT;
1051
1052 /*
1053 * file server thinks it's gone? then don't be afraid care,
1054 * node's life was already all it would ever be
1055 */
1056 if (pnode->pn_stat & PNODE_NOREFS) {
1057 pnode->pn_stat |= PNODE_DYING;
1058 *ap->a_recycle = true;
1059 }
1060
1061 VOP_UNLOCK(vp);
1062
1063 return 0;
1064 }
1065
1066 static void
1067 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
1068 {
1069 PUFFS_MSG_VARS(vn, reclaim);
1070
1071 if (!EXISTSOP(pmp, RECLAIM))
1072 return;
1073
1074 PUFFS_MSG_ALLOC(vn, reclaim);
1075 puffs_msg_setfaf(park_reclaim);
1076 puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
1077
1078 puffs_msg_enqueue(pmp, park_reclaim);
1079 PUFFS_MSG_RELEASE(reclaim);
1080 }
1081
1082 /*
1083 * always FAF, we don't really care if the server wants to fail to
1084 * reclaim the node or not
1085 */
1086 int
1087 puffs_vnop_reclaim(void *v)
1088 {
1089 struct vop_reclaim_args /* {
1090 const struct vnodeop_desc *a_desc;
1091 struct vnode *a_vp;
1092 } */ *ap = v;
1093 struct vnode *vp = ap->a_vp;
1094 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1095 struct puffs_node *pnode = vp->v_data;
1096 bool notifyserver = true;
1097
1098 /*
1099 * first things first: check if someone is trying to reclaim the
1100 * root vnode. do not allow that to travel to userspace.
1101 * Note that we don't need to take the lock similarly to
1102 * puffs_root(), since there is only one of us.
1103 */
1104 if (vp->v_vflag & VV_ROOT) {
1105 mutex_enter(&pmp->pmp_lock);
1106 KASSERT(pmp->pmp_root != NULL);
1107 pmp->pmp_root = NULL;
1108 mutex_exit(&pmp->pmp_lock);
1109 notifyserver = false;
1110 }
1111
1112 /*
1113 * purge info from kernel before issueing FAF, since we
1114 * don't really know when we'll get around to it after
1115 * that and someone might race us into node creation
1116 */
1117 mutex_enter(&pmp->pmp_lock);
1118 LIST_REMOVE(pnode, pn_hashent);
1119 mutex_exit(&pmp->pmp_lock);
1120 if (PUFFS_USE_NAMECACHE(pmp))
1121 cache_purge(vp);
1122
1123 if (notifyserver)
1124 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp));
1125
1126 puffs_putvnode(vp);
1127
1128 return 0;
1129 }
1130
1131 #define CSIZE sizeof(**ap->a_cookies)
1132 int
1133 puffs_vnop_readdir(void *v)
1134 {
1135 struct vop_readdir_args /* {
1136 const struct vnodeop_desc *a_desc;
1137 struct vnode *a_vp;
1138 struct uio *a_uio;
1139 kauth_cred_t a_cred;
1140 int *a_eofflag;
1141 off_t **a_cookies;
1142 int *a_ncookies;
1143 } */ *ap = v;
1144 PUFFS_MSG_VARS(vn, readdir);
1145 struct vnode *vp = ap->a_vp;
1146 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1147 size_t argsize, tomove, cookiemem, cookiesmax;
1148 struct uio *uio = ap->a_uio;
1149 size_t howmuch, resid;
1150 int error;
1151
1152 /*
1153 * ok, so we need: resid + cookiemem = maxreq
1154 * => resid + cookiesize * (resid/minsize) = maxreq
1155 * => resid + cookiesize/minsize * resid = maxreq
1156 * => (cookiesize/minsize + 1) * resid = maxreq
1157 * => resid = maxreq / (cookiesize/minsize + 1)
1158 *
1159 * Since cookiesize <= minsize and we're not very big on floats,
1160 * we approximate that to be 1. Therefore:
1161 *
1162 * resid = maxreq / 2;
1163 *
1164 * Well, at least we didn't have to use differential equations
1165 * or the Gram-Schmidt process.
1166 *
1167 * (yes, I'm very afraid of this)
1168 */
1169 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1170
1171 if (ap->a_cookies) {
1172 KASSERT(ap->a_ncookies != NULL);
1173 if (pmp->pmp_args.pa_fhsize == 0)
1174 return EOPNOTSUPP;
1175 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1176 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1177 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1178 } else {
1179 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1180 cookiesmax = 0;
1181 cookiemem = 0;
1182 }
1183
1184 argsize = sizeof(struct puffs_vnmsg_readdir);
1185 tomove = resid + cookiemem;
1186 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1187 (void *)&readdir_msg, 1);
1188
1189 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1190 readdir_msg->pvnr_offset = uio->uio_offset;
1191 readdir_msg->pvnr_resid = resid;
1192 readdir_msg->pvnr_ncookies = cookiesmax;
1193 readdir_msg->pvnr_eofflag = 0;
1194 readdir_msg->pvnr_dentoff = cookiemem;
1195 puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
1196 PUFFS_VN_READDIR, VPTOPNC(vp));
1197 puffs_msg_setdelta(park_readdir, tomove);
1198
1199 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
1200 error = checkerr(pmp, error, __func__);
1201 if (error)
1202 goto out;
1203
1204 /* userspace is cheating? */
1205 if (readdir_msg->pvnr_resid > resid) {
1206 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1207 "resid grew", VPTOPNC(vp));
1208 ERROUT(EPROTO);
1209 }
1210 if (readdir_msg->pvnr_ncookies > cookiesmax) {
1211 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1212 "too many cookies", VPTOPNC(vp));
1213 ERROUT(EPROTO);
1214 }
1215
1216 /* check eof */
1217 if (readdir_msg->pvnr_eofflag)
1218 *ap->a_eofflag = 1;
1219
1220 /* bouncy-wouncy with the directory data */
1221 howmuch = resid - readdir_msg->pvnr_resid;
1222
1223 /* force eof if no data was returned (getcwd() needs this) */
1224 if (howmuch == 0) {
1225 *ap->a_eofflag = 1;
1226 goto out;
1227 }
1228
1229 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1230 if (error)
1231 goto out;
1232
1233 /* provide cookies to caller if so desired */
1234 if (ap->a_cookies) {
1235 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1236 M_TEMP, M_WAITOK);
1237 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
1238 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1239 *ap->a_ncookies*CSIZE);
1240 }
1241
1242 /* next readdir starts here */
1243 uio->uio_offset = readdir_msg->pvnr_offset;
1244
1245 out:
1246 puffs_msgmem_release(park_readdir);
1247 return error;
1248 }
1249 #undef CSIZE
1250
1251 /*
1252 * poll works by consuming the bitmask in pn_revents. If there are
1253 * events available, poll returns immediately. If not, it issues a
1254 * poll to userspace, selrecords itself and returns with no available
1255 * events. When the file server returns, it executes puffs_parkdone_poll(),
1256 * where available events are added to the bitmask. selnotify() is
1257 * then also executed by that function causing us to enter here again
1258 * and hopefully find the missing bits (unless someone got them first,
1259 * in which case it starts all over again).
1260 */
1261 int
1262 puffs_vnop_poll(void *v)
1263 {
1264 struct vop_poll_args /* {
1265 const struct vnodeop_desc *a_desc;
1266 struct vnode *a_vp;
1267 int a_events;
1268 } */ *ap = v;
1269 PUFFS_MSG_VARS(vn, poll);
1270 struct vnode *vp = ap->a_vp;
1271 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1272 struct puffs_node *pn = vp->v_data;
1273 int events, error;
1274
1275 if (EXISTSOP(pmp, POLL)) {
1276 mutex_enter(&pn->pn_mtx);
1277 events = pn->pn_revents & ap->a_events;
1278 if (events & ap->a_events) {
1279 pn->pn_revents &= ~ap->a_events;
1280 mutex_exit(&pn->pn_mtx);
1281
1282 return events;
1283 } else {
1284 puffs_referencenode(pn);
1285 mutex_exit(&pn->pn_mtx);
1286
1287 PUFFS_MSG_ALLOC(vn, poll);
1288 poll_msg->pvnr_events = ap->a_events;
1289 puffs_msg_setinfo(park_poll, PUFFSOP_VN,
1290 PUFFS_VN_POLL, VPTOPNC(vp));
1291 puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn);
1292 selrecord(curlwp, &pn->pn_sel);
1293
1294 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_poll, vp->v_data,
1295 NULL, error);
1296 PUFFS_MSG_RELEASE(poll);
1297
1298 return 0;
1299 }
1300 } else {
1301 return genfs_poll(v);
1302 }
1303 }
1304
1305 static int
1306 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait)
1307 {
1308 struct puffs_node *pn = VPTOPP(vp);
1309 struct vattr va;
1310 int pflags, error;
1311
1312 /* flush out information from our metacache, see vop_setattr */
1313 if (pn->pn_stat & PNODE_METACACHE_MASK
1314 && (pn->pn_stat & PNODE_DYING) == 0) {
1315 vattr_null(&va);
1316 error = dosetattr(vp, &va, FSCRED,
1317 SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC));
1318 if (error)
1319 return error;
1320 }
1321
1322 /*
1323 * flush pages to avoid being overly dirty
1324 */
1325 pflags = PGO_CLEANIT;
1326 if (wait)
1327 pflags |= PGO_SYNCIO;
1328 mutex_enter(&vp->v_interlock);
1329 return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags);
1330 }
1331
1332 int
1333 puffs_vnop_fsync(void *v)
1334 {
1335 struct vop_fsync_args /* {
1336 const struct vnodeop_desc *a_desc;
1337 struct vnode *a_vp;
1338 kauth_cred_t a_cred;
1339 int a_flags;
1340 off_t a_offlo;
1341 off_t a_offhi;
1342 } */ *ap = v;
1343 PUFFS_MSG_VARS(vn, fsync);
1344 struct vnode *vp = ap->a_vp;
1345 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1346 struct puffs_node *pn = VPTOPP(vp);
1347 int error, dofaf;
1348
1349 error = flushvncache(vp, ap->a_offlo, ap->a_offhi,
1350 (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT);
1351 if (error)
1352 return error;
1353
1354 /*
1355 * HELLO! We exit already here if the user server does not
1356 * support fsync OR if we should call fsync for a node which
1357 * has references neither in the kernel or the fs server.
1358 * Otherwise we continue to issue fsync() forward.
1359 */
1360 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1361 return 0;
1362
1363 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1364 /*
1365 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1366 * only FAFs for those. Otherwise there's a danger of deadlock,
1367 * since the execution context here might be the user server
1368 * doing some operation on another fs, which in turn caused a
1369 * vnode to be reclaimed from the freelist for this fs.
1370 */
1371 if (dofaf == 0) {
1372 mutex_enter(&vp->v_interlock);
1373 if (vp->v_iflag & VI_XLOCK)
1374 dofaf = 1;
1375 mutex_exit(&vp->v_interlock);
1376 }
1377
1378 PUFFS_MSG_ALLOC(vn, fsync);
1379 if (dofaf)
1380 puffs_msg_setfaf(park_fsync);
1381
1382 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1383 fsync_msg->pvnr_flags = ap->a_flags;
1384 fsync_msg->pvnr_offlo = ap->a_offlo;
1385 fsync_msg->pvnr_offhi = ap->a_offhi;
1386 puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
1387 PUFFS_VN_FSYNC, VPTOPNC(vp));
1388
1389 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
1390 PUFFS_MSG_RELEASE(fsync);
1391
1392 error = checkerr(pmp, error, __func__);
1393
1394 return error;
1395 }
1396
1397 int
1398 puffs_vnop_seek(void *v)
1399 {
1400 struct vop_seek_args /* {
1401 const struct vnodeop_desc *a_desc;
1402 struct vnode *a_vp;
1403 off_t a_oldoff;
1404 off_t a_newoff;
1405 kauth_cred_t a_cred;
1406 } */ *ap = v;
1407 PUFFS_MSG_VARS(vn, seek);
1408 struct vnode *vp = ap->a_vp;
1409 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1410 int error;
1411
1412 PUFFS_MSG_ALLOC(vn, seek);
1413 seek_msg->pvnr_oldoff = ap->a_oldoff;
1414 seek_msg->pvnr_newoff = ap->a_newoff;
1415 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1416 puffs_msg_setinfo(park_seek, PUFFSOP_VN,
1417 PUFFS_VN_SEEK, VPTOPNC(vp));
1418
1419 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error);
1420 PUFFS_MSG_RELEASE(seek);
1421 return checkerr(pmp, error, __func__);
1422 }
1423
1424 static int
1425 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1426 struct componentname *cnp)
1427 {
1428 PUFFS_MSG_VARS(vn, remove);
1429 int error;
1430
1431 PUFFS_MSG_ALLOC(vn, remove);
1432 remove_msg->pvnr_cookie_targ = ck;
1433 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1434 cnp, PUFFS_USE_FULLPNBUF(pmp));
1435 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
1436
1437 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
1438 PUFFS_MSG_RELEASE(remove);
1439
1440 return checkerr(pmp, error, __func__);
1441 }
1442
1443 /*
1444 * XXX: can't use callremove now because can't catch setbacks with
1445 * it due to lack of a pnode argument.
1446 */
1447 int
1448 puffs_vnop_remove(void *v)
1449 {
1450 struct vop_remove_args /* {
1451 const struct vnodeop_desc *a_desc;
1452 struct vnode *a_dvp;
1453 struct vnode *a_vp;
1454 struct componentname *a_cnp;
1455 } */ *ap = v;
1456 PUFFS_MSG_VARS(vn, remove);
1457 struct vnode *dvp = ap->a_dvp;
1458 struct vnode *vp = ap->a_vp;
1459 struct puffs_node *dpn = VPTOPP(dvp);
1460 struct puffs_node *pn = VPTOPP(vp);
1461 struct componentname *cnp = ap->a_cnp;
1462 struct mount *mp = dvp->v_mount;
1463 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1464 int error;
1465
1466 PUFFS_MSG_ALLOC(vn, remove);
1467 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1468 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1469 cnp, PUFFS_USE_FULLPNBUF(pmp));
1470 puffs_msg_setinfo(park_remove, PUFFSOP_VN,
1471 PUFFS_VN_REMOVE, VPTOPNC(dvp));
1472
1473 puffs_msg_enqueue(pmp, park_remove);
1474 REFPN_AND_UNLOCKVP(dvp, dpn);
1475 if (dvp == vp)
1476 REFPN(pn);
1477 else
1478 REFPN_AND_UNLOCKVP(vp, pn);
1479 error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
1480
1481 PUFFS_MSG_RELEASE(remove);
1482
1483 RELEPN_AND_VP(dvp, dpn);
1484 RELEPN_AND_VP(vp, pn);
1485
1486 error = checkerr(pmp, error, __func__);
1487 if (error || (cnp->cn_flags & SAVESTART) == 0)
1488 PNBUF_PUT(cnp->cn_pnbuf);
1489 return error;
1490 }
1491
1492 int
1493 puffs_vnop_mkdir(void *v)
1494 {
1495 struct vop_mkdir_args /* {
1496 const struct vnodeop_desc *a_desc;
1497 struct vnode *a_dvp;
1498 struct vnode **a_vpp;
1499 struct componentname *a_cnp;
1500 struct vattr *a_vap;
1501 } */ *ap = v;
1502 PUFFS_MSG_VARS(vn, mkdir);
1503 struct vnode *dvp = ap->a_dvp;
1504 struct puffs_node *dpn = VPTOPP(dvp);
1505 struct componentname *cnp = ap->a_cnp;
1506 struct mount *mp = dvp->v_mount;
1507 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1508 int error;
1509
1510 PUFFS_MSG_ALLOC(vn, mkdir);
1511 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1512 cnp, PUFFS_USE_FULLPNBUF(pmp));
1513 mkdir_msg->pvnr_va = *ap->a_vap;
1514 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1515 PUFFS_VN_MKDIR, VPTOPNC(dvp));
1516
1517 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1518
1519 error = checkerr(pmp, error, __func__);
1520 if (error)
1521 goto out;
1522
1523 error = puffs_newnode(mp, dvp, ap->a_vpp,
1524 mkdir_msg->pvnr_newnode, cnp, VDIR, 0);
1525 if (error)
1526 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1527 mkdir_msg->pvnr_newnode, cnp);
1528
1529 out:
1530 vput(dvp);
1531 PUFFS_MSG_RELEASE(mkdir);
1532 if (error || (cnp->cn_flags & SAVESTART) == 0)
1533 PNBUF_PUT(cnp->cn_pnbuf);
1534 return error;
1535 }
1536
1537 static int
1538 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1539 struct componentname *cnp)
1540 {
1541 PUFFS_MSG_VARS(vn, rmdir);
1542 int error;
1543
1544 PUFFS_MSG_ALLOC(vn, rmdir);
1545 rmdir_msg->pvnr_cookie_targ = ck;
1546 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1547 cnp, PUFFS_USE_FULLPNBUF(pmp));
1548 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1549
1550 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1551 PUFFS_MSG_RELEASE(rmdir);
1552
1553 return checkerr(pmp, error, __func__);
1554 }
1555
1556 int
1557 puffs_vnop_rmdir(void *v)
1558 {
1559 struct vop_rmdir_args /* {
1560 const struct vnodeop_desc *a_desc;
1561 struct vnode *a_dvp;
1562 struct vnode *a_vp;
1563 struct componentname *a_cnp;
1564 } */ *ap = v;
1565 PUFFS_MSG_VARS(vn, rmdir);
1566 struct vnode *dvp = ap->a_dvp;
1567 struct vnode *vp = ap->a_vp;
1568 struct puffs_node *dpn = VPTOPP(dvp);
1569 struct puffs_node *pn = VPTOPP(vp);
1570 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1571 struct componentname *cnp = ap->a_cnp;
1572 int error;
1573
1574 PUFFS_MSG_ALLOC(vn, rmdir);
1575 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1576 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1577 cnp, PUFFS_USE_FULLPNBUF(pmp));
1578 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1579 PUFFS_VN_RMDIR, VPTOPNC(dvp));
1580
1581 puffs_msg_enqueue(pmp, park_rmdir);
1582 REFPN_AND_UNLOCKVP(dvp, dpn);
1583 REFPN_AND_UNLOCKVP(vp, pn);
1584 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1585
1586 PUFFS_MSG_RELEASE(rmdir);
1587
1588 /* XXX: some call cache_purge() *for both vnodes* here, investigate */
1589 RELEPN_AND_VP(dvp, dpn);
1590 RELEPN_AND_VP(vp, pn);
1591
1592 if (error || (cnp->cn_flags & SAVESTART) == 0)
1593 PNBUF_PUT(cnp->cn_pnbuf);
1594
1595 return error;
1596 }
1597
1598 int
1599 puffs_vnop_link(void *v)
1600 {
1601 struct vop_link_args /* {
1602 const struct vnodeop_desc *a_desc;
1603 struct vnode *a_dvp;
1604 struct vnode *a_vp;
1605 struct componentname *a_cnp;
1606 } */ *ap = v;
1607 PUFFS_MSG_VARS(vn, link);
1608 struct vnode *dvp = ap->a_dvp;
1609 struct vnode *vp = ap->a_vp;
1610 struct puffs_node *dpn = VPTOPP(dvp);
1611 struct puffs_node *pn = VPTOPP(vp);
1612 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1613 struct componentname *cnp = ap->a_cnp;
1614 int error;
1615
1616 PUFFS_MSG_ALLOC(vn, link);
1617 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1618 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1619 cnp, PUFFS_USE_FULLPNBUF(pmp));
1620 puffs_msg_setinfo(park_link, PUFFSOP_VN,
1621 PUFFS_VN_LINK, VPTOPNC(dvp));
1622
1623 puffs_msg_enqueue(pmp, park_link);
1624 REFPN_AND_UNLOCKVP(dvp, dpn);
1625 REFPN(pn);
1626 error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1627
1628 PUFFS_MSG_RELEASE(link);
1629
1630 error = checkerr(pmp, error, __func__);
1631
1632 /*
1633 * XXX: stay in touch with the cache. I don't like this, but
1634 * don't have a better solution either. See also puffs_rename().
1635 */
1636 if (error == 0)
1637 puffs_updatenode(pn, PUFFS_UPDATECTIME, 0);
1638
1639 PNBUF_PUT(cnp->cn_pnbuf);
1640 RELEPN_AND_VP(dvp, dpn);
1641 puffs_releasenode(pn);
1642
1643 return error;
1644 }
1645
1646 int
1647 puffs_vnop_symlink(void *v)
1648 {
1649 struct vop_symlink_args /* {
1650 const struct vnodeop_desc *a_desc;
1651 struct vnode *a_dvp;
1652 struct vnode **a_vpp;
1653 struct componentname *a_cnp;
1654 struct vattr *a_vap;
1655 char *a_target;
1656 } */ *ap = v;
1657 PUFFS_MSG_VARS(vn, symlink);
1658 struct vnode *dvp = ap->a_dvp;
1659 struct puffs_node *dpn = VPTOPP(dvp);
1660 struct mount *mp = dvp->v_mount;
1661 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1662 struct componentname *cnp = ap->a_cnp;
1663 int error;
1664
1665 *ap->a_vpp = NULL;
1666
1667 PUFFS_MSG_ALLOC(vn, symlink);
1668 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1669 cnp, PUFFS_USE_FULLPNBUF(pmp));
1670 symlink_msg->pvnr_va = *ap->a_vap;
1671 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1672 sizeof(symlink_msg->pvnr_link));
1673 puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
1674 PUFFS_VN_SYMLINK, VPTOPNC(dvp));
1675
1676 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
1677
1678 error = checkerr(pmp, error, __func__);
1679 if (error)
1680 goto out;
1681
1682 error = puffs_newnode(mp, dvp, ap->a_vpp,
1683 symlink_msg->pvnr_newnode, cnp, VLNK, 0);
1684 if (error)
1685 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
1686 symlink_msg->pvnr_newnode, cnp);
1687
1688 out:
1689 vput(dvp);
1690 PUFFS_MSG_RELEASE(symlink);
1691 if (error || (cnp->cn_flags & SAVESTART) == 0)
1692 PNBUF_PUT(cnp->cn_pnbuf);
1693
1694 return error;
1695 }
1696
1697 int
1698 puffs_vnop_readlink(void *v)
1699 {
1700 struct vop_readlink_args /* {
1701 const struct vnodeop_desc *a_desc;
1702 struct vnode *a_vp;
1703 struct uio *a_uio;
1704 kauth_cred_t a_cred;
1705 } */ *ap = v;
1706 PUFFS_MSG_VARS(vn, readlink);
1707 struct vnode *vp = ap->a_vp;
1708 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1709 size_t linklen;
1710 int error;
1711
1712 PUFFS_MSG_ALLOC(vn, readlink);
1713 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1714 linklen = sizeof(readlink_msg->pvnr_link);
1715 readlink_msg->pvnr_linklen = linklen;
1716 puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
1717 PUFFS_VN_READLINK, VPTOPNC(vp));
1718
1719 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
1720 error = checkerr(pmp, error, __func__);
1721 if (error)
1722 goto out;
1723
1724 /* bad bad user file server */
1725 if (readlink_msg->pvnr_linklen > linklen) {
1726 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
1727 "linklen too big", VPTOPNC(ap->a_vp));
1728 error = EPROTO;
1729 goto out;
1730 }
1731
1732 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1733 ap->a_uio);
1734 out:
1735 PUFFS_MSG_RELEASE(readlink);
1736 return error;
1737 }
1738
1739 int
1740 puffs_vnop_rename(void *v)
1741 {
1742 struct vop_rename_args /* {
1743 const struct vnodeop_desc *a_desc;
1744 struct vnode *a_fdvp;
1745 struct vnode *a_fvp;
1746 struct componentname *a_fcnp;
1747 struct vnode *a_tdvp;
1748 struct vnode *a_tvp;
1749 struct componentname *a_tcnp;
1750 } */ *ap = v;
1751 PUFFS_MSG_VARS(vn, rename);
1752 struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp;
1753 struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp;
1754 struct puffs_node *fpn = ap->a_fvp->v_data;
1755 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
1756 int error;
1757 bool doabort = true;
1758
1759 if ((fvp->v_mount != tdvp->v_mount) ||
1760 (tvp && (fvp->v_mount != tvp->v_mount))) {
1761 ERROUT(EXDEV);
1762 }
1763
1764 PUFFS_MSG_ALLOC(vn, rename);
1765 rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
1766 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
1767 if (tvp)
1768 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
1769 else
1770 rename_msg->pvnr_cookie_targ = NULL;
1771 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
1772 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
1773 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
1774 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
1775 puffs_msg_setinfo(park_rename, PUFFSOP_VN,
1776 PUFFS_VN_RENAME, VPTOPNC(fdvp));
1777
1778 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
1779 doabort = false;
1780 PUFFS_MSG_RELEASE(rename);
1781 error = checkerr(pmp, error, __func__);
1782
1783 /*
1784 * XXX: stay in touch with the cache. I don't like this, but
1785 * don't have a better solution either. See also puffs_link().
1786 */
1787 if (error == 0)
1788 puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0);
1789
1790 out:
1791 if (doabort)
1792 VOP_ABORTOP(tdvp, ap->a_tcnp);
1793 if (tvp != NULL)
1794 vput(tvp);
1795 if (tdvp == tvp)
1796 vrele(tdvp);
1797 else
1798 vput(tdvp);
1799
1800 if (doabort)
1801 VOP_ABORTOP(fdvp, ap->a_fcnp);
1802 vrele(fdvp);
1803 vrele(fvp);
1804
1805 return error;
1806 }
1807
1808 #define RWARGS(cont, iofl, move, offset, creds) \
1809 (cont)->pvnr_ioflag = (iofl); \
1810 (cont)->pvnr_resid = (move); \
1811 (cont)->pvnr_offset = (offset); \
1812 puffs_credcvt(&(cont)->pvnr_cred, creds)
1813
1814 int
1815 puffs_vnop_read(void *v)
1816 {
1817 struct vop_read_args /* {
1818 const struct vnodeop_desc *a_desc;
1819 struct vnode *a_vp;
1820 struct uio *a_uio;
1821 int a_ioflag;
1822 kauth_cred_t a_cred;
1823 } */ *ap = v;
1824 PUFFS_MSG_VARS(vn, read);
1825 struct vnode *vp = ap->a_vp;
1826 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1827 struct uio *uio = ap->a_uio;
1828 size_t tomove, argsize;
1829 vsize_t bytelen;
1830 int error;
1831
1832 read_msg = NULL;
1833 error = 0;
1834
1835 /* std sanity */
1836 if (uio->uio_resid == 0)
1837 return 0;
1838 if (uio->uio_offset < 0)
1839 return EINVAL;
1840
1841 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1842 const int advice = IO_ADV_DECODE(ap->a_ioflag);
1843
1844 while (uio->uio_resid > 0) {
1845 bytelen = MIN(uio->uio_resid,
1846 vp->v_size - uio->uio_offset);
1847 if (bytelen == 0)
1848 break;
1849
1850 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
1851 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
1852 if (error)
1853 break;
1854 }
1855
1856 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1857 puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0);
1858 } else {
1859 /*
1860 * in case it's not a regular file or we're operating
1861 * uncached, do read in the old-fashioned style,
1862 * i.e. explicit read operations
1863 */
1864
1865 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1866 argsize = sizeof(struct puffs_vnmsg_read);
1867 puffs_msgmem_alloc(argsize + tomove, &park_read,
1868 (void *)&read_msg, 1);
1869
1870 error = 0;
1871 while (uio->uio_resid > 0) {
1872 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1873 memset(read_msg, 0, argsize); /* XXX: touser KASSERT */
1874 RWARGS(read_msg, ap->a_ioflag, tomove,
1875 uio->uio_offset, ap->a_cred);
1876 puffs_msg_setinfo(park_read, PUFFSOP_VN,
1877 PUFFS_VN_READ, VPTOPNC(vp));
1878 puffs_msg_setdelta(park_read, tomove);
1879
1880 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data,
1881 NULL, error);
1882 error = checkerr(pmp, error, __func__);
1883 if (error)
1884 break;
1885
1886 if (read_msg->pvnr_resid > tomove) {
1887 puffs_senderr(pmp, PUFFS_ERR_READ,
1888 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1889 error = EPROTO;
1890 break;
1891 }
1892
1893 error = uiomove(read_msg->pvnr_data,
1894 tomove - read_msg->pvnr_resid, uio);
1895
1896 /*
1897 * in case the file is out of juice, resid from
1898 * userspace is != 0. and the error-case is
1899 * quite obvious
1900 */
1901 if (error || read_msg->pvnr_resid)
1902 break;
1903 }
1904
1905 puffs_msgmem_release(park_read);
1906 }
1907
1908 return error;
1909 }
1910
1911 /*
1912 * XXX: in case of a failure, this leaves uio in a bad state.
1913 * We could theoretically copy the uio and iovecs and "replay"
1914 * them the right amount after the userspace trip, but don't
1915 * bother for now.
1916 */
1917 int
1918 puffs_vnop_write(void *v)
1919 {
1920 struct vop_write_args /* {
1921 const struct vnodeop_desc *a_desc;
1922 struct vnode *a_vp;
1923 struct uio *a_uio;
1924 int a_ioflag;
1925 kauth_cred_t a_cred;
1926 } */ *ap = v;
1927 PUFFS_MSG_VARS(vn, write);
1928 struct vnode *vp = ap->a_vp;
1929 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1930 struct uio *uio = ap->a_uio;
1931 size_t tomove, argsize;
1932 off_t oldoff, newoff, origoff;
1933 vsize_t bytelen;
1934 int error, uflags;
1935 int ubcflags;
1936
1937 error = uflags = 0;
1938 write_msg = NULL;
1939
1940 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1941 ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp);
1942
1943 /*
1944 * userspace *should* be allowed to control this,
1945 * but with UBC it's a bit unclear how to handle it
1946 */
1947 if (ap->a_ioflag & IO_APPEND)
1948 uio->uio_offset = vp->v_size;
1949
1950 origoff = uio->uio_offset;
1951 while (uio->uio_resid > 0) {
1952 uflags |= PUFFS_UPDATECTIME;
1953 uflags |= PUFFS_UPDATEMTIME;
1954 oldoff = uio->uio_offset;
1955 bytelen = uio->uio_resid;
1956
1957 newoff = oldoff + bytelen;
1958 if (vp->v_size < newoff) {
1959 uvm_vnp_setwritesize(vp, newoff);
1960 }
1961 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
1962 UVM_ADV_RANDOM, ubcflags);
1963
1964 /*
1965 * In case of a ubc_uiomove() error,
1966 * opt to not extend the file at all and
1967 * return an error. Otherwise, if we attempt
1968 * to clear the memory we couldn't fault to,
1969 * we might generate a kernel page fault.
1970 */
1971 if (vp->v_size < newoff) {
1972 if (error == 0) {
1973 uflags |= PUFFS_UPDATESIZE;
1974 uvm_vnp_setsize(vp, newoff);
1975 } else {
1976 uvm_vnp_setwritesize(vp, vp->v_size);
1977 }
1978 }
1979 if (error)
1980 break;
1981
1982 /*
1983 * If we're writing large files, flush to file server
1984 * every 64k. Otherwise we can very easily exhaust
1985 * kernel and user memory, as the file server cannot
1986 * really keep up with our writing speed.
1987 *
1988 * Note: this does *NOT* honor MNT_ASYNC, because
1989 * that gives userland too much say in the kernel.
1990 */
1991 if (oldoff >> 16 != uio->uio_offset >> 16) {
1992 mutex_enter(&vp->v_interlock);
1993 error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
1994 uio->uio_offset & ~0xffff,
1995 PGO_CLEANIT | PGO_SYNCIO);
1996 if (error)
1997 break;
1998 }
1999 }
2000
2001 /* synchronous I/O? */
2002 if (error == 0 && ap->a_ioflag & IO_SYNC) {
2003 mutex_enter(&vp->v_interlock);
2004 error = VOP_PUTPAGES(vp, trunc_page(origoff),
2005 round_page(uio->uio_offset),
2006 PGO_CLEANIT | PGO_SYNCIO);
2007
2008 /* write through page cache? */
2009 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
2010 mutex_enter(&vp->v_interlock);
2011 error = VOP_PUTPAGES(vp, trunc_page(origoff),
2012 round_page(uio->uio_offset), PGO_CLEANIT);
2013 }
2014
2015 puffs_updatenode(VPTOPP(vp), uflags, vp->v_size);
2016 } else {
2017 /* tomove is non-increasing */
2018 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2019 argsize = sizeof(struct puffs_vnmsg_write) + tomove;
2020 puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1);
2021
2022 while (uio->uio_resid > 0) {
2023 /* move data to buffer */
2024 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2025 memset(write_msg, 0, argsize); /* XXX: touser KASSERT */
2026 RWARGS(write_msg, ap->a_ioflag, tomove,
2027 uio->uio_offset, ap->a_cred);
2028 error = uiomove(write_msg->pvnr_data, tomove, uio);
2029 if (error)
2030 break;
2031
2032 /* move buffer to userspace */
2033 puffs_msg_setinfo(park_write, PUFFSOP_VN,
2034 PUFFS_VN_WRITE, VPTOPNC(vp));
2035 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data,
2036 NULL, error);
2037 error = checkerr(pmp, error, __func__);
2038 if (error)
2039 break;
2040
2041 if (write_msg->pvnr_resid > tomove) {
2042 puffs_senderr(pmp, PUFFS_ERR_WRITE,
2043 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2044 error = EPROTO;
2045 break;
2046 }
2047
2048 /* adjust file size */
2049 if (vp->v_size < uio->uio_offset)
2050 uvm_vnp_setsize(vp, uio->uio_offset);
2051
2052 /* didn't move everything? bad userspace. bail */
2053 if (write_msg->pvnr_resid != 0) {
2054 error = EIO;
2055 break;
2056 }
2057 }
2058 puffs_msgmem_release(park_write);
2059 }
2060
2061 return error;
2062 }
2063
2064 int
2065 puffs_vnop_print(void *v)
2066 {
2067 struct vop_print_args /* {
2068 struct vnode *a_vp;
2069 } */ *ap = v;
2070 PUFFS_MSG_VARS(vn, print);
2071 struct vnode *vp = ap->a_vp;
2072 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2073 struct puffs_node *pn = vp->v_data;
2074 int error;
2075
2076 /* kernel portion */
2077 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
2078 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
2079 if (vp->v_type == VFIFO)
2080 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
2081 printf("\n");
2082
2083 /* userspace portion */
2084 if (EXISTSOP(pmp, PRINT)) {
2085 PUFFS_MSG_ALLOC(vn, print);
2086 puffs_msg_setinfo(park_print, PUFFSOP_VN,
2087 PUFFS_VN_PRINT, VPTOPNC(vp));
2088 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
2089 NULL, error);
2090 PUFFS_MSG_RELEASE(print);
2091 }
2092
2093 return 0;
2094 }
2095
2096 int
2097 puffs_vnop_pathconf(void *v)
2098 {
2099 struct vop_pathconf_args /* {
2100 const struct vnodeop_desc *a_desc;
2101 struct vnode *a_vp;
2102 int a_name;
2103 register_t *a_retval;
2104 } */ *ap = v;
2105 PUFFS_MSG_VARS(vn, pathconf);
2106 struct vnode *vp = ap->a_vp;
2107 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2108 int error;
2109
2110 PUFFS_MSG_ALLOC(vn, pathconf);
2111 pathconf_msg->pvnr_name = ap->a_name;
2112 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
2113 PUFFS_VN_PATHCONF, VPTOPNC(vp));
2114 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
2115 error = checkerr(pmp, error, __func__);
2116 if (!error)
2117 *ap->a_retval = pathconf_msg->pvnr_retval;
2118 PUFFS_MSG_RELEASE(pathconf);
2119
2120 return error;
2121 }
2122
2123 int
2124 puffs_vnop_advlock(void *v)
2125 {
2126 struct vop_advlock_args /* {
2127 const struct vnodeop_desc *a_desc;
2128 struct vnode *a_vp;
2129 void *a_id;
2130 int a_op;
2131 struct flock *a_fl;
2132 int a_flags;
2133 } */ *ap = v;
2134 PUFFS_MSG_VARS(vn, advlock);
2135 struct vnode *vp = ap->a_vp;
2136 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2137 int error;
2138
2139 PUFFS_MSG_ALLOC(vn, advlock);
2140 error = copyin(ap->a_fl, &advlock_msg->pvnr_fl, sizeof(struct flock));
2141 if (error)
2142 goto out;
2143 advlock_msg->pvnr_id = ap->a_id;
2144 advlock_msg->pvnr_op = ap->a_op;
2145 advlock_msg->pvnr_flags = ap->a_flags;
2146 puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
2147 PUFFS_VN_ADVLOCK, VPTOPNC(vp));
2148
2149 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
2150 error = checkerr(pmp, error, __func__);
2151
2152 out:
2153 PUFFS_MSG_RELEASE(advlock);
2154 return error;
2155 }
2156
2157 int
2158 puffs_vnop_abortop(void *v)
2159 {
2160 struct vop_abortop_args /* {
2161 struct vnode *a_dvp;
2162 struct componentname *a_cnp;
2163 }; */ *ap = v;
2164 PUFFS_MSG_VARS(vn, abortop);
2165 struct vnode *dvp = ap->a_dvp;
2166 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
2167 struct componentname *cnp = ap->a_cnp;
2168
2169 if (EXISTSOP(pmp, ABORTOP)) {
2170 PUFFS_MSG_ALLOC(vn, abortop);
2171 puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred,
2172 cnp, PUFFS_USE_FULLPNBUF(pmp));
2173 puffs_msg_setfaf(park_abortop);
2174 puffs_msg_setinfo(park_abortop, PUFFSOP_VN,
2175 PUFFS_VN_ABORTOP, VPTOPNC(dvp));
2176
2177 puffs_msg_enqueue(pmp, park_abortop);
2178 PUFFS_MSG_RELEASE(abortop);
2179 }
2180
2181 return genfs_abortop(v);
2182 }
2183
2184 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2185
2186 /*
2187 * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2188 */
2189 int
2190 puffs_vnop_strategy(void *v)
2191 {
2192 struct vop_strategy_args /* {
2193 const struct vnodeop_desc *a_desc;
2194 struct vnode *a_vp;
2195 struct buf *a_bp;
2196 } */ *ap = v;
2197 PUFFS_MSG_VARS(vn, rw);
2198 struct vnode *vp = ap->a_vp;
2199 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2200 struct puffs_node *pn;
2201 struct buf *bp;
2202 size_t argsize;
2203 size_t tomove, moved;
2204 int error, dofaf, dobiodone;
2205
2206 pmp = MPTOPUFFSMP(vp->v_mount);
2207 bp = ap->a_bp;
2208 error = 0;
2209 dofaf = 0;
2210 pn = VPTOPP(vp);
2211 park_rw = NULL; /* explicit */
2212 dobiodone = 1;
2213
2214 if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ))
2215 || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2216 ERROUT(EOPNOTSUPP);
2217
2218 /*
2219 * Short-circuit optimization: don't flush buffer in between
2220 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2221 */
2222 if (pn->pn_stat & PNODE_DYING) {
2223 KASSERT(BUF_ISWRITE(bp));
2224 bp->b_resid = 0;
2225 goto out;
2226 }
2227
2228 #ifdef DIAGNOSTIC
2229 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2230 panic("puffs_strategy: wildly inappropriate buf bcount %d",
2231 bp->b_bcount);
2232 #endif
2233
2234 /*
2235 * See explanation for the necessity of a FAF in puffs_fsync.
2236 *
2237 * Also, do FAF in case we're suspending.
2238 * See puffs_vfsops.c:pageflush()
2239 */
2240 if (BUF_ISWRITE(bp)) {
2241 mutex_enter(&vp->v_interlock);
2242 if (vp->v_iflag & VI_XLOCK)
2243 dofaf = 1;
2244 if (pn->pn_stat & PNODE_FAF)
2245 dofaf = 1;
2246 mutex_exit(&vp->v_interlock);
2247 }
2248
2249 #ifdef DIAGNOSTIC
2250 if (curlwp == uvm.pagedaemon_lwp)
2251 KASSERT(dofaf || BIOASYNC(bp));
2252 #endif
2253
2254 /* allocate transport structure */
2255 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2256 argsize = sizeof(struct puffs_vnmsg_rw);
2257 error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2258 (void *)&rw_msg, dofaf ? 0 : 1);
2259 if (error)
2260 goto out;
2261 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2262
2263 /* 2x2 cases: read/write, faf/nofaf */
2264 if (BUF_ISREAD(bp)) {
2265 puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2266 PUFFS_VN_READ, VPTOPNC(vp));
2267 puffs_msg_setdelta(park_rw, tomove);
2268 if (BIOASYNC(bp)) {
2269 puffs_msg_setcall(park_rw,
2270 puffs_parkdone_asyncbioread, bp);
2271 puffs_msg_enqueue(pmp, park_rw);
2272 dobiodone = 0;
2273 } else {
2274 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data,
2275 NULL, error);
2276 error = checkerr(pmp, error, __func__);
2277 if (error)
2278 goto out;
2279
2280 if (rw_msg->pvnr_resid > tomove) {
2281 puffs_senderr(pmp, PUFFS_ERR_READ,
2282 E2BIG, "resid grew", VPTOPNC(vp));
2283 ERROUT(EPROTO);
2284 }
2285
2286 moved = tomove - rw_msg->pvnr_resid;
2287
2288 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2289 bp->b_resid = bp->b_bcount - moved;
2290 }
2291 } else {
2292 puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2293 PUFFS_VN_WRITE, VPTOPNC(vp));
2294 /*
2295 * make pages read-only before we write them if we want
2296 * write caching info
2297 */
2298 if (PUFFS_WCACHEINFO(pmp)) {
2299 struct uvm_object *uobj = &vp->v_uobj;
2300 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2301 struct vm_page *vmp;
2302 int i;
2303
2304 for (i = 0; i < npages; i++) {
2305 vmp= uvm_pageratop((vaddr_t)bp->b_data
2306 + (i << PAGE_SHIFT));
2307 DPRINTF(("puffs_strategy: write-protecting "
2308 "vp %p page %p, offset %" PRId64"\n",
2309 vp, vmp, vmp->offset));
2310 mutex_enter(&uobj->vmobjlock);
2311 vmp->flags |= PG_RDONLY;
2312 pmap_page_protect(vmp, VM_PROT_READ);
2313 mutex_exit(&uobj->vmobjlock);
2314 }
2315 }
2316
2317 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2318 if (dofaf) {
2319 puffs_msg_setfaf(park_rw);
2320 } else if (BIOASYNC(bp)) {
2321 puffs_msg_setcall(park_rw,
2322 puffs_parkdone_asyncbiowrite, bp);
2323 dobiodone = 0;
2324 }
2325
2326 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error);
2327
2328 if (dobiodone == 0)
2329 goto out;
2330
2331 /*
2332 * XXXXXXXX: wrong, but kernel can't survive strategy
2333 * failure currently. Here, have one more X: X.
2334 */
2335 if (error != ENOMEM)
2336 error = 0;
2337
2338 error = checkerr(pmp, error, __func__);
2339 if (error)
2340 goto out;
2341
2342 if (rw_msg->pvnr_resid > tomove) {
2343 puffs_senderr(pmp, PUFFS_ERR_WRITE,
2344 E2BIG, "resid grew", VPTOPNC(vp));
2345 ERROUT(EPROTO);
2346 }
2347
2348 /*
2349 * FAF moved everything. Frankly, we don't
2350 * really have a choice.
2351 */
2352 if (dofaf && error == 0)
2353 moved = tomove;
2354 else
2355 moved = tomove - rw_msg->pvnr_resid;
2356
2357 bp->b_resid = bp->b_bcount - moved;
2358 if (bp->b_resid != 0) {
2359 ERROUT(EIO);
2360 }
2361 }
2362
2363 out:
2364 if (park_rw)
2365 puffs_msgmem_release(park_rw);
2366
2367 if (error)
2368 bp->b_error = error;
2369
2370 if (error || dobiodone)
2371 biodone(bp);
2372
2373 return error;
2374 }
2375
2376 int
2377 puffs_vnop_mmap(void *v)
2378 {
2379 struct vop_mmap_args /* {
2380 const struct vnodeop_desc *a_desc;
2381 struct vnode *a_vp;
2382 vm_prot_t a_prot;
2383 kauth_cred_t a_cred;
2384 } */ *ap = v;
2385 PUFFS_MSG_VARS(vn, mmap);
2386 struct vnode *vp = ap->a_vp;
2387 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2388 int error;
2389
2390 if (!PUFFS_USE_PAGECACHE(pmp))
2391 return genfs_eopnotsupp(v);
2392
2393 if (EXISTSOP(pmp, MMAP)) {
2394 PUFFS_MSG_ALLOC(vn, mmap);
2395 mmap_msg->pvnr_prot = ap->a_prot;
2396 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2397 puffs_msg_setinfo(park_mmap, PUFFSOP_VN,
2398 PUFFS_VN_MMAP, VPTOPNC(vp));
2399
2400 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error);
2401 error = checkerr(pmp, error, __func__);
2402 PUFFS_MSG_RELEASE(mmap);
2403 } else {
2404 error = genfs_mmap(v);
2405 }
2406
2407 return error;
2408 }
2409
2410
2411 /*
2412 * The rest don't get a free trip to userspace and back, they
2413 * have to stay within the kernel.
2414 */
2415
2416 /*
2417 * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2418 * well, maybe somehow, somewhere, some day ....
2419 */
2420 int
2421 puffs_vnop_bmap(void *v)
2422 {
2423 struct vop_bmap_args /* {
2424 const struct vnodeop_desc *a_desc;
2425 struct vnode *a_vp;
2426 daddr_t a_bn;
2427 struct vnode **a_vpp;
2428 daddr_t *a_bnp;
2429 int *a_runp;
2430 } */ *ap = v;
2431 struct puffs_mount *pmp;
2432
2433 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2434
2435 if (ap->a_vpp)
2436 *ap->a_vpp = ap->a_vp;
2437 if (ap->a_bnp)
2438 *ap->a_bnp = ap->a_bn;
2439 if (ap->a_runp)
2440 *ap->a_runp
2441 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2442
2443 return 0;
2444 }
2445
2446 /*
2447 * Handle getpages faults in puffs. We let genfs_getpages() do most
2448 * of the dirty work, but we come in this route to do accounting tasks.
2449 * If the user server has specified functions for cache notifications
2450 * about reads and/or writes, we record which type of operation we got,
2451 * for which page range, and proceed to issue a FAF notification to the
2452 * server about it.
2453 */
2454 int
2455 puffs_vnop_getpages(void *v)
2456 {
2457 struct vop_getpages_args /* {
2458 const struct vnodeop_desc *a_desc;
2459 struct vnode *a_vp;
2460 voff_t a_offset;
2461 struct vm_page **a_m;
2462 int *a_count;
2463 int a_centeridx;
2464 vm_prot_t a_access_type;
2465 int a_advice;
2466 int a_flags;
2467 } */ *ap = v;
2468 struct puffs_mount *pmp;
2469 struct puffs_node *pn;
2470 struct vnode *vp;
2471 struct vm_page **pgs;
2472 struct puffs_cacheinfo *pcinfo = NULL;
2473 struct puffs_cacherun *pcrun;
2474 void *parkmem = NULL;
2475 size_t runsizes;
2476 int i, npages, si, streakon;
2477 int error, locked, write;
2478
2479 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2480 npages = *ap->a_count;
2481 pgs = ap->a_m;
2482 vp = ap->a_vp;
2483 pn = vp->v_data;
2484 locked = (ap->a_flags & PGO_LOCKED) != 0;
2485 write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2486
2487 /* ccg xnaht - gets Wuninitialized wrong */
2488 pcrun = NULL;
2489 runsizes = 0;
2490
2491 /*
2492 * Check that we aren't trying to fault in pages which our file
2493 * server doesn't know about. This happens if we extend a file by
2494 * skipping some pages and later try to fault in pages which
2495 * are between pn_serversize and vp_size. This check optimizes
2496 * away the common case where a file is being extended.
2497 */
2498 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2499 struct vattr va;
2500
2501 /* try again later when we can block */
2502 if (locked)
2503 ERROUT(EBUSY);
2504
2505 mutex_exit(&vp->v_interlock);
2506 vattr_null(&va);
2507 va.va_size = vp->v_size;
2508 error = dosetattr(vp, &va, FSCRED, 0);
2509 if (error)
2510 ERROUT(error);
2511 mutex_enter(&vp->v_interlock);
2512 }
2513
2514 if (write && PUFFS_WCACHEINFO(pmp)) {
2515 #ifdef notnowjohn
2516 /* allocate worst-case memory */
2517 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2518 pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize,
2519 locked ? KM_NOSLEEP : KM_SLEEP);
2520
2521 /*
2522 * can't block if we're locked and can't mess up caching
2523 * information for fs server. so come back later, please
2524 */
2525 if (pcinfo == NULL)
2526 ERROUT(ENOMEM);
2527
2528 parkmem = puffs_park_alloc(locked == 0);
2529 if (parkmem == NULL)
2530 ERROUT(ENOMEM);
2531
2532 pcrun = pcinfo->pcache_runs;
2533 #else
2534 (void)parkmem;
2535 #endif
2536 }
2537
2538 error = genfs_getpages(v);
2539 if (error)
2540 goto out;
2541
2542 if (PUFFS_WCACHEINFO(pmp) == 0)
2543 goto out;
2544
2545 /*
2546 * Let's see whose fault it was and inform the user server of
2547 * possibly read/written pages. Map pages from read faults
2548 * strictly read-only, since otherwise we might miss info on
2549 * when the page is actually write-faulted to.
2550 */
2551 if (!locked)
2552 mutex_enter(&vp->v_uobj.vmobjlock);
2553 for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2554 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2555 if (streakon && write) {
2556 streakon = 0;
2557 pcrun[si].pcache_runend
2558 = trunc_page(pgs[i]->offset) + PAGE_MASK;
2559 si++;
2560 }
2561 continue;
2562 }
2563 if (streakon == 0 && write) {
2564 streakon = 1;
2565 pcrun[si].pcache_runstart = pgs[i]->offset;
2566 }
2567
2568 if (!write)
2569 pgs[i]->flags |= PG_RDONLY;
2570 }
2571 /* was the last page part of our streak? */
2572 if (streakon) {
2573 pcrun[si].pcache_runend
2574 = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2575 si++;
2576 }
2577 if (!locked)
2578 mutex_exit(&vp->v_uobj.vmobjlock);
2579
2580 KASSERT(si <= (npages / 2) + 1);
2581
2582 #ifdef notnowjohn
2583 /* send results to userspace */
2584 if (write)
2585 puffs_cacheop(pmp, parkmem, pcinfo,
2586 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2587 #endif
2588
2589 out:
2590 if (error) {
2591 if (pcinfo != NULL)
2592 kmem_free(pcinfo,
2593 sizeof(struct puffs_cacheinfo) + runsizes);
2594 #ifdef notnowjohn
2595 if (parkmem != NULL)
2596 puffs_park_release(parkmem, 1);
2597 #endif
2598 }
2599
2600 return error;
2601 }
2602
2603 /*
2604 * Extended attribute support.
2605 */
2606
2607 int
2608 puffs_vnop_getextattr(void *v)
2609 {
2610 struct vop_getextattr_args /*
2611 struct vnode *a_vp;
2612 int a_attrnamespace;
2613 const char *a_name;
2614 struct uio *a_uio;
2615 size_t *a_size;
2616 kauth_cred_t a_cred;
2617 }; */ *ap = v;
2618 PUFFS_MSG_VARS(vn, getextattr);
2619 struct vnode *vp = ap->a_vp;
2620 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2621 int attrnamespace = ap->a_attrnamespace;
2622 const char *name = ap->a_name;
2623 struct uio *uio = ap->a_uio;
2624 size_t *sizep = ap->a_size;
2625 size_t tomove, resid;
2626 int error;
2627
2628 if (uio)
2629 resid = uio->uio_resid;
2630 else
2631 resid = 0;
2632
2633 tomove = PUFFS_TOMOVE(resid, pmp);
2634 if (tomove != resid) {
2635 error = E2BIG;
2636 goto out;
2637 }
2638
2639 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove,
2640 &park_getextattr, (void *)&getextattr_msg, 1);
2641
2642 getextattr_msg->pvnr_attrnamespace = attrnamespace;
2643 strlcpy(getextattr_msg->pvnr_attrname, name,
2644 sizeof(getextattr_msg->pvnr_attrname));
2645 puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred);
2646 if (sizep)
2647 getextattr_msg->pvnr_datasize = 1;
2648 getextattr_msg->pvnr_resid = tomove;
2649
2650 puffs_msg_setinfo(park_getextattr,
2651 PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp));
2652 puffs_msg_setdelta(park_getextattr, tomove);
2653 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error);
2654
2655 error = checkerr(pmp, error, __func__);
2656 if (error)
2657 goto out;
2658
2659 resid = getextattr_msg->pvnr_resid;
2660 if (resid > tomove) {
2661 puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG,
2662 "resid grew", VPTOPNC(vp));
2663 error = EPROTO;
2664 goto out;
2665 }
2666
2667 if (sizep)
2668 *sizep = getextattr_msg->pvnr_datasize;
2669 if (uio)
2670 error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio);
2671
2672 out:
2673 PUFFS_MSG_RELEASE(getextattr);
2674 return error;
2675 }
2676
2677 int
2678 puffs_vnop_setextattr(void *v)
2679 {
2680 struct vop_setextattr_args /* {
2681 struct vnode *a_vp;
2682 int a_attrnamespace;
2683 const char *a_name;
2684 struct uio *a_uio;
2685 kauth_cred_t a_cred;
2686 }; */ *ap = v;
2687 PUFFS_MSG_VARS(vn, setextattr);
2688 struct vnode *vp = ap->a_vp;
2689 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2690 int attrnamespace = ap->a_attrnamespace;
2691 const char *name = ap->a_name;
2692 struct uio *uio = ap->a_uio;
2693 size_t tomove, resid;
2694 int error;
2695
2696 if (uio)
2697 resid = uio->uio_resid;
2698 else
2699 resid = 0;
2700
2701 tomove = PUFFS_TOMOVE(resid, pmp);
2702 if (tomove != resid) {
2703 error = E2BIG;
2704 goto out;
2705 }
2706
2707 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove,
2708 &park_setextattr, (void *)&setextattr_msg, 1);
2709
2710 setextattr_msg->pvnr_attrnamespace = attrnamespace;
2711 strlcpy(setextattr_msg->pvnr_attrname, name,
2712 sizeof(setextattr_msg->pvnr_attrname));
2713 puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred);
2714 setextattr_msg->pvnr_resid = tomove;
2715
2716 if (uio) {
2717 error = uiomove(setextattr_msg->pvnr_data, tomove, uio);
2718 if (error)
2719 goto out;
2720 }
2721
2722 puffs_msg_setinfo(park_setextattr,
2723 PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp));
2724 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error);
2725
2726 error = checkerr(pmp, error, __func__);
2727 if (error)
2728 goto out;
2729
2730 if (setextattr_msg->pvnr_resid != 0)
2731 error = EIO;
2732
2733 out:
2734 PUFFS_MSG_RELEASE(setextattr);
2735
2736 return error;
2737 }
2738
2739 int
2740 puffs_vnop_listextattr(void *v)
2741 {
2742 struct vop_listextattr_args /* {
2743 struct vnode *a_vp;
2744 int a_attrnamespace;
2745 struct uio *a_uio;
2746 size_t *a_size;
2747 kauth_cred_t a_cred;
2748 }; */ *ap = v;
2749 PUFFS_MSG_VARS(vn, listextattr);
2750 struct vnode *vp = ap->a_vp;
2751 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2752 int attrnamespace = ap->a_attrnamespace;
2753 struct uio *uio = ap->a_uio;
2754 size_t *sizep = ap->a_size;
2755 size_t tomove, resid;
2756 int error;
2757
2758 if (uio)
2759 resid = uio->uio_resid;
2760 else
2761 resid = 0;
2762
2763 tomove = PUFFS_TOMOVE(resid, pmp);
2764 if (tomove != resid) {
2765 error = E2BIG;
2766 goto out;
2767 }
2768
2769 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove,
2770 &park_listextattr, (void *)&listextattr_msg, 1);
2771
2772 listextattr_msg->pvnr_attrnamespace = attrnamespace;
2773 puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred);
2774 listextattr_msg->pvnr_resid = tomove;
2775 if (sizep)
2776 listextattr_msg->pvnr_datasize = 1;
2777
2778 puffs_msg_setinfo(park_listextattr,
2779 PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp));
2780 puffs_msg_setdelta(park_listextattr, tomove);
2781 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error);
2782
2783 error = checkerr(pmp, error, __func__);
2784 if (error)
2785 goto out;
2786
2787 resid = listextattr_msg->pvnr_resid;
2788 if (resid > tomove) {
2789 puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG,
2790 "resid grew", VPTOPNC(vp));
2791 error = EPROTO;
2792 goto out;
2793 }
2794
2795 if (sizep)
2796 *sizep = listextattr_msg->pvnr_datasize;
2797 if (uio)
2798 error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio);
2799
2800 out:
2801 PUFFS_MSG_RELEASE(listextattr);
2802 return error;
2803 }
2804
2805 int
2806 puffs_vnop_deleteextattr(void *v)
2807 {
2808 struct vop_deleteextattr_args /* {
2809 struct vnode *a_vp;
2810 int a_attrnamespace;
2811 const char *a_name;
2812 kauth_cred_t a_cred;
2813 }; */ *ap = v;
2814 PUFFS_MSG_VARS(vn, deleteextattr);
2815 struct vnode *vp = ap->a_vp;
2816 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2817 int attrnamespace = ap->a_attrnamespace;
2818 const char *name = ap->a_name;
2819 int error;
2820
2821 PUFFS_MSG_ALLOC(vn, deleteextattr);
2822 deleteextattr_msg->pvnr_attrnamespace = attrnamespace;
2823 strlcpy(deleteextattr_msg->pvnr_attrname, name,
2824 sizeof(deleteextattr_msg->pvnr_attrname));
2825 puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred);
2826
2827 puffs_msg_setinfo(park_deleteextattr,
2828 PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp));
2829 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr,
2830 vp->v_data, NULL, error);
2831
2832 error = checkerr(pmp, error, __func__);
2833
2834 PUFFS_MSG_RELEASE(deleteextattr);
2835 return error;
2836 }
2837
2838 /*
2839 * spec & fifo. These call the miscfs spec and fifo vectors, but issue
2840 * FAF update information for the puffs node first.
2841 */
2842 int
2843 puffs_vnop_spec_read(void *v)
2844 {
2845 struct vop_read_args /* {
2846 const struct vnodeop_desc *a_desc;
2847 struct vnode *a_vp;
2848 struct uio *a_uio;
2849 int a_ioflag;
2850 kauth_cred_t a_cred;
2851 } */ *ap = v;
2852
2853 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
2854 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
2855 }
2856
2857 int
2858 puffs_vnop_spec_write(void *v)
2859 {
2860 struct vop_write_args /* {
2861 const struct vnodeop_desc *a_desc;
2862 struct vnode *a_vp;
2863 struct uio *a_uio;
2864 int a_ioflag;
2865 kauth_cred_t a_cred;
2866 } */ *ap = v;
2867
2868 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
2869 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
2870 }
2871
2872 int
2873 puffs_vnop_fifo_read(void *v)
2874 {
2875 struct vop_read_args /* {
2876 const struct vnodeop_desc *a_desc;
2877 struct vnode *a_vp;
2878 struct uio *a_uio;
2879 int a_ioflag;
2880 kauth_cred_t a_cred;
2881 } */ *ap = v;
2882
2883 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
2884 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
2885 }
2886
2887 int
2888 puffs_vnop_fifo_write(void *v)
2889 {
2890 struct vop_write_args /* {
2891 const struct vnodeop_desc *a_desc;
2892 struct vnode *a_vp;
2893 struct uio *a_uio;
2894 int a_ioflag;
2895 kauth_cred_t a_cred;
2896 } */ *ap = v;
2897
2898 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
2899 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
2900 }
2901