puffs_vnops.c revision 1.111 1 /* $NetBSD: puffs_vnops.c,v 1.111 2007/10/21 19:43:52 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.111 2007/10/21 19:43:52 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 PUFFS_MSG_VARS(vn, lookup);
450 struct puffs_mount *pmp;
451 struct componentname *cnp;
452 struct vnode *vp, *dvp;
453 struct puffs_node *dpn;
454 int isdot;
455 int error;
456
457 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
458 cnp = ap->a_cnp;
459 dvp = ap->a_dvp;
460 *ap->a_vpp = NULL;
461
462 /* r/o fs? we check create later to handle EEXIST */
463 if ((cnp->cn_flags & ISLASTCN)
464 && (dvp->v_mount->mnt_flag & MNT_RDONLY)
465 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
466 return EROFS;
467
468 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
469
470 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
471 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
472
473 /*
474 * Check if someone fed it into the cache
475 */
476 if (PUFFS_USE_NAMECACHE(pmp)) {
477 error = cache_lookup(dvp, ap->a_vpp, cnp);
478
479 if (error >= 0)
480 return error;
481 }
482
483 if (isdot) {
484 vp = ap->a_dvp;
485 vref(vp);
486 *ap->a_vpp = vp;
487 return 0;
488 }
489
490 PUFFS_MSG_ALLOC(vn, lookup);
491 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
492 &lookup_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
493
494 if (cnp->cn_flags & ISDOTDOT)
495 VOP_UNLOCK(dvp, 0);
496
497 error = puffs_msg_vn(pmp, park_lookup, PUFFS_VN_LOOKUP, 0, dvp, NULL);
498 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
499
500 /*
501 * In case of error, there is no new vnode to play with, so be
502 * happy with the NULL value given to vpp in the beginning.
503 * Also, check if this really was an error or the target was not
504 * present. Either treat it as a non-error for CREATE/RENAME or
505 * enter the component into the negative name cache (if desired).
506 */
507 if (error) {
508 error = checkerr(pmp, error, __func__);
509 if (error == ENOENT) {
510 /* don't allow to create files on r/o fs */
511 if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
512 && cnp->cn_nameiop == CREATE) {
513 error = EROFS;
514
515 /* adjust values if we are creating */
516 } else if ((cnp->cn_flags & ISLASTCN)
517 && (cnp->cn_nameiop == CREATE
518 || cnp->cn_nameiop == RENAME)) {
519 cnp->cn_flags |= SAVENAME;
520 error = EJUSTRETURN;
521
522 /* save negative cache entry */
523 } else {
524 if ((cnp->cn_flags & MAKEENTRY)
525 && PUFFS_USE_NAMECACHE(pmp))
526 cache_enter(dvp, NULL, cnp);
527 }
528 }
529 goto out;
530 }
531
532 /*
533 * Check that we don't get our parent node back, that would cause
534 * a pretty obvious deadlock.
535 */
536 dpn = dvp->v_data;
537 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
538 puffs_msg_errnotify(pmp, PUFFS_ERR_LOOKUP, EINVAL,
539 "lookup produced parent cookie", lookup_msg->pvnr_newnode);
540 error = EPROTO;
541 goto out;
542 }
543
544 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, 1, &vp);
545 if (error == PUFFS_NOSUCHCOOKIE) {
546 error = puffs_getvnode(dvp->v_mount,
547 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
548 lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp);
549 if (error) {
550 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
551 lookup_msg->pvnr_newnode, ap->a_cnp);
552 goto out;
553 }
554 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
555 } else if (error) {
556 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
557 lookup_msg->pvnr_newnode, ap->a_cnp);
558 goto out;
559 }
560
561 *ap->a_vpp = vp;
562
563 if ((cnp->cn_flags & MAKEENTRY) != 0 && PUFFS_USE_NAMECACHE(pmp))
564 cache_enter(dvp, vp, cnp);
565
566 /* XXX */
567 if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
568 cnp->cn_flags &= ~REQUIREDIR;
569 if (lookup_msg->pvnr_cn.pkcn_consume)
570 cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume,
571 strlen(cnp->cn_nameptr) - cnp->cn_namelen);
572
573 out:
574 if (cnp->cn_flags & ISDOTDOT)
575 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
576
577 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
578 PUFFS_MSG_RELEASE(lookup);
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 PUFFS_MSG_VARS(vn, create);
593 struct vnode *dvp = ap->a_dvp;
594 struct componentname *cnp = ap->a_cnp;
595 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
596 int error;
597
598 DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
599 dvp, ap->a_cnp->cn_nameptr));
600
601 PUFFS_MSG_ALLOC(vn, create);
602 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
603 &create_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
604 create_msg->pvnr_va = *ap->a_vap;
605
606 error = puffs_msg_vn(pmp, park_create, PUFFS_VN_CREATE, 0, dvp, NULL);
607 error = checkerr(pmp, error, __func__);
608 if (error)
609 goto out;
610
611 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
612 create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0);
613 if (error)
614 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, VPTOPNC(dvp),
615 create_msg->pvnr_newnode, cnp);
616
617 out:
618 if (error || (cnp->cn_flags & SAVESTART) == 0)
619 PNBUF_PUT(cnp->cn_pnbuf);
620 vput(dvp);
621
622 DPRINTF(("puffs_create: return %d\n", error));
623 PUFFS_MSG_RELEASE(create);
624 return error;
625 }
626
627 int
628 puffs_mknod(void *v)
629 {
630 struct vop_mknod_args /* {
631 const struct vnodeop_desc *a_desc;
632 struct vnode *a_dvp;
633 struct vnode **a_vpp;
634 struct componentname *a_cnp;
635 struct vattr *a_vap;
636 } */ *ap = v;
637 PUFFS_MSG_VARS(vn, mknod);
638 struct vnode *dvp = ap->a_dvp;
639 struct componentname *cnp = ap->a_cnp;
640 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
641 int error;
642
643 PUFFS_MSG_ALLOC(vn, mknod);
644 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
645 &mknod_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
646 mknod_msg->pvnr_va = *ap->a_vap;
647
648 error = puffs_msg_vn(pmp, park_mknod, PUFFS_VN_MKNOD, 0, dvp, NULL);
649 error = checkerr(pmp, error, __func__);
650 if (error)
651 goto out;
652
653 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
654 mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type,
655 ap->a_vap->va_rdev);
656 if (error)
657 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, VPTOPNC(dvp),
658 mknod_msg->pvnr_newnode, cnp);
659
660 out:
661 PUFFS_MSG_RELEASE(mknod);
662 if (error || (cnp->cn_flags & SAVESTART) == 0)
663 PNBUF_PUT(cnp->cn_pnbuf);
664 vput(dvp);
665 return error;
666 }
667
668 int
669 puffs_open(void *v)
670 {
671 struct vop_open_args /* {
672 const struct vnodeop_desc *a_desc;
673 struct vnode *a_vp;
674 int a_mode;
675 kauth_cred_t a_cred;
676 struct lwp *a_l;
677 } */ *ap = v;
678 PUFFS_MSG_VARS(vn, open);
679 struct vnode *vp = ap->a_vp;
680 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
681 int mode = ap->a_mode;
682 int error;
683
684 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
685
686 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
687 ERROUT(EROFS);
688
689 if (!EXISTSOP(pmp, OPEN))
690 ERROUT(0);
691
692 PUFFS_MSG_ALLOC(vn, open);
693 open_msg->pvnr_mode = mode;
694 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
695 puffs_cidcvt(&open_msg->pvnr_cid, ap->a_l);
696
697 error = puffs_msg_vn(pmp, park_open, PUFFS_VN_OPEN, 0, vp, NULL);
698 error = checkerr(pmp, error, __func__);
699
700 out:
701 DPRINTF(("puffs_open: returning %d\n", error));
702 PUFFS_MSG_RELEASE(open);
703 return error;
704 }
705
706 int
707 puffs_close(void *v)
708 {
709 struct vop_close_args /* {
710 const struct vnodeop_desc *a_desc;
711 struct vnode *a_vp;
712 int a_fflag;
713 kauth_cred_t a_cred;
714 struct lwp *a_l;
715 } */ *ap = v;
716 PUFFS_MSG_VARS(vn, close);
717 struct vnode *vp = ap->a_vp;
718 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
719
720 PUFFS_MSG_ALLOC(vn, close);
721 puffs_msg_setfaf(park_close);
722 close_msg->pvnr_fflag = ap->a_fflag;
723 puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred);
724 puffs_cidcvt(&close_msg->pvnr_cid, ap->a_l);
725
726 puffs_msg_vn(pmp, park_close, PUFFS_VN_CLOSE, 0, vp, NULL);
727
728 PUFFS_MSG_RELEASE(close);
729 return 0;
730 }
731
732 int
733 puffs_access(void *v)
734 {
735 struct vop_access_args /* {
736 const struct vnodeop_desc *a_desc;
737 struct vnode *a_vp;
738 int a_mode;
739 kauth_cred_t a_cred;
740 struct lwp *a_l;
741 } */ *ap = v;
742 PUFFS_MSG_VARS(vn, access);
743 struct vnode *vp = ap->a_vp;
744 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
745 int mode = ap->a_mode;
746 int error;
747
748 if (mode & VWRITE) {
749 switch (vp->v_type) {
750 case VDIR:
751 case VLNK:
752 case VREG:
753 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
754 || !EXISTSOP(pmp, WRITE))
755 return EROFS;
756 break;
757 default:
758 break;
759 }
760 }
761
762 if (!EXISTSOP(pmp, ACCESS))
763 return 0;
764
765 PUFFS_MSG_ALLOC(vn, access);
766 access_msg->pvnr_mode = ap->a_mode;
767 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
768 puffs_cidcvt(&access_msg->pvnr_cid, ap->a_l);
769
770 error = puffs_msg_vn(pmp, park_access, PUFFS_VN_ACCESS, 0, vp, NULL);
771 error = checkerr(pmp, error, __func__);
772 PUFFS_MSG_RELEASE(access);
773
774 return error;
775 }
776
777 int
778 puffs_getattr(void *v)
779 {
780 struct vop_getattr_args /* {
781 const struct vnodeop_desc *a_desc;
782 struct vnode *a_vp;
783 struct vattr *a_vap;
784 kauth_cred_t a_cred;
785 struct lwp *a_l;
786 } */ *ap = v;
787 PUFFS_MSG_VARS(vn, getattr);
788 struct vnode *vp = ap->a_vp;
789 struct mount *mp = vp->v_mount;
790 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
791 struct vattr *vap, *rvap;
792 struct puffs_node *pn;
793 int error = 0;
794
795 vap = ap->a_vap;
796
797 PUFFS_MSG_ALLOC(vn, getattr);
798 vattr_null(&getattr_msg->pvnr_va);
799 puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
800 puffs_cidcvt(&getattr_msg->pvnr_cid, ap->a_l);
801
802 error = puffs_msg_vn(pmp, park_getattr, PUFFS_VN_GETATTR, 0, vp, NULL);
803 error = checkerr(pmp, error, __func__);
804 if (error)
805 goto out;
806
807 rvap = &getattr_msg->pvnr_va;
808 /*
809 * Don't listen to the file server regarding special device
810 * size info, the file server doesn't know anything about them.
811 */
812 if (vp->v_type == VBLK || vp->v_type == VCHR)
813 rvap->va_size = vp->v_size;
814
815 /* Ditto for blocksize (ufs comment: this doesn't belong here) */
816 if (vp->v_type == VBLK)
817 rvap->va_blocksize = BLKDEV_IOSIZE;
818 else if (vp->v_type == VCHR)
819 rvap->va_blocksize = MAXBSIZE;
820
821 (void) memcpy(vap, rvap, sizeof(struct vattr));
822 vap->va_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
823
824 pn = VPTOPP(vp);
825 if (pn->pn_stat & PNODE_METACACHE_ATIME)
826 vap->va_atime = pn->pn_mc_atime;
827 if (pn->pn_stat & PNODE_METACACHE_CTIME)
828 vap->va_ctime = pn->pn_mc_ctime;
829 if (pn->pn_stat & PNODE_METACACHE_MTIME)
830 vap->va_mtime = pn->pn_mc_mtime;
831 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
832 vap->va_size = pn->pn_mc_size;
833 } else {
834 if (rvap->va_size != VNOVAL
835 && vp->v_type != VBLK && vp->v_type != VCHR) {
836 uvm_vnp_setsize(vp, rvap->va_size);
837 pn->pn_serversize = rvap->va_size;
838 }
839 }
840
841 out:
842 PUFFS_MSG_RELEASE(getattr);
843 return error;
844 }
845
846 static int
847 puffs_dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred,
848 struct lwp *l, int chsize)
849 {
850 PUFFS_MSG_VARS(vn, setattr);
851 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
852 struct puffs_node *pn = vp->v_data;
853 int error;
854
855 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
856 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
857 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
858 || vap->va_mode != (mode_t)VNOVAL))
859 return EROFS;
860
861 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
862 && vp->v_type == VREG && vap->va_size != VNOVAL)
863 return EROFS;
864
865 /*
866 * Flush metacache first. If we are called with some explicit
867 * parameters, treat them as information overriding metacache
868 * information.
869 */
870 if (pn->pn_stat & PNODE_METACACHE_MASK) {
871 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
872 && vap->va_atime.tv_sec == VNOVAL)
873 vap->va_atime = pn->pn_mc_atime;
874 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
875 && vap->va_ctime.tv_sec == VNOVAL)
876 vap->va_ctime = pn->pn_mc_ctime;
877 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
878 && vap->va_mtime.tv_sec == VNOVAL)
879 vap->va_mtime = pn->pn_mc_mtime;
880 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
881 && vap->va_size == VNOVAL)
882 vap->va_size = pn->pn_mc_size;
883
884 pn->pn_stat &= ~PNODE_METACACHE_MASK;
885 }
886
887 PUFFS_MSG_ALLOC(vn, setattr);
888 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
889 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
890 puffs_cidcvt(&setattr_msg->pvnr_cid, l);
891
892 error = puffs_msg_vn(pmp, park_setattr, PUFFS_VN_SETATTR, 0, vp, NULL);
893 PUFFS_MSG_RELEASE(setattr);
894
895 error = checkerr(pmp, error, __func__);
896 if (error)
897 return error;
898
899 if (vap->va_size != VNOVAL) {
900 pn->pn_serversize = vap->va_size;
901 if (chsize)
902 uvm_vnp_setsize(vp, vap->va_size);
903 }
904
905 return 0;
906 }
907
908 int
909 puffs_setattr(void *v)
910 {
911 struct vop_getattr_args /* {
912 const struct vnodeop_desc *a_desc;
913 struct vnode *a_vp;
914 struct vattr *a_vap;
915 kauth_cred_t a_cred;
916 struct lwp *a_l;
917 } */ *ap = v;
918
919 return puffs_dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, ap->a_l, 1);
920 }
921
922 static __inline int
923 doinact(struct puffs_mount *pmp, int iaflag)
924 {
925
926 if (EXISTSOP(pmp, INACTIVE))
927 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
928 if (iaflag || ALLOPS(pmp))
929 return 1;
930 else
931 return 0;
932 else
933 return 1;
934 else
935 return 0;
936 }
937
938 static void
939 puffs_callinactive(struct puffs_mount *pmp, void *cookie, int iaflag,
940 struct lwp *l)
941 {
942 PUFFS_MSG_VARS(vn, inactive);
943
944 if (doinact(pmp, iaflag)) {
945 struct puffs_req *preq;
946
947 PUFFS_MSG_ALLOC(vn, inactive);
948 puffs_cidcvt(&inactive_msg->pvnr_cid, l);
949 preq = (struct puffs_req *)inactive_msg;
950 preq->preq_cookie = cookie;
951 preq->preq_opclass = PUFFSOP_VN;
952 preq->preq_optype = PUFFS_VN_INACTIVE;
953
954 puffs_msg_raw(pmp, park_inactive);
955 PUFFS_MSG_RELEASE(inactive);
956 }
957 }
958
959 /* XXX: callinactive can't setback */
960 int
961 puffs_inactive(void *v)
962 {
963 struct vop_inactive_args /* {
964 const struct vnodeop_desc *a_desc;
965 struct vnode *a_vp;
966 struct lwp *a_l;
967 } */ *ap = v;
968 PUFFS_MSG_VARS(vn, inactive);
969 struct vnode *vp = ap->a_vp;
970 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
971 struct puffs_node *pnode;
972
973 pnode = vp->v_data;
974
975 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
976 PUFFS_MSG_ALLOC(vn, inactive);
977 puffs_cidcvt(&inactive_msg->pvnr_cid, ap->a_l);
978 puffs_msg_vn(pmp, park_inactive, PUFFS_VN_INACTIVE, 0, vp,NULL);
979 PUFFS_MSG_RELEASE(inactive);
980 }
981 pnode->pn_stat &= ~PNODE_DOINACT;
982
983 VOP_UNLOCK(vp, 0);
984
985 /*
986 * file server thinks it's gone? then don't be afraid care,
987 * node's life was already all it would ever be
988 */
989 if (pnode->pn_stat & PNODE_NOREFS) {
990 pnode->pn_stat |= PNODE_DYING;
991 vrecycle(vp, NULL, ap->a_l);
992 }
993
994 return 0;
995 }
996
997 static void
998 puffs_callreclaim(struct puffs_mount *pmp, void *cookie, struct lwp *l)
999 {
1000 PUFFS_MSG_VARS(vn, reclaim);
1001 struct puffs_req *preq;
1002
1003 if (!EXISTSOP(pmp, RECLAIM))
1004 return;
1005
1006 PUFFS_MSG_ALLOC(vn, reclaim);
1007 puffs_msg_setfaf(park_reclaim);
1008 puffs_cidcvt(&reclaim_msg->pvnr_cid, l);
1009
1010 preq = (struct puffs_req *)reclaim_msg;
1011 preq->preq_cookie = cookie;
1012 preq->preq_opclass = PUFFSOP_VN;
1013 preq->preq_optype = PUFFS_VN_RECLAIM;
1014
1015 puffs_msg_raw(pmp, park_reclaim);
1016 PUFFS_MSG_RELEASE(reclaim);
1017 }
1018
1019 /*
1020 * always FAF, we don't really care if the server wants to fail to
1021 * reclaim the node or not
1022 */
1023 int
1024 puffs_reclaim(void *v)
1025 {
1026 struct vop_reclaim_args /* {
1027 const struct vnodeop_desc *a_desc;
1028 struct vnode *a_vp;
1029 struct lwp *a_l;
1030 } */ *ap = v;
1031 struct vnode *vp = ap->a_vp;
1032 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1033
1034 /*
1035 * first things first: check if someone is trying to reclaim the
1036 * root vnode. do not allow that to travel to userspace.
1037 * Note that we don't need to take the lock similarly to
1038 * puffs_root(), since there is only one of us.
1039 */
1040 if (vp->v_vflag & VV_ROOT) {
1041 mutex_enter(&pmp->pmp_lock);
1042 KASSERT(pmp->pmp_root != NULL);
1043 pmp->pmp_root = NULL;
1044 mutex_exit(&pmp->pmp_lock);
1045 goto out;
1046 }
1047
1048 puffs_callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), ap->a_l);
1049
1050 out:
1051 if (PUFFS_USE_NAMECACHE(pmp))
1052 cache_purge(vp);
1053 puffs_putvnode(vp);
1054
1055 return 0;
1056 }
1057
1058 #define CSIZE sizeof(**ap->a_cookies)
1059 int
1060 puffs_readdir(void *v)
1061 {
1062 struct vop_readdir_args /* {
1063 const struct vnodeop_desc *a_desc;
1064 struct vnode *a_vp;
1065 struct uio *a_uio;
1066 kauth_cred_t a_cred;
1067 int *a_eofflag;
1068 off_t **a_cookies;
1069 int *a_ncookies;
1070 } */ *ap = v;
1071 PUFFS_MSG_VARS(vn, readdir);
1072 struct vnode *vp = ap->a_vp;
1073 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1074 size_t argsize, tomove, cookiemem, cookiesmax;
1075 struct uio *uio = ap->a_uio;
1076 size_t howmuch, resid;
1077 int error;
1078
1079 /*
1080 * ok, so we need: resid + cookiemem = maxreq
1081 * => resid + cookiesize * (resid/minsize) = maxreq
1082 * => resid + cookiesize/minsize * resid = maxreq
1083 * => (cookiesize/minsize + 1) * resid = maxreq
1084 * => resid = maxreq / (cookiesize/minsize + 1)
1085 *
1086 * Since cookiesize <= minsize and we're not very big on floats,
1087 * we approximate that to be 1. Therefore:
1088 *
1089 * resid = maxreq / 2;
1090 *
1091 * Well, at least we didn't have to use differential equations
1092 * or the Gram-Schmidt process.
1093 *
1094 * (yes, I'm very afraid of this)
1095 */
1096 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1097
1098 if (ap->a_cookies) {
1099 KASSERT(ap->a_ncookies != NULL);
1100 if (pmp->pmp_args.pa_fhsize == 0)
1101 return EOPNOTSUPP;
1102 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1103 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1104 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1105 } else {
1106 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1107 cookiesmax = 0;
1108 cookiemem = 0;
1109 }
1110
1111 argsize = sizeof(struct puffs_vnmsg_readdir);
1112 tomove = resid + cookiemem;
1113 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1114 (void **)&readdir_msg, 1);
1115
1116 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1117 readdir_msg->pvnr_offset = uio->uio_offset;
1118 readdir_msg->pvnr_resid = resid;
1119 readdir_msg->pvnr_ncookies = cookiesmax;
1120 readdir_msg->pvnr_eofflag = 0;
1121 readdir_msg->pvnr_dentoff = cookiemem;
1122
1123 error = puffs_msg_vn(pmp, park_readdir, PUFFS_VN_READDIR,
1124 tomove, vp, NULL);
1125 error = checkerr(pmp, error, __func__);
1126 if (error)
1127 goto out;
1128
1129 /* userspace is cheating? */
1130 if (readdir_msg->pvnr_resid > resid) {
1131 puffs_msg_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1132 "resid grew", VPTOPNC(vp));
1133 ERROUT(EPROTO);
1134 }
1135 if (readdir_msg->pvnr_ncookies > cookiesmax) {
1136 puffs_msg_errnotify(pmp, PUFFS_ERR_READDIR, E2BIG,
1137 "too many cookies", VPTOPNC(vp));
1138 ERROUT(EPROTO);
1139 }
1140
1141 /* check eof */
1142 if (readdir_msg->pvnr_eofflag)
1143 *ap->a_eofflag = 1;
1144
1145 /* bouncy-wouncy with the directory data */
1146 howmuch = resid - readdir_msg->pvnr_resid;
1147
1148 /* force eof if no data was returned (getcwd() needs this) */
1149 if (howmuch == 0) {
1150 *ap->a_eofflag = 1;
1151 goto out;
1152 }
1153
1154 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1155 if (error)
1156 goto out;
1157
1158 /* provide cookies to caller if so desired */
1159 if (ap->a_cookies) {
1160 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1161 M_TEMP, M_WAITOK);
1162 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
1163 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1164 *ap->a_ncookies*CSIZE);
1165 }
1166
1167 /* next readdir starts here */
1168 uio->uio_offset = readdir_msg->pvnr_offset;
1169
1170 out:
1171 puffs_msgmem_release(park_readdir);
1172 return error;
1173 }
1174 #undef CSIZE
1175
1176 /*
1177 * poll works by consuming the bitmask in pn_revents. If there are
1178 * events available, poll returns immediately. If not, it issues a
1179 * poll to userspace, selrecords itself and returns with no available
1180 * events. When the file server returns, it executes puffs_parkdone_poll(),
1181 * where available events are added to the bitmask. selnotify() is
1182 * then also executed by that function causing us to enter here again
1183 * and hopefully find the missing bits (unless someone got them first,
1184 * in which case it starts all over again).
1185 */
1186 int
1187 puffs_poll(void *v)
1188 {
1189 struct vop_poll_args /* {
1190 const struct vnodeop_desc *a_desc;
1191 struct vnode *a_vp;
1192 int a_events;
1193 struct lwp *a_l;
1194 }*/ *ap = v;
1195 PUFFS_MSG_VARS(vn, poll);
1196 struct vnode *vp = ap->a_vp;
1197 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1198 struct puffs_node *pn = vp->v_data;
1199 int events;
1200
1201 if (EXISTSOP(pmp, POLL)) {
1202 mutex_enter(&pn->pn_mtx);
1203 events = pn->pn_revents & ap->a_events;
1204 if (events & ap->a_events) {
1205 pn->pn_revents &= ~ap->a_events;
1206 mutex_exit(&pn->pn_mtx);
1207
1208 return events;
1209 } else {
1210 puffs_referencenode(pn);
1211 mutex_exit(&pn->pn_mtx);
1212
1213 PUFFS_MSG_ALLOC(vn, poll);
1214 poll_msg->pvnr_events = ap->a_events;
1215 puffs_cidcvt(&poll_msg->pvnr_cid, ap->a_l);
1216
1217 selrecord(ap->a_l, &pn->pn_sel);
1218 puffs_msg_vncall(pmp, park_poll, PUFFS_VN_POLL, 0,
1219 puffs_parkdone_poll, pn, vp);
1220 PUFFS_MSG_RELEASE(poll);
1221
1222 return 0;
1223 }
1224 } else {
1225 return genfs_poll(v);
1226 }
1227 }
1228
1229 int
1230 puffs_fsync(void *v)
1231 {
1232 struct vop_fsync_args /* {
1233 const struct vnodeop_desc *a_desc;
1234 struct vnode *a_vp;
1235 kauth_cred_t a_cred;
1236 int a_flags;
1237 off_t a_offlo;
1238 off_t a_offhi;
1239 struct lwp *a_l;
1240 } */ *ap = v;
1241 PUFFS_MSG_VARS(vn, fsync);
1242 struct vnode *vp = ap->a_vp;
1243 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1244 struct puffs_node *pn;
1245 struct vattr va;
1246 int pflags, error, dofaf;
1247
1248 pn = VPTOPP(vp);
1249
1250 /* flush out information from our metacache, see vop_setattr */
1251 if (pn->pn_stat & PNODE_METACACHE_MASK
1252 && (pn->pn_stat & PNODE_DYING) == 0) {
1253 vattr_null(&va);
1254 error = VOP_SETATTR(vp, &va, FSCRED, NULL);
1255 if (error)
1256 return error;
1257 }
1258
1259 /*
1260 * flush pages to avoid being overly dirty
1261 */
1262 pflags = PGO_CLEANIT;
1263 if (ap->a_flags & FSYNC_WAIT)
1264 pflags |= PGO_SYNCIO;
1265 simple_lock(&vp->v_interlock);
1266 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
1267 round_page(ap->a_offhi), pflags);
1268 if (error)
1269 return error;
1270
1271 /*
1272 * HELLO! We exit already here if the user server does not
1273 * support fsync OR if we should call fsync for a node which
1274 * has references neither in the kernel or the fs server.
1275 * Otherwise we continue to issue fsync() forward.
1276 */
1277 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1278 return 0;
1279
1280 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1281 /*
1282 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1283 * only FAFs for those. Otherwise there's a danger of deadlock,
1284 * since the execution context here might be the user server
1285 * doing some operation on another fs, which in turn caused a
1286 * vnode to be reclaimed from the freelist for this fs.
1287 */
1288 if (dofaf == 0) {
1289 simple_lock(&vp->v_interlock);
1290 if (vp->v_iflag & VI_XLOCK)
1291 dofaf = 1;
1292 simple_unlock(&vp->v_interlock);
1293 }
1294
1295 PUFFS_MSG_ALLOC(vn, fsync);
1296 if (dofaf)
1297 puffs_msg_setfaf(park_fsync);
1298
1299 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1300 fsync_msg->pvnr_flags = ap->a_flags;
1301 fsync_msg->pvnr_offlo = ap->a_offlo;
1302 fsync_msg->pvnr_offhi = ap->a_offhi;
1303 puffs_cidcvt(&fsync_msg->pvnr_cid, ap->a_l);
1304
1305 error = puffs_msg_vn(pmp, park_fsync, PUFFS_VN_FSYNC, 0, vp, NULL);
1306 PUFFS_MSG_RELEASE(fsync);
1307
1308 error = checkerr(pmp, error, __func__);
1309
1310 return error;
1311 }
1312
1313 int
1314 puffs_seek(void *v)
1315 {
1316 struct vop_seek_args /* {
1317 const struct vnodeop_desc *a_desc;
1318 struct vnode *a_vp;
1319 off_t a_oldoff;
1320 off_t a_newoff;
1321 kauth_cred_t a_cred;
1322 } */ *ap = v;
1323 PUFFS_MSG_VARS(vn, seek);
1324 struct vnode *vp = ap->a_vp;
1325 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1326 int error;
1327
1328 PUFFS_MSG_ALLOC(vn, seek);
1329 seek_msg->pvnr_oldoff = ap->a_oldoff;
1330 seek_msg->pvnr_newoff = ap->a_newoff;
1331 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1332
1333 error = puffs_msg_vn(pmp, park_seek, PUFFS_VN_SEEK, 0, vp, NULL);
1334 PUFFS_MSG_RELEASE(seek);
1335 return checkerr(pmp, error, __func__);
1336 }
1337
1338 static int
1339 puffs_callremove(struct puffs_mount *pmp, void *dcookie, void *cookie,
1340 struct componentname *cnp)
1341 {
1342 PUFFS_MSG_VARS(vn, remove);
1343 struct puffs_req *preq;
1344 int error;
1345
1346 PUFFS_MSG_ALLOC(vn, remove);
1347 remove_msg->pvnr_cookie_targ = cookie;
1348 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1349 &remove_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1350
1351 /* XXX: uh, this is wrong because we don't get setbacks with raw */
1352 preq = (struct puffs_req *)remove_msg;
1353 preq->preq_cookie = dcookie;
1354 preq->preq_opclass = PUFFSOP_VN;
1355 preq->preq_optype = PUFFS_VN_REMOVE;
1356
1357 error = puffs_msg_raw(pmp, park_remove);
1358 PUFFS_MSG_RELEASE(remove);
1359
1360 return checkerr(pmp, error, __func__);
1361 }
1362
1363 /*
1364 * XXX: can't use callremove now because can't catch setbacks with
1365 * it due to lack of a vnode argument.
1366 */
1367 int
1368 puffs_remove(void *v)
1369 {
1370 struct vop_remove_args /* {
1371 const struct vnodeop_desc *a_desc;
1372 struct vnode *a_dvp;
1373 struct vnode *a_vp;
1374 struct componentname *a_cnp;
1375 } */ *ap = v;
1376 PUFFS_MSG_VARS(vn, remove);
1377 struct vnode *dvp = ap->a_dvp;
1378 struct vnode *vp = ap->a_vp;
1379 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1380 struct componentname *cnp = ap->a_cnp;
1381 int error;
1382
1383 PUFFS_MSG_ALLOC(vn, remove);
1384 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1385 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1386 &remove_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1387
1388 error = puffs_msg_vn(pmp, park_remove, PUFFS_VN_REMOVE, 0, dvp, vp);
1389 PUFFS_MSG_RELEASE(remove);
1390
1391 error = checkerr(pmp, error, __func__);
1392 vput(vp);
1393 if (dvp == vp)
1394 vrele(dvp);
1395 else
1396 vput(dvp);
1397
1398 return error;
1399 }
1400
1401 int
1402 puffs_mkdir(void *v)
1403 {
1404 struct vop_mkdir_args /* {
1405 const struct vnodeop_desc *a_desc;
1406 struct vnode *a_dvp;
1407 struct vnode **a_vpp;
1408 struct componentname *a_cnp;
1409 struct vattr *a_vap;
1410 } */ *ap = v;
1411 PUFFS_MSG_VARS(vn, mkdir);
1412 struct vnode *dvp = ap->a_dvp;
1413 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1414 struct componentname *cnp = ap->a_cnp;
1415 int error;
1416
1417 PUFFS_MSG_ALLOC(vn, mkdir);
1418 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1419 &mkdir_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1420 mkdir_msg->pvnr_va = *ap->a_vap;
1421
1422 error = puffs_msg_vn(pmp, park_mkdir, PUFFS_VN_MKDIR, 0, dvp, NULL);
1423 error = checkerr(pmp, error, __func__);
1424 if (error)
1425 goto out;
1426
1427 error = puffs_newnode(dvp->v_mount, dvp, ap->a_vpp,
1428 mkdir_msg->pvnr_newnode, cnp, VDIR, 0);
1429 if (error)
1430 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, VPTOPNC(ap->a_dvp),
1431 mkdir_msg->pvnr_newnode, cnp);
1432
1433 out:
1434 PUFFS_MSG_RELEASE(mkdir);
1435 if (error || (cnp->cn_flags & SAVESTART) == 0)
1436 PNBUF_PUT(cnp->cn_pnbuf);
1437 vput(ap->a_dvp);
1438 return error;
1439 }
1440
1441 static int
1442 puffs_callrmdir(struct puffs_mount *pmp, void *dcookie, void *cookie,
1443 struct componentname *cnp)
1444 {
1445 PUFFS_MSG_VARS(vn, rmdir);
1446 struct puffs_req *preq;
1447 int error;
1448
1449 PUFFS_MSG_ALLOC(vn, rmdir);
1450 rmdir_msg->pvnr_cookie_targ = cookie;
1451 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1452 &rmdir_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1453
1454 /* XXX: uh, this is wrong because we don't get setbacks with raw */
1455 preq = (struct puffs_req *)rmdir_msg;
1456 preq->preq_cookie = dcookie;
1457 preq->preq_opclass = PUFFSOP_VN;
1458 preq->preq_optype = PUFFS_VN_RMDIR;
1459
1460 error = puffs_msg_raw(pmp, park_rmdir);
1461 PUFFS_MSG_RELEASE(rmdir);
1462
1463 return checkerr(pmp, error, __func__);
1464 }
1465
1466 int
1467 puffs_rmdir(void *v)
1468 {
1469 struct vop_rmdir_args /* {
1470 const struct vnodeop_desc *a_desc;
1471 struct vnode *a_dvp;
1472 struct vnode *a_vp;
1473 struct componentname *a_cnp;
1474 } */ *ap = v;
1475 PUFFS_MSG_VARS(vn, rmdir);
1476 struct vnode *dvp = ap->a_dvp;
1477 struct vnode *vp = ap->a_vp;
1478 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1479 struct componentname *cnp = ap->a_cnp;
1480 int error;
1481
1482 PUFFS_MSG_ALLOC(vn, rmdir);
1483 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1484 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1485 &rmdir_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1486
1487 error = puffs_msg_vn(pmp, park_rmdir, PUFFS_VN_RMDIR, 0, dvp, vp);
1488 PUFFS_MSG_RELEASE(rmdir);
1489
1490 /* XXX: some call cache_purge() *for both vnodes* here, investigate */
1491 vput(dvp);
1492 vput(vp);
1493
1494 return error;
1495 }
1496
1497 int
1498 puffs_link(void *v)
1499 {
1500 struct vop_link_args /* {
1501 const struct vnodeop_desc *a_desc;
1502 struct vnode *a_dvp;
1503 struct vnode *a_vp;
1504 struct componentname *a_cnp;
1505 }*/ *ap = v;
1506 PUFFS_MSG_VARS(vn, link);
1507 struct vnode *dvp = ap->a_dvp;
1508 struct vnode *vp = ap->a_vp;
1509 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1510 struct componentname *cnp = ap->a_cnp;
1511 int error;
1512
1513 PUFFS_MSG_ALLOC(vn, link);
1514 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1515 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1516 &link_msg->pvnr_cn_cid, cnp, PUFFS_USE_FULLPNBUF(pmp));
1517
1518 error = puffs_msg_vn(pmp, park_link, PUFFS_VN_LINK, 0, dvp, NULL);
1519 PUFFS_MSG_RELEASE(link);
1520
1521 error = checkerr(pmp, error, __func__);
1522
1523 /*
1524 * XXX: stay in touch with the cache. I don't like this, but
1525 * don't have a better solution either. See also puffs_rename().
1526 */
1527 if (error == 0)
1528 puffs_updatenode(vp, PUFFS_UPDATECTIME);
1529
1530 PNBUF_PUT(cnp->cn_pnbuf);
1531 vput(dvp);
1532
1533 return error;
1534 }
1535
1536 int
1537 puffs_symlink(void *v)
1538 {
1539 struct vop_symlink_args /* {
1540 const struct vnodeop_desc *a_desc;
1541 struct vnode *a_dvp;
1542 struct vnode **a_vpp;
1543 struct componentname *a_cnp;
1544 struct vattr *a_vap;
1545 char *a_target;
1546 }*/ *ap = v;
1547 PUFFS_MSG_VARS(vn, symlink);
1548 struct vnode *dvp = ap->a_dvp;
1549 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1550 int error;
1551
1552 *ap->a_vpp = NULL;
1553
1554 PUFFS_MSG_ALLOC(vn, symlink);
1555 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1556 &symlink_msg->pvnr_cn_cid, ap->a_cnp, PUFFS_USE_FULLPNBUF(pmp));
1557 symlink_msg->pvnr_va = *ap->a_vap;
1558 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1559 sizeof(symlink_msg->pvnr_link));
1560
1561 error = puffs_msg_vn(pmp, park_symlink, PUFFS_VN_SYMLINK, 0, dvp,NULL);
1562 error = checkerr(pmp, error, __func__);
1563 if (error)
1564 goto out;
1565
1566 error = puffs_newnode(ap->a_dvp->v_mount, ap->a_dvp, ap->a_vpp,
1567 symlink_msg->pvnr_newnode, ap->a_cnp, VLNK, 0);
1568 if (error)
1569 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, VPTOPNC(ap->a_dvp),
1570 symlink_msg->pvnr_newnode, ap->a_cnp);
1571
1572 out:
1573 PUFFS_MSG_RELEASE(symlink);
1574 if (error || (ap->a_cnp->cn_flags & SAVESTART) == 0)
1575 PNBUF_PUT(ap->a_cnp->cn_pnbuf);
1576 vput(ap->a_dvp);
1577
1578 return error;
1579 }
1580
1581 int
1582 puffs_readlink(void *v)
1583 {
1584 struct vop_readlink_args /* {
1585 const struct vnodeop_desc *a_desc;
1586 struct vnode *a_vp;
1587 struct uio *a_uio;
1588 kauth_cred_t a_cred;
1589 } */ *ap = v;
1590 PUFFS_MSG_VARS(vn, readlink);
1591 struct vnode *vp = ap->a_vp;
1592 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1593 size_t linklen;
1594 int error;
1595
1596 PUFFS_MSG_ALLOC(vn, readlink);
1597 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1598 linklen = sizeof(readlink_msg->pvnr_link);
1599 readlink_msg->pvnr_linklen = linklen;
1600
1601 error = puffs_msg_vn(pmp, park_readlink, PUFFS_VN_READLINK, 0, vp,NULL);
1602 error = checkerr(pmp, error, __func__);
1603 if (error)
1604 goto out;
1605
1606 /* bad bad user file server */
1607 if (readlink_msg->pvnr_linklen > linklen) {
1608 puffs_msg_errnotify(pmp, PUFFS_ERR_READLINK, E2BIG,
1609 "linklen too big", VPTOPNC(ap->a_vp));
1610 error = EPROTO;
1611 goto out;
1612 }
1613
1614 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1615 ap->a_uio);
1616 out:
1617 PUFFS_MSG_RELEASE(readlink);
1618 return error;
1619 }
1620
1621 int
1622 puffs_rename(void *v)
1623 {
1624 struct vop_rename_args /* {
1625 const struct vnodeop_desc *a_desc;
1626 struct vnode *a_fdvp;
1627 struct vnode *a_fvp;
1628 struct componentname *a_fcnp;
1629 struct vnode *a_tdvp;
1630 struct vnode *a_tvp;
1631 struct componentname *a_tcnp;
1632 }*/ *ap = v;
1633 PUFFS_MSG_VARS(vn, rename);
1634 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_fdvp->v_mount);
1635 int error;
1636
1637 if (ap->a_fvp->v_mount != ap->a_tdvp->v_mount)
1638 ERROUT(EXDEV);
1639
1640 PUFFS_MSG_ALLOC(vn, rename);
1641 rename_msg->pvnr_cookie_src = VPTOPNC(ap->a_fvp);
1642 rename_msg->pvnr_cookie_targdir = VPTOPNC(ap->a_tdvp);
1643 if (ap->a_tvp)
1644 rename_msg->pvnr_cookie_targ = VPTOPNC(ap->a_tvp);
1645 else
1646 rename_msg->pvnr_cookie_targ = NULL;
1647 puffs_makecn(&rename_msg->pvnr_cn_src,
1648 &rename_msg->pvnr_cn_src_cred, &rename_msg->pvnr_cn_src_cid,
1649 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
1650 puffs_makecn(&rename_msg->pvnr_cn_targ,
1651 &rename_msg->pvnr_cn_targ_cred, &rename_msg->pvnr_cn_targ_cid,
1652 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
1653
1654 error = puffs_msg_vn(pmp, park_rename, PUFFS_VN_RENAME,
1655 0, ap->a_fdvp, NULL); /* XXX: missing vnodes */
1656 error = checkerr(pmp, error, __func__);
1657
1658 /*
1659 * XXX: stay in touch with the cache. I don't like this, but
1660 * don't have a better solution either. See also puffs_link().
1661 */
1662 if (error == 0)
1663 puffs_updatenode(ap->a_fvp, PUFFS_UPDATECTIME);
1664
1665 out:
1666 PUFFS_MSG_RELEASE(rename);
1667 if (ap->a_tvp != NULL)
1668 vput(ap->a_tvp);
1669 if (ap->a_tdvp == ap->a_tvp)
1670 vrele(ap->a_tdvp);
1671 else
1672 vput(ap->a_tdvp);
1673
1674 vrele(ap->a_fdvp);
1675 vrele(ap->a_fvp);
1676
1677 return error;
1678 }
1679
1680 #define RWARGS(cont, iofl, move, offset, creds) \
1681 (cont)->pvnr_ioflag = (iofl); \
1682 (cont)->pvnr_resid = (move); \
1683 (cont)->pvnr_offset = (offset); \
1684 puffs_credcvt(&(cont)->pvnr_cred, creds)
1685
1686 int
1687 puffs_read(void *v)
1688 {
1689 struct vop_read_args /* {
1690 const struct vnodeop_desc *a_desc;
1691 struct vnode *a_vp;
1692 struct uio *a_uio;
1693 int a_ioflag;
1694 kauth_cred_t a_cred;
1695 } */ *ap = v;
1696 PUFFS_MSG_VARS(vn, read);
1697 struct vnode *vp = ap->a_vp;
1698 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1699 struct uio *uio = ap->a_uio;
1700 void *win;
1701 size_t tomove, argsize;
1702 vsize_t bytelen;
1703 int error, ubcflags;
1704
1705 read_msg = NULL;
1706 error = 0;
1707
1708 /* std sanity */
1709 if (uio->uio_resid == 0)
1710 return 0;
1711 if (uio->uio_offset < 0)
1712 return EINVAL;
1713
1714 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1715 const int advice = IO_ADV_DECODE(ap->a_ioflag);
1716
1717 ubcflags = 0;
1718 if (UBC_WANT_UNMAP(vp))
1719 ubcflags = UBC_UNMAP;
1720
1721 while (uio->uio_resid > 0) {
1722 bytelen = MIN(uio->uio_resid,
1723 vp->v_size - uio->uio_offset);
1724 if (bytelen == 0)
1725 break;
1726
1727 win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
1728 &bytelen, advice, UBC_READ);
1729 error = uiomove(win, bytelen, uio);
1730 ubc_release(win, ubcflags);
1731 if (error)
1732 break;
1733 }
1734
1735 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
1736 puffs_updatenode(vp, PUFFS_UPDATEATIME);
1737 } else {
1738 /*
1739 * in case it's not a regular file or we're operating
1740 * uncached, do read in the old-fashioned style,
1741 * i.e. explicit read operations
1742 */
1743
1744 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1745 argsize = sizeof(struct puffs_vnmsg_read);
1746 puffs_msgmem_alloc(argsize + tomove, &park_read,
1747 (void **)&read_msg, 1);
1748
1749 error = 0;
1750 while (uio->uio_resid > 0) {
1751 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1752 RWARGS(read_msg, ap->a_ioflag, tomove,
1753 uio->uio_offset, ap->a_cred);
1754
1755 error = puffs_msg_vn(pmp, park_read, PUFFS_VN_READ,
1756 tomove, vp, NULL);
1757 error = checkerr(pmp, error, __func__);
1758 if (error)
1759 break;
1760
1761 if (read_msg->pvnr_resid > tomove) {
1762 puffs_msg_errnotify(pmp, PUFFS_ERR_READ,
1763 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1764 error = EPROTO;
1765 break;
1766 }
1767
1768 error = uiomove(read_msg->pvnr_data,
1769 tomove - read_msg->pvnr_resid, uio);
1770
1771 /*
1772 * in case the file is out of juice, resid from
1773 * userspace is != 0. and the error-case is
1774 * quite obvious
1775 */
1776 if (error || read_msg->pvnr_resid)
1777 break;
1778 }
1779
1780 puffs_msgmem_release(park_read);
1781 }
1782
1783 return error;
1784 }
1785
1786 /*
1787 * XXX: in case of a failure, this leaves uio in a bad state.
1788 * We could theoretically copy the uio and iovecs and "replay"
1789 * them the right amount after the userspace trip, but don't
1790 * bother for now.
1791 */
1792 int
1793 puffs_write(void *v)
1794 {
1795 struct vop_write_args /* {
1796 const struct vnodeop_desc *a_desc;
1797 struct vnode *a_vp;
1798 struct uio *a_uio;
1799 int a_ioflag;
1800 kauth_cred_t a_cred;
1801 } */ *ap = v;
1802 PUFFS_MSG_VARS(vn, write);
1803 struct vnode *vp = ap->a_vp;
1804 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1805 struct uio *uio = ap->a_uio;
1806 size_t tomove, argsize;
1807 off_t oldoff, newoff, origoff;
1808 vsize_t bytelen;
1809 int error, uflags;
1810 int ubcflags;
1811
1812 error = uflags = 0;
1813 write_msg = NULL;
1814
1815 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
1816 ubcflags = UBC_WRITE | UBC_PARTIALOK;
1817 if (UBC_WANT_UNMAP(vp))
1818 ubcflags |= UBC_UNMAP;
1819
1820 /*
1821 * userspace *should* be allowed to control this,
1822 * but with UBC it's a bit unclear how to handle it
1823 */
1824 if (ap->a_ioflag & IO_APPEND)
1825 uio->uio_offset = vp->v_size;
1826
1827 origoff = uio->uio_offset;
1828 while (uio->uio_resid > 0) {
1829 uflags |= PUFFS_UPDATECTIME;
1830 uflags |= PUFFS_UPDATEMTIME;
1831 oldoff = uio->uio_offset;
1832 bytelen = uio->uio_resid;
1833
1834 newoff = oldoff + bytelen;
1835 if (vp->v_size < newoff) {
1836 uvm_vnp_setwritesize(vp, newoff);
1837 }
1838 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
1839 UVM_ADV_RANDOM, ubcflags);
1840
1841 /*
1842 * In case of a ubc_uiomove() error,
1843 * opt to not extend the file at all and
1844 * return an error. Otherwise, if we attempt
1845 * to clear the memory we couldn't fault to,
1846 * we might generate a kernel page fault.
1847 */
1848 if (vp->v_size < newoff) {
1849 if (error == 0) {
1850 uflags |= PUFFS_UPDATESIZE;
1851 uvm_vnp_setsize(vp, newoff);
1852 } else {
1853 uvm_vnp_setwritesize(vp, vp->v_size);
1854 }
1855 }
1856 if (error)
1857 break;
1858
1859 /*
1860 * If we're writing large files, flush to file server
1861 * every 64k. Otherwise we can very easily exhaust
1862 * kernel and user memory, as the file server cannot
1863 * really keep up with our writing speed.
1864 *
1865 * Note: this does *NOT* honor MNT_ASYNC, because
1866 * that gives userland too much say in the kernel.
1867 */
1868 if (oldoff >> 16 != uio->uio_offset >> 16) {
1869 simple_lock(&vp->v_interlock);
1870 error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
1871 uio->uio_offset & ~0xffff,
1872 PGO_CLEANIT | PGO_SYNCIO);
1873 if (error)
1874 break;
1875 }
1876 }
1877
1878 /* synchronous I/O? */
1879 if (error == 0 && ap->a_ioflag & IO_SYNC) {
1880 simple_lock(&vp->v_interlock);
1881 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1882 round_page(uio->uio_offset),
1883 PGO_CLEANIT | PGO_SYNCIO);
1884
1885 /* write through page cache? */
1886 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
1887 simple_lock(&vp->v_interlock);
1888 error = VOP_PUTPAGES(vp, trunc_page(origoff),
1889 round_page(uio->uio_offset), PGO_CLEANIT);
1890 }
1891
1892 puffs_updatenode(vp, uflags);
1893 } else {
1894 /* tomove is non-increasing */
1895 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1896 argsize = sizeof(struct puffs_vnmsg_write) + tomove;
1897 puffs_msgmem_alloc(argsize, &park_write, (void **)&write_msg,1);
1898
1899 while (uio->uio_resid > 0) {
1900 /* move data to buffer */
1901 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
1902 RWARGS(write_msg, ap->a_ioflag, tomove,
1903 uio->uio_offset, ap->a_cred);
1904 error = uiomove(write_msg->pvnr_data, tomove, uio);
1905 if (error)
1906 break;
1907
1908 /* move buffer to userspace */
1909 error = puffs_msg_vn(pmp, park_write, PUFFS_VN_WRITE,
1910 0, vp, NULL);
1911 error = checkerr(pmp, error, __func__);
1912 if (error)
1913 break;
1914
1915 if (write_msg->pvnr_resid > tomove) {
1916 puffs_msg_errnotify(pmp, PUFFS_ERR_WRITE,
1917 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
1918 error = EPROTO;
1919 break;
1920 }
1921
1922 /* adjust file size */
1923 if (vp->v_size < uio->uio_offset)
1924 uvm_vnp_setsize(vp, uio->uio_offset);
1925
1926 /* didn't move everything? bad userspace. bail */
1927 if (write_msg->pvnr_resid != 0) {
1928 error = EIO;
1929 break;
1930 }
1931 }
1932 puffs_msgmem_release(park_write);
1933 }
1934
1935 return error;
1936 }
1937
1938 int
1939 puffs_print(void *v)
1940 {
1941 struct vop_print_args /* {
1942 struct vnode *a_vp;
1943 } */ *ap = v;
1944 PUFFS_MSG_VARS(vn, print);
1945 struct vnode *vp = ap->a_vp;
1946 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1947 struct puffs_node *pn = vp->v_data;
1948
1949 /* kernel portion */
1950 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1951 " userspace cookie: %p\n", vp, pn, pn->pn_cookie);
1952 if (vp->v_type == VFIFO)
1953 fifo_printinfo(vp);
1954 lockmgr_printinfo(&vp->v_lock);
1955
1956 /* userspace portion */
1957 if (EXISTSOP(pmp, PRINT)) {
1958 PUFFS_MSG_ALLOC(vn, print);
1959 puffs_msg_vn(pmp, park_print, PUFFS_VN_PRINT, 0, vp, NULL);
1960 PUFFS_MSG_RELEASE(print);
1961 }
1962
1963 return 0;
1964 }
1965
1966 int
1967 puffs_pathconf(void *v)
1968 {
1969 struct vop_pathconf_args /* {
1970 const struct vnodeop_desc *a_desc;
1971 struct vnode *a_vp;
1972 int a_name;
1973 register_t *a_retval;
1974 } */ *ap = v;
1975 PUFFS_MSG_VARS(vn, pathconf);
1976 struct vnode *vp = ap->a_vp;
1977 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1978 int error;
1979
1980 PUFFS_MSG_ALLOC(vn, pathconf);
1981 pathconf_msg->pvnr_name = ap->a_name;
1982 error = puffs_msg_vn(pmp, park_pathconf, PUFFS_VN_PATHCONF, 0, vp,NULL);
1983 error = checkerr(pmp, error, __func__);
1984 if (!error)
1985 *ap->a_retval = pathconf_msg->pvnr_retval;
1986 PUFFS_MSG_RELEASE(pathconf);
1987
1988 return error;
1989 }
1990
1991 int
1992 puffs_advlock(void *v)
1993 {
1994 struct vop_advlock_args /* {
1995 const struct vnodeop_desc *a_desc;
1996 struct vnode *a_vp;
1997 void *a_id;
1998 int a_op;
1999 struct flock *a_fl;
2000 int a_flags;
2001 } */ *ap = v;
2002 PUFFS_MSG_VARS(vn, advlock);
2003 struct vnode *vp = ap->a_vp;
2004 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2005 int error;
2006
2007 PUFFS_MSG_ALLOC(vn, advlock);
2008 error = copyin(ap->a_fl, &advlock_msg->pvnr_fl, sizeof(struct flock));
2009 if (error)
2010 goto out;
2011 advlock_msg->pvnr_id = ap->a_id;
2012 advlock_msg->pvnr_op = ap->a_op;
2013 advlock_msg->pvnr_flags = ap->a_flags;
2014
2015 error = puffs_msg_vn(pmp, park_advlock, PUFFS_VN_ADVLOCK, 0, vp, NULL);
2016 error = checkerr(pmp, error, __func__);
2017
2018 out:
2019 PUFFS_MSG_RELEASE(advlock);
2020 return error;
2021 }
2022
2023 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2024 #define BIOREAD(bp) (bp->b_flags & B_READ)
2025 #define BIOWRITE(bp) ((bp->b_flags & B_READ) == 0)
2026
2027 /*
2028 * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2029 */
2030 int
2031 puffs_strategy(void *v)
2032 {
2033 struct vop_strategy_args /* {
2034 const struct vnodeop_desc *a_desc;
2035 struct vnode *a_vp;
2036 struct buf *a_bp;
2037 } */ *ap = v;
2038 PUFFS_MSG_VARS(vn, rw);
2039 struct vnode *vp = ap->a_vp;
2040 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2041 struct puffs_node *pn;
2042 struct buf *bp;
2043 size_t argsize;
2044 size_t tomove, moved;
2045 int error, dofaf;
2046
2047 pmp = MPTOPUFFSMP(vp->v_mount);
2048 bp = ap->a_bp;
2049 error = 0;
2050 dofaf = 0;
2051 pn = VPTOPP(vp);
2052 park_rw = NULL; /* explicit */
2053
2054 if ((BIOREAD(bp) && !EXISTSOP(pmp, READ))
2055 || (BIOWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2056 ERROUT(EOPNOTSUPP);
2057
2058 /*
2059 * Short-circuit optimization: don't flush buffer in between
2060 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2061 */
2062 if (pn->pn_stat & PNODE_DYING) {
2063 KASSERT(BIOWRITE(bp));
2064 bp->b_resid = 0;
2065 goto out;
2066 }
2067
2068 #ifdef DIAGNOSTIC
2069 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2070 panic("puffs_strategy: wildly inappropriate buf bcount %d",
2071 bp->b_bcount);
2072 #endif
2073
2074 /*
2075 * See explanation for the necessity of a FAF in puffs_fsync.
2076 *
2077 * Also, do FAF in case we're suspending.
2078 * See puffs_vfsops.c:pageflush()
2079 */
2080 if (BIOWRITE(bp)) {
2081 simple_lock(&vp->v_interlock);
2082 if (vp->v_iflag & VI_XLOCK)
2083 dofaf = 1;
2084 if (pn->pn_stat & PNODE_SUSPEND)
2085 dofaf = 1;
2086 simple_unlock(&vp->v_interlock);
2087 }
2088
2089 if (BIOASYNC(bp))
2090 dofaf = 1;
2091
2092 #ifdef DIAGNOSTIC
2093 if (curlwp == uvm.pagedaemon_lwp)
2094 KASSERT(dofaf);
2095 #endif
2096
2097 /* allocate transport structure */
2098 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2099 argsize = sizeof(struct puffs_vnmsg_rw);
2100 error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2101 (void **)&rw_msg, dofaf ? 0 : 1);
2102 if (error)
2103 goto out;
2104 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2105
2106 /* 2x2 cases: read/write, faf/nofaf */
2107 if (BIOREAD(bp)) {
2108 if (dofaf) {
2109 puffs_msg_vncall(pmp, park_rw, PUFFS_VN_READ, 0,
2110 puffs_parkdone_asyncbioread, bp, vp);
2111 } else {
2112 error = puffs_msg_vn(pmp, park_rw, PUFFS_VN_READ,
2113 tomove, vp, NULL);
2114 error = checkerr(pmp, error, __func__);
2115 if (error)
2116 goto out;
2117
2118 if (rw_msg->pvnr_resid > tomove) {
2119 puffs_msg_errnotify(pmp, PUFFS_ERR_READ,
2120 E2BIG, "resid grew", VPTOPNC(vp));
2121 ERROUT(EPROTO);
2122 }
2123
2124 moved = tomove - rw_msg->pvnr_resid;
2125
2126 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2127 bp->b_resid = bp->b_bcount - moved;
2128 }
2129 } else {
2130 /*
2131 * make pages read-only before we write them if we want
2132 * write caching info
2133 */
2134 if (PUFFS_WCACHEINFO(pmp)) {
2135 struct uvm_object *uobj = &vp->v_uobj;
2136 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2137 struct vm_page *vmp;
2138 int i;
2139
2140 for (i = 0; i < npages; i++) {
2141 vmp= uvm_pageratop((vaddr_t)bp->b_data
2142 + (i << PAGE_SHIFT));
2143 DPRINTF(("puffs_strategy: write-protecting "
2144 "vp %p page %p, offset %" PRId64"\n",
2145 vp, vmp, vmp->offset));
2146 simple_lock(&uobj->vmobjlock);
2147 vmp->flags |= PG_RDONLY;
2148 pmap_page_protect(vmp, VM_PROT_READ);
2149 simple_unlock(&uobj->vmobjlock);
2150 }
2151 }
2152
2153 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2154 if (dofaf)
2155 puffs_msg_setfaf(park_rw);
2156 error = puffs_msg_vn(pmp, park_rw, PUFFS_VN_WRITE, 0, vp, NULL);
2157
2158 if (dofaf) {
2159 /*
2160 * FAF moves everything. Frankly, we don't
2161 * really have a choice.
2162 */
2163 KASSERT(error == 0);
2164 bp->b_resid = bp->b_bcount - tomove;
2165 } else {
2166 error = checkerr(pmp, error, __func__);
2167 if (error)
2168 goto out;
2169
2170 moved = tomove - rw_msg->pvnr_resid;
2171 if (rw_msg->pvnr_resid > tomove) {
2172 puffs_msg_errnotify(pmp, PUFFS_ERR_WRITE,
2173 E2BIG, "resid grew", VPTOPNC(vp));
2174 ERROUT(EPROTO);
2175 }
2176
2177 bp->b_resid = bp->b_bcount - moved;
2178 if (rw_msg->pvnr_resid != 0) {
2179 ERROUT(EIO);
2180 }
2181 }
2182 }
2183
2184 out:
2185 if (park_rw)
2186 puffs_msgmem_release(park_rw);
2187
2188 if (error)
2189 bp->b_error = error;
2190
2191 if (error || !(BIOREAD(bp) && BIOASYNC(bp)))
2192 biodone(bp);
2193
2194 return error;
2195 }
2196
2197 int
2198 puffs_mmap(void *v)
2199 {
2200 struct vop_mmap_args /* {
2201 const struct vnodeop_desc *a_desc;
2202 struct vnode *a_vp;
2203 vm_prot_t a_prot;
2204 kauth_cred_t a_cred;
2205 struct lwp *a_l;
2206 } */ *ap = v;
2207 PUFFS_MSG_VARS(vn, mmap);
2208 struct vnode *vp = ap->a_vp;
2209 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2210 int error;
2211
2212 if (!PUFFS_USE_PAGECACHE(pmp))
2213 return genfs_eopnotsupp(v);
2214
2215 if (EXISTSOP(pmp, MMAP)) {
2216 PUFFS_MSG_ALLOC(vn, mmap);
2217 mmap_msg->pvnr_prot = ap->a_prot;
2218 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2219 puffs_cidcvt(&mmap_msg->pvnr_cid, ap->a_l);
2220
2221 error = puffs_msg_vn(pmp, park_mmap, PUFFS_VN_MMAP,
2222 0, vp, NULL);
2223 error = checkerr(pmp, error, __func__);
2224 PUFFS_MSG_RELEASE(mmap);
2225 } else {
2226 error = genfs_mmap(v);
2227 }
2228
2229 return error;
2230 }
2231
2232
2233 /*
2234 * The rest don't get a free trip to userspace and back, they
2235 * have to stay within the kernel.
2236 */
2237
2238 /*
2239 * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2240 * well, maybe somehow, somewhere, some day ....
2241 */
2242 int
2243 puffs_bmap(void *v)
2244 {
2245 struct vop_bmap_args /* {
2246 const struct vnodeop_desc *a_desc;
2247 struct vnode *a_vp;
2248 daddr_t a_bn;
2249 struct vnode **a_vpp;
2250 daddr_t *a_bnp;
2251 int *a_runp;
2252 } */ *ap = v;
2253 struct puffs_mount *pmp;
2254
2255 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2256
2257 if (ap->a_vpp)
2258 *ap->a_vpp = ap->a_vp;
2259 if (ap->a_bnp)
2260 *ap->a_bnp = ap->a_bn;
2261 if (ap->a_runp)
2262 *ap->a_runp
2263 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2264
2265 return 0;
2266 }
2267
2268 /*
2269 * Handle getpages faults in puffs. We let genfs_getpages() do most
2270 * of the dirty work, but we come in this route to do accounting tasks.
2271 * If the user server has specified functions for cache notifications
2272 * about reads and/or writes, we record which type of operation we got,
2273 * for which page range, and proceed to issue a FAF notification to the
2274 * server about it.
2275 */
2276 int
2277 puffs_getpages(void *v)
2278 {
2279 struct vop_getpages_args /* {
2280 const struct vnodeop_desc *a_desc;
2281 struct vnode *a_vp;
2282 voff_t a_offset;
2283 struct vm_page **a_m;
2284 int *a_count;
2285 int a_centeridx;
2286 vm_prot_t a_access_type;
2287 int a_advice;
2288 int a_flags;
2289 } */ *ap = v;
2290 struct puffs_mount *pmp;
2291 struct puffs_node *pn;
2292 struct vnode *vp;
2293 struct vm_page **pgs;
2294 struct puffs_cacheinfo *pcinfo = NULL;
2295 struct puffs_cacherun *pcrun;
2296 void *parkmem = NULL;
2297 size_t runsizes;
2298 int i, npages, si, streakon;
2299 int error, locked, write;
2300
2301 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2302 npages = *ap->a_count;
2303 pgs = ap->a_m;
2304 vp = ap->a_vp;
2305 pn = vp->v_data;
2306 locked = (ap->a_flags & PGO_LOCKED) != 0;
2307 write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2308
2309 /* ccg xnaht - gets Wuninitialized wrong */
2310 pcrun = NULL;
2311 runsizes = 0;
2312
2313 /*
2314 * Check that we aren't trying to fault in pages which our file
2315 * server doesn't know about. This happens if we extend a file by
2316 * skipping some pages and later try to fault in pages which
2317 * are between pn_serversize and vp_size. This check optimizes
2318 * away the common case where a file is being extended.
2319 */
2320 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2321 struct vattr va;
2322
2323 /* try again later when we can block */
2324 if (locked)
2325 ERROUT(EBUSY);
2326
2327 simple_unlock(&vp->v_interlock);
2328 vattr_null(&va);
2329 va.va_size = vp->v_size;
2330 error = puffs_dosetattr(vp, &va, FSCRED, NULL, 0);
2331 if (error)
2332 ERROUT(error);
2333 simple_lock(&vp->v_interlock);
2334 }
2335
2336 if (write && PUFFS_WCACHEINFO(pmp)) {
2337 #ifdef notnowjohn
2338 /* allocate worst-case memory */
2339 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2340 pcinfo = malloc(sizeof(struct puffs_cacheinfo) + runsizes,
2341 M_PUFFS, M_ZERO | locked ? M_NOWAIT : M_WAITOK);
2342
2343 /*
2344 * can't block if we're locked and can't mess up caching
2345 * information for fs server. so come back later, please
2346 */
2347 if (pcinfo == NULL)
2348 ERROUT(ENOMEM);
2349
2350 parkmem = puffs_park_alloc(locked == 0);
2351 if (parkmem == NULL)
2352 ERROUT(ENOMEM);
2353
2354 pcrun = pcinfo->pcache_runs;
2355 #else
2356 (void)parkmem;
2357 #endif
2358 }
2359
2360 error = genfs_getpages(v);
2361 if (error)
2362 goto out;
2363
2364 if (PUFFS_WCACHEINFO(pmp) == 0)
2365 goto out;
2366
2367 /*
2368 * Let's see whose fault it was and inform the user server of
2369 * possibly read/written pages. Map pages from read faults
2370 * strictly read-only, since otherwise we might miss info on
2371 * when the page is actually write-faulted to.
2372 */
2373 if (!locked)
2374 simple_lock(&vp->v_uobj.vmobjlock);
2375 for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2376 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2377 if (streakon && write) {
2378 streakon = 0;
2379 pcrun[si].pcache_runend
2380 = trunc_page(pgs[i]->offset) + PAGE_MASK;
2381 si++;
2382 }
2383 continue;
2384 }
2385 if (streakon == 0 && write) {
2386 streakon = 1;
2387 pcrun[si].pcache_runstart = pgs[i]->offset;
2388 }
2389
2390 if (!write)
2391 pgs[i]->flags |= PG_RDONLY;
2392 }
2393 /* was the last page part of our streak? */
2394 if (streakon) {
2395 pcrun[si].pcache_runend
2396 = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2397 si++;
2398 }
2399 if (!locked)
2400 simple_unlock(&vp->v_uobj.vmobjlock);
2401
2402 KASSERT(si <= (npages / 2) + 1);
2403
2404 #ifdef notnowjohn
2405 /* send results to userspace */
2406 if (write)
2407 puffs_cacheop(pmp, parkmem, pcinfo,
2408 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2409 #endif
2410
2411 out:
2412 if (error) {
2413 if (pcinfo != NULL)
2414 free(pcinfo, M_PUFFS);
2415 #ifdef notnowjohn
2416 if (parkmem != NULL)
2417 puffs_park_release(parkmem, 1);
2418 #endif
2419 }
2420
2421 return error;
2422 }
2423
2424 int
2425 puffs_lock(void *v)
2426 {
2427 struct vop_lock_args /* {
2428 struct vnode *a_vp;
2429 int a_flags;
2430 }*/ *ap = v;
2431 struct vnode *vp = ap->a_vp;
2432 struct mount *mp = vp->v_mount;
2433
2434 #if 0
2435 DPRINTF(("puffs_lock: lock %p, args 0x%x\n", vp, ap->a_flags));
2436 #endif
2437
2438 /*
2439 * XXX: this avoids deadlocking when we're suspending.
2440 * e.g. some ops holding the vnode lock might be blocked for
2441 * the vfs transaction lock so we'd deadlock.
2442 *
2443 * Now once again this is skating on the thin ice of modern life,
2444 * since we are breaking the consistency guarantee provided
2445 * _to the user server_ by vnode locking. Hopefully this will
2446 * get fixed soon enough by getting rid of the dependency on
2447 * vnode locks alltogether.
2448 */
2449 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2450 if (ap->a_flags & LK_INTERLOCK)
2451 simple_unlock(&vp->v_interlock);
2452 return 0;
2453 }
2454
2455 return lockmgr(&vp->v_lock, ap->a_flags, &vp->v_interlock);
2456 }
2457
2458 int
2459 puffs_unlock(void *v)
2460 {
2461 struct vop_unlock_args /* {
2462 struct vnode *a_vp;
2463 int a_flags;
2464 } */ *ap = v;
2465 struct vnode *vp = ap->a_vp;
2466 struct mount *mp = vp->v_mount;
2467
2468 #if 0
2469 DPRINTF(("puffs_unlock: lock %p, args 0x%x\n", vp, ap->a_flags));
2470 #endif
2471
2472 /* XXX: see puffs_lock() */
2473 if (fstrans_is_owner(mp) && fstrans_getstate(mp) == FSTRANS_SUSPENDING){
2474 if (ap->a_flags & LK_INTERLOCK)
2475 simple_unlock(&vp->v_interlock);
2476 return 0;
2477 }
2478
2479 return lockmgr(&vp->v_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock);
2480 }
2481
2482 int
2483 puffs_islocked(void *v)
2484 {
2485 struct vop_islocked_args *ap = v;
2486 int rv;
2487
2488 rv = lockstatus(&ap->a_vp->v_lock);
2489 return rv;
2490 }
2491
2492 int
2493 puffs_generic(void *v)
2494 {
2495 struct vop_generic_args *ap = v;
2496
2497 (void)ap;
2498 DPRINTF(("puffs_generic: ap->a_desc = %s\n", ap->a_desc->vdesc_name));
2499
2500 return EOPNOTSUPP;
2501 }
2502
2503
2504 /*
2505 * spec & fifo. These call the miscfs spec and fifo vectors, but issue
2506 * FAF update information for the puffs node first.
2507 */
2508 int
2509 puffs_spec_read(void *v)
2510 {
2511 struct vop_read_args /* {
2512 const struct vnodeop_desc *a_desc;
2513 struct vnode *a_vp;
2514 struct uio *a_uio;
2515 int a_ioflag;
2516 kauth_cred_t a_cred;
2517 } */ *ap = v;
2518
2519 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2520 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
2521 }
2522
2523 int
2524 puffs_spec_write(void *v)
2525 {
2526 struct vop_write_args /* {
2527 const struct vnodeop_desc *a_desc;
2528 struct vnode *a_vp;
2529 struct uio *a_uio;
2530 int a_ioflag;
2531 kauth_cred_t a_cred;
2532 }*/ *ap = v;
2533
2534 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2535 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
2536 }
2537
2538 int
2539 puffs_fifo_read(void *v)
2540 {
2541 struct vop_read_args /* {
2542 const struct vnodeop_desc *a_desc;
2543 struct vnode *a_vp;
2544 struct uio *a_uio;
2545 int a_ioflag;
2546 kauth_cred_t a_cred;
2547 } */ *ap = v;
2548
2549 puffs_updatenode(ap->a_vp, PUFFS_UPDATEATIME);
2550 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
2551 }
2552
2553 int
2554 puffs_fifo_write(void *v)
2555 {
2556 struct vop_write_args /* {
2557 const struct vnodeop_desc *a_desc;
2558 struct vnode *a_vp;
2559 struct uio *a_uio;
2560 int a_ioflag;
2561 kauth_cred_t a_cred;
2562 }*/ *ap = v;
2563
2564 puffs_updatenode(ap->a_vp, PUFFS_UPDATEMTIME);
2565 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
2566 }
2567