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