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