puffs_vnops.c revision 1.106 1 /* $NetBSD: puffs_vnops.c,v 1.106 2007/10/11 12:31:45 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.106 2007/10/11 12:31:45 pooka Exp $");
34
35 #include <sys/param.h>
36 #include <sys/fstrans.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_lookup(void *);
53 int puffs_create(void *);
54 int puffs_access(void *);
55 int puffs_mknod(void *);
56 int puffs_open(void *);
57 int puffs_close(void *);
58 int puffs_getattr(void *);
59 int puffs_setattr(void *);
60 int puffs_reclaim(void *);
61 int puffs_readdir(void *);
62 int puffs_poll(void *);
63 int puffs_fsync(void *);
64 int puffs_seek(void *);
65 int puffs_remove(void *);
66 int puffs_mkdir(void *);
67 int puffs_rmdir(void *);
68 int puffs_link(void *);
69 int puffs_readlink(void *);
70 int puffs_symlink(void *);
71 int puffs_rename(void *);
72 int puffs_read(void *);
73 int puffs_write(void *);
74 int puffs_fcntl(void *);
75 int puffs_ioctl(void *);
76 int puffs_inactive(void *);
77 int puffs_print(void *);
78 int puffs_pathconf(void *);
79 int puffs_advlock(void *);
80 int puffs_strategy(void *);
81 int puffs_bmap(void *);
82 int puffs_mmap(void *);
83 int puffs_getpages(void *);
84
85 int puffs_spec_read(void *);
86 int puffs_spec_write(void *);
87 int puffs_fifo_read(void *);
88 int puffs_fifo_write(void *);
89
90 int puffs_checkop(void *);
91
92
93 /* VOP_LEASE() not included */
94
95 int puffs_generic(void *);
96
97 #if 0
98 #define puffs_lock genfs_lock
99 #define puffs_unlock genfs_unlock
100 #define puffs_islocked genfs_islocked
101 #else
102 int puffs_lock(void *);
103 int puffs_unlock(void *);
104 int puffs_islocked(void *);
105 #endif
106
107 int (**puffs_vnodeop_p)(void *);
108 const struct vnodeopv_entry_desc puffs_vnodeop_entries[] = {
109 { &vop_default_desc, vn_default_error },
110 { &vop_lookup_desc, puffs_lookup }, /* REAL lookup */
111 { &vop_create_desc, puffs_checkop }, /* create */
112 { &vop_mknod_desc, puffs_checkop }, /* mknod */
113 { &vop_open_desc, puffs_open }, /* REAL open */
114 { &vop_close_desc, puffs_checkop }, /* close */
115 { &vop_access_desc, puffs_access }, /* REAL access */
116 { &vop_getattr_desc, puffs_checkop }, /* getattr */
117 { &vop_setattr_desc, puffs_checkop }, /* setattr */
118 { &vop_read_desc, puffs_checkop }, /* read */
119 { &vop_write_desc, puffs_checkop }, /* write */
120 { &vop_fsync_desc, puffs_fsync }, /* REAL fsync */
121 { &vop_seek_desc, puffs_checkop }, /* seek */
122 { &vop_remove_desc, puffs_checkop }, /* remove */
123 { &vop_link_desc, puffs_checkop }, /* link */
124 { &vop_rename_desc, puffs_checkop }, /* rename */
125 { &vop_mkdir_desc, puffs_checkop }, /* mkdir */
126 { &vop_rmdir_desc, puffs_checkop }, /* rmdir */
127 { &vop_symlink_desc, puffs_checkop }, /* symlink */
128 { &vop_readdir_desc, puffs_checkop }, /* readdir */
129 { &vop_readlink_desc, puffs_checkop }, /* readlink */
130 { &vop_getpages_desc, puffs_checkop }, /* getpages */
131 { &vop_putpages_desc, genfs_putpages }, /* REAL putpages */
132 { &vop_pathconf_desc, puffs_checkop }, /* pathconf */
133 { &vop_advlock_desc, puffs_checkop }, /* advlock */
134 { &vop_strategy_desc, puffs_strategy }, /* REAL strategy */
135 { &vop_revoke_desc, genfs_revoke }, /* REAL revoke */
136 { &vop_abortop_desc, genfs_abortop }, /* REAL abortop */
137 { &vop_inactive_desc, puffs_inactive }, /* REAL inactive */
138 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
139 { &vop_lock_desc, puffs_lock }, /* REAL lock */
140 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
141 { &vop_bmap_desc, puffs_bmap }, /* REAL bmap */
142 { &vop_print_desc, puffs_print }, /* REAL print */
143 { &vop_islocked_desc, puffs_islocked }, /* REAL islocked */
144 { &vop_bwrite_desc, genfs_nullop }, /* REAL bwrite */
145 { &vop_mmap_desc, puffs_mmap }, /* REAL mmap */
146 { &vop_poll_desc, puffs_poll }, /* REAL poll */
147
148 { &vop_kqfilter_desc, genfs_eopnotsupp }, /* kqfilter XXX */
149 { NULL, NULL }
150 };
151 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
152 { &puffs_vnodeop_p, puffs_vnodeop_entries };
153
154
155 int (**puffs_specop_p)(void *);
156 const struct vnodeopv_entry_desc puffs_specop_entries[] = {
157 { &vop_default_desc, vn_default_error },
158 { &vop_lookup_desc, spec_lookup }, /* lookup, ENOTDIR */
159 { &vop_create_desc, spec_create }, /* genfs_badop */
160 { &vop_mknod_desc, spec_mknod }, /* genfs_badop */
161 { &vop_open_desc, spec_open }, /* spec_open */
162 { &vop_close_desc, spec_close }, /* spec_close */
163 { &vop_access_desc, puffs_checkop }, /* access */
164 { &vop_getattr_desc, puffs_checkop }, /* getattr */
165 { &vop_setattr_desc, puffs_checkop }, /* setattr */
166 { &vop_read_desc, puffs_spec_read }, /* update, read */
167 { &vop_write_desc, puffs_spec_write }, /* update, write */
168 { &vop_lease_desc, spec_lease_check }, /* genfs_nullop */
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_inactive }, /* REAL inactive */
187 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
188 { &vop_lock_desc, puffs_lock }, /* REAL lock */
189 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
190 { &vop_bmap_desc, spec_bmap }, /* dummy */
191 { &vop_strategy_desc, spec_strategy }, /* dev strategy */
192 { &vop_print_desc, puffs_print }, /* REAL print */
193 { &vop_islocked_desc, puffs_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 #if 0
200 { &vop_openextattr_desc, _openextattr }, /* openextattr */
201 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
202 { &vop_getextattr_desc, _getextattr }, /* getextattr */
203 { &vop_setextattr_desc, _setextattr }, /* setextattr */
204 { &vop_listextattr_desc, _listextattr }, /* listextattr */
205 { &vop_deleteextattr_desc, _deleteextattr }, /* deleteextattr */
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, fifo_lookup }, /* lookup, ENOTDIR */
217 { &vop_create_desc, fifo_create }, /* genfs_badop */
218 { &vop_mknod_desc, fifo_mknod }, /* genfs_badop */
219 { &vop_open_desc, fifo_open }, /* open */
220 { &vop_close_desc, fifo_close }, /* close */
221 { &vop_access_desc, puffs_checkop }, /* access */
222 { &vop_getattr_desc, puffs_checkop }, /* getattr */
223 { &vop_setattr_desc, puffs_checkop }, /* setattr */
224 { &vop_read_desc, puffs_fifo_read }, /* read, update */
225 { &vop_write_desc, puffs_fifo_write }, /* write, update */
226 { &vop_lease_desc, fifo_lease_check }, /* genfs_nullop */
227 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
228 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
229 { &vop_poll_desc, fifo_poll }, /* poll */
230 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
231 { &vop_revoke_desc, fifo_revoke }, /* genfs_revoke */
232 { &vop_mmap_desc, fifo_mmap }, /* genfs_badop */
233 { &vop_fsync_desc, fifo_fsync }, /* genfs_nullop*/
234 { &vop_seek_desc, fifo_seek }, /* genfs_badop */
235 { &vop_remove_desc, fifo_remove }, /* genfs_badop */
236 { &vop_link_desc, fifo_link }, /* genfs_badop */
237 { &vop_rename_desc, fifo_rename }, /* genfs_badop */
238 { &vop_mkdir_desc, fifo_mkdir }, /* genfs_badop */
239 { &vop_rmdir_desc, fifo_rmdir }, /* genfs_badop */
240 { &vop_symlink_desc, fifo_symlink }, /* genfs_badop */
241 { &vop_readdir_desc, fifo_readdir }, /* genfs_badop */
242 { &vop_readlink_desc, fifo_readlink }, /* genfs_badop */
243 { &vop_abortop_desc, fifo_abortop }, /* genfs_badop */
244 { &vop_inactive_desc, puffs_inactive }, /* REAL inactive */
245 { &vop_reclaim_desc, puffs_reclaim }, /* REAL reclaim */
246 { &vop_lock_desc, puffs_lock }, /* REAL lock */
247 { &vop_unlock_desc, puffs_unlock }, /* REAL unlock */
248 { &vop_bmap_desc, fifo_bmap }, /* dummy */
249 { &vop_strategy_desc, fifo_strategy }, /* genfs_badop */
250 { &vop_print_desc, puffs_print }, /* REAL print */
251 { &vop_islocked_desc, puffs_islocked }, /* REAL islocked */
252 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
253 { &vop_advlock_desc, fifo_advlock }, /* genfs_einval */
254 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
255 { &vop_putpages_desc, fifo_putpages }, /* genfs_null_putpages*/
256 #if 0
257 { &vop_openextattr_desc, _openextattr }, /* openextattr */
258 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
259 { &vop_getextattr_desc, _getextattr }, /* getextattr */
260 { &vop_setextattr_desc, _setextattr }, /* setextattr */
261 { &vop_listextattr_desc, _listextattr }, /* listextattr */
262 { &vop_deleteextattr_desc, _deleteextattr }, /* deleteextattr */
263 #endif
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_create }, /* create */
275 { &vop_mknod_desc, puffs_mknod }, /* mknod */
276 { &vop_open_desc, puffs_open }, /* open */
277 { &vop_close_desc, puffs_close }, /* close */
278 { &vop_access_desc, puffs_access }, /* access */
279 { &vop_getattr_desc, puffs_getattr }, /* getattr */
280 { &vop_setattr_desc, puffs_setattr }, /* setattr */
281 { &vop_read_desc, puffs_read }, /* read */
282 { &vop_write_desc, puffs_write }, /* write */
283 { &vop_seek_desc, puffs_seek }, /* seek */
284 { &vop_remove_desc, puffs_remove }, /* remove */
285 { &vop_link_desc, puffs_link }, /* link */
286 { &vop_rename_desc, puffs_rename }, /* rename */
287 { &vop_mkdir_desc, puffs_mkdir }, /* mkdir */
288 { &vop_rmdir_desc, puffs_rmdir }, /* rmdir */
289 { &vop_symlink_desc, puffs_symlink }, /* symlink */
290 { &vop_readdir_desc, puffs_readdir }, /* readdir */
291 { &vop_readlink_desc, puffs_readlink }, /* readlink */
292 { &vop_print_desc, puffs_print }, /* print */
293 { &vop_islocked_desc, puffs_islocked }, /* islocked */
294 { &vop_pathconf_desc, puffs_pathconf }, /* pathconf */
295 { &vop_advlock_desc, puffs_advlock }, /* advlock */
296 { &vop_getpages_desc, puffs_getpages }, /* getpages */
297 { NULL, NULL }
298 };
299 const struct vnodeopv_desc puffs_msgop_opv_desc =
300 { &puffs_msgop_p, puffs_msgop_entries };
301
302
303 #define ERROUT(err) \
304 do { \
305 error = err; \
306 goto out; \
307 } while (/*CONSTCOND*/0)
308
309 /*
310 * This is a generic vnode operation handler. It checks if the necessary
311 * operations for the called vnode operation are implemented by userspace
312 * and either returns a dummy return value or proceeds to call the real
313 * vnode operation from puffs_msgop_v.
314 *
315 * XXX: this should described elsewhere and autogenerated, the complexity
316 * of the vnode operations vectors and their interrelationships is also
317 * getting a bit out of hand. Another problem is that we need this same
318 * information in the fs server code, so keeping the two in sync manually
319 * is not a viable (long term) plan.
320 */
321
322 /* not supported, handle locking protocol */
323 #define CHECKOP_NOTSUPP(op) \
324 case VOP_##op##_DESCOFFSET: \
325 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
326 return genfs_eopnotsupp(v); \
327 break
328
329 /* always succeed, no locking */
330 #define CHECKOP_SUCCESS(op) \
331 case VOP_##op##_DESCOFFSET: \
332 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
333 return 0; \
334 break
335
336 int
337 puffs_checkop(void *v)
338 {
339 struct vop_generic_args /* {
340 struct vnodeop_desc *a_desc;
341 spooky mystery contents;
342 } */ *ap = v;
343 struct vnodeop_desc *desc = ap->a_desc;
344 struct puffs_mount *pmp;
345 struct vnode *vp;
346 int offset, rv;
347
348 offset = ap->a_desc->vdesc_vp_offsets[0];
349 #ifdef DIAGNOSTIC
350 if (offset == VDESC_NO_OFFSET)
351 panic("puffs_checkop: no vnode, why did you call me?");
352 #endif
353 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
354 pmp = MPTOPUFFSMP(vp->v_mount);
355
356 DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n",
357 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp));
358
359 if (!ALLOPS(pmp)) {
360 switch (desc->vdesc_offset) {
361 CHECKOP_NOTSUPP(CREATE);
362 CHECKOP_NOTSUPP(MKNOD);
363 CHECKOP_NOTSUPP(GETATTR);
364 CHECKOP_NOTSUPP(SETATTR);
365 CHECKOP_NOTSUPP(READ);
366 CHECKOP_NOTSUPP(WRITE);
367 CHECKOP_NOTSUPP(FCNTL);
368 CHECKOP_NOTSUPP(IOCTL);
369 CHECKOP_NOTSUPP(REMOVE);
370 CHECKOP_NOTSUPP(LINK);
371 CHECKOP_NOTSUPP(RENAME);
372 CHECKOP_NOTSUPP(MKDIR);
373 CHECKOP_NOTSUPP(RMDIR);
374 CHECKOP_NOTSUPP(SYMLINK);
375 CHECKOP_NOTSUPP(READDIR);
376 CHECKOP_NOTSUPP(READLINK);
377 CHECKOP_NOTSUPP(PRINT);
378 CHECKOP_NOTSUPP(PATHCONF);
379 CHECKOP_NOTSUPP(ADVLOCK);
380
381 CHECKOP_SUCCESS(ACCESS);
382 CHECKOP_SUCCESS(CLOSE);
383 CHECKOP_SUCCESS(SEEK);
384
385 case VOP_GETPAGES_DESCOFFSET:
386 if (!EXISTSOP(pmp, READ))
387 return genfs_eopnotsupp(v);
388 break;
389
390 default:
391 panic("puffs_checkop: unhandled vnop %d",
392 desc->vdesc_offset);
393 }
394 }
395
396 rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v);
397
398 DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n",
399 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv));
400
401 return rv;
402 }
403
404 static int puffs_callremove(struct puffs_mount *, void *, void *,
405 struct componentname *);
406 static int puffs_callrmdir(struct puffs_mount *, void *, void *,
407 struct componentname *);
408 static void puffs_callinactive(struct puffs_mount *, void *, int, struct lwp *);
409 static void puffs_callreclaim(struct puffs_mount *, void *, struct lwp *);
410
411 #define PUFFS_ABORT_LOOKUP 1
412 #define PUFFS_ABORT_CREATE 2
413 #define PUFFS_ABORT_MKNOD 3
414 #define PUFFS_ABORT_MKDIR 4
415 #define PUFFS_ABORT_SYMLINK 5
416
417 /*
418 * Press the pani^Wabort button! Kernel resource allocation failed.
419 */
420 static void
421 puffs_abortbutton(struct puffs_mount *pmp, int what,
422 void *dcookie, void *cookie, struct componentname *cnp)
423 {
424
425 switch (what) {
426 case PUFFS_ABORT_CREATE:
427 case PUFFS_ABORT_MKNOD:
428 case PUFFS_ABORT_SYMLINK:
429 puffs_callremove(pmp, dcookie, cookie, cnp);
430 break;
431 case PUFFS_ABORT_MKDIR:
432 puffs_callrmdir(pmp, dcookie, cookie, cnp);
433 break;
434 }
435
436 puffs_callinactive(pmp, cookie, 0, cnp->cn_lwp);
437 puffs_callreclaim(pmp, cookie, cnp->cn_lwp);
438 }
439
440 int
441 puffs_lookup(void *v)
442 {
443 struct vop_lookup_args /* {
444 const struct vnodeop_desc *a_desc;
445 struct vnode *a_dvp;
446 struct vnode **a_vpp;
447 struct componentname *a_cnp;
448 } */ *ap = v;
449 struct puffs_mount *pmp;
450 struct componentname *cnp;
451 struct vnode *vp, *dvp;
452 struct puffs_node *dpn;
453 int isdot;
454 int error;
455
456 PUFFS_VNREQ(lookup);
457
458 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
459 cnp = ap->a_cnp;
460 dvp = ap->a_dvp;
461 *ap->a_vpp = NULL;
462
463 /* r/o fs? we check create later to handle EEXIST */
464 if ((cnp->cn_flags & ISLASTCN)
465 && (dvp->v_mount->mnt_flag & MNT_RDONLY)
466 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
467 return EROFS;
468
469 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
470
471 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
472 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
473
474 /*
475 * Check if someone fed it into the cache
476 */
477 if (PUFFS_USE_NAMECACHE(pmp)) {
478 error = cache_lookup(dvp, ap->a_vpp, cnp);
479
480 if (error >= 0)
481 return error;
482 }
483
484 if (isdot) {
485 vp = ap->a_dvp;
486 vref(vp);
487 *ap->a_vpp = vp;
488 return 0;
489 }
490
491 puffs_makecn(&lookup_arg.pvnr_cn, &lookup_arg.pvnr_cn_cred,
492 &lookup_arg.pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
493
494 if (cnp->cn_flags & ISDOTDOT)
495 VOP_UNLOCK(dvp, 0);
496
497 error = puffs_vntouser(pmp, PUFFS_VN_LOOKUP,
498 &lookup_arg, sizeof(lookup_arg), 0, dvp, NULL);
499 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
500
501 /*
502 * In case of error, there is no new vnode to play with, so be
503 * happy with the NULL value given to vpp in the beginning.
504 * Also, check if this really was an error or the target was not
505 * present. Either treat it as a non-error for CREATE/RENAME or
506 * enter the component into the negative name cache (if desired).
507 */
508 if (error) {
509 error = checkerr(pmp, error, __func__);
510 if (error == ENOENT) {
511 /* don't allow to create files on r/o fs */
512 if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
513 && cnp->cn_nameiop == CREATE) {
514 error = EROFS;
515
516 /* adjust values if we are creating */
517 } else if ((cnp->cn_flags & ISLASTCN)
518 && (cnp->cn_nameiop == CREATE
519 || cnp->cn_nameiop == RENAME)) {
520 cnp->cn_flags |= SAVENAME;
521 error = EJUSTRETURN;
522
523 /* save negative cache entry */
524 } else {
525 if ((cnp->cn_flags & MAKEENTRY)
526 && PUFFS_USE_NAMECACHE(pmp))
527 cache_enter(dvp, NULL, cnp);
528 }
529 }
530 goto out;
531 }
532
533 /*
534 * Check that we don't get our parent node back, that would cause
535 * a pretty obvious deadlock.
536 */
537 dpn = dvp->v_data;
538 if (lookup_arg.pvnr_newnode == dpn->pn_cookie) {
539 puffs_errnotify(pmp, PUFFS_ERR_LOOKUP, EINVAL,
540 "lookup produced parent cookie", lookup_arg.pvnr_newnode);
541 error = EPROTO;
542 goto out;
543 }
544
545 error = puffs_cookie2vnode(pmp, lookup_arg.pvnr_newnode, 1, 1, &vp);
546 if (error == PUFFS_NOSUCHCOOKIE) {
547 error = puffs_getvnode(dvp->v_mount,
548 lookup_arg.pvnr_newnode, lookup_arg.pvnr_vtype,
549 lookup_arg.pvnr_size, lookup_arg.pvnr_rdev, &vp);
550 if (error) {
551 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
552 lookup_arg.pvnr_newnode, ap->a_cnp);
553 goto out;
554 }
555 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
556 } else if (error) {
557 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
558 lookup_arg.pvnr_newnode, ap->a_cnp);
559 goto out;
560 }
561
562 *ap->a_vpp = vp;
563
564 if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp))
565 cache_enter(dvp, vp, cnp);
566
567 /* XXX */
568 if ((lookup_arg.pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
569 cnp->cn_flags &= ~REQUIREDIR;
570 if (lookup_arg.pvnr_cn.pkcn_consume)
571 cnp->cn_consume = MIN(lookup_arg.pvnr_cn.pkcn_consume,
572 strlen(cnp->cn_nameptr) - cnp->cn_namelen);
573
574 out:
575 if (cnp->cn_flags & ISDOTDOT)
576 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
577
578 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
579 return error;
580 }
581
582 int
583 puffs_create(void *v)
584 {
585 struct vop_create_args /* {
586 const struct vnodeop_desc *a_desc;
587 struct vnode *a_dvp;
588 struct vnode **a_vpp;
589 struct componentname *a_cnp;
590 struct vattr *a_vap;
591 } */ *ap = v;
592 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
593 int error;
594
595 PUFFS_VNREQ(create);
596
597 DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
598 ap->a_dvp, ap->a_cnp->cn_nameptr));
599
600 puffs_makecn(&create_arg.pvnr_cn, &create_arg.pvnr_cn_cred,
601 &create_arg.pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
602 create_arg.pvnr_va = *ap->a_vap;
603
604 error = puffs_vntouser(pmp, PUFFS_VN_CREATE,
605 &create_arg, sizeof(create_arg), 0, ap->a_dvp, NULL);
606 error = checkerr(pmp, error, __func__);
607 if (error)
608 goto out;
609
610 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
611 create_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type, 0);
612 if (error)
613 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, VPTOPNC(ap->a_dvp),
614 create_arg.pvnr_newnode, ap->a_cnp);
615
616 out:
617 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
618 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
619 vput(ap->a_dvp);
620
621 DPRINTF(("puffs_create: return %d\n", error));
622 return error;
623 }
624
625 int
626 puffs_mknod(void *v)
627 {
628 struct vop_mknod_args /* {
629 const struct vnodeop_desc *a_desc;
630 struct vnode *a_dvp;
631 struct vnode **a_vpp;
632 struct componentname *a_cnp;
633 struct vattr *a_vap;
634 } */ *ap = v;
635 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
636 int error;
637
638 PUFFS_VNREQ(mknod);
639
640 puffs_makecn(&mknod_arg.pvnr_cn, &mknod_arg.pvnr_cn_cred,
641 &mknod_arg.pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
642 mknod_arg.pvnr_va = *ap->a_vap;
643
644 error = puffs_vntouser(pmp, PUFFS_VN_MKNOD,
645 &mknod_arg, sizeof(mknod_arg), 0, ap->a_dvp, NULL);
646 error = checkerr(pmp, error, __func__);
647 if (error)
648 goto out;
649
650 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
651 mknod_arg.pvnr_newnode, ap->a_cnp, ap->a_vap->va_type,
652 ap->a_vap->va_rdev);
653 if (error)
654 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, VPTOPNC(ap->a_dvp),
655 mknod_arg.pvnr_newnode, ap->a_cnp);
656
657 out:
658 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
659 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
660 vput(ap->a_dvp);
661 return error;
662 }
663
664 int
665 puffs_open(void *v)
666 {
667 struct vop_open_args /* {
668 const struct vnodeop_desc *a_desc;
669 struct vnode *a_vp;
670 int a_mode;
671 kauth_cred_t a_cred;
672 struct lwp *a_l;
673 } */ *ap = v;
674 struct vnode *vp = ap->a_vp;
675 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
676 int mode = ap->a_mode;
677 int error;
678
679 PUFFS_VNREQ(open);
680 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
681
682 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
683 ERROUT(EROFS);
684
685 if (!EXISTSOP(pmp, OPEN))
686 ERROUT(0);
687
688 open_arg.pvnr_mode = mode;
689 puffs_credcvt(&open_arg.pvnr_cred, ap->a_cred);
690 puffs_cidcvt(&open_arg.pvnr_cid, ap->a_l);
691
692 error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_OPEN,
693 &open_arg, sizeof(open_arg), 0, vp, NULL);
694 error = checkerr(pmp, error, __func__);
695
696 out:
697 DPRINTF(("puffs_open: returning %d\n", error));
698 return error;
699 }
700
701 int
702 puffs_close(void *v)
703 {
704 struct vop_close_args /* {
705 const struct vnodeop_desc *a_desc;
706 struct vnode *a_vp;
707 int a_fflag;
708 kauth_cred_t a_cred;
709 struct lwp *a_l;
710 } */ *ap = v;
711 struct puffs_vnreq_close *close_argp;
712
713 close_argp = malloc(sizeof(struct puffs_vnreq_close),
714 M_PUFFS, M_WAITOK | M_ZERO);
715 close_argp->pvnr_fflag = ap->a_fflag;
716 puffs_credcvt(&close_argp->pvnr_cred, ap->a_cred);
717 puffs_cidcvt(&close_argp->pvnr_cid, ap->a_l);
718
719 puffs_vntouser_faf(MPTOPUFFSMP(ap->a_vp->v_mount), PUFFS_VN_CLOSE,
720 close_argp, sizeof(struct puffs_vnreq_close), ap->a_vp);
721
722 return 0;
723 }
724
725 int
726 puffs_access(void *v)
727 {
728 struct vop_access_args /* {
729 const struct vnodeop_desc *a_desc;
730 struct vnode *a_vp;
731 int a_mode;
732 kauth_cred_t a_cred;
733 struct lwp *a_l;
734 } */ *ap = v;
735 struct vnode *vp = ap->a_vp;
736 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
737 int mode = ap->a_mode;
738 int error;
739
740 PUFFS_VNREQ(access);
741
742 if (mode & VWRITE) {
743 switch (vp->v_type) {
744 case VDIR:
745 case VLNK:
746 case VREG:
747 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
748 || !EXISTSOP(pmp, WRITE))
749 return EROFS;
750 break;
751 default:
752 break;
753 }
754 }
755
756 if (!EXISTSOP(pmp, ACCESS))
757 return 0;
758
759 access_arg.pvnr_mode = ap->a_mode;
760 puffs_credcvt(&access_arg.pvnr_cred, ap->a_cred);
761 puffs_cidcvt(&access_arg.pvnr_cid, ap->a_l);
762
763 error = puffs_vntouser(pmp, PUFFS_VN_ACCESS,
764 &access_arg, sizeof(access_arg), 0, vp, NULL);
765 return checkerr(pmp, error, __func__);
766 }
767
768 int
769 puffs_getattr(void *v)
770 {
771 struct vop_getattr_args /* {
772 const struct vnodeop_desc *a_desc;
773 struct vnode *a_vp;
774 struct vattr *a_vap;
775 kauth_cred_t a_cred;
776 struct lwp *a_l;
777 } */ *ap = v;
778 struct puffs_mount *pmp;
779 struct mount *mp;
780 struct vnode *vp;
781 struct vattr *vap, *rvap;
782 struct puffs_node *pn;
783 int error;
784
785 PUFFS_VNREQ(getattr);
786
787 vp = ap->a_vp;
788 mp = vp->v_mount;
789 vap = ap->a_vap;
790 pmp = MPTOPUFFSMP(mp);
791
792 vattr_null(&getattr_arg.pvnr_va);
793 puffs_credcvt(&getattr_arg.pvnr_cred, ap->a_cred);
794 puffs_cidcvt(&getattr_arg.pvnr_cid, ap->a_l);
795
796 error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount), PUFFS_VN_GETATTR,
797 &getattr_arg, sizeof(getattr_arg), 0, vp, NULL);
798 error = checkerr(pmp, error, __func__);
799 if (error)
800 return error;
801
802 rvap = &getattr_arg.pvnr_va;
803 /*
804 * Don't listen to the file server regarding special device
805 * size info, the file server doesn't know anything about them.
806 */
807 if (vp->v_type == VBLK || vp->v_type == VCHR)
808 rvap->va_size = vp->v_size;
809
810 /* Ditto for blocksize (ufs comment: this doesn't belong here) */
811 if (vp->v_type == VBLK)
812 rvap->va_blocksize = BLKDEV_IOSIZE;
813 else if (vp->v_type == VCHR)
814 rvap->va_blocksize = MAXBSIZE;
815
816 (void) memcpy(vap, rvap, sizeof(struct vattr));
817 vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
818
819 pn = VPTOPP(vp);
820 if (pn->pn_stat & PNODE_METACACHE_ATIME)
821 vap->va_atime = pn->pn_mc_atime;
822 if (pn->pn_stat & PNODE_METACACHE_CTIME)
823 vap->va_ctime = pn->pn_mc_ctime;
824 if (pn->pn_stat & PNODE_METACACHE_MTIME)
825 vap->va_mtime = pn->pn_mc_mtime;
826 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
827 vap->va_size = pn->pn_mc_size;
828 } else {
829 if (rvap->va_size != VNOVAL
830 && vp->v_type != VBLK && vp->v_type != VCHR) {
831 uvm_vnp_setsize(vp, rvap->va_size);
832 pn->pn_serversize = rvap->va_size;
833 }
834 }
835
836 return 0;
837 }
838
839 static int
840 puffs_dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred,
841 struct lwp *l, int chsize)
842 {
843 struct puffs_node *pn = vp->v_data;
844 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
845 int error;
846
847 PUFFS_VNREQ(setattr);
848
849 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
850 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
851 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
852 || vap->va_mode != (mode_t)VNOVAL))
853 return EROFS;
854
855 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
856 && vp->v_type == VREG && vap->va_size != VNOVAL)
857 return EROFS;
858
859 /*
860 * Flush metacache first. If we are called with some explicit
861 * parameters, treat them as information overriding metacache
862 * information.
863 */
864 if (pn->pn_stat & PNODE_METACACHE_MASK) {
865 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
866 && vap->va_atime.tv_sec == VNOVAL)
867 vap->va_atime = pn->pn_mc_atime;
868 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
869 && vap->va_ctime.tv_sec == VNOVAL)
870 vap->va_ctime = pn->pn_mc_ctime;
871 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
872 && vap->va_mtime.tv_sec == VNOVAL)
873 vap->va_mtime = pn->pn_mc_mtime;
874 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
875 && vap->va_size == VNOVAL)
876 vap->va_size = pn->pn_mc_size;
877
878 pn->pn_stat &= ~PNODE_METACACHE_MASK;
879 }
880
881 (void)memcpy(&setattr_arg.pvnr_va, vap, sizeof(struct vattr));
882 puffs_credcvt(&setattr_arg.pvnr_cred, cred);
883 puffs_cidcvt(&setattr_arg.pvnr_cid, l);
884
885 error = puffs_vntouser(pmp, PUFFS_VN_SETATTR,
886 &setattr_arg, sizeof(setattr_arg), 0, vp, NULL);
887 error = checkerr(pmp, error, __func__);
888 if (error)
889 return error;
890
891 if (vap->va_size != VNOVAL) {
892 pn->pn_serversize = vap->va_size;
893 if (chsize)
894 uvm_vnp_setsize(vp, vap->va_size);
895 }
896
897 return 0;
898 }
899
900 int
901 puffs_setattr(void *v)
902 {
903 struct vop_getattr_args /* {
904 const struct vnodeop_desc *a_desc;
905 struct vnode *a_vp;
906 struct vattr *a_vap;
907 kauth_cred_t a_cred;
908 struct lwp *a_l;
909 } */ *ap = v;
910
911 return puffs_dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, ap->a_l, 1);
912 }
913
914 static void
915 puffs_callinactive(struct puffs_mount *pmp, void *cookie, int iaflag,
916 struct lwp *l)
917 {
918 int call;
919
920 PUFFS_VNREQ(inactive);
921
922 puffs_cidcvt(&inactive_arg.pvnr_cid, l);
923
924 if (EXISTSOP(pmp, INACTIVE))
925 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
926 if (iaflag || ALLOPS(pmp))
927 call = 1;
928 else
929 call = 0;
930 else
931 call = 1;
932 else
933 call = 0;
934
935 if (call)
936 puffs_cookietouser(pmp, PUFFS_VN_INACTIVE,
937 &inactive_arg, sizeof(inactive_arg), cookie, 0);
938 }
939
940 int
941 puffs_inactive(void *v)
942 {
943 struct vop_inactive_args /* {
944 const struct vnodeop_desc *a_desc;
945 struct vnode *a_vp;
946 struct lwp *a_l;
947 } */ *ap = v;
948 struct vnode *vp = ap->a_vp;
949 struct puffs_node *pnode;
950
951 pnode = vp->v_data;
952
953 puffs_callinactive(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp),
954 pnode->pn_stat & PNODE_DOINACT, ap->a_l);
955 pnode->pn_stat &= ~PNODE_DOINACT;
956
957 VOP_UNLOCK(ap->a_vp, 0);
958
959 /*
960 * file server thinks it's gone? then don't be afraid care,
961 * node's life was already all it would ever be
962 */
963 if (pnode->pn_stat & PNODE_NOREFS) {
964 pnode->pn_stat |= PNODE_DYING;
965 vrecycle(ap->a_vp, NULL, ap->a_l);
966 }
967
968 return 0;
969 }
970
971 static void
972 puffs_callreclaim(struct puffs_mount *pmp, void *cookie, struct lwp *l)
973 {
974 struct puffs_vnreq_reclaim *reclaim_argp;
975
976 if (!EXISTSOP(pmp, RECLAIM))
977 return;
978
979 reclaim_argp = malloc(sizeof(struct puffs_vnreq_reclaim),
980 M_PUFFS, M_WAITOK | M_ZERO);
981 puffs_cidcvt(&reclaim_argp->pvnr_cid, l);
982
983 puffs_cookietouser(pmp, PUFFS_VN_RECLAIM,
984 reclaim_argp, sizeof(struct puffs_vnreq_reclaim), cookie, 1);
985 }
986
987 /*
988 * always FAF, we don't really care if the server wants to fail to
989 * reclaim the node or not
990 */
991 int
992 puffs_reclaim(void *v)
993 {
994 struct vop_reclaim_args /* {
995 const struct vnodeop_desc *a_desc;
996 struct vnode *a_vp;
997 struct lwp *a_l;
998 } */ *ap = v;
999 struct vnode *vp = ap->a_vp;
1000 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1001
1002 /*
1003 * first things first: check if someone is trying to reclaim the
1004 * root vnode. do not allow that to travel to userspace.
1005 * Note that we don't need to take the lock similarly to
1006 * puffs_root(), since there is only one of us.
1007 */
1008 if (vp->v_vflag & VV_ROOT) {
1009 mutex_enter(&pmp->pmp_lock);
1010 KASSERT(pmp->pmp_root != NULL);
1011 pmp->pmp_root = NULL;
1012 mutex_exit(&pmp->pmp_lock);
1013 goto out;
1014 }
1015
1016 puffs_callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), ap->a_l);
1017
1018 out:
1019 if (PUFFS_USE_NAMECACHE(pmp))
1020 cache_purge(vp);
1021 puffs_putvnode(vp);
1022
1023 return 0;
1024 }
1025
1026 #define CSIZE sizeof(**ap->a_cookies)
1027 int
1028 puffs_readdir(void *v)
1029 {
1030 struct vop_readdir_args /* {
1031 const struct vnodeop_desc *a_desc;
1032 struct vnode *a_vp;
1033 struct uio *a_uio;
1034 kauth_cred_t a_cred;
1035 int *a_eofflag;
1036 off_t **a_cookies;
1037 int *a_ncookies;
1038 } */ *ap = v;
1039 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1040 struct puffs_vnreq_readdir *readdir_argp;
1041 struct vnode *vp = ap->a_vp;
1042 size_t argsize, tomove, cookiemem, cookiesmax;
1043 struct uio *uio = ap->a_uio;
1044 size_t howmuch, resid;
1045 int error;
1046
1047 /*
1048 * ok, so we need: resid + cookiemem = maxreq
1049 * => resid + cookiesize * (resid/minsize) = maxreq
1050 * => resid + cookiesize/minsize * resid = maxreq
1051 * => (cookiesize/minsize + 1) * resid = maxreq
1052 * => resid = maxreq / (cookiesize/minsize + 1)
1053 *
1054 * Since cookiesize <= minsize and we're not very big on floats,
1055 * we approximate that to be 1. Therefore:
1056 *
1057 * resid = maxreq / 2;
1058 *
1059 * Well, at least we didn't have to use differential equations
1060 * or the Gram-Schmidt process.
1061 *
1062 * (yes, I'm very afraid of this)
1063 */
1064 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1065
1066 if (ap->a_cookies) {
1067 KASSERT(ap->a_ncookies != NULL);
1068 if (pmp->pmp_args.pa_fhsize == 0)
1069 return EOPNOTSUPP;
1070 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1071 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1072 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1073 } else {
1074 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1075 cookiesmax = 0;
1076 cookiemem = 0;
1077 }
1078
1079 argsize = sizeof(struct puffs_vnreq_readdir);
1080 tomove = resid + cookiemem;
1081 readdir_argp = malloc(argsize + tomove, M_PUFFS, M_ZERO | M_WAITOK);
1082
1083 puffs_credcvt(&readdir_argp->pvnr_cred, ap->a_cred);
1084 readdir_argp->pvnr_offset = uio->uio_offset;
1085 readdir_argp->pvnr_resid = resid;
1086 readdir_argp->pvnr_ncookies = cookiesmax;
1087 readdir_argp->pvnr_eofflag = 0;
1088 readdir_argp->pvnr_dentoff = cookiemem;
1089
1090 error = puffs_vntouser(pmp, PUFFS_VN_READDIR,
1091 readdir_argp, argsize, tomove, vp, NULL);
1092 error = checkerr(pmp, error, __func__);
1093 if (error)
1094 goto out;
1095
1096 /* userspace is cheating? */
1097 if (readdir_argp->pvnr_resid > resid) {
1098 puffs_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1099 "resid grew", VPTOPNC(vp));
1100 ERROUT(EPROTO);
1101 }
1102 if (readdir_argp->pvnr_ncookies > cookiesmax) {
1103 puffs_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1104 "too many cookies", VPTOPNC(vp));
1105 ERROUT(EPROTO);
1106 }
1107
1108 /* check eof */
1109 if (readdir_argp->pvnr_eofflag)
1110 *ap->a_eofflag = 1;
1111
1112 /* bouncy-wouncy with the directory data */
1113 howmuch = resid - readdir_argp->pvnr_resid;
1114
1115 /* force eof if no data was returned (getcwd() needs this) */
1116 if (howmuch == 0) {
1117 *ap->a_eofflag = 1;
1118 goto out;
1119 }
1120
1121 error = uiomove(readdir_argp->pvnr_data + cookiemem, howmuch, uio);
1122 if (error)
1123 goto out;
1124
1125 /* provide cookies to caller if so desired */
1126 if (ap->a_cookies) {
1127 *ap->a_cookies = malloc(readdir_argp->pvnr_ncookies*CSIZE,
1128 M_TEMP, M_WAITOK);
1129 *ap->a_ncookies = readdir_argp->pvnr_ncookies;
1130 memcpy(*ap->a_cookies, readdir_argp->pvnr_data,
1131 *ap->a_ncookies*CSIZE);
1132 }
1133
1134 /* next readdir starts here */
1135 uio->uio_offset = readdir_argp->pvnr_offset;
1136
1137 out:
1138 free(readdir_argp, M_PUFFS);
1139 return error;
1140 }
1141 #undef CSIZE
1142
1143 /*
1144 * poll works by consuming the bitmask in pn_revents. If there are
1145 * events available, poll returns immediately. If not, it issues a
1146 * poll to userspace, selrecords itself and returns with no available
1147 * events. When the file server returns, it executes puffs_parkdone_poll(),
1148 * where available events are added to the bitmask. selnotify() is
1149 * then also executed by that function causing us to enter here again
1150 * and hopefully find the missing bits (unless someone got them first,
1151 * in which case it starts all over again).
1152 */
1153 int
1154 puffs_poll(void *v)
1155 {
1156 struct vop_poll_args /* {
1157 const struct vnodeop_desc *a_desc;
1158 struct vnode *a_vp;
1159 int a_events;
1160 struct lwp *a_l;
1161 }*/ *ap = v;
1162 struct vnode *vp = ap->a_vp;
1163 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1164 struct puffs_vnreq_poll *poll_argp;
1165 struct puffs_node *pn = vp->v_data;
1166 int events;
1167
1168 if (EXISTSOP(pmp, POLL)) {
1169 mutex_enter(&pn->pn_mtx);
1170 events = pn->pn_revents & ap->a_events;
1171 if (events & ap->a_events) {
1172 pn->pn_revents &= ~ap->a_events;
1173 mutex_exit(&pn->pn_mtx);
1174
1175 return events;
1176 } else {
1177 puffs_referencenode(pn);
1178 mutex_exit(&pn->pn_mtx);
1179
1180 /* freed in puffs_parkdone_poll */
1181 poll_argp = malloc(sizeof(struct puffs_vnreq_poll),
1182 M_PUFFS, M_ZERO | M_WAITOK);
1183
1184 poll_argp->pvnr_events = ap->a_events;
1185 puffs_cidcvt(&poll_argp->pvnr_cid, ap->a_l);
1186
1187 selrecord(ap->a_l, &pn->pn_sel);
1188 puffs_vntouser_call(pmp, PUFFS_VN_POLL,
1189 poll_argp, sizeof(struct puffs_vnreq_poll), 0,
1190 puffs_parkdone_poll, pn,
1191 vp, NULL);
1192
1193 return 0;
1194 }
1195 } else {
1196 return genfs_poll(v);
1197 }
1198 }
1199
1200 int
1201 puffs_fsync(void *v)
1202 {
1203 struct vop_fsync_args /* {
1204 const struct vnodeop_desc *a_desc;
1205 struct vnode *a_vp;
1206 kauth_cred_t a_cred;
1207 int a_flags;
1208 off_t a_offlo;
1209 off_t a_offhi;
1210 struct lwp *a_l;
1211 } */ *ap = v;
1212 struct vattr va;
1213 struct puffs_mount *pmp;
1214 struct puffs_vnreq_fsync *fsync_argp;
1215 struct vnode *vp;
1216 struct puffs_node *pn;
1217 int pflags, error, dofaf;
1218
1219 PUFFS_VNREQ(fsync);
1220
1221 vp = ap->a_vp;
1222 pn = VPTOPP(vp);
1223 pmp = MPTOPUFFSMP(vp->v_mount);
1224
1225 /* flush out information from our metacache, see vop_setattr */
1226 if (pn->pn_stat & PNODE_METACACHE_MASK
1227 && (pn->pn_stat & PNODE_DYING) == 0) {
1228 vattr_null(&va);
1229 error = VOP_SETATTR(vp, &va, FSCRED, NULL);
1230 if (error)
1231 return error;
1232 }
1233
1234 /*
1235 * flush pages to avoid being overly dirty
1236 */
1237 pflags = PGO_CLEANIT;
1238 if (ap->a_flags & FSYNC_WAIT)
1239 pflags |= PGO_SYNCIO;
1240 simple_lock(&vp->v_interlock);
1241 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
1242 round_page(ap->a_offhi), pflags);
1243 if (error)
1244 return error;
1245
1246 /*
1247 * HELLO! We exit already here if the user server does not
1248 * support fsync OR if we should call fsync for a node which
1249 * has references neither in the kernel or the fs server.
1250 * Otherwise we continue to issue fsync() forward.
1251 */
1252 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1253 return 0;
1254
1255 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1256 /*
1257 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1258 * only FAFs for those. Otherwise there's a danger of deadlock,
1259 * since the execution context here might be the user server
1260 * doing some operation on another fs, which in turn caused a
1261 * vnode to be reclaimed from the freelist for this fs.
1262 */
1263 if (dofaf == 0) {
1264 simple_lock(&vp->v_interlock);
1265 if (vp->v_iflag & VI_XLOCK)
1266 dofaf = 1;
1267 simple_unlock(&vp->v_interlock);
1268 }
1269
1270 if (dofaf == 0) {
1271 fsync_argp = &fsync_arg;
1272 } else {
1273 fsync_argp = malloc(sizeof(struct puffs_vnreq_fsync),
1274 M_PUFFS, M_ZERO | M_NOWAIT);
1275 if (fsync_argp == NULL)
1276 return ENOMEM;
1277 }
1278
1279 puffs_credcvt(&fsync_argp->pvnr_cred, ap->a_cred);
1280 fsync_argp->pvnr_flags = ap->a_flags;
1281 fsync_argp->pvnr_offlo = ap->a_offlo;
1282 fsync_argp->pvnr_offhi = ap->a_offhi;
1283 puffs_cidcvt(&fsync_argp->pvnr_cid, ap->a_l);
1284
1285 /*
1286 * XXX: see comment at puffs_getattr about locking
1287 *
1288 * If we are not required to wait, do a FAF operation.
1289 * Otherwise block here.
1290 */
1291 if (dofaf == 0) {
1292 error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount),
1293 PUFFS_VN_FSYNC, fsync_argp, sizeof(*fsync_argp), 0,
1294 vp, NULL);
1295 error = checkerr(pmp, error, __func__);
1296 } else {
1297 /* FAF is always "succesful" */
1298 error = 0;
1299 puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount),
1300 PUFFS_VN_FSYNC, fsync_argp, sizeof(*fsync_argp), vp);
1301 }
1302
1303 return error;
1304 }
1305
1306 int
1307 puffs_seek(void *v)
1308 {
1309 struct vop_seek_args /* {
1310 const struct vnodeop_desc *a_desc;
1311 struct vnode *a_vp;
1312 off_t a_oldoff;
1313 off_t a_newoff;
1314 kauth_cred_t a_cred;
1315 } */ *ap = v;
1316 struct vnode *vp = ap->a_vp;
1317 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1318 int error;
1319
1320 PUFFS_VNREQ(seek);
1321
1322 seek_arg.pvnr_oldoff = ap->a_oldoff;
1323 seek_arg.pvnr_newoff = ap->a_newoff;
1324 puffs_credcvt(&seek_arg.pvnr_cred, ap->a_cred);
1325
1326 /*
1327 * XXX: seems like seek is called with an unlocked vp, but
1328 * it can't hurt to play safe
1329 */
1330 error = puffs_vntouser(pmp, PUFFS_VN_SEEK,
1331 &seek_arg, sizeof(seek_arg), 0, vp, NULL);
1332 return checkerr(pmp, error, __func__);
1333 }
1334
1335 static int
1336 puffs_callremove(struct puffs_mount *pmp, void *dcookie, void *cookie,
1337 struct componentname *cnp)
1338 {
1339 int error;
1340
1341 PUFFS_VNREQ(remove);
1342
1343 remove_arg.pvnr_cookie_targ = cookie;
1344 puffs_makecn(&remove_arg.pvnr_cn, &remove_arg.pvnr_cn_cred,
1345 &remove_arg.pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1346
1347 error = puffs_cookietouser(pmp, PUFFS_VN_REMOVE,
1348 &remove_arg, sizeof(remove_arg), dcookie, 0);
1349 return checkerr(pmp, error, __func__);
1350 }
1351
1352 int
1353 puffs_remove(void *v)
1354 {
1355 struct vop_remove_args /* {
1356 const struct vnodeop_desc *a_desc;
1357 struct vnode *a_dvp;
1358 struct vnode *a_vp;
1359 struct componentname *a_cnp;
1360 } */ *ap = v;
1361 struct vnode *dvp = ap->a_dvp;
1362 struct vnode *vp = ap->a_vp;
1363 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1364 int error;
1365
1366 error = puffs_callremove(pmp, VPTOPNC(dvp), VPTOPNC(vp), ap->a_cnp);
1367
1368 vput(vp);
1369 if (dvp == vp)
1370 vrele(dvp);
1371 else
1372 vput(dvp);
1373
1374 return error;
1375 }
1376
1377 int
1378 puffs_mkdir(void *v)
1379 {
1380 struct vop_mkdir_args /* {
1381 const struct vnodeop_desc *a_desc;
1382 struct vnode *a_dvp;
1383 struct vnode **a_vpp;
1384 struct componentname *a_cnp;
1385 struct vattr *a_vap;
1386 } */ *ap = v;
1387 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
1388 int error;
1389
1390 PUFFS_VNREQ(mkdir);
1391
1392 puffs_makecn(&mkdir_arg.pvnr_cn, &mkdir_arg.pvnr_cn_cred,
1393 &mkdir_arg.pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1394 mkdir_arg.pvnr_va = *ap->a_vap;
1395
1396 error = puffs_vntouser(pmp, PUFFS_VN_MKDIR,
1397 &mkdir_arg, sizeof(mkdir_arg), 0, ap->a_dvp, NULL);
1398 error = checkerr(pmp, error, __func__);
1399 if (error)
1400 goto out;
1401
1402 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
1403 mkdir_arg.pvnr_newnode, ap->a_cnp, VDIR, 0);
1404 if (error)
1405 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, VPTOPNC(ap->a_dvp),
1406 mkdir_arg.pvnr_newnode, ap->a_cnp);
1407
1408 out:
1409 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
1410 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1411 vput(ap->a_dvp);
1412 return error;
1413 }
1414
1415 static int
1416 puffs_callrmdir(struct puffs_mount *pmp, void *dcookie, void *cookie,
1417 struct componentname *cnp)
1418 {
1419 int error;
1420
1421 PUFFS_VNREQ(rmdir);
1422
1423 rmdir_arg.pvnr_cookie_targ = cookie;
1424 puffs_makecn(&rmdir_arg.pvnr_cn, &rmdir_arg.pvnr_cn_cred,
1425 &rmdir_arg.pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1426
1427 error = puffs_cookietouser(pmp, PUFFS_VN_RMDIR,
1428 &rmdir_arg, sizeof(rmdir_arg), dcookie, 0);
1429 return checkerr(pmp, error, __func__);
1430 }
1431
1432 int
1433 puffs_rmdir(void *v)
1434 {
1435 struct vop_rmdir_args /* {
1436 const struct vnodeop_desc *a_desc;
1437 struct vnode *a_dvp;
1438 struct vnode *a_vp;
1439 struct componentname *a_cnp;
1440 } */ *ap = v;
1441 struct vnode *dvp = ap->a_dvp;
1442 struct vnode *vp = ap->a_vp;
1443 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1444 int error;
1445
1446 error = puffs_callrmdir(pmp, VPTOPNC(dvp), VPTOPNC(vp), ap->a_cnp);
1447
1448 /* XXX: some call cache_purge() *for both vnodes* here, investigate */
1449
1450 vput(dvp);
1451 vput(vp);
1452
1453 return error;
1454 }
1455
1456 int
1457 puffs_link(void *v)
1458 {
1459 struct vop_link_args /* {
1460 const struct vnodeop_desc *a_desc;
1461 struct vnode *a_dvp;
1462 struct vnode *a_vp;
1463 struct componentname *a_cnp;
1464 }*/ *ap = v;
1465 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
1466 int error;
1467
1468 PUFFS_VNREQ(link);
1469
1470 link_arg.pvnr_cookie_targ = VPTOPNC(ap->a_vp);
1471 puffs_makecn(&link_arg.pvnr_cn, &link_arg.pvnr_cn_cred,
1472 &link_arg.pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1473
1474 error = puffs_vntouser(pmp, PUFFS_VN_LINK,
1475 &link_arg, sizeof(link_arg), 0, ap->a_dvp, ap->a_vp);
1476 error = checkerr(pmp, error, __func__);
1477
1478 /*
1479 * XXX: stay in touch with the cache. I don't like this, but
1480 * don't have a better solution either. See also puffs_rename().
1481 */
1482 if (error == 0)
1483 puffs_updatenode(ap->a_vp, PUFFS_UPDATECTIME);
1484
1485 vput(ap->a_dvp);
1486
1487 return error;
1488 }
1489
1490 int
1491 puffs_symlink(void *v)
1492 {
1493 struct vop_symlink_args /* {
1494 const struct vnodeop_desc *a_desc;
1495 struct vnode *a_dvp;
1496 struct vnode **a_vpp;
1497 struct componentname *a_cnp;
1498 struct vattr *a_vap;
1499 char *a_target;
1500 }*/ *ap = v;
1501 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
1502 struct puffs_vnreq_symlink *symlink_argp;
1503 int error;
1504
1505 *ap->a_vpp = NULL;
1506
1507 symlink_argp = malloc(sizeof(struct puffs_vnreq_symlink),
1508 M_PUFFS, M_ZERO | M_WAITOK);
1509 puffs_makecn(&symlink_argp->pvnr_cn, &symlink_argp->pvnr_cn_cred,
1510 &symlink_argp->pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1511 symlink_argp->pvnr_va = *ap->a_vap;
1512 (void)strlcpy(symlink_argp->pvnr_link, ap->a_target,
1513 sizeof(symlink_argp->pvnr_link));
1514
1515 error = puffs_vntouser(pmp, PUFFS_VN_SYMLINK,
1516 symlink_argp, sizeof(*symlink_argp), 0, ap->a_dvp, NULL);
1517 error = checkerr(pmp, error, __func__);
1518 if (error)
1519 goto out;
1520
1521 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
1522 symlink_argp->pvnr_newnode, ap->a_cnp, VLNK, 0);
1523 if (error)
1524 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, VPTOPNC(ap->a_dvp),
1525 symlink_argp->pvnr_newnode, ap->a_cnp);
1526
1527 out:
1528 free(symlink_argp, M_PUFFS);
1529 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
1530 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1531 vput(ap->a_dvp);
1532
1533 return error;
1534 }
1535
1536 int
1537 puffs_readlink(void *v)
1538 {
1539 struct vop_readlink_args /* {
1540 const struct vnodeop_desc *a_desc;
1541 struct vnode *a_vp;
1542 struct uio *a_uio;
1543 kauth_cred_t a_cred;
1544 } */ *ap = v;
1545 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1546 size_t linklen;
1547 int error;
1548
1549 PUFFS_VNREQ(readlink);
1550
1551 puffs_credcvt(&readlink_arg.pvnr_cred, ap->a_cred);
1552 linklen = sizeof(readlink_arg.pvnr_link);
1553 readlink_arg.pvnr_linklen = linklen;
1554
1555 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
1556 PUFFS_VN_READLINK, &readlink_arg, sizeof(readlink_arg), 0,
1557 ap->a_vp, NULL);
1558 error = checkerr(pmp, error, __func__);
1559 if (error)
1560 return error;
1561
1562 /* bad bad user file server */
1563 if (readlink_arg.pvnr_linklen > linklen) {
1564 puffs_errnotify(pmp, PUFFS_ERR_READLINK, E2BIG,
1565 "linklen too big", VPTOPNC(ap->a_vp));
1566 return EPROTO;
1567 }
1568
1569 return uiomove(&readlink_arg.pvnr_link, readlink_arg.pvnr_linklen,
1570 ap->a_uio);
1571 }
1572
1573 int
1574 puffs_rename(void *v)
1575 {
1576 struct vop_rename_args /* {
1577 const struct vnodeop_desc *a_desc;
1578 struct vnode *a_fdvp;
1579 struct vnode *a_fvp;
1580 struct componentname *a_fcnp;
1581 struct vnode *a_tdvp;
1582 struct vnode *a_tvp;
1583 struct componentname *a_tcnp;
1584 }*/ *ap = v;
1585 struct puffs_vnreq_rename *rename_argp = NULL;
1586 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_fdvp->v_mount);
1587 int error;
1588
1589 if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount)
1590 ERROUT(EXDEV);
1591
1592 rename_argp = malloc(sizeof(struct puffs_vnreq_rename),
1593 M_PUFFS, M_WAITOK | M_ZERO);
1594
1595 rename_argp->pvnr_cookie_src = VPTOPNC(ap->a_fvp);
1596 rename_argp->pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
1597 if (ap->a_tvp)
1598 rename_argp->pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
1599 else
1600 rename_argp->pvnr_cookie_targ = NULL;
1601 puffs_makecn(&rename_argp->pvnr_cn_src,
1602 &rename_argp->pvnr_cn_src_cred, &rename_argp->pvnr_cn_src_cid,
1603 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
1604 puffs_makecn(&rename_argp->pvnr_cn_targ,
1605 &rename_argp->pvnr_cn_targ_cred, &rename_argp->pvnr_cn_targ_cid,
1606 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
1607
1608 error = puffs_vntouser(pmp, PUFFS_VN_RENAME,
1609 rename_argp, sizeof(*rename_argp), 0, ap->a_fdvp, NULL); /* XXX */
1610 error = checkerr(pmp, error, __func__);
1611
1612 /*
1613 * XXX: stay in touch with the cache. I don't like this, but
1614 * don't have a better solution either. See also puffs_link().
1615 */
1616 if (error == 0)
1617 puffs_updatenode(ap->a_fvp, PUFFS_UPDATECTIME);
1618
1619 out:
1620 if (rename_argp)
1621 free(rename_argp, M_PUFFS);
1622 if (ap->a_tvp != NULL)
1623 vput(ap->a_tvp);
1624 if (ap->a_tdvp == ap->a_tvp)
1625 vrele(ap->a_tdvp);
1626 else
1627 vput(ap->a_tdvp);
1628
1629 vrele(ap->a_fdvp);
1630 vrele(ap->a_fvp);
1631
1632 return error;
1633 }
1634
1635 #define RWARGS(cont, iofl, move, offset, creds) \
1636 (cont)->pvnr_ioflag = (iofl); \
1637 (cont)->pvnr_resid = (move); \
1638 (cont)->pvnr_offset = (offset); \
1639 puffs_credcvt(&(cont)->pvnr_cred, creds)
1640
1641 int
1642 puffs_read(void *v)
1643 {
1644 struct vop_read_args /* {
1645 const struct vnodeop_desc *a_desc;
1646 struct vnode *a_vp;
1647 struct uio *a_uio;
1648 int a_ioflag;
1649 kauth_cred_t a_cred;
1650 } */ *ap = v;
1651 struct puffs_vnreq_read *read_argp;
1652 struct puffs_mount *pmp;
1653 struct vnode *vp;
1654 struct uio *uio;
1655 void *win;
1656 size_t tomove, argsize;
1657 vsize_t bytelen;
1658 int error, ubcflags;
1659
1660 uio = ap->a_uio;
1661 vp = ap->a_vp;
1662 read_argp = NULL;
1663 error = 0;
1664 pmp = MPTOPUFFSMP(vp->v_mount);
1665
1666 /* std sanity */
1667 if (uio->uio_resid == 0)
1668 return 0;
1669 if (uio->uio_offset < 0)
1670 return EINVAL;
1671
1672 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1673 const int advice = IO_ADV_DECODE(ap->a_ioflag);
1674
1675 ubcflags = 0;
1676 if (UBC_WANT_UNMAP(vp))
1677 ubcflags = UBC_UNMAP;
1678
1679 while (uio->uio_resid > 0) {
1680 bytelen = MIN(uio->uio_resid,
1681 vp->v_size - uio->uio_offset);
1682 if (bytelen == 0)
1683 break;
1684
1685 win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
1686 &bytelen, advice, UBC_READ);
1687 error = uiomove(win, bytelen, uio);
1688 ubc_release(win, ubcflags);
1689 if (error)
1690 break;
1691 }
1692
1693 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1694 puffs_updatenode(vp, PUFFS_UPDATEATIME);
1695 } else {
1696 /*
1697 * in case it's not a regular file or we're operating
1698 * uncached, do read in the old-fashioned style,
1699 * i.e. explicit read operations
1700 */
1701
1702 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1703 argsize = sizeof(struct puffs_vnreq_read);
1704 read_argp = malloc(argsize + tomove,
1705 M_PUFFS, M_WAITOK | M_ZERO);
1706
1707 error = 0;
1708 while (uio->uio_resid > 0) {
1709 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1710 RWARGS(read_argp, ap->a_ioflag, tomove,
1711 uio->uio_offset, ap->a_cred);
1712
1713 error = puffs_vntouser(pmp, PUFFS_VN_READ,
1714 read_argp, argsize, tomove,
1715 ap->a_vp, NULL);
1716 error = checkerr(pmp, error, __func__);
1717 if (error)
1718 break;
1719
1720 if (read_argp->pvnr_resid > tomove) {
1721 puffs_errnotify(pmp, PUFFS_ERR_READ,
1722 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1723 error = EPROTO;
1724 break;
1725 }
1726
1727 error = uiomove(read_argp->pvnr_data,
1728 tomove - read_argp->pvnr_resid, uio);
1729
1730 /*
1731 * in case the file is out of juice, resid from
1732 * userspace is != 0. and the error-case is
1733 * quite obvious
1734 */
1735 if (error || read_argp->pvnr_resid)
1736 break;
1737 }
1738 }
1739
1740 if (read_argp)
1741 free(read_argp, M_PUFFS);
1742 return error;
1743 }
1744
1745 /*
1746 * XXX: in case of a failure, this leaves uio in a bad state.
1747 * We could theoretically copy the uio and iovecs and "replay"
1748 * them the right amount after the userspace trip, but don't
1749 * bother for now.
1750 */
1751 int
1752 puffs_write(void *v)
1753 {
1754 struct vop_write_args /* {
1755 const struct vnodeop_desc *a_desc;
1756 struct vnode *a_vp;
1757 struct uio *a_uio;
1758 int a_ioflag;
1759 kauth_cred_t a_cred;
1760 } */ *ap = v;
1761 struct puffs_vnreq_write *write_argp;
1762 struct puffs_mount *pmp;
1763 struct uio *uio;
1764 struct vnode *vp;
1765 size_t tomove, argsize;
1766 off_t oldoff, newoff, origoff;
1767 vsize_t bytelen;
1768 int error, uflags;
1769 int ubcflags;
1770
1771 vp = ap->a_vp;
1772 uio = ap->a_uio;
1773 error = uflags = 0;
1774 write_argp = NULL;
1775 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1776
1777 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1778 ubcflags = UBC_WRITE | UBC_PARTIALOK;
1779 if (UBC_WANT_UNMAP(vp))
1780 ubcflags |= UBC_UNMAP;
1781
1782 /*
1783 * userspace *should* be allowed to control this,
1784 * but with UBC it's a bit unclear how to handle it
1785 */
1786 if (ap->a_ioflag & IO_APPEND)
1787 uio->uio_offset = vp->v_size;
1788
1789 origoff = uio->uio_offset;
1790 while (uio->uio_resid > 0) {
1791 uflags |= PUFFS_UPDATECTIME;
1792 uflags |= PUFFS_UPDATEMTIME;
1793 oldoff = uio->uio_offset;
1794 bytelen = uio->uio_resid;
1795
1796 newoff = oldoff + bytelen;
1797 if (vp->v_size < newoff) {
1798 uvm_vnp_setwritesize(vp, newoff);
1799 }
1800 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
1801 UVM_ADV_RANDOM, ubcflags);
1802
1803 /*
1804 * In case of a ubc_uiomove() error,
1805 * opt to not extend the file at all and
1806 * return an error. Otherwise, if we attempt
1807 * to clear the memory we couldn't fault to,
1808 * we might generate a kernel page fault.
1809 */
1810 if (vp->v_size < newoff) {
1811 if (error == 0) {
1812 uflags |= PUFFS_UPDATESIZE;
1813 uvm_vnp_setsize(vp, newoff);
1814 } else {
1815 uvm_vnp_setwritesize(vp, vp->v_size);
1816 }
1817 }
1818 if (error)
1819 break;
1820
1821 /*
1822 * If we're writing large files, flush to file server
1823 * every 64k. Otherwise we can very easily exhaust
1824 * kernel and user memory, as the file server cannot
1825 * really keep up with our writing speed.
1826 *
1827 * Note: this does *NOT* honor MNT_ASYNC, because
1828 * that gives userland too much say in the kernel.
1829 */
1830 if (oldoff >> 16 != uio->uio_offset >> 16) {
1831 simple_lock(&vp->v_interlock);
1832 error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
1833 uio->uio_offset & ~0xffff,
1834 PGO_CLEANIT | PGO_SYNCIO);
1835 if (error)
1836 break;
1837 }
1838 }
1839
1840 /* synchronous I/O? */
1841 if (error == 0 && ap->a_ioflag & IO_SYNC) {
1842 simple_lock(&vp->v_interlock);
1843 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1844 round_page(uio->uio_offset),
1845 PGO_CLEANIT | PGO_SYNCIO);
1846
1847 /* write through page cache? */
1848 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
1849 simple_lock(&vp->v_interlock);
1850 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1851 round_page(uio->uio_offset), PGO_CLEANIT);
1852 }
1853
1854 puffs_updatenode(vp, uflags);
1855 } else {
1856 /* tomove is non-increasing */
1857 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1858 argsize = sizeof(struct puffs_vnreq_write) + tomove;
1859 write_argp = malloc(argsize, M_PUFFS, M_WAITOK | M_ZERO);
1860
1861 while (uio->uio_resid > 0) {
1862 /* move data to buffer */
1863 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1864 RWARGS(write_argp, ap->a_ioflag, tomove,
1865 uio->uio_offset, ap->a_cred);
1866 error = uiomove(write_argp->pvnr_data, tomove, uio);
1867 if (error)
1868 break;
1869
1870 /* move buffer to userspace */
1871 error = puffs_vntouser(MPTOPUFFSMP(ap->a_vp->v_mount),
1872 PUFFS_VN_WRITE, write_argp, argsize, 0,
1873 ap->a_vp, NULL);
1874 error = checkerr(pmp, error, __func__);
1875 if (error)
1876 break;
1877
1878 if (write_argp->pvnr_resid > tomove) {
1879 puffs_errnotify(pmp, PUFFS_ERR_WRITE,
1880 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1881 error = EPROTO;
1882 break;
1883 }
1884
1885 /* adjust file size */
1886 if (vp->v_size < uio->uio_offset)
1887 uvm_vnp_setsize(vp, uio->uio_offset);
1888
1889 /* didn't move everything? bad userspace. bail */
1890 if (write_argp->pvnr_resid != 0) {
1891 error = EIO;
1892 break;
1893 }
1894 }
1895 }
1896
1897 if (write_argp)
1898 free(write_argp, M_PUFFS);
1899 return error;
1900 }
1901
1902 int
1903 puffs_print(void *v)
1904 {
1905 struct vop_print_args /* {
1906 struct vnode *a_vp;
1907 } */ *ap = v;
1908 struct puffs_mount *pmp;
1909 struct vnode *vp = ap->a_vp;
1910 struct puffs_node *pn = vp->v_data;
1911
1912 PUFFS_VNREQ(print);
1913
1914 pmp = MPTOPUFFSMP(vp->v_mount);
1915
1916 /* kernel portion */
1917 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1918 " userspace cookie: %p\n", vp, pn, pn->pn_cookie);
1919 if (vp->v_type == VFIFO)
1920 fifo_printinfo(vp);
1921 lockmgr_printinfo(&vp->v_lock);
1922
1923 /* userspace portion */
1924 if (EXISTSOP(pmp, PRINT))
1925 puffs_vntouser(pmp, PUFFS_VN_PRINT,
1926 &print_arg, sizeof(print_arg), 0, ap->a_vp, NULL);
1927
1928 return 0;
1929 }
1930
1931 int
1932 puffs_pathconf(void *v)
1933 {
1934 struct vop_pathconf_args /* {
1935 const struct vnodeop_desc *a_desc;
1936 struct vnode *a_vp;
1937 int a_name;
1938 register_t *a_retval;
1939 } */ *ap = v;
1940 struct vnode *vp = ap->a_vp;
1941 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1942 int error;
1943
1944 PUFFS_VNREQ(pathconf);
1945
1946 pathconf_arg.pvnr_name = ap->a_name;
1947
1948 error = puffs_vntouser(pmp, PUFFS_VN_PATHCONF,
1949 &pathconf_arg, sizeof(pathconf_arg), 0, vp, NULL);
1950 error = checkerr(pmp, error, __func__);
1951 if (error)
1952 return error;
1953
1954 *ap->a_retval = pathconf_arg.pvnr_retval;
1955
1956 return 0;
1957 }
1958
1959 int
1960 puffs_advlock(void *v)
1961 {
1962 struct vop_advlock_args /* {
1963 const struct vnodeop_desc *a_desc;
1964 struct vnode *a_vp;
1965 void *a_id;
1966 int a_op;
1967 struct flock *a_fl;
1968 int a_flags;
1969 } */ *ap = v;
1970 struct vnode *vp = ap->a_vp;
1971 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1972 int error;
1973
1974 PUFFS_VNREQ(advlock);
1975
1976 error = copyin(ap->a_fl, &advlock_arg.pvnr_fl, sizeof(struct flock));
1977 if (error)
1978 return error;
1979 advlock_arg.pvnr_id = ap->a_id;
1980 advlock_arg.pvnr_op = ap->a_op;
1981 advlock_arg.pvnr_flags = ap->a_flags;
1982
1983 error = puffs_vntouser(pmp, PUFFS_VN_ADVLOCK,
1984 &advlock_arg, sizeof(advlock_arg), 0, vp, NULL);
1985 return checkerr(pmp, error, __func__);
1986 }
1987
1988 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
1989 #define BIOREAD(bp) (bp->b_flags & B_READ)
1990 #define BIOWRITE(bp) ((bp->b_flags & B_READ) == 0)
1991
1992 /*
1993 * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
1994 */
1995 int
1996 puffs_strategy(void *v)
1997 {
1998 struct vop_strategy_args /* {
1999 const struct vnodeop_desc *a_desc;
2000 struct vnode *a_vp;
2001 struct buf *a_bp;
2002 } */ *ap = v;
2003 struct puffs_mount *pmp;
2004 struct vnode *vp = ap->a_vp;
2005 struct puffs_node *pn;
2006 struct puffs_vnreq_readwrite *rw_argp = NULL;
2007 struct buf *bp;
2008 size_t argsize;
2009 size_t tomove, moved;
2010 int error, dofaf;
2011
2012 pmp = MPTOPUFFSMP(vp->v_mount);
2013 bp = ap->a_bp;
2014 error = 0;
2015 dofaf = 0;
2016 pn = VPTOPP(vp);
2017
2018 if ((BIOREAD(bp) && !EXISTSOP(pmp, READ))
2019 || (BIOWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2020 ERROUT(EOPNOTSUPP);
2021
2022 /*
2023 * Short-circuit optimization: don't flush buffer in between
2024 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2025 */
2026 if (pn->pn_stat & PNODE_DYING) {
2027 KASSERT(BIOWRITE(bp));
2028 bp->b_resid = 0;
2029 goto out;
2030 }
2031
2032 #ifdef DIAGNOSTIC
2033 if (bp->b_bcount > pmp->pmp_req_maxsize - PUFFS_REQSTRUCT_MAX)
2034 panic("puffs_strategy: wildly inappropriate buf bcount %d",
2035 bp->b_bcount);
2036 #endif
2037
2038 /*
2039 * See explanation for the necessity of a FAF in puffs_fsync.
2040 *
2041 * Also, do FAF in case we're suspending.
2042 * See puffs_vfsops.c:pageflush()
2043 */
2044 if (BIOWRITE(bp)) {
2045 simple_lock(&vp->v_interlock);
2046 if (vp->v_iflag & VI_XLOCK)
2047 dofaf = 1;
2048 if (pn->pn_stat & PNODE_SUSPEND)
2049 dofaf = 1;
2050 simple_unlock(&vp->v_interlock);
2051 }
2052
2053 if (BIOASYNC(bp))
2054 dofaf = 1;
2055
2056 #ifdef DIAGNOSTIC
2057 if (curlwp == uvm.pagedaemon_lwp)
2058 KASSERT(dofaf);
2059 #endif
2060
2061 /* allocate transport structure */
2062 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2063 argsize = sizeof(struct puffs_vnreq_readwrite);
2064 rw_argp = malloc(argsize + tomove, M_PUFFS,
2065 M_ZERO | (dofaf ? M_NOWAIT : M_WAITOK));
2066 if (rw_argp == NULL)
2067 ERROUT(ENOMEM);
2068 RWARGS(rw_argp, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2069
2070 /* 2x2 cases: read/write, faf/nofaf */
2071 if (BIOREAD(bp)) {
2072 if (dofaf) {
2073 puffs_vntouser_call(pmp, PUFFS_VN_READ, rw_argp,
2074 argsize, tomove, puffs_parkdone_asyncbioread,
2075 bp, vp, NULL);
2076 } else {
2077 error = puffs_vntouser(pmp, PUFFS_VN_READ,
2078 rw_argp, argsize, tomove, vp, NULL);
2079 error = checkerr(pmp, error, __func__);
2080 if (error)
2081 goto out;
2082
2083 if (rw_argp->pvnr_resid > tomove) {
2084 puffs_errnotify(pmp, PUFFS_ERR_READ,
2085 E2BIG, "resid grew", VPTOPNC(vp));
2086 ERROUT(EPROTO);
2087 }
2088
2089 moved = tomove - rw_argp->pvnr_resid;
2090
2091 (void)memcpy(bp->b_data, rw_argp->pvnr_data, moved);
2092 bp->b_resid = bp->b_bcount - moved;
2093 }
2094 } else {
2095 /*
2096 * make pages read-only before we write them if we want
2097 * write caching info
2098 */
2099 if (PUFFS_WCACHEINFO(pmp)) {
2100 struct uvm_object *uobj = &vp->v_uobj;
2101 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2102 struct vm_page *vmp;
2103 int i;
2104
2105 for (i = 0; i < npages; i++) {
2106 vmp= uvm_pageratop((vaddr_t)bp->b_data
2107 + (i << PAGE_SHIFT));
2108 DPRINTF(("puffs_strategy: write-protecting "
2109 "vp %p page %p, offset %" PRId64"\n",
2110 vp, vmp, vmp->offset));
2111 simple_lock(&uobj->vmobjlock);
2112 vmp->flags |= PG_RDONLY;
2113 pmap_page_protect(vmp, VM_PROT_READ);
2114 simple_unlock(&uobj->vmobjlock);
2115 }
2116 }
2117
2118 (void)memcpy(&rw_argp->pvnr_data, bp->b_data, tomove);
2119 if (dofaf) {
2120 /*
2121 * assume FAF moves everything. frankly, we don't
2122 * really have a choice.
2123 */
2124 puffs_vntouser_faf(MPTOPUFFSMP(vp->v_mount),
2125 PUFFS_VN_WRITE, rw_argp, argsize + tomove, vp);
2126 bp->b_resid = bp->b_bcount - tomove;
2127 } else {
2128 error = puffs_vntouser(MPTOPUFFSMP(vp->v_mount),
2129 PUFFS_VN_WRITE, rw_argp, argsize + tomove,
2130 0, vp, NULL);
2131 error = checkerr(pmp, error, __func__);
2132 if (error)
2133 goto out;
2134
2135 moved = tomove - rw_argp->pvnr_resid;
2136 if (rw_argp->pvnr_resid > tomove) {
2137 puffs_errnotify(pmp, PUFFS_ERR_WRITE,
2138 E2BIG, "resid grew", VPTOPNC(vp));
2139 ERROUT(EPROTO);
2140 }
2141
2142 bp->b_resid = bp->b_bcount - moved;
2143 if (rw_argp->pvnr_resid != 0) {
2144 ERROUT(EIO);
2145 }
2146 }
2147 }
2148
2149 out:
2150 KASSERT(dofaf == 0 || error == 0 || rw_argp == NULL);
2151 if (rw_argp && !dofaf)
2152 free(rw_argp, M_PUFFS);
2153
2154 if (error)
2155 bp->b_error = error;
2156
2157 if (error || !(BIOREAD(bp) && BIOASYNC(bp)))
2158 biodone(bp);
2159
2160 return error;
2161 }
2162
2163 int
2164 puffs_mmap(void *v)
2165 {
2166 struct vop_mmap_args /* {
2167 const struct vnodeop_desc *a_desc;
2168 struct vnode *a_vp;
2169 vm_prot_t a_prot;
2170 kauth_cred_t a_cred;
2171 struct lwp *a_l;
2172 } */ *ap = v;
2173 struct puffs_mount *pmp;
2174 int error;
2175
2176 PUFFS_VNREQ(mmap);
2177
2178 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2179
2180 if (!PUFFS_USE_PAGECACHE(pmp))
2181 return genfs_eopnotsupp(v);
2182
2183 if (EXISTSOP(pmp, MMAP)) {
2184 mmap_arg.pvnr_prot = ap->a_prot;
2185 puffs_credcvt(&mmap_arg.pvnr_cred, ap->a_cred);
2186 puffs_cidcvt(&mmap_arg.pvnr_cid, ap->a_l);
2187
2188 error = puffs_vntouser(pmp, PUFFS_VN_MMAP,
2189 &mmap_arg, sizeof(mmap_arg), 0,
2190 ap->a_vp, NULL);
2191 error = checkerr(pmp, error, __func__);
2192 } else {
2193 error = genfs_mmap(v);
2194 }
2195
2196 return error;
2197 }
2198
2199
2200 /*
2201 * The rest don't get a free trip to userspace and back, they
2202 * have to stay within the kernel.
2203 */
2204
2205 /*
2206 * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2207 * well, maybe somehow, somewhere, some day ....
2208 */
2209 int
2210 puffs_bmap(void *v)
2211 {
2212 struct vop_bmap_args /* {
2213 const struct vnodeop_desc *a_desc;
2214 struct vnode *a_vp;
2215 daddr_t a_bn;
2216 struct vnode **a_vpp;
2217 daddr_t *a_bnp;
2218 int *a_runp;
2219 } */ *ap = v;
2220 struct puffs_mount *pmp;
2221
2222 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2223
2224 if (ap->a_vpp)
2225 *ap->a_vpp = ap->a_vp;
2226 if (ap->a_bnp)
2227 *ap->a_bnp = ap->a_bn;
2228 if (ap->a_runp)
2229 *ap->a_runp
2230 = (PUFFS_TOMOVE(pmp->pmp_req_maxsize, pmp)>>DEV_BSHIFT) - 1;
2231
2232 return 0;
2233 }
2234
2235 /*
2236 * Handle getpages faults in puffs. We let genfs_getpages() do most
2237 * of the dirty work, but we come in this route to do accounting tasks.
2238 * If the user server has specified functions for cache notifications
2239 * about reads and/or writes, we record which type of operation we got,
2240 * for which page range, and proceed to issue a FAF notification to the
2241 * server about it.
2242 */
2243 int
2244 puffs_getpages(void *v)
2245 {
2246 struct vop_getpages_args /* {
2247 const struct vnodeop_desc *a_desc;
2248 struct vnode *a_vp;
2249 voff_t a_offset;
2250 struct vm_page **a_m;
2251 int *a_count;
2252 int a_centeridx;
2253 vm_prot_t a_access_type;
2254 int a_advice;
2255 int a_flags;
2256 } */ *ap = v;
2257 struct puffs_mount *pmp;
2258 struct puffs_node *pn;
2259 struct vnode *vp;
2260 struct vm_page **pgs;
2261 struct puffs_cacheinfo *pcinfo = NULL;
2262 struct puffs_cacherun *pcrun;
2263 void *parkmem = NULL;
2264 size_t runsizes;
2265 int i, npages, si, streakon;
2266 int error, locked, write;
2267
2268 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2269 npages = *ap->a_count;
2270 pgs = ap->a_m;
2271 vp = ap->a_vp;
2272 pn = vp->v_data;
2273 locked = (ap->a_flags & PGO_LOCKED) != 0;
2274 write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2275
2276 /* ccg xnaht - gets Wuninitialized wrong */
2277 pcrun = NULL;
2278 runsizes = 0;
2279
2280 /*
2281 * Check that we aren't trying to fault in pages which our file
2282 * server doesn't know about. This happens if we extend a file by
2283 * skipping some pages and later try to fault in pages which
2284 * are between pn_serversize and vp_size. This check optimizes
2285 * away the common case where a file is being extended.
2286 */
2287 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2288 struct vattr va;
2289
2290 /* try again later when we can block */
2291 if (locked)
2292 ERROUT(EBUSY);
2293
2294 simple_unlock(&vp->v_interlock);
2295 vattr_null(&va);
2296 va.va_size = vp->v_size;
2297 error = puffs_dosetattr(vp, &va, FSCRED, NULL, 0);
2298 if (error)
2299 ERROUT(error);
2300 simple_lock(&vp->v_interlock);
2301 }
2302
2303 if (write && PUFFS_WCACHEINFO(pmp)) {
2304 /* allocate worst-case memory */
2305 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2306 pcinfo = malloc(sizeof(struct puffs_cacheinfo) + runsizes,
2307 M_PUFFS, M_ZERO | locked ? M_NOWAIT : M_WAITOK);
2308
2309 /*
2310 * can't block if we're locked and can't mess up caching
2311 * information for fs server. so come back later, please
2312 */
2313 if (pcinfo == NULL)
2314 ERROUT(ENOMEM);
2315
2316 parkmem = puffs_park_alloc(locked == 0);
2317 if (parkmem == NULL)
2318 ERROUT(ENOMEM);
2319
2320 pcrun = pcinfo->pcache_runs;
2321 }
2322
2323 error = genfs_getpages(v);
2324 if (error)
2325 goto out;
2326
2327 if (PUFFS_WCACHEINFO(pmp) == 0)
2328 goto out;
2329
2330 /*
2331 * Let's see whose fault it was and inform the user server of
2332 * possibly read/written pages. Map pages from read faults
2333 * strictly read-only, since otherwise we might miss info on
2334 * when the page is actually write-faulted to.
2335 */
2336 if (!locked)
2337 simple_lock(&vp->v_uobj.vmobjlock);
2338 for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2339 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2340 if (streakon && write) {
2341 streakon = 0;
2342 pcrun[si].pcache_runend
2343 = trunc_page(pgs[i]->offset) + PAGE_MASK;
2344 si++;
2345 }
2346 continue;
2347 }
2348 if (streakon == 0 && write) {
2349 streakon = 1;
2350 pcrun[si].pcache_runstart = pgs[i]->offset;
2351 }
2352
2353 if (!write)
2354 pgs[i]->flags |= PG_RDONLY;
2355 }
2356 /* was the last page part of our streak? */
2357 if (streakon) {
2358 pcrun[si].pcache_runend
2359 = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2360 si++;
2361 }
2362 if (!locked)
2363 simple_unlock(&vp->v_uobj.vmobjlock);
2364
2365 KASSERT(si <= (npages / 2) + 1);
2366
2367 /* send results to userspace */
2368 if (write)
2369 puffs_cacheop(pmp, parkmem, pcinfo,
2370 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2371
2372 out:
2373 if (error) {
2374 if (pcinfo != NULL)
2375 free(pcinfo, M_PUFFS);
2376 if (parkmem != NULL)
2377 puffs_park_release(parkmem, 1);
2378 }
2379
2380 return error;
2381 }
2382
2383 int
2384 puffs_lock(void *v)
2385 {
2386 struct vop_lock_args /* {
2387 struct vnode *a_vp;
2388 int a_flags;
2389 }*/ *ap = v;
2390 struct vnode *vp = ap->a_vp;
2391 struct mount *mp = vp->v_mount;
2392
2393 #if 0
2394 DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
2395 #endif
2396
2397 /*
2398 * XXX: this avoids deadlocking when we're suspending.
2399 * e.g. some ops holding the vnode lock might be blocked for
2400 * the vfs transaction lock so we'd deadlock.
2401 *
2402 * Now once again this is skating on the thin ice of modern life,
2403 * since we are breaking the consistency guarantee provided
2404 * _to the user server_ by vnode locking. Hopefully this will
2405 * get fixed soon enough by getting rid of the dependency on
2406 * vnode locks alltogether.
2407 */
2408 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2409 if (ap->a_flags & LK_INTERLOCK)
2410 simple_unlock(&vp->v_interlock);
2411 return 0;
2412 }
2413
2414 return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
2415 }
2416
2417 int
2418 puffs_unlock(void *v)
2419 {
2420 struct vop_unlock_args /* {
2421 struct vnode *a_vp;
2422 int a_flags;
2423 } */ *ap = v;
2424 struct vnode *vp = ap->a_vp;
2425 struct mount *mp = vp->v_mount;
2426
2427 #if 0
2428 DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
2429 #endif
2430
2431 /* XXX: see puffs_lock() */
2432 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2433 if (ap->a_flags & LK_INTERLOCK)
2434 simple_unlock(&vp->v_interlock);
2435 return 0;
2436 }
2437
2438 return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
2439 }
2440
2441 int
2442 puffs_islocked(void *v)
2443 {
2444 struct vop_islocked_args *ap = v;
2445 int rv;
2446
2447 rv = lockstatus(&ap->a_vp->v_lock);
2448 return rv;
2449 }
2450
2451 int
2452 puffs_generic(void *v)
2453 {
2454 struct vop_generic_args *ap = v;
2455
2456 (void)ap;
2457 DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
2458
2459 return EOPNOTSUPP;
2460 }
2461
2462
2463 /*
2464 * spec & fifo. These call the miscfs spec and fifo vectors, but issue
2465 * FAF update information for the puffs node first.
2466 */
2467 int
2468 puffs_spec_read(void *v)
2469 {
2470 struct vop_read_args /* {
2471 const struct vnodeop_desc *a_desc;
2472 struct vnode *a_vp;
2473 struct uio *a_uio;
2474 int a_ioflag;
2475 kauth_cred_t a_cred;
2476 } */ *ap = v;
2477
2478 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2479 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
2480 }
2481
2482 int
2483 puffs_spec_write(void *v)
2484 {
2485 struct vop_write_args /* {
2486 const struct vnodeop_desc *a_desc;
2487 struct vnode *a_vp;
2488 struct uio *a_uio;
2489 int a_ioflag;
2490 kauth_cred_t a_cred;
2491 }*/ *ap = v;
2492
2493 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2494 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
2495 }
2496
2497 int
2498 puffs_fifo_read(void *v)
2499 {
2500 struct vop_read_args /* {
2501 const struct vnodeop_desc *a_desc;
2502 struct vnode *a_vp;
2503 struct uio *a_uio;
2504 int a_ioflag;
2505 kauth_cred_t a_cred;
2506 } */ *ap = v;
2507
2508 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2509 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
2510 }
2511
2512 int
2513 puffs_fifo_write(void *v)
2514 {
2515 struct vop_write_args /* {
2516 const struct vnodeop_desc *a_desc;
2517 struct vnode *a_vp;
2518 struct uio *a_uio;
2519 int a_ioflag;
2520 kauth_cred_t a_cred;
2521 }*/ *ap = v;
2522
2523 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2524 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
2525 }
2526