summaryrefslogtreecommitdiffstats
path: root/sys/gnu/ext2fs/ext2_vnops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/gnu/ext2fs/ext2_vnops.c')
-rw-r--r--sys/gnu/ext2fs/ext2_vnops.c1114
1 files changed, 996 insertions, 118 deletions
diff --git a/sys/gnu/ext2fs/ext2_vnops.c b/sys/gnu/ext2fs/ext2_vnops.c
index 180ac3d..ba7b714 100644
--- a/sys/gnu/ext2fs/ext2_vnops.c
+++ b/sys/gnu/ext2fs/ext2_vnops.c
@@ -46,34 +46,38 @@
* $FreeBSD$
*/
-#include "opt_quota.h"
#include "opt_suiddir.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/resourcevar.h>
#include <sys/kernel.h>
+#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/proc.h>
#include <sys/mount.h>
+#include <sys/unistd.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/namei.h>
+#include <sys/lockf.h>
+#include <sys/event.h>
+#include <sys/conf.h>
+#include <sys/file.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vnode_pager.h>
+#include <fs/fifofs/fifo.h>
+
#include <sys/signalvar.h>
#include <ufs/ufs/dir.h>
-#include <ufs/ufs/extattr.h>
-#include <ufs/ufs/quota.h>
-#include <ufs/ufs/inode.h>
-#include <ufs/ufs/ufsmount.h>
-#include <ufs/ufs/ufs_extern.h>
+#include <gnu/ext2fs/inode.h>
+#include <gnu/ext2fs/ext2_mount.h>
#include <gnu/ext2fs/ext2_fs_sb.h>
#include <gnu/ext2fs/fs.h>
#include <gnu/ext2fs/ext2_extern.h>
@@ -81,38 +85,81 @@
static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *);
+static int ext2_access(struct vop_access_args *);
+static int ext2_advlock(struct vop_advlock_args *);
+static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *);
+static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *,
+ struct thread *);
+static int ext2_close(struct vop_close_args *);
+static int ext2_create(struct vop_create_args *);
static int ext2_fsync(struct vop_fsync_args *);
+static int ext2_getattr(struct vop_getattr_args *);
+static int ext2_kqfilter(struct vop_kqfilter_args *ap);
+static int ext2_link(struct vop_link_args *);
+static int ext2_mkdir(struct vop_mkdir_args *);
+static int ext2_mknod(struct vop_mknod_args *);
+static int ext2_open(struct vop_open_args *);
+static int ext2_pathconf(struct vop_pathconf_args *);
+static int ext2_print(struct vop_print_args *);
static int ext2_read(struct vop_read_args *);
-static int ext2_write(struct vop_write_args *);
+static int ext2_readlink(struct vop_readlink_args *);
static int ext2_remove(struct vop_remove_args *);
-static int ext2_link(struct vop_link_args *);
static int ext2_rename(struct vop_rename_args *);
-static int ext2_mkdir(struct vop_mkdir_args *);
static int ext2_rmdir(struct vop_rmdir_args *);
-static int ext2_create(struct vop_create_args *);
-static int ext2_mknod(struct vop_mknod_args *);
+static int ext2_setattr(struct vop_setattr_args *);
+static int ext2_strategy(struct vop_strategy_args *);
static int ext2_symlink(struct vop_symlink_args *);
+static int ext2_write(struct vop_write_args *);
+static int ext2fifo_close(struct vop_close_args *);
+static int ext2fifo_kqfilter(struct vop_kqfilter_args *);
+static int ext2fifo_read(struct vop_read_args *);
+static int ext2fifo_write(struct vop_write_args *);
+static int ext2spec_close(struct vop_close_args *);
+static int ext2spec_read(struct vop_read_args *);
+static int ext2spec_write(struct vop_write_args *);
+static int filt_ext2read(struct knote *kn, long hint);
+static int filt_ext2write(struct knote *kn, long hint);
+static int filt_ext2vnode(struct knote *kn, long hint);
+static void filt_ext2detach(struct knote *kn);
-/* Global vfs data structures for ufs. */
+/* Global vfs data structures for ext2. */
vop_t **ext2_vnodeop_p;
static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = {
- { &vop_default_desc, (vop_t *) ufs_vnoperate },
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_access_desc, (vop_t *) ext2_access },
+ { &vop_advlock_desc, (vop_t *) ext2_advlock },
+ { &vop_bmap_desc, (vop_t *) ext2_bmap },
{ &vop_cachedlookup_desc, (vop_t *) ext2_lookup },
+ { &vop_close_desc, (vop_t *) ext2_close },
+ { &vop_create_desc, (vop_t *) ext2_create },
{ &vop_fsync_desc, (vop_t *) ext2_fsync },
+ { &vop_getattr_desc, (vop_t *) ext2_getattr },
+ { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount },
{ &vop_inactive_desc, (vop_t *) ext2_inactive },
+ { &vop_islocked_desc, (vop_t *) vop_stdislocked },
+ { &vop_link_desc, (vop_t *) ext2_link },
+ { &vop_lock_desc, (vop_t *) vop_stdlock },
{ &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
+ { &vop_mkdir_desc, (vop_t *) ext2_mkdir },
+ { &vop_mknod_desc, (vop_t *) ext2_mknod },
+ { &vop_open_desc, (vop_t *) ext2_open },
+ { &vop_pathconf_desc, (vop_t *) ext2_pathconf },
+ { &vop_poll_desc, (vop_t *) vop_stdpoll },
+ { &vop_kqfilter_desc, (vop_t *) ext2_kqfilter },
+ { &vop_print_desc, (vop_t *) ext2_print },
{ &vop_read_desc, (vop_t *) ext2_read },
{ &vop_readdir_desc, (vop_t *) ext2_readdir },
+ { &vop_readlink_desc, (vop_t *) ext2_readlink },
{ &vop_reallocblks_desc, (vop_t *) ext2_reallocblks },
- { &vop_write_desc, (vop_t *) ext2_write },
+ { &vop_reclaim_desc, (vop_t *) ext2_reclaim },
{ &vop_remove_desc, (vop_t *) ext2_remove },
- { &vop_link_desc, (vop_t *) ext2_link },
{ &vop_rename_desc, (vop_t *) ext2_rename },
- { &vop_mkdir_desc, (vop_t *) ext2_mkdir },
{ &vop_rmdir_desc, (vop_t *) ext2_rmdir },
- { &vop_create_desc, (vop_t *) ext2_create },
- { &vop_mknod_desc, (vop_t *) ext2_mknod },
+ { &vop_setattr_desc, (vop_t *) ext2_setattr },
+ { &vop_strategy_desc, (vop_t *) ext2_strategy },
{ &vop_symlink_desc, (vop_t *) ext2_symlink },
+ { &vop_unlock_desc, (vop_t *) vop_stdunlock },
+ { &vop_write_desc, (vop_t *) ext2_write },
{ NULL, NULL }
};
static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
@@ -120,9 +167,20 @@ static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
vop_t **ext2_specop_p;
static struct vnodeopv_entry_desc ext2_specop_entries[] = {
- { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
+ { &vop_default_desc, (vop_t *) spec_vnoperate },
+ { &vop_access_desc, (vop_t *) ext2_access },
+ { &vop_close_desc, (vop_t *) ext2spec_close },
{ &vop_fsync_desc, (vop_t *) ext2_fsync },
+ { &vop_getattr_desc, (vop_t *) ext2_getattr },
{ &vop_inactive_desc, (vop_t *) ext2_inactive },
+ { &vop_islocked_desc, (vop_t *) vop_stdislocked },
+ { &vop_lock_desc, (vop_t *) vop_stdlock },
+ { &vop_print_desc, (vop_t *) ext2_print },
+ { &vop_read_desc, (vop_t *) ext2spec_read },
+ { &vop_reclaim_desc, (vop_t *) ext2_reclaim },
+ { &vop_setattr_desc, (vop_t *) ext2_setattr },
+ { &vop_unlock_desc, (vop_t *) vop_stdunlock },
+ { &vop_write_desc, (vop_t *) ext2spec_write },
{ NULL, NULL }
};
static struct vnodeopv_desc ext2fs_specop_opv_desc =
@@ -130,9 +188,21 @@ static struct vnodeopv_desc ext2fs_specop_opv_desc =
vop_t **ext2_fifoop_p;
static struct vnodeopv_entry_desc ext2_fifoop_entries[] = {
- { &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
+ { &vop_default_desc, (vop_t *) fifo_vnoperate },
+ { &vop_access_desc, (vop_t *) ext2_access },
+ { &vop_close_desc, (vop_t *) ext2fifo_close },
{ &vop_fsync_desc, (vop_t *) ext2_fsync },
+ { &vop_getattr_desc, (vop_t *) ext2_getattr },
{ &vop_inactive_desc, (vop_t *) ext2_inactive },
+ { &vop_islocked_desc, (vop_t *) vop_stdislocked },
+ { &vop_kqfilter_desc, (vop_t *) ext2fifo_kqfilter },
+ { &vop_lock_desc, (vop_t *) vop_stdlock },
+ { &vop_print_desc, (vop_t *) ext2_print },
+ { &vop_read_desc, (vop_t *) ext2fifo_read },
+ { &vop_reclaim_desc, (vop_t *) ext2_reclaim },
+ { &vop_setattr_desc, (vop_t *) ext2_setattr },
+ { &vop_unlock_desc, (vop_t *) vop_stdunlock },
+ { &vop_write_desc, (vop_t *) ext2fifo_write },
{ NULL, NULL }
};
static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
@@ -144,9 +214,26 @@ static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
#include <gnu/ext2fs/ext2_readwrite.c>
+union _qcvt {
+ int64_t qcvt;
+ int32_t val[2];
+};
+#define SETHIGH(q, h) { \
+ union _qcvt tmp; \
+ tmp.qcvt = (q); \
+ tmp.val[_QUAD_HIGHWORD] = (h); \
+ (q) = tmp.qcvt; \
+}
+#define SETLOW(q, l) { \
+ union _qcvt tmp; \
+ tmp.qcvt = (q); \
+ tmp.val[_QUAD_LOWWORD] = (l); \
+ (q) = tmp.qcvt; \
+}
+
/*
* A virgin directory (no blushing please).
- * Note that the type and namlen fields are reversed relative to ufs.
+ * Note that the type and namlen fields are reversed relative to ext2.
* Also, we don't use `struct odirtemplate', since it would just cause
* endianness problems.
*/
@@ -159,6 +246,39 @@ static struct dirtemplate omastertemplate = {
0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".."
};
+void
+ext2_itimes(vp)
+ struct vnode *vp;
+{
+ struct inode *ip;
+ struct timespec ts;
+
+ ip = VTOI(vp);
+ if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
+ return;
+ if ((vp->v_type == VBLK || vp->v_type == VCHR))
+ ip->i_flag |= IN_LAZYMOD;
+ else
+ ip->i_flag |= IN_MODIFIED;
+ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
+ vfs_timestamp(&ts);
+ if (ip->i_flag & IN_ACCESS) {
+ ip->i_atime = ts.tv_sec;
+ ip->i_atimensec = ts.tv_nsec;
+ }
+ if (ip->i_flag & IN_UPDATE) {
+ ip->i_mtime = ts.tv_sec;
+ ip->i_mtimensec = ts.tv_nsec;
+ ip->i_modrev++;
+ }
+ if (ip->i_flag & IN_CHANGE) {
+ ip->i_ctime = ts.tv_sec;
+ ip->i_ctimensec = ts.tv_nsec;
+ }
+ }
+ ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
+}
+
/*
* Create a regular file
*/
@@ -182,6 +302,375 @@ ext2_create(ap)
}
/*
+ * Open called.
+ *
+ * Nothing to do.
+ */
+int
+ext2_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+
+ /*
+ * Files marked append-only must be opened for appending.
+ */
+ if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
+ (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
+ return (EPERM);
+ return (0);
+}
+
+/*
+ * Close called.
+ *
+ * Update the times on the inode.
+ */
+static int
+ext2_close(ap)
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct mount *mp;
+
+ mtx_lock(&vp->v_interlock);
+ if (vp->v_usecount > 1) {
+ ext2_itimes(vp);
+ mtx_unlock(&vp->v_interlock);
+ } else {
+ mtx_unlock(&vp->v_interlock);
+ /*
+ * If we are closing the last reference to an unlinked
+ * file, then it will be freed by the inactive routine.
+ * Because the freeing causes a the filesystem to be
+ * modified, it must be held up during periods when the
+ * filesystem is suspended.
+ *
+ * XXX - EAGAIN is returned to prevent vn_close from
+ * repeating the vrele operation.
+ */
+ if (vp->v_type == VREG && VTOI(vp)->i_nlink == 0) {
+ (void) vn_start_write(vp, &mp, V_WAIT);
+ vrele(vp);
+ vn_finished_write(mp);
+ return (EAGAIN);
+ }
+ }
+ return (0);
+}
+
+static int
+ext2_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+ mode_t mode = ap->a_mode;
+ int error;
+
+ /*
+ * Disallow write attempts on read-only file systems;
+ * unless the file is a socket, fifo, or a block or
+ * character device resident on the file system.
+ */
+ if (mode & VWRITE) {
+ switch (vp->v_type) {
+ case VDIR:
+ case VLNK:
+ case VREG:
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* If immutable bit set, nobody gets to write it. */
+ if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
+ return (EPERM);
+
+ error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid,
+ ap->a_mode, ap->a_cred, NULL);
+ return (error);
+}
+
+static int
+ext2_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+ struct vattr *vap = ap->a_vap;
+
+ ext2_itimes(vp);
+ /*
+ * Copy from inode table
+ */
+ vap->va_fsid = dev2udev(ip->i_dev);
+ vap->va_fileid = ip->i_number;
+ vap->va_mode = ip->i_mode & ~IFMT;
+ vap->va_nlink = ip->i_nlink;
+ vap->va_uid = ip->i_uid;
+ vap->va_gid = ip->i_gid;
+ vap->va_rdev = ip->i_rdev;
+ vap->va_size = ip->i_size;
+ vap->va_atime.tv_sec = ip->i_atime;
+ vap->va_atime.tv_nsec = ip->i_atimensec;
+ vap->va_mtime.tv_sec = ip->i_mtime;
+ vap->va_mtime.tv_nsec = ip->i_mtimensec;
+ vap->va_ctime.tv_sec = ip->i_ctime;
+ vap->va_ctime.tv_nsec = ip->i_ctimensec;
+ vap->va_flags = ip->i_flags;
+ vap->va_gen = ip->i_gen;
+ vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
+ vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
+ vap->va_type = IFTOVT(ip->i_mode);
+ vap->va_filerev = ip->i_modrev;
+ return (0);
+}
+
+/*
+ * Set attribute vnode op. called from several syscalls
+ */
+int
+ext2_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vattr *vap = ap->a_vap;
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+ struct ucred *cred = ap->a_cred;
+ struct thread *td = ap->a_td;
+ int error;
+
+ /*
+ * Check for unsettable attributes.
+ */
+ if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
+ (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
+ (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
+ ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+ return (EINVAL);
+ }
+ if (vap->va_flags != VNOVAL) {
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ /*
+ * Callers may only modify the file flags on objects they
+ * have VADMIN rights for.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+ return (error);
+ /*
+ * Unprivileged processes and privileged processes in
+ * jail() are not permitted to unset system flags, or
+ * modify flags if any system flags are set.
+ * Privileged non-jail processes may not modify system flags
+ * if securelevel > 0 and any existing system flags are set.
+ */
+ if (!suser_cred(cred, PRISON_ROOT)) {
+ if (ip->i_flags
+ & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) {
+ error = securelevel_gt(cred, 0);
+ if (error)
+ return (error);
+ }
+ ip->i_flags = vap->va_flags;
+ } else {
+ if (ip->i_flags
+ & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
+ (vap->va_flags & UF_SETTABLE) != vap->va_flags)
+ return (EPERM);
+ ip->i_flags &= SF_SETTABLE;
+ ip->i_flags |= (vap->va_flags & UF_SETTABLE);
+ }
+ ip->i_flag |= IN_CHANGE;
+ if (vap->va_flags & (IMMUTABLE | APPEND))
+ return (0);
+ }
+ if (ip->i_flags & (IMMUTABLE | APPEND))
+ return (EPERM);
+ /*
+ * Go through the fields and update iff not VNOVAL.
+ */
+ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred,
+ td)) != 0)
+ return (error);
+ }
+ if (vap->va_size != VNOVAL) {
+ /*
+ * Disallow write attempts on read-only file systems;
+ * unless the file is a socket, fifo, or a block or
+ * character device resident on the file system.
+ */
+ switch (vp->v_type) {
+ case VDIR:
+ return (EISDIR);
+ case VLNK:
+ case VREG:
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ break;
+ default:
+ break;
+ }
+ if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0)
+ return (error);
+ }
+ if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ /*
+ * From utimes(2):
+ * If times is NULL, ... The caller must be the owner of
+ * the file, have permission to write the file, or be the
+ * super-user.
+ * If times is non-NULL, ... The caller must be the owner of
+ * the file or be the super-user.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) &&
+ ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
+ (error = VOP_ACCESS(vp, VWRITE, cred, td))))
+ return (error);
+ if (vap->va_atime.tv_sec != VNOVAL)
+ ip->i_flag |= IN_ACCESS;
+ if (vap->va_mtime.tv_sec != VNOVAL)
+ ip->i_flag |= IN_CHANGE | IN_UPDATE;
+ ext2_itimes(vp);
+ if (vap->va_atime.tv_sec != VNOVAL) {
+ ip->i_atime = vap->va_atime.tv_sec;
+ ip->i_atimensec = vap->va_atime.tv_nsec;
+ }
+ if (vap->va_mtime.tv_sec != VNOVAL) {
+ ip->i_mtime = vap->va_mtime.tv_sec;
+ ip->i_mtimensec = vap->va_mtime.tv_nsec;
+ }
+ error = ext2_update(vp, 0);
+ if (error)
+ return (error);
+ }
+ error = 0;
+ if (vap->va_mode != (mode_t)VNOVAL) {
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ error = ext2_chmod(vp, (int)vap->va_mode, cred, td);
+ }
+ VN_KNOTE(vp, NOTE_ATTRIB);
+ return (error);
+}
+
+/*
+ * Change the mode on a file.
+ * Inode must be locked before calling.
+ */
+static int
+ext2_chmod(vp, mode, cred, td)
+ struct vnode *vp;
+ int mode;
+ struct ucred *cred;
+ struct thread *td;
+{
+ struct inode *ip = VTOI(vp);
+ int error;
+
+ /*
+ * To modify the permissions on a file, must possess VADMIN
+ * for that file.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+ return (error);
+ /*
+ * Privileged processes may set the sticky bit on non-directories,
+ * as well as set the setgid bit on a file with a group that the
+ * process is not a member of.
+ */
+ if (suser_cred(cred, PRISON_ROOT)) {
+ if (vp->v_type != VDIR && (mode & S_ISTXT))
+ return (EFTYPE);
+ if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
+ return (EPERM);
+ }
+ ip->i_mode &= ~ALLPERMS;
+ ip->i_mode |= (mode & ALLPERMS);
+ ip->i_flag |= IN_CHANGE;
+ return (0);
+}
+
+/*
+ * Perform chown operation on inode ip;
+ * inode must be locked prior to call.
+ */
+static int
+ext2_chown(vp, uid, gid, cred, td)
+ struct vnode *vp;
+ uid_t uid;
+ gid_t gid;
+ struct ucred *cred;
+ struct thread *td;
+{
+ struct inode *ip = VTOI(vp);
+ uid_t ouid;
+ gid_t ogid;
+ int error = 0;
+
+ if (uid == (uid_t)VNOVAL)
+ uid = ip->i_uid;
+ if (gid == (gid_t)VNOVAL)
+ gid = ip->i_gid;
+ /*
+ * To modify the ownership of a file, must possess VADMIN
+ * for that file.
+ */
+ if ((error = VOP_ACCESS(vp, VADMIN, cred, td)))
+ return (error);
+ /*
+ * To change the owner of a file, or change the group of a file
+ * to a group of which we are not a member, the caller must
+ * have privilege.
+ */
+ if ((uid != ip->i_uid ||
+ (gid != ip->i_gid && !groupmember(gid, cred))) &&
+ (error = suser_cred(cred, PRISON_ROOT)))
+ return (error);
+ ogid = ip->i_gid;
+ ouid = ip->i_uid;
+ ip->i_gid = gid;
+ ip->i_uid = uid;
+ ip->i_flag |= IN_CHANGE;
+ if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid))
+ ip->i_mode &= ~(ISUID | ISGID);
+ return (0);
+}
+
+/*
* Synch an open file.
*/
/* ARGSUSED */
@@ -241,7 +730,7 @@ loop:
#endif
}
splx(s);
- return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
+ return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT));
}
/*
@@ -341,7 +830,7 @@ ext2_link(ap)
#ifdef DIAGNOSTIC
if ((cnp->cn_flags & HASBUF) == 0)
- panic("ufs_link: no name");
+ panic("ext2_link: no name");
#endif
if (tdvp->v_mount != vp->v_mount) {
error = EXDEV;
@@ -361,7 +850,7 @@ ext2_link(ap)
}
ip->i_nlink++;
ip->i_flag |= IN_CHANGE;
- error = UFS_UPDATE(vp, 1);
+ error = ext2_update(vp, 1);
if (!error)
error = ext2_direnter(ip, tdvp, cnp);
if (error) {
@@ -406,7 +895,7 @@ ext2_rename(ap)
#ifdef DIAGNOSTIC
if ((tcnp->cn_flags & HASBUF) == 0 ||
(fcnp->cn_flags & HASBUF) == 0)
- panic("ufs_rename: no name");
+ panic("ext2_rename: no name");
#endif
/*
* Check for cross-device rename.
@@ -447,7 +936,7 @@ abortit:
* completed before the lookup.
*/
#ifdef UFS_RENAME_DEBUG
- printf("ufs_rename: fvp == tvp for directories\n");
+ printf("ext2_rename: fvp == tvp for directories\n");
#endif
error = ENOENT;
goto abortit;
@@ -474,7 +963,7 @@ abortit:
vrele(fdvp);
if (fvp == NULL) {
#ifdef UFS_RENAME_DEBUG
- printf("ufs_rename: from name disappeared\n");
+ printf("ext2_rename: from name disappeared\n");
#endif
return (ENOENT);
}
@@ -536,7 +1025,7 @@ abortit:
*/
ip->i_nlink++;
ip->i_flag |= IN_CHANGE;
- if ((error = UFS_UPDATE(fvp, 1)) != 0) {
+ if ((error = ext2_update(fvp, 1)) != 0) {
VOP_UNLOCK(fvp, 0, td);
goto bad;
}
@@ -582,7 +1071,7 @@ abortit:
*/
if (xp == NULL) {
if (dp->i_dev != ip->i_dev)
- panic("ufs_rename: EXDEV");
+ panic("ext2_rename: EXDEV");
/*
* Account for ".." in new directory.
* When source and destination have the same
@@ -595,7 +1084,7 @@ abortit:
}
dp->i_nlink++;
dp->i_flag |= IN_CHANGE;
- error = UFS_UPDATE(tdvp, 1);
+ error = ext2_update(tdvp, 1);
if (error)
goto bad;
}
@@ -604,19 +1093,19 @@ abortit:
if (doingdirectory && newparent) {
dp->i_nlink--;
dp->i_flag |= IN_CHANGE;
- (void)UFS_UPDATE(tdvp, 1);
+ (void)ext2_update(tdvp, 1);
}
goto bad;
}
vput(tdvp);
} else {
if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
- panic("ufs_rename: EXDEV");
+ panic("ext2_rename: EXDEV");
/*
* Short circuit rename(foo, foo).
*/
if (xp->i_number == ip->i_number)
- panic("ufs_rename: same file");
+ panic("ext2_rename: same file");
/*
* If the parent directory is "sticky", then the user must
* own the parent directory, or the destination of the rename,
@@ -676,8 +1165,8 @@ abortit:
xp->i_nlink--;
if (doingdirectory) {
if (--xp->i_nlink != 0)
- panic("ufs_rename: linked directory");
- error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
+ panic("ext2_rename: linked directory");
+ error = ext2_truncate(tvp, (off_t)0, IO_SYNC,
tcnp->cn_cred, tcnp->cn_thread);
}
xp->i_flag |= IN_CHANGE;
@@ -702,7 +1191,7 @@ abortit:
* From name has disappeared.
*/
if (doingdirectory)
- panic("ufs_rename: lost dir entry");
+ panic("ext2_rename: lost dir entry");
vrele(ap->a_fvp);
return (0);
}
@@ -718,7 +1207,7 @@ abortit:
*/
if (xp != ip) {
if (doingdirectory)
- panic("ufs_rename: lost dir entry");
+ panic("ext2_rename: lost dir entry");
} else {
/*
* If the source is a directory with a
@@ -739,7 +1228,7 @@ abortit:
if (namlen != 2 ||
dirbuf.dotdot_name[0] != '.' ||
dirbuf.dotdot_name[1] != '.') {
- ufs_dirbad(xp, (doff_t)12,
+ ext2_dirbad(xp, (doff_t)12,
"rename: mangled dir");
} else {
dirbuf.dotdot_ino = newparent;
@@ -807,7 +1296,7 @@ ext2_mkdir(ap)
#ifdef DIAGNOSTIC
if ((cnp->cn_flags & HASBUF) == 0)
- panic("ufs_mkdir: no name");
+ panic("ext2_mkdir: no name");
#endif
dp = VTOI(dvp);
if ((nlink_t)dp->i_nlink >= LINK_MAX) {
@@ -821,17 +1310,13 @@ ext2_mkdir(ap)
* but not have it entered in the parent directory. The entry is
* made later after writing "." and ".." entries.
*/
- error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
+ error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp);
if (error)
goto out;
ip = VTOI(tvp);
ip->i_gid = dp->i_gid;
#ifdef SUIDDIR
{
-#ifdef QUOTA
- struct ucred ucred, *ucp;
- ucp = cnp->cn_cred;
-#endif
/*
* if we are hacking owners here, (only do this where told to)
* and we are not giving it TOO root, (would subvert quotas)
@@ -844,44 +1329,12 @@ ext2_mkdir(ap)
(dp->i_mode & ISUID) && dp->i_uid) {
dmode |= ISUID;
ip->i_uid = dp->i_uid;
-#ifdef QUOTA
- if (dp->i_uid != cnp->cn_cred->cr_uid) {
- /*
- * make sure the correct user gets charged
- * for the space.
- * Make a dummy credential for the victim.
- * XXX This seems to never be accessed out of
- * our context so a stack variable is ok.
- */
- ucred.cr_ref = 1;
- ucred.cr_uid = ip->i_uid;
- ucred.cr_ngroups = 1;
- ucred.cr_groups[0] = dp->i_gid;
- ucp = &ucred;
- }
-#endif
} else {
ip->i_uid = cnp->cn_cred->cr_uid;
}
-#ifdef QUOTA
- if ((error = getinoquota(ip)) ||
- (error = chkiq(ip, 1, ucp, 0))) {
- UFS_VFREE(tvp, ip->i_number, dmode);
- vput(tvp);
- return (error);
- }
-#endif
}
#else
ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
- if ((error = getinoquota(ip)) ||
- (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
- UFS_VFREE(tvp, ip->i_number, dmode);
- vput(tvp);
- return (error);
- }
-#endif
#endif
ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
ip->i_mode = dmode;
@@ -889,7 +1342,7 @@ ext2_mkdir(ap)
ip->i_nlink = 2;
if (cnp->cn_flags & ISWHITEOUT)
ip->i_flags |= UF_OPAQUE;
- error = UFS_UPDATE(tvp, 1);
+ error = ext2_update(tvp, 1);
/*
* Bump link count in parent directory
@@ -899,7 +1352,7 @@ ext2_mkdir(ap)
*/
dp->i_nlink++;
dp->i_flag |= IN_CHANGE;
- error = UFS_UPDATE(dvp, 1);
+ error = ext2_update(dvp, 1);
if (error)
goto bad;
@@ -926,8 +1379,9 @@ ext2_mkdir(ap)
dp->i_flag |= IN_CHANGE;
goto bad;
}
- if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
- panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
+ if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
+ /* XXX should grow with balloc() */
+ panic("ext2_mkdir: blksize");
else {
ip->i_size = DIRBLKSIZ;
ip->i_flag |= IN_CHANGE;
@@ -1018,7 +1472,7 @@ ext2_rmdir(ap)
* worry about them later.
*/
ip->i_nlink -= 2;
- error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
+ error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td);
cache_purge(ITOV(ip));
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
out:
@@ -1063,6 +1517,362 @@ ext2_symlink(ap)
}
/*
+ * Return target name of a symbolic link
+ */
+static int
+ext2_readlink(ap)
+ struct vop_readlink_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+ int isize;
+
+ isize = ip->i_size;
+ if (isize < vp->v_mount->mnt_maxsymlinklen) {
+ uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
+ return (0);
+ }
+ return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
+}
+
+/*
+ * Calculate the logical to physical mapping if not done already,
+ * then call the device strategy routine.
+ *
+ * In order to be able to swap to a file, the ext2_bmaparray() operation may not
+ * deadlock on memory. See ext2_bmap() for details.
+ */
+int
+ext2_strategy(ap)
+ struct vop_strategy_args /* {
+ struct vnode *a_vp;
+ struct buf *a_bp;
+ } */ *ap;
+{
+ struct buf *bp = ap->a_bp;
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip;
+ daddr_t blkno;
+ int error;
+
+ ip = VTOI(vp);
+ if (vp->v_type == VBLK || vp->v_type == VCHR)
+ panic("ext2_strategy: spec");
+ if (bp->b_blkno == bp->b_lblkno) {
+ error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL);
+ bp->b_blkno = blkno;
+ if (error) {
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ bufdone(bp);
+ return (error);
+ }
+ if ((long)bp->b_blkno == -1)
+ vfs_bio_clrbuf(bp);
+ }
+ if ((long)bp->b_blkno == -1) {
+ bufdone(bp);
+ return (0);
+ }
+ vp = ip->i_devvp;
+ bp->b_dev = vp->v_rdev;
+ VOP_STRATEGY(vp, bp);
+ return (0);
+}
+
+/*
+ * Print out the contents of an inode.
+ */
+int
+ext2_print(ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct inode *ip = VTOI(vp);
+
+ printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)",
+ (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev),
+ minor(ip->i_dev));
+ if (vp->v_type == VFIFO)
+ fifo_printinfo(vp);
+ lockmgr_printinfo(&vp->v_lock);
+ printf("\n");
+ return (0);
+}
+
+/*
+ * Read wrapper for special devices.
+ */
+int
+ext2spec_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error, resid;
+ struct inode *ip;
+ struct uio *uio;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
+ /*
+ * The inode may have been revoked during the call, so it must not
+ * be accessed blindly here or in the other wrapper functions.
+ */
+ ip = VTOI(ap->a_vp);
+ if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+ ip->i_flag |= IN_ACCESS;
+ return (error);
+}
+
+/*
+ * Write wrapper for special devices.
+ */
+int
+ext2spec_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error, resid;
+ struct inode *ip;
+ struct uio *uio;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
+ ip = VTOI(ap->a_vp);
+ if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+ VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+ return (error);
+}
+
+/*
+ * Close wrapper for special devices.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2spec_close(ap)
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ mtx_lock(&vp->v_interlock);
+ if (vp->v_usecount > 1)
+ ext2_itimes(vp);
+ mtx_unlock(&vp->v_interlock);
+ return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Read wrapper for fifos.
+ */
+int
+ext2fifo_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error, resid;
+ struct inode *ip;
+ struct uio *uio;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
+ ip = VTOI(ap->a_vp);
+ if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
+ (uio->uio_resid != resid || (error == 0 && resid != 0)))
+ VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
+ return (error);
+}
+
+/*
+ * Write wrapper for fifos.
+ */
+int
+ext2fifo_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error, resid;
+ struct inode *ip;
+ struct uio *uio;
+
+ uio = ap->a_uio;
+ resid = uio->uio_resid;
+ error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
+ ip = VTOI(ap->a_vp);
+ if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
+ VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
+ return (error);
+}
+
+/*
+ * Close wrapper for fifos.
+ *
+ * Update the times on the inode then do device close.
+ */
+int
+ext2fifo_close(ap)
+ struct vop_close_args /* {
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct thread *a_td;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ mtx_lock(&vp->v_interlock);
+ if (vp->v_usecount > 1)
+ ext2_itimes(vp);
+ mtx_unlock(&vp->v_interlock);
+ return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
+}
+
+/*
+ * Kqfilter wrapper for fifos.
+ *
+ * Fall through to ext2 kqfilter routines if needed
+ */
+int
+ext2fifo_kqfilter(ap)
+ struct vop_kqfilter_args *ap;
+{
+ int error;
+
+ error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap);
+ if (error)
+ error = ext2_kqfilter(ap);
+ return (error);
+}
+
+/*
+ * Return POSIX pathconf information applicable to ext2 filesystems.
+ */
+int
+ext2_pathconf(ap)
+ struct vop_pathconf_args /* {
+ struct vnode *a_vp;
+ int a_name;
+ int *a_retval;
+ } */ *ap;
+{
+
+ switch (ap->a_name) {
+ case _PC_LINK_MAX:
+ *ap->a_retval = LINK_MAX;
+ return (0);
+ case _PC_NAME_MAX:
+ *ap->a_retval = NAME_MAX;
+ return (0);
+ case _PC_PATH_MAX:
+ *ap->a_retval = PATH_MAX;
+ return (0);
+ case _PC_PIPE_BUF:
+ *ap->a_retval = PIPE_BUF;
+ return (0);
+ case _PC_CHOWN_RESTRICTED:
+ *ap->a_retval = 1;
+ return (0);
+ case _PC_NO_TRUNC:
+ *ap->a_retval = 1;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Advisory record locking support
+ */
+static int
+ext2_advlock(ap)
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap;
+{
+ struct inode *ip = VTOI(ap->a_vp);
+
+ return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
+}
+
+/*
+ * Initialize the vnode associated with a new inode, handle aliased
+ * vnodes.
+ */
+int
+ext2_vinit(mntp, specops, fifoops, vpp)
+ struct mount *mntp;
+ vop_t **specops;
+ vop_t **fifoops;
+ struct vnode **vpp;
+{
+ struct inode *ip;
+ struct vnode *vp;
+ struct timeval tv;
+
+ vp = *vpp;
+ ip = VTOI(vp);
+ switch(vp->v_type = IFTOVT(ip->i_mode)) {
+ case VCHR:
+ case VBLK:
+ vp->v_op = specops;
+ vp = addaliasu(vp, ip->i_rdev);
+ ip->i_vnode = vp;
+ break;
+ case VFIFO:
+ vp->v_op = fifoops;
+ break;
+ default:
+ break;
+
+ }
+ if (ip->i_number == ROOTINO)
+ vp->v_flag |= VROOT;
+ /*
+ * Initialize modrev times
+ */
+ getmicrouptime(&tv);
+ SETHIGH(ip->i_modrev, tv.tv_sec);
+ SETLOW(ip->i_modrev, tv.tv_usec * 4294);
+ *vpp = vp;
+ return (0);
+}
+
+/*
* Allocate a new inode.
*/
static int
@@ -1085,7 +1895,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
if ((mode & IFMT) == 0)
mode |= IFREG;
- error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
+ error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp);
if (error) {
return (error);
}
@@ -1093,10 +1903,6 @@ ext2_makeinode(mode, dvp, vpp, cnp)
ip->i_gid = pdir->i_gid;
#ifdef SUIDDIR
{
-#ifdef QUOTA
- struct ucred ucred, *ucp;
- ucp = cnp->cn_cred;
-#endif
/*
* if we are
* not the owner of the directory,
@@ -1110,43 +1916,12 @@ ext2_makeinode(mode, dvp, vpp, cnp)
(pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
ip->i_uid = pdir->i_uid;
mode &= ~07111;
-#ifdef QUOTA
- /*
- * make sure the correct user gets charged
- * for the space.
- * Quickly knock up a dummy credential for the victim.
- * XXX This seems to never be accessed out of our
- * context so a stack variable is ok.
- */
- ucred.cr_ref = 1;
- ucred.cr_uid = ip->i_uid;
- ucred.cr_ngroups = 1;
- ucred.cr_groups[0] = pdir->i_gid;
- ucp = &ucred;
-#endif
} else {
ip->i_uid = cnp->cn_cred->cr_uid;
}
-
-#ifdef QUOTA
- if ((error = getinoquota(ip)) ||
- (error = chkiq(ip, 1, ucp, 0))) {
- UFS_VFREE(tvp, ip->i_number, mode);
- vput(tvp);
- return (error);
- }
-#endif
}
#else
ip->i_uid = cnp->cn_cred->cr_uid;
-#ifdef QUOTA
- if ((error = getinoquota(ip)) ||
- (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
- UFS_VFREE(tvp, ip->i_number, mode);
- vput(tvp);
- return (error);
- }
-#endif
#endif
ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
ip->i_mode = mode;
@@ -1162,7 +1937,7 @@ ext2_makeinode(mode, dvp, vpp, cnp)
/*
* Make sure inode goes to disk before directory entry.
*/
- error = UFS_UPDATE(tvp, 1);
+ error = ext2_update(tvp, 1);
if (error)
goto bad;
error = ext2_direnter(ip, dvp, cnp);
@@ -1182,3 +1957,106 @@ bad:
vput(tvp);
return (error);
}
+
+static struct filterops ext2read_filtops =
+ { 1, NULL, filt_ext2detach, filt_ext2read };
+static struct filterops ext2write_filtops =
+ { 1, NULL, filt_ext2detach, filt_ext2write };
+static struct filterops ext2vnode_filtops =
+ { 1, NULL, filt_ext2detach, filt_ext2vnode };
+
+static int
+ext2_kqfilter(ap)
+ struct vop_kqfilter_args /* {
+ struct vnode *a_vp;
+ struct knote *a_kn;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct knote *kn = ap->a_kn;
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ kn->kn_fop = &ext2read_filtops;
+ break;
+ case EVFILT_WRITE:
+ kn->kn_fop = &ext2write_filtops;
+ break;
+ case EVFILT_VNODE:
+ kn->kn_fop = &ext2vnode_filtops;
+ break;
+ default:
+ return (1);
+ }
+
+ kn->kn_hook = (caddr_t)vp;
+
+ if (vp->v_pollinfo == NULL)
+ v_addpollinfo(vp);
+ mtx_lock(&vp->v_pollinfo->vpi_lock);
+ SLIST_INSERT_HEAD(&vp->v_pollinfo->vpi_selinfo.si_note, kn, kn_selnext);
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+
+ return (0);
+}
+
+static void
+filt_ext2detach(struct knote *kn)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_hook;
+
+ KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo"));
+ mtx_lock(&vp->v_pollinfo->vpi_lock);
+ SLIST_REMOVE(&vp->v_pollinfo->vpi_selinfo.si_note,
+ kn, knote, kn_selnext);
+ mtx_unlock(&vp->v_pollinfo->vpi_lock);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2read(struct knote *kn, long hint)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_hook;
+ struct inode *ip = VTOI(vp);
+
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ if (hint == NOTE_REVOKE) {
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ return (1);
+ }
+
+ kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
+ return (kn->kn_data != 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_ext2write(struct knote *kn, long hint)
+{
+
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ if (hint == NOTE_REVOKE)
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+
+ kn->kn_data = 0;
+ return (1);
+}
+
+static int
+filt_ext2vnode(struct knote *kn, long hint)
+{
+
+ if (kn->kn_sfflags & hint)
+ kn->kn_fflags |= hint;
+ if (hint == NOTE_REVOKE) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ return (kn->kn_fflags != 0);
+}
OpenPOWER on IntegriCloud