puffs_vnops.c revision 1.173 1 /* $NetBSD: puffs_vnops.c,v 1.173 2012/08/10 14:52:56 manu 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.173 2012/08/10 14:52:56 manu Exp $");
34
35 #include <sys/param.h>
36 #include <sys/buf.h>
37 #include <sys/lockf.h>
38 #include <sys/malloc.h>
39 #include <sys/mount.h>
40 #include <sys/namei.h>
41 #include <sys/vnode.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h> /* For hz, hardclock_ticks */
44
45 #include <uvm/uvm.h>
46
47 #include <fs/puffs/puffs_msgif.h>
48 #include <fs/puffs/puffs_sys.h>
49
50 #include <miscfs/fifofs/fifo.h>
51 #include <miscfs/genfs/genfs.h>
52 #include <miscfs/specfs/specdev.h>
53
54 int puffs_vnop_lookup(void *);
55 int puffs_vnop_create(void *);
56 int puffs_vnop_access(void *);
57 int puffs_vnop_mknod(void *);
58 int puffs_vnop_open(void *);
59 int puffs_vnop_close(void *);
60 int puffs_vnop_getattr(void *);
61 int puffs_vnop_setattr(void *);
62 int puffs_vnop_reclaim(void *);
63 int puffs_vnop_readdir(void *);
64 int puffs_vnop_poll(void *);
65 int puffs_vnop_fsync(void *);
66 int puffs_vnop_seek(void *);
67 int puffs_vnop_remove(void *);
68 int puffs_vnop_mkdir(void *);
69 int puffs_vnop_rmdir(void *);
70 int puffs_vnop_link(void *);
71 int puffs_vnop_readlink(void *);
72 int puffs_vnop_symlink(void *);
73 int puffs_vnop_rename(void *);
74 int puffs_vnop_read(void *);
75 int puffs_vnop_write(void *);
76 int puffs_vnop_fcntl(void *);
77 int puffs_vnop_ioctl(void *);
78 int puffs_vnop_inactive(void *);
79 int puffs_vnop_print(void *);
80 int puffs_vnop_pathconf(void *);
81 int puffs_vnop_advlock(void *);
82 int puffs_vnop_strategy(void *);
83 int puffs_vnop_bmap(void *);
84 int puffs_vnop_mmap(void *);
85 int puffs_vnop_getpages(void *);
86 int puffs_vnop_abortop(void *);
87 int puffs_vnop_getextattr(void *);
88 int puffs_vnop_setextattr(void *);
89 int puffs_vnop_listextattr(void *);
90 int puffs_vnop_deleteextattr(void *);
91
92 int puffs_vnop_spec_read(void *);
93 int puffs_vnop_spec_write(void *);
94 int puffs_vnop_fifo_read(void *);
95 int puffs_vnop_fifo_write(void *);
96
97 int puffs_vnop_checkop(void *);
98
99 #define puffs_vnop_lock genfs_lock
100 #define puffs_vnop_unlock genfs_unlock
101 #define puffs_vnop_islocked genfs_islocked
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_advlock }, /* advlock */
130 { &vop_strategy_desc, puffs_vnop_strategy }, /* REAL strategy */
131 { &vop_revoke_desc, genfs_revoke }, /* REAL revoke */
132 { &vop_abortop_desc, puffs_vnop_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 { &vop_getextattr_desc, puffs_vnop_getextattr }, /* getextattr */
144 { &vop_setextattr_desc, puffs_vnop_setextattr }, /* setextattr */
145 { &vop_listextattr_desc, puffs_vnop_listextattr }, /* listextattr */
146 { &vop_deleteextattr_desc, puffs_vnop_deleteextattr },/* deleteextattr */
147 #if 0
148 { &vop_openextattr_desc, puffs_vnop_checkop }, /* openextattr */
149 { &vop_closeextattr_desc, puffs_vnop_checkop }, /* closeextattr */
150 #endif
151 { &vop_kqfilter_desc, genfs_eopnotsupp }, /* kqfilter XXX */
152 { NULL, NULL }
153 };
154 const struct vnodeopv_desc puffs_vnodeop_opv_desc =
155 { &puffs_vnodeop_p, puffs_vnodeop_entries };
156
157
158 int (**puffs_specop_p)(void *);
159 const struct vnodeopv_entry_desc puffs_specop_entries[] = {
160 { &vop_default_desc, vn_default_error },
161 { &vop_lookup_desc, spec_lookup }, /* lookup, ENOTDIR */
162 { &vop_create_desc, spec_create }, /* genfs_badop */
163 { &vop_mknod_desc, spec_mknod }, /* genfs_badop */
164 { &vop_open_desc, spec_open }, /* spec_open */
165 { &vop_close_desc, spec_close }, /* spec_close */
166 { &vop_access_desc, puffs_vnop_checkop }, /* access */
167 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */
168 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */
169 { &vop_read_desc, puffs_vnop_spec_read }, /* update, read */
170 { &vop_write_desc, puffs_vnop_spec_write }, /* update, write */
171 { &vop_ioctl_desc, spec_ioctl }, /* spec_ioctl */
172 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
173 { &vop_poll_desc, spec_poll }, /* spec_poll */
174 { &vop_kqfilter_desc, spec_kqfilter }, /* spec_kqfilter */
175 { &vop_revoke_desc, spec_revoke }, /* genfs_revoke */
176 { &vop_mmap_desc, spec_mmap }, /* spec_mmap */
177 { &vop_fsync_desc, spec_fsync }, /* vflushbuf */
178 { &vop_seek_desc, spec_seek }, /* genfs_nullop */
179 { &vop_remove_desc, spec_remove }, /* genfs_badop */
180 { &vop_link_desc, spec_link }, /* genfs_badop */
181 { &vop_rename_desc, spec_rename }, /* genfs_badop */
182 { &vop_mkdir_desc, spec_mkdir }, /* genfs_badop */
183 { &vop_rmdir_desc, spec_rmdir }, /* genfs_badop */
184 { &vop_symlink_desc, spec_symlink }, /* genfs_badop */
185 { &vop_readdir_desc, spec_readdir }, /* genfs_badop */
186 { &vop_readlink_desc, spec_readlink }, /* genfs_badop */
187 { &vop_abortop_desc, spec_abortop }, /* genfs_badop */
188 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */
189 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */
190 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */
191 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */
192 { &vop_bmap_desc, spec_bmap }, /* dummy */
193 { &vop_strategy_desc, spec_strategy }, /* dev strategy */
194 { &vop_print_desc, puffs_vnop_print }, /* REAL print */
195 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */
196 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
197 { &vop_advlock_desc, spec_advlock }, /* lf_advlock */
198 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
199 { &vop_getpages_desc, spec_getpages }, /* genfs_getpages */
200 { &vop_putpages_desc, spec_putpages }, /* genfs_putpages */
201 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */
202 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */
203 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */
204 { &vop_deleteextattr_desc, puffs_vnop_checkop },/* deleteextattr */
205 #if 0
206 { &vop_openextattr_desc, _openextattr }, /* openextattr */
207 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
208 #endif
209 { NULL, NULL }
210 };
211 const struct vnodeopv_desc puffs_specop_opv_desc =
212 { &puffs_specop_p, puffs_specop_entries };
213
214
215 int (**puffs_fifoop_p)(void *);
216 const struct vnodeopv_entry_desc puffs_fifoop_entries[] = {
217 { &vop_default_desc, vn_default_error },
218 { &vop_lookup_desc, vn_fifo_bypass }, /* lookup, ENOTDIR */
219 { &vop_create_desc, vn_fifo_bypass }, /* genfs_badop */
220 { &vop_mknod_desc, vn_fifo_bypass }, /* genfs_badop */
221 { &vop_open_desc, vn_fifo_bypass }, /* open */
222 { &vop_close_desc, vn_fifo_bypass }, /* close */
223 { &vop_access_desc, puffs_vnop_checkop }, /* access */
224 { &vop_getattr_desc, puffs_vnop_checkop }, /* getattr */
225 { &vop_setattr_desc, puffs_vnop_checkop }, /* setattr */
226 { &vop_read_desc, puffs_vnop_fifo_read }, /* read, update */
227 { &vop_write_desc, puffs_vnop_fifo_write }, /* write, update */
228 { &vop_ioctl_desc, vn_fifo_bypass }, /* ioctl */
229 { &vop_fcntl_desc, genfs_fcntl }, /* dummy */
230 { &vop_poll_desc, vn_fifo_bypass }, /* poll */
231 { &vop_kqfilter_desc, vn_fifo_bypass }, /* kqfilter */
232 { &vop_revoke_desc, vn_fifo_bypass }, /* genfs_revoke */
233 { &vop_mmap_desc, vn_fifo_bypass }, /* genfs_badop */
234 { &vop_fsync_desc, vn_fifo_bypass }, /* genfs_nullop*/
235 { &vop_seek_desc, vn_fifo_bypass }, /* genfs_badop */
236 { &vop_remove_desc, vn_fifo_bypass }, /* genfs_badop */
237 { &vop_link_desc, vn_fifo_bypass }, /* genfs_badop */
238 { &vop_rename_desc, vn_fifo_bypass }, /* genfs_badop */
239 { &vop_mkdir_desc, vn_fifo_bypass }, /* genfs_badop */
240 { &vop_rmdir_desc, vn_fifo_bypass }, /* genfs_badop */
241 { &vop_symlink_desc, vn_fifo_bypass }, /* genfs_badop */
242 { &vop_readdir_desc, vn_fifo_bypass }, /* genfs_badop */
243 { &vop_readlink_desc, vn_fifo_bypass }, /* genfs_badop */
244 { &vop_abortop_desc, vn_fifo_bypass }, /* genfs_badop */
245 { &vop_inactive_desc, puffs_vnop_inactive }, /* REAL inactive */
246 { &vop_reclaim_desc, puffs_vnop_reclaim }, /* REAL reclaim */
247 { &vop_lock_desc, puffs_vnop_lock }, /* REAL lock */
248 { &vop_unlock_desc, puffs_vnop_unlock }, /* REAL unlock */
249 { &vop_bmap_desc, vn_fifo_bypass }, /* dummy */
250 { &vop_strategy_desc, vn_fifo_bypass }, /* genfs_badop */
251 { &vop_print_desc, puffs_vnop_print }, /* REAL print */
252 { &vop_islocked_desc, puffs_vnop_islocked }, /* REAL islocked */
253 { &vop_pathconf_desc, vn_fifo_bypass }, /* pathconf */
254 { &vop_advlock_desc, vn_fifo_bypass }, /* genfs_einval */
255 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
256 { &vop_putpages_desc, vn_fifo_bypass }, /* genfs_null_putpages*/
257 #if 0
258 { &vop_openextattr_desc, _openextattr }, /* openextattr */
259 { &vop_closeextattr_desc, _closeextattr }, /* closeextattr */
260 #endif
261 { &vop_getextattr_desc, puffs_vnop_checkop }, /* getextattr */
262 { &vop_setextattr_desc, puffs_vnop_checkop }, /* setextattr */
263 { &vop_listextattr_desc, puffs_vnop_checkop }, /* listextattr */
264 { &vop_deleteextattr_desc, puffs_vnop_checkop }, /* deleteextattr */
265 { NULL, NULL }
266 };
267 const struct vnodeopv_desc puffs_fifoop_opv_desc =
268 { &puffs_fifoop_p, puffs_fifoop_entries };
269
270
271 /* "real" vnode operations */
272 int (**puffs_msgop_p)(void *);
273 const struct vnodeopv_entry_desc puffs_msgop_entries[] = {
274 { &vop_default_desc, vn_default_error },
275 { &vop_create_desc, puffs_vnop_create }, /* create */
276 { &vop_mknod_desc, puffs_vnop_mknod }, /* mknod */
277 { &vop_open_desc, puffs_vnop_open }, /* open */
278 { &vop_close_desc, puffs_vnop_close }, /* close */
279 { &vop_access_desc, puffs_vnop_access }, /* access */
280 { &vop_getattr_desc, puffs_vnop_getattr }, /* getattr */
281 { &vop_setattr_desc, puffs_vnop_setattr }, /* setattr */
282 { &vop_read_desc, puffs_vnop_read }, /* read */
283 { &vop_write_desc, puffs_vnop_write }, /* write */
284 { &vop_seek_desc, puffs_vnop_seek }, /* seek */
285 { &vop_remove_desc, puffs_vnop_remove }, /* remove */
286 { &vop_link_desc, puffs_vnop_link }, /* link */
287 { &vop_rename_desc, puffs_vnop_rename }, /* rename */
288 { &vop_mkdir_desc, puffs_vnop_mkdir }, /* mkdir */
289 { &vop_rmdir_desc, puffs_vnop_rmdir }, /* rmdir */
290 { &vop_symlink_desc, puffs_vnop_symlink }, /* symlink */
291 { &vop_readdir_desc, puffs_vnop_readdir }, /* readdir */
292 { &vop_readlink_desc, puffs_vnop_readlink }, /* readlink */
293 { &vop_print_desc, puffs_vnop_print }, /* print */
294 { &vop_islocked_desc, puffs_vnop_islocked }, /* islocked */
295 { &vop_pathconf_desc, puffs_vnop_pathconf }, /* pathconf */
296 { &vop_getpages_desc, puffs_vnop_getpages }, /* getpages */
297 { NULL, NULL }
298 };
299 const struct vnodeopv_desc puffs_msgop_opv_desc =
300 { &puffs_msgop_p, puffs_msgop_entries };
301
302 /*
303 * for dosetattr / update_va
304 */
305 #define SETATTR_CHSIZE 0x01
306 #define SETATTR_ASYNC 0x02
307
308 #define ERROUT(err) \
309 do { \
310 error = err; \
311 goto out; \
312 } while (/*CONSTCOND*/0)
313
314 /*
315 * This is a generic vnode operation handler. It checks if the necessary
316 * operations for the called vnode operation are implemented by userspace
317 * and either returns a dummy return value or proceeds to call the real
318 * vnode operation from puffs_msgop_v.
319 *
320 * XXX: this should described elsewhere and autogenerated, the complexity
321 * of the vnode operations vectors and their interrelationships is also
322 * getting a bit out of hand. Another problem is that we need this same
323 * information in the fs server code, so keeping the two in sync manually
324 * is not a viable (long term) plan.
325 */
326
327 /* not supported, handle locking protocol */
328 #define CHECKOP_NOTSUPP(op) \
329 case VOP_##op##_DESCOFFSET: \
330 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
331 return genfs_eopnotsupp(v); \
332 break
333
334 /* always succeed, no locking */
335 #define CHECKOP_SUCCESS(op) \
336 case VOP_##op##_DESCOFFSET: \
337 if (pmp->pmp_vnopmask[PUFFS_VN_##op] == 0) \
338 return 0; \
339 break
340
341 int
342 puffs_vnop_checkop(void *v)
343 {
344 struct vop_generic_args /* {
345 struct vnodeop_desc *a_desc;
346 spooky mystery contents;
347 } */ *ap = v;
348 struct vnodeop_desc *desc = ap->a_desc;
349 struct puffs_mount *pmp;
350 struct vnode *vp;
351 int offset, rv;
352
353 offset = ap->a_desc->vdesc_vp_offsets[0];
354 #ifdef DIAGNOSTIC
355 if (offset == VDESC_NO_OFFSET)
356 panic("puffs_checkop: no vnode, why did you call me?");
357 #endif
358 vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
359 pmp = MPTOPUFFSMP(vp->v_mount);
360
361 DPRINTF_VERBOSE(("checkop call %s (%d), vp %p\n",
362 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp));
363
364 if (!ALLOPS(pmp)) {
365 switch (desc->vdesc_offset) {
366 CHECKOP_NOTSUPP(CREATE);
367 CHECKOP_NOTSUPP(MKNOD);
368 CHECKOP_NOTSUPP(GETATTR);
369 CHECKOP_NOTSUPP(SETATTR);
370 CHECKOP_NOTSUPP(READ);
371 CHECKOP_NOTSUPP(WRITE);
372 CHECKOP_NOTSUPP(FCNTL);
373 CHECKOP_NOTSUPP(IOCTL);
374 CHECKOP_NOTSUPP(REMOVE);
375 CHECKOP_NOTSUPP(LINK);
376 CHECKOP_NOTSUPP(RENAME);
377 CHECKOP_NOTSUPP(MKDIR);
378 CHECKOP_NOTSUPP(RMDIR);
379 CHECKOP_NOTSUPP(SYMLINK);
380 CHECKOP_NOTSUPP(READDIR);
381 CHECKOP_NOTSUPP(READLINK);
382 CHECKOP_NOTSUPP(PRINT);
383 CHECKOP_NOTSUPP(PATHCONF);
384 CHECKOP_NOTSUPP(GETEXTATTR);
385 CHECKOP_NOTSUPP(SETEXTATTR);
386 CHECKOP_NOTSUPP(LISTEXTATTR);
387 CHECKOP_NOTSUPP(DELETEEXTATTR);
388
389 CHECKOP_SUCCESS(ACCESS);
390 CHECKOP_SUCCESS(CLOSE);
391 CHECKOP_SUCCESS(SEEK);
392
393 case VOP_GETPAGES_DESCOFFSET:
394 if (!EXISTSOP(pmp, READ))
395 return genfs_eopnotsupp(v);
396 break;
397
398 default:
399 panic("puffs_checkop: unhandled vnop %d",
400 desc->vdesc_offset);
401 }
402 }
403
404 rv = VOCALL(puffs_msgop_p, ap->a_desc->vdesc_offset, v);
405
406 DPRINTF_VERBOSE(("checkop return %s (%d), vp %p: %d\n",
407 ap->a_desc->vdesc_name, ap->a_desc->vdesc_offset, vp, rv));
408
409 return rv;
410 }
411
412 static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
413 struct componentname *);
414 static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
415 struct componentname *);
416 static void callinactive(struct puffs_mount *, puffs_cookie_t, int);
417 static void callreclaim(struct puffs_mount *, puffs_cookie_t, int);
418 static int flushvncache(struct vnode *, off_t, off_t, bool);
419 static void update_va(struct vnode *, struct vattr *, struct vattr *,
420 struct timespec *, struct timespec *, int);
421
422
423 #define PUFFS_ABORT_LOOKUP 1
424 #define PUFFS_ABORT_CREATE 2
425 #define PUFFS_ABORT_MKNOD 3
426 #define PUFFS_ABORT_MKDIR 4
427 #define PUFFS_ABORT_SYMLINK 5
428
429 /*
430 * Press the pani^Wabort button! Kernel resource allocation failed.
431 */
432 static void
433 puffs_abortbutton(struct puffs_mount *pmp, int what,
434 puffs_cookie_t dck, puffs_cookie_t ck, struct componentname *cnp)
435 {
436
437 switch (what) {
438 case PUFFS_ABORT_CREATE:
439 case PUFFS_ABORT_MKNOD:
440 case PUFFS_ABORT_SYMLINK:
441 callremove(pmp, dck, ck, cnp);
442 break;
443 case PUFFS_ABORT_MKDIR:
444 callrmdir(pmp, dck, ck, cnp);
445 break;
446 }
447
448 callinactive(pmp, ck, 0);
449 callreclaim(pmp, ck, 1);
450 }
451
452 /*
453 * Begin vnode operations.
454 *
455 * A word from the keymaster about locks: generally we don't want
456 * to use the vnode locks at all: it creates an ugly dependency between
457 * the userlandia file server and the kernel. But we'll play along with
458 * the kernel vnode locks for now. However, even currently we attempt
459 * to release locks as early as possible. This is possible for some
460 * operations which a) don't need a locked vnode after the userspace op
461 * and b) return with the vnode unlocked. Theoretically we could
462 * unlock-do op-lock for others and order the graph in userspace, but I
463 * don't want to think of the consequences for the time being.
464 */
465
466 #define TTL_TO_TIMEOUT(ts) \
467 (hardclock_ticks + (ts->tv_sec * hz) + (ts->tv_nsec * hz / 1000000000))
468 #define TTL_VALID(ts) \
469 ((ts != NULL) && !((ts->tv_sec == 0) && (ts->tv_nsec == 0)))
470 #define TIMED_OUT(expire) \
471 ((int)((unsigned int)hardclock_ticks - (unsigned int)expire) > 0)
472 int
473 puffs_vnop_lookup(void *v)
474 {
475 struct vop_lookup_args /* {
476 const struct vnodeop_desc *a_desc;
477 struct vnode *a_dvp;
478 struct vnode **a_vpp;
479 struct componentname *a_cnp;
480 } */ *ap = v;
481 PUFFS_MSG_VARS(vn, lookup);
482 struct puffs_mount *pmp;
483 struct componentname *cnp;
484 struct vnode *vp, *dvp, *cvp;
485 struct puffs_node *dpn, *cpn;
486 int isdot;
487 int error;
488
489 pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
490 cnp = ap->a_cnp;
491 dvp = ap->a_dvp;
492 cvp = NULL;
493 cpn = NULL;
494 *ap->a_vpp = NULL;
495
496 /* r/o fs? we check create later to handle EEXIST */
497 if ((cnp->cn_flags & ISLASTCN)
498 && (dvp->v_mount->mnt_flag & MNT_RDONLY)
499 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
500 return EROFS;
501
502 isdot = cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.';
503
504 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p, op: %x\n",
505 cnp->cn_nameptr, dvp, cnp->cn_nameiop));
506
507 /*
508 * Check if someone fed it into the cache
509 */
510 if (!isdot && PUFFS_USE_NAMECACHE(pmp)) {
511 error = cache_lookup(dvp, ap->a_vpp, cnp);
512
513 if ((error == 0) && PUFFS_USE_FS_TTL(pmp)) {
514 cvp = *ap->a_vpp;
515 cpn = VPTOPP(cvp);
516
517 if (TIMED_OUT(cpn->pn_cn_timeout)) {
518 cache_purge(cvp);
519 /*
520 * cached vnode (cvp) is still locked
521 * so that we can reuse it upon a new
522 * successful lookup.
523 */
524 *ap->a_vpp = NULL;
525 error = -1;
526 }
527 }
528
529 /*
530 * Do not use negative caching, since the filesystem
531 * provides no TTL for it.
532 */
533 if ((error == ENOENT) && PUFFS_USE_FS_TTL(pmp))
534 error = -1;
535
536 if (error >= 0)
537 return error;
538 }
539
540 if (isdot) {
541 /* deal with rename lookup semantics */
542 if (cnp->cn_nameiop == RENAME && (cnp->cn_flags & ISLASTCN))
543 return EISDIR;
544
545 vp = ap->a_dvp;
546 vref(vp);
547 *ap->a_vpp = vp;
548 return 0;
549 }
550
551 if (cvp != NULL)
552 mutex_enter(&cpn->pn_sizemtx);
553
554 PUFFS_MSG_ALLOC(vn, lookup);
555 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
556 cnp, PUFFS_USE_FULLPNBUF(pmp));
557
558 if (cnp->cn_flags & ISDOTDOT)
559 VOP_UNLOCK(dvp);
560
561 puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
562 PUFFS_VN_LOOKUP, VPTOPNC(dvp));
563 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
564 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
565
566 /*
567 * In case of error, there is no new vnode to play with, so be
568 * happy with the NULL value given to vpp in the beginning.
569 * Also, check if this really was an error or the target was not
570 * present. Either treat it as a non-error for CREATE/RENAME or
571 * enter the component into the negative name cache (if desired).
572 */
573 if (error) {
574 error = checkerr(pmp, error, __func__);
575 if (error == ENOENT) {
576 /* don't allow to create files on r/o fs */
577 if ((dvp->v_mount->mnt_flag & MNT_RDONLY)
578 && cnp->cn_nameiop == CREATE) {
579 error = EROFS;
580
581 /* adjust values if we are creating */
582 } else if ((cnp->cn_flags & ISLASTCN)
583 && (cnp->cn_nameiop == CREATE
584 || cnp->cn_nameiop == RENAME)) {
585 error = EJUSTRETURN;
586
587 /* save negative cache entry */
588 } else {
589 if (PUFFS_USE_NAMECACHE(pmp) &&
590 !PUFFS_USE_FS_TTL(pmp))
591 cache_enter(dvp, NULL, cnp);
592 }
593 }
594 goto out;
595 }
596
597 /*
598 * Check that we don't get our parent node back, that would cause
599 * a pretty obvious deadlock.
600 */
601 dpn = dvp->v_data;
602 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
603 puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
604 "lookup produced parent cookie", lookup_msg->pvnr_newnode);
605 error = EPROTO;
606 goto out;
607 }
608
609 /*
610 * Check if we looked up the cached vnode
611 */
612 vp = NULL;
613 if (cvp && (VPTOPP(cvp)->pn_cookie == lookup_msg->pvnr_newnode)) {
614 int grace;
615
616 /*
617 * Bump grace time of this node so that it does not get
618 * reclaimed too fast. We try to increase a bit more the
619 * lifetime of busiest * nodes - with some limits.
620 */
621 grace = 10 * puffs_sopreq_expire_timeout;
622 cpn->pn_cn_grace = hardclock_ticks + grace;
623 vp = cvp;
624 }
625
626 /*
627 * No cached vnode available, or the cached vnode does not
628 * match the userland cookie anymore: is the node known?
629 */
630 if (vp == NULL) {
631 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode,
632 1, 1, &vp);
633 }
634
635 if (error == PUFFS_NOSUCHCOOKIE) {
636 error = puffs_getvnode(dvp->v_mount,
637 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
638 lookup_msg->pvnr_size, lookup_msg->pvnr_rdev, &vp);
639 if (error) {
640 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP,
641 VPTOPNC(dvp), lookup_msg->pvnr_newnode,
642 ap->a_cnp);
643 goto out;
644 }
645
646 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
647 } else if (error) {
648 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
649 lookup_msg->pvnr_newnode, ap->a_cnp);
650 goto out;
651 }
652
653 /*
654 * Update cache and TTL
655 */
656 if (PUFFS_USE_FS_TTL(pmp)) {
657 struct timespec *va_ttl = &lookup_msg->pvnr_va_ttl;
658 struct timespec *cn_ttl = &lookup_msg->pvnr_cn_ttl;
659 update_va(vp, NULL, &lookup_msg->pvnr_va,
660 va_ttl, cn_ttl, SETATTR_CHSIZE);
661 }
662
663 KASSERT(lookup_msg->pvnr_newnode == VPTOPP(vp)->pn_cookie);
664 *ap->a_vpp = vp;
665
666 if (PUFFS_USE_NAMECACHE(pmp))
667 cache_enter(dvp, vp, cnp);
668
669 /* XXX */
670 if ((lookup_msg->pvnr_cn.pkcn_flags & REQUIREDIR) == 0)
671 cnp->cn_flags &= ~REQUIREDIR;
672 if (lookup_msg->pvnr_cn.pkcn_consume)
673 cnp->cn_consume = MIN(lookup_msg->pvnr_cn.pkcn_consume,
674 strlen(cnp->cn_nameptr) - cnp->cn_namelen);
675
676 VPTOPP(vp)->pn_nlookup++;
677 out:
678 if (cvp != NULL) {
679 mutex_exit(&cpn->pn_sizemtx);
680
681 if (error || (cvp != vp))
682 vput(cvp);
683 }
684
685 if (cnp->cn_flags & ISDOTDOT)
686 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
687
688 DPRINTF(("puffs_lookup: returning %d %p\n", error, *ap->a_vpp));
689 PUFFS_MSG_RELEASE(lookup);
690 return error;
691 }
692
693 #define REFPN_AND_UNLOCKVP(a, b) \
694 do { \
695 mutex_enter(&b->pn_mtx); \
696 puffs_referencenode(b); \
697 mutex_exit(&b->pn_mtx); \
698 VOP_UNLOCK(a); \
699 } while (/*CONSTCOND*/0)
700
701 #define REFPN(b) \
702 do { \
703 mutex_enter(&b->pn_mtx); \
704 puffs_referencenode(b); \
705 mutex_exit(&b->pn_mtx); \
706 } while (/*CONSTCOND*/0)
707
708 #define RELEPN_AND_VP(a, b) \
709 do { \
710 puffs_releasenode(b); \
711 vrele(a); \
712 } while (/*CONSTCOND*/0)
713
714 int
715 puffs_vnop_create(void *v)
716 {
717 struct vop_create_args /* {
718 const struct vnodeop_desc *a_desc;
719 struct vnode *a_dvp;
720 struct vnode **a_vpp;
721 struct componentname *a_cnp;
722 struct vattr *a_vap;
723 } */ *ap = v;
724 PUFFS_MSG_VARS(vn, create);
725 struct vnode *dvp = ap->a_dvp;
726 struct puffs_node *dpn = VPTOPP(dvp);
727 struct componentname *cnp = ap->a_cnp;
728 struct mount *mp = dvp->v_mount;
729 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
730 int error;
731
732 DPRINTF(("puffs_create: dvp %p, cnp: %s\n",
733 dvp, ap->a_cnp->cn_nameptr));
734
735 PUFFS_MSG_ALLOC(vn, create);
736 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
737 cnp, PUFFS_USE_FULLPNBUF(pmp));
738 create_msg->pvnr_va = *ap->a_vap;
739 puffs_msg_setinfo(park_create, PUFFSOP_VN,
740 PUFFS_VN_CREATE, VPTOPNC(dvp));
741 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_create, dvp->v_data, NULL, error);
742
743 error = checkerr(pmp, error, __func__);
744 if (error)
745 goto out;
746
747 error = puffs_newnode(mp, dvp, ap->a_vpp,
748 create_msg->pvnr_newnode, cnp, ap->a_vap->va_type, 0);
749 if (error) {
750 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie,
751 create_msg->pvnr_newnode, cnp);
752 goto out;
753 }
754
755 if (PUFFS_USE_FS_TTL(pmp)) {
756 struct timespec *va_ttl = &create_msg->pvnr_va_ttl;
757 struct timespec *cn_ttl = &create_msg->pvnr_cn_ttl;
758 struct vattr *rvap = &create_msg->pvnr_va;
759
760 update_va(*ap->a_vpp, NULL, rvap,
761 va_ttl, cn_ttl, SETATTR_CHSIZE);
762 }
763
764 VPTOPP(*ap->a_vpp)->pn_nlookup++;
765
766 out:
767 vput(dvp);
768
769 DPRINTF(("puffs_create: return %d\n", error));
770 PUFFS_MSG_RELEASE(create);
771 return error;
772 }
773
774 int
775 puffs_vnop_mknod(void *v)
776 {
777 struct vop_mknod_args /* {
778 const struct vnodeop_desc *a_desc;
779 struct vnode *a_dvp;
780 struct vnode **a_vpp;
781 struct componentname *a_cnp;
782 struct vattr *a_vap;
783 } */ *ap = v;
784 PUFFS_MSG_VARS(vn, mknod);
785 struct vnode *dvp = ap->a_dvp;
786 struct puffs_node *dpn = VPTOPP(dvp);
787 struct componentname *cnp = ap->a_cnp;
788 struct mount *mp = dvp->v_mount;
789 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
790 int error;
791
792 PUFFS_MSG_ALLOC(vn, mknod);
793 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
794 cnp, PUFFS_USE_FULLPNBUF(pmp));
795 mknod_msg->pvnr_va = *ap->a_vap;
796 puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
797 PUFFS_VN_MKNOD, VPTOPNC(dvp));
798
799 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);
800
801 error = checkerr(pmp, error, __func__);
802 if (error)
803 goto out;
804
805 error = puffs_newnode(mp, dvp, ap->a_vpp,
806 mknod_msg->pvnr_newnode, cnp, ap->a_vap->va_type,
807 ap->a_vap->va_rdev);
808 if (error) {
809 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
810 mknod_msg->pvnr_newnode, cnp);
811 goto out;
812 }
813
814 if (PUFFS_USE_FS_TTL(pmp)) {
815 struct timespec *va_ttl = &mknod_msg->pvnr_va_ttl;
816 struct timespec *cn_ttl = &mknod_msg->pvnr_cn_ttl;
817 struct vattr *rvap = &mknod_msg->pvnr_va;
818
819 update_va(*ap->a_vpp, NULL, rvap,
820 va_ttl, cn_ttl, SETATTR_CHSIZE);
821 }
822
823 VPTOPP(*ap->a_vpp)->pn_nlookup++;
824
825 out:
826 vput(dvp);
827 PUFFS_MSG_RELEASE(mknod);
828 return error;
829 }
830
831 int
832 puffs_vnop_open(void *v)
833 {
834 struct vop_open_args /* {
835 const struct vnodeop_desc *a_desc;
836 struct vnode *a_vp;
837 int a_mode;
838 kauth_cred_t a_cred;
839 } */ *ap = v;
840 PUFFS_MSG_VARS(vn, open);
841 struct vnode *vp = ap->a_vp;
842 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
843 int mode = ap->a_mode;
844 int error;
845
846 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
847
848 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
849 ERROUT(EROFS);
850
851 if (!EXISTSOP(pmp, OPEN))
852 ERROUT(0);
853
854 PUFFS_MSG_ALLOC(vn, open);
855 open_msg->pvnr_mode = mode;
856 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
857 puffs_msg_setinfo(park_open, PUFFSOP_VN,
858 PUFFS_VN_OPEN, VPTOPNC(vp));
859
860 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
861 error = checkerr(pmp, error, __func__);
862
863 out:
864 DPRINTF(("puffs_open: returning %d\n", error));
865 PUFFS_MSG_RELEASE(open);
866 return error;
867 }
868
869 int
870 puffs_vnop_close(void *v)
871 {
872 struct vop_close_args /* {
873 const struct vnodeop_desc *a_desc;
874 struct vnode *a_vp;
875 int a_fflag;
876 kauth_cred_t a_cred;
877 } */ *ap = v;
878 PUFFS_MSG_VARS(vn, close);
879 struct vnode *vp = ap->a_vp;
880 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
881
882 PUFFS_MSG_ALLOC(vn, close);
883 puffs_msg_setfaf(park_close);
884 close_msg->pvnr_fflag = ap->a_fflag;
885 puffs_credcvt(&close_msg->pvnr_cred, ap->a_cred);
886 puffs_msg_setinfo(park_close, PUFFSOP_VN,
887 PUFFS_VN_CLOSE, VPTOPNC(vp));
888
889 puffs_msg_enqueue(pmp, park_close);
890 PUFFS_MSG_RELEASE(close);
891 return 0;
892 }
893
894 int
895 puffs_vnop_access(void *v)
896 {
897 struct vop_access_args /* {
898 const struct vnodeop_desc *a_desc;
899 struct vnode *a_vp;
900 int a_mode;
901 kauth_cred_t a_cred;
902 } */ *ap = v;
903 PUFFS_MSG_VARS(vn, access);
904 struct vnode *vp = ap->a_vp;
905 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
906 int mode = ap->a_mode;
907 int error;
908
909 if (mode & VWRITE) {
910 switch (vp->v_type) {
911 case VDIR:
912 case VLNK:
913 case VREG:
914 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
915 || !EXISTSOP(pmp, WRITE))
916 return EROFS;
917 break;
918 default:
919 break;
920 }
921 }
922
923 if (!EXISTSOP(pmp, ACCESS))
924 return 0;
925
926 PUFFS_MSG_ALLOC(vn, access);
927 access_msg->pvnr_mode = ap->a_mode;
928 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
929 puffs_msg_setinfo(park_access, PUFFSOP_VN,
930 PUFFS_VN_ACCESS, VPTOPNC(vp));
931
932 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
933 error = checkerr(pmp, error, __func__);
934 PUFFS_MSG_RELEASE(access);
935
936 return error;
937 }
938
939 static void
940 update_va(struct vnode *vp, struct vattr *vap, struct vattr *rvap,
941 struct timespec *va_ttl, struct timespec *cn_ttl, int flags)
942 {
943 struct puffs_node *pn = VPTOPP(vp);
944
945 if (TTL_VALID(cn_ttl)) {
946 pn->pn_cn_timeout = TTL_TO_TIMEOUT(cn_ttl);
947 pn->pn_cn_grace = MAX(pn->pn_cn_timeout, pn->pn_cn_grace);
948 }
949
950 /*
951 * Don't listen to the file server regarding special device
952 * size info, the file server doesn't know anything about them.
953 */
954 if (vp->v_type == VBLK || vp->v_type == VCHR)
955 rvap->va_size = vp->v_size;
956
957 /* Ditto for blocksize (ufs comment: this doesn't belong here) */
958 if (vp->v_type == VBLK)
959 rvap->va_blocksize = BLKDEV_IOSIZE;
960 else if (vp->v_type == VCHR)
961 rvap->va_blocksize = MAXBSIZE;
962
963 if (vap != NULL) {
964 (void) memcpy(vap, rvap, sizeof(struct vattr));
965 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
966
967 if (pn->pn_stat & PNODE_METACACHE_ATIME)
968 vap->va_atime = pn->pn_mc_atime;
969 if (pn->pn_stat & PNODE_METACACHE_CTIME)
970 vap->va_ctime = pn->pn_mc_ctime;
971 if (pn->pn_stat & PNODE_METACACHE_MTIME)
972 vap->va_mtime = pn->pn_mc_mtime;
973 if (pn->pn_stat & PNODE_METACACHE_SIZE)
974 vap->va_size = pn->pn_mc_size;
975 }
976
977 if (!(pn->pn_stat & PNODE_METACACHE_SIZE) && (flags & SETATTR_CHSIZE)) {
978 if (rvap->va_size != VNOVAL
979 && vp->v_type != VBLK && vp->v_type != VCHR) {
980 uvm_vnp_setsize(vp, rvap->va_size);
981 pn->pn_serversize = rvap->va_size;
982 }
983 }
984
985 if ((va_ttl != NULL) && TTL_VALID(va_ttl)) {
986 if (pn->pn_va_cache == NULL)
987 pn->pn_va_cache = pool_get(&puffs_vapool, PR_WAITOK);
988
989 (void)memcpy(pn->pn_va_cache, rvap, sizeof(*rvap));
990
991 pn->pn_va_timeout = TTL_TO_TIMEOUT(va_ttl);
992 }
993 }
994
995 int
996 puffs_vnop_getattr(void *v)
997 {
998 struct vop_getattr_args /* {
999 const struct vnodeop_desc *a_desc;
1000 struct vnode *a_vp;
1001 struct vattr *a_vap;
1002 kauth_cred_t a_cred;
1003 } */ *ap = v;
1004 PUFFS_MSG_VARS(vn, getattr);
1005 struct vnode *vp = ap->a_vp;
1006 struct mount *mp = vp->v_mount;
1007 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1008 struct vattr *vap, *rvap;
1009 struct puffs_node *pn = VPTOPP(vp);
1010 struct timespec *va_ttl = NULL;
1011 int error = 0;
1012
1013 /*
1014 * A lock is required so that we do not race with
1015 * setattr, write and fsync when changing vp->v_size.
1016 * This is critical, since setting a stall smaler value
1017 * triggers a file truncate in uvm_vnp_setsize(), which
1018 * most of the time means data corruption (a chunk of
1019 * data is replaced by zeroes). This can be removed if
1020 * we decide one day that VOP_GETATTR must operate on
1021 * a locked vnode.
1022 *
1023 * XXX Should be useless now that VOP_GETATTR has been
1024 * fixed to always require a shared lock at least.
1025 */
1026 mutex_enter(&pn->pn_sizemtx);
1027
1028 REFPN(pn);
1029 vap = ap->a_vap;
1030
1031 if (PUFFS_USE_FS_TTL(pmp)) {
1032 if (!TIMED_OUT(pn->pn_va_timeout)) {
1033 update_va(vp, vap, pn->pn_va_cache,
1034 NULL, NULL, SETATTR_CHSIZE);
1035 goto out2;
1036 }
1037 }
1038
1039 PUFFS_MSG_ALLOC(vn, getattr);
1040 vattr_null(&getattr_msg->pvnr_va);
1041 puffs_credcvt(&getattr_msg->pvnr_cred, ap->a_cred);
1042 puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
1043 PUFFS_VN_GETATTR, VPTOPNC(vp));
1044
1045 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
1046 error = checkerr(pmp, error, __func__);
1047 if (error)
1048 goto out;
1049
1050 rvap = &getattr_msg->pvnr_va;
1051
1052 if (PUFFS_USE_FS_TTL(pmp))
1053 va_ttl = &getattr_msg->pvnr_va_ttl;
1054
1055 update_va(vp, vap, rvap, va_ttl, NULL, SETATTR_CHSIZE);
1056
1057 out:
1058 PUFFS_MSG_RELEASE(getattr);
1059
1060 out2:
1061 puffs_releasenode(pn);
1062
1063 mutex_exit(&pn->pn_sizemtx);
1064
1065 return error;
1066 }
1067
1068 static int
1069 dosetattr(struct vnode *vp, struct vattr *vap, kauth_cred_t cred, int flags)
1070 {
1071 PUFFS_MSG_VARS(vn, setattr);
1072 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1073 struct puffs_node *pn = vp->v_data;
1074 int error = 0;
1075
1076 KASSERT(!(flags & SETATTR_CHSIZE) || mutex_owned(&pn->pn_sizemtx));
1077
1078 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
1079 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
1080 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
1081 || vap->va_mode != (mode_t)VNOVAL))
1082 return EROFS;
1083
1084 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
1085 && vp->v_type == VREG && vap->va_size != VNOVAL)
1086 return EROFS;
1087
1088 /*
1089 * Flush metacache first. If we are called with some explicit
1090 * parameters, treat them as information overriding metacache
1091 * information.
1092 */
1093 if (pn->pn_stat & PNODE_METACACHE_MASK) {
1094 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
1095 && vap->va_atime.tv_sec == VNOVAL)
1096 vap->va_atime = pn->pn_mc_atime;
1097 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
1098 && vap->va_ctime.tv_sec == VNOVAL)
1099 vap->va_ctime = pn->pn_mc_ctime;
1100 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
1101 && vap->va_mtime.tv_sec == VNOVAL)
1102 vap->va_mtime = pn->pn_mc_mtime;
1103 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
1104 && vap->va_size == VNOVAL)
1105 vap->va_size = pn->pn_mc_size;
1106
1107 pn->pn_stat &= ~PNODE_METACACHE_MASK;
1108 }
1109
1110 /*
1111 * Flush attribute cache so that another thread do
1112 * not get a stale value during the operation.
1113 */
1114 if (PUFFS_USE_FS_TTL(pmp))
1115 pn->pn_va_timeout = 0;
1116
1117 PUFFS_MSG_ALLOC(vn, setattr);
1118 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
1119 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
1120 puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
1121 PUFFS_VN_SETATTR, VPTOPNC(vp));
1122 if (flags & SETATTR_ASYNC)
1123 puffs_msg_setfaf(park_setattr);
1124
1125 puffs_msg_enqueue(pmp, park_setattr);
1126 if ((flags & SETATTR_ASYNC) == 0)
1127 error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
1128
1129 if ((error == 0) && PUFFS_USE_FS_TTL(pmp)) {
1130 struct timespec *va_ttl = &setattr_msg->pvnr_va_ttl;
1131 struct vattr *rvap = &setattr_msg->pvnr_va;
1132
1133 update_va(vp, NULL, rvap, va_ttl, NULL, flags);
1134 }
1135
1136 PUFFS_MSG_RELEASE(setattr);
1137 if ((flags & SETATTR_ASYNC) == 0) {
1138 error = checkerr(pmp, error, __func__);
1139 if (error)
1140 return error;
1141 } else {
1142 error = 0;
1143 }
1144
1145 if (vap->va_size != VNOVAL) {
1146 pn->pn_serversize = vap->va_size;
1147 if (flags & SETATTR_CHSIZE)
1148 uvm_vnp_setsize(vp, vap->va_size);
1149 }
1150
1151 return 0;
1152 }
1153
1154 int
1155 puffs_vnop_setattr(void *v)
1156 {
1157 struct vop_getattr_args /* {
1158 const struct vnodeop_desc *a_desc;
1159 struct vnode *a_vp;
1160 struct vattr *a_vap;
1161 kauth_cred_t a_cred;
1162 } */ *ap = v;
1163 struct puffs_node *pn = ap->a_vp->v_data;
1164 int error;
1165
1166 mutex_enter(&pn->pn_sizemtx);
1167 error = dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
1168 mutex_exit(&pn->pn_sizemtx);
1169
1170 return error;
1171 }
1172
1173 static __inline int
1174 doinact(struct puffs_mount *pmp, int iaflag)
1175 {
1176
1177 if (EXISTSOP(pmp, INACTIVE))
1178 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
1179 if (iaflag || ALLOPS(pmp))
1180 return 1;
1181 else
1182 return 0;
1183 else
1184 return 1;
1185 else
1186 return 0;
1187 }
1188
1189 static void
1190 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
1191 {
1192 int error;
1193 PUFFS_MSG_VARS(vn, inactive);
1194
1195 if (doinact(pmp, iaflag)) {
1196 PUFFS_MSG_ALLOC(vn, inactive);
1197 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1198 PUFFS_VN_INACTIVE, ck);
1199
1200 PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
1201 PUFFS_MSG_RELEASE(inactive);
1202 }
1203 }
1204
1205 /* XXX: callinactive can't setback */
1206 int
1207 puffs_vnop_inactive(void *v)
1208 {
1209 struct vop_inactive_args /* {
1210 const struct vnodeop_desc *a_desc;
1211 struct vnode *a_vp;
1212 } */ *ap = v;
1213 PUFFS_MSG_VARS(vn, inactive);
1214 struct vnode *vp = ap->a_vp;
1215 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1216 struct puffs_node *pnode;
1217 bool recycle = false;
1218 int error;
1219
1220 pnode = vp->v_data;
1221 mutex_enter(&pnode->pn_sizemtx);
1222
1223 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
1224 flushvncache(vp, 0, 0, false);
1225 PUFFS_MSG_ALLOC(vn, inactive);
1226 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
1227 PUFFS_VN_INACTIVE, VPTOPNC(vp));
1228
1229 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_inactive, vp->v_data,
1230 NULL, error);
1231 PUFFS_MSG_RELEASE(inactive);
1232 }
1233 pnode->pn_stat &= ~PNODE_DOINACT;
1234
1235 /*
1236 * file server thinks it's gone? then don't be afraid care,
1237 * node's life was already all it would ever be
1238 */
1239 if (pnode->pn_stat & PNODE_NOREFS) {
1240 pnode->pn_stat |= PNODE_DYING;
1241 recycle = true;
1242 }
1243
1244 /*
1245 * Handle node TTL.
1246 * If grace has already timed out, make it reclaimed.
1247 * Otherwise, we queue its expiration by sop thread, so
1248 * that it does not remain for ages in the freelist,
1249 * holding memory in userspace, while we will have
1250 * to look it up again anyway.
1251 */
1252 if (PUFFS_USE_FS_TTL(pmp) && !(vp->v_vflag & VV_ROOT) && !recycle) {
1253 bool incache = !TIMED_OUT(pnode->pn_cn_timeout);
1254 bool ingrace = !TIMED_OUT(pnode->pn_cn_grace);
1255 bool reclaimqueued = pnode->pn_stat & PNODE_SOPEXP;
1256
1257 if (!incache && !ingrace && !reclaimqueued) {
1258 pnode->pn_stat |= PNODE_DYING;
1259 recycle = true;
1260 }
1261
1262 if (!recycle && !reclaimqueued) {
1263 struct puffs_sopreq *psopr;
1264 int at = MAX(pnode->pn_cn_grace, pnode->pn_cn_timeout);
1265
1266 KASSERT(curlwp != uvm.pagedaemon_lwp);
1267 psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
1268 psopr->psopr_ck = VPTOPNC(pnode->pn_vp);
1269 psopr->psopr_sopreq = PUFFS_SOPREQ_EXPIRE;
1270 psopr->psopr_at = at;
1271
1272 mutex_enter(&pmp->pmp_sopmtx);
1273
1274 /*
1275 * If thread has disapeared, just give up. The
1276 * fs is being unmounted and the node will be
1277 * be reclaimed anyway.
1278 *
1279 * Otherwise, we queue the request but do not
1280 * immediatly signal the thread, as the node
1281 * has not been expired yet.
1282 */
1283 if (pmp->pmp_sopthrcount == 0) {
1284 kmem_free(psopr, sizeof(*psopr));
1285 } else {
1286 TAILQ_INSERT_TAIL(&pmp->pmp_sopnodereqs,
1287 psopr, psopr_entries);
1288 pnode->pn_stat |= PNODE_SOPEXP;
1289 }
1290
1291 mutex_exit(&pmp->pmp_sopmtx);
1292 }
1293 }
1294
1295 *ap->a_recycle = recycle;
1296
1297 mutex_exit(&pnode->pn_sizemtx);
1298 VOP_UNLOCK(vp);
1299
1300 return 0;
1301 }
1302
1303 static void
1304 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck, int nlookup)
1305 {
1306 PUFFS_MSG_VARS(vn, reclaim);
1307
1308 if (!EXISTSOP(pmp, RECLAIM))
1309 return;
1310
1311 PUFFS_MSG_ALLOC(vn, reclaim);
1312 reclaim_msg->pvnr_nlookup = nlookup;
1313 puffs_msg_setfaf(park_reclaim);
1314 puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
1315
1316 puffs_msg_enqueue(pmp, park_reclaim);
1317 PUFFS_MSG_RELEASE(reclaim);
1318 return;
1319 }
1320
1321 /*
1322 * always FAF, we don't really care if the server wants to fail to
1323 * reclaim the node or not
1324 */
1325 int
1326 puffs_vnop_reclaim(void *v)
1327 {
1328 struct vop_reclaim_args /* {
1329 const struct vnodeop_desc *a_desc;
1330 struct vnode *a_vp;
1331 } */ *ap = v;
1332 struct vnode *vp = ap->a_vp;
1333 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1334 struct puffs_node *pnode = vp->v_data;
1335 bool notifyserver = true;
1336
1337 /*
1338 * first things first: check if someone is trying to reclaim the
1339 * root vnode. do not allow that to travel to userspace.
1340 * Note that we don't need to take the lock similarly to
1341 * puffs_root(), since there is only one of us.
1342 */
1343 if (vp->v_vflag & VV_ROOT) {
1344 mutex_enter(&pmp->pmp_lock);
1345 KASSERT(pmp->pmp_root != NULL);
1346 pmp->pmp_root = NULL;
1347 mutex_exit(&pmp->pmp_lock);
1348 notifyserver = false;
1349 }
1350
1351 /*
1352 * purge info from kernel before issueing FAF, since we
1353 * don't really know when we'll get around to it after
1354 * that and someone might race us into node creation
1355 */
1356 mutex_enter(&pmp->pmp_lock);
1357 LIST_REMOVE(pnode, pn_hashent);
1358 if (PUFFS_USE_NAMECACHE(pmp))
1359 cache_purge(vp);
1360 mutex_exit(&pmp->pmp_lock);
1361
1362 if (notifyserver) {
1363 int nlookup = VPTOPP(vp)->pn_nlookup;
1364
1365 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp), nlookup);
1366 }
1367
1368 puffs_putvnode(vp);
1369 vp->v_data = NULL;
1370
1371 return 0;
1372 }
1373
1374 #define CSIZE sizeof(**ap->a_cookies)
1375 int
1376 puffs_vnop_readdir(void *v)
1377 {
1378 struct vop_readdir_args /* {
1379 const struct vnodeop_desc *a_desc;
1380 struct vnode *a_vp;
1381 struct uio *a_uio;
1382 kauth_cred_t a_cred;
1383 int *a_eofflag;
1384 off_t **a_cookies;
1385 int *a_ncookies;
1386 } */ *ap = v;
1387 PUFFS_MSG_VARS(vn, readdir);
1388 struct vnode *vp = ap->a_vp;
1389 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1390 size_t argsize, tomove, cookiemem, cookiesmax;
1391 struct uio *uio = ap->a_uio;
1392 size_t howmuch, resid;
1393 int error;
1394
1395 /*
1396 * ok, so we need: resid + cookiemem = maxreq
1397 * => resid + cookiesize * (resid/minsize) = maxreq
1398 * => resid + cookiesize/minsize * resid = maxreq
1399 * => (cookiesize/minsize + 1) * resid = maxreq
1400 * => resid = maxreq / (cookiesize/minsize + 1)
1401 *
1402 * Since cookiesize <= minsize and we're not very big on floats,
1403 * we approximate that to be 1. Therefore:
1404 *
1405 * resid = maxreq / 2;
1406 *
1407 * Well, at least we didn't have to use differential equations
1408 * or the Gram-Schmidt process.
1409 *
1410 * (yes, I'm very afraid of this)
1411 */
1412 KASSERT(CSIZE <= _DIRENT_MINSIZE((struct dirent *)0));
1413
1414 if (ap->a_cookies) {
1415 KASSERT(ap->a_ncookies != NULL);
1416 if (pmp->pmp_args.pa_fhsize == 0)
1417 return EOPNOTSUPP;
1418 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
1419 cookiesmax = resid/_DIRENT_MINSIZE((struct dirent *)0);
1420 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
1421 } else {
1422 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
1423 cookiesmax = 0;
1424 cookiemem = 0;
1425 }
1426
1427 argsize = sizeof(struct puffs_vnmsg_readdir);
1428 tomove = resid + cookiemem;
1429 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
1430 (void *)&readdir_msg, 1);
1431
1432 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
1433 readdir_msg->pvnr_offset = uio->uio_offset;
1434 readdir_msg->pvnr_resid = resid;
1435 readdir_msg->pvnr_ncookies = cookiesmax;
1436 readdir_msg->pvnr_eofflag = 0;
1437 readdir_msg->pvnr_dentoff = cookiemem;
1438 puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
1439 PUFFS_VN_READDIR, VPTOPNC(vp));
1440 puffs_msg_setdelta(park_readdir, tomove);
1441
1442 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
1443 error = checkerr(pmp, error, __func__);
1444 if (error)
1445 goto out;
1446
1447 /* userspace is cheating? */
1448 if (readdir_msg->pvnr_resid > resid) {
1449 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1450 "resid grew", VPTOPNC(vp));
1451 ERROUT(EPROTO);
1452 }
1453 if (readdir_msg->pvnr_ncookies > cookiesmax) {
1454 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
1455 "too many cookies", VPTOPNC(vp));
1456 ERROUT(EPROTO);
1457 }
1458
1459 /* check eof */
1460 if (readdir_msg->pvnr_eofflag)
1461 *ap->a_eofflag = 1;
1462
1463 /* bouncy-wouncy with the directory data */
1464 howmuch = resid - readdir_msg->pvnr_resid;
1465
1466 /* force eof if no data was returned (getcwd() needs this) */
1467 if (howmuch == 0) {
1468 *ap->a_eofflag = 1;
1469 goto out;
1470 }
1471
1472 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
1473 if (error)
1474 goto out;
1475
1476 /* provide cookies to caller if so desired */
1477 if (ap->a_cookies) {
1478 KASSERT(curlwp != uvm.pagedaemon_lwp);
1479 *ap->a_cookies = malloc(readdir_msg->pvnr_ncookies*CSIZE,
1480 M_TEMP, M_WAITOK);
1481 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
1482 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
1483 *ap->a_ncookies*CSIZE);
1484 }
1485
1486 /* next readdir starts here */
1487 uio->uio_offset = readdir_msg->pvnr_offset;
1488
1489 out:
1490 puffs_msgmem_release(park_readdir);
1491 return error;
1492 }
1493 #undef CSIZE
1494
1495 /*
1496 * poll works by consuming the bitmask in pn_revents. If there are
1497 * events available, poll returns immediately. If not, it issues a
1498 * poll to userspace, selrecords itself and returns with no available
1499 * events. When the file server returns, it executes puffs_parkdone_poll(),
1500 * where available events are added to the bitmask. selnotify() is
1501 * then also executed by that function causing us to enter here again
1502 * and hopefully find the missing bits (unless someone got them first,
1503 * in which case it starts all over again).
1504 */
1505 int
1506 puffs_vnop_poll(void *v)
1507 {
1508 struct vop_poll_args /* {
1509 const struct vnodeop_desc *a_desc;
1510 struct vnode *a_vp;
1511 int a_events;
1512 } */ *ap = v;
1513 PUFFS_MSG_VARS(vn, poll);
1514 struct vnode *vp = ap->a_vp;
1515 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1516 struct puffs_node *pn = vp->v_data;
1517 int events, error;
1518
1519 if (EXISTSOP(pmp, POLL)) {
1520 mutex_enter(&pn->pn_mtx);
1521 events = pn->pn_revents & ap->a_events;
1522 if (events & ap->a_events) {
1523 pn->pn_revents &= ~ap->a_events;
1524 mutex_exit(&pn->pn_mtx);
1525
1526 return events;
1527 } else {
1528 puffs_referencenode(pn);
1529 mutex_exit(&pn->pn_mtx);
1530
1531 PUFFS_MSG_ALLOC(vn, poll);
1532 poll_msg->pvnr_events = ap->a_events;
1533 puffs_msg_setinfo(park_poll, PUFFSOP_VN,
1534 PUFFS_VN_POLL, VPTOPNC(vp));
1535 puffs_msg_setcall(park_poll, puffs_parkdone_poll, pn);
1536 selrecord(curlwp, &pn->pn_sel);
1537
1538 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_poll, vp->v_data,
1539 NULL, error);
1540 PUFFS_MSG_RELEASE(poll);
1541
1542 return 0;
1543 }
1544 } else {
1545 return genfs_poll(v);
1546 }
1547 }
1548
1549 static int
1550 flushvncache(struct vnode *vp, off_t offlo, off_t offhi, bool wait)
1551 {
1552 struct puffs_node *pn = VPTOPP(vp);
1553 struct vattr va;
1554 int pflags, error;
1555
1556 /* flush out information from our metacache, see vop_setattr */
1557 if (pn->pn_stat & PNODE_METACACHE_MASK
1558 && (pn->pn_stat & PNODE_DYING) == 0) {
1559 vattr_null(&va);
1560 error = dosetattr(vp, &va, FSCRED,
1561 SETATTR_CHSIZE | (wait ? 0 : SETATTR_ASYNC));
1562 if (error)
1563 return error;
1564 }
1565
1566 /*
1567 * flush pages to avoid being overly dirty
1568 */
1569 pflags = PGO_CLEANIT;
1570 if (wait)
1571 pflags |= PGO_SYNCIO;
1572
1573 mutex_enter(vp->v_interlock);
1574 return VOP_PUTPAGES(vp, trunc_page(offlo), round_page(offhi), pflags);
1575 }
1576
1577 int
1578 puffs_vnop_fsync(void *v)
1579 {
1580 struct vop_fsync_args /* {
1581 const struct vnodeop_desc *a_desc;
1582 struct vnode *a_vp;
1583 kauth_cred_t a_cred;
1584 int a_flags;
1585 off_t a_offlo;
1586 off_t a_offhi;
1587 } */ *ap = v;
1588 PUFFS_MSG_VARS(vn, fsync);
1589 struct vnode *vp;
1590 struct puffs_node *pn;
1591 struct puffs_mount *pmp;
1592 int error, dofaf;
1593
1594 vp = ap->a_vp;
1595 KASSERT(vp != NULL);
1596 pn = VPTOPP(vp);
1597 KASSERT(pn != NULL);
1598 pmp = MPTOPUFFSMP(vp->v_mount);
1599 if (ap->a_flags & FSYNC_WAIT) {
1600 mutex_enter(&pn->pn_sizemtx);
1601 } else {
1602 if (mutex_tryenter(&pn->pn_sizemtx) == 0)
1603 return EDEADLK;
1604 }
1605
1606 error = flushvncache(vp, ap->a_offlo, ap->a_offhi,
1607 (ap->a_flags & FSYNC_WAIT) == FSYNC_WAIT);
1608 if (error)
1609 goto out;
1610
1611 /*
1612 * HELLO! We exit already here if the user server does not
1613 * support fsync OR if we should call fsync for a node which
1614 * has references neither in the kernel or the fs server.
1615 * Otherwise we continue to issue fsync() forward.
1616 */
1617 error = 0;
1618 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
1619 goto out;
1620
1621 dofaf = (ap->a_flags & FSYNC_WAIT) == 0 || ap->a_flags == FSYNC_LAZY;
1622 /*
1623 * We abuse VXLOCK to mean "vnode is going to die", so we issue
1624 * only FAFs for those. Otherwise there's a danger of deadlock,
1625 * since the execution context here might be the user server
1626 * doing some operation on another fs, which in turn caused a
1627 * vnode to be reclaimed from the freelist for this fs.
1628 */
1629 if (dofaf == 0) {
1630 mutex_enter(vp->v_interlock);
1631 if (vp->v_iflag & VI_XLOCK)
1632 dofaf = 1;
1633 mutex_exit(vp->v_interlock);
1634 }
1635
1636 PUFFS_MSG_ALLOC(vn, fsync);
1637 if (dofaf)
1638 puffs_msg_setfaf(park_fsync);
1639
1640 puffs_credcvt(&fsync_msg->pvnr_cred, ap->a_cred);
1641 fsync_msg->pvnr_flags = ap->a_flags;
1642 fsync_msg->pvnr_offlo = ap->a_offlo;
1643 fsync_msg->pvnr_offhi = ap->a_offhi;
1644 puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
1645 PUFFS_VN_FSYNC, VPTOPNC(vp));
1646
1647 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
1648 PUFFS_MSG_RELEASE(fsync);
1649
1650 error = checkerr(pmp, error, __func__);
1651
1652 out:
1653 mutex_exit(&pn->pn_sizemtx);
1654 return error;
1655 }
1656
1657 int
1658 puffs_vnop_seek(void *v)
1659 {
1660 struct vop_seek_args /* {
1661 const struct vnodeop_desc *a_desc;
1662 struct vnode *a_vp;
1663 off_t a_oldoff;
1664 off_t a_newoff;
1665 kauth_cred_t a_cred;
1666 } */ *ap = v;
1667 PUFFS_MSG_VARS(vn, seek);
1668 struct vnode *vp = ap->a_vp;
1669 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1670 int error;
1671
1672 PUFFS_MSG_ALLOC(vn, seek);
1673 seek_msg->pvnr_oldoff = ap->a_oldoff;
1674 seek_msg->pvnr_newoff = ap->a_newoff;
1675 puffs_credcvt(&seek_msg->pvnr_cred, ap->a_cred);
1676 puffs_msg_setinfo(park_seek, PUFFSOP_VN,
1677 PUFFS_VN_SEEK, VPTOPNC(vp));
1678
1679 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_seek, vp->v_data, NULL, error);
1680 PUFFS_MSG_RELEASE(seek);
1681 return checkerr(pmp, error, __func__);
1682 }
1683
1684 static int
1685 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1686 struct componentname *cnp)
1687 {
1688 PUFFS_MSG_VARS(vn, remove);
1689 int error;
1690
1691 PUFFS_MSG_ALLOC(vn, remove);
1692 remove_msg->pvnr_cookie_targ = ck;
1693 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1694 cnp, PUFFS_USE_FULLPNBUF(pmp));
1695 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
1696
1697 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
1698 PUFFS_MSG_RELEASE(remove);
1699
1700 return checkerr(pmp, error, __func__);
1701 }
1702
1703 /*
1704 * XXX: can't use callremove now because can't catch setbacks with
1705 * it due to lack of a pnode argument.
1706 */
1707 int
1708 puffs_vnop_remove(void *v)
1709 {
1710 struct vop_remove_args /* {
1711 const struct vnodeop_desc *a_desc;
1712 struct vnode *a_dvp;
1713 struct vnode *a_vp;
1714 struct componentname *a_cnp;
1715 } */ *ap = v;
1716 PUFFS_MSG_VARS(vn, remove);
1717 struct vnode *dvp = ap->a_dvp;
1718 struct vnode *vp = ap->a_vp;
1719 struct puffs_node *dpn = VPTOPP(dvp);
1720 struct puffs_node *pn = VPTOPP(vp);
1721 struct componentname *cnp = ap->a_cnp;
1722 struct mount *mp = dvp->v_mount;
1723 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1724 int error;
1725
1726 PUFFS_MSG_ALLOC(vn, remove);
1727 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
1728 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
1729 cnp, PUFFS_USE_FULLPNBUF(pmp));
1730 puffs_msg_setinfo(park_remove, PUFFSOP_VN,
1731 PUFFS_VN_REMOVE, VPTOPNC(dvp));
1732
1733 puffs_msg_enqueue(pmp, park_remove);
1734 REFPN_AND_UNLOCKVP(dvp, dpn);
1735 if (dvp == vp)
1736 REFPN(pn);
1737 else
1738 REFPN_AND_UNLOCKVP(vp, pn);
1739 error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
1740
1741 PUFFS_MSG_RELEASE(remove);
1742
1743 RELEPN_AND_VP(dvp, dpn);
1744 RELEPN_AND_VP(vp, pn);
1745
1746 error = checkerr(pmp, error, __func__);
1747 return error;
1748 }
1749
1750 int
1751 puffs_vnop_mkdir(void *v)
1752 {
1753 struct vop_mkdir_args /* {
1754 const struct vnodeop_desc *a_desc;
1755 struct vnode *a_dvp;
1756 struct vnode **a_vpp;
1757 struct componentname *a_cnp;
1758 struct vattr *a_vap;
1759 } */ *ap = v;
1760 PUFFS_MSG_VARS(vn, mkdir);
1761 struct vnode *dvp = ap->a_dvp;
1762 struct puffs_node *dpn = VPTOPP(dvp);
1763 struct componentname *cnp = ap->a_cnp;
1764 struct mount *mp = dvp->v_mount;
1765 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
1766 int error;
1767
1768 PUFFS_MSG_ALLOC(vn, mkdir);
1769 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1770 cnp, PUFFS_USE_FULLPNBUF(pmp));
1771 mkdir_msg->pvnr_va = *ap->a_vap;
1772 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1773 PUFFS_VN_MKDIR, VPTOPNC(dvp));
1774
1775 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1776
1777 error = checkerr(pmp, error, __func__);
1778 if (error)
1779 goto out;
1780
1781 error = puffs_newnode(mp, dvp, ap->a_vpp,
1782 mkdir_msg->pvnr_newnode, cnp, VDIR, 0);
1783 if (error) {
1784 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1785 mkdir_msg->pvnr_newnode, cnp);
1786 goto out;
1787 }
1788
1789 if (PUFFS_USE_FS_TTL(pmp)) {
1790 struct timespec *va_ttl = &mkdir_msg->pvnr_va_ttl;
1791 struct timespec *cn_ttl = &mkdir_msg->pvnr_cn_ttl;
1792 struct vattr *rvap = &mkdir_msg->pvnr_va;
1793
1794 update_va(*ap->a_vpp, NULL, rvap,
1795 va_ttl, cn_ttl, SETATTR_CHSIZE);
1796 }
1797
1798 VPTOPP(*ap->a_vpp)->pn_nlookup++;
1799
1800 out:
1801 vput(dvp);
1802 PUFFS_MSG_RELEASE(mkdir);
1803 return error;
1804 }
1805
1806 static int
1807 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1808 struct componentname *cnp)
1809 {
1810 PUFFS_MSG_VARS(vn, rmdir);
1811 int error;
1812
1813 PUFFS_MSG_ALLOC(vn, rmdir);
1814 rmdir_msg->pvnr_cookie_targ = ck;
1815 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1816 cnp, PUFFS_USE_FULLPNBUF(pmp));
1817 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1818
1819 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1820 PUFFS_MSG_RELEASE(rmdir);
1821
1822 return checkerr(pmp, error, __func__);
1823 }
1824
1825 int
1826 puffs_vnop_rmdir(void *v)
1827 {
1828 struct vop_rmdir_args /* {
1829 const struct vnodeop_desc *a_desc;
1830 struct vnode *a_dvp;
1831 struct vnode *a_vp;
1832 struct componentname *a_cnp;
1833 } */ *ap = v;
1834 PUFFS_MSG_VARS(vn, rmdir);
1835 struct vnode *dvp = ap->a_dvp;
1836 struct vnode *vp = ap->a_vp;
1837 struct puffs_node *dpn = VPTOPP(dvp);
1838 struct puffs_node *pn = VPTOPP(vp);
1839 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1840 struct componentname *cnp = ap->a_cnp;
1841 int error;
1842
1843 PUFFS_MSG_ALLOC(vn, rmdir);
1844 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1845 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1846 cnp, PUFFS_USE_FULLPNBUF(pmp));
1847 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1848 PUFFS_VN_RMDIR, VPTOPNC(dvp));
1849
1850 puffs_msg_enqueue(pmp, park_rmdir);
1851 REFPN_AND_UNLOCKVP(dvp, dpn);
1852 REFPN_AND_UNLOCKVP(vp, pn);
1853 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1854
1855 PUFFS_MSG_RELEASE(rmdir);
1856
1857 /* XXX: some call cache_purge() *for both vnodes* here, investigate */
1858 RELEPN_AND_VP(dvp, dpn);
1859 RELEPN_AND_VP(vp, pn);
1860
1861 return error;
1862 }
1863
1864 int
1865 puffs_vnop_link(void *v)
1866 {
1867 struct vop_link_args /* {
1868 const struct vnodeop_desc *a_desc;
1869 struct vnode *a_dvp;
1870 struct vnode *a_vp;
1871 struct componentname *a_cnp;
1872 } */ *ap = v;
1873 PUFFS_MSG_VARS(vn, link);
1874 struct vnode *dvp = ap->a_dvp;
1875 struct vnode *vp = ap->a_vp;
1876 struct puffs_node *dpn = VPTOPP(dvp);
1877 struct puffs_node *pn = VPTOPP(vp);
1878 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1879 struct componentname *cnp = ap->a_cnp;
1880 int error;
1881
1882 PUFFS_MSG_ALLOC(vn, link);
1883 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1884 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1885 cnp, PUFFS_USE_FULLPNBUF(pmp));
1886 puffs_msg_setinfo(park_link, PUFFSOP_VN,
1887 PUFFS_VN_LINK, VPTOPNC(dvp));
1888
1889 puffs_msg_enqueue(pmp, park_link);
1890 REFPN_AND_UNLOCKVP(dvp, dpn);
1891 REFPN(pn);
1892 error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1893
1894 PUFFS_MSG_RELEASE(link);
1895
1896 error = checkerr(pmp, error, __func__);
1897
1898 /*
1899 * XXX: stay in touch with the cache. I don't like this, but
1900 * don't have a better solution either. See also puffs_rename().
1901 */
1902 if (error == 0)
1903 puffs_updatenode(pn, PUFFS_UPDATECTIME, 0);
1904
1905 RELEPN_AND_VP(dvp, dpn);
1906 puffs_releasenode(pn);
1907
1908 return error;
1909 }
1910
1911 int
1912 puffs_vnop_symlink(void *v)
1913 {
1914 struct vop_symlink_args /* {
1915 const struct vnodeop_desc *a_desc;
1916 struct vnode *a_dvp;
1917 struct vnode **a_vpp;
1918 struct componentname *a_cnp;
1919 struct vattr *a_vap;
1920 char *a_target;
1921 } */ *ap = v;
1922 PUFFS_MSG_VARS(vn, symlink);
1923 struct vnode *dvp = ap->a_dvp;
1924 struct puffs_node *dpn = VPTOPP(dvp);
1925 struct mount *mp = dvp->v_mount;
1926 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1927 struct componentname *cnp = ap->a_cnp;
1928 int error;
1929
1930 *ap->a_vpp = NULL;
1931
1932 PUFFS_MSG_ALLOC(vn, symlink);
1933 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1934 cnp, PUFFS_USE_FULLPNBUF(pmp));
1935 symlink_msg->pvnr_va = *ap->a_vap;
1936 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1937 sizeof(symlink_msg->pvnr_link));
1938 puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
1939 PUFFS_VN_SYMLINK, VPTOPNC(dvp));
1940
1941 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
1942
1943 error = checkerr(pmp, error, __func__);
1944 if (error)
1945 goto out;
1946
1947 error = puffs_newnode(mp, dvp, ap->a_vpp,
1948 symlink_msg->pvnr_newnode, cnp, VLNK, 0);
1949 if (error) {
1950 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
1951 symlink_msg->pvnr_newnode, cnp);
1952 goto out;
1953 }
1954
1955 if (PUFFS_USE_FS_TTL(pmp)) {
1956 struct timespec *va_ttl = &symlink_msg->pvnr_va_ttl;
1957 struct timespec *cn_ttl = &symlink_msg->pvnr_cn_ttl;
1958 struct vattr *rvap = &symlink_msg->pvnr_va;
1959
1960 update_va(*ap->a_vpp, NULL, rvap,
1961 va_ttl, cn_ttl, SETATTR_CHSIZE);
1962 }
1963
1964 VPTOPP(*ap->a_vpp)->pn_nlookup++;
1965
1966 out:
1967 vput(dvp);
1968 PUFFS_MSG_RELEASE(symlink);
1969
1970 return error;
1971 }
1972
1973 int
1974 puffs_vnop_readlink(void *v)
1975 {
1976 struct vop_readlink_args /* {
1977 const struct vnodeop_desc *a_desc;
1978 struct vnode *a_vp;
1979 struct uio *a_uio;
1980 kauth_cred_t a_cred;
1981 } */ *ap = v;
1982 PUFFS_MSG_VARS(vn, readlink);
1983 struct vnode *vp = ap->a_vp;
1984 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1985 size_t linklen;
1986 int error;
1987
1988 PUFFS_MSG_ALLOC(vn, readlink);
1989 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1990 linklen = sizeof(readlink_msg->pvnr_link);
1991 readlink_msg->pvnr_linklen = linklen;
1992 puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
1993 PUFFS_VN_READLINK, VPTOPNC(vp));
1994
1995 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
1996 error = checkerr(pmp, error, __func__);
1997 if (error)
1998 goto out;
1999
2000 /* bad bad user file server */
2001 if (readlink_msg->pvnr_linklen > linklen) {
2002 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
2003 "linklen too big", VPTOPNC(ap->a_vp));
2004 error = EPROTO;
2005 goto out;
2006 }
2007
2008 error = uiomove(&readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
2009 ap->a_uio);
2010 out:
2011 PUFFS_MSG_RELEASE(readlink);
2012 return error;
2013 }
2014
2015 int
2016 puffs_vnop_rename(void *v)
2017 {
2018 struct vop_rename_args /* {
2019 const struct vnodeop_desc *a_desc;
2020 struct vnode *a_fdvp;
2021 struct vnode *a_fvp;
2022 struct componentname *a_fcnp;
2023 struct vnode *a_tdvp;
2024 struct vnode *a_tvp;
2025 struct componentname *a_tcnp;
2026 } */ *ap = v;
2027 PUFFS_MSG_VARS(vn, rename);
2028 struct vnode *fdvp = ap->a_fdvp, *fvp = ap->a_fvp;
2029 struct vnode *tdvp = ap->a_tdvp, *tvp = ap->a_tvp;
2030 struct puffs_node *fpn = ap->a_fvp->v_data;
2031 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
2032 int error;
2033 bool doabort = true;
2034
2035 if ((fvp->v_mount != tdvp->v_mount) ||
2036 (tvp && (fvp->v_mount != tvp->v_mount))) {
2037 ERROUT(EXDEV);
2038 }
2039
2040 PUFFS_MSG_ALLOC(vn, rename);
2041 rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
2042 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
2043 if (tvp)
2044 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
2045 else
2046 rename_msg->pvnr_cookie_targ = NULL;
2047 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
2048 ap->a_fcnp, PUFFS_USE_FULLPNBUF(pmp));
2049 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
2050 ap->a_tcnp, PUFFS_USE_FULLPNBUF(pmp));
2051 puffs_msg_setinfo(park_rename, PUFFSOP_VN,
2052 PUFFS_VN_RENAME, VPTOPNC(fdvp));
2053
2054 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
2055 doabort = false;
2056 PUFFS_MSG_RELEASE(rename);
2057 error = checkerr(pmp, error, __func__);
2058
2059 /*
2060 * XXX: stay in touch with the cache. I don't like this, but
2061 * don't have a better solution either. See also puffs_link().
2062 */
2063 if (error == 0)
2064 puffs_updatenode(fpn, PUFFS_UPDATECTIME, 0);
2065
2066 out:
2067 if (doabort)
2068 VOP_ABORTOP(tdvp, ap->a_tcnp);
2069 if (tvp != NULL)
2070 vput(tvp);
2071 if (tdvp == tvp)
2072 vrele(tdvp);
2073 else
2074 vput(tdvp);
2075
2076 if (doabort)
2077 VOP_ABORTOP(fdvp, ap->a_fcnp);
2078 vrele(fdvp);
2079 vrele(fvp);
2080
2081 return error;
2082 }
2083
2084 #define RWARGS(cont, iofl, move, offset, creds) \
2085 (cont)->pvnr_ioflag = (iofl); \
2086 (cont)->pvnr_resid = (move); \
2087 (cont)->pvnr_offset = (offset); \
2088 puffs_credcvt(&(cont)->pvnr_cred, creds)
2089
2090 int
2091 puffs_vnop_read(void *v)
2092 {
2093 struct vop_read_args /* {
2094 const struct vnodeop_desc *a_desc;
2095 struct vnode *a_vp;
2096 struct uio *a_uio;
2097 int a_ioflag;
2098 kauth_cred_t a_cred;
2099 } */ *ap = v;
2100 PUFFS_MSG_VARS(vn, read);
2101 struct vnode *vp = ap->a_vp;
2102 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2103 struct uio *uio = ap->a_uio;
2104 size_t tomove, argsize;
2105 vsize_t bytelen;
2106 int error;
2107
2108 read_msg = NULL;
2109 error = 0;
2110
2111 /* std sanity */
2112 if (uio->uio_resid == 0)
2113 return 0;
2114 if (uio->uio_offset < 0)
2115 return EINVAL;
2116
2117 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
2118 const int advice = IO_ADV_DECODE(ap->a_ioflag);
2119
2120 while (uio->uio_resid > 0) {
2121 if (vp->v_size <= uio->uio_offset) {
2122 break;
2123 }
2124 bytelen = MIN(uio->uio_resid,
2125 vp->v_size - uio->uio_offset);
2126 if (bytelen == 0)
2127 break;
2128
2129 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
2130 UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp));
2131 if (error)
2132 break;
2133 }
2134
2135 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
2136 puffs_updatenode(VPTOPP(vp), PUFFS_UPDATEATIME, 0);
2137 } else {
2138 /*
2139 * in case it's not a regular file or we're operating
2140 * uncached, do read in the old-fashioned style,
2141 * i.e. explicit read operations
2142 */
2143
2144 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2145 argsize = sizeof(struct puffs_vnmsg_read);
2146 puffs_msgmem_alloc(argsize + tomove, &park_read,
2147 (void *)&read_msg, 1);
2148
2149 error = 0;
2150 while (uio->uio_resid > 0) {
2151 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2152 memset(read_msg, 0, argsize); /* XXX: touser KASSERT */
2153 RWARGS(read_msg, ap->a_ioflag, tomove,
2154 uio->uio_offset, ap->a_cred);
2155 puffs_msg_setinfo(park_read, PUFFSOP_VN,
2156 PUFFS_VN_READ, VPTOPNC(vp));
2157 puffs_msg_setdelta(park_read, tomove);
2158
2159 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_read, vp->v_data,
2160 NULL, error);
2161 error = checkerr(pmp, error, __func__);
2162 if (error)
2163 break;
2164
2165 if (read_msg->pvnr_resid > tomove) {
2166 puffs_senderr(pmp, PUFFS_ERR_READ,
2167 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2168 error = EPROTO;
2169 break;
2170 }
2171
2172 error = uiomove(read_msg->pvnr_data,
2173 tomove - read_msg->pvnr_resid, uio);
2174
2175 /*
2176 * in case the file is out of juice, resid from
2177 * userspace is != 0. and the error-case is
2178 * quite obvious
2179 */
2180 if (error || read_msg->pvnr_resid)
2181 break;
2182 }
2183
2184 puffs_msgmem_release(park_read);
2185 }
2186
2187 return error;
2188 }
2189
2190 /*
2191 * XXX: in case of a failure, this leaves uio in a bad state.
2192 * We could theoretically copy the uio and iovecs and "replay"
2193 * them the right amount after the userspace trip, but don't
2194 * bother for now.
2195 */
2196 int
2197 puffs_vnop_write(void *v)
2198 {
2199 struct vop_write_args /* {
2200 const struct vnodeop_desc *a_desc;
2201 struct vnode *a_vp;
2202 struct uio *a_uio;
2203 int a_ioflag;
2204 kauth_cred_t a_cred;
2205 } */ *ap = v;
2206 PUFFS_MSG_VARS(vn, write);
2207 struct vnode *vp = ap->a_vp;
2208 struct puffs_node *pn = VPTOPP(vp);
2209 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2210 struct uio *uio = ap->a_uio;
2211 size_t tomove, argsize;
2212 off_t oldoff, newoff, origoff;
2213 vsize_t bytelen;
2214 int error, uflags;
2215 int ubcflags;
2216
2217 error = uflags = 0;
2218 write_msg = NULL;
2219
2220 mutex_enter(&pn->pn_sizemtx);
2221
2222 if (vp->v_type == VREG && PUFFS_USE_PAGECACHE(pmp)) {
2223 ubcflags = UBC_WRITE | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp);
2224
2225 /*
2226 * userspace *should* be allowed to control this,
2227 * but with UBC it's a bit unclear how to handle it
2228 */
2229 if (ap->a_ioflag & IO_APPEND)
2230 uio->uio_offset = vp->v_size;
2231
2232 origoff = uio->uio_offset;
2233 while (uio->uio_resid > 0) {
2234 if (vp->v_mount->mnt_flag & MNT_RELATIME)
2235 uflags |= PUFFS_UPDATEATIME;
2236 uflags |= PUFFS_UPDATECTIME;
2237 uflags |= PUFFS_UPDATEMTIME;
2238 oldoff = uio->uio_offset;
2239 bytelen = uio->uio_resid;
2240
2241 newoff = oldoff + bytelen;
2242 if (vp->v_size < newoff) {
2243 uvm_vnp_setwritesize(vp, newoff);
2244 }
2245 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
2246 UVM_ADV_RANDOM, ubcflags);
2247
2248 /*
2249 * In case of a ubc_uiomove() error,
2250 * opt to not extend the file at all and
2251 * return an error. Otherwise, if we attempt
2252 * to clear the memory we couldn't fault to,
2253 * we might generate a kernel page fault.
2254 */
2255 if (vp->v_size < newoff) {
2256 if (error == 0) {
2257 uflags |= PUFFS_UPDATESIZE;
2258 uvm_vnp_setsize(vp, newoff);
2259 } else {
2260 uvm_vnp_setwritesize(vp, vp->v_size);
2261 }
2262 }
2263 if (error)
2264 break;
2265
2266 /*
2267 * If we're writing large files, flush to file server
2268 * every 64k. Otherwise we can very easily exhaust
2269 * kernel and user memory, as the file server cannot
2270 * really keep up with our writing speed.
2271 *
2272 * Note: this does *NOT* honor MNT_ASYNC, because
2273 * that gives userland too much say in the kernel.
2274 */
2275 if (oldoff >> 16 != uio->uio_offset >> 16) {
2276 mutex_enter(vp->v_interlock);
2277 error = VOP_PUTPAGES(vp, oldoff & ~0xffff,
2278 uio->uio_offset & ~0xffff,
2279 PGO_CLEANIT | PGO_SYNCIO);
2280 if (error)
2281 break;
2282 }
2283 }
2284
2285 /* synchronous I/O? */
2286 if (error == 0 && ap->a_ioflag & IO_SYNC) {
2287 mutex_enter(vp->v_interlock);
2288 error = VOP_PUTPAGES(vp, trunc_page(origoff),
2289 round_page(uio->uio_offset),
2290 PGO_CLEANIT | PGO_SYNCIO);
2291
2292 /* write through page cache? */
2293 } else if (error == 0 && pmp->pmp_flags & PUFFS_KFLAG_WTCACHE) {
2294 mutex_enter(vp->v_interlock);
2295 error = VOP_PUTPAGES(vp, trunc_page(origoff),
2296 round_page(uio->uio_offset), PGO_CLEANIT);
2297 }
2298
2299 puffs_updatenode(VPTOPP(vp), uflags, vp->v_size);
2300 } else {
2301 /* tomove is non-increasing */
2302 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2303 argsize = sizeof(struct puffs_vnmsg_write) + tomove;
2304 puffs_msgmem_alloc(argsize, &park_write, (void *)&write_msg,1);
2305
2306 while (uio->uio_resid > 0) {
2307 /* move data to buffer */
2308 tomove = PUFFS_TOMOVE(uio->uio_resid, pmp);
2309 memset(write_msg, 0, argsize); /* XXX: touser KASSERT */
2310 RWARGS(write_msg, ap->a_ioflag, tomove,
2311 uio->uio_offset, ap->a_cred);
2312 error = uiomove(write_msg->pvnr_data, tomove, uio);
2313 if (error)
2314 break;
2315
2316 /* move buffer to userspace */
2317 puffs_msg_setinfo(park_write, PUFFSOP_VN,
2318 PUFFS_VN_WRITE, VPTOPNC(vp));
2319 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_write, vp->v_data,
2320 NULL, error);
2321 error = checkerr(pmp, error, __func__);
2322 if (error)
2323 break;
2324
2325 if (write_msg->pvnr_resid > tomove) {
2326 puffs_senderr(pmp, PUFFS_ERR_WRITE,
2327 E2BIG, "resid grew", VPTOPNC(ap->a_vp));
2328 error = EPROTO;
2329 break;
2330 }
2331
2332 /* adjust file size */
2333 if (vp->v_size < uio->uio_offset)
2334 uvm_vnp_setsize(vp, uio->uio_offset);
2335
2336 /* didn't move everything? bad userspace. bail */
2337 if (write_msg->pvnr_resid != 0) {
2338 error = EIO;
2339 break;
2340 }
2341 }
2342 puffs_msgmem_release(park_write);
2343 }
2344
2345 mutex_exit(&pn->pn_sizemtx);
2346 return error;
2347 }
2348
2349 int
2350 puffs_vnop_print(void *v)
2351 {
2352 struct vop_print_args /* {
2353 struct vnode *a_vp;
2354 } */ *ap = v;
2355 PUFFS_MSG_VARS(vn, print);
2356 struct vnode *vp = ap->a_vp;
2357 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2358 struct puffs_node *pn = vp->v_data;
2359 int error;
2360
2361 /* kernel portion */
2362 printf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
2363 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
2364 if (vp->v_type == VFIFO)
2365 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
2366 printf("\n");
2367
2368 /* userspace portion */
2369 if (EXISTSOP(pmp, PRINT)) {
2370 PUFFS_MSG_ALLOC(vn, print);
2371 puffs_msg_setinfo(park_print, PUFFSOP_VN,
2372 PUFFS_VN_PRINT, VPTOPNC(vp));
2373 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
2374 NULL, error);
2375 PUFFS_MSG_RELEASE(print);
2376 }
2377
2378 return 0;
2379 }
2380
2381 int
2382 puffs_vnop_pathconf(void *v)
2383 {
2384 struct vop_pathconf_args /* {
2385 const struct vnodeop_desc *a_desc;
2386 struct vnode *a_vp;
2387 int a_name;
2388 register_t *a_retval;
2389 } */ *ap = v;
2390 PUFFS_MSG_VARS(vn, pathconf);
2391 struct vnode *vp = ap->a_vp;
2392 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2393 int error;
2394
2395 PUFFS_MSG_ALLOC(vn, pathconf);
2396 pathconf_msg->pvnr_name = ap->a_name;
2397 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
2398 PUFFS_VN_PATHCONF, VPTOPNC(vp));
2399 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
2400 error = checkerr(pmp, error, __func__);
2401 if (!error)
2402 *ap->a_retval = pathconf_msg->pvnr_retval;
2403 PUFFS_MSG_RELEASE(pathconf);
2404
2405 return error;
2406 }
2407
2408 int
2409 puffs_vnop_advlock(void *v)
2410 {
2411 struct vop_advlock_args /* {
2412 const struct vnodeop_desc *a_desc;
2413 struct vnode *a_vp;
2414 void *a_id;
2415 int a_op;
2416 struct flock *a_fl;
2417 int a_flags;
2418 } */ *ap = v;
2419 PUFFS_MSG_VARS(vn, advlock);
2420 struct vnode *vp = ap->a_vp;
2421 struct puffs_node *pn = VPTOPP(vp);
2422 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2423 int error;
2424
2425 if (!EXISTSOP(pmp, ADVLOCK))
2426 return lf_advlock(ap, &pn->pn_lockf, vp->v_size);
2427
2428 PUFFS_MSG_ALLOC(vn, advlock);
2429 (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
2430 sizeof(advlock_msg->pvnr_fl));
2431 advlock_msg->pvnr_id = ap->a_id;
2432 advlock_msg->pvnr_op = ap->a_op;
2433 advlock_msg->pvnr_flags = ap->a_flags;
2434 puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
2435 PUFFS_VN_ADVLOCK, VPTOPNC(vp));
2436 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
2437 error = checkerr(pmp, error, __func__);
2438 PUFFS_MSG_RELEASE(advlock);
2439
2440 return error;
2441 }
2442
2443 int
2444 puffs_vnop_abortop(void *v)
2445 {
2446 struct vop_abortop_args /* {
2447 struct vnode *a_dvp;
2448 struct componentname *a_cnp;
2449 }; */ *ap = v;
2450 PUFFS_MSG_VARS(vn, abortop);
2451 struct vnode *dvp = ap->a_dvp;
2452 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
2453 struct componentname *cnp = ap->a_cnp;
2454
2455 if (EXISTSOP(pmp, ABORTOP)) {
2456 PUFFS_MSG_ALLOC(vn, abortop);
2457 puffs_makecn(&abortop_msg->pvnr_cn, &abortop_msg->pvnr_cn_cred,
2458 cnp, PUFFS_USE_FULLPNBUF(pmp));
2459 puffs_msg_setfaf(park_abortop);
2460 puffs_msg_setinfo(park_abortop, PUFFSOP_VN,
2461 PUFFS_VN_ABORTOP, VPTOPNC(dvp));
2462
2463 puffs_msg_enqueue(pmp, park_abortop);
2464 PUFFS_MSG_RELEASE(abortop);
2465 }
2466
2467 return genfs_abortop(v);
2468 }
2469
2470 #define BIOASYNC(bp) (bp->b_flags & B_ASYNC)
2471
2472 /*
2473 * This maps itself to PUFFS_VN_READ/WRITE for data transfer.
2474 */
2475 int
2476 puffs_vnop_strategy(void *v)
2477 {
2478 struct vop_strategy_args /* {
2479 const struct vnodeop_desc *a_desc;
2480 struct vnode *a_vp;
2481 struct buf *a_bp;
2482 } */ *ap = v;
2483 PUFFS_MSG_VARS(vn, rw);
2484 struct vnode *vp = ap->a_vp;
2485 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2486 struct puffs_node *pn;
2487 struct buf *bp;
2488 size_t argsize;
2489 size_t tomove, moved;
2490 int error, dofaf, cansleep, dobiodone;
2491
2492 pmp = MPTOPUFFSMP(vp->v_mount);
2493 bp = ap->a_bp;
2494 error = 0;
2495 dofaf = 0;
2496 cansleep = 0;
2497 pn = VPTOPP(vp);
2498 park_rw = NULL; /* explicit */
2499 dobiodone = 1;
2500
2501 if ((BUF_ISREAD(bp) && !EXISTSOP(pmp, READ))
2502 || (BUF_ISWRITE(bp) && !EXISTSOP(pmp, WRITE)))
2503 ERROUT(EOPNOTSUPP);
2504
2505 /*
2506 * Short-circuit optimization: don't flush buffer in between
2507 * VOP_INACTIVE and VOP_RECLAIM in case the node has no references.
2508 */
2509 if (pn->pn_stat & PNODE_DYING) {
2510 KASSERT(BUF_ISWRITE(bp));
2511 bp->b_resid = 0;
2512 goto out;
2513 }
2514
2515 #ifdef DIAGNOSTIC
2516 if (bp->b_bcount > pmp->pmp_msg_maxsize - PUFFS_MSGSTRUCT_MAX)
2517 panic("puffs_strategy: wildly inappropriate buf bcount %d",
2518 bp->b_bcount);
2519 #endif
2520
2521 /*
2522 * See explanation for the necessity of a FAF in puffs_fsync.
2523 *
2524 * Also, do FAF in case we're suspending.
2525 * See puffs_vfsops.c:pageflush()
2526 */
2527 if (BUF_ISWRITE(bp)) {
2528 mutex_enter(vp->v_interlock);
2529 if (vp->v_iflag & VI_XLOCK)
2530 dofaf = 1;
2531 if (pn->pn_stat & PNODE_FAF)
2532 dofaf = 1;
2533 mutex_exit(vp->v_interlock);
2534 }
2535
2536 cansleep = (curlwp == uvm.pagedaemon_lwp || dofaf) ? 0 : 1;
2537
2538 KASSERT(curlwp != uvm.pagedaemon_lwp || dofaf || BIOASYNC(bp));
2539
2540 /* allocate transport structure */
2541 tomove = PUFFS_TOMOVE(bp->b_bcount, pmp);
2542 argsize = sizeof(struct puffs_vnmsg_rw);
2543 error = puffs_msgmem_alloc(argsize + tomove, &park_rw,
2544 (void *)&rw_msg, cansleep);
2545 if (error)
2546 goto out;
2547 RWARGS(rw_msg, 0, tomove, bp->b_blkno << DEV_BSHIFT, FSCRED);
2548
2549 /* 2x2 cases: read/write, faf/nofaf */
2550 if (BUF_ISREAD(bp)) {
2551 puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2552 PUFFS_VN_READ, VPTOPNC(vp));
2553 puffs_msg_setdelta(park_rw, tomove);
2554 if (BIOASYNC(bp)) {
2555 puffs_msg_setcall(park_rw,
2556 puffs_parkdone_asyncbioread, bp);
2557 puffs_msg_enqueue(pmp, park_rw);
2558 dobiodone = 0;
2559 } else {
2560 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data,
2561 NULL, error);
2562 error = checkerr(pmp, error, __func__);
2563 if (error)
2564 goto out;
2565
2566 if (rw_msg->pvnr_resid > tomove) {
2567 puffs_senderr(pmp, PUFFS_ERR_READ,
2568 E2BIG, "resid grew", VPTOPNC(vp));
2569 ERROUT(EPROTO);
2570 }
2571
2572 moved = tomove - rw_msg->pvnr_resid;
2573
2574 (void)memcpy(bp->b_data, rw_msg->pvnr_data, moved);
2575 bp->b_resid = bp->b_bcount - moved;
2576 }
2577 } else {
2578 puffs_msg_setinfo(park_rw, PUFFSOP_VN,
2579 PUFFS_VN_WRITE, VPTOPNC(vp));
2580 /*
2581 * make pages read-only before we write them if we want
2582 * write caching info
2583 */
2584 if (PUFFS_WCACHEINFO(pmp)) {
2585 struct uvm_object *uobj = &vp->v_uobj;
2586 int npages = (bp->b_bcount + PAGE_SIZE-1) >> PAGE_SHIFT;
2587 struct vm_page *vmp;
2588 int i;
2589
2590 for (i = 0; i < npages; i++) {
2591 vmp= uvm_pageratop((vaddr_t)bp->b_data
2592 + (i << PAGE_SHIFT));
2593 DPRINTF(("puffs_strategy: write-protecting "
2594 "vp %p page %p, offset %" PRId64"\n",
2595 vp, vmp, vmp->offset));
2596 mutex_enter(uobj->vmobjlock);
2597 vmp->flags |= PG_RDONLY;
2598 pmap_page_protect(vmp, VM_PROT_READ);
2599 mutex_exit(uobj->vmobjlock);
2600 }
2601 }
2602
2603 (void)memcpy(&rw_msg->pvnr_data, bp->b_data, tomove);
2604 if (dofaf) {
2605 puffs_msg_setfaf(park_rw);
2606 } else if (BIOASYNC(bp)) {
2607 puffs_msg_setcall(park_rw,
2608 puffs_parkdone_asyncbiowrite, bp);
2609 dobiodone = 0;
2610 }
2611
2612 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rw, vp->v_data, NULL, error);
2613
2614 if (dobiodone == 0)
2615 goto out;
2616
2617 /*
2618 * XXXXXXXX: wrong, but kernel can't survive strategy
2619 * failure currently. Here, have one more X: X.
2620 */
2621 if (error != ENOMEM)
2622 error = 0;
2623
2624 error = checkerr(pmp, error, __func__);
2625 if (error)
2626 goto out;
2627
2628 if (rw_msg->pvnr_resid > tomove) {
2629 puffs_senderr(pmp, PUFFS_ERR_WRITE,
2630 E2BIG, "resid grew", VPTOPNC(vp));
2631 ERROUT(EPROTO);
2632 }
2633
2634 /*
2635 * FAF moved everything. Frankly, we don't
2636 * really have a choice.
2637 */
2638 if (dofaf && error == 0)
2639 moved = tomove;
2640 else
2641 moved = tomove - rw_msg->pvnr_resid;
2642
2643 bp->b_resid = bp->b_bcount - moved;
2644 if (bp->b_resid != 0) {
2645 ERROUT(EIO);
2646 }
2647 }
2648
2649 out:
2650 if (park_rw)
2651 puffs_msgmem_release(park_rw);
2652
2653 if (error)
2654 bp->b_error = error;
2655
2656 if (error || dobiodone)
2657 biodone(bp);
2658
2659 return error;
2660 }
2661
2662 int
2663 puffs_vnop_mmap(void *v)
2664 {
2665 struct vop_mmap_args /* {
2666 const struct vnodeop_desc *a_desc;
2667 struct vnode *a_vp;
2668 vm_prot_t a_prot;
2669 kauth_cred_t a_cred;
2670 } */ *ap = v;
2671 PUFFS_MSG_VARS(vn, mmap);
2672 struct vnode *vp = ap->a_vp;
2673 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2674 int error;
2675
2676 if (!PUFFS_USE_PAGECACHE(pmp))
2677 return genfs_eopnotsupp(v);
2678
2679 if (EXISTSOP(pmp, MMAP)) {
2680 PUFFS_MSG_ALLOC(vn, mmap);
2681 mmap_msg->pvnr_prot = ap->a_prot;
2682 puffs_credcvt(&mmap_msg->pvnr_cred, ap->a_cred);
2683 puffs_msg_setinfo(park_mmap, PUFFSOP_VN,
2684 PUFFS_VN_MMAP, VPTOPNC(vp));
2685
2686 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mmap, vp->v_data, NULL, error);
2687 error = checkerr(pmp, error, __func__);
2688 PUFFS_MSG_RELEASE(mmap);
2689 } else {
2690 error = genfs_mmap(v);
2691 }
2692
2693 return error;
2694 }
2695
2696
2697 /*
2698 * The rest don't get a free trip to userspace and back, they
2699 * have to stay within the kernel.
2700 */
2701
2702 /*
2703 * bmap doesn't really make any sense for puffs, so just 1:1 map it.
2704 * well, maybe somehow, somewhere, some day ....
2705 */
2706 int
2707 puffs_vnop_bmap(void *v)
2708 {
2709 struct vop_bmap_args /* {
2710 const struct vnodeop_desc *a_desc;
2711 struct vnode *a_vp;
2712 daddr_t a_bn;
2713 struct vnode **a_vpp;
2714 daddr_t *a_bnp;
2715 int *a_runp;
2716 } */ *ap = v;
2717 struct puffs_mount *pmp;
2718
2719 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2720
2721 if (ap->a_vpp)
2722 *ap->a_vpp = ap->a_vp;
2723 if (ap->a_bnp)
2724 *ap->a_bnp = ap->a_bn;
2725 if (ap->a_runp)
2726 *ap->a_runp
2727 = (PUFFS_TOMOVE(pmp->pmp_msg_maxsize, pmp)>>DEV_BSHIFT) - 1;
2728
2729 return 0;
2730 }
2731
2732 /*
2733 * Handle getpages faults in puffs. We let genfs_getpages() do most
2734 * of the dirty work, but we come in this route to do accounting tasks.
2735 * If the user server has specified functions for cache notifications
2736 * about reads and/or writes, we record which type of operation we got,
2737 * for which page range, and proceed to issue a FAF notification to the
2738 * server about it.
2739 */
2740 int
2741 puffs_vnop_getpages(void *v)
2742 {
2743 struct vop_getpages_args /* {
2744 const struct vnodeop_desc *a_desc;
2745 struct vnode *a_vp;
2746 voff_t a_offset;
2747 struct vm_page **a_m;
2748 int *a_count;
2749 int a_centeridx;
2750 vm_prot_t a_access_type;
2751 int a_advice;
2752 int a_flags;
2753 } */ *ap = v;
2754 struct puffs_mount *pmp;
2755 struct puffs_node *pn;
2756 struct vnode *vp;
2757 struct vm_page **pgs;
2758 struct puffs_cacheinfo *pcinfo = NULL;
2759 struct puffs_cacherun *pcrun;
2760 void *parkmem = NULL;
2761 size_t runsizes;
2762 int i, npages, si, streakon;
2763 int error, locked, write;
2764
2765 pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
2766 npages = *ap->a_count;
2767 pgs = ap->a_m;
2768 vp = ap->a_vp;
2769 pn = vp->v_data;
2770 locked = (ap->a_flags & PGO_LOCKED) != 0;
2771 write = (ap->a_access_type & VM_PROT_WRITE) != 0;
2772
2773 /* ccg xnaht - gets Wuninitialized wrong */
2774 pcrun = NULL;
2775 runsizes = 0;
2776
2777 /*
2778 * Check that we aren't trying to fault in pages which our file
2779 * server doesn't know about. This happens if we extend a file by
2780 * skipping some pages and later try to fault in pages which
2781 * are between pn_serversize and vp_size. This check optimizes
2782 * away the common case where a file is being extended.
2783 */
2784 if (ap->a_offset >= pn->pn_serversize && ap->a_offset < vp->v_size) {
2785 struct vattr va;
2786
2787 /* try again later when we can block */
2788 if (locked)
2789 ERROUT(EBUSY);
2790
2791 mutex_exit(vp->v_interlock);
2792 vattr_null(&va);
2793 va.va_size = vp->v_size;
2794 error = dosetattr(vp, &va, FSCRED, 0);
2795 if (error)
2796 ERROUT(error);
2797 mutex_enter(vp->v_interlock);
2798 }
2799
2800 if (write && PUFFS_WCACHEINFO(pmp)) {
2801 #ifdef notnowjohn
2802 /* allocate worst-case memory */
2803 runsizes = ((npages / 2) + 1) * sizeof(struct puffs_cacherun);
2804 KASSERT(curlwp != uvm.pagedaemon_lwp || locked);
2805 pcinfo = kmem_zalloc(sizeof(struct puffs_cacheinfo) + runsize,
2806 locked ? KM_NOSLEEP : KM_SLEEP);
2807
2808 /*
2809 * can't block if we're locked and can't mess up caching
2810 * information for fs server. so come back later, please
2811 */
2812 if (pcinfo == NULL)
2813 ERROUT(ENOMEM);
2814
2815 parkmem = puffs_park_alloc(locked == 0);
2816 if (parkmem == NULL)
2817 ERROUT(ENOMEM);
2818
2819 pcrun = pcinfo->pcache_runs;
2820 #else
2821 (void)parkmem;
2822 #endif
2823 }
2824
2825 error = genfs_getpages(v);
2826 if (error)
2827 goto out;
2828
2829 if (PUFFS_WCACHEINFO(pmp) == 0)
2830 goto out;
2831
2832 /*
2833 * Let's see whose fault it was and inform the user server of
2834 * possibly read/written pages. Map pages from read faults
2835 * strictly read-only, since otherwise we might miss info on
2836 * when the page is actually write-faulted to.
2837 */
2838 if (!locked)
2839 mutex_enter(vp->v_uobj.vmobjlock);
2840 for (i = 0, si = 0, streakon = 0; i < npages; i++) {
2841 if (pgs[i] == NULL || pgs[i] == PGO_DONTCARE) {
2842 if (streakon && write) {
2843 streakon = 0;
2844 pcrun[si].pcache_runend
2845 = trunc_page(pgs[i]->offset) + PAGE_MASK;
2846 si++;
2847 }
2848 continue;
2849 }
2850 if (streakon == 0 && write) {
2851 streakon = 1;
2852 pcrun[si].pcache_runstart = pgs[i]->offset;
2853 }
2854
2855 if (!write)
2856 pgs[i]->flags |= PG_RDONLY;
2857 }
2858 /* was the last page part of our streak? */
2859 if (streakon) {
2860 pcrun[si].pcache_runend
2861 = trunc_page(pgs[i-1]->offset) + PAGE_MASK;
2862 si++;
2863 }
2864 if (!locked)
2865 mutex_exit(vp->v_uobj.vmobjlock);
2866
2867 KASSERT(si <= (npages / 2) + 1);
2868
2869 #ifdef notnowjohn
2870 /* send results to userspace */
2871 if (write)
2872 puffs_cacheop(pmp, parkmem, pcinfo,
2873 sizeof(struct puffs_cacheinfo) + runsizes, VPTOPNC(vp));
2874 #endif
2875
2876 out:
2877 if (error) {
2878 if (pcinfo != NULL)
2879 kmem_free(pcinfo,
2880 sizeof(struct puffs_cacheinfo) + runsizes);
2881 #ifdef notnowjohn
2882 if (parkmem != NULL)
2883 puffs_park_release(parkmem, 1);
2884 #endif
2885 }
2886
2887 return error;
2888 }
2889
2890 /*
2891 * Extended attribute support.
2892 */
2893
2894 int
2895 puffs_vnop_getextattr(void *v)
2896 {
2897 struct vop_getextattr_args /*
2898 struct vnode *a_vp;
2899 int a_attrnamespace;
2900 const char *a_name;
2901 struct uio *a_uio;
2902 size_t *a_size;
2903 kauth_cred_t a_cred;
2904 }; */ *ap = v;
2905 PUFFS_MSG_VARS(vn, getextattr);
2906 struct vnode *vp = ap->a_vp;
2907 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2908 int attrnamespace = ap->a_attrnamespace;
2909 const char *name = ap->a_name;
2910 struct uio *uio = ap->a_uio;
2911 size_t *sizep = ap->a_size;
2912 size_t tomove, resid;
2913 int error;
2914
2915 if (uio)
2916 resid = uio->uio_resid;
2917 else
2918 resid = 0;
2919
2920 tomove = PUFFS_TOMOVE(resid, pmp);
2921 if (tomove != resid) {
2922 error = E2BIG;
2923 goto out;
2924 }
2925
2926 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_getextattr) + tomove,
2927 &park_getextattr, (void *)&getextattr_msg, 1);
2928
2929 getextattr_msg->pvnr_attrnamespace = attrnamespace;
2930 strlcpy(getextattr_msg->pvnr_attrname, name,
2931 sizeof(getextattr_msg->pvnr_attrname));
2932 puffs_credcvt(&getextattr_msg->pvnr_cred, ap->a_cred);
2933 if (sizep)
2934 getextattr_msg->pvnr_datasize = 1;
2935 getextattr_msg->pvnr_resid = tomove;
2936
2937 puffs_msg_setinfo(park_getextattr,
2938 PUFFSOP_VN, PUFFS_VN_GETEXTATTR, VPTOPNC(vp));
2939 puffs_msg_setdelta(park_getextattr, tomove);
2940 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getextattr, vp->v_data, NULL, error);
2941
2942 error = checkerr(pmp, error, __func__);
2943 if (error)
2944 goto out;
2945
2946 resid = getextattr_msg->pvnr_resid;
2947 if (resid > tomove) {
2948 puffs_senderr(pmp, PUFFS_ERR_GETEXTATTR, E2BIG,
2949 "resid grew", VPTOPNC(vp));
2950 error = EPROTO;
2951 goto out;
2952 }
2953
2954 if (sizep)
2955 *sizep = getextattr_msg->pvnr_datasize;
2956 if (uio)
2957 error = uiomove(getextattr_msg->pvnr_data, tomove - resid, uio);
2958
2959 out:
2960 PUFFS_MSG_RELEASE(getextattr);
2961 return error;
2962 }
2963
2964 int
2965 puffs_vnop_setextattr(void *v)
2966 {
2967 struct vop_setextattr_args /* {
2968 struct vnode *a_vp;
2969 int a_attrnamespace;
2970 const char *a_name;
2971 struct uio *a_uio;
2972 kauth_cred_t a_cred;
2973 }; */ *ap = v;
2974 PUFFS_MSG_VARS(vn, setextattr);
2975 struct vnode *vp = ap->a_vp;
2976 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
2977 int attrnamespace = ap->a_attrnamespace;
2978 const char *name = ap->a_name;
2979 struct uio *uio = ap->a_uio;
2980 size_t tomove, resid;
2981 int error;
2982
2983 if (uio)
2984 resid = uio->uio_resid;
2985 else
2986 resid = 0;
2987
2988 tomove = PUFFS_TOMOVE(resid, pmp);
2989 if (tomove != resid) {
2990 error = E2BIG;
2991 goto out;
2992 }
2993
2994 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_setextattr) + tomove,
2995 &park_setextattr, (void *)&setextattr_msg, 1);
2996
2997 setextattr_msg->pvnr_attrnamespace = attrnamespace;
2998 strlcpy(setextattr_msg->pvnr_attrname, name,
2999 sizeof(setextattr_msg->pvnr_attrname));
3000 puffs_credcvt(&setextattr_msg->pvnr_cred, ap->a_cred);
3001 setextattr_msg->pvnr_resid = tomove;
3002
3003 if (uio) {
3004 error = uiomove(setextattr_msg->pvnr_data, tomove, uio);
3005 if (error)
3006 goto out;
3007 }
3008
3009 puffs_msg_setinfo(park_setextattr,
3010 PUFFSOP_VN, PUFFS_VN_SETEXTATTR, VPTOPNC(vp));
3011 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_setextattr, vp->v_data, NULL, error);
3012
3013 error = checkerr(pmp, error, __func__);
3014 if (error)
3015 goto out;
3016
3017 if (setextattr_msg->pvnr_resid != 0)
3018 error = EIO;
3019
3020 out:
3021 PUFFS_MSG_RELEASE(setextattr);
3022
3023 return error;
3024 }
3025
3026 int
3027 puffs_vnop_listextattr(void *v)
3028 {
3029 struct vop_listextattr_args /* {
3030 struct vnode *a_vp;
3031 int a_attrnamespace;
3032 struct uio *a_uio;
3033 size_t *a_size;
3034 int a_flag,
3035 kauth_cred_t a_cred;
3036 }; */ *ap = v;
3037 PUFFS_MSG_VARS(vn, listextattr);
3038 struct vnode *vp = ap->a_vp;
3039 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3040 int attrnamespace = ap->a_attrnamespace;
3041 struct uio *uio = ap->a_uio;
3042 size_t *sizep = ap->a_size;
3043 int flag = ap->a_flag;
3044 size_t tomove, resid;
3045 int error;
3046
3047 if (uio)
3048 resid = uio->uio_resid;
3049 else
3050 resid = 0;
3051
3052 tomove = PUFFS_TOMOVE(resid, pmp);
3053 if (tomove != resid) {
3054 error = E2BIG;
3055 goto out;
3056 }
3057
3058 puffs_msgmem_alloc(sizeof(struct puffs_vnmsg_listextattr) + tomove,
3059 &park_listextattr, (void *)&listextattr_msg, 1);
3060
3061 listextattr_msg->pvnr_attrnamespace = attrnamespace;
3062 listextattr_msg->pvnr_flag = flag;
3063 puffs_credcvt(&listextattr_msg->pvnr_cred, ap->a_cred);
3064 listextattr_msg->pvnr_resid = tomove;
3065 if (sizep)
3066 listextattr_msg->pvnr_datasize = 1;
3067
3068 puffs_msg_setinfo(park_listextattr,
3069 PUFFSOP_VN, PUFFS_VN_LISTEXTATTR, VPTOPNC(vp));
3070 puffs_msg_setdelta(park_listextattr, tomove);
3071 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_listextattr, vp->v_data, NULL, error);
3072
3073 error = checkerr(pmp, error, __func__);
3074 if (error)
3075 goto out;
3076
3077 resid = listextattr_msg->pvnr_resid;
3078 if (resid > tomove) {
3079 puffs_senderr(pmp, PUFFS_ERR_LISTEXTATTR, E2BIG,
3080 "resid grew", VPTOPNC(vp));
3081 error = EPROTO;
3082 goto out;
3083 }
3084
3085 if (sizep)
3086 *sizep = listextattr_msg->pvnr_datasize;
3087 if (uio)
3088 error = uiomove(listextattr_msg->pvnr_data, tomove-resid, uio);
3089
3090 out:
3091 PUFFS_MSG_RELEASE(listextattr);
3092 return error;
3093 }
3094
3095 int
3096 puffs_vnop_deleteextattr(void *v)
3097 {
3098 struct vop_deleteextattr_args /* {
3099 struct vnode *a_vp;
3100 int a_attrnamespace;
3101 const char *a_name;
3102 kauth_cred_t a_cred;
3103 }; */ *ap = v;
3104 PUFFS_MSG_VARS(vn, deleteextattr);
3105 struct vnode *vp = ap->a_vp;
3106 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
3107 int attrnamespace = ap->a_attrnamespace;
3108 const char *name = ap->a_name;
3109 int error;
3110
3111 PUFFS_MSG_ALLOC(vn, deleteextattr);
3112 deleteextattr_msg->pvnr_attrnamespace = attrnamespace;
3113 strlcpy(deleteextattr_msg->pvnr_attrname, name,
3114 sizeof(deleteextattr_msg->pvnr_attrname));
3115 puffs_credcvt(&deleteextattr_msg->pvnr_cred, ap->a_cred);
3116
3117 puffs_msg_setinfo(park_deleteextattr,
3118 PUFFSOP_VN, PUFFS_VN_DELETEEXTATTR, VPTOPNC(vp));
3119 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_deleteextattr,
3120 vp->v_data, NULL, error);
3121
3122 error = checkerr(pmp, error, __func__);
3123
3124 PUFFS_MSG_RELEASE(deleteextattr);
3125 return error;
3126 }
3127
3128 /*
3129 * spec & fifo. These call the miscfs spec and fifo vectors, but issue
3130 * FAF update information for the puffs node first.
3131 */
3132 int
3133 puffs_vnop_spec_read(void *v)
3134 {
3135 struct vop_read_args /* {
3136 const struct vnodeop_desc *a_desc;
3137 struct vnode *a_vp;
3138 struct uio *a_uio;
3139 int a_ioflag;
3140 kauth_cred_t a_cred;
3141 } */ *ap = v;
3142
3143 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
3144 return VOCALL(spec_vnodeop_p, VOFFSET(vop_read), v);
3145 }
3146
3147 int
3148 puffs_vnop_spec_write(void *v)
3149 {
3150 struct vop_write_args /* {
3151 const struct vnodeop_desc *a_desc;
3152 struct vnode *a_vp;
3153 struct uio *a_uio;
3154 int a_ioflag;
3155 kauth_cred_t a_cred;
3156 } */ *ap = v;
3157
3158 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
3159 return VOCALL(spec_vnodeop_p, VOFFSET(vop_write), v);
3160 }
3161
3162 int
3163 puffs_vnop_fifo_read(void *v)
3164 {
3165 struct vop_read_args /* {
3166 const struct vnodeop_desc *a_desc;
3167 struct vnode *a_vp;
3168 struct uio *a_uio;
3169 int a_ioflag;
3170 kauth_cred_t a_cred;
3171 } */ *ap = v;
3172
3173 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEATIME, 0);
3174 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), v);
3175 }
3176
3177 int
3178 puffs_vnop_fifo_write(void *v)
3179 {
3180 struct vop_write_args /* {
3181 const struct vnodeop_desc *a_desc;
3182 struct vnode *a_vp;
3183 struct uio *a_uio;
3184 int a_ioflag;
3185 kauth_cred_t a_cred;
3186 } */ *ap = v;
3187
3188 puffs_updatenode(VPTOPP(ap->a_vp), PUFFS_UPDATEMTIME, 0);
3189 return VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), v);
3190 }
3191