Merge branch 'vendor/BZIP'
[dragonfly.git] / sys / vfs / gnu / ext2fs / ext2_vnops.c
1 /*
2  *  modified for EXT2FS support in Lites 1.1
3  *
4  *  Aug 1995, Godmar Back (gback@cs.utah.edu)
5  *  University of Utah, Department of Computer Science
6  */
7 /*
8  * Copyright (c) 1982, 1986, 1989, 1993
9  *      The Regents of the University of California.  All rights reserved.
10  * (c) UNIX System Laboratories, Inc.
11  * All or some portions of this file are derived from material licensed
12  * to the University of California by American Telephone and Telegraph
13  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
14  * the permission of UNIX System Laboratories, Inc.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *      This product includes software developed by the University of
27  *      California, Berkeley and its contributors.
28  * 4. Neither the name of the University nor the names of its contributors
29  *    may be used to endorse or promote products derived from this software
30  *    without specific prior written permission.
31  *
32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42  * SUCH DAMAGE.
43  *
44  *      @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
45  *      @(#)ext2_vnops.c        8.7 (Berkeley) 2/3/94
46  * $FreeBSD: src/sys/gnu/ext2fs/ext2_vnops.c,v 1.51.2.2 2003/01/02 17:26:18 bde Exp $
47  * $DragonFly: src/sys/vfs/gnu/ext2fs/ext2_vnops.c,v 1.43 2008/06/19 23:27:39 dillon Exp $
48  */
49
50 #include "opt_quota.h"
51 #include "opt_suiddir.h"
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/resourcevar.h>
56 #include <sys/kernel.h>
57 #include <sys/stat.h>
58 #include <sys/fcntl.h>
59 #include <sys/buf.h>
60 #include <sys/stat.h>
61 #include <sys/proc.h>
62 #include <sys/priv.h>
63 #include <sys/mount.h>
64 #include <sys/time.h>
65 #include <sys/vnode.h>
66 #include <sys/dirent.h>
67 #include <sys/lockf.h>
68 #include <sys/event.h>
69 #include <sys/conf.h>
70 #include <sys/file.h>
71 #include <sys/jail.h>
72 #include <sys/namei.h>
73 #include <sys/signalvar.h>
74 #include <sys/unistd.h>
75
76 #include <vm/vm.h>
77 #include <vm/vm_extern.h>
78 #include <vm/vm_zone.h>
79 #include <vm/vnode_pager.h>
80
81 #include <sys/buf2.h>
82 #include <sys/thread2.h>
83
84 #include <vfs/fifofs/fifo.h>
85
86 #include "dir.h"
87 #include "quota.h"
88 #include "inode.h"
89 #include "ext2mount.h"
90 #include "ext2_fs_sb.h"
91 #include "fs.h"
92 #include "ext2_extern.h"
93 #include "ext2_fs.h"
94
95 static int ext2_access (struct vop_access_args *);
96 static int ext2_advlock (struct vop_advlock_args *);
97 static int ext2_chmod (struct vnode *, int, struct ucred *);
98 static int ext2_chown (struct vnode *, uid_t, gid_t, struct ucred *);
99 static int ext2_close (struct vop_close_args *);
100 static int ext2_getattr (struct vop_getattr_args *);
101 static int ext2_makeinode (int mode, struct vnode *, struct vnode **, struct componentname *);
102 static int ext2_mmap (struct vop_mmap_args *);
103 static int ext2_open (struct vop_open_args *);
104 static int ext2_pathconf (struct vop_pathconf_args *);
105 static int ext2_print (struct vop_print_args *);
106 static int ext2_readlink (struct vop_readlink_args *);
107 static int ext2_setattr (struct vop_setattr_args *);
108 static int ext2_strategy (struct vop_strategy_args *);
109 static int ext2_whiteout (struct vop_old_whiteout_args *);
110 static int filt_ext2read (struct knote *kn, long hint);
111 static int filt_ext2write (struct knote *kn, long hint);
112 static int filt_ext2vnode (struct knote *kn, long hint);
113 static void filt_ext2detach (struct knote *kn);
114 static int ext2_kqfilter (struct vop_kqfilter_args *ap);
115 static int ext2fifo_close (struct vop_close_args *);
116 static int ext2fifo_kqfilter (struct vop_kqfilter_args *);
117 static int ext2fifo_read (struct vop_read_args *);
118 static int ext2fifo_write (struct vop_write_args *);
119
120 static int ext2_fsync (struct vop_fsync_args *);
121 static int ext2_read (struct vop_read_args *);
122 static int ext2_write (struct vop_write_args *);
123 static int ext2_remove (struct vop_old_remove_args *);
124 static int ext2_link (struct vop_old_link_args *);
125 static int ext2_rename (struct vop_old_rename_args *);
126 static int ext2_mkdir (struct vop_old_mkdir_args *);
127 static int ext2_rmdir (struct vop_old_rmdir_args *);
128 static int ext2_create (struct vop_old_create_args *);
129 static int ext2_mknod (struct vop_old_mknod_args *);
130 static int ext2_symlink (struct vop_old_symlink_args *);
131
132 #include "ext2_readwrite.c"
133
134 union _qcvt {
135         int64_t qcvt;
136         int32_t val[2];
137 };
138 #define SETHIGH(q, h) { \
139         union _qcvt tmp; \
140         tmp.qcvt = (q); \
141         tmp.val[_QUAD_HIGHWORD] = (h); \
142         (q) = tmp.qcvt; \
143 }
144 #define SETLOW(q, l) { \
145         union _qcvt tmp; \
146         tmp.qcvt = (q); \
147         tmp.val[_QUAD_LOWWORD] = (l); \
148         (q) = tmp.qcvt; \
149 }
150 #define VN_KNOTE(vp, b) \
151         KNOTE(&vp->v_pollinfo.vpi_kqinfo.ki_note, (b))
152
153 #define OFSFMT(vp)              ((vp)->v_mount->mnt_maxsymlinklen <= 0)
154
155 /*
156  * A virgin directory (no blushing please).
157  * Note that the type and namlen fields are reversed relative to ufs.
158  * Also, we don't use `struct odirtemplate', since it would just cause
159  * endianness problems.
160  */
161 static struct dirtemplate ext2_mastertemplate = {
162         0, 12, 1, EXT2_FT_DIR, ".",
163         0, DIRBLKSIZ - 12, 2, EXT2_FT_DIR, ".."
164 };
165 static struct dirtemplate ext2_omastertemplate = {
166         0, 12, 1, EXT2_FT_UNKNOWN, ".",
167         0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
168 };
169
170 /*
171  * Create a regular file
172  *
173  * ext2_create(struct vnode *a_dvp, struct vnode **a_vpp,
174  *             struct componentname *a_cnp, struct vattr *a_vap)
175  */
176 static int
177 ext2_create(struct vop_old_create_args *ap)
178 {
179         int error;
180
181         error =
182             ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
183             ap->a_dvp, ap->a_vpp, ap->a_cnp);
184         if (error)
185                 return (error);
186         return (0);
187 }
188
189 /*
190  * Synch an open file.
191  *
192  * ext2_fsync(struct vnode *a_vp, struct ucred *a_cred, int a_waitfor,
193  *            struct proc *a_p)
194  */
195 /* ARGSUSED */
196
197 static int ext2_fsync_bp(struct buf *bp, void *data);
198
199 struct ext2_fsync_bp_info {
200         struct vnode *vp;
201         int waitfor;
202 };
203
204 static int
205 ext2_fsync(struct vop_fsync_args *ap)
206 {
207         struct ext2_fsync_bp_info info;
208         struct vnode *vp = ap->a_vp;
209         int count;
210
211         /* 
212          * XXX why is all this fs specific?
213          */
214
215         /*
216          * Flush all dirty buffers associated with a vnode.
217          */
218         ext2_discard_prealloc(VTOI(vp));
219
220         lwkt_gettoken(&vp->v_token);
221         info.vp = vp;
222 loop:
223         info.waitfor = ap->a_waitfor;
224         count = RB_SCAN(buf_rb_tree, &vp->v_rbdirty_tree, NULL, 
225                         ext2_fsync_bp, &info);
226         if (count)
227                 goto loop;
228
229         if (ap->a_waitfor == MNT_WAIT) {
230                 bio_track_wait(&vp->v_track_write, 0, 0);
231 #if DIAGNOSTIC
232                 if (!RB_EMPTY(&vp->v_rbdirty_tree)) {
233                         vprint("ext2_fsync: dirty", vp);
234                         goto loop;
235                 }
236 #endif
237         }
238         lwkt_reltoken(&vp->v_token);
239         return (EXT2_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
240 }
241
242 static int
243 ext2_fsync_bp(struct buf *bp, void *data)
244 {
245         struct ext2_fsync_bp_info *info = data;
246
247         if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
248                 return(0);
249         if ((bp->b_flags & B_DELWRI) == 0)
250                 panic("ext2_fsync: not dirty");
251         bremfree(bp);
252
253         /*
254          * Wait for I/O associated with indirect blocks to complete,
255          * since there is no way to quickly wait for them below.
256          */
257         if (bp->b_vp == info->vp || info->waitfor == MNT_NOWAIT)
258                 bawrite(bp);
259         else
260                 bwrite(bp);
261         return(1);
262 }
263
264 /*
265  * Mknod vnode call
266  *
267  * ext2_mknod(struct vnode *a_dvp, struct vnode **a_vpp,
268  *            struct componentname *a_cnp, struct vattr *a_vap)
269  */
270 /* ARGSUSED */
271 static int
272 ext2_mknod(struct vop_old_mknod_args *ap)
273 {
274         struct vattr *vap = ap->a_vap;
275         struct vnode **vpp = ap->a_vpp;
276         struct inode *ip;
277         ino_t ino;
278         int error;
279
280         if (vap->va_rmajor != VNOVAL &&
281             makeudev(vap->va_rmajor, vap->va_rminor) == NOUDEV) {
282                 return (EINVAL);
283         }
284
285         error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
286             ap->a_dvp, vpp, ap->a_cnp);
287         if (error)
288                 return (error);
289         ip = VTOI(*vpp);
290         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
291         if (vap->va_rmajor != VNOVAL) {
292                 /*
293                  * Want to be able to use this to make badblock
294                  * inodes, so don't truncate the dev number.
295                  */
296                 ip->i_rdev = makeudev(vap->va_rmajor, vap->va_rminor);
297         }
298         /*
299          * Remove inode, then reload it through VFS_VGET so it is
300          * checked to see if it is an alias of an existing entry in
301          * the inode cache.
302          */
303         (*vpp)->v_type = VNON;
304         ino = ip->i_number;     /* Save this before vgone() invalidates ip. */
305         vgone_vxlocked(*vpp);
306         vput(*vpp);
307         error = VFS_VGET(ap->a_dvp->v_mount, NULL, ino, vpp);
308         if (error) {
309                 *vpp = NULL;
310                 return (error);
311         }
312         return (0);
313 }
314
315 /*
316  * ext2_remove(struct vnode *a_dvp, struct vnode *a_vp,
317  *             struct componentname *a_cnp)
318  */
319 static int
320 ext2_remove(struct vop_old_remove_args *ap)
321 {
322         struct inode *ip;
323         struct vnode *vp = ap->a_vp;
324         struct vnode *dvp = ap->a_dvp;
325         int error;
326
327         ip = VTOI(vp);
328         if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
329             (VTOI(dvp)->i_flags & APPEND)) {
330                 error = EPERM;
331                 goto out;
332         }
333         error = ext2_dirremove(dvp, ap->a_cnp);
334         if (error == 0) {
335                 ip->i_nlink--;
336                 ip->i_flag |= IN_CHANGE;
337         }
338 out:
339         return (error);
340 }
341
342 /*
343  * link vnode call
344  *
345  * ext2_link(struct vnode *a_tdvp, struct vnode *a_vp,
346  *           struct componentname *a_cnp)
347  */
348 static int
349 ext2_link(struct vop_old_link_args *ap)
350 {
351         struct vnode *vp = ap->a_vp;
352         struct vnode *tdvp = ap->a_tdvp;
353         struct componentname *cnp = ap->a_cnp;
354         struct inode *ip;
355         int error;
356
357         if (tdvp->v_mount != vp->v_mount) {
358                 error = EXDEV;
359                 goto out2;
360         }
361         if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
362                 goto out2;
363         }
364         ip = VTOI(vp);
365         if ((nlink_t)ip->i_nlink >= LINK_MAX) {
366                 error = EMLINK;
367                 goto out1;
368         }
369         if (ip->i_flags & (IMMUTABLE | APPEND)) {
370                 error = EPERM;
371                 goto out1;
372         }
373         ip->i_nlink++;
374         ip->i_flag |= IN_CHANGE;
375         error = EXT2_UPDATE(vp, 1);
376         if (!error)
377                 error = ext2_direnter(ip, tdvp, cnp);
378         if (error) {
379                 ip->i_nlink--;
380                 ip->i_flag |= IN_CHANGE;
381         }
382 out1:
383         if (tdvp != vp)
384                 vn_unlock(vp);
385 out2:
386         return (error);
387 }
388
389 /*
390  * Rename system call.  fdvp, fvp are ref'd.  tvp, tdvp are ref'd and locked.
391  * all vp's are released and must be in an unlocked state on return.
392  *
393  * ext2_rename(struct vnode *a_fdvp, struct vnode *a_fvp,
394  *              struct componentname *a_fcnp, struct vnode *a_tdvp,
395  *              struct vnode *a_tvp, struct componentname *a_tcnp)
396  */
397 static int
398 ext2_rename(struct vop_old_rename_args *ap)
399 {
400         struct vnode *tvp = ap->a_tvp;
401         struct vnode *tdvp = ap->a_tdvp;
402         struct vnode *fvp = ap->a_fvp;
403         struct vnode *fdvp = ap->a_fdvp;
404         struct componentname *tcnp = ap->a_tcnp;
405         struct componentname *fcnp = ap->a_fcnp;
406         struct inode *ip, *xp, *dp;
407         struct dirtemplate dirbuf;
408         int doingdirectory = 0, oldparent = 0, newparent = 0;
409         int error = 0;
410         u_char namlen;
411
412         /*
413          * Check for cross-device rename.
414          */
415         if ((fvp->v_mount != tdvp->v_mount) ||
416             (tvp && (fvp->v_mount != tvp->v_mount)) ||
417             tvp == tdvp) {
418                 error = EXDEV;
419 abortit:
420                 if (tdvp == tvp)
421                         vrele(tdvp);
422                 else
423                         vput(tdvp);
424                 if (tvp)
425                         vput(tvp);
426                 vrele(fdvp);
427                 vrele(fvp);
428                 return (error);
429         }
430
431         if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
432             (VTOI(tdvp)->i_flags & APPEND))) {
433                 error = EPERM;
434                 goto abortit;
435         }
436
437         /*
438          * Renaming a file to itself has no effect.  The upper layers should
439          * not call us in that case.  Temporarily just warn if they do.
440          */
441         if (fvp == tvp) {
442                 error = 0;
443                 goto abortit;
444         }
445
446         if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
447                 goto abortit;
448
449         /*
450          * fvp, tvp, tdvp locked.  fdvp not locked but note that fdvp may
451          * be equal to tdvp.
452          */
453         dp = VTOI(fdvp);
454         ip = VTOI(fvp);
455         if (ip->i_nlink >= LINK_MAX) {
456                 vn_unlock(fvp);
457                 error = EMLINK;
458                 goto abortit;
459         }
460         if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
461             || (dp->i_flags & APPEND)) {
462                 vn_unlock(fvp);
463                 error = EPERM;
464                 goto abortit;
465         }
466         if ((ip->i_mode & IFMT) == IFDIR) {
467                 /*
468                  * Avoid ".", "..", and aliases of "." for obvious reasons.
469                  */
470                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
471                     dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & CNP_ISDOTDOT ||
472                     (ip->i_flag & IN_RENAME)) {
473                         vn_unlock(fvp);
474                         error = EINVAL;
475                         goto abortit;
476                 }
477                 ip->i_flag |= IN_RENAME;
478                 oldparent = dp->i_number;
479                 doingdirectory++;
480         }
481
482         /*
483          * tvp is non-NULL if the target exists.   fvp is still locked but
484          * we will unlock it soon.  The 'bad' goto target requires dp and
485          * xp to be correctly assigned.
486          */
487         dp = VTOI(tdvp);
488         if (tvp)
489                 xp = VTOI(tvp);
490         else
491                 xp = NULL;
492
493         /*
494          * 1) Bump link count while we're moving stuff
495          *    around.  If we crash somewhere before
496          *    completing our work, the link count
497          *    may be wrong, but correctable.
498          */
499         ip->i_nlink++;
500         ip->i_flag |= IN_CHANGE;
501         if ((error = EXT2_UPDATE(fvp, 1)) != 0) {
502                 vn_unlock(fvp);
503                 goto bad;
504         }
505
506         /*
507          * If ".." must be changed (ie the directory gets a new
508          * parent) then the source directory must not be in the
509          * directory heirarchy above the target, as this would
510          * orphan everything below the source directory. Also
511          * the user must have write permission in the source so
512          * as to be able to change "..". We must repeat the call
513          * to namei, as the parent directory is unlocked by the
514          * call to checkpath().
515          */
516         error = VOP_EACCESS(fvp, VWRITE, tcnp->cn_cred);
517         vn_unlock(fvp);
518
519         /*
520          * tvp (if not NULL) and tdvp are locked.  fvp and fdvp are not.
521          * dp and xp are set according to tdvp and tvp.
522          */
523         if (oldparent != dp->i_number)
524                 newparent = dp->i_number;
525         if (doingdirectory && newparent) {
526                 if (error)      /* write access check above */
527                         goto bad;
528
529                 /*
530                  * Prepare for relookup, get rid of xp
531                  */
532                 if (xp != NULL) {
533                         vput(tvp);
534                         xp = NULL;
535                 }
536
537                 /*
538                  * checkpath vput()'s tdvp (VTOI(dp)) on return no matter what,
539                  * get an extra ref so we wind up with just an unlocked, ref'd
540                  * tdvp.  The 'out' target skips xp and tdvp cleanups.  Our
541                  * tdvp is now unlocked so we have to clean it up ourselves.
542                  */
543                 vref(tdvp);
544                 error = ext2_checkpath(ip, dp, tcnp->cn_cred);
545                 tcnp->cn_flags |= CNP_PDIRUNLOCK;
546                 if (error) {
547                         vrele(tdvp);
548                         goto out;
549                 }
550                 /*
551                  * relookup no longer messes with the ref count.  An unlocked
552                  * tdvp must be passed and if no error occurs a locked tdvp
553                  * will be returned.  We have to use the out target again.
554                  */
555                 error = relookup(tdvp, &tvp, tcnp);
556                 if (error) {
557                         if (tcnp->cn_flags & CNP_PDIRUNLOCK)
558                                 vrele(tdvp);
559                         else
560                                 vput(tdvp);
561                         goto out;
562                 }
563
564                 /*
565                  * tdvp is locked at this point.  in the RENAME case tvp may
566                  * be NULL without an error, assign xp accordingly.  The
567                  * 'bad' target can be used again after this.
568                  */
569                 dp = VTOI(tdvp);
570                 if (tvp)
571                         xp = VTOI(tvp);
572         }
573         /*
574          * 2) If target doesn't exist, link the target
575          *    to the source and unlink the source.
576          *    Otherwise, rewrite the target directory
577          *    entry to reference the source inode and
578          *    expunge the original entry's existence.
579          *
580          * tdvp and tvp are cleaned up by this code.  tvp is only good if
581          * xp is not NULL.
582          */
583         if (xp == NULL) {
584                 if (dp->i_dev != ip->i_dev)
585                         panic("ext2_rename: EXDEV");
586                 /*
587                  * Account for ".." in new directory.
588                  * When source and destination have the same
589                  * parent we don't fool with the link count.
590                  */
591                 if (doingdirectory && newparent) {
592                         if ((nlink_t)dp->i_nlink >= LINK_MAX) {
593                                 error = EMLINK;
594                                 goto bad;
595                         }
596                         dp->i_nlink++;
597                         dp->i_flag |= IN_CHANGE;
598                         error = EXT2_UPDATE(tdvp, 1);
599                         if (error)
600                                 goto bad;
601                 }
602                 error = ext2_direnter(ip, tdvp, tcnp);
603                 if (error) {
604                         if (doingdirectory && newparent) {
605                                 dp->i_nlink--;
606                                 dp->i_flag |= IN_CHANGE;
607                                 EXT2_UPDATE(tdvp, 1);
608                         }
609                         goto bad;
610                 }
611
612                 /*
613                  * manual cleanup, we can't use the bad or out target after
614                  * this.
615                  */
616                 vput(tdvp);
617         } else {
618                 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
619                         panic("ext2_rename: EXDEV");
620                 /*
621                  * Short circuit rename(foo, foo).
622                  */
623                 if (xp->i_number == ip->i_number)
624                         panic("ext2_rename: same file");
625                 /*
626                  * If the parent directory is "sticky", then the user must
627                  * own the parent directory, or the destination of the rename,
628                  * otherwise the destination may not be changed (except by
629                  * root). This implements append-only directories.
630                  */
631                 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
632                     tcnp->cn_cred->cr_uid != dp->i_uid &&
633                     xp->i_uid != tcnp->cn_cred->cr_uid) {
634                         error = EPERM;
635                         goto bad;
636                 }
637                 /*
638                  * Target must be empty if a directory and have no links
639                  * to it. Also, ensure source and target are compatible
640                  * (both directories, or both not directories).
641                  */
642                 if ((xp->i_mode&IFMT) == IFDIR) {
643                         if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) || 
644                             xp->i_nlink > 2) {
645                                 error = ENOTEMPTY;
646                                 goto bad;
647                         }
648                         if (!doingdirectory) {
649                                 error = ENOTDIR;
650                                 goto bad;
651                         }
652                 } else if (doingdirectory) {
653                         error = EISDIR;
654                         goto bad;
655                 }
656                 error = ext2_dirrewrite(dp, ip, tcnp);
657                 if (error)
658                         goto bad;
659                 /*
660                  * If the target directory is in the same
661                  * directory as the source directory,
662                  * decrement the link count on the parent
663                  * of the target directory.
664                  */
665                  if (doingdirectory && !newparent) {
666                         dp->i_nlink--;
667                         dp->i_flag |= IN_CHANGE;
668                 }
669
670                 /*
671                  * manual cleanup, we can't use the bad or out target after
672                  * this.
673                  */
674                 vput(tdvp);
675
676                 /*
677                  * Adjust the link count of the target to
678                  * reflect the dirrewrite above.  If this is
679                  * a directory it is empty and there are
680                  * no links to it, so we can squash the inode and
681                  * any space associated with it.  We disallowed
682                  * renaming over top of a directory with links to
683                  * it above, as the remaining link would point to
684                  * a directory without "." or ".." entries.
685                  */
686                 xp->i_nlink--;
687                 if (doingdirectory) {
688                         if (--xp->i_nlink != 0)
689                                 panic("ext2_rename: linked directory");
690                         error = EXT2_TRUNCATE(tvp, (off_t)0, IO_SYNC,
691                                               tcnp->cn_cred);
692                 }
693                 xp->i_flag |= IN_CHANGE;
694                 vput(tvp);
695                 xp = NULL;
696         }
697
698         /*
699          * tvp and tdvp have been cleaned up.  The bad and out targets may
700          * not be used.  fvp and fdvp are ref'd but not locked.  ip
701          * still represents the old fvp and ip->i_flag may still have IN_RENAME
702          * set (if doingdirectory).
703          */
704
705         /*
706          * 3) Unlink the source.
707          *
708          * fdvp is locked and ref'd. ap->a_fvp holds the old lookup unlocked
709          * and ref'd, fvp will hold the new lookup locked and ref'd.
710          *
711          * After the relookup ap->a_fvp must be released as part of our
712          * cleanup, not just fdvp and fvp.  And, on success, fdvp and
713          * fvp will be locked so the bad and out targets cannot be used.
714          */
715         fcnp->cn_flags &= ~CNP_MODMASK;
716         fcnp->cn_flags |= CNP_LOCKPARENT;
717         KKASSERT(fcnp->cn_flags & CNP_PDIRUNLOCK);
718         error = relookup(fdvp, &fvp, fcnp);
719         if (error) {
720                 /*
721                  * From name has disappeared.
722                  */
723                 if (doingdirectory)
724                         panic("ext2_rename: lost dir entry");
725                 /* ip->i_flag only sets IN_RENAME if doingdirectory */
726                 vrele(ap->a_fvp);
727                 if (fcnp->cn_flags & CNP_PDIRUNLOCK)
728                         vrele(fdvp);
729                 else
730                         vput(fdvp);
731                 return (0);
732         }
733         KKASSERT((fcnp->cn_flags & CNP_PDIRUNLOCK) == 0);
734
735         /*
736          * This case shouldn't occur
737          */
738         if (fvp == NULL) {
739                 /*
740                  * From name has disappeared.
741                  */
742                 if (doingdirectory)
743                         panic("ext2_rename: lost dir entry");
744                 /* ip->i_flag only sets IN_RENAME if doingdirectory */
745                 vrele(ap->a_fvp);
746                 vput(fvp);
747                 vput(fdvp);
748                 return (0);
749         }
750
751         /*
752          * fvp and fdvp are both ref'd and locked.
753          */
754         xp = VTOI(fvp);
755         dp = VTOI(fdvp);
756
757         /*
758          * Ensure that the directory entry still exists and has not
759          * changed while the new name has been entered. If the source is
760          * a file then the entry may have been unlinked or renamed. In
761          * either case there is no further work to be done. If the source
762          * is a directory then it cannot have been rmdir'ed; its link
763          * count of three would cause a rmdir to fail with ENOTEMPTY.
764          * The IN_RENAME flag ensures that it cannot be moved by another
765          * rename.
766          */
767         if (xp != ip) {
768                 if (doingdirectory)
769                         panic("ext2_rename: lost dir entry");
770                 /* ip->i_flag only sets IN_RENAME if doingdirectory */
771         } else {
772                 /*
773                  * If the source is a directory with a
774                  * new parent, the link count of the old
775                  * parent directory must be decremented
776                  * and ".." set to point to the new parent.
777                  */
778                 if (doingdirectory && newparent) {
779                         dp->i_nlink--;
780                         dp->i_flag |= IN_CHANGE;
781                         error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
782                                         sizeof (struct dirtemplate), (off_t)0,
783                                         UIO_SYSSPACE, IO_NODELOCKED,
784                                         tcnp->cn_cred, NULL);
785                         if (error == 0) {
786                                 /* Like ext2 little-endian: */
787                                 namlen = dirbuf.dotdot_type;
788                                 if (namlen != 2 ||
789                                     dirbuf.dotdot_name[0] != '.' ||
790                                     dirbuf.dotdot_name[1] != '.') {
791                                         ext2_dirbad(xp, (doff_t)12,
792                                             "rename: mangled dir");
793                                 } else {
794                                         dirbuf.dotdot_ino = newparent;
795                                         vn_rdwr(UIO_WRITE, fvp,
796                                                 (caddr_t)&dirbuf,
797                                                 sizeof (struct dirtemplate),
798                                                 (off_t)0, UIO_SYSSPACE,
799                                                 IO_NODELOCKED|IO_SYNC,
800                                                 tcnp->cn_cred, NULL);
801                                 }
802                         }
803                 }
804                 error = ext2_dirremove(fdvp, fcnp);
805                 if (!error) {
806                         xp->i_nlink--;
807                         xp->i_flag |= IN_CHANGE;
808                 }
809                 xp->i_flag &= ~IN_RENAME;
810         }
811         vput(fdvp);
812         vput(fvp);
813         vrele(ap->a_fvp);
814         return (error);
815
816 bad:
817         if (xp)
818                 vput(ITOV(xp));
819         if (dp)
820                 vput(ITOV(dp));
821 out:
822         if (doingdirectory)
823                 ip->i_flag &= ~IN_RENAME;
824         if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
825                 ip->i_nlink--;
826                 ip->i_flag |= IN_CHANGE;
827                 ip->i_flag &= ~IN_RENAME;
828                 vput(fvp);
829         } else {
830                 vrele(fvp);
831         }
832         return (error);
833 }
834
835 /*
836  * Mkdir system call
837  *
838  * ext2_mkdir(struct vnode *a_dvp, struct vnode **a_vpp,
839  *            struct componentname *a_cnp, struct vattr *a_vap)
840  */
841 static int
842 ext2_mkdir(struct vop_old_mkdir_args *ap)
843 {
844         struct vnode *dvp = ap->a_dvp;
845         struct vattr *vap = ap->a_vap;
846         struct componentname *cnp = ap->a_cnp;
847         struct inode *ip, *dp;
848         struct vnode *tvp;
849         struct dirtemplate dirtemplate, *dtp;
850         int error, dmode;
851
852         dp = VTOI(dvp);
853         if ((nlink_t)dp->i_nlink >= LINK_MAX) {
854                 error = EMLINK;
855                 goto out;
856         }
857         dmode = vap->va_mode & 0777;
858         dmode |= IFDIR;
859         /*
860          * Must simulate part of ext2_makeinode here to acquire the inode,
861          * but not have it entered in the parent directory. The entry is
862          * made later after writing "." and ".." entries.
863          */
864         error = EXT2_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
865         if (error)
866                 goto out;
867         ip = VTOI(tvp);
868         ip->i_gid = dp->i_gid;
869 #ifdef SUIDDIR
870         {
871 #ifdef QUOTA
872                 struct ucred ucred, *ucp;
873                 ucp = cnp->cn_cred;
874 #endif
875                 /*
876                  * if we are hacking owners here, (only do this where told to)
877                  * and we are not giving it TOO root, (would subvert quotas)
878                  * then go ahead and give it to the other user.
879                  * The new directory also inherits the SUID bit. 
880                  * If user's UID and dir UID are the same,
881                  * 'give it away' so that the SUID is still forced on.
882                  */
883                 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
884                    (dp->i_mode & ISUID) && dp->i_uid) {
885                         dmode |= ISUID;
886                         ip->i_uid = dp->i_uid;
887 #ifdef QUOTA
888                         if (dp->i_uid != cnp->cn_cred->cr_uid) {
889                                 /*
890                                  * make sure the correct user gets charged
891                                  * for the space.
892                                  * Make a dummy credential for the victim.
893                                  * XXX This seems to never be accessed out of
894                                  * our context so a stack variable is ok.
895                                  */
896                                 ucred.cr_ref = 1;
897                                 ucred.cr_uid = ip->i_uid;
898                                 ucred.cr_ngroups = 1;
899                                 ucred.cr_groups[0] = dp->i_gid;
900                                 ucp = &ucred;
901                         }
902 #endif
903                 } else {
904                         ip->i_uid = cnp->cn_cred->cr_uid;
905                 }
906 #ifdef QUOTA
907                 if ((error = ext2_getinoquota(ip)) ||
908                 (error = ext2_chkiq(ip, 1, ucp, 0))) {
909                         EXT2_VFREE(tvp, ip->i_number, dmode);
910                         vput(tvp);
911                         return (error);
912                 }
913 #endif
914         }
915 #else
916         ip->i_uid = cnp->cn_cred->cr_uid;
917 #ifdef QUOTA
918         if ((error = ext2_getinoquota(ip)) ||
919             (error = ext2_chkiq(ip, 1, cnp->cn_cred, 0))) {
920                 EXT2_VFREE(tvp, ip->i_number, dmode);
921                 vput(tvp);
922                 return (error);
923         }
924 #endif
925 #endif
926         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
927         ip->i_mode = dmode;
928         tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
929         ip->i_nlink = 2;
930         if (cnp->cn_flags & CNP_ISWHITEOUT)
931                 ip->i_flags |= UF_OPAQUE;
932         error = EXT2_UPDATE(tvp, 1);
933
934         /*
935          * The vnode must have a VM object in order to issue buffer cache
936          * ops on it.
937          */
938         vinitvmio(tvp, 0, PAGE_SIZE, -1);
939
940         /*
941          * Bump link count in parent directory
942          * to reflect work done below.  Should
943          * be done before reference is created
944          * so reparation is possible if we crash.
945          */
946         dp->i_nlink++;
947         dp->i_flag |= IN_CHANGE;
948         error = EXT2_UPDATE(dvp, 1);
949         if (error)
950                 goto bad;
951
952         /* Initialize directory with "." and ".." from static template. */
953         if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es,
954             EXT2_FEATURE_INCOMPAT_FILETYPE))
955                 dtp = &ext2_mastertemplate;
956         else
957                 dtp = &ext2_omastertemplate;
958         dirtemplate = *dtp;
959         dirtemplate.dot_ino = ip->i_number;
960         dirtemplate.dotdot_ino = dp->i_number;
961         /* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE 
962          * so let's just redefine it - for this function only
963          */
964 #undef  DIRBLKSIZ 
965 #define DIRBLKSIZ  VTOI(dvp)->i_e2fs->s_blocksize
966         dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
967         error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
968                         sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
969                         IO_NODELOCKED|IO_SYNC, cnp->cn_cred, NULL);
970         if (error) {
971                 dp->i_nlink--;
972                 dp->i_flag |= IN_CHANGE;
973                 goto bad;
974         }
975         if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
976                 panic("ext2_mkdir: blksize"); /* XXX should grow with balloc() */
977         else {
978                 ip->i_size = DIRBLKSIZ;
979                 ip->i_flag |= IN_CHANGE;
980         }
981
982         /* Directory set up, now install its entry in the parent directory. */
983         error = ext2_direnter(ip, dvp, cnp);
984         if (error) {
985                 dp->i_nlink--;
986                 dp->i_flag |= IN_CHANGE;
987         }
988 bad:
989         /*
990          * No need to do an explicit VOP_TRUNCATE here, vrele will do this
991          * for us because we set the link count to 0.
992          */
993         if (error) {
994                 ip->i_nlink = 0;
995                 ip->i_flag |= IN_CHANGE;
996                 vput(tvp);
997         } else
998                 *ap->a_vpp = tvp;
999 out:
1000         return (error);
1001 #undef  DIRBLKSIZ
1002 #define DIRBLKSIZ  DEV_BSIZE
1003 }
1004
1005 /*
1006  * Rmdir system call.
1007  *
1008  * ext2_rmdir(struct vnode *a_dvp, struct vnode *a_vp,
1009  *            struct componentname *a_cnp)
1010  */
1011 static int
1012 ext2_rmdir(struct vop_old_rmdir_args *ap)
1013 {
1014         struct vnode *vp = ap->a_vp;
1015         struct vnode *dvp = ap->a_dvp;
1016         struct componentname *cnp = ap->a_cnp;
1017         struct inode *ip, *dp;
1018         int error;
1019
1020         ip = VTOI(vp);
1021         dp = VTOI(dvp);
1022
1023         /*
1024          * Verify the directory is empty (and valid).
1025          * (Rmdir ".." won't be valid since
1026          *  ".." will contain a reference to
1027          *  the current directory and thus be
1028          *  non-empty.)
1029          */
1030         error = 0;
1031         if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1032                 error = ENOTEMPTY;
1033                 goto out;
1034         }
1035         if ((dp->i_flags & APPEND)
1036             || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1037                 error = EPERM;
1038                 goto out;
1039         }
1040         /*
1041          * Delete reference to directory before purging
1042          * inode.  If we crash in between, the directory
1043          * will be reattached to lost+found,
1044          */
1045         error = ext2_dirremove(dvp, cnp);
1046         if (error)
1047                 goto out;
1048         dp->i_nlink--;
1049         dp->i_flag |= IN_CHANGE;
1050         vn_unlock(dvp);
1051         /*
1052          * Truncate inode.  The only stuff left
1053          * in the directory is "." and "..".  The
1054          * "." reference is inconsequential since
1055          * we're quashing it.  The ".." reference
1056          * has already been adjusted above.  We've
1057          * removed the "." reference and the reference
1058          * in the parent directory, but there may be
1059          * other hard links so decrement by 2 and
1060          * worry about them later.
1061          */
1062         ip->i_nlink -= 2;
1063         error = EXT2_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1064         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
1065 out:
1066         return (error);
1067 }
1068
1069 /*
1070  * symlink -- make a symbolic link
1071  *
1072  * ext2_symlink(struct vnode *a_dvp, struct vnode **a_vpp,
1073  *              struct componentname *a_cnp, struct vattr *a_vap,
1074  *              char *a_target)
1075  */
1076 static int
1077 ext2_symlink(struct vop_old_symlink_args *ap)
1078 {
1079         struct vnode *vp, **vpp = ap->a_vpp;
1080         struct inode *ip;
1081         int len, error;
1082
1083         error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1084             vpp, ap->a_cnp);
1085         if (error)
1086                 return (error);
1087         vp = *vpp;
1088         len = strlen(ap->a_target);
1089         if (len < vp->v_mount->mnt_maxsymlinklen) {
1090                 ip = VTOI(vp);
1091                 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1092                 ip->i_size = len;
1093                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1094         } else {
1095                 /*
1096                  * Make sure we have a VM object in order to use
1097                  * the buffer cache.
1098                  */
1099                 if (vp->v_object == NULL)
1100                         vinitvmio(vp, 0, PAGE_SIZE, -1);
1101
1102                 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1103                                 UIO_SYSSPACE, IO_NODELOCKED, 
1104                                 ap->a_cnp->cn_cred, NULL);
1105
1106                 if (error)
1107                         vput(vp);
1108         }
1109
1110         return (error);
1111 }
1112
1113 /*
1114  * Allocate a new inode.
1115  */
1116 static int
1117 ext2_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1118                struct componentname *cnp)
1119 {
1120         struct inode *ip, *pdir;
1121         struct vnode *tvp;
1122         int error;
1123
1124         pdir = VTOI(dvp);
1125         *vpp = NULL;
1126         if ((mode & IFMT) == 0)
1127                 mode |= IFREG;
1128
1129         error = EXT2_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
1130         if (error) {
1131                 return (error);
1132         }
1133         ip = VTOI(tvp);
1134         ip->i_gid = pdir->i_gid;
1135 #ifdef SUIDDIR
1136         {
1137 #ifdef QUOTA
1138                 struct ucred ucred, *ucp;
1139                 ucp = cnp->cn_cred;
1140 #endif
1141                 /*
1142                  * if we are
1143                  * not the owner of the directory,
1144                  * and we are hacking owners here, (only do this where told to)
1145                  * and we are not giving it TOO root, (would subvert quotas)
1146                  * then go ahead and give it to the other user.
1147                  * Note that this drops off the execute bits for security.
1148                  */
1149                 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
1150                      (pdir->i_mode & ISUID) &&
1151                      (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
1152                         ip->i_uid = pdir->i_uid;
1153                         mode &= ~07111;
1154 #ifdef QUOTA
1155                         /*
1156                          * make sure the correct user gets charged
1157                          * for the space.
1158                          * Quickly knock up a dummy credential for the victim.
1159                          * XXX This seems to never be accessed out of our
1160                          * context so a stack variable is ok.
1161                          */
1162                         ucred.cr_ref = 1;
1163                         ucred.cr_uid = ip->i_uid;
1164                         ucred.cr_ngroups = 1;
1165                         ucred.cr_groups[0] = pdir->i_gid;
1166                         ucp = &ucred;
1167 #endif
1168                 } else {
1169                         ip->i_uid = cnp->cn_cred->cr_uid;
1170                 }
1171         
1172 #ifdef QUOTA
1173                 if ((error = ext2_getinoquota(ip)) ||
1174                 (error = ext2_chkiq(ip, 1, ucp, 0))) {
1175                         EXT2_VFREE(tvp, ip->i_number, mode);
1176                         vput(tvp);
1177                         return (error);
1178                 }
1179 #endif
1180         }
1181 #else
1182         ip->i_uid = cnp->cn_cred->cr_uid;
1183 #ifdef QUOTA
1184         if ((error = ext2_getinoquota(ip)) ||
1185             (error = ext2_chkiq(ip, 1, cnp->cn_cred, 0))) {
1186                 EXT2_VFREE(tvp, ip->i_number, mode);
1187                 vput(tvp);
1188                 return (error);
1189         }
1190 #endif
1191 #endif
1192         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1193         ip->i_mode = mode;
1194         tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
1195         ip->i_nlink = 1;
1196         if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
1197             priv_check_cred(cnp->cn_cred, PRIV_VFS_SETGID, 0))
1198                 ip->i_mode &= ~ISGID;
1199
1200         if (cnp->cn_flags & CNP_ISWHITEOUT)
1201                 ip->i_flags |= UF_OPAQUE;
1202
1203         /*
1204          * Regular files and directories need VM objects.  Softlinks do 
1205          * not (not immediately anyway).
1206          */
1207         if (tvp->v_type == VREG || tvp->v_type == VDIR)
1208                 vinitvmio(tvp, 0, PAGE_SIZE, -1);
1209
1210         /*
1211          * Make sure inode goes to disk before directory entry.
1212          */
1213         error = EXT2_UPDATE(tvp, 1);
1214         if (error)
1215                 goto bad;
1216         error = ext2_direnter(ip, dvp, cnp);
1217         if (error)
1218                 goto bad;
1219
1220         *vpp = tvp;
1221         return (0);
1222
1223 bad:
1224         /*
1225          * Write error occurred trying to update the inode
1226          * or the directory so must deallocate the inode.
1227          */
1228         ip->i_nlink = 0;
1229         ip->i_flag |= IN_CHANGE;
1230         vput(tvp);
1231         return (error);
1232 }
1233
1234 void
1235 ext2_itimes(struct vnode *vp)
1236 {
1237         struct inode *ip;
1238         struct timespec ts;
1239
1240         ip = VTOI(vp);
1241         if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
1242                 return;
1243         if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
1244                 ip->i_flag |= IN_LAZYMOD;
1245         else
1246                 ip->i_flag |= IN_MODIFIED;
1247         if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
1248                 vfs_timestamp(&ts);
1249                 if (ip->i_flag & IN_ACCESS) {
1250                         ip->i_atime = ts.tv_sec;
1251                         ip->i_atimensec = ts.tv_nsec;
1252                 }
1253                 if (ip->i_flag & IN_UPDATE) {
1254                         ip->i_mtime = ts.tv_sec;
1255                         ip->i_mtimensec = ts.tv_nsec;
1256                         ip->i_modrev++;
1257                 }
1258                 if (ip->i_flag & IN_CHANGE) {
1259                         ip->i_ctime = ts.tv_sec;
1260                         ip->i_ctimensec = ts.tv_nsec;
1261                 }
1262         }
1263         ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
1264 }
1265
1266 /*
1267  * Open called.
1268  *
1269  * Nothing to do.
1270  *
1271  * ext2_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
1272  *           struct file *a_fp)
1273  */
1274 /* ARGSUSED */
1275 static
1276 int
1277 ext2_open(struct vop_open_args *ap)
1278 {
1279         struct vnode *vp = ap->a_vp;
1280
1281         /*
1282          * Files marked append-only must be opened for appending.
1283          */
1284         if ((VTOI(vp)->i_flags & APPEND) &&
1285             (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) {
1286                 return (EPERM);
1287         }
1288         return (vop_stdopen(ap));
1289 }
1290
1291 /*
1292  * Close called.
1293  *
1294  * Update the times on the inode.
1295  *
1296  * ext2_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred)
1297  */
1298 /* ARGSUSED */
1299 static
1300 int
1301 ext2_close(struct vop_close_args *ap)
1302 {
1303         struct vnode *vp = ap->a_vp;
1304
1305         if (vp->v_sysref.refcnt > 1)
1306                 ext2_itimes(vp);
1307         return (vop_stdclose(ap));
1308 }
1309
1310 /*
1311  * ext2_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred)
1312  */
1313 static
1314 int
1315 ext2_access(struct vop_access_args *ap)
1316 {
1317         struct vnode *vp = ap->a_vp;
1318         struct inode *ip = VTOI(vp);
1319         int error;
1320
1321 #ifdef QUOTA
1322         if (ap->a_mode & VWRITE) {
1323                 switch (vp->v_type) {
1324                 case VDIR:
1325                 case VLNK:
1326                 case VREG:
1327                         if ((error = ext2_getinoquota(ip)) != 0)
1328                                 return (error);
1329                         break;
1330                 default:
1331                         break;
1332                 }
1333         }
1334 #endif
1335
1336         error = vop_helper_access(ap, ip->i_uid, ip->i_gid, ip->i_mode,
1337                                   ip->i_flags);
1338         return (error);
1339 }
1340
1341 /*
1342  * ext2_getattr(struct vnode *a_vp, struct vattr *a_vap)
1343  */
1344 /* ARGSUSED */
1345 static
1346 int
1347 ext2_getattr(struct vop_getattr_args *ap)
1348 {
1349         struct vnode *vp = ap->a_vp;
1350         struct inode *ip = VTOI(vp);
1351         struct vattr *vap = ap->a_vap;
1352
1353         ext2_itimes(vp);
1354         /*
1355          * Copy from inode table
1356          */
1357         vap->va_fsid = dev2udev(ip->i_dev);
1358         vap->va_fileid = ip->i_number;
1359         vap->va_mode = ip->i_mode & ~IFMT;
1360         vap->va_nlink = VFSTOEXT2(vp->v_mount)->um_i_effnlink_valid ?
1361             ip->i_effnlink : ip->i_nlink;
1362         vap->va_uid = ip->i_uid;
1363         vap->va_gid = ip->i_gid;
1364         vap->va_rmajor = umajor(ip->i_rdev);
1365         vap->va_rminor = uminor(ip->i_rdev);
1366         vap->va_size = ip->i_din.di_size;
1367         vap->va_atime.tv_sec = ip->i_atime;
1368         vap->va_atime.tv_nsec = ip->i_atimensec;
1369         vap->va_mtime.tv_sec = ip->i_mtime;
1370         vap->va_mtime.tv_nsec = ip->i_mtimensec;
1371         vap->va_ctime.tv_sec = ip->i_ctime;
1372         vap->va_ctime.tv_nsec = ip->i_ctimensec;
1373         vap->va_flags = ip->i_flags;
1374         vap->va_gen = ip->i_gen;
1375         vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
1376         vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
1377         vap->va_type = IFTOVT(ip->i_mode);
1378         vap->va_filerev = ip->i_modrev;
1379         return (0);
1380 }
1381
1382 /*
1383  * Set attribute vnode op. called from several syscalls
1384  *
1385  * ext2_setattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred)
1386  */
1387 static
1388 int
1389 ext2_setattr(struct vop_setattr_args *ap)
1390 {
1391         struct vattr *vap = ap->a_vap;
1392         struct vnode *vp = ap->a_vp;
1393         struct inode *ip = VTOI(vp);
1394         struct ucred *cred = ap->a_cred;
1395         int error;
1396
1397         /*
1398          * Check for unsettable attributes.
1399          */
1400         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
1401             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
1402             (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) ||
1403             ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
1404                 return (EINVAL);
1405         }
1406         if (vap->va_flags != VNOVAL) {
1407                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
1408                         return (EROFS);
1409                 if (cred->cr_uid != ip->i_uid &&
1410                     (error = priv_check_cred(cred, PRIV_VFS_SETATTR, 0)))
1411                         return (error);
1412                 /*
1413                  * Note that a root chflags becomes a user chflags when
1414                  * we are jailed, unless the jail.chflags_allowed sysctl
1415                  * is set.
1416                  */
1417                 if (cred->cr_uid == 0 && 
1418                     (!jailed(cred) || jail_chflags_allowed)) {
1419                         if ((ip->i_flags
1420                             & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
1421                             securelevel > 0)
1422                                 return (EPERM);
1423                         ip->i_flags = vap->va_flags;
1424                 } else {
1425                         if (ip->i_flags
1426                             & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
1427                             (vap->va_flags & UF_SETTABLE) != vap->va_flags)
1428                                 return (EPERM);
1429                         ip->i_flags &= SF_SETTABLE;
1430                         ip->i_flags |= (vap->va_flags & UF_SETTABLE);
1431                 }
1432                 ip->i_flag |= IN_CHANGE;
1433                 if (vap->va_flags & (IMMUTABLE | APPEND))
1434                         return (0);
1435         }
1436         if (ip->i_flags & (IMMUTABLE | APPEND))
1437                 return (EPERM);
1438         /*
1439          * Go through the fields and update iff not VNOVAL.
1440          */
1441         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1442                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
1443                         return (EROFS);
1444                 if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred)) != 0)
1445                         return (error);
1446         }
1447         if (vap->va_size != VNOVAL) {
1448                 /*
1449                  * Disallow write attempts on read-only filesystems;
1450                  * unless the file is a socket, fifo, or a block or
1451                  * character device resident on the filesystem.
1452                  */
1453                 switch (vp->v_type) {
1454                 case VDIR:
1455                         return (EISDIR);
1456                 case VLNK:
1457                 case VREG:
1458                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
1459                                 return (EROFS);
1460                         break;
1461                 default:
1462                         break;
1463                 }
1464                 if ((error = EXT2_TRUNCATE(vp, vap->va_size, 0, cred)) != 0)
1465                         return (error);
1466         }
1467         ip = VTOI(vp);
1468         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
1469                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
1470                         return (EROFS);
1471                 if (cred->cr_uid != ip->i_uid &&
1472                     (error = priv_check_cred(cred, PRIV_VFS_SETATTR, 0)) &&
1473                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1474                     (error = VOP_EACCESS(vp, VWRITE, cred))))
1475                         return (error);
1476                 if (vap->va_atime.tv_sec != VNOVAL)
1477                         ip->i_flag |= IN_ACCESS;
1478                 if (vap->va_mtime.tv_sec != VNOVAL)
1479                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
1480                 ext2_itimes(vp);
1481                 if (vap->va_atime.tv_sec != VNOVAL) {
1482                         ip->i_atime = vap->va_atime.tv_sec;
1483                         ip->i_atimensec = vap->va_atime.tv_nsec;
1484                 }
1485                 if (vap->va_mtime.tv_sec != VNOVAL) {
1486                         ip->i_mtime = vap->va_mtime.tv_sec;
1487                         ip->i_mtimensec = vap->va_mtime.tv_nsec;
1488                 }
1489                 error = EXT2_UPDATE(vp, 0);
1490                 if (error)
1491                         return (error);
1492         }
1493         error = 0;
1494         if (vap->va_mode != (mode_t)VNOVAL) {
1495                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
1496                         return (EROFS);
1497                 error = ext2_chmod(vp, (int)vap->va_mode, cred);
1498         }
1499         VN_KNOTE(vp, NOTE_ATTRIB);
1500         return (error);
1501 }
1502
1503 /*
1504  * Change the mode on a file.
1505  * Inode must be locked before calling.
1506  */
1507 static int
1508 ext2_chmod(struct vnode *vp, int mode, struct ucred *cred)
1509 {
1510         struct inode *ip = VTOI(vp);
1511         int error;
1512
1513         if (cred->cr_uid != ip->i_uid) {
1514             error = priv_check_cred(cred, PRIV_VFS_CHMOD, 0);
1515             if (error)
1516                 return (error);
1517         }
1518         if (cred->cr_uid) {
1519                 if (vp->v_type != VDIR && (mode & S_ISTXT))
1520                         return (EFTYPE);
1521                 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
1522                         return (EPERM);
1523         }
1524         ip->i_mode &= ~ALLPERMS;
1525         ip->i_mode |= (mode & ALLPERMS);
1526         ip->i_flag |= IN_CHANGE;
1527         return (0);
1528 }
1529
1530 /*
1531  * Perform chown operation on inode ip;
1532  * inode must be locked prior to call.
1533  */
1534 static int
1535 ext2_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred)
1536 {
1537         struct inode *ip = VTOI(vp);
1538         uid_t ouid;
1539         gid_t ogid;
1540         int error = 0;
1541 #ifdef QUOTA
1542         int i;
1543         long change;
1544 #endif
1545
1546         if (uid == (uid_t)VNOVAL)
1547                 uid = ip->i_uid;
1548         if (gid == (gid_t)VNOVAL)
1549                 gid = ip->i_gid;
1550         /*
1551          * If we don't own the file, are trying to change the owner
1552          * of the file, or are not a member of the target group,
1553          * the caller must be superuser or the call fails.
1554          */
1555         if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
1556             (gid != ip->i_gid && !(cred->cr_gid == gid ||
1557             groupmember((gid_t)gid, cred)))) &&
1558             (error = priv_check_cred(cred, PRIV_VFS_CHOWN, 0)))
1559                 return (error);
1560         ogid = ip->i_gid;
1561         ouid = ip->i_uid;
1562 #ifdef QUOTA
1563         if ((error = ext2_getinoquota(ip)) != 0)
1564                 return (error);
1565         if (ouid == uid) {
1566                 ext2_dqrele(vp, ip->i_dquot[USRQUOTA]);
1567                 ip->i_dquot[USRQUOTA] = NODQUOT;
1568         }
1569         if (ogid == gid) {
1570                 ext2_dqrele(vp, ip->i_dquot[GRPQUOTA]);
1571                 ip->i_dquot[GRPQUOTA] = NODQUOT;
1572         }
1573         change = ip->i_blocks;
1574         (void) ext2_chkdq(ip, -change, cred, CHOWN);
1575         (void) ext2_chkiq(ip, -1, cred, CHOWN);
1576         for (i = 0; i < MAXQUOTAS; i++) {
1577                 ext2_dqrele(vp, ip->i_dquot[i]);
1578                 ip->i_dquot[i] = NODQUOT;
1579         }
1580 #endif
1581         ip->i_gid = gid;
1582         ip->i_uid = uid;
1583 #ifdef QUOTA
1584         if ((error = ext2_getinoquota(ip)) == 0) {
1585                 if (ouid == uid) {
1586                         ext2_dqrele(vp, ip->i_dquot[USRQUOTA]);
1587                         ip->i_dquot[USRQUOTA] = NODQUOT;
1588                 }
1589                 if (ogid == gid) {
1590                         ext2_dqrele(vp, ip->i_dquot[GRPQUOTA]);
1591                         ip->i_dquot[GRPQUOTA] = NODQUOT;
1592                 }
1593                 if ((error = ext2_chkdq(ip, change, cred, CHOWN)) == 0) {
1594                         if ((error = ext2_chkiq(ip, 1, cred, CHOWN)) == 0)
1595                                 goto good;
1596                         else
1597                                 (void)ext2_chkdq(ip, -change, cred, CHOWN|FORCE);
1598                 }
1599                 for (i = 0; i < MAXQUOTAS; i++) {
1600                         ext2_dqrele(vp, ip->i_dquot[i]);
1601                         ip->i_dquot[i] = NODQUOT;
1602                 }
1603         }
1604         ip->i_gid = ogid;
1605         ip->i_uid = ouid;
1606         if (ext2_getinoquota(ip) == 0) {
1607                 if (ouid == uid) {
1608                         ext2_dqrele(vp, ip->i_dquot[USRQUOTA]);
1609                         ip->i_dquot[USRQUOTA] = NODQUOT;
1610                 }
1611                 if (ogid == gid) {
1612                         ext2_dqrele(vp, ip->i_dquot[GRPQUOTA]);
1613                         ip->i_dquot[GRPQUOTA] = NODQUOT;
1614                 }
1615                 (void) ext2_chkdq(ip, change, cred, FORCE|CHOWN);
1616                 (void) ext2_chkiq(ip, 1, cred, FORCE|CHOWN);
1617                 (void) ext2_getinoquota(ip);
1618         }
1619         return (error);
1620 good:
1621         if (ext2_getinoquota(ip))
1622                 panic("ext2_chown: lost quota");
1623 #endif /* QUOTA */
1624         ip->i_flag |= IN_CHANGE;
1625         if (cred->cr_uid != 0 && (ouid != uid || ogid != gid))
1626                 ip->i_mode &= ~(ISUID | ISGID);
1627         return (0);
1628 }
1629
1630 /*
1631  * Mmap a file
1632  *
1633  * NB Currently unsupported.
1634  *
1635  * ext2_mmap(struct vnode *a_vp, int a_fflags, struct ucred *a_cred)
1636  */
1637 /* ARGSUSED */
1638 static
1639 int
1640 ext2_mmap(struct vop_mmap_args *ap)
1641 {
1642         return (EINVAL);
1643 }
1644
1645 /*
1646  * whiteout vnode call
1647  *
1648  * ext2_whiteout(struct vnode *a_dvp, struct componentname *a_cnp, int a_flags)
1649  */
1650 static
1651 int
1652 ext2_whiteout(struct vop_old_whiteout_args *ap)
1653 {
1654         return (EOPNOTSUPP);
1655 }
1656
1657 /*
1658  * Return target name of a symbolic link
1659  *
1660  * ext2_readlink(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred)
1661  */
1662 static
1663 int
1664 ext2_readlink(struct vop_readlink_args *ap)
1665 {
1666         struct vnode *vp = ap->a_vp;
1667         struct inode *ip = VTOI(vp);
1668         int isize;
1669
1670         isize = ip->i_size;
1671         if ((isize < vp->v_mount->mnt_maxsymlinklen) ||
1672             (ip->i_din.di_blocks == 0)) {   /* XXX - for old fastlink support */
1673                 uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
1674                 return (0);
1675         }
1676         return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1677 }
1678
1679 /*
1680  * Calculate the logical to physical mapping if not done already,
1681  * then call the device strategy routine.
1682  *
1683  * In order to be able to swap to a file, the VOP_BMAP operation may not
1684  * deadlock on memory.  See ext2_bmap() for details.
1685  *
1686  * ext2_strategy(struct vnode *a_vp, struct bio *a_bio)
1687  */
1688 static
1689 int
1690 ext2_strategy(struct vop_strategy_args *ap)
1691 {
1692         struct bio *bio = ap->a_bio;
1693         struct bio *nbio;
1694         struct buf *bp = bio->bio_buf;
1695         struct vnode *vp = ap->a_vp;
1696         struct inode *ip;
1697         int error;
1698
1699         ip = VTOI(vp);
1700         if (vp->v_type == VBLK || vp->v_type == VCHR)
1701                 panic("ext2_strategy: spec");
1702         nbio = push_bio(bio);
1703         if (nbio->bio_offset == NOOFFSET) {
1704                 error = VOP_BMAP(vp, bio->bio_offset, &nbio->bio_offset,
1705                                  NULL, NULL, bp->b_cmd);
1706                 if (error) {
1707                         bp->b_error = error;
1708                         bp->b_flags |= B_ERROR;
1709                         /* I/O was never started on nbio, must biodone(bio) */
1710                         biodone(bio);
1711                         return (error);
1712                 }
1713                 if (nbio->bio_offset == NOOFFSET)
1714                         vfs_bio_clrbuf(bp);
1715         }
1716         if (nbio->bio_offset == NOOFFSET) {
1717                 /* I/O was never started on nbio, must biodone(bio) */
1718                 biodone(bio);
1719                 return (0);
1720         }
1721         vn_strategy(ip->i_devvp, nbio);
1722         return (0);
1723 }
1724
1725 /*
1726  * Print out the contents of an inode.
1727  *
1728  * ext2_print(struct vnode *a_vp)
1729  */
1730 static
1731 int
1732 ext2_print(struct vop_print_args *ap)
1733 {
1734         struct vnode *vp = ap->a_vp;
1735         struct inode *ip = VTOI(vp);
1736
1737         kprintf("tag VT_EXT2FS, ino %lu, on dev %s (%d, %d)",
1738             (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev),
1739             minor(ip->i_dev));
1740         if (vp->v_type == VFIFO)
1741                 fifo_printinfo(vp);
1742         lockmgr_printinfo(&vp->v_lock);
1743         kprintf("\n");
1744         return (0);
1745 }
1746
1747 /*
1748  * Read wrapper for fifos.
1749  *
1750  * ext2fifo_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1751  *              struct ucred *a_cred)
1752  */
1753 static
1754 int
1755 ext2fifo_read(struct vop_read_args *ap)
1756 {
1757         int error, resid;
1758         struct inode *ip;
1759         struct uio *uio;
1760
1761         uio = ap->a_uio;
1762         resid = uio->uio_resid;
1763         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
1764         ip = VTOI(ap->a_vp);
1765         if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
1766             (uio->uio_resid != resid || (error == 0 && resid != 0)))
1767                 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1768         return (error);
1769 }
1770
1771 /*
1772  * Write wrapper for fifos.
1773  *
1774  * ext2fifo_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1775  *               struct ucred *a_cred)
1776  */
1777 static
1778 int
1779 ext2fifo_write(struct vop_write_args *ap)
1780 {
1781         int error, resid;
1782         struct inode *ip;
1783         struct uio *uio;
1784
1785         uio = ap->a_uio;
1786         resid = uio->uio_resid;
1787         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
1788         ip = VTOI(ap->a_vp);
1789         if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1790                 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1791         return (error);
1792 }
1793
1794 /*
1795  * Close wrapper for fifos.
1796  *
1797  * Update the times on the inode then do device close.
1798  *
1799  * ext2fifo_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred)
1800  */
1801 static
1802 int
1803 ext2fifo_close(struct vop_close_args *ap)
1804 {
1805         struct vnode *vp = ap->a_vp;
1806
1807         if (vp->v_sysref.refcnt > 1)
1808                 ext2_itimes(vp);
1809         return (VOCALL(&fifo_vnode_vops, &ap->a_head));
1810 }
1811
1812 /*
1813  * Kqfilter wrapper for fifos.
1814  *
1815  * Fall through to ext2 kqfilter routines if needed 
1816  */
1817 static
1818 int
1819 ext2fifo_kqfilter(struct vop_kqfilter_args *ap)
1820 {
1821         int error;
1822
1823         error = VOCALL(&fifo_vnode_vops, &ap->a_head);
1824         if (error)
1825                 error = ext2_kqfilter(ap);
1826         return (error);
1827 }
1828
1829 /*
1830  * Return POSIX pathconf information applicable to ext2 filesystems.
1831  *
1832  * ext2_pathconf(struct vnode *a_vp, int a_name, int *a_retval)
1833  */
1834 static
1835 int
1836 ext2_pathconf(struct vop_pathconf_args *ap)
1837 {
1838         switch (ap->a_name) {
1839         case _PC_LINK_MAX:
1840                 *ap->a_retval = LINK_MAX;
1841                 return (0);
1842         case _PC_NAME_MAX:
1843                 *ap->a_retval = NAME_MAX;
1844                 return (0);
1845         case _PC_PATH_MAX:
1846                 *ap->a_retval = PATH_MAX;
1847                 return (0);
1848         case _PC_PIPE_BUF:
1849                 *ap->a_retval = PIPE_BUF;
1850                 return (0);
1851         case _PC_CHOWN_RESTRICTED:
1852                 *ap->a_retval = 1;
1853                 return (0);
1854         case _PC_NO_TRUNC:
1855                 *ap->a_retval = 1;
1856                 return (0);
1857         default:
1858                 return (EINVAL);
1859         }
1860         /* NOTREACHED */
1861 }
1862
1863 /*
1864  * Advisory record locking support
1865  *
1866  * ext2_advlock(struct vnode *a_vp, caddr_t a_id, int a_op, struct flock *a_fl,
1867  *             int a_flags)
1868  */
1869 static
1870 int
1871 ext2_advlock(struct vop_advlock_args *ap)
1872 {
1873         struct inode *ip = VTOI(ap->a_vp);
1874
1875         return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
1876 }
1877
1878 /*
1879  * Initialize the vnode associated with a new inode, handle aliased
1880  * vnodes.
1881  */
1882 int
1883 ext2_vinit(struct mount *mntp, struct vnode **vpp)
1884 {
1885         struct inode *ip;
1886         struct vnode *vp;
1887         struct timeval tv;
1888
1889         vp = *vpp;
1890         ip = VTOI(vp);
1891
1892         switch(vp->v_type = IFTOVT(ip->i_mode)) {
1893         case VCHR:
1894         case VBLK:
1895                 vp->v_ops = &mntp->mnt_vn_spec_ops;
1896                 addaliasu(vp, umajor(ip->i_rdev), uminor(ip->i_rdev));
1897                 break;
1898         case VFIFO:
1899                 vp->v_ops = &mntp->mnt_vn_fifo_ops;
1900                 break;
1901         case VDIR:
1902         case VREG:
1903                 vinitvmio(vp, ip->i_size, PAGE_SIZE, -1); /* XXX */
1904                 break;
1905         case VLNK:
1906                 if ((ip->i_size >= vp->v_mount->mnt_maxsymlinklen) &&
1907                     ip->i_din.di_blocks != 0
1908                 ) {
1909                         vinitvmio(vp, ip->i_size, PAGE_SIZE, -1);
1910                 }
1911                 break;
1912         default:
1913                 break;
1914
1915         }
1916
1917         if (ip->i_number == ROOTINO)
1918                 vp->v_flag |= VROOT;
1919         /*
1920          * Initialize modrev times
1921          */
1922         getmicrouptime(&tv);
1923         SETHIGH(ip->i_modrev, tv.tv_sec);
1924         SETLOW(ip->i_modrev, tv.tv_usec * 4294);
1925         *vpp = vp;
1926         return (0);
1927 }
1928
1929 static struct filterops ext2read_filtops = 
1930         { FILTEROP_ISFD, NULL, filt_ext2detach, filt_ext2read };
1931 static struct filterops ext2write_filtops = 
1932         { FILTEROP_ISFD, NULL, filt_ext2detach, filt_ext2write };
1933 static struct filterops ext2vnode_filtops = 
1934         { FILTEROP_ISFD, NULL, filt_ext2detach, filt_ext2vnode };
1935
1936 /*
1937  * ext2_kqfilter(struct vnode *a_vp, struct knote *a_kn)
1938  */
1939 static int
1940 ext2_kqfilter(struct vop_kqfilter_args *ap)
1941 {
1942         struct vnode *vp = ap->a_vp;
1943         struct knote *kn = ap->a_kn;
1944
1945         switch (kn->kn_filter) {
1946         case EVFILT_READ:
1947                 kn->kn_fop = &ext2read_filtops;
1948                 break;
1949         case EVFILT_WRITE:
1950                 kn->kn_fop = &ext2write_filtops;
1951                 break;
1952         case EVFILT_VNODE:
1953                 kn->kn_fop = &ext2vnode_filtops;
1954                 break;
1955         default:
1956                 return (EOPNOTSUPP);
1957         }
1958
1959         kn->kn_hook = (caddr_t)vp;
1960
1961         /* XXX: kq token actually protects the list */
1962         lwkt_gettoken(&vp->v_token);
1963         knote_insert(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1964         lwkt_reltoken(&vp->v_token);
1965
1966         return (0);
1967 }
1968
1969 static void
1970 filt_ext2detach(struct knote *kn)
1971 {
1972         struct vnode *vp = (struct vnode *)kn->kn_hook;
1973
1974         lwkt_gettoken(&vp->v_token);
1975         knote_remove(&vp->v_pollinfo.vpi_kqinfo.ki_note, kn);
1976         lwkt_reltoken(&vp->v_token);
1977 }
1978
1979 /*ARGSUSED*/
1980 static int
1981 filt_ext2read(struct knote *kn, long hint)
1982 {
1983         struct vnode *vp = (struct vnode *)kn->kn_hook;
1984         struct inode *ip = VTOI(vp);
1985         off_t off;
1986
1987         /*
1988          * filesystem is gone, so set the EOF flag and schedule 
1989          * the knote for deletion.
1990          */
1991         if (hint == NOTE_REVOKE) {
1992                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1993                 return (1);
1994         }
1995         off = ip->i_size - kn->kn_fp->f_offset;
1996         kn->kn_data = (off < INTPTR_MAX) ? off : INTPTR_MAX;
1997         if (kn->kn_sfflags & NOTE_OLDAPI)
1998                 return(1);
1999         return (kn->kn_data != 0);
2000 }
2001
2002 /*ARGSUSED*/
2003 static int
2004 filt_ext2write(struct knote *kn, long hint)
2005 {
2006         /*
2007          * filesystem is gone, so set the EOF flag and schedule 
2008          * the knote for deletion.
2009          */
2010         if (hint == NOTE_REVOKE)
2011                 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
2012
2013         kn->kn_data = 0;
2014         return (1);
2015 }
2016
2017 static int
2018 filt_ext2vnode(struct knote *kn, long hint)
2019 {
2020         if (kn->kn_sfflags & hint)
2021                 kn->kn_fflags |= hint;
2022         if (hint == NOTE_REVOKE) {
2023                 kn->kn_flags |= EV_EOF;
2024                 return (1);
2025         }
2026         return (kn->kn_fflags != 0);
2027 }
2028
2029 struct vop_ops ext2_vnode_vops = {
2030         .vop_default =          vop_defaultop,
2031         .vop_fsync =            ext2_fsync,
2032         .vop_read =             ext2_read,
2033         .vop_reallocblks =      ext2_reallocblks,
2034         .vop_write =            ext2_write,
2035         .vop_access =           ext2_access,
2036         .vop_advlock =          ext2_advlock,
2037         .vop_bmap =             ext2_bmap,
2038         .vop_old_lookup =       ext2_lookup,
2039         .vop_close =            ext2_close,
2040         .vop_old_create =       ext2_create,
2041         .vop_getattr =          ext2_getattr,
2042         .vop_inactive =         ext2_inactive,
2043         .vop_old_link =         ext2_link,
2044         .vop_old_mkdir =        ext2_mkdir,
2045         .vop_old_mknod =        ext2_mknod,
2046         .vop_mmap =             ext2_mmap,
2047         .vop_open =             ext2_open,
2048         .vop_pathconf =         ext2_pathconf,
2049         .vop_kqfilter =         ext2_kqfilter,
2050         .vop_print =            ext2_print,
2051         .vop_readdir =          ext2_readdir,
2052         .vop_readlink =         ext2_readlink,
2053         .vop_reclaim =          ext2_reclaim,
2054         .vop_old_remove =       ext2_remove,
2055         .vop_old_rename =       ext2_rename,
2056         .vop_old_rmdir =        ext2_rmdir,
2057         .vop_setattr =          ext2_setattr,
2058         .vop_strategy =         ext2_strategy,
2059         .vop_old_symlink =      ext2_symlink,
2060         .vop_old_whiteout =     ext2_whiteout,
2061         .vop_getpages =         vop_stdgetpages,
2062         .vop_putpages =         vop_stdputpages
2063 };
2064
2065 struct vop_ops ext2_spec_vops = {
2066         .vop_default =          vop_defaultop,
2067         .vop_fsync =            ext2_fsync,
2068         .vop_access =           ext2_access,
2069         .vop_close =            ext2_close,
2070         .vop_getattr =          ext2_getattr,
2071         .vop_inactive =         ext2_inactive,
2072         .vop_print =            ext2_print,
2073         .vop_read =             vop_stdnoread,
2074         .vop_reclaim =          ext2_reclaim,
2075         .vop_setattr =          ext2_setattr,
2076         .vop_write =            vop_stdnowrite
2077 };
2078
2079 struct vop_ops ext2_fifo_vops = {
2080         .vop_default =          ext2_vnoperatefifo,
2081         .vop_fsync =            ext2_fsync,
2082         .vop_access =           ext2_access,
2083         .vop_close =            ext2fifo_close,
2084         .vop_getattr =          ext2_getattr,
2085         .vop_inactive =         ext2_inactive,
2086         .vop_kqfilter =         ext2fifo_kqfilter,
2087         .vop_print =            ext2_print,
2088         .vop_read =             ext2fifo_read,
2089         .vop_reclaim =          ext2_reclaim,
2090         .vop_setattr =          ext2_setattr,
2091         .vop_write =            ext2fifo_write
2092 };
2093
2094 VNODEOP_SET(ext2_vnode_vops);
2095 VNODEOP_SET(ext2_spec_vops);
2096 VNODEOP_SET(ext2_fifo_vops);
2097
2098 /*
2099  * ext2_vnoperate()
2100  */
2101 int
2102 ext2_vnoperate(struct vop_generic_args *ap)
2103 {
2104         return (VOCALL(&ext2_vnode_vops, ap));
2105 }
2106
2107 /*
2108  * ext2_vnoperatefifo()
2109  */
2110 int
2111 ext2_vnoperatefifo(struct vop_generic_args *ap)
2112 {
2113         return (VOCALL(&ext2_fifo_vops, ap));
2114 }
2115