Bug #129 » ncc3-null.diff
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 }
|
||
};
|
||
- « Previous
- 1
- 2
- Next »