]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/gnu/fs/xfs/FreeBSD/xfs_vnops.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / gnu / fs / xfs / FreeBSD / xfs_vnops.c
1 /*
2  * Copyright (c) 2001, Alexander Kabaev
3  * Copyright (c) 2006, Russell Cattelan Digital Elves Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/namei.h>
32 #include <sys/kernel.h>
33 #include <sys/fcntl.h>
34 #include <sys/mount.h>
35 #include <sys/unistd.h>
36 #include <sys/vnode.h>
37 #include <sys/dirent.h>
38 #include <sys/ioccom.h>
39 #include <sys/malloc.h>
40 #include <sys/extattr.h>
41
42 #include <vm/vm.h>
43 #include <vm/vm_extern.h>
44 #include <vm/vm_object.h>
45 #include <vm/vm_page.h>
46 #include <vm/vm_pager.h>
47 #include <vm/vnode_pager.h>
48
49 #include <fs/fifofs/fifo.h>
50
51 #define NO_VFS_MACROS
52 #include "xfs.h"
53 #include "xfs_types.h"
54 #include "xfs_bit.h"
55 #include "xfs_inum.h"
56 #include "xfs_log.h"
57 #include "xfs_trans.h"
58 #include "xfs_trans_priv.h"
59 #include "xfs_sb.h"
60 #include "xfs_ag.h"
61 #include "xfs_dir.h"
62 #include "xfs_dir2.h"
63 #include "xfs_dmapi.h"
64 #include "xfs_mount.h"
65 #include "xfs_alloc_btree.h"
66 #include "xfs_bmap_btree.h"
67 #include "xfs_ialloc_btree.h"
68 #include "xfs_btree.h"
69 #include "xfs_imap.h"
70 #include "xfs_attr.h"
71 #include "xfs_attr_sf.h"
72 #include "xfs_dir_sf.h"
73 #include "xfs_dir2_sf.h"
74 #include "xfs_dinode.h"
75 #include "xfs_ialloc.h"
76 #include "xfs_alloc.h"
77 #include "xfs_inode.h"
78 #include "xfs_inode_item.h"
79 #include "xfs_acl.h"
80 #include "xfs_cap.h"
81 #include "xfs_mac.h"
82 #include "xfs_iomap.h"
83 #include "xfs_clnt.h"
84 #include "xfs_mountops.h"
85
86 /*
87  * Prototypes for XFS vnode operations.
88  */
89 static vop_access_t             _xfs_access;
90 static vop_advlock_t            _xfs_advlock;
91 static vop_bmap_t               _xfs_bmap;
92 static vop_cachedlookup_t       _xfs_cachedlookup;
93 static vop_close_t              _xfs_close;
94 static vop_create_t             _xfs_create;
95 static vop_deleteextattr_t      _xfs_deleteextattr;
96 static vop_fsync_t              _xfs_fsync;
97 static vop_getattr_t            _xfs_getattr;
98 static vop_getextattr_t         _xfs_getextattr;
99 static vop_inactive_t           _xfs_inactive;
100 static vop_ioctl_t              _xfs_ioctl;
101 static vop_link_t               _xfs_link;
102 static vop_listextattr_t        _xfs_listextattr;
103 static vop_mkdir_t              _xfs_mkdir;
104 static vop_mknod_t              _xfs_mknod;
105 static vop_open_t               _xfs_open;
106 static vop_read_t               _xfs_read;
107 static vop_readdir_t            _xfs_readdir;
108 static vop_readlink_t           _xfs_readlink;
109 static vop_reclaim_t            _xfs_reclaim;
110 static vop_remove_t             _xfs_remove;
111 static vop_rename_t             _xfs_rename;
112 static vop_rmdir_t              _xfs_rmdir;
113 static vop_setattr_t            _xfs_setattr;
114 static vop_setextattr_t         _xfs_setextattr;
115 static vop_strategy_t           _xfs_strategy;
116 static vop_symlink_t            _xfs_symlink;
117 static vop_write_t              _xfs_write;
118 static vop_vptofh_t             _xfs_vptofh;
119
120 struct vop_vector xfs_vnops = {
121         .vop_default =          &default_vnodeops,
122         .vop_access =           _xfs_access,
123         .vop_advlock =          _xfs_advlock,
124         .vop_bmap =             _xfs_bmap,
125         .vop_cachedlookup =     _xfs_cachedlookup,
126         .vop_close =            _xfs_close,
127         .vop_create =           _xfs_create,
128         .vop_deleteextattr =    _xfs_deleteextattr,
129         .vop_fsync =            _xfs_fsync,
130         .vop_getattr =          _xfs_getattr,
131         .vop_getextattr =       _xfs_getextattr,
132         .vop_inactive =         _xfs_inactive,
133         .vop_ioctl =            _xfs_ioctl,
134         .vop_link =             _xfs_link,
135         .vop_listextattr =      _xfs_listextattr,
136         .vop_lookup =           vfs_cache_lookup,
137         .vop_mkdir =            _xfs_mkdir,
138         .vop_mknod =            _xfs_mknod,
139         .vop_open =             _xfs_open,
140         .vop_read =             _xfs_read,
141         .vop_readdir =          _xfs_readdir,
142         .vop_readlink =         _xfs_readlink,
143         .vop_reclaim =          _xfs_reclaim,
144         .vop_remove =           _xfs_remove,
145         .vop_rename =           _xfs_rename,
146         .vop_rmdir =            _xfs_rmdir,
147         .vop_setattr =          _xfs_setattr,
148         .vop_setextattr =       _xfs_setextattr,
149         .vop_strategy =         _xfs_strategy,
150         .vop_symlink =          _xfs_symlink,
151         .vop_write =            _xfs_write,
152         .vop_vptofh =           _xfs_vptofh,
153 };
154
155 /*
156  *  FIFO's specific operations.
157  */
158
159 static vop_close_t      _xfsfifo_close;
160 static vop_read_t       _xfsfifo_read;
161 static vop_kqfilter_t   _xfsfifo_kqfilter;
162 static vop_write_t      _xfsfifo_write;
163
164 struct vop_vector xfs_fifoops = {
165         .vop_default =          &fifo_specops,
166         .vop_access =           _xfs_access,
167         .vop_close =            _xfsfifo_close,
168         .vop_fsync =            _xfs_fsync,
169         .vop_getattr =          _xfs_getattr,
170         .vop_inactive =         _xfs_inactive,
171         .vop_kqfilter =         _xfsfifo_kqfilter,
172         .vop_read =             _xfsfifo_read,
173         .vop_reclaim =          _xfs_reclaim,
174         .vop_setattr =          _xfs_setattr,
175         .vop_write =            _xfsfifo_write,
176         .vop_vptofh =           _xfs_vptofh,
177 };
178
179 static int
180 _xfs_access(
181         struct vop_access_args /* {
182                 struct vnode *a_vp;
183                 accmode_t a_accmode;
184                 struct ucred *a_cred;
185                 struct thread *a_td;
186         } */ *ap)
187 {
188         int error;
189
190         XVOP_ACCESS(VPTOXFSVP(ap->a_vp), ap->a_accmode, ap->a_cred, error);
191         return (error);
192 }
193
194 static int
195 _xfs_open(
196         struct vop_open_args /* {
197                 struct vnode *a_vp;
198                 int  a_mode;
199                 struct ucred *a_cred;
200                 struct thread *a_td;
201                 struct file *a_fp;
202         } */ *ap)
203 {
204         int error;
205
206         XVOP_OPEN(VPTOXFSVP(ap->a_vp), ap->a_cred, error);
207         if (error == 0)
208                 vnode_create_vobject(ap->a_vp, 0, ap->a_td);
209         return (error);
210 }
211
212 static int
213 _xfs_close(
214         struct vop_close_args /* {
215                 struct vnodeop_desc *a_desc;
216                 struct vnode *a_vp;
217                 int  a_fflag;
218                 struct ucred *a_cred;
219                 struct thread *a_td;
220         } */ *ap)
221 {
222         int error = 0;
223         /* XVOP_CLOSE(VPTOXFSVP(ap->a_vp), NULL, error); */
224         return (error);
225 }
226
227 static int
228 _xfs_getattr(
229         struct vop_getattr_args /* {
230                 struct vnode *a_vp;
231                 struct vattr *a_vap;
232                 struct ucred *a_cred;
233         } */ *ap)
234 {
235         struct vnode    *vp = ap->a_vp;
236         struct vattr    *vap = ap->a_vap;
237         struct mount    *mp;
238         xfs_vattr_t     va;
239         int             error;
240         /* extract the xfs vnode from the private data */
241         //xfs_vnode_t   *xvp = (xfs_vnode_t *)vp->v_data;
242
243         memset(&va,0,sizeof(xfs_vattr_t));
244         va.va_mask = XFS_AT_STAT|XFS_AT_GENCOUNT|XFS_AT_XFLAGS;
245
246         XVOP_GETATTR(VPTOXFSVP(vp), &va, 0, ap->a_cred, error);
247         if (error)
248                 return (error);
249
250         mp  = vp->v_mount;
251
252         vap->va_type = IFTOVT(((xfs_vnode_t *)vp->v_data)->v_inode->i_d.di_mode);
253         vap->va_mode = va.va_mode;
254         vap->va_nlink = va.va_nlink;
255         vap->va_uid = va.va_uid;
256         vap->va_gid = va.va_gid;
257         vap->va_fsid = mp->mnt_stat.f_fsid.val[0];
258         vap->va_fileid = va.va_nodeid;
259         vap->va_size = va.va_size;
260         vap->va_blocksize = va.va_blocksize;
261         vap->va_atime = va.va_atime;
262         vap->va_mtime = va.va_mtime;
263         vap->va_ctime = va.va_ctime;
264         vap->va_gen = va.va_gen;
265         vap->va_rdev = va.va_rdev;
266         vap->va_bytes = (va.va_nblocks << BBSHIFT);
267
268         /* XFS now supports devices that have block sizes
269          * other than 512 so BBSHIFT will work for now
270          * but need to get this value from the super block
271          */
272
273         /*
274          * Fields with no direct equivalent in XFS
275          */
276         vap->va_filerev = 0;
277         vap->va_flags = 0;
278
279         return (0);
280 }
281
282 static int
283 _xfs_setattr(
284         struct vop_setattr_args /* {
285                 struct vnode *a_vp;
286                 struct vattr *a_vap;
287                 struct ucred *a_cred;
288         } */ *ap)
289 {
290         struct vnode *vp = ap->a_vp;
291         struct vattr *vap = ap->a_vap;
292         xfs_vattr_t   va;
293         int error;
294
295         /*
296          * Check for unsettable attributes.
297          */
298 #ifdef RMC
299         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
300             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
301             (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
302             ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
303                 return (EINVAL);
304 #endif
305
306         memset(&va, 0, sizeof(va));
307
308         if (vap->va_uid != (uid_t)VNOVAL) {
309                 va.va_mask |= XFS_AT_UID;
310                 va.va_uid = vap->va_uid;
311         }
312         if (vap->va_gid != (gid_t)VNOVAL) {
313                 va.va_mask |= XFS_AT_GID;
314                 va.va_gid = vap->va_gid;
315         }
316         if (vap->va_size != VNOVAL) {
317                 va.va_mask |= XFS_AT_SIZE;
318                 va.va_size = vap->va_size;
319         }
320         if (vap->va_atime.tv_sec != VNOVAL) {
321                 va.va_mask |= XFS_AT_ATIME;
322                 va.va_atime = vap->va_atime;
323         }
324         if (vap->va_mtime.tv_sec != VNOVAL) {
325                 va.va_mask |= XFS_AT_MTIME;
326                 va.va_mtime = vap->va_mtime;
327         }
328         if (vap->va_ctime.tv_sec != VNOVAL) {
329                 va.va_mask |= XFS_AT_CTIME;
330                 va.va_ctime = vap->va_ctime;
331         }
332         if (vap->va_mode != (mode_t)VNOVAL) {
333                 va.va_mask |= XFS_AT_MODE;
334                 va.va_mode = vap->va_mode;
335         }
336
337         XVOP_SETATTR(VPTOXFSVP(vp), &va, 0, ap->a_cred, error);
338         return (error);
339 }
340
341 static int
342 _xfs_inactive(
343         struct vop_inactive_args  /* {
344                 struct vnode *a_vp;
345                 struct thread *a_td;
346         } */ *ap)
347 {
348         struct vnode *vp = ap->a_vp;
349         struct thread *td = ap->a_td;
350         int error;
351
352         XVOP_INACTIVE(VPTOXFSVP(vp), td->td_ucred, error);
353         return (error);
354 }
355
356 static int
357 _xfs_read(
358         struct vop_read_args /* {
359                 struct vnode *a_vp;
360                 struct uio *a_uio;
361                 int  a_ioflag;
362                 struct ucred *a_cred;
363         } */ *ap)
364 {
365         struct vnode *vp = ap->a_vp;
366         struct uio *uio = ap->a_uio;
367         int error;
368
369         switch (vp->v_type) {
370         case VREG:
371                 break;
372         case VDIR:
373                 return (EISDIR);
374         default:
375                 return (EPERM);
376         };
377
378         XVOP_READ(VPTOXFSVP(vp), uio, ap->a_ioflag, ap->a_cred, error);
379         return error;
380 }
381
382 int
383 xfs_read_file(xfs_mount_t *mp, xfs_inode_t *ip, struct uio *uio, int ioflag)
384 {
385         xfs_fileoff_t lbn, nextlbn;
386         xfs_fsize_t bytesinfile;
387         long size, xfersize, blkoffset;
388         struct buf *bp;
389         struct vnode *vp;
390         int error, orig_resid;
391         int seqcount;
392
393         seqcount = ioflag >> IO_SEQSHIFT;
394
395         orig_resid = uio->uio_resid;
396         if (orig_resid <= 0)
397                 return (0);
398
399         vp = XFS_ITOV(ip)->v_vnode;
400
401         /*
402          * Ok so we couldn't do it all in one vm trick...
403          * so cycle around trying smaller bites..
404          */
405         for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
406                 if ((bytesinfile = ip->i_d.di_size - uio->uio_offset) <= 0)
407                         break;
408
409                 lbn = XFS_B_TO_FSBT(mp, uio->uio_offset);
410                 nextlbn = lbn + 1;
411
412                 /*
413                  * size of buffer.  The buffer representing the
414                  * end of the file is rounded up to the size of
415                  * the block type ( fragment or full block,
416                  * depending ).
417                  */
418                 size = mp->m_sb.sb_blocksize;
419                 blkoffset = XFS_B_FSB_OFFSET(mp, uio->uio_offset);
420
421                 /*
422                  * The amount we want to transfer in this iteration is
423                  * one FS block less the amount of the data before
424                  * our startpoint (duh!)
425                  */
426                 xfersize = mp->m_sb.sb_blocksize - blkoffset;
427
428                 /*
429                  * But if we actually want less than the block,
430                  * or the file doesn't have a whole block more of data,
431                  * then use the lesser number.
432                  */
433                 if (uio->uio_resid < xfersize)
434                         xfersize = uio->uio_resid;
435                 if (bytesinfile < xfersize)
436                         xfersize = bytesinfile;
437
438                 if (XFS_FSB_TO_B(mp, nextlbn) >= ip->i_d.di_size ) {
439                         /*
440                          * Don't do readahead if this is the end of the file.
441                          */
442                         error = bread(vp, lbn, size, NOCRED, &bp);
443                 } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
444                         /*
445                          * Otherwise if we are allowed to cluster,
446                          * grab as much as we can.
447                          *
448                          * XXX  This may not be a win if we are not
449                          * doing sequential access.
450                          */
451                         error = cluster_read(vp, ip->i_d.di_size, lbn,
452                                 size, NOCRED, uio->uio_resid, seqcount, &bp);
453                 } else if (seqcount > 1) {
454                         /*
455                          * If we are NOT allowed to cluster, then
456                          * if we appear to be acting sequentially,
457                          * fire off a request for a readahead
458                          * as well as a read. Note that the 4th and 5th
459                          * arguments point to arrays of the size specified in
460                          * the 6th argument.
461                          */
462                         int nextsize = mp->m_sb.sb_blocksize;
463                         error = breadn(vp, lbn,
464                             size, &nextlbn, &nextsize, 1, NOCRED, &bp);
465                 } else {
466                         /*
467                          * Failing all of the above, just read what the
468                          * user asked for. Interestingly, the same as
469                          * the first option above.
470                          */
471                         error = bread(vp, lbn, size, NOCRED, &bp);
472                 }
473                 if (error) {
474                         brelse(bp);
475                         bp = NULL;
476                         break;
477                 }
478
479                 /*
480                  * If IO_DIRECT then set B_DIRECT for the buffer.  This
481                  * will cause us to attempt to release the buffer later on
482                  * and will cause the buffer cache to attempt to free the
483                  * underlying pages.
484                  */
485                 if (ioflag & IO_DIRECT)
486                         bp->b_flags |= B_DIRECT;
487
488                 /*
489                  * We should only get non-zero b_resid when an I/O error
490                  * has occurred, which should cause us to break above.
491                  * However, if the short read did not cause an error,
492                  * then we want to ensure that we do not uiomove bad
493                  * or uninitialized data.
494                  */
495                 size -= bp->b_resid;
496                 if (size < xfersize) {
497                         if (size == 0)
498                                 break;
499                         xfersize = size;
500                 }
501
502                 /*
503                  * otherwise use the general form
504                  */
505                 error = uiomove((char *)bp->b_data + blkoffset,
506                             (int)xfersize, uio);
507
508                 if (error)
509                         break;
510
511                 if (ioflag & (IO_VMIO|IO_DIRECT) ) {
512                         /*
513                          * If there are no dependencies, and it's VMIO,
514                          * then we don't need the buf, mark it available
515                          * for freeing. The VM has the data.
516                          */
517                         bp->b_flags |= B_RELBUF;
518                         brelse(bp);
519                 } else {
520                         /*
521                          * Otherwise let whoever
522                          * made the request take care of
523                          * freeing it. We just queue
524                          * it onto another list.
525                          */
526                         bqrelse(bp);
527                 }
528         }
529
530         /*
531          * This can only happen in the case of an error
532          * because the loop above resets bp to NULL on each iteration
533          * and on normal completion has not set a new value into it.
534          * so it must have come from a 'break' statement
535          */
536         if (bp != NULL) {
537                 if (ioflag & (IO_VMIO|IO_DIRECT)) {
538                         bp->b_flags |= B_RELBUF;
539                         brelse(bp);
540                 } else
541                         bqrelse(bp);
542         }
543
544         return (error);
545 }
546
547 static int
548 _xfs_write(struct vop_write_args /* {
549                 struct vnode *a_vp;
550                 struct uio *a_uio;
551                 int  a_ioflag;
552                 struct ucred *a_cred;
553         } */ *ap)
554 {
555         struct vnode *vp = ap->a_vp;
556         struct uio *uio = ap->a_uio;
557         int ioflag = ap->a_ioflag;
558         int error;
559
560         xfs_vnode_t *xvp = (xfs_vnode_t *)vp->v_data;
561
562         error = xfs_write(xvp->v_bh.bh_first, uio, ioflag, ap->a_cred);
563
564         if (error < 0) {
565                 printf("Xfs_write got error %d\n",error);
566                 return -error;
567         }
568         return 0;
569 }
570
571
572 int
573 xfs_write_file(xfs_inode_t *xip, struct uio *uio, int ioflag)
574 {
575         struct buf      *bp;
576         //struct thread *td;
577         daddr_t         lbn;
578         off_t           osize = 0;
579         off_t           offset= 0;
580         int             blkoffset, error, resid, xfersize;
581         int             fsblocksize;
582         int             seqcount;
583         xfs_iomap_t     iomap;
584         int             maps = 1;
585
586         xfs_vnode_t     *xvp = XFS_ITOV(xip);
587         struct vnode    *vp = xvp->v_vnode;
588
589         xfs_mount_t     *mp = (&xip->i_iocore)->io_mount;
590
591         seqcount = ioflag >> IO_SEQSHIFT;
592
593         memset(&iomap,0,sizeof(xfs_iomap_t));
594
595         /*
596          * Maybe this should be above the vnode op call, but so long as
597          * file servers have no limits, I don't think it matters.
598          */
599 #if 0
600         td = uio->uio_td;
601         if (vn_rlimit_fsize(vp, uio, uio->uio_td))
602                 return (EFBIG);
603 #endif
604
605         resid = uio->uio_resid;
606         offset = uio->uio_offset;
607         osize = xip->i_d.di_size;
608
609    /* xfs bmap wants bytes for both offset and size */
610         XVOP_BMAP(xvp,
611                   uio->uio_offset,
612                   uio->uio_resid,
613                   BMAPI_WRITE|BMAPI_DIRECT,
614                   &iomap, &maps, error);
615         if(error) {
616                 printf("XVOP_BMAP failed\n");
617                 goto error;
618         }
619
620         for (error = 0; uio->uio_resid > 0;) {
621
622                 lbn = XFS_B_TO_FSBT(mp, offset);
623                 blkoffset = XFS_B_FSB_OFFSET(mp, offset);
624                 xfersize = mp->m_sb.sb_blocksize - blkoffset;
625                 fsblocksize = mp->m_sb.sb_blocksize;
626
627                 if (uio->uio_resid < xfersize)
628                         xfersize = uio->uio_resid;
629
630                 /*
631                  * getblk sets buf by  blkno *  bo->bo_bsize
632                  * bo_bsize is set from the mnt point fsize
633                  * so we call getblk in the case using fsblocks
634                  * not basic blocks
635                  */
636
637                 bp = getblk(vp, lbn, fsblocksize, 0, 0, 0);
638                 if(!bp) {
639                         printf("getblk failed\n");
640                         error = EINVAL;
641                         break;
642                 }
643
644                 if (!(bp->b_flags & B_CACHE)  && fsblocksize > xfersize)
645                         vfs_bio_clrbuf(bp);
646
647                 if (offset + xfersize >  xip->i_d.di_size) {
648                         xip->i_d.di_size = offset + xfersize;
649                         vnode_pager_setsize(vp, offset + fsblocksize);
650                 }
651
652                 /* move the offset for the next itteration of the loop */
653                 offset += xfersize;
654
655                 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
656
657                 if ((ioflag & IO_VMIO) &&
658                    (LIST_FIRST(&bp->b_dep) == NULL)) /* in ext2fs? */
659                         bp->b_flags |= B_RELBUF;
660
661                 /* force to full direct for now */
662                 bp->b_flags |= B_DIRECT;
663                 /* and sync ... the delay path is not pushing data out */
664                 ioflag |= IO_SYNC;
665
666                 if (ioflag & IO_SYNC) {
667                         (void)bwrite(bp);
668                 } else if (0 /* RMC xfersize + blkoffset == fs->s_frag_size */) {
669                         if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
670                                 bp->b_flags |= B_CLUSTEROK;
671                                 cluster_write(vp, bp, osize, seqcount);
672                         } else {
673                                 bawrite(bp);
674                         }
675                 } else {
676                         bp->b_flags |= B_CLUSTEROK;
677                         bdwrite(bp);
678                 }
679                 if (error || xfersize == 0)
680                         break;
681         }
682         /*
683          * If we successfully wrote any data, and we are not the superuser
684          * we clear the setuid and setgid bits as a precaution against
685          * tampering.
686          */
687 #if 0
688         if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
689                 ip->i_mode &= ~(ISUID | ISGID);
690 #endif
691         if (error) {
692                 if (ioflag & IO_UNIT) {
693 #if 0
694                         (void)ext2_truncate(vp, osize,
695                             ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
696 #endif
697                         uio->uio_offset -= resid - uio->uio_resid;
698                         uio->uio_resid = resid;
699                 }
700         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
701                 /* Update the vnode here? */
702         }
703
704 error:
705         return error;
706 }
707
708 static int
709 _xfs_create(
710         struct vop_create_args  /* {
711                 struct vnode *a_dvp;
712                 struct vnode **a_vpp;
713                 struct componentname *a_cnp;
714                 struct vattr *a_vap;
715         } */ *ap)
716 {
717         struct vnode *dvp = ap->a_dvp;
718         struct vattr *vap = ap->a_vap;
719         struct thread *td = curthread;
720         struct ucred *credp = td->td_ucred;
721         struct componentname *cnp = ap->a_cnp;
722         xfs_vnode_t *xvp;
723         xfs_vattr_t va;
724         int error;
725
726         memset(&va, 0, sizeof (va));
727         va.va_mask |= XFS_AT_MODE;
728         va.va_mode = vap->va_mode;
729         va.va_mask |= XFS_AT_TYPE;
730         va.va_mode |=  VTTOIF(vap->va_type);
731
732         xvp = NULL;
733         XVOP_CREATE(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
734
735         if (error == 0) {
736                 *ap->a_vpp = xvp->v_vnode;
737                 VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE);
738         }
739
740         return (error);
741 }
742
743 extern int xfs_remove(bhv_desc_t *, bhv_desc_t *, vname_t *, cred_t *);
744
745 static int
746 _xfs_remove(
747         struct vop_remove_args /* {
748                 struct vnodeop_desc *a_desc;
749                 struct vnode * a_dvp;
750                 struct vnode * a_vp;
751                 struct componentname * a_cnp;
752         } */ *ap)
753 {
754         struct vnode *vp = ap->a_vp;
755         struct thread *td = curthread;
756         struct ucred  *credp = td->td_ucred;
757         /*
758         struct vnode *dvp = ap->a_dvp; 
759         struct componentname *cnp = ap->a_cnp;
760         */
761         int error;
762
763         if (vp->v_type == VDIR || vp->v_usecount != 1)
764                 return (EPERM);
765
766         error = xfs_remove(VPTOXFSVP(ap->a_dvp)->v_bh.bh_first,
767                            VPTOXFSVP(ap->a_vp)->v_bh.bh_first,
768                            ap->a_cnp,credp);
769
770         cache_purge(vp);
771         return error;
772 }
773
774 static int
775 _xfs_rename(
776         struct vop_rename_args /* {
777                 struct vnode *a_fdvp;
778                 struct vnode *a_fvp;
779                 struct componentname *a_fcnp;
780                 struct vnode *a_tdvp;
781                 struct vnode *a_tvp;
782                 struct componentname *a_tcnp;
783         } */ *ap)
784 {
785         struct vnode *fvp = ap->a_fvp;
786         struct vnode *tvp = ap->a_tvp;
787         struct vnode *fdvp = ap->a_fdvp;
788         struct vnode *tdvp = ap->a_tdvp;
789 /*      struct componentname *tcnp = ap->a_tcnp; */
790 /*      struct componentname *fcnp = ap->a_fcnp;*/
791         int error = EPERM;
792
793         if (error)
794                 goto out;
795
796         /* Check for cross-device rename */
797         if ((fvp->v_mount != tdvp->v_mount) ||
798             (tvp && (fvp->v_mount != tvp->v_mount))) {
799                 error = EXDEV;
800                 goto out;
801         }
802
803         if (tvp && tvp->v_usecount > 1) {
804                 error = EBUSY;
805                 goto out;
806         }
807
808         if (fvp->v_type == VDIR) {
809                 if (tvp != NULL && tvp->v_type == VDIR)
810                         cache_purge(tdvp);
811                 cache_purge(fdvp);
812         }
813 out:
814         if (tdvp == tvp)
815                 vrele(tdvp);
816         else
817                 vput(tdvp);
818         if (tvp)
819                 vput(tvp);
820         vrele(fdvp);
821         vrele(fvp);
822         vgone(fvp);
823         if (tvp)
824                 vgone(tvp);
825         return (error);
826 }
827
828 static int
829 _xfs_link(
830         struct vop_link_args /* {
831                 struct vnode *a_tdvp;
832                 struct vnode *a_vp;
833                 struct componentname *a_cnp;
834         } */ *ap)
835 {
836         xfs_vnode_t *tdvp, *vp;
837         int error;
838
839         tdvp = VPTOXFSVP(ap->a_tdvp);
840         vp = VPTOXFSVP(ap->a_vp);
841         XVOP_LINK(tdvp, vp, ap->a_cnp, NULL, error);
842         return (error);
843 }
844
845 static int
846 _xfs_symlink(
847         struct vop_symlink_args /* {
848                 struct vnode *a_dvp;
849                 struct vnode **a_vpp;
850                 struct componentname *a_cnp;
851                 struct vattr *a_vap;
852                 char *a_target;
853         } */ *ap)
854 {
855         struct thread *td = curthread;
856         struct ucred  *credp = td->td_ucred;
857         xfs_vnode_t *xvp;
858         xfs_vattr_t va;
859         int error;
860
861         memset(&va, 0, sizeof (va));
862
863         va.va_mask |= XFS_AT_MODE;
864         va.va_mode = ap->a_vap->va_mode | S_IFLNK;
865         va.va_mask |= XFS_AT_TYPE;
866
867         XVOP_SYMLINK(VPTOXFSVP(ap->a_dvp), ap->a_cnp, &va, ap->a_target,
868             &xvp, credp, error);
869
870         if (error == 0) {
871                 *ap->a_vpp = xvp->v_vnode;
872                 VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE);
873         }
874
875         return (error);
876 }
877
878 static int
879 _xfs_mknod(
880         struct vop_mknod_args /* {
881                 struct vnode *a_dvp;
882                 struct vnode **a_vpp;
883                 struct componentname *a_cnp;
884                 struct vattr *a_vap;
885         } */ *ap)
886 {
887         struct vnode *dvp = ap->a_dvp;
888         struct vattr *vap = ap->a_vap;
889         struct thread *td = curthread;
890         struct ucred *credp = td->td_ucred;
891         struct componentname *cnp = ap->a_cnp;
892         xfs_vnode_t *xvp;
893         xfs_vattr_t va;
894         int error;
895
896         memset(&va, 0, sizeof (va));
897         va.va_mask |= XFS_AT_MODE;
898         va.va_mode = vap->va_mode | S_IFIFO;
899         va.va_mask |= XFS_AT_TYPE;
900         va.va_mask |= XFS_AT_RDEV;
901         va.va_rdev = vap->va_rdev;
902
903         xvp = NULL;
904         XVOP_CREATE(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
905
906         if (error == 0) {
907                 *ap->a_vpp = xvp->v_vnode;
908                 VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE);
909         }
910
911         return (error);
912 }
913
914 static int
915 _xfs_mkdir(
916         struct vop_mkdir_args /* {
917                  struct vnode *a_dvp;
918                  struct vnode **a_vpp;
919                  struct componentname *a_cnp;
920                  struct vattr *a_vap;
921         } */ *ap)
922 {
923         struct vnode *dvp = ap->a_dvp;
924         struct vattr *vap = ap->a_vap;
925         struct thread *td = curthread;
926         struct ucred *credp = td->td_ucred;
927         struct componentname *cnp = ap->a_cnp;
928         xfs_vnode_t *xvp;
929         xfs_vattr_t va;
930         int error;
931
932         memset(&va, 0, sizeof (va));
933         va.va_mask |= XFS_AT_MODE;
934         va.va_mode = vap->va_mode | S_IFDIR;
935         va.va_mask |= XFS_AT_TYPE;
936
937         xvp = NULL;
938         XVOP_MKDIR(VPTOXFSVP(dvp), cnp, &va, &xvp, credp, error);
939
940         if (error == 0) {
941                 *ap->a_vpp = xvp->v_vnode;
942                 VOP_LOCK(xvp->v_vnode, LK_EXCLUSIVE);
943         }
944
945         return (error);
946 }
947
948 static int
949 _xfs_rmdir(
950         struct vop_rmdir_args /* {
951                 struct vnode *a_dvp;
952                 struct vnode *a_vp;
953                 struct componentname *a_cnp;
954         } */ *ap)
955 {
956         struct vnode *vp = ap->a_vp;
957         struct vnode *dvp = ap->a_dvp;
958 /*      struct componentname *cnp = ap->a_cnp; */
959         int error;
960
961         if (dvp == vp)
962                 return (EINVAL);
963
964         error = EPERM;
965
966         return (error);
967 }
968
969 static int
970 _xfs_readdir(
971         struct vop_readdir_args /* {
972                 struct vnode *a_vp;
973                 struct uio *a_uio;
974                 struct ucred *a_cred;
975                 int *a_eofflag;
976                 int *a_ncookies;
977                 u_long **a_cookies;
978         } */ *ap)
979 {
980         struct vnode *vp = ap->a_vp;
981         struct uio *uio = ap->a_uio;
982         int error;
983         off_t   off;
984         int     eof = 0;
985
986         if (vp->v_type != VDIR)
987                 return (EPERM);
988         if (ap->a_ncookies) {
989                 return (EOPNOTSUPP);
990         }
991
992         error = 0;
993         while (!eof){
994                 off = (int)uio->uio_offset;
995
996                 XVOP_READDIR(VPTOXFSVP(vp), uio, NULL, &eof, error);
997                 if ((uio->uio_offset == off) || error) {
998                         break;
999                 }
1000         }
1001
1002         if (ap->a_eofflag)
1003                 *ap->a_eofflag = (eof != 0);
1004
1005         return (error);
1006 }
1007
1008
1009 static int
1010 _xfs_readlink(
1011         struct vop_readlink_args /* {
1012                 struct vnode *a_vp;
1013                 struct uio *a_uio;
1014                 struct ucred *a_cred;
1015         } */ *ap)
1016 {
1017         struct vnode *vp = ap->a_vp;
1018         struct uio *uio = ap->a_uio;
1019         struct ucred *cred = ap->a_cred;
1020         int error;
1021
1022         XVOP_READLINK(VPTOXFSVP(vp), uio, 0, cred, error);
1023         return (error);
1024 }
1025
1026 static int
1027 _xfs_fsync(
1028         struct vop_fsync_args /* {
1029                 struct vnode * a_vp;
1030                 int  a_waitfor;
1031                 struct thread * a_td;
1032         } */ *ap)
1033 {
1034         xfs_vnode_t  *vp = VPTOXFSVP(ap->a_vp);
1035         int flags = FSYNC_DATA;
1036         int error;
1037
1038         if (ap->a_waitfor == MNT_WAIT)
1039                 flags |= FSYNC_WAIT;
1040         XVOP_FSYNC(vp, flags, ap->a_td->td_ucred, (xfs_off_t)0, (xfs_off_t)-1, error);
1041
1042         return (error);
1043 }
1044
1045 static int
1046 _xfs_bmap(
1047         struct vop_bmap_args /* {
1048                 struct vnode *a_vp;
1049                 daddr_t  a_bn;
1050                 struct bufobj **a_bop;
1051                 daddr_t *a_bnp;
1052                 int *a_runp;
1053                 int *a_runb;
1054         } */ *ap)
1055 {
1056         xfs_iomap_t iomap;
1057         xfs_off_t offset;
1058         ssize_t   size;
1059         struct mount *mp;
1060         struct xfs_mount *xmp;
1061         struct xfs_vnode *xvp;
1062         int error, maxrun, retbm;
1063
1064         mp  = ap->a_vp->v_mount;
1065         xmp = XFS_VFSTOM(MNTTOVFS(mp));
1066         if (ap->a_bop != NULL)
1067                 *ap->a_bop = &xmp->m_ddev_targp->specvp->v_bufobj;
1068         if (ap->a_bnp == NULL)
1069                 return (0);
1070
1071         xvp = VPTOXFSVP(ap->a_vp);
1072         retbm = 1;
1073
1074         offset = XFS_FSB_TO_B(xmp, ap->a_bn);
1075         size = XFS_FSB_TO_B(xmp, 1);
1076         XVOP_BMAP(xvp, offset, size, BMAPI_READ, &iomap, &retbm, error);
1077         if (error)
1078                 return (error);
1079         if (retbm == 0 || iomap.iomap_bn == IOMAP_DADDR_NULL) {
1080                 *ap->a_bnp = (daddr_t)-1;
1081                 if (ap->a_runb)
1082                         *ap->a_runb = 0;
1083                 if (ap->a_runp)
1084                         *ap->a_runp = 0;
1085         } else {
1086                 *ap->a_bnp = iomap.iomap_bn + btodb(iomap.iomap_delta);
1087                 maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
1088                 if (ap->a_runb) {
1089                         *ap->a_runb = XFS_B_TO_FSB(xmp, iomap.iomap_delta);
1090                         if (*ap->a_runb > maxrun)
1091                                 *ap->a_runb  = maxrun;
1092                 }
1093                 if (ap->a_runp) {
1094                         *ap->a_runp =
1095                             XFS_B_TO_FSB(xmp, iomap.iomap_bsize
1096                                 - iomap.iomap_delta - size);
1097                         if (*ap->a_runp > maxrun)
1098                                 *ap->a_runp  = maxrun;
1099                 }
1100         }
1101         return (0);
1102 }
1103
1104 static int
1105 _xfs_strategy(
1106         struct vop_strategy_args /* {
1107                 struct vnode *a_vp;
1108                 struct buf *a_bp;
1109         } */ *ap)
1110 {
1111         daddr_t blkno;
1112         struct buf *bp;
1113         struct bufobj *bo;
1114         struct vnode *vp;
1115         struct xfs_mount *xmp;
1116         int error;
1117
1118         bp = ap->a_bp;
1119         vp = ap->a_vp;
1120
1121         KASSERT(ap->a_vp == ap->a_bp->b_vp, ("%s(%p != %p)",
1122             __func__, ap->a_vp, ap->a_bp->b_vp));
1123         if (bp->b_blkno == bp->b_lblkno) {
1124                 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &blkno, NULL, NULL);
1125                 bp->b_blkno = blkno;
1126                 bp->b_iooffset = (blkno << BBSHIFT);
1127                 if (error) {
1128                         bp->b_error = error;
1129                         bp->b_ioflags |= BIO_ERROR;
1130                         bufdone(bp);
1131                         return (0);
1132                 }
1133                 if ((long)bp->b_blkno == -1)
1134                         vfs_bio_clrbuf(bp);
1135         }
1136         if ((long)bp->b_blkno == -1) {
1137                 bufdone(bp);
1138                 return (0);
1139         }
1140
1141         xmp = XFS_VFSTOM(MNTTOVFS(vp->v_mount));
1142         bo = &xmp->m_ddev_targp->specvp->v_bufobj;
1143         bo->bo_ops->bop_strategy(bo, bp);
1144         return (0);
1145 }
1146
1147 int
1148 _xfs_ioctl(
1149         struct vop_ioctl_args /* {
1150                 struct vnode *a_vp;
1151                 u_long a_command;
1152                 caddr_t a_data;
1153                 int fflag;
1154                 struct ucred *cred;
1155                 struct thread *a_td;
1156         } */ *ap)
1157 {
1158 /*      struct vnode *vp = ap->a_vp; */
1159 /*      struct thread *p = ap->a_td; */
1160 /*      struct file *fp; */
1161         int error;
1162
1163         xfs_vnode_t *xvp = VPTOXFSVP(ap->a_vp);
1164
1165         printf("_xfs_ioctl cmd 0x%lx data %p\n",ap->a_command,ap->a_data);
1166
1167 //      XVOP_IOCTL(xvp,(void *)NULL,(void *)NULL,ap->a_fflag,ap->a_command,ap->a_data,error);
1168         error = xfs_ioctl(xvp->v_bh.bh_first,NULL,NULL,ap->a_fflag,ap->a_command,ap->a_data);
1169
1170         return error;
1171 }
1172
1173 int
1174 _xfs_advlock(
1175         struct vop_advlock_args /* {
1176                 struct vnode *a_vp;
1177                 caddr_t  a_id;
1178                 int  a_op;
1179                 struct flock *a_fl;
1180                 int  a_flags;
1181         } */ *ap)
1182 {
1183 /*      struct vnode *vp = ap->a_vp;*/
1184         struct flock *fl = ap->a_fl;
1185 /*      caddr_t id = (caddr_t)1 */ /* ap->a_id */;
1186 /*      int flags = ap->a_flags; */
1187         off_t start, end, size;
1188         int error/* , lkop */;
1189
1190         /*KAN: temp */
1191         return (EOPNOTSUPP);
1192
1193         size = 0;
1194         error = 0;
1195         switch (fl->l_whence) {
1196             case SEEK_SET:
1197             case SEEK_CUR:
1198                 start = fl->l_start;
1199                 break;
1200             case SEEK_END:
1201                 start = fl->l_start + size;
1202             default:
1203                 return (EINVAL);
1204         }
1205         if (start < 0)
1206                 return (EINVAL);
1207         if (fl->l_len == 0)
1208                 end = -1;
1209         else {
1210                 end = start + fl->l_len - 1;
1211                 if (end < start)
1212                         return (EINVAL);
1213         }
1214 #ifdef notyet
1215         switch (ap->a_op) {
1216             case F_SETLK:
1217                 error = lf_advlock(ap, &vp->v_lockf, size);
1218                 break;
1219             case F_UNLCK:
1220                 lf_advlock(ap, &vp->v_lockf, size);
1221                 break;
1222             case F_GETLK:
1223                 error = lf_advlock(ap, &vp->v_lockf, size);
1224                 break;
1225             default:
1226                 return (EINVAL);
1227         }
1228 #endif
1229         return (error);
1230 }
1231
1232 static int
1233 _xfs_cachedlookup(
1234         struct vop_cachedlookup_args /* {
1235                 struct vnode * a_dvp;
1236                 struct vnode ** a_vpp;
1237                 struct componentname * a_cnp;
1238         } */ *ap)
1239 {
1240         struct vnode *dvp, *tvp;
1241         struct xfs_vnode *cvp;
1242         int islastcn;
1243         int error;
1244         struct vnode **vpp = ap->a_vpp;
1245         struct componentname *cnp = ap->a_cnp;
1246         struct ucred *cred = cnp->cn_cred;
1247         int flags = cnp->cn_flags;
1248         int nameiop = cnp->cn_nameiop;
1249         struct thread *td = cnp->cn_thread;
1250
1251         char *pname = cnp->cn_nameptr;
1252         int namelen = cnp->cn_namelen;
1253
1254         *vpp = NULL;
1255         dvp = ap->a_dvp;
1256         islastcn = flags & ISLASTCN;
1257
1258         XVOP_LOOKUP(VPTOXFSVP(dvp), cnp, &cvp, 0, NULL, cred, error);
1259
1260         if (error == ENOENT) {
1261                 if ((nameiop == CREATE || nameiop == RENAME ||
1262                      nameiop == DELETE) && islastcn)
1263                 {
1264                         error = VOP_ACCESS(dvp, VWRITE, cred, td);
1265                         if (error)
1266                                 return (error);
1267                         cnp->cn_flags |= SAVENAME;
1268                         return (EJUSTRETURN);
1269                 }
1270                 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
1271                         cache_enter(dvp, *vpp, cnp);
1272                 return (error);
1273         }
1274         if (error)
1275                 return (error);
1276
1277         tvp = cvp->v_vnode;
1278
1279         if (nameiop == DELETE && islastcn) {
1280                 if ((error = vn_lock(tvp, LK_EXCLUSIVE))) {
1281                         vrele(tvp);
1282                         goto err_out;
1283                 }
1284                 *vpp = tvp;
1285
1286                 /* Directory should be writable for deletes. */
1287                 error = VOP_ACCESS(dvp, VWRITE, cred, td);
1288                 if (error)
1289                         goto err_out;
1290
1291                 /* XXXKAN: Permission checks for sticky dirs? */
1292                 return (0);
1293          }
1294
1295         if (nameiop == RENAME && islastcn) {
1296                 if ((error = vn_lock(tvp, LK_EXCLUSIVE))) {
1297                         vrele(tvp);
1298                         goto err_out;
1299                 }
1300                 *vpp = tvp;
1301
1302                 if ((error = VOP_ACCESS(dvp, VWRITE, cred, td)))
1303                         goto err_out;
1304                 return (0);
1305         }
1306
1307         if (flags & ISDOTDOT) {
1308                 VOP_UNLOCK(dvp, 0);
1309                 error = vn_lock(tvp, cnp->cn_lkflags);
1310                 if (error) {
1311                         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1312                         vrele(tvp);
1313                         goto err_out;
1314                 }
1315                 *vpp = tvp;
1316         } else if (namelen == 1 && pname[0] == '.') {
1317                 *vpp = tvp;
1318                 KASSERT(tvp == dvp, ("not same directory"));
1319         } else {
1320                 if ((error = vn_lock(tvp, cnp->cn_lkflags))) {
1321                         vrele(tvp);
1322                         goto err_out;
1323                 }
1324                 *vpp = tvp;
1325         }
1326
1327         if (cnp->cn_flags & MAKEENTRY)
1328                 cache_enter(dvp, *vpp, cnp);
1329         return (0);
1330
1331 err_out:
1332         if (*vpp != 0)
1333                 vput(*vpp);
1334         return (error);
1335 }
1336
1337 static int
1338 _xfs_reclaim(
1339         struct vop_reclaim_args /* {
1340                 struct vnode *a_vp;
1341                 struct thread  *a_td;
1342         } */ *ap)
1343 {
1344
1345         struct vnode *vp = ap->a_vp;
1346         struct xfs_vnode *xfs_vp = VPTOXFSVP(vp);
1347         int error;
1348
1349         XVOP_RECLAIM(xfs_vp, error);
1350         kmem_free(xfs_vp, sizeof(*xfs_vp));
1351         vp->v_data = NULL;
1352         return (error);
1353 }
1354
1355 static int
1356 _xfs_kqfilter(
1357         struct vop_kqfilter_args /* {
1358                 struct vnodeop_desc *a_desc;
1359                 struct vnode *a_vp;
1360                 struct knote *a_kn;
1361         } */ *ap)
1362 {
1363         return (0);
1364 }
1365
1366 struct xfs_inode *
1367 xfs_vtoi(struct xfs_vnode *xvp)
1368 {
1369         return(XFS_BHVTOI(xvp->v_fbhv));
1370 }
1371
1372 /*
1373  * Read wrapper for fifos.
1374  */
1375 static int
1376 _xfsfifo_read(
1377         struct vop_read_args /* {
1378                 struct vnode *a_vp;
1379                 struct uio *a_uio;
1380                 int  a_ioflag;
1381                 struct ucred *a_cred;
1382         } */ *ap)
1383 {
1384         int error, resid;
1385         struct xfs_inode *ip;
1386         struct uio *uio;
1387
1388         uio = ap->a_uio;
1389         resid = uio->uio_resid;
1390         error = fifo_specops.vop_read(ap);
1391         ip = xfs_vtoi(VPTOXFSVP(ap->a_vp));
1392         if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
1393             (uio->uio_resid != resid || (error == 0 && resid != 0)))
1394                 xfs_ichgtime(ip, XFS_ICHGTIME_ACC);
1395         return (error);
1396 }
1397
1398 /*
1399  * Write wrapper for fifos.
1400  */
1401 static int
1402 _xfsfifo_write(
1403         struct vop_write_args /* {
1404                 struct vnode *a_vp;
1405                 struct uio *a_uio;
1406                 int  a_ioflag;
1407                 struct ucred *a_cred;
1408         } */ *ap)
1409 {
1410         int error, resid;
1411         struct uio *uio;
1412         struct xfs_inode *ip;
1413
1414         uio = ap->a_uio;
1415         resid = uio->uio_resid;
1416         error = fifo_specops.vop_write(ap);
1417         ip = xfs_vtoi(VPTOXFSVP(ap->a_vp));
1418         if (ip != NULL && (uio->uio_resid != resid ||
1419             (error == 0 && resid != 0)))
1420                 xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
1421         return (error);
1422 }
1423
1424 /*
1425  * Close wrapper for fifos.
1426  *
1427  * Update the times on the inode then do device close.
1428  */
1429 static int
1430 _xfsfifo_close(
1431         struct vop_close_args /* {
1432                 struct vnode *a_vp;
1433                 int  a_fflag;
1434                 struct ucred *a_cred;
1435                 struct thread *a_td;
1436         } */ *ap)
1437 {
1438
1439         return (fifo_specops.vop_close(ap));
1440 }
1441
1442 /*
1443  * Kqfilter wrapper for fifos.
1444  *
1445  * Fall through to ufs kqfilter routines if needed
1446  */
1447 static int
1448 _xfsfifo_kqfilter(
1449         struct vop_kqfilter_args /* {
1450                 struct vnodeop_desc *a_desc;
1451                 struct vnode *a_vp;
1452                 struct knote *a_kn;
1453         } */ *ap)
1454 {
1455         int error;
1456
1457         error = fifo_specops.vop_kqfilter(ap);
1458         if (error)
1459                 error = _xfs_kqfilter(ap);
1460         return (error);
1461 }
1462
1463 static int
1464 _xfs_getextattr(
1465         struct vop_getextattr_args /* {
1466                 struct vnode *a_vp;
1467                 int a_attrnamespace;
1468                 const char *a_name;
1469                 struct uio *a_uio;
1470                 size_t *a_size;
1471                 struct ucred *a_cred;
1472                 struct thread *a_td;
1473         } */ *ap)
1474 {
1475         int error;
1476         char *value;
1477         int size;
1478
1479         error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1480             ap->a_cred, ap->a_td, VREAD);
1481         if (error)
1482                 return (error);
1483
1484         size = ATTR_MAX_VALUELEN;
1485         value = (char *)kmem_zalloc(size, KM_SLEEP);
1486         if (value == NULL)
1487                 return (ENOMEM);
1488
1489         XVOP_ATTR_GET(VPTOXFSVP(ap->a_vp), ap->a_name, value, &size, 1,
1490             ap->a_cred, error);
1491
1492         if (ap->a_uio != NULL) {
1493                 if (ap->a_uio->uio_iov->iov_len < size)
1494                         error = ERANGE;
1495                 else
1496                         uiomove(value, size, ap->a_uio);
1497         }
1498
1499         if (ap->a_size != NULL)
1500                 *ap->a_size = size;
1501
1502         kmem_free(value, ATTR_MAX_VALUELEN);
1503         return (error);
1504 }               
1505
1506 static int
1507 _xfs_listextattr(
1508         struct vop_listextattr_args /* {
1509                 struct vnode *a_vp;
1510                 int a_attrnamespace;
1511                 struct uio *a_uio;
1512                 size_t *a_size;
1513                 struct ucred *a_cred;
1514                 struct thread *a_td;
1515         } */ *ap)
1516 {
1517         int error;
1518         char *buf = NULL;
1519         int buf_len = 0;
1520         attrlist_cursor_kern_t  cursor = { 0 };
1521         int i;
1522         char name_len;
1523         int attrnames_len = 0;
1524         int xfs_flags = ATTR_KERNAMELS;
1525
1526         error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1527             ap->a_cred, ap->a_td, VREAD);
1528         if (error)
1529                 return (error);
1530
1531         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
1532                 xfs_flags |= ATTR_KERNORMALS;
1533
1534         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
1535                 xfs_flags |= ATTR_KERNROOTLS;
1536
1537         if (ap->a_uio == NULL || ap->a_uio->uio_iov[0].iov_base == NULL) {
1538                 xfs_flags |= ATTR_KERNOVAL;
1539                 buf_len = 0;
1540         } else {
1541                 buf = ap->a_uio->uio_iov[0].iov_base;
1542                 buf_len = ap->a_uio->uio_iov[0].iov_len;
1543         }
1544
1545         XVOP_ATTR_LIST(VPTOXFSVP(ap->a_vp), buf, buf_len, xfs_flags,
1546                     &cursor, ap->a_cred, error);
1547         if (error < 0) {
1548                 attrnames_len = -error;
1549                 error = 0;
1550         }
1551         if (buf == NULL)
1552                 goto done;
1553
1554         /*
1555          * extattr_list expects a list of names.  Each list
1556          * entry consists of one byte for the name length, followed
1557          * by the name (not null terminated)
1558          */
1559         name_len=0;
1560         for(i=attrnames_len-1; i > 0 ; --i) {
1561                 buf[i] = buf[i-1];
1562                 if (buf[i])
1563                         ++name_len;
1564                 else {
1565                         buf[i] = name_len;
1566                         name_len = 0;
1567                 }
1568         } 
1569         buf[0] = name_len;
1570
1571         if (ap->a_uio != NULL)
1572                 ap->a_uio->uio_resid -= attrnames_len;
1573
1574 done:
1575         if (ap->a_size != NULL)
1576                 *ap->a_size = attrnames_len;
1577
1578         return (error);
1579 }
1580
1581 static int
1582 _xfs_setextattr(struct vop_setextattr_args *ap)
1583 /*
1584 vop_setextattr {
1585         IN struct vnode *a_vp;
1586         IN int a_attrnamespace;
1587         IN const char *a_name;
1588         INOUT struct uio *a_uio;
1589         IN struct ucred *a_cred;
1590         IN struct thread *a_td;
1591 };
1592 */
1593 {
1594         char *val;
1595         size_t vallen;
1596         int error, xfs_flags;
1597
1598         if (ap->a_vp->v_type == VCHR)
1599                 return (EOPNOTSUPP);
1600
1601         if (ap->a_uio == NULL)
1602                 return (EINVAL);
1603         vallen = ap->a_uio->uio_resid;
1604         if (vallen > ATTR_MAX_VALUELEN)
1605                 return (EOVERFLOW);
1606
1607         if (ap->a_name[0] == '\0')
1608                 return (EINVAL);
1609
1610         error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1611             ap->a_cred, ap->a_td, VWRITE);
1612         if (error)
1613                 return (error);
1614
1615         xfs_flags = 0;
1616         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
1617                 xfs_flags |= ATTR_KERNORMALS;
1618         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
1619                 xfs_flags |= ATTR_KERNROOTLS;
1620
1621         val = (char *)kmem_zalloc(vallen, KM_SLEEP);
1622         if (val == NULL)
1623                 return (ENOMEM);
1624         error = uiomove(val, (int)vallen, ap->a_uio);
1625         if (error)
1626                 goto err_out;
1627
1628         XVOP_ATTR_SET(VPTOXFSVP(ap->a_vp), ap->a_name, val, vallen, xfs_flags,
1629             ap->a_cred, error);
1630 err_out:
1631         kmem_free(val, vallen);
1632         return(error);
1633 }
1634
1635 static int
1636 _xfs_deleteextattr(struct vop_deleteextattr_args *ap)
1637 /*
1638 vop_deleteextattr {
1639         IN struct vnode *a_vp;
1640         IN int a_attrnamespace;
1641         IN const char *a_name;
1642         IN struct ucred *a_cred;
1643         IN struct thread *a_td;
1644 };
1645 */
1646 {
1647         int error, xfs_flags;
1648
1649         if (ap->a_vp->v_type == VCHR)
1650                 return (EOPNOTSUPP);
1651
1652         if (ap->a_name[0] == '\0')
1653                 return (EINVAL);
1654
1655         error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
1656             ap->a_cred, ap->a_td, VWRITE);
1657         if (error)
1658                 return (error);
1659
1660         xfs_flags = 0;
1661         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_USER)
1662                 xfs_flags |= ATTR_KERNORMALS;
1663         if (ap->a_attrnamespace & EXTATTR_NAMESPACE_SYSTEM)
1664                 xfs_flags |= ATTR_KERNROOTLS;
1665
1666         XVOP_ATTR_REMOVE(VPTOXFSVP(ap->a_vp), ap->a_name, xfs_flags,
1667             ap->a_cred, error);
1668         return (error);
1669 }
1670
1671 static int
1672 _xfs_vptofh(struct vop_vptofh_args *ap)
1673 /*
1674 vop_vptofh {
1675         IN struct vnode *a_vp;
1676         IN struct fid *a_fhp;
1677 };
1678 */
1679 {
1680         printf("xfs_vptofh");
1681         return ENOSYS;
1682 }