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