Project

General

Profile

Bug #129 » ncc3-null.diff

csaba.henk, 03/29/2006 10:02 AM

View differences:

sys/vfs/nullfs/null.h Sun Mar 26 07:56:54 2006 +0000 → sys/vfs/nullfs/null.h Wed Mar 29 10:29:08 2006 +0200
};
struct null_mount {
struct mount *nullm_vfs;
struct vnode *nullm_rootvp; /* Reference to root null_node */
struct namecache *nullm_ncp;
};
#ifdef _KERNEL
#define MOUNTTONULLMOUNT(mp) ((struct null_mount *)((mp)->mnt_data))
#ifdef NULLFS_DEBUG
#define NULLFSDEBUG(format, args...) printf(format ,## args)
#define NULLFSDEBUG(format, args...) \
printf(" [nullfs] %s:%d: " format, __func__, __LINE__, ## args)
#define NULLNCDEBUG(ncp) \
NULLFSDEBUG(#ncp " %p: name %s, refs %d, exlocks %d, nc_flag 0x%x, " \
"nc_mount %p, nc_shadowed %p, nc_shadowinfo %p, " \
"nc_shadowheight %d, nc_vp %p\n", \
(ncp), (ncp)->nc_name, (ncp)->nc_refs, \
(ncp)->nc_shadowinfo->sh_exlocks, (ncp)->nc_flag, \
(ncp)->nc_mount, (ncp)->nc_shadowed, \
(ncp)->nc_shadowinfo, (ncp)->nc_shadowheight, (ncp)->nc_vp)
#else
#define NULLFSDEBUG(format, args...)
#define NULLNCDEBUG(ncp)
#endif /* NULLFS_DEBUG */
#endif /* _KERNEL */
sys/vfs/nullfs/null_vfsops.c Sun Mar 26 07:56:54 2006 +0000 → sys/vfs/nullfs/null_vfsops.c Wed Mar 29 10:29:08 2006 +0200
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/nlookup.h>
#include <sys/namecache.h>
#include "null.h"
extern struct vnodeopv_entry_desc null_vnodeop_entries[];
......
{
int error = 0;
struct null_args args;
struct vnode *rootvp;
struct null_mount *xmp;
u_int size;
struct nlookupdata nd;
NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
NULLFSDEBUG("mp %p\n", (void *)mp);
/*
* Update is a no-op
......
* Get argument
*/
error = copyin(data, (caddr_t)&args, sizeof(struct null_args));
if (error)
xmp = malloc(sizeof(*xmp), M_NULLFSMNT, M_WAITOK | M_ZERO);
NULLFSDEBUG("nlookup %s\n", args.target);
xmp->nullm_ncp = nlookup_simple(args.target,
UIO_SYSSPACE, NLC_FOLLOW, &error);
if (! xmp->nullm_ncp) {
free(xmp, M_NULLFSMNT);
return (error);
/*
* Find lower node
*/
rootvp = NULL;
error = nlookup_init(&nd, args.target, UIO_USERSPACE, NLC_FOLLOW);
if (error == 0)
error = nlookup(&nd);
if (error == 0) {
error = cache_vget(nd.nl_ncp, nd.nl_cred, LK_EXCLUSIVE,
&rootvp);
}
xmp = (struct null_mount *) malloc(sizeof(struct null_mount),
M_NULLFSMNT, M_WAITOK); /* XXX */
/*
* Save reference to underlying FS
*/
/*
* As lite stacking enters the scene, the old way of doing this
* -- via the vnode -- is not good enough anymore...
*/
xmp->nullm_vfs = nd.nl_ncp->nc_mount;
nlookup_done(&nd);
vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops,
null_vnodeop_entries, 0);
VOP_UNLOCK(rootvp, 0, td);
/*
* Keep a held reference to the root vnode.
* It is vrele'd in nullfs_unmount.
*/
xmp->nullm_rootvp = rootvp;
/*
* XXX What's the proper safety condition for querying
* the underlying mount? Is this flag tuning necessary
* at all?
*/
if (xmp->nullm_vfs->mnt_flag & MNT_LOCAL)
}
cache_unlock(xmp->nullm_ncp);
vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, null_vnodeop_entries, 0);
if (xmp->nullm_ncp->nc_mount->mnt_flag & MNT_LOCAL)
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) xmp;
mp->mnt_data = (void *)xmp;
vfs_getnewfsid(mp);
(void) copyinstr(args.target, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
&size);
bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void)nullfs_statfs(mp, &mp->mnt_stat, td);
NULLFSDEBUG("nullfs_mount: lower %s, alias at %s\n",
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntfromname);
return (0);
}
/*
* Free reference to null layer
*/
NULLFSDEBUG("lower %s, alias at %s\n",
mp->mnt_stat.f_mntfromname, mp->mnt_stat.f_mntonname);
return (0);
}
static int
nullfs_unmount(struct mount *mp, int mntflags, struct thread *td)
{
void *mntdata;
int flags = 0;
NULLFSDEBUG("nullfs_unmount: mp = %p\n", (void *)mp);
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
/*
* Finally, throw away the null_mount structure
*/
mntdata = mp->mnt_data;
mp->mnt_data = 0;
free(mntdata, M_NULLFSMNT);
return 0;
NULLNCDEBUG(mp->mnt_ncp);
cache_drop(MOUNTTONULLMOUNT(mp)->nullm_ncp);
free(mp->mnt_data, M_NULLFSMNT);
return (0);
}
static int
nullfs_start(struct mount *mp, int flags, struct thread *td)
{
mp->mnt_ncp->nc_shadowed = MOUNTTONULLMOUNT(mp)->nullm_ncp;
return (0);
}
static int
nullfs_root(struct mount *mp, struct vnode **vpp)
{
struct thread *td = curthread; /* XXX */
struct vnode *vp;
NULLFSDEBUG("nullfs_root(mp = %p, vp = %p)\n", (void *)mp,
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp);
/*
* Return locked reference to root.
*/
vp = MOUNTTONULLMOUNT(mp)->nullm_rootvp;
vref(vp);
#ifdef NULLFS_DEBUG
if (VOP_ISLOCKED(vp, NULL)) {
Debugger("root vnode is locked.\n");
vrele(vp);
return (EDEADLK);
}
#endif
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
*vpp = vp;
return 0;
int error;
error = cache_vget(MOUNTTONULLMOUNT(mp)->nullm_ncp,
crhold(proc0.p_ucred), LK_EXCLUSIVE | LK_RETRY, vpp);
crfree(proc0.p_ucred);
return (error);
}
static __inline
struct mount *
nullfs_lowermount_0(struct mount *mp)
{
return (MOUNTTONULLMOUNT(mp)->nullm_ncp->nc_mount);
}
static int
nullfs_quotactl(struct mount *mp, int cmd, uid_t uid, caddr_t arg,
struct thread *td)
{
return VFS_QUOTACTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, uid, arg, td);
return VFS_QUOTACTL(nullfs_lowermount_0(mp), cmd, uid, arg, td);
}
static int
......
int error;
struct statfs mstat;
NULLFSDEBUG("nullfs_statfs(mp = %p, vp = %p)\n", (void *)mp,
(void *)MOUNTTONULLMOUNT(mp)->nullm_rootvp);
NULLFSDEBUG("mp %p, ncp %p, lower mp %p\n",
mp, mp->mnt_ncp, nullfs_lowermount_0(mp));
bzero(&mstat, sizeof(mstat));
error = VFS_STATFS(MOUNTTONULLMOUNT(mp)->nullm_vfs, &mstat, td);
error = VFS_STATFS(nullfs_lowermount_0(mp), &mstat, td);
if (error)
return (error);
......
nullfs_checkexp(struct mount *mp, struct sockaddr *nam, int *extflagsp,
struct ucred **credanonp)
{
return VFS_CHECKEXP(MOUNTTONULLMOUNT(mp)->nullm_vfs, nam,
extflagsp, credanonp);
return VFS_CHECKEXP(nullfs_lowermount_0(mp), nam, extflagsp, credanonp);
}
static int
nullfs_extattrctl(struct mount *mp, int cmd, const char *attrname, caddr_t arg,
struct thread *td)
{
return VFS_EXTATTRCTL(MOUNTTONULLMOUNT(mp)->nullm_vfs, cmd, attrname,
arg, td);
return VFS_EXTATTRCTL(nullfs_lowermount_0(mp), cmd, attrname, arg, td);
}
static struct vfsops null_vfsops = {
.vfs_mount = nullfs_mount,
.vfs_unmount = nullfs_unmount,
.vfs_start = nullfs_start,
.vfs_root = nullfs_root,
.vfs_quotactl = nullfs_quotactl,
.vfs_statfs = nullfs_statfs,
sys/vfs/nullfs/null_vnops.c Sun Mar 26 07:56:54 2006 +0000 → sys/vfs/nullfs/null_vnops.c Wed Mar 29 10:29:08 2006 +0200
* might be able to get on with a hybrid solution: overlay some vnodes, and rely
* on namecache API for the rest.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
......
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <sys/namecache.h>
#include <sys/nlookup.h>
#include "null.h"
static int null_nresolve(struct vop_nresolve_args *ap);
......
static int null_nrmdir(struct vop_nrmdir_args *ap);
static int null_nrename(struct vop_nrename_args *ap);
static __inline
struct mount *
nullfs_lowermount_l(struct namecache *ncp)
{
/*
* The code in use below allows allows passing through lower mounts.
* If we didn't want to do that, we could use
*
* MOUNTTONULLMOUNT(ncp->nc_mount)->nullm_ncp->nc_mount
*
* Eventually, the choice might be configurable.
*/
return (ncp->nc_shadowed->nc_mount);
}
static __inline
int
nullfs_check(struct namecache *ncp)
{
if (ncp->nc_mount->mnt_ncp == ncp)
return (EPERM);
if (!ncp->nc_shadowed)
return (ENOENT);
if (ncp->nc_shadowheight == 0)
return (EINVAL);
return (0);
}
static int
null_nresolve(struct vop_nresolve_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nresolve_ap(ap);
}
static int
null_ncreate(struct vop_ncreate_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_ncreate_ap(ap);
}
static int
null_nmkdir(struct vop_nmkdir_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nmkdir_ap(ap);
}
static int
null_nmknod(struct vop_nmknod_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nmknod_ap(ap);
}
static int
null_nlink(struct vop_nlink_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nlink_ap(ap);
}
static int
null_nsymlink(struct vop_nsymlink_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nsymlink_ap(ap);
}
static int
null_nwhiteout(struct vop_nwhiteout_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nwhiteout_ap(ap);
}
static int
null_nremove(struct vop_nremove_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nremove_ap(ap);
}
static int
null_nrmdir(struct vop_nrmdir_args *ap)
{
ap->a_head.a_ops = MOUNTTONULLMOUNT(ap->a_ncp->nc_mount)->nullm_vfs->mnt_vn_norm_ops;
return vop_nrmdir_ap(ap);
}
struct namecache *ncp = ap->a_ncp;
struct nlcomponent nlc;
struct namecache *sncp, *psncp;
int error = 0;
sncp = ncp->nc_shadow_next;
if (sncp) {
cache_hold(sncp);
cache_setunresolved(sncp);
cache_put(sncp);
}
cache_unlock(ncp);
cache_lock(ncp->nc_parent);
psncp = ncp->nc_parent->nc_shadowed;
if (psncp)
cache_hold(psncp);
cache_unlock(ncp->nc_parent);
if (! psncp) {
cache_lock(ncp);
if ((ncp->nc_flag & NCF_UNRESOLVED) == 0)
cache_setvp(ncp, NULL);
return (ncp->nc_error);
}
nlc.nlc_nameptr = ncp->nc_name;
nlc.nlc_namelen = ncp->nc_nlen;
sncp = cache_nlookup(psncp, &nlc);
cache_drop(psncp);
if ((sncp->nc_flag & NCF_UNRESOLVED) == 0)
goto postdowncall;
ap->a_head.a_ops = sncp->nc_mount->mnt_vn_use_ops;
ap->a_ncp = sncp;
/*
* According to cache_resolve(), the primary place for
* VOP_NRESOLVE calls, the caller of the nresolve method
* is the one who should take care about ncp->nc_error.
*/
ap->a_ncp->nc_error = vop_nresolve_ap(ap);
postdowncall:
error = cache_shadow_attach(ncp, sncp);
NULLNCDEBUG(ncp);
NULLNCDEBUG(sncp);
NULLFSDEBUG("attach error %d\n", error);
if (error) {
cache_put(sncp);
if (ncp->nc_flag & NCF_UNRESOLVED) {
cache_setvp(ncp, NULL);
error = ENOENT;
} else if (error == EEXIST)
error = ncp->nc_error;
} else {
error = sncp->nc_error;
cache_setvp(ncp, sncp->nc_vp);
ncp->nc_shadowed = sncp;
cache_drop(sncp);
}
NULLFSDEBUG("error %d\n", error);
return (error);
}
#define NULL_NVOP_TEMPLATE(OP) \
static int \
null_ ## OP(struct vop_ ## OP ## _args *ap) \
{ \
struct namecache *ncp = ap->a_ncp; \
struct namecache *sncp = ncp->nc_shadowed; \
int error; \
\
NULLNCDEBUG(ap->a_ncp); \
\
if ((error = nullfs_check(ncp))) \
return (error); \
cache_hold(sncp); \
\
NULLNCDEBUG(ap->a_ncp->nc_shadowed); \
\
ap->a_head.a_ops = nullfs_lowermount_l(ap->a_ncp)->mnt_vn_use_ops; \
ap->a_ncp = ncp->nc_shadowed; \
\
error = vop_ ## OP ## _ap(ap); \
NULLNCDEBUG(ncp); \
NULLNCDEBUG(sncp); \
sncp->nc_shadowinfo == ncp->nc_shadowinfo ? \
cache_drop(sncp) : \
cache_put(sncp); \
\
return (error); \
}
NULL_NVOP_TEMPLATE(ncreate)
NULL_NVOP_TEMPLATE(nmkdir)
NULL_NVOP_TEMPLATE(nmknod)
NULL_NVOP_TEMPLATE(nlink)
NULL_NVOP_TEMPLATE(nsymlink)
NULL_NVOP_TEMPLATE(nwhiteout)
NULL_NVOP_TEMPLATE(nremove)
NULL_NVOP_TEMPLATE(nrmdir)
static int
null_nrename(struct vop_nrename_args *ap)
{
struct namecache *fncp = ap->a_fncp;
struct namecache *tncp = ap->a_tncp;
struct namecache *sfncp = fncp->nc_shadowed;
struct namecache *stncp = tncp->nc_shadowed;
struct mount *lmp;
lmp = MOUNTTONULLMOUNT(ap->a_fncp->nc_mount)->nullm_vfs;
if (lmp != MOUNTTONULLMOUNT(ap->a_tncp->nc_mount)->nullm_vfs)
return (EINVAL);
ap->a_head.a_ops = lmp->mnt_vn_norm_ops;
return vop_nrename_ap(ap);
int error;
NULLNCDEBUG(ap->a_fncp);
NULLNCDEBUG(ap->a_tncp);
if ((error = nullfs_check(fncp)))
return (error);
if ((error = nullfs_check(tncp)))
return (error);
lmp = nullfs_lowermount_l(fncp);
if (lmp != nullfs_lowermount_l(tncp))
return (EXDEV);
cache_hold(sfncp);
cache_hold(stncp);
NULLNCDEBUG(ap->a_fncp->nc_shadowed);
NULLNCDEBUG(ap->a_tncp->nc_shadowed);
ap->a_head.a_ops = lmp->mnt_vn_use_ops;
ap->a_fncp = fncp->nc_shadowed;
ap->a_tncp = tncp->nc_shadowed;
error = vop_nrename_ap(ap);
sfncp->nc_shadowinfo == fncp->nc_shadowinfo ?
cache_drop(sfncp) :
cache_put(sfncp);
stncp->nc_shadowinfo == tncp->nc_shadowinfo ?
cache_drop(stncp) :
cache_put(stncp);
return (error);
}
/*
......
{ &vop_nrename_desc, (vnodeopv_entry_t) null_nrename },
{ NULL, NULL }
};
(2-2/2)