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