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