kernel - pmap->pm_spin now uses a shared spinlock
[dragonfly.git] / sys / vfs / puffs / puffs_vnops.c
blobe8446c0e026931e40d984de2245accaa4734da76
1 /* $NetBSD: puffs_vnops.c,v 1.154 2011/07/04 08:07:30 manu Exp $ */
3 /*
4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
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.
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.
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.
32 #include <sys/param.h>
33 #include <sys/buf.h>
34 #include <sys/lockf.h>
35 #include <sys/malloc.h>
36 #include <sys/mount.h>
37 #include <sys/namei.h>
38 #include <sys/vnode.h>
39 #include <sys/proc.h>
41 #include <vfs/fifofs/fifo.h>
43 #include <vfs/puffs/puffs_msgif.h>
44 #include <vfs/puffs/puffs_sys.h>
46 int (**puffs_vnodeop_p)(void *);
48 #define ERROUT(err) \
49 do { \
50 error = err; \
51 goto out; \
52 } while (/*CONSTCOND*/0)
54 static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
55 struct namecache *, struct ucred *);
56 static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
57 struct namecache *, struct ucred *);
58 static void callinactive(struct puffs_mount *, puffs_cookie_t, int);
59 static void callreclaim(struct puffs_mount *, puffs_cookie_t);
60 static int flushvncache(struct vnode *, int);
63 #define PUFFS_ABORT_LOOKUP 1
64 #define PUFFS_ABORT_CREATE 2
65 #define PUFFS_ABORT_MKNOD 3
66 #define PUFFS_ABORT_MKDIR 4
67 #define PUFFS_ABORT_SYMLINK 5
70 * Press the pani^Wabort button! Kernel resource allocation failed.
72 static void
73 puffs_abortbutton(struct puffs_mount *pmp, int what,
74 puffs_cookie_t dck, puffs_cookie_t ck,
75 struct namecache *ncp, struct ucred *cred)
78 switch (what) {
79 case PUFFS_ABORT_CREATE:
80 case PUFFS_ABORT_MKNOD:
81 case PUFFS_ABORT_SYMLINK:
82 callremove(pmp, dck, ck, ncp, cred);
83 break;
84 case PUFFS_ABORT_MKDIR:
85 callrmdir(pmp, dck, ck, ncp, cred);
86 break;
89 callinactive(pmp, ck, 0);
90 callreclaim(pmp, ck);
94 * Begin vnode operations.
96 * A word from the keymaster about locks: generally we don't want
97 * to use the vnode locks at all: it creates an ugly dependency between
98 * the userlandia file server and the kernel. But we'll play along with
99 * the kernel vnode locks for now. However, even currently we attempt
100 * to release locks as early as possible. This is possible for some
101 * operations which a) don't need a locked vnode after the userspace op
102 * and b) return with the vnode unlocked. Theoretically we could
103 * unlock-do op-lock for others and order the graph in userspace, but I
104 * don't want to think of the consequences for the time being.
106 static int
107 puffs_vnop_lookup(struct vop_nresolve_args *ap)
109 PUFFS_MSG_VARS(vn, lookup);
110 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
111 struct nchandle *nch = ap->a_nch;
112 struct namecache *ncp = nch->ncp;
113 struct ucred *cred = ap->a_cred;
114 struct vnode *vp = NULL, *dvp = ap->a_dvp;
115 struct puffs_node *dpn;
116 int error;
118 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p\n",
119 ncp->nc_name, dvp));
121 PUFFS_MSG_ALLOC(vn, lookup);
122 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
123 ncp, cred);
125 puffs_msg_setinfo(park_lookup, PUFFSOP_VN,
126 PUFFS_VN_LOOKUP, VPTOPNC(dvp));
127 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookup, dvp->v_data, NULL, error);
128 DPRINTF(("puffs_lookup: return of the userspace, part %d\n", error));
129 if (error) {
130 error = checkerr(pmp, error, __func__);
131 if (error == ENOENT)
132 cache_setvp(nch, NULL);
133 goto out;
137 * Check that we don't get our parent node back, that would cause
138 * a pretty obvious deadlock.
140 dpn = VPTOPP(dvp);
141 if (lookup_msg->pvnr_newnode == dpn->pn_cookie) {
142 puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
143 "lookup produced parent cookie", lookup_msg->pvnr_newnode);
144 error = EPROTO;
145 goto out;
148 error = puffs_cookie2vnode(pmp, lookup_msg->pvnr_newnode, 1, &vp);
149 if (error == PUFFS_NOSUCHCOOKIE) {
150 error = puffs_getvnode(dvp->v_mount,
151 lookup_msg->pvnr_newnode, lookup_msg->pvnr_vtype,
152 lookup_msg->pvnr_size, &vp);
153 if (error) {
154 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
155 lookup_msg->pvnr_newnode, ncp, cred);
156 goto out;
158 } else if (error) {
159 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
160 lookup_msg->pvnr_newnode, ncp, cred);
161 goto out;
164 out:
165 if (!error && vp != NULL) {
166 vn_unlock(vp);
167 cache_setvp(nch, vp);
168 vrele(vp);
170 DPRINTF(("puffs_lookup: returning %d\n", error));
171 PUFFS_MSG_RELEASE(lookup);
172 return error;
175 static int
176 puffs_vnop_lookupdotdot(struct vop_nlookupdotdot_args *ap)
178 PUFFS_MSG_VARS(vn, lookupdotdot);
179 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_dvp->v_mount);
180 struct ucred *cred = ap->a_cred;
181 struct vnode *vp, *dvp = ap->a_dvp;
182 struct puffs_node *dpn;
183 int error;
185 *ap->a_vpp = NULL;
187 DPRINTF(("puffs_lookupdotdot: vnode %p\n", dvp));
189 PUFFS_MSG_ALLOC(vn, lookupdotdot);
190 puffs_credcvt(&lookupdotdot_msg->pvnr_cred, cred);
192 puffs_msg_setinfo(park_lookupdotdot, PUFFSOP_VN,
193 PUFFS_VN_LOOKUPDOTDOT, VPTOPNC(dvp));
194 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_lookupdotdot, dvp->v_data, NULL,
195 error);
196 DPRINTF(("puffs_lookupdotdot: return of the userspace, part %d\n",
197 error));
198 if (error) {
199 error = checkerr(pmp, error, __func__);
200 goto out;
204 * Check that we don't get our node back, that would cause
205 * a pretty obvious deadlock.
207 dpn = VPTOPP(dvp);
208 if (lookupdotdot_msg->pvnr_newnode == dpn->pn_cookie) {
209 puffs_senderr(pmp, PUFFS_ERR_LOOKUP, EINVAL,
210 "lookupdotdot produced the same cookie",
211 lookupdotdot_msg->pvnr_newnode);
212 error = EPROTO;
213 goto out;
216 error = puffs_cookie2vnode(pmp, lookupdotdot_msg->pvnr_newnode,
217 1, &vp);
218 if (error == PUFFS_NOSUCHCOOKIE) {
219 error = puffs_getvnode(dvp->v_mount,
220 lookupdotdot_msg->pvnr_newnode, VDIR, 0, &vp);
221 if (error) {
222 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
223 lookupdotdot_msg->pvnr_newnode, NULL, cred);
224 goto out;
226 } else if (error) {
227 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
228 lookupdotdot_msg->pvnr_newnode, NULL, cred);
229 goto out;
232 *ap->a_vpp = vp;
233 vn_unlock(vp);
235 out:
236 DPRINTF(("puffs_lookupdotdot: returning %d %p\n", error, *ap->a_vpp));
237 PUFFS_MSG_RELEASE(lookupdotdot);
238 return error;
241 static int
242 puffs_vnop_create(struct vop_ncreate_args *ap)
244 PUFFS_MSG_VARS(vn, create);
245 struct vnode *dvp = ap->a_dvp;
246 struct vattr *vap = ap->a_vap;
247 struct puffs_node *dpn = VPTOPP(dvp);
248 struct nchandle *nch = ap->a_nch;
249 struct namecache *ncp = nch->ncp;
250 struct ucred *cred = ap->a_cred;
251 struct mount *mp = dvp->v_mount;
252 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
253 int error;
255 if (!EXISTSOP(pmp, CREATE))
256 return EOPNOTSUPP;
258 DPRINTF(("puffs_create: dvp %p, name: %s\n",
259 dvp, ncp->nc_name));
261 if (vap->va_type != VREG && vap->va_type != VSOCK)
262 return EINVAL;
264 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
265 DPRINTF(("puffs_vnop_create: EAGAIN on ncp %p %s\n",
266 ncp, ncp->nc_name));
267 return EAGAIN;
270 PUFFS_MSG_ALLOC(vn, create);
271 puffs_makecn(&create_msg->pvnr_cn, &create_msg->pvnr_cn_cred,
272 ncp, cred);
273 create_msg->pvnr_va = *ap->a_vap;
274 puffs_msg_setinfo(park_create, PUFFSOP_VN,
275 PUFFS_VN_CREATE, VPTOPNC(dvp));
276 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_create, dvp->v_data, NULL, error);
278 error = checkerr(pmp, error, __func__);
279 if (error)
280 goto out;
282 error = puffs_newnode(mp, dvp, ap->a_vpp,
283 create_msg->pvnr_newnode, vap->va_type);
284 if (error)
285 puffs_abortbutton(pmp, PUFFS_ABORT_CREATE, dpn->pn_cookie,
286 create_msg->pvnr_newnode, ncp, cred);
288 out:
289 DPRINTF(("puffs_create: return %d\n", error));
290 vput(dvp);
291 if (!error) {
292 cache_setunresolved(nch);
293 cache_setvp(nch, *ap->a_vpp);
295 PUFFS_MSG_RELEASE(create);
296 return error;
299 static int
300 puffs_vnop_mknod(struct vop_nmknod_args *ap)
302 PUFFS_MSG_VARS(vn, mknod);
303 struct vnode *dvp = ap->a_dvp;
304 struct vattr *vap = ap->a_vap;
305 struct puffs_node *dpn = VPTOPP(dvp);
306 struct nchandle *nch = ap->a_nch;
307 struct namecache *ncp = nch->ncp;
308 struct ucred *cred = ap->a_cred;
309 struct mount *mp = dvp->v_mount;
310 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
311 int error;
313 if (!EXISTSOP(pmp, MKNOD))
314 return EOPNOTSUPP;
316 DPRINTF(("puffs_mknod: dvp %p, name: %s\n",
317 dvp, ncp->nc_name));
319 if (vap->va_type != VFIFO)
320 return EINVAL;
322 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
323 DPRINTF(("puffs_vnop_mknod: EAGAIN on ncp %p %s\n",
324 ncp, ncp->nc_name));
325 return EAGAIN;
328 PUFFS_MSG_ALLOC(vn, mknod);
329 puffs_makecn(&mknod_msg->pvnr_cn, &mknod_msg->pvnr_cn_cred,
330 ncp, cred);
331 mknod_msg->pvnr_va = *ap->a_vap;
332 puffs_msg_setinfo(park_mknod, PUFFSOP_VN,
333 PUFFS_VN_MKNOD, VPTOPNC(dvp));
335 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);
337 error = checkerr(pmp, error, __func__);
338 if (error)
339 goto out;
341 error = puffs_newnode(mp, dvp, ap->a_vpp,
342 mknod_msg->pvnr_newnode, vap->va_type);
343 if (error)
344 puffs_abortbutton(pmp, PUFFS_ABORT_MKNOD, dpn->pn_cookie,
345 mknod_msg->pvnr_newnode, ncp, cred);
347 out:
348 vput(dvp);
349 if (!error) {
350 cache_setunresolved(nch);
351 cache_setvp(nch, *ap->a_vpp);
353 PUFFS_MSG_RELEASE(mknod);
354 return error;
357 static int
358 puffs_vnop_open(struct vop_open_args *ap)
360 PUFFS_MSG_VARS(vn, open);
361 struct vnode *vp = ap->a_vp;
362 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
363 int mode = ap->a_mode;
364 int error;
366 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
368 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
369 ERROUT(EROFS);
371 if (!EXISTSOP(pmp, OPEN))
372 ERROUT(0);
374 PUFFS_MSG_ALLOC(vn, open);
375 open_msg->pvnr_mode = mode;
376 puffs_credcvt(&open_msg->pvnr_cred, ap->a_cred);
377 puffs_msg_setinfo(park_open, PUFFSOP_VN,
378 PUFFS_VN_OPEN, VPTOPNC(vp));
380 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
381 error = checkerr(pmp, error, __func__);
383 out:
384 DPRINTF(("puffs_open: returning %d\n", error));
385 PUFFS_MSG_RELEASE(open);
386 if (error)
387 return error;
388 return vop_stdopen(ap);
391 static int
392 puffs_vnop_close(struct vop_close_args *ap)
394 PUFFS_MSG_VARS(vn, close);
395 struct vnode *vp = ap->a_vp;
396 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
398 vn_lock(vp, LK_UPGRADE | LK_RETRY);
400 if (!EXISTSOP(pmp, CLOSE))
401 return vop_stdclose(ap);
403 PUFFS_MSG_ALLOC(vn, close);
404 puffs_msg_setfaf(park_close);
405 close_msg->pvnr_fflag = ap->a_fflag;
406 puffs_msg_setinfo(park_close, PUFFSOP_VN,
407 PUFFS_VN_CLOSE, VPTOPNC(vp));
409 puffs_msg_enqueue(pmp, park_close);
410 PUFFS_MSG_RELEASE(close);
411 return vop_stdclose(ap);
414 static int
415 puffs_vnop_access(struct vop_access_args *ap)
417 PUFFS_MSG_VARS(vn, access);
418 struct vnode *vp = ap->a_vp;
419 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
420 int mode = ap->a_mode;
421 int error;
423 if (mode & VWRITE) {
424 switch (vp->v_type) {
425 case VDIR:
426 case VLNK:
427 case VREG:
428 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
429 || !EXISTSOP(pmp, WRITE))
430 return EROFS;
431 break;
432 default:
433 break;
437 if (!EXISTSOP(pmp, ACCESS))
438 return 0;
440 PUFFS_MSG_ALLOC(vn, access);
441 access_msg->pvnr_mode = ap->a_mode;
442 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
443 puffs_msg_setinfo(park_access, PUFFSOP_VN,
444 PUFFS_VN_ACCESS, VPTOPNC(vp));
446 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
447 error = checkerr(pmp, error, __func__);
448 PUFFS_MSG_RELEASE(access);
450 return error;
453 static int
454 puffs_vnop_getattr(struct vop_getattr_args *ap)
456 PUFFS_MSG_VARS(vn, getattr);
457 struct vnode *vp = ap->a_vp;
458 struct mount *mp = vp->v_mount;
459 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
460 struct vattr *vap, *rvap;
461 struct puffs_node *pn = VPTOPP(vp);
462 int error = 0;
464 if (vp->v_type == VBLK || vp->v_type == VCHR)
465 return ENOTSUP;
467 vap = ap->a_vap;
469 PUFFS_MSG_ALLOC(vn, getattr);
470 vattr_null(&getattr_msg->pvnr_va);
471 puffs_credcvt(&getattr_msg->pvnr_cred, curproc->p_ucred);
472 puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
473 PUFFS_VN_GETATTR, VPTOPNC(vp));
475 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
476 error = checkerr(pmp, error, __func__);
477 if (error)
478 goto out;
480 rvap = &getattr_msg->pvnr_va;
482 (void) memcpy(vap, rvap, sizeof(struct vattr));
483 vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
485 if (pn->pn_stat & PNODE_METACACHE_ATIME)
486 vap->va_atime = pn->pn_mc_atime;
487 if (pn->pn_stat & PNODE_METACACHE_CTIME)
488 vap->va_ctime = pn->pn_mc_ctime;
489 if (pn->pn_stat & PNODE_METACACHE_MTIME)
490 vap->va_mtime = pn->pn_mc_mtime;
491 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
492 vap->va_size = pn->pn_mc_size;
493 } else {
494 if (rvap->va_size != VNOVAL
495 && vp->v_type != VBLK && vp->v_type != VCHR) {
496 pn->pn_serversize = rvap->va_size;
497 if (vp->v_type == VREG)
498 puffs_meta_setsize(vp, rvap->va_size, 0);
502 out:
503 PUFFS_MSG_RELEASE(getattr);
504 return error;
507 #define SETATTR_CHSIZE 0x01
508 #define SETATTR_ASYNC 0x02
509 static int
510 dosetattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, int flags)
512 PUFFS_MSG_VARS(vn, setattr);
513 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
514 struct puffs_node *pn = VPTOPP(vp);
515 int error = 0;
517 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
518 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
519 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
520 || vap->va_mode != (mode_t)VNOVAL))
521 return EROFS;
523 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
524 && vp->v_type == VREG && vap->va_size != VNOVAL)
525 return EROFS;
528 * Flush metacache first. If we are called with some explicit
529 * parameters, treat them as information overriding metacache
530 * information.
532 if (pn->pn_stat & PNODE_METACACHE_MASK) {
533 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
534 && vap->va_atime.tv_sec == VNOVAL)
535 vap->va_atime = pn->pn_mc_atime;
536 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
537 && vap->va_ctime.tv_sec == VNOVAL)
538 vap->va_ctime = pn->pn_mc_ctime;
539 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
540 && vap->va_mtime.tv_sec == VNOVAL)
541 vap->va_mtime = pn->pn_mc_mtime;
542 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
543 && vap->va_size == VNOVAL)
544 vap->va_size = pn->pn_mc_size;
546 pn->pn_stat &= ~PNODE_METACACHE_MASK;
549 PUFFS_MSG_ALLOC(vn, setattr);
550 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
551 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
552 puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
553 PUFFS_VN_SETATTR, VPTOPNC(vp));
554 if (flags & SETATTR_ASYNC)
555 puffs_msg_setfaf(park_setattr);
557 puffs_msg_enqueue(pmp, park_setattr);
558 if ((flags & SETATTR_ASYNC) == 0)
559 error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
560 PUFFS_MSG_RELEASE(setattr);
561 if ((flags & SETATTR_ASYNC) == 0) {
562 error = checkerr(pmp, error, __func__);
563 if (error)
564 return error;
565 } else {
566 error = 0;
569 if (vap->va_size != VNOVAL) {
570 pn->pn_serversize = vap->va_size;
571 if (flags & SETATTR_CHSIZE)
572 puffs_meta_setsize(vp, vap->va_size, 0);
575 return 0;
578 static int
579 puffs_vnop_setattr(struct vop_setattr_args *ap)
581 return dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
584 static __inline int
585 doinact(struct puffs_mount *pmp, int iaflag)
588 if (EXISTSOP(pmp, INACTIVE))
589 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
590 if (iaflag || ALLOPS(pmp))
591 return 1;
592 else
593 return 0;
594 else
595 return 1;
596 else
597 return 0;
600 static void
601 callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
603 int error;
604 PUFFS_MSG_VARS(vn, inactive);
606 if (doinact(pmp, iaflag)) {
607 PUFFS_MSG_ALLOC(vn, inactive);
608 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
609 PUFFS_VN_INACTIVE, ck);
611 PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
612 PUFFS_MSG_RELEASE(inactive);
616 /* XXX: callinactive can't setback */
617 static int
618 puffs_vnop_inactive(struct vop_inactive_args *ap)
620 PUFFS_MSG_VARS(vn, inactive);
621 struct vnode *vp = ap->a_vp;
622 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
623 struct puffs_node *pnode = VPTOPP(vp);
625 flushvncache(vp, MNT_NOWAIT);
627 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
629 * do not wait for reply from userspace, otherwise it may
630 * deadlock.
633 PUFFS_MSG_ALLOC(vn, inactive);
634 puffs_msg_setfaf(park_inactive);
635 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
636 PUFFS_VN_INACTIVE, VPTOPNC(vp));
638 puffs_msg_enqueue(pmp, park_inactive);
639 PUFFS_MSG_RELEASE(inactive);
641 pnode->pn_stat &= ~PNODE_DOINACT;
644 * file server thinks it's gone? then don't be afraid care,
645 * node's life was already all it would ever be
647 if (pnode->pn_stat & PNODE_NOREFS) {
648 pnode->pn_stat |= PNODE_DYING;
649 vrecycle(vp);
652 return 0;
655 static void
656 callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
658 PUFFS_MSG_VARS(vn, reclaim);
660 if (!EXISTSOP(pmp, RECLAIM))
661 return;
663 PUFFS_MSG_ALLOC(vn, reclaim);
664 puffs_msg_setfaf(park_reclaim);
665 puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
667 puffs_msg_enqueue(pmp, park_reclaim);
668 PUFFS_MSG_RELEASE(reclaim);
672 * always FAF, we don't really care if the server wants to fail to
673 * reclaim the node or not
675 static int
676 puffs_vnop_reclaim(struct vop_reclaim_args *ap)
678 struct vnode *vp = ap->a_vp;
679 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
680 struct puffs_node *pnode = VPTOPP(vp);
681 boolean_t notifyserver = TRUE;
683 vinvalbuf(vp, V_SAVE, 0, 0);
686 * first things first: check if someone is trying to reclaim the
687 * root vnode. do not allow that to travel to userspace.
688 * Note that we don't need to take the lock similarly to
689 * puffs_root(), since there is only one of us.
691 if (vp->v_flag & VROOT) {
692 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
693 KKASSERT(pmp->pmp_root != NULL);
694 pmp->pmp_root = NULL;
695 lockmgr(&pmp->pmp_lock, LK_RELEASE);
696 notifyserver = FALSE;
700 * purge info from kernel before issueing FAF, since we
701 * don't really know when we'll get around to it after
702 * that and someone might race us into node creation
704 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
705 LIST_REMOVE(pnode, pn_hashent);
706 lockmgr(&pmp->pmp_lock, LK_RELEASE);
708 if (notifyserver)
709 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp));
711 puffs_putvnode(vp);
712 vp->v_data = NULL;
714 return 0;
717 #define CSIZE sizeof(**ap->a_cookies)
718 static int
719 puffs_vnop_readdir(struct vop_readdir_args *ap)
721 PUFFS_MSG_VARS(vn, readdir);
722 struct vnode *vp = ap->a_vp;
723 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
724 size_t argsize, tomove, cookiemem, cookiesmax;
725 struct uio *uio = ap->a_uio;
726 size_t howmuch, resid;
727 int error;
729 if (!EXISTSOP(pmp, READDIR))
730 return EOPNOTSUPP;
733 * ok, so we need: resid + cookiemem = maxreq
734 * => resid + cookiesize * (resid/minsize) = maxreq
735 * => resid + cookiesize/minsize * resid = maxreq
736 * => (cookiesize/minsize + 1) * resid = maxreq
737 * => resid = maxreq / (cookiesize/minsize + 1)
739 * Since cookiesize <= minsize and we're not very big on floats,
740 * we approximate that to be 1. Therefore:
742 * resid = maxreq / 2;
744 * Well, at least we didn't have to use differential equations
745 * or the Gram-Schmidt process.
747 * (yes, I'm very afraid of this)
749 KKASSERT(CSIZE <= _DIRENT_RECLEN(1));
751 if (ap->a_cookies) {
752 KKASSERT(ap->a_ncookies != NULL);
753 if (pmp->pmp_args.pa_fhsize == 0)
754 return EOPNOTSUPP;
755 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
756 cookiesmax = resid/_DIRENT_RECLEN(1);
757 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
758 } else {
759 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
760 cookiesmax = 0;
761 cookiemem = 0;
764 argsize = sizeof(struct puffs_vnmsg_readdir);
765 tomove = resid + cookiemem;
766 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
767 (void *)&readdir_msg, 1);
769 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
770 readdir_msg->pvnr_offset = uio->uio_offset;
771 readdir_msg->pvnr_resid = resid;
772 readdir_msg->pvnr_ncookies = cookiesmax;
773 readdir_msg->pvnr_eofflag = 0;
774 readdir_msg->pvnr_dentoff = cookiemem;
775 puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
776 PUFFS_VN_READDIR, VPTOPNC(vp));
777 puffs_msg_setdelta(park_readdir, tomove);
779 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
780 error = checkerr(pmp, error, __func__);
781 if (error)
782 goto out;
784 /* userspace is cheating? */
785 if (readdir_msg->pvnr_resid > resid) {
786 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
787 "resid grew", VPTOPNC(vp));
788 ERROUT(EPROTO);
790 if (readdir_msg->pvnr_ncookies > cookiesmax) {
791 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
792 "too many cookies", VPTOPNC(vp));
793 ERROUT(EPROTO);
796 /* check eof */
797 if (readdir_msg->pvnr_eofflag)
798 *ap->a_eofflag = 1;
800 /* bouncy-wouncy with the directory data */
801 howmuch = resid - readdir_msg->pvnr_resid;
803 /* force eof if no data was returned (getcwd() needs this) */
804 if (howmuch == 0) {
805 *ap->a_eofflag = 1;
806 goto out;
809 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
810 if (error)
811 goto out;
813 /* provide cookies to caller if so desired */
814 if (ap->a_cookies) {
815 *ap->a_cookies = kmalloc(readdir_msg->pvnr_ncookies*CSIZE,
816 M_TEMP, M_WAITOK);
817 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
818 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
819 *ap->a_ncookies*CSIZE);
822 /* next readdir starts here */
823 uio->uio_offset = readdir_msg->pvnr_offset;
825 out:
826 puffs_msgmem_release(park_readdir);
827 return error;
829 #undef CSIZE
831 static int
832 flushvncache(struct vnode *vp, int waitfor)
834 struct puffs_node *pn = VPTOPP(vp);
835 struct vattr va;
836 int error = 0;
838 /* flush out information from our metacache, see vop_setattr */
839 if (pn->pn_stat & PNODE_METACACHE_MASK
840 && (pn->pn_stat & PNODE_DYING) == 0) {
841 vattr_null(&va);
842 error = dosetattr(vp, &va, FSCRED, SETATTR_CHSIZE |
843 (waitfor == MNT_NOWAIT ? 0 : SETATTR_ASYNC));
844 if (error)
845 return error;
849 * flush pages to avoid being overly dirty
851 vfsync(vp, waitfor, 0, NULL, NULL);
853 return error;
856 static int
857 puffs_vnop_fsync(struct vop_fsync_args *ap)
859 PUFFS_MSG_VARS(vn, fsync);
860 struct vnode *vp = ap->a_vp;
861 int waitfor = ap->a_waitfor;
862 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
863 struct puffs_node *pn = VPTOPP(vp);
864 int error, dofaf;
866 error = flushvncache(vp, waitfor);
867 if (error)
868 return error;
871 * HELLO! We exit already here if the user server does not
872 * support fsync OR if we should call fsync for a node which
873 * has references neither in the kernel or the fs server.
874 * Otherwise we continue to issue fsync() forward.
876 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
877 return 0;
879 dofaf = (waitfor & MNT_WAIT) == 0 || (waitfor & MNT_LAZY) != 0;
881 PUFFS_MSG_ALLOC(vn, fsync);
882 if (dofaf)
883 puffs_msg_setfaf(park_fsync);
885 fsync_msg->pvnr_flags = ap->a_flags;
886 puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
887 PUFFS_VN_FSYNC, VPTOPNC(vp));
889 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
890 PUFFS_MSG_RELEASE(fsync);
892 error = checkerr(pmp, error, __func__);
894 return error;
897 static int
898 callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
899 struct namecache *ncp, struct ucred *cred)
901 PUFFS_MSG_VARS(vn, remove);
902 int error;
904 PUFFS_MSG_ALLOC(vn, remove);
905 remove_msg->pvnr_cookie_targ = ck;
906 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
907 ncp, cred);
908 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
910 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
911 PUFFS_MSG_RELEASE(remove);
913 return checkerr(pmp, error, __func__);
917 * XXX: can't use callremove now because can't catch setbacks with
918 * it due to lack of a pnode argument.
920 static int
921 puffs_vnop_remove(struct vop_nremove_args *ap)
923 PUFFS_MSG_VARS(vn, remove);
924 struct vnode *dvp = ap->a_dvp;
925 struct vnode *vp;
926 struct puffs_node *dpn = VPTOPP(dvp);
927 struct puffs_node *pn;
928 struct nchandle *nch = ap->a_nch;
929 struct namecache *ncp = nch->ncp;
930 struct ucred *cred = ap->a_cred;
931 struct mount *mp = dvp->v_mount;
932 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
933 int error;
935 if (!EXISTSOP(pmp, REMOVE))
936 return EOPNOTSUPP;
938 error = vget(dvp, LK_EXCLUSIVE);
939 if (error != 0) {
940 DPRINTF(("puffs_vnop_remove: EAGAIN on parent vnode %p %s\n",
941 dvp, ncp->nc_name));
942 return EAGAIN;
945 error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
946 if (error != 0) {
947 DPRINTF(("puffs_vnop_remove: cache_vget error: %p %s\n",
948 dvp, ncp->nc_name));
949 return EAGAIN;
951 if (vp->v_type == VDIR) {
952 error = EISDIR;
953 goto out;
956 pn = VPTOPP(vp);
957 PUFFS_MSG_ALLOC(vn, remove);
958 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
959 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
960 ncp, cred);
961 puffs_msg_setinfo(park_remove, PUFFSOP_VN,
962 PUFFS_VN_REMOVE, VPTOPNC(dvp));
964 puffs_msg_enqueue(pmp, park_remove);
965 error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
967 PUFFS_MSG_RELEASE(remove);
969 error = checkerr(pmp, error, __func__);
971 out:
972 vput(dvp);
973 vn_unlock(vp);
974 if (error == 0)
975 cache_unlink(nch);
976 vrele(vp);
977 return error;
980 static int
981 puffs_vnop_mkdir(struct vop_nmkdir_args *ap)
983 PUFFS_MSG_VARS(vn, mkdir);
984 struct vnode *dvp = ap->a_dvp;
985 struct puffs_node *dpn = VPTOPP(dvp);
986 struct nchandle *nch = ap->a_nch;
987 struct namecache *ncp = nch->ncp;
988 struct ucred *cred = ap->a_cred;
989 struct mount *mp = dvp->v_mount;
990 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
991 int error;
993 if (!EXISTSOP(pmp, MKDIR))
994 return EOPNOTSUPP;
996 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
997 DPRINTF(("puffs_vnop_mkdir: EAGAIN on ncp %p %s\n",
998 ncp, ncp->nc_name));
999 return EAGAIN;
1002 PUFFS_MSG_ALLOC(vn, mkdir);
1003 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1004 ncp, cred);
1005 mkdir_msg->pvnr_va = *ap->a_vap;
1006 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1007 PUFFS_VN_MKDIR, VPTOPNC(dvp));
1009 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1011 error = checkerr(pmp, error, __func__);
1012 if (error)
1013 goto out;
1015 error = puffs_newnode(mp, dvp, ap->a_vpp,
1016 mkdir_msg->pvnr_newnode, VDIR);
1017 if (error)
1018 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1019 mkdir_msg->pvnr_newnode, ncp, cred);
1021 out:
1022 vput(dvp);
1023 if (!error) {
1024 cache_setunresolved(nch);
1025 cache_setvp(nch, *ap->a_vpp);
1027 PUFFS_MSG_RELEASE(mkdir);
1028 return error;
1031 static int
1032 callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1033 struct namecache *ncp, struct ucred *cred)
1035 PUFFS_MSG_VARS(vn, rmdir);
1036 int error;
1038 PUFFS_MSG_ALLOC(vn, rmdir);
1039 rmdir_msg->pvnr_cookie_targ = ck;
1040 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1041 ncp, cred);
1042 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1044 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1045 PUFFS_MSG_RELEASE(rmdir);
1047 return checkerr(pmp, error, __func__);
1050 static int
1051 puffs_vnop_rmdir(struct vop_nrmdir_args *ap)
1053 PUFFS_MSG_VARS(vn, rmdir);
1054 struct vnode *dvp = ap->a_dvp;
1055 struct vnode *vp;
1056 struct puffs_node *dpn = VPTOPP(dvp);
1057 struct puffs_node *pn;
1058 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1059 struct nchandle *nch = ap->a_nch;
1060 struct namecache *ncp = nch->ncp;
1061 struct ucred *cred = ap->a_cred;
1062 int error;
1064 if (!EXISTSOP(pmp, RMDIR))
1065 return EOPNOTSUPP;
1067 error = vget(dvp, LK_EXCLUSIVE);
1068 if (error != 0) {
1069 DPRINTF(("puffs_vnop_rmdir: EAGAIN on parent vnode %p %s\n",
1070 dvp, ncp->nc_name));
1071 return EAGAIN;
1073 error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
1074 if (error != 0) {
1075 DPRINTF(("puffs_vnop_rmdir: cache_vget error: %p %s\n",
1076 dvp, ncp->nc_name));
1077 return EAGAIN;
1079 if (vp->v_type != VDIR) {
1080 error = ENOTDIR;
1081 goto out;
1084 pn = VPTOPP(vp);
1085 PUFFS_MSG_ALLOC(vn, rmdir);
1086 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1087 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1088 ncp, cred);
1089 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1090 PUFFS_VN_RMDIR, VPTOPNC(dvp));
1092 puffs_msg_enqueue(pmp, park_rmdir);
1093 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1095 PUFFS_MSG_RELEASE(rmdir);
1097 error = checkerr(pmp, error, __func__);
1099 out:
1100 vput(dvp);
1101 vn_unlock(vp);
1102 if (error == 0)
1103 cache_unlink(nch);
1104 vrele(vp);
1105 return error;
1108 static int
1109 puffs_vnop_link(struct vop_nlink_args *ap)
1111 PUFFS_MSG_VARS(vn, link);
1112 struct vnode *dvp = ap->a_dvp;
1113 struct vnode *vp = ap->a_vp;
1114 struct puffs_node *dpn = VPTOPP(dvp);
1115 struct puffs_node *pn = VPTOPP(vp);
1116 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1117 struct nchandle *nch = ap->a_nch;
1118 struct namecache *ncp = nch->ncp;
1119 struct ucred *cred = ap->a_cred;
1120 int error;
1122 if (!EXISTSOP(pmp, LINK))
1123 return EOPNOTSUPP;
1125 if (vp->v_mount != dvp->v_mount)
1126 return EXDEV;
1128 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
1129 DPRINTF(("puffs_vnop_link: EAGAIN on ncp %p %s\n",
1130 ncp, ncp->nc_name));
1131 return EAGAIN;
1134 PUFFS_MSG_ALLOC(vn, link);
1135 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1136 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1137 ncp, cred);
1138 puffs_msg_setinfo(park_link, PUFFSOP_VN,
1139 PUFFS_VN_LINK, VPTOPNC(dvp));
1141 puffs_msg_enqueue(pmp, park_link);
1142 error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1144 PUFFS_MSG_RELEASE(link);
1146 error = checkerr(pmp, error, __func__);
1149 * XXX: stay in touch with the cache. I don't like this, but
1150 * don't have a better solution either. See also puffs_rename().
1152 if (error == 0) {
1153 puffs_updatenode(pn, PUFFS_UPDATECTIME);
1156 vput(dvp);
1157 if (error == 0) {
1158 cache_setunresolved(nch);
1159 cache_setvp(nch, vp);
1161 return error;
1164 static int
1165 puffs_vnop_symlink(struct vop_nsymlink_args *ap)
1167 PUFFS_MSG_VARS(vn, symlink);
1168 struct vnode *dvp = ap->a_dvp;
1169 struct puffs_node *dpn = VPTOPP(dvp);
1170 struct mount *mp = dvp->v_mount;
1171 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1172 struct nchandle *nch = ap->a_nch;
1173 struct namecache *ncp = nch->ncp;
1174 struct ucred *cred = ap->a_cred;
1175 int error;
1177 if (!EXISTSOP(pmp, SYMLINK))
1178 return EOPNOTSUPP;
1180 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
1181 DPRINTF(("puffs_vnop_symlink: EAGAIN on ncp %p %s\n",
1182 ncp, ncp->nc_name));
1183 return EAGAIN;
1186 *ap->a_vpp = NULL;
1188 PUFFS_MSG_ALLOC(vn, symlink);
1189 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1190 ncp, cred);
1191 symlink_msg->pvnr_va = *ap->a_vap;
1192 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1193 sizeof(symlink_msg->pvnr_link));
1194 puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
1195 PUFFS_VN_SYMLINK, VPTOPNC(dvp));
1197 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
1199 error = checkerr(pmp, error, __func__);
1200 if (error)
1201 goto out;
1203 error = puffs_newnode(mp, dvp, ap->a_vpp,
1204 symlink_msg->pvnr_newnode, VLNK);
1205 if (error)
1206 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
1207 symlink_msg->pvnr_newnode, ncp, cred);
1209 out:
1210 vput(dvp);
1211 PUFFS_MSG_RELEASE(symlink);
1212 if (!error) {
1213 cache_setunresolved(nch);
1214 cache_setvp(nch, *ap->a_vpp);
1216 return error;
1219 static int
1220 puffs_vnop_readlink(struct vop_readlink_args *ap)
1222 PUFFS_MSG_VARS(vn, readlink);
1223 struct vnode *vp = ap->a_vp;
1224 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1225 size_t linklen;
1226 int error;
1228 if (!EXISTSOP(pmp, READLINK))
1229 return EOPNOTSUPP;
1231 PUFFS_MSG_ALLOC(vn, readlink);
1232 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1233 linklen = sizeof(readlink_msg->pvnr_link);
1234 readlink_msg->pvnr_linklen = linklen;
1235 puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
1236 PUFFS_VN_READLINK, VPTOPNC(vp));
1238 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
1239 error = checkerr(pmp, error, __func__);
1240 if (error)
1241 goto out;
1243 /* bad bad user file server */
1244 if (readlink_msg->pvnr_linklen > linklen) {
1245 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
1246 "linklen too big", VPTOPNC(ap->a_vp));
1247 error = EPROTO;
1248 goto out;
1251 error = uiomove(readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1252 ap->a_uio);
1253 out:
1254 PUFFS_MSG_RELEASE(readlink);
1255 return error;
1258 static int
1259 puffs_vnop_rename(struct vop_nrename_args *ap)
1261 PUFFS_MSG_VARS(vn, rename);
1262 struct nchandle *fnch = ap->a_fnch;
1263 struct nchandle *tnch = ap->a_tnch;
1264 struct vnode *fdvp = ap->a_fdvp;
1265 struct vnode *fvp = fnch->ncp->nc_vp;
1266 struct vnode *tdvp = ap->a_tdvp;
1267 struct vnode *tvp = tnch->ncp->nc_vp;
1268 struct ucred *cred = ap->a_cred;
1269 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
1270 int error;
1272 if (!EXISTSOP(pmp, RENAME))
1273 return EOPNOTSUPP;
1275 error = vget(tdvp, LK_EXCLUSIVE);
1276 if (error != 0) {
1277 DPRINTF(("puffs_vnop_rename: EAGAIN on tdvp vnode %p %s\n",
1278 tdvp, tnch->ncp->nc_name));
1279 return EAGAIN;
1281 if (tvp != NULL) {
1282 error = vget(tvp, LK_EXCLUSIVE);
1283 if (error != 0) {
1284 DPRINTF(("puffs_vnop_rename: EAGAIN on tvp vnode %p %s\n",
1285 tvp, tnch->ncp->nc_name));
1286 vput(tdvp);
1287 return EAGAIN;
1291 if ((fvp->v_mount != tdvp->v_mount) ||
1292 (tvp && (fvp->v_mount != tvp->v_mount))) {
1293 error = EXDEV;
1294 goto out;
1297 if (tvp) {
1298 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1299 error = ENOTDIR;
1300 goto out;
1301 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1302 error = EISDIR;
1303 goto out;
1307 PUFFS_MSG_ALLOC(vn, rename);
1308 rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
1309 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
1310 if (tvp)
1311 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
1312 else
1313 rename_msg->pvnr_cookie_targ = NULL;
1314 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
1315 fnch->ncp, cred);
1316 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
1317 tnch->ncp, cred);
1318 puffs_msg_setinfo(park_rename, PUFFSOP_VN,
1319 PUFFS_VN_RENAME, VPTOPNC(fdvp));
1321 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
1322 PUFFS_MSG_RELEASE(rename);
1323 error = checkerr(pmp, error, __func__);
1325 if (error == 0)
1326 puffs_updatenode(VPTOPP(fvp), PUFFS_UPDATECTIME);
1328 out:
1329 if (tvp != NULL)
1330 vn_unlock(tvp);
1331 if (tdvp != tvp)
1332 vn_unlock(tdvp);
1333 if (error == 0)
1334 cache_rename(fnch, tnch);
1335 if (tvp != NULL)
1336 vrele(tvp);
1337 vrele(tdvp);
1339 return error;
1342 static int
1343 puffs_vnop_read(struct vop_read_args *ap)
1345 struct vnode *vp = ap->a_vp;
1346 struct uio *uio = ap->a_uio;
1347 int ioflag = ap->a_ioflag;
1348 struct ucred * cred = ap->a_cred;
1349 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1350 int error;
1352 if (!EXISTSOP(pmp, READ))
1353 return EOPNOTSUPP;
1355 if (vp->v_type == VDIR)
1356 return EISDIR;
1357 else if (vp->v_type != VREG)
1358 return EINVAL;
1360 if (PUFFS_USE_PAGECACHE(pmp))
1361 error = puffs_bioread(vp, uio, ioflag, cred);
1362 else
1363 error = puffs_directread(vp, uio, ioflag, cred);
1365 return error;
1368 static int
1369 puffs_vnop_write(struct vop_write_args *ap)
1371 struct vnode *vp = ap->a_vp;
1372 struct uio *uio = ap->a_uio;
1373 int ioflag = ap->a_ioflag;
1374 struct ucred * cred = ap->a_cred;
1375 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1376 int error;
1378 if (!EXISTSOP(pmp, WRITE))
1379 return EOPNOTSUPP;
1381 if (vp->v_type == VDIR)
1382 return EISDIR;
1383 else if (vp->v_type != VREG)
1384 return EINVAL;
1386 if (PUFFS_USE_PAGECACHE(pmp))
1387 error = puffs_biowrite(vp, uio, ioflag, cred);
1388 else
1389 error = puffs_directwrite(vp, uio, ioflag, cred);
1391 return error;
1394 static int
1395 puffs_vnop_print(struct vop_print_args *ap)
1397 PUFFS_MSG_VARS(vn, print);
1398 struct vnode *vp = ap->a_vp;
1399 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1400 struct puffs_node *pn = VPTOPP(vp);
1401 int error;
1403 /* kernel portion */
1404 kprintf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1405 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
1406 if (vp->v_type == VFIFO)
1407 fifo_printinfo(vp);
1408 kprintf("\n");
1410 /* userspace portion */
1411 if (EXISTSOP(pmp, PRINT)) {
1412 PUFFS_MSG_ALLOC(vn, print);
1413 puffs_msg_setinfo(park_print, PUFFSOP_VN,
1414 PUFFS_VN_PRINT, VPTOPNC(vp));
1415 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
1416 NULL, error);
1417 PUFFS_MSG_RELEASE(print);
1420 return 0;
1423 static int
1424 puffs_vnop_pathconf(struct vop_pathconf_args *ap)
1426 PUFFS_MSG_VARS(vn, pathconf);
1427 struct vnode *vp = ap->a_vp;
1428 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1429 int error;
1431 if (!EXISTSOP(pmp, PATHCONF))
1432 return EOPNOTSUPP;
1434 PUFFS_MSG_ALLOC(vn, pathconf);
1435 pathconf_msg->pvnr_name = ap->a_name;
1436 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
1437 PUFFS_VN_PATHCONF, VPTOPNC(vp));
1438 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
1439 error = checkerr(pmp, error, __func__);
1440 if (!error)
1441 *ap->a_retval = pathconf_msg->pvnr_retval;
1442 PUFFS_MSG_RELEASE(pathconf);
1444 return error;
1447 static int
1448 puffs_vnop_advlock(struct vop_advlock_args *ap)
1450 PUFFS_MSG_VARS(vn, advlock);
1451 struct vnode *vp = ap->a_vp;
1452 struct puffs_node *pn = VPTOPP(vp);
1453 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1454 int error;
1456 if (!EXISTSOP(pmp, ADVLOCK))
1457 return lf_advlock(ap, &pn->pn_lockf, vp->v_filesize);
1459 PUFFS_MSG_ALLOC(vn, advlock);
1460 (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
1461 sizeof(advlock_msg->pvnr_fl));
1462 advlock_msg->pvnr_id = ap->a_id;
1463 advlock_msg->pvnr_op = ap->a_op;
1464 advlock_msg->pvnr_flags = ap->a_flags;
1465 puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
1466 PUFFS_VN_ADVLOCK, VPTOPNC(vp));
1467 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
1468 error = checkerr(pmp, error, __func__);
1469 PUFFS_MSG_RELEASE(advlock);
1471 return error;
1474 static int
1475 puffs_vnop_bmap(struct vop_bmap_args *ap)
1477 if (ap->a_doffsetp != NULL)
1478 *ap->a_doffsetp = ap->a_loffset;
1479 if (ap->a_runp != NULL)
1480 *ap->a_runp = 0;
1481 if (ap->a_runb != NULL)
1482 *ap->a_runb = 0;
1483 return (0);
1486 static int
1487 puffs_vnop_mmap(struct vop_mmap_args *ap)
1489 return EINVAL;
1493 static int
1494 puffs_vnop_strategy(struct vop_strategy_args *ap)
1496 return puffs_doio(ap->a_vp, ap->a_bio, curthread);
1499 struct vop_ops puffs_fifo_vops = {
1500 .vop_default = fifo_vnoperate,
1501 .vop_access = puffs_vnop_access,
1502 .vop_getattr = puffs_vnop_getattr,
1503 .vop_setattr = puffs_vnop_setattr,
1504 .vop_inactive = puffs_vnop_inactive,
1505 .vop_reclaim = puffs_vnop_reclaim,
1506 .vop_print = puffs_vnop_print,
1509 struct vop_ops puffs_vnode_vops = {
1510 .vop_default = vop_defaultop,
1511 .vop_nresolve = puffs_vnop_lookup,
1512 .vop_nlookupdotdot = puffs_vnop_lookupdotdot,
1513 .vop_ncreate = puffs_vnop_create,
1514 .vop_nmkdir = puffs_vnop_mkdir,
1515 .vop_nrmdir = puffs_vnop_rmdir,
1516 .vop_nremove = puffs_vnop_remove,
1517 .vop_nrename = puffs_vnop_rename,
1518 .vop_nlink = puffs_vnop_link,
1519 .vop_nsymlink = puffs_vnop_symlink,
1520 .vop_nmknod = puffs_vnop_mknod,
1521 .vop_access = puffs_vnop_access,
1522 .vop_getattr = puffs_vnop_getattr,
1523 .vop_setattr = puffs_vnop_setattr,
1524 .vop_readdir = puffs_vnop_readdir,
1525 .vop_open = puffs_vnop_open,
1526 .vop_close = puffs_vnop_close,
1527 .vop_read = puffs_vnop_read,
1528 .vop_write = puffs_vnop_write,
1529 .vop_readlink = puffs_vnop_readlink,
1530 .vop_advlock = puffs_vnop_advlock,
1531 .vop_bmap = puffs_vnop_bmap,
1532 .vop_mmap = puffs_vnop_mmap,
1533 .vop_strategy = puffs_vnop_strategy,
1534 .vop_getpages = vop_stdgetpages,
1535 .vop_putpages = vop_stdputpages,
1536 .vop_fsync = puffs_vnop_fsync,
1537 .vop_inactive = puffs_vnop_inactive,
1538 .vop_reclaim = puffs_vnop_reclaim,
1539 .vop_pathconf = puffs_vnop_pathconf,
1540 .vop_print = puffs_vnop_print,