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