Merge branch 'vendor/FILE'
[dragonfly.git] / sys / vfs / userfs / userfs_vnops.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/vfs/userfs/userfs_vnops.c,v 1.4 2007/11/20 21:03:51 dillon Exp $
35  */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/fcntl.h>
41 #include <sys/namecache.h>
42 #include <sys/vnode.h>
43 #include <sys/lockf.h>
44 #include <sys/event.h>
45 #include <sys/stat.h>
46 #include <sys/syslink.h>
47 #include <sys/syslink_vfs.h>
48 #include <sys/unistd.h>
49 #include <vm/vnode_pager.h>
50 #include "userfs.h"
51
52 /*
53  * USERFS VNOPS
54  */
55 /*static int user_vop_vnoperate(struct vop_generic_args *);*/
56 static int user_vop_fsync (struct vop_fsync_args *);
57 static int user_vop_read (struct vop_read_args *);
58 static int user_vop_write (struct vop_write_args *);
59 static int user_vop_access (struct vop_access_args *);
60 static int user_vop_advlock (struct vop_advlock_args *);
61 static int user_vop_close (struct vop_close_args *);
62 static int user_vop_ncreate (struct vop_ncreate_args *);
63 static int user_vop_getattr (struct vop_getattr_args *);
64 static int user_vop_nresolve (struct vop_nresolve_args *);
65 static int user_vop_nlookupdotdot (struct vop_nlookupdotdot_args *);
66 static int user_vop_nlink (struct vop_nlink_args *);
67 static int user_vop_nmkdir (struct vop_nmkdir_args *);
68 static int user_vop_nmknod (struct vop_nmknod_args *);
69 static int user_vop_open (struct vop_open_args *);
70 static int user_vop_pathconf (struct vop_pathconf_args *);
71 static int user_vop_print (struct vop_print_args *);
72 static int user_vop_readdir (struct vop_readdir_args *);
73 static int user_vop_readlink (struct vop_readlink_args *);
74 static int user_vop_nremove (struct vop_nremove_args *);
75 static int user_vop_nrename (struct vop_nrename_args *);
76 static int user_vop_nrmdir (struct vop_nrmdir_args *);
77 static int user_vop_setattr (struct vop_setattr_args *);
78 static int user_vop_strategy (struct vop_strategy_args *);
79 static int user_vop_nsymlink (struct vop_nsymlink_args *);
80 static int user_vop_nwhiteout (struct vop_nwhiteout_args *);
81 static int user_vop_bmap (struct vop_bmap_args *);
82
83 struct vop_ops userfs_vnode_vops = {
84         .vop_default =          vop_defaultop,
85         .vop_fsync =            user_vop_fsync,
86         .vop_getpages =         vop_stdgetpages,
87         .vop_putpages =         vop_stdputpages,
88         .vop_read =             user_vop_read,
89         .vop_write =            user_vop_write,
90         .vop_access =           user_vop_access,
91         .vop_advlock =          user_vop_advlock,
92         .vop_close =            user_vop_close,
93         .vop_ncreate =          user_vop_ncreate,
94         .vop_getattr =          user_vop_getattr,
95         .vop_inactive =         user_vop_inactive,
96         .vop_reclaim =          user_vop_reclaim,
97         .vop_nresolve =         user_vop_nresolve,
98         .vop_nlookupdotdot =    user_vop_nlookupdotdot,
99         .vop_nlink =            user_vop_nlink,
100         .vop_nmkdir =           user_vop_nmkdir,
101         .vop_nmknod =           user_vop_nmknod,
102         .vop_open =             user_vop_open,
103         .vop_pathconf =         user_vop_pathconf,
104         .vop_print =            user_vop_print,
105         .vop_readdir =          user_vop_readdir,
106         .vop_readlink =         user_vop_readlink,
107         .vop_nremove =          user_vop_nremove,
108         .vop_nrename =          user_vop_nrename,
109         .vop_nrmdir =           user_vop_nrmdir,
110         .vop_setattr =          user_vop_setattr,
111         .vop_strategy =         user_vop_strategy,
112         .vop_nsymlink =         user_vop_nsymlink,
113         .vop_nwhiteout =        user_vop_nwhiteout,
114         .vop_bmap =             user_vop_bmap
115 };
116
117 #if 0
118 static
119 int
120 user_vop_vnoperate(struct vop_generic_args *)
121 {
122         return (VOCALL(&userfs_vnode_vops, ap));
123 }
124 #endif
125
126 /*
127  * vop_fsync(struct vnode *vp, int waitfor)
128  */
129 static
130 int
131 user_vop_fsync (struct vop_fsync_args *ap)
132 {
133         struct user_mount *ump;
134         struct user_inode *ip;
135         struct vnode *vp;
136         struct slmsg *slmsg;
137         syslink_elm_t par;
138         int error;
139
140         vp = ap->a_vp;
141         ip = vp->v_data;
142         ump = ip->ump;
143
144         slmsg = syslink_kallocmsg();
145         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
146                               SLVFS_CMD_VOP_FSYNC);
147         user_elm_push_vnode(par, ap->a_vp);
148         sl_msg_fini(slmsg->msg);
149
150         kprintf("userfs_fsync\n");
151         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
152                 par = &slmsg->rep->msg->sm_head;
153
154                 if (par->se_cmd == (SLVFS_CMD_VOP_FSYNC|SE_CMDF_REPLY)) {
155                         ;
156                 } else {
157                         error = EBADRPC;
158                 }
159         }
160         syslink_kfreemsg(ump->sldesc, slmsg);
161         kprintf("error %d\n", error);
162         return(error);
163 }
164
165 /*
166  * vop_read(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
167  */
168 static
169 int
170 user_vop_read (struct vop_read_args *ap)
171 {
172         struct user_mount *ump;
173         struct user_inode *ip;
174         struct vnode *vp;
175         struct uio *uio;
176         struct buf *bp;
177         int error;
178         int offset;
179         int n;
180
181         vp = ap->a_vp;
182         ip = vp->v_data;
183         ump = ip->ump;
184         uio = ap->a_uio;
185
186         if (uio->uio_offset < 0)
187                 return (EINVAL);
188         if (vp->v_type != VREG)
189                 return (EINVAL);
190
191         kprintf("userfs_read\n");
192         error = 0;
193         while (uio->uio_resid > 0 && uio->uio_offset < ip->filesize) {
194                 /*
195                  * Use buffer cache I/O (via user_vop_strategy), aligned
196                  * on USERFS_BSIZE boundaries.
197                  */
198                 offset = (int)uio->uio_offset & USERFS_BMASK;
199                 error = bread(vp, uio->uio_offset - offset, USERFS_BSIZE, &bp);
200                 if (error) {
201                         brelse(bp);
202                         break;
203                 }
204
205                 /*
206                  * Figure out how many bytes we can actually copy this loop.
207                  */
208                 n = USERFS_BSIZE - offset;
209                 if (n > uio->uio_resid)
210                         n = uio->uio_resid;
211                 if (n > ip->filesize - uio->uio_offset)
212                         n = (int)(ip->filesize - uio->uio_offset);
213
214                 error = uiomove((char *)bp->b_data + offset, n, uio);
215                 bqrelse(bp);
216                 if (error)
217                         break;
218         }
219         kprintf("userfs_read error %d\n", error);
220         return(error);
221 }
222
223 /*
224  * vop_write(struct vnode *vp, struct uio *uio, int ioflag, struct ucred *cred)
225  */
226 static
227 int
228 user_vop_write (struct vop_write_args *ap)
229 {
230         struct user_mount *ump;
231         struct user_inode *ip;
232         struct vnode *vp;
233         struct buf *bp;
234         struct uio *uio;
235         int error;
236         off_t loffset;
237         size_t offset;
238         size_t n;
239
240         vp = ap->a_vp;
241         ip = vp->v_data;
242         ump = ip->ump;
243         uio = ap->a_uio;
244
245         if (vp->v_type != VREG)
246                 return (EINVAL);
247         if (ap->a_ioflag & IO_APPEND)
248                 uio->uio_offset = ip->filesize;
249
250         /*
251          * Check for illegal write offsets.  Valid range is 0...2^63-1
252          */
253         loffset = uio->uio_offset;
254         if (loffset < 0)
255                 return (EFBIG);
256         if (uio->uio_resid) {
257                 /* GCC4 - workaround optimization */
258                 loffset += uio->uio_resid;
259                 if (loffset <= 0)
260                         return (EFBIG);
261         }
262
263         kprintf("userfs_write\n");
264         error = 0;
265         while (uio->uio_resid > 0) {
266                 /*
267                  * Use buffer cache I/O (via user_vop_strategy), aligned
268                  * on USERFS_BSIZE boundaries.
269                  *
270                  * XXX not optimized for complete write-overs or file
271                  * extensions.  Note: must bread on UIO_NOCOPY writes.
272                  *
273                  * XXX No need to read if strictly appending.
274                  */
275                 offset = (size_t)uio->uio_offset & USERFS_BMASK;
276                 /* if offset == ip->filesize use getblk instead */
277                 error = bread(vp, uio->uio_offset - offset, USERFS_BSIZE, &bp);
278                 if (error) {
279                         brelse(bp);
280                         break;
281                 }
282
283                 /*
284                  * Figure out how many bytes we can actually copy this loop.
285                  */
286                 n = USERFS_BSIZE - offset;
287                 if (n > uio->uio_resid)
288                         n = uio->uio_resid;
289                 if (n > ip->filesize - uio->uio_offset)
290                         n = (size_t)(ip->filesize - uio->uio_offset);
291
292                 error = uiomove((char *)bp->b_data + offset, n, uio);
293                 if (error) {
294                         brelse(bp);
295                         break;
296                 }
297
298                 /*
299                  * Extend the file's size if necessary
300                  */
301                 if (ip->filesize < uio->uio_offset)
302                         ip->filesize = uio->uio_offset;
303
304                 /*
305                  * The data has been loaded into the buffer, write it out.
306                  */
307                 if (ap->a_ioflag & IO_SYNC) {
308                         bwrite(bp);
309                 } else if (ap->a_ioflag & IO_DIRECT) {
310                         bp->b_flags |= B_CLUSTEROK;
311                         bawrite(bp);
312                 } else {
313                         bp->b_flags |= B_CLUSTEROK;
314                         bdwrite(bp);
315                 }
316         }
317         kprintf("userfs_write error %d\n", error);
318         return(error);
319 }
320
321 /*
322  * vop_access(struct vnode *vp, int mode, struct ucred *cred)
323  */
324 static
325 int
326 user_vop_access (struct vop_access_args *ap)
327 {
328         struct user_mount *ump;
329         struct user_inode *ip;
330         struct vnode *vp;
331         struct slmsg *slmsg;
332         syslink_elm_t par;
333         int error;
334
335         vp = ap->a_vp;
336         ip = vp->v_data;
337         ump = ip->ump;
338
339         slmsg = syslink_kallocmsg();
340         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
341                               SLVFS_CMD_VOP_ACCESS);
342         user_elm_push_vnode(par, vp);
343         user_elm_push_mode(par, ap->a_mode);
344         user_elm_push_cred(par, ap->a_cred);
345         sl_msg_fini(slmsg->msg);
346
347         /*
348          * Issue the request and do basic validation of the response
349          */
350         kprintf("userfs_access\n");
351         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) != 0)
352                 goto done;
353         par = &slmsg->rep->msg->sm_head;
354         if (par->se_cmd != (SLVFS_CMD_VOP_ACCESS|SE_CMDF_REPLY)) {
355                 error = EBADRPC;
356                 goto done;
357         }
358
359 done:
360         syslink_kfreemsg(ump->sldesc, slmsg);
361         kprintf("error %d\n", error);
362         return(error);
363 }
364
365 /*
366  * vop_advlock(struct vnode *vp, caddr_t id, int op, struct flock *fl,
367  *             int flags)
368  *
369  * This vop is handled directly by the kernel.
370  */
371 static
372 int
373 user_vop_advlock (struct vop_advlock_args *ap)
374 {
375         struct user_inode *ip;
376         struct vnode *vp;
377
378         vp = ap->a_vp;
379         ip = vp->v_data;
380
381         return (lf_advlock(ap, &ip->lockf, ip->filesize));
382 }
383
384 /*
385  * vop_open(struct vnode *vp, int mode, struct ucred *cred, struct file *file)
386  *
387  * This vop is handled directly by the kernel.
388  */
389 static
390 int
391 user_vop_open (struct vop_open_args *ap)
392 {
393         return (vop_stdopen(ap));
394 }
395
396 /*
397  * vop_close(struct vnode *vp, int fflag)
398  *
399  * This vop is handled directly by the kernel.
400  */
401 static
402 int
403 user_vop_close (struct vop_close_args *ap)
404 {
405         return (vop_stdclose(ap));
406 }
407
408 /*
409  * vop_getattr(struct vnode *vp, struct vattr *vap)
410  */
411 static
412 int
413 user_vop_getattr (struct vop_getattr_args *ap)
414 {
415         struct user_mount *ump;
416         struct user_inode *ip;
417         struct vnode *vp;
418         struct slmsg *slmsg;
419         syslink_elm_t par;
420         syslink_elm_t elm;
421         int error;
422
423         vp = ap->a_vp;
424         ip = vp->v_data;
425         ump = ip->ump;
426
427         slmsg = syslink_kallocmsg();
428         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
429                               SLVFS_CMD_VOP_GETATTR);
430         sl_msg_fini(slmsg->msg);
431
432         kprintf("userfs_getattr\n");
433         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) != 0)
434                 goto done;
435         par = &slmsg->rep->msg->sm_head;
436         if (par->se_cmd != (SLVFS_CMD_VOP_GETATTR|SE_CMDF_REPLY)) {
437                 error = EBADRPC;
438                 goto done;
439         }
440
441         /*
442          * Parse reply content
443          */
444         SL_FOREACH_ELEMENT(par, elm) {
445                 switch(elm->se_cmd) {
446                 case SLVFS_ELM_VATTR:
447                         error = user_elm_parse_vattr(elm, ap->a_vap);
448                         break;
449                 default:
450                         break;
451                 }
452                 if (error)
453                         break;
454         }
455 done:
456         syslink_kfreemsg(ump->sldesc, slmsg);
457         kprintf("error %d\n", error);
458         return(error);
459 }
460
461 /*
462  * vop_pathconf(int name, int *retval)
463  *
464  * This vop is handled directly by the kernel.
465  */
466 static
467 int
468 user_vop_pathconf (struct vop_pathconf_args *ap)
469 {
470         int error = 0;
471
472         switch(ap->a_name) {
473         case _PC_LINK_MAX:
474                 *ap->a_retval = LINK_MAX;
475                 break;
476         case _PC_MAX_CANON:
477                 *ap->a_retval = MAX_CANON;
478                 break;
479         case _PC_MAX_INPUT:
480                 *ap->a_retval = MAX_INPUT;
481                 break;
482         case _PC_PIPE_BUF:
483                 *ap->a_retval = PIPE_BUF;
484                 break;
485         case _PC_CHOWN_RESTRICTED:
486                 *ap->a_retval = 1;
487                 break;
488         case _PC_VDISABLE:
489                 *ap->a_retval = _POSIX_VDISABLE;
490                 break;
491         default:
492                 error = EINVAL;
493                 break;
494         }
495         return (error);
496 }
497
498 /*
499  * vop_print(int name, int *retval)
500  *
501  * This vop is handled directly by the kernel.
502  */
503 static
504 int
505 user_vop_print (struct vop_print_args *ap)
506 {
507         return(0);
508 }
509
510 /*
511  * vop_readdir(struct vnode *vp, struct uio *uio, struct ucred *cred,
512  *             int *eofflag, int *ncookies, off_t **a_cookies)
513  */
514 static
515 int
516 user_vop_readdir (struct vop_readdir_args *ap)
517 {
518         struct user_mount *ump;
519         struct user_inode *ip;
520         struct vnode *vp;
521         struct slmsg *slmsg;
522         syslink_elm_t par;
523         int error;
524
525         vp = ap->a_vp;
526         ip = vp->v_data;
527         ump = ip->ump;
528
529         slmsg = syslink_kallocmsg();
530         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
531                               SLVFS_CMD_VOP_READDIR);
532         sl_msg_fini(slmsg->msg);
533
534         kprintf("userfs_readdir\n");
535         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
536                 par = &slmsg->rep->msg->sm_head;
537
538                 if (par->se_cmd == (SLVFS_CMD_VOP_READDIR|SE_CMDF_REPLY)) {
539                         ;
540                 } else {
541                         error = EBADRPC;
542                 }
543         }
544         syslink_kfreemsg(ump->sldesc, slmsg);
545         kprintf("error %d\n", error);
546         return(error);
547 }
548
549 /*
550  * vop_readlink(struct vnode *vp, struct uio *uio, struct ucred *cred)
551  */
552 static
553 int
554 user_vop_readlink (struct vop_readlink_args *ap)
555 {
556         struct user_mount *ump;
557         struct user_inode *ip;
558         struct vnode *vp;
559         struct slmsg *slmsg;
560         syslink_elm_t par;
561         int error;
562
563         vp = ap->a_vp;
564         ip = vp->v_data;
565         ump = ip->ump;
566
567         slmsg = syslink_kallocmsg();
568         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
569                               SLVFS_CMD_VOP_READLINK);
570         sl_msg_fini(slmsg->msg);
571
572         kprintf("userfs_readlink\n");
573         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
574                 par = &slmsg->rep->msg->sm_head;
575
576                 if (par->se_cmd == (SLVFS_CMD_VOP_READLINK|SE_CMDF_REPLY)) {
577                         ;
578                 } else {
579                         error = EBADRPC;
580                 }
581         }
582         syslink_kfreemsg(ump->sldesc, slmsg);
583         kprintf("error %d\n", error);
584         return(error);
585 }
586
587 /*
588  * vop_setattr(struct vnode *vp, struct vattr *vap, struct ucred *cred)
589  */
590 static
591 int
592 user_vop_setattr (struct vop_setattr_args *ap)
593 {
594         struct user_mount *ump;
595         struct user_inode *ip;
596         struct vnode *vp;
597         struct slmsg *slmsg;
598         syslink_elm_t par;
599         int error;
600
601         vp = ap->a_vp;
602         ip = vp->v_data;
603         ump = ip->ump;
604
605         slmsg = syslink_kallocmsg();
606         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
607                               SLVFS_CMD_VOP_SETATTR);
608         sl_msg_fini(slmsg->msg);
609
610         kprintf("userfs_setattr\n");
611         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
612                 par = &slmsg->rep->msg->sm_head;
613
614                 if (par->se_cmd == (SLVFS_CMD_VOP_SETATTR|SE_CMDF_REPLY)) {
615                         ;
616                 } else {
617                         error = EBADRPC;
618                 }
619         }
620         syslink_kfreemsg(ump->sldesc, slmsg);
621         kprintf("error %d\n", error);
622         return(error);
623 }
624
625 /*
626  * user_vop_strategy() - I/O strategy routine.
627  *
628  * Note that userfs interfaces fake-up BMAP so the strategy call just
629  * uses the passed bio instead of pushing a bio to get to the (faked)
630  * device block cache.
631  */
632 static void user_strategy_callback(struct slmsg *msg, void *arg, int error);
633
634 static
635 int
636 user_vop_strategy (struct vop_strategy_args *ap)
637 {
638         struct user_mount *ump;
639         struct user_inode *ip;
640         struct vnode *vp;
641         struct bio *bio;
642         struct buf *bp;
643         struct slmsg *slmsg;
644         syslink_elm_t par;
645         int error;
646
647         vp = ap->a_vp;
648         ip = vp->v_data;
649         ump = ip->ump;
650         bio = ap->a_bio;
651         bp = bio->bio_buf;
652
653         bio->bio_driver_info = ump;
654
655         slmsg = syslink_kallocmsg();
656         switch(bp->b_cmd) {
657         case BUF_CMD_READ:
658                 par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
659                                       SLVFS_CMD_VOP_STRATEGY_READ);
660                 break;
661         case BUF_CMD_WRITE:
662                 par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
663                                       SLVFS_CMD_VOP_STRATEGY_WRITE);
664                 break;
665         default:
666                 par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
667                                       SLVFS_CMD_VOP_STRATEGY_MISC);
668                 break;
669         }
670         user_elm_push_vnode(par, vp);
671         user_elm_push_offset(par, bio->bio_offset);
672         user_elm_push_bio(par, bp->b_cmd, bp->b_bcount);
673         syslink_kdmabuf_data(slmsg, bp->b_data, bp->b_bcount);
674         sl_msg_fini(slmsg->msg);
675
676         kprintf("userfs_strategy\n");
677         error = syslink_ksendmsg(ump->sldesc, slmsg,
678                                  user_strategy_callback, bio);
679         if (error)
680                 syslink_kfreemsg(ump->sldesc, slmsg);
681         kprintf("error %d\n", error);
682         return(error);
683 }
684
685 /*
686  * This callback is made in the context of the responding process which
687  * may or may not be the process the message was sent to.
688  */
689 static void
690 user_strategy_callback(struct slmsg *slmsg, void *arg, int error)
691 {
692         struct bio *bio = arg;
693         struct buf *bp = bio->bio_buf;
694         struct user_mount *ump;
695         syslink_elm_t par;
696
697         kprintf("user_strategy_callback\n");
698         if (error == 0) {
699                 par = &slmsg->rep->msg->sm_head;
700                 if (par->se_cmd != (slmsg->msg->sm_head.se_cmd | SE_CMDF_REPLY)) {
701                         error = EBADRPC;
702                 }
703         }
704         if (error) {
705                 bp->b_error = error;
706                 bp->b_flags |= B_ERROR;
707         }
708         ump = bio->bio_driver_info;
709         syslink_kfreemsg(ump->sldesc, slmsg);
710         biodone(bio);
711 }
712
713 /*
714  * vop_bmap(struct vnode *vp, off_t loffset, off_t *doffsetp,
715  *          int *runp, int *runb)
716  *
717  * Dummy up the bmap op so the kernel will cluster I/Os.  The strategy
718  * code will ignore the dummied up device block translation.
719  */
720 static
721 int
722 user_vop_bmap(struct vop_bmap_args *ap)
723 {
724         int cluster_off;
725
726         *ap->a_doffsetp = ap->a_loffset;
727         cluster_off = (int)(*ap->a_doffsetp & (MAXPHYS - 1));
728
729         if (ap->a_runp)
730                 *ap->a_runp = MAXPHYS - cluster_off;
731         if (ap->a_runb)
732                 *ap->a_runb = cluster_off;
733         return(0);
734 }
735
736
737 /*
738  * vop_ncreate(struct nchandle *nch, struct vnode *dvp, struct vnode **vpp,
739  *             struct ucred *cred, struct vattr *vap)
740  */
741 static
742 int
743 user_vop_ncreate (struct vop_ncreate_args *ap)
744 {
745         struct user_mount *ump;
746         struct user_inode *ip;
747         struct namecache *ncp;
748         struct ucred *cred;
749         struct vnode *dvp;
750         struct slmsg *slmsg;
751         syslink_elm_t par;
752         syslink_elm_t elm;
753         int error;
754
755         cred = ap->a_cred;
756         ncp = ap->a_nch->ncp;
757         dvp = ap->a_dvp;
758
759         if ((error = vget(dvp, LK_SHARED)) != 0)
760                 return (error);
761
762         ip = dvp->v_data;
763         ump = ip->ump;
764
765         slmsg = syslink_kallocmsg();
766         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
767                               SLVFS_CMD_VOP_NCREATE);
768         user_elm_push_nch(par, ap->a_nch);
769         user_elm_push_vnode(par, dvp);
770         user_elm_push_cred(par, ap->a_cred);
771         user_elm_push_vattr(par, ap->a_vap);
772         sl_msg_fini(slmsg->msg);
773
774         kprintf("userfs_ncreate\n");
775         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) != 0)
776                 goto done;
777         par = &slmsg->rep->msg->sm_head;
778         if (par->se_cmd != (SLVFS_CMD_VOP_NCREATE|SE_CMDF_REPLY)) {
779                 error = EBADRPC;
780                 goto done;
781         }
782
783         /*
784          * Parse reply - extract the inode number of the newly created
785          * object and construct a vnode using it.
786          */
787         SL_FOREACH_ELEMENT(par, elm) {
788                 switch(elm->se_cmd) {
789                 case SLVFS_ELM_INUM:
790                         /* XXX */
791                         break;
792                 default:
793                         break;
794                 }
795                 if (error)
796                         break;
797         }
798         /* XXX construct vnode using fileid */
799         error = EINVAL;
800
801 done:
802         syslink_kfreemsg(ump->sldesc, slmsg);
803         kprintf("error %d\n", error);
804         vput(dvp);
805         return(error);
806 }
807
808 /*
809  * vop_nresolve(struct nchandle *nch, struct vnode *dvp, struct ucred *cred)
810  */
811 static
812 int
813 user_vop_nresolve (struct vop_nresolve_args *ap)
814 {
815         struct user_mount *ump;
816         struct user_inode *ip;
817         struct namecache *ncp;
818         struct ucred *cred;
819         struct vnode *dvp;
820         struct slmsg *slmsg;
821         syslink_elm_t par;
822         syslink_elm_t elm;
823         int error;
824         int flags;
825         ino_t inum;
826
827         cred = ap->a_cred;
828         ncp = ap->a_nch->ncp;
829         dvp = ap->a_dvp;
830         if ((error = vget(dvp, LK_SHARED)) != 0)
831                 return (error);
832         vn_unlock(dvp);
833
834         ip = dvp->v_data;
835         ump = ip->ump;
836
837         slmsg = syslink_kallocmsg();
838         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
839                               SLVFS_CMD_VOP_NRESOLVE);
840         user_elm_push_nch(par, ap->a_nch);
841         user_elm_push_vnode(par, dvp);
842         user_elm_push_cred(par, ap->a_cred);
843         sl_msg_fini(slmsg->msg);
844
845         /*
846          * Run the RPC.  The response must still be parsed for a ENOENT
847          * error to extract the whiteout flag.
848          */
849         kprintf("userfs_nresolve\n");
850         error = syslink_kdomsg(ump->sldesc, slmsg);
851         if (error && error != ENOENT)
852                 goto done;
853         par = &slmsg->rep->msg->sm_head;
854         if (par->se_cmd != (SLVFS_CMD_VOP_NRESOLVE|SE_CMDF_REPLY)) {
855                 error = EBADRPC;
856                 goto done;
857         }
858
859         /*
860          * Parse reply - returns inode number of resolved vnode
861          */
862         flags = 0;
863         inum = 0;
864         SL_FOREACH_ELEMENT(par, elm) {
865                 switch(elm->se_cmd) {
866                 case SLVFS_ELM_INUM:
867                         /* XXX */
868                         break;
869                 case SLVFS_ELM_NCPFLAG:
870                         /* flags = & NCF_WHITEOUT */
871                         break;
872                 default:
873                         break;
874                 }
875         }
876
877         if (error == 0) {
878                 error = EINVAL;
879                 /*vp = user_getvp(inum);*/
880                 /* XXX construct vp cache_setvp(nch, vp); */
881         } else {
882                 ncp->nc_flag |= flags;
883                 cache_setvp(ap->a_nch, NULL);
884         }
885 done:
886         syslink_kfreemsg(ump->sldesc, slmsg);
887         vrele(dvp);
888         kprintf("error %d\n", error);
889         return(error);
890 }
891
892 /*
893  * vop_nlookupdotdot(struct vnode *dvp, struct vnode **vpp, struct ucred *cred)
894  *
895  * Lookup the parent of dvp. dvp is ref'd but not locked.  The returned
896  * vnode should be ref'd and locked.
897  */
898 static
899 int
900 user_vop_nlookupdotdot (struct vop_nlookupdotdot_args *ap)
901 {
902         struct user_mount *ump;
903         struct user_inode *ip;
904         struct ucred *cred;
905         struct vnode *dvp;
906         struct vnode *vp;
907         struct slmsg *slmsg;
908         syslink_elm_t par;
909         syslink_elm_t elm;
910         int error;
911         ino_t inum;
912
913         cred = ap->a_cred;
914         dvp = ap->a_dvp;
915         vp = NULL;      /* XXX */
916         ip = vp->v_data;
917         ump = ip->ump;
918
919         slmsg = syslink_kallocmsg();
920         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
921                               SLVFS_CMD_VOP_NLOOKUPDOTDOT);
922         sl_msg_fini(slmsg->msg);
923
924         kprintf("userfs_nlookupdotdot\n");
925         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) != 0)
926                 goto done;
927         par = &slmsg->rep->msg->sm_head;
928
929         if (par->se_cmd != (SLVFS_CMD_VOP_NLOOKUPDOTDOT|SE_CMDF_REPLY)) {
930                 error = EBADRPC;
931                 goto done;
932         }
933
934         /*
935          * Parse reply - inumber of parent directory
936          */
937         inum = 0;
938         SL_FOREACH_ELEMENT(par, elm) {
939                 switch(elm->se_cmd) {
940                 case SLVFS_ELM_INUM:
941                         /* XXX */
942                         break;
943                 case SLVFS_ELM_NCPFLAG:
944                         /* flags = & NCF_WHITEOUT */
945                         break;
946                 default:
947                         break;
948                 }
949         }
950
951         /* construct parent vnode */
952
953 done:
954         syslink_kfreemsg(ump->sldesc, slmsg);
955         kprintf("error %d\n", error);
956         return(error);
957 }
958
959 /*
960  * vop_nlink(struct nchandle *nch, struct vnode *dvp, struct vnode *vp,
961  *           struct ucred *cred)
962  */
963 static
964 int
965 user_vop_nlink (struct vop_nlink_args *ap)
966 {
967         struct user_mount *ump;
968         struct user_inode *ip;
969         struct vnode *vp;
970         struct slmsg *slmsg;
971         syslink_elm_t par;
972         int error;
973
974         vp = ap->a_vp;
975         ip = vp->v_data;
976         ump = ip->ump;
977
978         slmsg = syslink_kallocmsg();
979         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
980                               SLVFS_CMD_VOP_NLINK);
981         sl_msg_fini(slmsg->msg);
982
983         kprintf("userfs_nlink\n");
984         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
985                 par = &slmsg->rep->msg->sm_head;
986
987                 if (par->se_cmd == (SLVFS_CMD_VOP_NLINK|SE_CMDF_REPLY)) {
988                         ;
989                 } else {
990                         error = EBADRPC;
991                 }
992         }
993         syslink_kfreemsg(ump->sldesc, slmsg);
994         kprintf("error %d\n", error);
995         return(error);
996 }
997
998 /*
999  * vop_nmkdir(struct nchandle *nch, struct vnode *dvp, struct vnode **vpp,
1000  *           struct ucred *cred, struct vattr *vap)
1001  */
1002 static
1003 int
1004 user_vop_nmkdir (struct vop_nmkdir_args *ap)
1005 {
1006         struct user_mount *ump;
1007         struct user_inode *ip;
1008         struct namecache *ncp;
1009         struct ucred *cred;
1010         struct vnode *dvp;
1011         struct vnode *vp;
1012         struct slmsg *slmsg;
1013         syslink_elm_t par;
1014         int error;
1015
1016         cred = ap->a_cred;
1017         ncp = ap->a_nch->ncp;
1018         dvp = ap->a_dvp;
1019         if ((error = vget(dvp, LK_SHARED)) != 0)
1020                 return (error);
1021
1022         vp = NULL;      /* XXX */
1023
1024         ip = vp->v_data;
1025         ump = ip->ump;
1026
1027         slmsg = syslink_kallocmsg();
1028         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1029                               SLVFS_CMD_VOP_NMKDIR);
1030         sl_msg_fini(slmsg->msg);
1031
1032         kprintf("userfs_nmkdir\n");
1033         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1034                 par = &slmsg->rep->msg->sm_head;
1035
1036                 if (par->se_cmd == (SLVFS_CMD_VOP_NMKDIR|SE_CMDF_REPLY)) {
1037                         ;
1038                 } else {
1039                         error = EBADRPC;
1040                 }
1041         }
1042         syslink_kfreemsg(ump->sldesc, slmsg);
1043         kprintf("error %d\n", error);
1044         vput(dvp);
1045         return(error);
1046 }
1047
1048 /*
1049  * vop_nmknod(struct nchandle *nch, struct vnode *dvp, struct vnode **vpp,
1050  *           struct ucred *cred, struct vattr *vap)
1051  */
1052 static
1053 int
1054 user_vop_nmknod (struct vop_nmknod_args *ap)
1055 {
1056         struct user_mount *ump;
1057         struct user_inode *ip;
1058         struct namecache *ncp;
1059         struct ucred *cred;
1060         struct vnode *dvp;
1061         struct vnode *vp;
1062         struct slmsg *slmsg;
1063         syslink_elm_t par;
1064         int error;
1065
1066         cred = ap->a_cred;
1067         ncp = ap->a_nch->ncp;
1068         dvp = ncp->nc_parent->nc_vp;    /* needs vget */
1069
1070         vp = NULL;      /* XXX */
1071
1072         ip = vp->v_data;
1073         ump = ip->ump;
1074
1075         slmsg = syslink_kallocmsg();
1076         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1077                               SLVFS_CMD_VOP_NMKNOD);
1078         sl_msg_fini(slmsg->msg);
1079
1080         kprintf("userfs_nmknod\n");
1081         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1082                 par = &slmsg->rep->msg->sm_head;
1083
1084                 if (par->se_cmd == (SLVFS_CMD_VOP_NMKNOD|SE_CMDF_REPLY)) {
1085                         ;
1086                 } else {
1087                         error = EBADRPC;
1088                 }
1089         }
1090         syslink_kfreemsg(ump->sldesc, slmsg);
1091         kprintf("error %d\n", error);
1092         return(error);
1093 }
1094
1095 /*
1096  * vop_nremove(struct nchandle *nch, struct vnode *dvp, struct ucred *cred)
1097  */
1098 static
1099 int
1100 user_vop_nremove (struct vop_nremove_args *ap)
1101 {
1102         struct user_mount *ump;
1103         struct user_inode *ip;
1104         struct namecache *ncp;
1105         struct ucred *cred;
1106         struct vnode *dvp;
1107         struct vnode *vp;
1108         struct slmsg *slmsg;
1109         syslink_elm_t par;
1110         int error;
1111
1112         cred = ap->a_cred;
1113         ncp = ap->a_nch->ncp;
1114         dvp = ncp->nc_parent->nc_vp;    /* needs vget */
1115
1116         vp = NULL;      /* XXX */
1117
1118         ip = vp->v_data;
1119         ump = ip->ump;
1120
1121         slmsg = syslink_kallocmsg();
1122         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1123                               SLVFS_CMD_VOP_NREMOVE);
1124         sl_msg_fini(slmsg->msg);
1125
1126         kprintf("userfs_nremove\n");
1127         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1128                 par = &slmsg->rep->msg->sm_head;
1129
1130                 if (par->se_cmd == (SLVFS_CMD_VOP_NREMOVE|SE_CMDF_REPLY)) {
1131                         ;
1132                 } else {
1133                         error = EBADRPC;
1134                 }
1135         }
1136         syslink_kfreemsg(ump->sldesc, slmsg);
1137         kprintf("error %d\n", error);
1138         return(error);
1139 }
1140
1141 /*
1142  * vop_nrename(struct nchandle *fnch, struct nchandle *tnch,
1143  *             struct vnode *fdvp, struct vnode *tdvp,
1144  *             struct ucred *cred)
1145  */
1146 static
1147 int
1148 user_vop_nrename (struct vop_nrename_args *ap)
1149 {
1150         struct user_mount *ump;
1151         struct user_inode *ip;
1152         struct namecache *fncp;
1153         struct namecache *tncp;
1154         struct ucred *cred;
1155         struct vnode *fdvp;
1156         struct vnode *tdvp;
1157         struct vnode *vp;
1158         struct slmsg *slmsg;
1159         syslink_elm_t par;
1160         int error;
1161
1162         cred = ap->a_cred;
1163         fncp = ap->a_fnch->ncp;
1164         fdvp = ap->a_fdvp;      /* XXX needs vget */
1165         tncp = ap->a_tnch->ncp;
1166         tdvp = ap->a_tdvp;      /* XXX needs vget */
1167
1168         vp = NULL;      /* XXX */
1169
1170         ip = vp->v_data;
1171         ump = ip->ump;
1172
1173         slmsg = syslink_kallocmsg();
1174         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1175                               SLVFS_CMD_VOP_NRENAME);
1176         sl_msg_fini(slmsg->msg);
1177
1178         kprintf("userfs_nrename\n");
1179         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1180                 par = &slmsg->rep->msg->sm_head;
1181
1182                 if (par->se_cmd == (SLVFS_CMD_VOP_NRENAME|SE_CMDF_REPLY)) {
1183                         ;
1184                 } else {
1185                         error = EBADRPC;
1186                 }
1187         }
1188         syslink_kfreemsg(ump->sldesc, slmsg);
1189         kprintf("error %d\n", error);
1190         return(error);
1191 }
1192
1193 /*
1194  * vop_nrmdir(struct nchandle *nch, struct vnode *dvp, struct ucred *cred)
1195  */
1196 static
1197 int
1198 user_vop_nrmdir (struct vop_nrmdir_args *ap)
1199 {
1200         struct user_mount *ump;
1201         struct user_inode *ip;
1202         struct namecache *ncp;
1203         struct ucred *cred;
1204         struct vnode *dvp;
1205         struct vnode *vp;
1206         struct slmsg *slmsg;
1207         syslink_elm_t par;
1208         int error;
1209
1210         cred = ap->a_cred;
1211         ncp = ap->a_nch->ncp;
1212         dvp = ncp->nc_parent->nc_vp;    /* needs vget */
1213
1214         vp = NULL;      /* XXX */
1215
1216         ip = vp->v_data;
1217         ump = ip->ump;
1218
1219         slmsg = syslink_kallocmsg();
1220         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1221                               SLVFS_CMD_VOP_NRMDIR);
1222         sl_msg_fini(slmsg->msg);
1223
1224         kprintf("userfs_nrmdir\n");
1225         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1226                 par = &slmsg->rep->msg->sm_head;
1227
1228                 if (par->se_cmd == (SLVFS_CMD_VOP_NRMDIR|SE_CMDF_REPLY)) {
1229                         ;
1230                 } else {
1231                         error = EBADRPC;
1232                 }
1233         }
1234         syslink_kfreemsg(ump->sldesc, slmsg);
1235         kprintf("error %d\n", error);
1236         return(error);
1237 }
1238
1239 static
1240 int
1241 user_vop_nsymlink (struct vop_nsymlink_args *ap)
1242 {
1243         struct user_mount *ump;
1244         struct user_inode *ip;
1245         struct namecache *ncp;
1246         struct ucred *cred;
1247         struct vnode *dvp;
1248         struct vnode *vp;
1249         struct slmsg *slmsg;
1250         syslink_elm_t par;
1251         int error;
1252
1253         cred = ap->a_cred;
1254         ncp = ap->a_nch->ncp;
1255         dvp = ncp->nc_parent->nc_vp;    /* needs vget */
1256
1257         vp = NULL;      /* XXX */
1258
1259         ip = vp->v_data;
1260         ump = ip->ump;
1261
1262         slmsg = syslink_kallocmsg();
1263         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1264                               SLVFS_CMD_VOP_NSYMLINK);
1265         sl_msg_fini(slmsg->msg);
1266
1267         kprintf("userfs_nsymlink\n");
1268         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1269                 par = &slmsg->rep->msg->sm_head;
1270
1271                 if (par->se_cmd == (SLVFS_CMD_VOP_NSYMLINK|SE_CMDF_REPLY)) {
1272                         ;
1273                 } else {
1274                         error = EBADRPC;
1275                 }
1276         }
1277         syslink_kfreemsg(ump->sldesc, slmsg);
1278         kprintf("error %d\n", error);
1279         return(error);
1280 }
1281
1282 static
1283 int
1284 user_vop_nwhiteout (struct vop_nwhiteout_args *ap)
1285 {
1286         struct user_mount *ump;
1287         struct user_inode *ip;
1288         struct namecache *ncp;
1289         struct ucred *cred;
1290         struct vnode *dvp;
1291         struct vnode *vp;
1292         struct slmsg *slmsg;
1293         syslink_elm_t par;
1294         int error;
1295
1296         cred = ap->a_cred;
1297         ncp = ap->a_nch->ncp;
1298         dvp = ncp->nc_parent->nc_vp;    /* needs vget */
1299
1300         vp = NULL;      /* XXX */
1301
1302         ip = vp->v_data;
1303         ump = ip->ump;
1304
1305         slmsg = syslink_kallocmsg();
1306         par = sl_msg_init_cmd(slmsg->msg, SMPROTO_BSDVFS,
1307                               SLVFS_CMD_VOP_NWHITEOUT);
1308         sl_msg_fini(slmsg->msg);
1309
1310         kprintf("userfs_nwhiteout\n");
1311         if ((error = syslink_kdomsg(ump->sldesc, slmsg)) == 0) {
1312                 par = &slmsg->rep->msg->sm_head;
1313
1314                 if (par->se_cmd == (SLVFS_CMD_VOP_NWHITEOUT|SE_CMDF_REPLY)) {
1315                         ;
1316                 } else {
1317                         error = EBADRPC;
1318                 }
1319         }
1320         syslink_kfreemsg(ump->sldesc, slmsg);
1321         kprintf("error %d\n", error);
1322         return(error);
1323 }
1324