kernel - Adjust devfs, hammer, and puffs to use the new cache_unlink()
[dragonfly.git] / sys / vfs / puffs / puffs_vnops.c
CommitLineData
ab5617b3
SW
1/* $NetBSD: puffs_vnops.c,v 1.154 2011/07/04 08:07:30 manu Exp $ */
2
3/*
4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/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>
40
41#include <vfs/fifofs/fifo.h>
42
43#include <vfs/puffs/puffs_msgif.h>
44#include <vfs/puffs/puffs_sys.h>
45
46int (**puffs_vnodeop_p)(void *);
47
48#define ERROUT(err) \
49do { \
50 error = err; \
51 goto out; \
52} while (/*CONSTCOND*/0)
53
54static int callremove(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
55 struct namecache *, struct ucred *);
56static int callrmdir(struct puffs_mount *, puffs_cookie_t, puffs_cookie_t,
57 struct namecache *, struct ucred *);
58static void callinactive(struct puffs_mount *, puffs_cookie_t, int);
59static void callreclaim(struct puffs_mount *, puffs_cookie_t);
60static int flushvncache(struct vnode *, int);
61
62
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
68
69/*
70 * Press the pani^Wabort button! Kernel resource allocation failed.
71 */
72static void
73puffs_abortbutton(struct puffs_mount *pmp, int what,
74 puffs_cookie_t dck, puffs_cookie_t ck,
75 struct namecache *ncp, struct ucred *cred)
76{
77
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;
87 }
88
89 callinactive(pmp, ck, 0);
90 callreclaim(pmp, ck);
91}
92
93/*
94 * Begin vnode operations.
95 *
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.
105 */
106static int
107puffs_vnop_lookup(struct vop_nresolve_args *ap)
108{
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;
64242bb1 114 struct vnode *vp = NULL, *dvp = ap->a_dvp;
ab5617b3
SW
115 struct puffs_node *dpn;
116 int error;
117
118 DPRINTF(("puffs_lookup: \"%s\", parent vnode %p\n",
119 ncp->nc_name, dvp));
120
ab5617b3
SW
121 PUFFS_MSG_ALLOC(vn, lookup);
122 puffs_makecn(&lookup_msg->pvnr_cn, &lookup_msg->pvnr_cn_cred,
123 ncp, cred);
124
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;
134 }
135
136 /*
137 * Check that we don't get our parent node back, that would cause
138 * a pretty obvious deadlock.
139 */
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;
146 }
147
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;
157 }
158 } else if (error) {
159 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
160 lookup_msg->pvnr_newnode, ncp, cred);
161 goto out;
162 }
163
164 out:
64242bb1 165 if (!error && vp != NULL) {
ab5617b3
SW
166 vn_unlock(vp);
167 cache_setvp(nch, vp);
168 vrele(vp);
169 }
170 DPRINTF(("puffs_lookup: returning %d\n", error));
171 PUFFS_MSG_RELEASE(lookup);
172 return error;
173}
174
175static int
176puffs_vnop_lookupdotdot(struct vop_nlookupdotdot_args *ap)
177{
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;
184
185 *ap->a_vpp = NULL;
186
187 DPRINTF(("puffs_lookupdotdot: vnode %p\n", dvp));
188
189 PUFFS_MSG_ALLOC(vn, lookupdotdot);
190 puffs_credcvt(&lookupdotdot_msg->pvnr_cred, cred);
191
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;
201 }
202
203 /*
204 * Check that we don't get our node back, that would cause
205 * a pretty obvious deadlock.
206 */
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;
214 }
215
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;
225 }
226 } else if (error) {
227 puffs_abortbutton(pmp, PUFFS_ABORT_LOOKUP, VPTOPNC(dvp),
228 lookupdotdot_msg->pvnr_newnode, NULL, cred);
229 goto out;
230 }
231
232 *ap->a_vpp = vp;
233 vn_unlock(vp);
234
235 out:
236 DPRINTF(("puffs_lookupdotdot: returning %d %p\n", error, *ap->a_vpp));
237 PUFFS_MSG_RELEASE(lookupdotdot);
238 return error;
239}
240
241static int
242puffs_vnop_create(struct vop_ncreate_args *ap)
243{
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;
254
376a18e4
AH
255 if (!EXISTSOP(pmp, CREATE))
256 return EOPNOTSUPP;
257
ab5617b3
SW
258 DPRINTF(("puffs_create: dvp %p, name: %s\n",
259 dvp, ncp->nc_name));
260
261 if (vap->va_type != VREG && vap->va_type != VSOCK)
262 return EINVAL;
263
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;
268 }
269
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);
277
278 error = checkerr(pmp, error, __func__);
279 if (error)
280 goto out;
281
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);
287
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);
294 }
295 PUFFS_MSG_RELEASE(create);
296 return error;
297}
298
299static int
300puffs_vnop_mknod(struct vop_nmknod_args *ap)
301{
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;
312
376a18e4
AH
313 if (!EXISTSOP(pmp, MKNOD))
314 return EOPNOTSUPP;
315
ab5617b3
SW
316 DPRINTF(("puffs_mknod: dvp %p, name: %s\n",
317 dvp, ncp->nc_name));
318
319 if (vap->va_type != VFIFO)
320 return EINVAL;
321
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;
326 }
327
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));
334
335 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mknod, dvp->v_data, NULL, error);
336
337 error = checkerr(pmp, error, __func__);
338 if (error)
339 goto out;
340
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);
346
347 out:
348 vput(dvp);
349 if (!error) {
350 cache_setunresolved(nch);
351 cache_setvp(nch, *ap->a_vpp);
352 }
353 PUFFS_MSG_RELEASE(mknod);
354 return error;
355}
356
357static int
358puffs_vnop_open(struct vop_open_args *ap)
359{
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;
365
366 DPRINTF(("puffs_open: vp %p, mode 0x%x\n", vp, mode));
367
368 if (vp->v_type == VREG && mode & FWRITE && !EXISTSOP(pmp, WRITE))
369 ERROUT(EROFS);
370
371 if (!EXISTSOP(pmp, OPEN))
372 ERROUT(0);
373
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));
379
380 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_open, vp->v_data, NULL, error);
381 error = checkerr(pmp, error, __func__);
382
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);
389}
390
391static int
392puffs_vnop_close(struct vop_close_args *ap)
393{
394 PUFFS_MSG_VARS(vn, close);
395 struct vnode *vp = ap->a_vp;
396 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
397
376a18e4
AH
398 if (!EXISTSOP(pmp, CLOSE))
399 return vop_stdclose(ap);
400
ab5617b3
SW
401 PUFFS_MSG_ALLOC(vn, close);
402 puffs_msg_setfaf(park_close);
403 close_msg->pvnr_fflag = ap->a_fflag;
404 puffs_msg_setinfo(park_close, PUFFSOP_VN,
405 PUFFS_VN_CLOSE, VPTOPNC(vp));
406
407 puffs_msg_enqueue(pmp, park_close);
408 PUFFS_MSG_RELEASE(close);
409 return vop_stdclose(ap);
410}
411
412static int
413puffs_vnop_access(struct vop_access_args *ap)
414{
415 PUFFS_MSG_VARS(vn, access);
416 struct vnode *vp = ap->a_vp;
417 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
418 int mode = ap->a_mode;
419 int error;
420
421 if (mode & VWRITE) {
422 switch (vp->v_type) {
423 case VDIR:
424 case VLNK:
425 case VREG:
426 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
427 || !EXISTSOP(pmp, WRITE))
428 return EROFS;
429 break;
430 default:
431 break;
432 }
433 }
434
435 if (!EXISTSOP(pmp, ACCESS))
436 return 0;
437
438 PUFFS_MSG_ALLOC(vn, access);
439 access_msg->pvnr_mode = ap->a_mode;
440 puffs_credcvt(&access_msg->pvnr_cred, ap->a_cred);
441 puffs_msg_setinfo(park_access, PUFFSOP_VN,
442 PUFFS_VN_ACCESS, VPTOPNC(vp));
443
444 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_access, vp->v_data, NULL, error);
445 error = checkerr(pmp, error, __func__);
446 PUFFS_MSG_RELEASE(access);
447
448 return error;
449}
450
451static int
452puffs_vnop_getattr(struct vop_getattr_args *ap)
453{
454 PUFFS_MSG_VARS(vn, getattr);
455 struct vnode *vp = ap->a_vp;
456 struct mount *mp = vp->v_mount;
457 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
458 struct vattr *vap, *rvap;
459 struct puffs_node *pn = VPTOPP(vp);
460 int error = 0;
461
462 if (vp->v_type == VBLK || vp->v_type == VCHR)
463 return ENOTSUP;
464
465 vap = ap->a_vap;
466
467 PUFFS_MSG_ALLOC(vn, getattr);
468 vattr_null(&getattr_msg->pvnr_va);
469 puffs_credcvt(&getattr_msg->pvnr_cred, curproc->p_ucred);
470 puffs_msg_setinfo(park_getattr, PUFFSOP_VN,
471 PUFFS_VN_GETATTR, VPTOPNC(vp));
472
473 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_getattr, vp->v_data, NULL, error);
474 error = checkerr(pmp, error, __func__);
475 if (error)
476 goto out;
477
478 rvap = &getattr_msg->pvnr_va;
479
480 (void) memcpy(vap, rvap, sizeof(struct vattr));
481 vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
482
483 if (pn->pn_stat & PNODE_METACACHE_ATIME)
484 vap->va_atime = pn->pn_mc_atime;
485 if (pn->pn_stat & PNODE_METACACHE_CTIME)
486 vap->va_ctime = pn->pn_mc_ctime;
487 if (pn->pn_stat & PNODE_METACACHE_MTIME)
488 vap->va_mtime = pn->pn_mc_mtime;
489 if (pn->pn_stat & PNODE_METACACHE_SIZE) {
490 vap->va_size = pn->pn_mc_size;
491 } else {
492 if (rvap->va_size != VNOVAL
493 && vp->v_type != VBLK && vp->v_type != VCHR) {
494 pn->pn_serversize = rvap->va_size;
495 if (vp->v_type == VREG)
496 puffs_meta_setsize(vp, rvap->va_size, 0);
497 }
498 }
499
500 out:
501 PUFFS_MSG_RELEASE(getattr);
502 return error;
503}
504
505#define SETATTR_CHSIZE 0x01
506#define SETATTR_ASYNC 0x02
507static int
508dosetattr(struct vnode *vp, struct vattr *vap, struct ucred *cred, int flags)
509{
510 PUFFS_MSG_VARS(vn, setattr);
511 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
512 struct puffs_node *pn = VPTOPP(vp);
513 int error = 0;
514
515 if ((vp->v_mount->mnt_flag & MNT_RDONLY) &&
516 (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL
517 || vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL
518 || vap->va_mode != (mode_t)VNOVAL))
519 return EROFS;
520
521 if ((vp->v_mount->mnt_flag & MNT_RDONLY)
522 && vp->v_type == VREG && vap->va_size != VNOVAL)
523 return EROFS;
524
525 /*
526 * Flush metacache first. If we are called with some explicit
527 * parameters, treat them as information overriding metacache
528 * information.
529 */
530 if (pn->pn_stat & PNODE_METACACHE_MASK) {
531 if ((pn->pn_stat & PNODE_METACACHE_ATIME)
532 && vap->va_atime.tv_sec == VNOVAL)
533 vap->va_atime = pn->pn_mc_atime;
534 if ((pn->pn_stat & PNODE_METACACHE_CTIME)
535 && vap->va_ctime.tv_sec == VNOVAL)
536 vap->va_ctime = pn->pn_mc_ctime;
537 if ((pn->pn_stat & PNODE_METACACHE_MTIME)
538 && vap->va_mtime.tv_sec == VNOVAL)
539 vap->va_mtime = pn->pn_mc_mtime;
540 if ((pn->pn_stat & PNODE_METACACHE_SIZE)
541 && vap->va_size == VNOVAL)
542 vap->va_size = pn->pn_mc_size;
543
544 pn->pn_stat &= ~PNODE_METACACHE_MASK;
545 }
546
547 PUFFS_MSG_ALLOC(vn, setattr);
548 (void)memcpy(&setattr_msg->pvnr_va, vap, sizeof(struct vattr));
549 puffs_credcvt(&setattr_msg->pvnr_cred, cred);
550 puffs_msg_setinfo(park_setattr, PUFFSOP_VN,
551 PUFFS_VN_SETATTR, VPTOPNC(vp));
552 if (flags & SETATTR_ASYNC)
553 puffs_msg_setfaf(park_setattr);
554
555 puffs_msg_enqueue(pmp, park_setattr);
556 if ((flags & SETATTR_ASYNC) == 0)
557 error = puffs_msg_wait2(pmp, park_setattr, vp->v_data, NULL);
558 PUFFS_MSG_RELEASE(setattr);
559 if ((flags & SETATTR_ASYNC) == 0) {
560 error = checkerr(pmp, error, __func__);
561 if (error)
562 return error;
563 } else {
564 error = 0;
565 }
566
567 if (vap->va_size != VNOVAL) {
568 pn->pn_serversize = vap->va_size;
569 if (flags & SETATTR_CHSIZE)
570 puffs_meta_setsize(vp, vap->va_size, 0);
571 }
572
573 return 0;
574}
575
576static int
577puffs_vnop_setattr(struct vop_setattr_args *ap)
578{
579 return dosetattr(ap->a_vp, ap->a_vap, ap->a_cred, SETATTR_CHSIZE);
580}
581
582static __inline int
583doinact(struct puffs_mount *pmp, int iaflag)
584{
585
586 if (EXISTSOP(pmp, INACTIVE))
587 if (pmp->pmp_flags & PUFFS_KFLAG_IAONDEMAND)
588 if (iaflag || ALLOPS(pmp))
589 return 1;
590 else
591 return 0;
592 else
593 return 1;
594 else
595 return 0;
596}
597
598static void
599callinactive(struct puffs_mount *pmp, puffs_cookie_t ck, int iaflag)
600{
601 int error;
602 PUFFS_MSG_VARS(vn, inactive);
603
604 if (doinact(pmp, iaflag)) {
605 PUFFS_MSG_ALLOC(vn, inactive);
606 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
607 PUFFS_VN_INACTIVE, ck);
608
609 PUFFS_MSG_ENQUEUEWAIT(pmp, park_inactive, error);
610 PUFFS_MSG_RELEASE(inactive);
611 }
612}
613
614/* XXX: callinactive can't setback */
615static int
616puffs_vnop_inactive(struct vop_inactive_args *ap)
617{
618 PUFFS_MSG_VARS(vn, inactive);
619 struct vnode *vp = ap->a_vp;
620 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
621 struct puffs_node *pnode = VPTOPP(vp);
622
623 flushvncache(vp, MNT_NOWAIT);
624
625 if (doinact(pmp, pnode->pn_stat & PNODE_DOINACT)) {
626 /*
627 * do not wait for reply from userspace, otherwise it may
628 * deadlock.
629 */
630
631 PUFFS_MSG_ALLOC(vn, inactive);
632 puffs_msg_setfaf(park_inactive);
633 puffs_msg_setinfo(park_inactive, PUFFSOP_VN,
634 PUFFS_VN_INACTIVE, VPTOPNC(vp));
635
636 puffs_msg_enqueue(pmp, park_inactive);
637 PUFFS_MSG_RELEASE(inactive);
638 }
639 pnode->pn_stat &= ~PNODE_DOINACT;
640
641 /*
642 * file server thinks it's gone? then don't be afraid care,
643 * node's life was already all it would ever be
644 */
645 if (pnode->pn_stat & PNODE_NOREFS) {
646 pnode->pn_stat |= PNODE_DYING;
647 vrecycle(vp);
648 }
649
650 return 0;
651}
652
653static void
654callreclaim(struct puffs_mount *pmp, puffs_cookie_t ck)
655{
656 PUFFS_MSG_VARS(vn, reclaim);
657
658 if (!EXISTSOP(pmp, RECLAIM))
659 return;
660
661 PUFFS_MSG_ALLOC(vn, reclaim);
662 puffs_msg_setfaf(park_reclaim);
663 puffs_msg_setinfo(park_reclaim, PUFFSOP_VN, PUFFS_VN_RECLAIM, ck);
664
665 puffs_msg_enqueue(pmp, park_reclaim);
666 PUFFS_MSG_RELEASE(reclaim);
667}
668
669/*
670 * always FAF, we don't really care if the server wants to fail to
671 * reclaim the node or not
672 */
673static int
674puffs_vnop_reclaim(struct vop_reclaim_args *ap)
675{
676 struct vnode *vp = ap->a_vp;
677 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
678 struct puffs_node *pnode = VPTOPP(vp);
679 boolean_t notifyserver = TRUE;
680
681 vinvalbuf(vp, V_SAVE, 0, 0);
682
683 /*
684 * first things first: check if someone is trying to reclaim the
685 * root vnode. do not allow that to travel to userspace.
686 * Note that we don't need to take the lock similarly to
687 * puffs_root(), since there is only one of us.
688 */
689 if (vp->v_flag & VROOT) {
690 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
691 KKASSERT(pmp->pmp_root != NULL);
692 pmp->pmp_root = NULL;
693 lockmgr(&pmp->pmp_lock, LK_RELEASE);
694 notifyserver = FALSE;
695 }
696
697 /*
698 * purge info from kernel before issueing FAF, since we
699 * don't really know when we'll get around to it after
700 * that and someone might race us into node creation
701 */
702 lockmgr(&pmp->pmp_lock, LK_EXCLUSIVE);
703 LIST_REMOVE(pnode, pn_hashent);
704 lockmgr(&pmp->pmp_lock, LK_RELEASE);
705
706 if (notifyserver)
707 callreclaim(MPTOPUFFSMP(vp->v_mount), VPTOPNC(vp));
708
709 puffs_putvnode(vp);
710 vp->v_data = NULL;
711
712 return 0;
713}
714
715#define CSIZE sizeof(**ap->a_cookies)
716static int
717puffs_vnop_readdir(struct vop_readdir_args *ap)
718{
719 PUFFS_MSG_VARS(vn, readdir);
720 struct vnode *vp = ap->a_vp;
721 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
722 size_t argsize, tomove, cookiemem, cookiesmax;
723 struct uio *uio = ap->a_uio;
724 size_t howmuch, resid;
725 int error;
726
376a18e4
AH
727 if (!EXISTSOP(pmp, READDIR))
728 return EOPNOTSUPP;
729
ab5617b3
SW
730 /*
731 * ok, so we need: resid + cookiemem = maxreq
732 * => resid + cookiesize * (resid/minsize) = maxreq
733 * => resid + cookiesize/minsize * resid = maxreq
734 * => (cookiesize/minsize + 1) * resid = maxreq
735 * => resid = maxreq / (cookiesize/minsize + 1)
736 *
737 * Since cookiesize <= minsize and we're not very big on floats,
738 * we approximate that to be 1. Therefore:
739 *
740 * resid = maxreq / 2;
741 *
742 * Well, at least we didn't have to use differential equations
743 * or the Gram-Schmidt process.
744 *
745 * (yes, I'm very afraid of this)
746 */
747 KKASSERT(CSIZE <= _DIRENT_RECLEN(1));
748
749 if (ap->a_cookies) {
750 KKASSERT(ap->a_ncookies != NULL);
751 if (pmp->pmp_args.pa_fhsize == 0)
752 return EOPNOTSUPP;
753 resid = PUFFS_TOMOVE(uio->uio_resid, pmp) / 2;
754 cookiesmax = resid/_DIRENT_RECLEN(1);
755 cookiemem = ALIGN(cookiesmax*CSIZE); /* play safe */
756 } else {
757 resid = PUFFS_TOMOVE(uio->uio_resid, pmp);
758 cookiesmax = 0;
759 cookiemem = 0;
760 }
761
762 argsize = sizeof(struct puffs_vnmsg_readdir);
763 tomove = resid + cookiemem;
764 puffs_msgmem_alloc(argsize + tomove, &park_readdir,
765 (void *)&readdir_msg, 1);
766
767 puffs_credcvt(&readdir_msg->pvnr_cred, ap->a_cred);
768 readdir_msg->pvnr_offset = uio->uio_offset;
769 readdir_msg->pvnr_resid = resid;
770 readdir_msg->pvnr_ncookies = cookiesmax;
771 readdir_msg->pvnr_eofflag = 0;
772 readdir_msg->pvnr_dentoff = cookiemem;
773 puffs_msg_setinfo(park_readdir, PUFFSOP_VN,
774 PUFFS_VN_READDIR, VPTOPNC(vp));
775 puffs_msg_setdelta(park_readdir, tomove);
776
777 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readdir, vp->v_data, NULL, error);
778 error = checkerr(pmp, error, __func__);
779 if (error)
780 goto out;
781
782 /* userspace is cheating? */
783 if (readdir_msg->pvnr_resid > resid) {
784 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
785 "resid grew", VPTOPNC(vp));
786 ERROUT(EPROTO);
787 }
788 if (readdir_msg->pvnr_ncookies > cookiesmax) {
789 puffs_senderr(pmp, PUFFS_ERR_READDIR, E2BIG,
790 "too many cookies", VPTOPNC(vp));
791 ERROUT(EPROTO);
792 }
793
794 /* check eof */
795 if (readdir_msg->pvnr_eofflag)
796 *ap->a_eofflag = 1;
797
798 /* bouncy-wouncy with the directory data */
799 howmuch = resid - readdir_msg->pvnr_resid;
800
801 /* force eof if no data was returned (getcwd() needs this) */
802 if (howmuch == 0) {
803 *ap->a_eofflag = 1;
804 goto out;
805 }
806
807 error = uiomove(readdir_msg->pvnr_data + cookiemem, howmuch, uio);
808 if (error)
809 goto out;
810
811 /* provide cookies to caller if so desired */
812 if (ap->a_cookies) {
813 *ap->a_cookies = kmalloc(readdir_msg->pvnr_ncookies*CSIZE,
814 M_TEMP, M_WAITOK);
815 *ap->a_ncookies = readdir_msg->pvnr_ncookies;
816 memcpy(*ap->a_cookies, readdir_msg->pvnr_data,
817 *ap->a_ncookies*CSIZE);
818 }
819
820 /* next readdir starts here */
821 uio->uio_offset = readdir_msg->pvnr_offset;
822
823 out:
824 puffs_msgmem_release(park_readdir);
825 return error;
826}
827#undef CSIZE
828
829static int
830flushvncache(struct vnode *vp, int waitfor)
831{
832 struct puffs_node *pn = VPTOPP(vp);
833 struct vattr va;
834 int error = 0;
835
836 /* flush out information from our metacache, see vop_setattr */
837 if (pn->pn_stat & PNODE_METACACHE_MASK
838 && (pn->pn_stat & PNODE_DYING) == 0) {
839 vattr_null(&va);
840 error = dosetattr(vp, &va, FSCRED, SETATTR_CHSIZE |
841 (waitfor == MNT_NOWAIT ? 0 : SETATTR_ASYNC));
842 if (error)
843 return error;
844 }
845
846 /*
847 * flush pages to avoid being overly dirty
848 */
849 vfsync(vp, waitfor, 0, NULL, NULL);
850
851 return error;
852}
853
854static int
855puffs_vnop_fsync(struct vop_fsync_args *ap)
856{
857 PUFFS_MSG_VARS(vn, fsync);
858 struct vnode *vp = ap->a_vp;
859 int waitfor = ap->a_waitfor;
860 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
861 struct puffs_node *pn = VPTOPP(vp);
862 int error, dofaf;
863
864 error = flushvncache(vp, waitfor);
865 if (error)
866 return error;
867
868 /*
869 * HELLO! We exit already here if the user server does not
870 * support fsync OR if we should call fsync for a node which
871 * has references neither in the kernel or the fs server.
872 * Otherwise we continue to issue fsync() forward.
873 */
874 if (!EXISTSOP(pmp, FSYNC) || (pn->pn_stat & PNODE_DYING))
875 return 0;
876
877 dofaf = (waitfor & MNT_WAIT) == 0 || (waitfor & MNT_LAZY) != 0;
878
879 PUFFS_MSG_ALLOC(vn, fsync);
880 if (dofaf)
881 puffs_msg_setfaf(park_fsync);
882
883 fsync_msg->pvnr_flags = ap->a_flags;
884 puffs_msg_setinfo(park_fsync, PUFFSOP_VN,
885 PUFFS_VN_FSYNC, VPTOPNC(vp));
886
887 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_fsync, vp->v_data, NULL, error);
888 PUFFS_MSG_RELEASE(fsync);
889
890 error = checkerr(pmp, error, __func__);
891
892 return error;
893}
894
895static int
896callremove(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
897 struct namecache *ncp, struct ucred *cred)
898{
899 PUFFS_MSG_VARS(vn, remove);
900 int error;
901
902 PUFFS_MSG_ALLOC(vn, remove);
903 remove_msg->pvnr_cookie_targ = ck;
904 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
905 ncp, cred);
906 puffs_msg_setinfo(park_remove, PUFFSOP_VN, PUFFS_VN_REMOVE, dck);
907
908 PUFFS_MSG_ENQUEUEWAIT(pmp, park_remove, error);
909 PUFFS_MSG_RELEASE(remove);
910
911 return checkerr(pmp, error, __func__);
912}
913
914/*
915 * XXX: can't use callremove now because can't catch setbacks with
916 * it due to lack of a pnode argument.
917 */
918static int
919puffs_vnop_remove(struct vop_nremove_args *ap)
920{
921 PUFFS_MSG_VARS(vn, remove);
922 struct vnode *dvp = ap->a_dvp;
923 struct vnode *vp;
924 struct puffs_node *dpn = VPTOPP(dvp);
6a640170 925 struct puffs_node *pn;
ab5617b3
SW
926 struct nchandle *nch = ap->a_nch;
927 struct namecache *ncp = nch->ncp;
928 struct ucred *cred = ap->a_cred;
929 struct mount *mp = dvp->v_mount;
930 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
931 int error;
932
376a18e4
AH
933 if (!EXISTSOP(pmp, REMOVE))
934 return EOPNOTSUPP;
935
ab5617b3
SW
936 error = vget(dvp, LK_EXCLUSIVE);
937 if (error != 0) {
938 DPRINTF(("puffs_vnop_remove: EAGAIN on parent vnode %p %s\n",
939 dvp, ncp->nc_name));
940 return EAGAIN;
941 }
942
943 error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
944 if (error != 0) {
945 DPRINTF(("puffs_vnop_remove: cache_vget error: %p %s\n",
946 dvp, ncp->nc_name));
947 return EAGAIN;
948 }
949 if (vp->v_type == VDIR) {
950 error = EISDIR;
951 goto out;
952 }
953
6a640170 954 pn = VPTOPP(vp);
ab5617b3
SW
955 PUFFS_MSG_ALLOC(vn, remove);
956 remove_msg->pvnr_cookie_targ = VPTOPNC(vp);
957 puffs_makecn(&remove_msg->pvnr_cn, &remove_msg->pvnr_cn_cred,
958 ncp, cred);
959 puffs_msg_setinfo(park_remove, PUFFSOP_VN,
960 PUFFS_VN_REMOVE, VPTOPNC(dvp));
961
962 puffs_msg_enqueue(pmp, park_remove);
963 error = puffs_msg_wait2(pmp, park_remove, dpn, pn);
964
965 PUFFS_MSG_RELEASE(remove);
966
967 error = checkerr(pmp, error, __func__);
968
969 out:
970 vput(dvp);
971 vn_unlock(vp);
5323ed62
MD
972 if (error == 0)
973 cache_unlink(nch);
ab5617b3
SW
974 vrele(vp);
975 return error;
976}
977
978static int
979puffs_vnop_mkdir(struct vop_nmkdir_args *ap)
980{
981 PUFFS_MSG_VARS(vn, mkdir);
982 struct vnode *dvp = ap->a_dvp;
983 struct puffs_node *dpn = VPTOPP(dvp);
984 struct nchandle *nch = ap->a_nch;
985 struct namecache *ncp = nch->ncp;
986 struct ucred *cred = ap->a_cred;
987 struct mount *mp = dvp->v_mount;
988 struct puffs_mount *pmp = MPTOPUFFSMP(mp);
989 int error;
990
376a18e4
AH
991 if (!EXISTSOP(pmp, MKDIR))
992 return EOPNOTSUPP;
993
ab5617b3
SW
994 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
995 DPRINTF(("puffs_vnop_mkdir: EAGAIN on ncp %p %s\n",
996 ncp, ncp->nc_name));
997 return EAGAIN;
998 }
999
1000 PUFFS_MSG_ALLOC(vn, mkdir);
1001 puffs_makecn(&mkdir_msg->pvnr_cn, &mkdir_msg->pvnr_cn_cred,
1002 ncp, cred);
1003 mkdir_msg->pvnr_va = *ap->a_vap;
1004 puffs_msg_setinfo(park_mkdir, PUFFSOP_VN,
1005 PUFFS_VN_MKDIR, VPTOPNC(dvp));
1006
1007 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_mkdir, dvp->v_data, NULL, error);
1008
1009 error = checkerr(pmp, error, __func__);
1010 if (error)
1011 goto out;
1012
1013 error = puffs_newnode(mp, dvp, ap->a_vpp,
1014 mkdir_msg->pvnr_newnode, VDIR);
1015 if (error)
1016 puffs_abortbutton(pmp, PUFFS_ABORT_MKDIR, dpn->pn_cookie,
1017 mkdir_msg->pvnr_newnode, ncp, cred);
1018
1019 out:
1020 vput(dvp);
1021 if (!error) {
1022 cache_setunresolved(nch);
1023 cache_setvp(nch, *ap->a_vpp);
1024 }
1025 PUFFS_MSG_RELEASE(mkdir);
1026 return error;
1027}
1028
1029static int
1030callrmdir(struct puffs_mount *pmp, puffs_cookie_t dck, puffs_cookie_t ck,
1031 struct namecache *ncp, struct ucred *cred)
1032{
1033 PUFFS_MSG_VARS(vn, rmdir);
1034 int error;
1035
1036 PUFFS_MSG_ALLOC(vn, rmdir);
1037 rmdir_msg->pvnr_cookie_targ = ck;
1038 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1039 ncp, cred);
1040 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN, PUFFS_VN_RMDIR, dck);
1041
1042 PUFFS_MSG_ENQUEUEWAIT(pmp, park_rmdir, error);
1043 PUFFS_MSG_RELEASE(rmdir);
1044
1045 return checkerr(pmp, error, __func__);
1046}
1047
1048static int
1049puffs_vnop_rmdir(struct vop_nrmdir_args *ap)
1050{
1051 PUFFS_MSG_VARS(vn, rmdir);
1052 struct vnode *dvp = ap->a_dvp;
1053 struct vnode *vp;
1054 struct puffs_node *dpn = VPTOPP(dvp);
6a640170 1055 struct puffs_node *pn;
ab5617b3
SW
1056 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1057 struct nchandle *nch = ap->a_nch;
1058 struct namecache *ncp = nch->ncp;
1059 struct ucred *cred = ap->a_cred;
1060 int error;
1061
376a18e4
AH
1062 if (!EXISTSOP(pmp, RMDIR))
1063 return EOPNOTSUPP;
1064
ab5617b3
SW
1065 error = vget(dvp, LK_EXCLUSIVE);
1066 if (error != 0) {
1067 DPRINTF(("puffs_vnop_rmdir: EAGAIN on parent vnode %p %s\n",
1068 dvp, ncp->nc_name));
1069 return EAGAIN;
1070 }
1071 error = cache_vget(nch, cred, LK_EXCLUSIVE, &vp);
1072 if (error != 0) {
1073 DPRINTF(("puffs_vnop_rmdir: cache_vget error: %p %s\n",
1074 dvp, ncp->nc_name));
1075 return EAGAIN;
1076 }
1077 if (vp->v_type != VDIR) {
1078 error = ENOTDIR;
1079 goto out;
1080 }
1081
6a640170 1082 pn = VPTOPP(vp);
ab5617b3
SW
1083 PUFFS_MSG_ALLOC(vn, rmdir);
1084 rmdir_msg->pvnr_cookie_targ = VPTOPNC(vp);
1085 puffs_makecn(&rmdir_msg->pvnr_cn, &rmdir_msg->pvnr_cn_cred,
1086 ncp, cred);
1087 puffs_msg_setinfo(park_rmdir, PUFFSOP_VN,
1088 PUFFS_VN_RMDIR, VPTOPNC(dvp));
1089
1090 puffs_msg_enqueue(pmp, park_rmdir);
1091 error = puffs_msg_wait2(pmp, park_rmdir, dpn, pn);
1092
1093 PUFFS_MSG_RELEASE(rmdir);
1094
1095 error = checkerr(pmp, error, __func__);
1096
1097 out:
1098 vput(dvp);
1099 vn_unlock(vp);
5323ed62
MD
1100 if (error == 0)
1101 cache_unlink(nch);
ab5617b3
SW
1102 vrele(vp);
1103 return error;
1104}
1105
1106static int
1107puffs_vnop_link(struct vop_nlink_args *ap)
1108{
1109 PUFFS_MSG_VARS(vn, link);
1110 struct vnode *dvp = ap->a_dvp;
1111 struct vnode *vp = ap->a_vp;
1112 struct puffs_node *dpn = VPTOPP(dvp);
1113 struct puffs_node *pn = VPTOPP(vp);
1114 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1115 struct nchandle *nch = ap->a_nch;
1116 struct namecache *ncp = nch->ncp;
1117 struct ucred *cred = ap->a_cred;
1118 int error;
1119
376a18e4
AH
1120 if (!EXISTSOP(pmp, LINK))
1121 return EOPNOTSUPP;
1122
ab5617b3
SW
1123 if (vp->v_mount != dvp->v_mount)
1124 return EXDEV;
1125
1126 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
1127 DPRINTF(("puffs_vnop_link: EAGAIN on ncp %p %s\n",
1128 ncp, ncp->nc_name));
1129 return EAGAIN;
1130 }
ab5617b3
SW
1131
1132 PUFFS_MSG_ALLOC(vn, link);
1133 link_msg->pvnr_cookie_targ = VPTOPNC(vp);
1134 puffs_makecn(&link_msg->pvnr_cn, &link_msg->pvnr_cn_cred,
1135 ncp, cred);
1136 puffs_msg_setinfo(park_link, PUFFSOP_VN,
1137 PUFFS_VN_LINK, VPTOPNC(dvp));
1138
1139 puffs_msg_enqueue(pmp, park_link);
1140 error = puffs_msg_wait2(pmp, park_link, dpn, pn);
1141
1142 PUFFS_MSG_RELEASE(link);
1143
1144 error = checkerr(pmp, error, __func__);
1145
1146 /*
1147 * XXX: stay in touch with the cache. I don't like this, but
1148 * don't have a better solution either. See also puffs_rename().
1149 */
1150 if (error == 0) {
1151 puffs_updatenode(pn, PUFFS_UPDATECTIME);
1152 }
1153
1154 vput(dvp);
ab5617b3
SW
1155 if (error == 0) {
1156 cache_setunresolved(nch);
1157 cache_setvp(nch, vp);
1158 }
1159 return error;
1160}
1161
1162static int
1163puffs_vnop_symlink(struct vop_nsymlink_args *ap)
1164{
1165 PUFFS_MSG_VARS(vn, symlink);
1166 struct vnode *dvp = ap->a_dvp;
1167 struct puffs_node *dpn = VPTOPP(dvp);
1168 struct mount *mp = dvp->v_mount;
1169 struct puffs_mount *pmp = MPTOPUFFSMP(dvp->v_mount);
1170 struct nchandle *nch = ap->a_nch;
1171 struct namecache *ncp = nch->ncp;
1172 struct ucred *cred = ap->a_cred;
1173 int error;
1174
376a18e4
AH
1175 if (!EXISTSOP(pmp, SYMLINK))
1176 return EOPNOTSUPP;
1177
ab5617b3
SW
1178 if ((error = vget(dvp, LK_EXCLUSIVE)) != 0) {
1179 DPRINTF(("puffs_vnop_symlink: EAGAIN on ncp %p %s\n",
1180 ncp, ncp->nc_name));
1181 return EAGAIN;
1182 }
1183
1184 *ap->a_vpp = NULL;
1185
1186 PUFFS_MSG_ALLOC(vn, symlink);
1187 puffs_makecn(&symlink_msg->pvnr_cn, &symlink_msg->pvnr_cn_cred,
1188 ncp, cred);
1189 symlink_msg->pvnr_va = *ap->a_vap;
1190 (void)strlcpy(symlink_msg->pvnr_link, ap->a_target,
1191 sizeof(symlink_msg->pvnr_link));
1192 puffs_msg_setinfo(park_symlink, PUFFSOP_VN,
1193 PUFFS_VN_SYMLINK, VPTOPNC(dvp));
1194
1195 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_symlink, dvp->v_data, NULL, error);
1196
1197 error = checkerr(pmp, error, __func__);
1198 if (error)
1199 goto out;
1200
1201 error = puffs_newnode(mp, dvp, ap->a_vpp,
1202 symlink_msg->pvnr_newnode, VLNK);
1203 if (error)
1204 puffs_abortbutton(pmp, PUFFS_ABORT_SYMLINK, dpn->pn_cookie,
1205 symlink_msg->pvnr_newnode, ncp, cred);
1206
1207 out:
1208 vput(dvp);
1209 PUFFS_MSG_RELEASE(symlink);
1210 if (!error) {
1211 cache_setunresolved(nch);
1212 cache_setvp(nch, *ap->a_vpp);
1213 }
1214 return error;
1215}
1216
1217static int
1218puffs_vnop_readlink(struct vop_readlink_args *ap)
1219{
1220 PUFFS_MSG_VARS(vn, readlink);
1221 struct vnode *vp = ap->a_vp;
1222 struct puffs_mount *pmp = MPTOPUFFSMP(ap->a_vp->v_mount);
1223 size_t linklen;
1224 int error;
1225
376a18e4
AH
1226 if (!EXISTSOP(pmp, READLINK))
1227 return EOPNOTSUPP;
1228
ab5617b3
SW
1229 PUFFS_MSG_ALLOC(vn, readlink);
1230 puffs_credcvt(&readlink_msg->pvnr_cred, ap->a_cred);
1231 linklen = sizeof(readlink_msg->pvnr_link);
1232 readlink_msg->pvnr_linklen = linklen;
1233 puffs_msg_setinfo(park_readlink, PUFFSOP_VN,
1234 PUFFS_VN_READLINK, VPTOPNC(vp));
1235
1236 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_readlink, vp->v_data, NULL, error);
1237 error = checkerr(pmp, error, __func__);
1238 if (error)
1239 goto out;
1240
1241 /* bad bad user file server */
1242 if (readlink_msg->pvnr_linklen > linklen) {
1243 puffs_senderr(pmp, PUFFS_ERR_READLINK, E2BIG,
1244 "linklen too big", VPTOPNC(ap->a_vp));
1245 error = EPROTO;
1246 goto out;
1247 }
1248
1249 error = uiomove(readlink_msg->pvnr_link, readlink_msg->pvnr_linklen,
1250 ap->a_uio);
1251 out:
1252 PUFFS_MSG_RELEASE(readlink);
1253 return error;
1254}
1255
1256static int
1257puffs_vnop_rename(struct vop_nrename_args *ap)
1258{
1259 PUFFS_MSG_VARS(vn, rename);
1260 struct nchandle *fnch = ap->a_fnch;
1261 struct nchandle *tnch = ap->a_tnch;
1262 struct vnode *fdvp = ap->a_fdvp;
1263 struct vnode *fvp = fnch->ncp->nc_vp;
1264 struct vnode *tdvp = ap->a_tdvp;
1265 struct vnode *tvp = tnch->ncp->nc_vp;
1266 struct ucred *cred = ap->a_cred;
1267 struct puffs_mount *pmp = MPTOPUFFSMP(fdvp->v_mount);
1268 int error;
ab5617b3 1269
376a18e4
AH
1270 if (!EXISTSOP(pmp, RENAME))
1271 return EOPNOTSUPP;
1272
ab5617b3
SW
1273 error = vget(tdvp, LK_EXCLUSIVE);
1274 if (error != 0) {
1275 DPRINTF(("puffs_vnop_rename: EAGAIN on tdvp vnode %p %s\n",
1276 tdvp, tnch->ncp->nc_name));
1277 return EAGAIN;
1278 }
1279 if (tvp != NULL) {
1280 error = vget(tvp, LK_EXCLUSIVE);
1281 if (error != 0) {
1282 DPRINTF(("puffs_vnop_rename: EAGAIN on tvp vnode %p %s\n",
1283 tvp, tnch->ncp->nc_name));
1284 vput(tdvp);
1285 return EAGAIN;
1286 }
1287 }
1288
1289 if ((fvp->v_mount != tdvp->v_mount) ||
1290 (tvp && (fvp->v_mount != tvp->v_mount))) {
1291 error = EXDEV;
1292 goto out;
1293 }
1294
1295 if (tvp) {
1296 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1297 error = ENOTDIR;
1298 goto out;
1299 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1300 error = EISDIR;
1301 goto out;
1302 }
1303 }
1304
1305 PUFFS_MSG_ALLOC(vn, rename);
1306 rename_msg->pvnr_cookie_src = VPTOPNC(fvp);
1307 rename_msg->pvnr_cookie_targdir = VPTOPNC(tdvp);
1308 if (tvp)
1309 rename_msg->pvnr_cookie_targ = VPTOPNC(tvp);
1310 else
1311 rename_msg->pvnr_cookie_targ = NULL;
1312 puffs_makecn(&rename_msg->pvnr_cn_src, &rename_msg->pvnr_cn_src_cred,
1313 fnch->ncp, cred);
1314 puffs_makecn(&rename_msg->pvnr_cn_targ, &rename_msg->pvnr_cn_targ_cred,
1315 tnch->ncp, cred);
1316 puffs_msg_setinfo(park_rename, PUFFSOP_VN,
1317 PUFFS_VN_RENAME, VPTOPNC(fdvp));
1318
1319 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_rename, fdvp->v_data, NULL, error);
ab5617b3
SW
1320 PUFFS_MSG_RELEASE(rename);
1321 error = checkerr(pmp, error, __func__);
1322
1323 if (error == 0)
1324 puffs_updatenode(VPTOPP(fvp), PUFFS_UPDATECTIME);
1325
1326 out:
1327 if (tvp != NULL)
1328 vn_unlock(tvp);
1329 if (tdvp != tvp)
1330 vn_unlock(tdvp);
1331 if (error == 0)
1332 cache_rename(fnch, tnch);
1333 if (tvp != NULL)
1334 vrele(tvp);
1335 vrele(tdvp);
1336
1337 return error;
1338}
1339
1340static int
1341puffs_vnop_read(struct vop_read_args *ap)
1342{
1343 struct vnode *vp = ap->a_vp;
1344 struct uio *uio = ap->a_uio;
1345 int ioflag = ap->a_ioflag;
1346 struct ucred * cred = ap->a_cred;
1347 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1348 int error;
1349
376a18e4
AH
1350 if (!EXISTSOP(pmp, READ))
1351 return EOPNOTSUPP;
1352
ab5617b3
SW
1353 if (vp->v_type == VDIR)
1354 return EISDIR;
1355 else if (vp->v_type != VREG)
1356 return EINVAL;
1357
1358 if (PUFFS_USE_PAGECACHE(pmp))
1359 error = puffs_bioread(vp, uio, ioflag, cred);
1360 else
1361 error = puffs_directread(vp, uio, ioflag, cred);
1362
1363 return error;
1364}
1365
1366static int
1367puffs_vnop_write(struct vop_write_args *ap)
1368{
1369 struct vnode *vp = ap->a_vp;
1370 struct uio *uio = ap->a_uio;
1371 int ioflag = ap->a_ioflag;
1372 struct ucred * cred = ap->a_cred;
1373 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1374 int error;
1375
376a18e4
AH
1376 if (!EXISTSOP(pmp, WRITE))
1377 return EOPNOTSUPP;
1378
ab5617b3
SW
1379 if (vp->v_type == VDIR)
1380 return EISDIR;
1381 else if (vp->v_type != VREG)
1382 return EINVAL;
1383
1384 if (PUFFS_USE_PAGECACHE(pmp))
1385 error = puffs_biowrite(vp, uio, ioflag, cred);
1386 else
1387 error = puffs_directwrite(vp, uio, ioflag, cred);
1388
1389 return error;
1390}
1391
1392static int
1393puffs_vnop_print(struct vop_print_args *ap)
1394{
1395 PUFFS_MSG_VARS(vn, print);
1396 struct vnode *vp = ap->a_vp;
1397 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1398 struct puffs_node *pn = VPTOPP(vp);
1399 int error;
1400
1401 /* kernel portion */
1402 kprintf("tag VT_PUFFS, vnode %p, puffs node: %p,\n"
1403 "\tuserspace cookie: %p", vp, pn, pn->pn_cookie);
1404 if (vp->v_type == VFIFO)
1405 fifo_printinfo(vp);
1406 kprintf("\n");
1407
1408 /* userspace portion */
1409 if (EXISTSOP(pmp, PRINT)) {
1410 PUFFS_MSG_ALLOC(vn, print);
1411 puffs_msg_setinfo(park_print, PUFFSOP_VN,
1412 PUFFS_VN_PRINT, VPTOPNC(vp));
1413 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_print, vp->v_data,
1414 NULL, error);
1415 PUFFS_MSG_RELEASE(print);
1416 }
1417
1418 return 0;
1419}
1420
1421static int
1422puffs_vnop_pathconf(struct vop_pathconf_args *ap)
1423{
1424 PUFFS_MSG_VARS(vn, pathconf);
1425 struct vnode *vp = ap->a_vp;
1426 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1427 int error;
1428
376a18e4
AH
1429 if (!EXISTSOP(pmp, PATHCONF))
1430 return EOPNOTSUPP;
1431
ab5617b3
SW
1432 PUFFS_MSG_ALLOC(vn, pathconf);
1433 pathconf_msg->pvnr_name = ap->a_name;
1434 puffs_msg_setinfo(park_pathconf, PUFFSOP_VN,
1435 PUFFS_VN_PATHCONF, VPTOPNC(vp));
1436 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_pathconf, vp->v_data, NULL, error);
1437 error = checkerr(pmp, error, __func__);
1438 if (!error)
1439 *ap->a_retval = pathconf_msg->pvnr_retval;
1440 PUFFS_MSG_RELEASE(pathconf);
1441
1442 return error;
1443}
1444
1445static int
1446puffs_vnop_advlock(struct vop_advlock_args *ap)
1447{
1448 PUFFS_MSG_VARS(vn, advlock);
1449 struct vnode *vp = ap->a_vp;
1450 struct puffs_node *pn = VPTOPP(vp);
1451 struct puffs_mount *pmp = MPTOPUFFSMP(vp->v_mount);
1452 int error;
1453
1454 if (!EXISTSOP(pmp, ADVLOCK))
1455 return lf_advlock(ap, &pn->pn_lockf, vp->v_filesize);
1456
1457 PUFFS_MSG_ALLOC(vn, advlock);
1458 (void)memcpy(&advlock_msg->pvnr_fl, ap->a_fl,
1459 sizeof(advlock_msg->pvnr_fl));
1460 advlock_msg->pvnr_id = ap->a_id;
1461 advlock_msg->pvnr_op = ap->a_op;
1462 advlock_msg->pvnr_flags = ap->a_flags;
1463 puffs_msg_setinfo(park_advlock, PUFFSOP_VN,
1464 PUFFS_VN_ADVLOCK, VPTOPNC(vp));
1465 PUFFS_MSG_ENQUEUEWAIT2(pmp, park_advlock, vp->v_data, NULL, error);
1466 error = checkerr(pmp, error, __func__);
1467 PUFFS_MSG_RELEASE(advlock);
1468
1469 return error;
1470}
1471
1472static int
1473puffs_vnop_bmap(struct vop_bmap_args *ap)
1474{
1475 if (ap->a_doffsetp != NULL)
1476 *ap->a_doffsetp = ap->a_loffset;
1477 if (ap->a_runp != NULL)
1478 *ap->a_runp = 0;
1479 if (ap->a_runb != NULL)
1480 *ap->a_runb = 0;
1481 return (0);
1482}
1483
1484static int
1485puffs_vnop_mmap(struct vop_mmap_args *ap)
1486{
1487 return EINVAL;
1488}
1489
1490
1491static int
1492puffs_vnop_strategy(struct vop_strategy_args *ap)
1493{
1494 return puffs_doio(ap->a_vp, ap->a_bio, curthread);
1495}
1496
1497struct vop_ops puffs_fifo_vops = {
1498 .vop_default = fifo_vnoperate,
1499 .vop_access = puffs_vnop_access,
1500 .vop_getattr = puffs_vnop_getattr,
1501 .vop_setattr = puffs_vnop_setattr,
1502 .vop_inactive = puffs_vnop_inactive,
1503 .vop_reclaim = puffs_vnop_reclaim,
1504 .vop_print = puffs_vnop_print,
1505};
1506
1507struct vop_ops puffs_vnode_vops = {
1508 .vop_default = vop_defaultop,
1509 .vop_nresolve = puffs_vnop_lookup,
1510 .vop_nlookupdotdot = puffs_vnop_lookupdotdot,
1511 .vop_ncreate = puffs_vnop_create,
1512 .vop_nmkdir = puffs_vnop_mkdir,
1513 .vop_nrmdir = puffs_vnop_rmdir,
1514 .vop_nremove = puffs_vnop_remove,
1515 .vop_nrename = puffs_vnop_rename,
1516 .vop_nlink = puffs_vnop_link,
1517 .vop_nsymlink = puffs_vnop_symlink,
1518 .vop_nmknod = puffs_vnop_mknod,
1519 .vop_access = puffs_vnop_access,
1520 .vop_getattr = puffs_vnop_getattr,
1521 .vop_setattr = puffs_vnop_setattr,
1522 .vop_readdir = puffs_vnop_readdir,
1523 .vop_open = puffs_vnop_open,
1524 .vop_close = puffs_vnop_close,
1525 .vop_read = puffs_vnop_read,
1526 .vop_write = puffs_vnop_write,
1527 .vop_readlink = puffs_vnop_readlink,
1528 .vop_advlock = puffs_vnop_advlock,
1529 .vop_bmap = puffs_vnop_bmap,
1530 .vop_mmap = puffs_vnop_mmap,
1531 .vop_strategy = puffs_vnop_strategy,
1532 .vop_getpages = vop_stdgetpages,
1533 .vop_putpages = vop_stdputpages,
1534 .vop_fsync = puffs_vnop_fsync,
1535 .vop_inactive = puffs_vnop_inactive,
1536 .vop_reclaim = puffs_vnop_reclaim,
1537 .vop_pathconf = puffs_vnop_pathconf,
1538 .vop_print = puffs_vnop_print,
1539};