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