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