From 46eb0d5bf03c88c29888c11a69f85895f02f12b0 Mon Sep 17 00:00:00 2001 From: jdolecek Date: Mon, 17 Mar 2003 09:11:29 +0000 Subject: [PATCH] make it possible for UNION fs to be loaded via LKM - instead of having some #ifdef UNION code in vfs_vnops.c, introduce variable 'vn_union_readdir_hook' which is set to address of appropriate vn_readdir() hook by union filesystem when it's loaded & mounted --- sys/fs/union/union.h | 3 ++- sys/fs/union/union_subr.c | 50 +++++++++++++++++++++++++++++++--- sys/fs/union/union_vfsops.c | 9 +++++-- sys/kern/vfs_vnops.c | 53 ++++++++++--------------------------- sys/sys/vnode.h | 7 ++++- 5 files changed, 76 insertions(+), 46 deletions(-) diff --git a/sys/fs/union/union.h b/sys/fs/union/union.h index 08d592bbf9b6..dfd76cd77e8b 100644 --- a/sys/fs/union/union.h +++ b/sys/fs/union/union.h @@ -1,4 +1,4 @@ -/* $NetBSD: union.h,v 1.1 2003/03/16 08:26:51 jdolecek Exp $ */ +/* $NetBSD: union.h,v 1.2 2003/03/17 09:11:30 jdolecek Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -122,6 +122,7 @@ extern struct vnode *union_lowervp __P((struct vnode *)); extern void union_newlower __P((struct union_node *, struct vnode *)); extern void union_newupper __P((struct union_node *, struct vnode *)); extern void union_newsize __P((struct vnode *, off_t, off_t)); +int union_readdirhook(struct vnode **, struct file *, struct proc *); #define MOUNTTOUNIONMOUNT(mp) ((struct union_mount *)((mp)->mnt_data)) #define VTOUNION(vp) ((struct union_node *)(vp)->v_data) diff --git a/sys/fs/union/union_subr.c b/sys/fs/union/union_subr.c index d1e38ea11e3d..e75735ac4f9e 100644 --- a/sys/fs/union/union_subr.c +++ b/sys/fs/union/union_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: union_subr.c,v 1.1 2003/03/16 08:26:52 jdolecek Exp $ */ +/* $NetBSD: union_subr.c,v 1.2 2003/03/17 09:11:30 jdolecek Exp $ */ /* * Copyright (c) 1994 Jan-Simon Pendry @@ -40,7 +40,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.1 2003/03/16 08:26:52 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.2 2003/03/17 09:11:30 jdolecek Exp $"); #include #include @@ -100,7 +100,9 @@ union_init() void union_done() { - /* Nothing */ + + /* Make sure to unset the readdir hook. */ + vn_union_readdir_hook = NULL; } static int @@ -1153,3 +1155,45 @@ union_diruncache(un) un->un_dircache = 0; } } + +/* + * This hook is called from vn_readdir() to switch to lower directory + * entry after the upper directory is read. + */ +int +union_readdirhook(struct vnode **vpp, struct file *fp, struct proc *p) +{ + struct vnode *vp = *vpp, *lvp; + struct vattr va; + int error; + + if (vp->v_op != union_vnodeop_p) + return (0); + + if ((lvp = union_dircache(vp, p)) == NULLVP) + return (0); + + /* + * If the directory is opaque, + * then don't show lower entries + */ + error = VOP_GETATTR(vp, &va, fp->f_cred, p); + if (error || (va.va_flags & OPAQUE)) { + vput(lvp); + return (error); + } + + error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); + if (error) { + vput(lvp); + return (error); + } + VOP_UNLOCK(lvp, 0); + fp->f_data = (caddr_t) lvp; + fp->f_offset = 0; + error = vn_close(vp, FREAD, fp->f_cred, p); + if (error) + return (error); + *vpp = lvp; + return (0); +} diff --git a/sys/fs/union/union_vfsops.c b/sys/fs/union/union_vfsops.c index e13f5d02edf7..5eb42a925726 100644 --- a/sys/fs/union/union_vfsops.c +++ b/sys/fs/union/union_vfsops.c @@ -1,4 +1,4 @@ -/* $NetBSD: union_vfsops.c,v 1.1 2003/03/16 08:26:54 jdolecek Exp $ */ +/* $NetBSD: union_vfsops.c,v 1.2 2003/03/17 09:11:31 jdolecek Exp $ */ /* * Copyright (c) 1994 The Regents of the University of California. @@ -44,7 +44,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: union_vfsops.c,v 1.1 2003/03/16 08:26:54 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_vfsops.c,v 1.2 2003/03/17 09:11:31 jdolecek Exp $"); #include #include @@ -259,6 +259,11 @@ union_mount(mp, path, data, ndp, p) printf("union_mount: from %s, on %s\n", mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname); #endif + + /* Setup the readdir hook if it's not set already */ + if (!vn_union_readdir_hook) + vn_union_readdir_hook = union_readdirhook; + return (0); bad: diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index c35adfceed54..6144238123f5 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_vnops.c,v 1.65 2003/03/16 08:26:48 jdolecek Exp $ */ +/* $NetBSD: vfs_vnops.c,v 1.66 2003/03/17 09:11:30 jdolecek Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -41,7 +41,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.65 2003/03/16 08:26:48 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.66 2003/03/17 09:11:30 jdolecek Exp $"); #include "fs_union.h" @@ -65,6 +65,10 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_vnops.c,v 1.65 2003/03/16 08:26:48 jdolecek Exp #include #endif +#if defined(LKM) || defined(UNION) +int (*vn_union_readdir_hook) (struct vnode **, struct file *, struct proc *); +#endif + #ifdef VERIFIED_EXEC #include @@ -440,46 +444,17 @@ unionread: if (error) return (error); -#ifdef UNION -{ - extern struct vnode *union_dircache __P((struct vnode *)); +#if defined(UNION) || defined(LKM) + if (count == auio.uio_resid && vn_union_readdir_hook) { + struct vnode *ovp = vp; - if (count == auio.uio_resid && (vp->v_op == union_vnodeop_p)) { - struct vnode *lvp; - - lvp = union_dircache(vp); - if (lvp != NULLVP) { - struct vattr va; - - /* - * If the directory is opaque, - * then don't show lower entries - */ - error = VOP_GETATTR(vp, &va, fp->f_cred, p); - if (va.va_flags & OPAQUE) { - vput(lvp); - lvp = NULL; - } - } - - if (lvp != NULLVP) { - error = VOP_OPEN(lvp, FREAD, fp->f_cred, p); - if (error) { - vput(lvp); - return (error); - } - VOP_UNLOCK(lvp, 0); - fp->f_data = (caddr_t) lvp; - fp->f_offset = 0; - error = vn_close(vp, FREAD, fp->f_cred, p); - if (error) - return (error); - vp = lvp; + error = (*vn_union_readdir_hook)(&vp, fp, p); + if (error) + return (error); + if (vp != ovp) goto unionread; - } } -} -#endif /* UNION */ +#endif /* UNION || LKM */ if (count == auio.uio_resid && (vp->v_flag & VROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) { diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 4020ab8ec7cc..a391b634fc6a 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1,4 +1,4 @@ -/* $NetBSD: vnode.h,v 1.105 2003/03/17 09:06:40 jdolecek Exp $ */ +/* $NetBSD: vnode.h,v 1.106 2003/03/17 09:11:29 jdolecek Exp $ */ /* * Copyright (c) 1989, 1993 @@ -440,6 +440,11 @@ extern struct vnodeop_desc *vnodeop_descs[]; */ extern struct simplelock mntvnode_slock; +/* + * Union filesystem hook for vn_readdir(). + */ +extern int (*vn_union_readdir_hook) (struct vnode **, struct file *, struct proc *); + /* * This macro is very helpful in defining those offsets in the vdesc struct. *