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