Stop abusing relookup() to prepare the creation of new nodes

in the upper layer.
Replace union_relookup() with union_do_lookup() that prepares
a component, calls VOP_LOOKUP() and does the EEXIST test.
This commit is contained in:
hannken 2011-08-23 07:39:37 +00:00
parent 875018bf8a
commit f937bd97b7
3 changed files with 78 additions and 136 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: union.h,v 1.20 2011/08/12 17:41:17 hannken Exp $ */
/* $NetBSD: union.h,v 1.21 2011/08/23 07:39:37 hannken Exp $ */
/*
* Copyright (c) 1994 The Regents of the University of California.
@ -144,7 +144,7 @@ extern int union_dowhiteout(struct union_node *, kauth_cred_t);
extern int union_mkshadow(struct union_mount *, struct vnode *,
struct componentname *, struct vnode **);
extern int union_mkwhiteout(struct union_mount *, struct vnode *,
struct componentname *, char *);
struct componentname *, struct union_node *);
extern int union_vn_create(struct vnode **, struct union_node *,
struct lwp *);
extern int union_cn_close(struct vnode *, int, kauth_cred_t,

View File

@ -1,4 +1,4 @@
/* $NetBSD: union_subr.c,v 1.49 2011/08/13 10:48:14 hannken Exp $ */
/* $NetBSD: union_subr.c,v 1.50 2011/08/23 07:39:37 hannken Exp $ */
/*
* Copyright (c) 1994
@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.49 2011/08/13 10:48:14 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: union_subr.c,v 1.50 2011/08/23 07:39:37 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -106,10 +106,7 @@ static LIST_HEAD(unhead, union_node) unhead[NHASH];
static kmutex_t unheadlock[NHASH];
void union_updatevp(struct union_node *, struct vnode *, struct vnode *);
static int union_relookup(struct union_mount *, struct vnode *,
struct vnode **, struct componentname *,
struct componentname *, char **,
const char *, int);
static int union_do_lookup(struct vnode *, struct componentname *, kauth_cred_t, const char *, u_long);
int union_vn_close(struct vnode *, int, kauth_cred_t, struct lwp *);
static void union_dircache_r(struct vnode *, struct vnode ***, int *);
struct vnode *union_dircache(struct vnode *, struct lwp *);
@ -755,54 +752,50 @@ union_copyup(struct union_node *un, int docopy, kauth_cred_t cred,
}
/*
* Prepare the creation of a new node in the upper layer.
*
* (dvp) is the directory in which to create the new node.
* it is locked on entry and exit.
* (cnp) is the componentname to be created.
* (cred, path, hash) are credentials, path and its hash to fill (cnp).
*/
static int
union_relookup(
struct union_mount *um,
struct vnode *dvp,
struct vnode **vpp,
struct componentname *cnp,
struct componentname *cn,
char **pnbuf_ret,
const char *path,
int pathlen)
union_do_lookup(struct vnode *dvp, struct componentname *cnp, kauth_cred_t cred,
const char *path, u_long hash)
{
int error;
char *pnbuf;
const char *cp;
struct vnode *vp;
/*
* A new componentname structure must be faked up because
* there is no way to know where the upper level cnp came
* from or what it is being used for. This must duplicate
* some of the work done by NDINIT, some of the work done
* by namei, some of the work done by lookup and some of
* the work done by VOP_LOOKUP when given a CREATE flag.
* Conclusion: Horrible.
*/
cn->cn_namelen = pathlen;
if ((cn->cn_namelen + 1) > MAXPATHLEN)
return (ENAMETOOLONG);
pnbuf = PNBUF_GET();
memcpy(pnbuf, path, cn->cn_namelen);
pnbuf[cn->cn_namelen] = '\0';
*pnbuf_ret = pnbuf;
cn->cn_nameiop = CREATE;
cn->cn_flags = (LOCKPARENT|ISLASTCN);
if (um->um_op == UNMNT_ABOVE)
cn->cn_cred = cnp->cn_cred;
else
cn->cn_cred = um->um_cred;
cn->cn_nameptr = pnbuf;
cn->cn_hash = cnp->cn_hash;
cn->cn_consume = cnp->cn_consume;
error = relookup(dvp, vpp, cn, 0);
if (error) {
PNBUF_PUT(pnbuf);
*pnbuf_ret = NULL;
cnp->cn_nameiop = CREATE;
cnp->cn_flags = LOCKPARENT | ISLASTCN;
cnp->cn_cred = cred;
cnp->cn_nameptr = path;
cnp->cn_namelen = strlen(path);
if (hash == 0) {
cp = NULL;
cnp->cn_hash = namei_hash(cnp->cn_nameptr, &cp);
KASSERT(*cp == 0);
} else {
cnp->cn_hash = hash;
}
return (error);
error = VOP_LOOKUP(dvp, &vp, cnp);
if (error == 0) {
KASSERT(vp != NULL);
VOP_ABORTOP(dvp, cnp);
if (dvp != vp)
vput(vp);
else
vrele(vp);
error = EEXIST;
} else if (error == EJUSTRETURN) {
error = 0;
}
return error;
}
/*
@ -829,22 +822,20 @@ union_mkshadow(struct union_mount *um, struct vnode *dvp,
struct componentname cn;
char *pnbuf;
if (cnp->cn_namelen + 1 > MAXPATHLEN)
return ENAMETOOLONG;
pnbuf = PNBUF_GET();
memcpy(pnbuf, cnp->cn_nameptr, cnp->cn_namelen);
pnbuf[cnp->cn_namelen] = '\0';
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
error = union_relookup(um, dvp, vpp, cnp, &cn, &pnbuf,
cnp->cn_nameptr, cnp->cn_namelen);
error = union_do_lookup(dvp, &cn,
(um->um_op == UNMNT_ABOVE ? cnp->cn_cred : um->um_cred), pnbuf, 0);
if (error) {
VOP_UNLOCK(dvp);
return (error);
}
if (*vpp) {
VOP_ABORTOP(dvp, &cn);
PNBUF_PUT(pnbuf);
if (dvp != *vpp)
VOP_UNLOCK(dvp);
vput(*vpp);
*vpp = NULLVP;
return (EEXIST);
return error;
}
/*
@ -862,7 +853,7 @@ union_mkshadow(struct union_mount *um, struct vnode *dvp,
vref(dvp);
error = VOP_MKDIR(dvp, vpp, &cn, &va);
PNBUF_PUT(pnbuf);
return (error);
return error;
}
/*
@ -873,39 +864,23 @@ union_mkshadow(struct union_mount *um, struct vnode *dvp,
* (dvp) is the directory in which to create the whiteout.
* it is locked on entry and exit.
* (cnp) is the componentname to be created.
* (un) holds the path and its hash to be created.
*/
int
union_mkwhiteout(struct union_mount *um, struct vnode *dvp,
struct componentname *cnp, char *path)
struct componentname *cnp, struct union_node *un)
{
int error;
struct vnode *wvp;
struct componentname cn;
char *pnbuf;
VOP_UNLOCK(dvp);
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
error = union_relookup(um, dvp, &wvp, cnp, &cn, &pnbuf,
path, strlen(path));
error = union_do_lookup(dvp, &cn,
(um->um_op == UNMNT_ABOVE ? cnp->cn_cred : um->um_cred),
un->un_path, un->un_hash);
if (error)
return (error);
if (wvp) {
VOP_ABORTOP(dvp, &cn);
PNBUF_PUT(pnbuf);
if (dvp != wvp)
VOP_UNLOCK(dvp);
vput(wvp);
return (EEXIST);
}
return error;
error = VOP_WHITEOUT(dvp, &cn, CREATE);
if (error) {
VOP_ABORTOP(dvp, &cn);
}
PNBUF_PUT(pnbuf);
return (error);
return error;
}
/*
@ -914,7 +889,7 @@ union_mkwhiteout(struct union_mount *um, struct vnode *dvp,
* in spirit to calling vn_open but it avoids calling namei().
* the problem with calling namei is that a) it locks too many
* things, and b) it doesn't start at the "right" directory,
* whereas relookup is told where to start.
* whereas union_do_lookup is told where to start.
*/
int
union_vn_create(struct vnode **vpp, struct union_node *un, struct lwp *l)
@ -927,46 +902,16 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct lwp *l)
int error;
int cmode = UN_FILEMODE & ~l->l_proc->p_cwdi->cwdi_cmask;
struct componentname cn;
char *pnbuf;
*vpp = NULLVP;
/*
* Build a new componentname structure (for the same
* reasons outlines in union_mkshadow).
* The difference here is that the file is owned by
* the current user, rather than by the person who
* did the mount, since the current user needs to be
* able to write the file (that's why it is being
* copied in the first place).
*/
cn.cn_namelen = strlen(un->un_path);
if ((cn.cn_namelen + 1) > MAXPATHLEN)
return (ENAMETOOLONG);
pnbuf = PNBUF_GET();
memcpy(pnbuf, un->un_path, cn.cn_namelen+1);
cn.cn_nameiop = CREATE;
cn.cn_flags = (LOCKPARENT|ISLASTCN);
cn.cn_cred = l->l_cred;
cn.cn_nameptr = pnbuf;
cn.cn_hash = un->un_hash;
cn.cn_consume = 0;
vn_lock(un->un_dirvp, LK_EXCLUSIVE | LK_RETRY);
error = relookup(un->un_dirvp, &vp, &cn, 0);
if (error) {
PNBUF_PUT(pnbuf);
VOP_UNLOCK(un->un_dirvp);
return (error);
}
if (vp) {
VOP_ABORTOP(un->un_dirvp, &cn);
PNBUF_PUT(pnbuf);
if (un->un_dirvp != vp)
VOP_UNLOCK(un->un_dirvp);
vput(vp);
return (EEXIST);
error = union_do_lookup(un->un_dirvp, &cn, l->l_cred,
un->un_path, un->un_hash);
if (error) {
VOP_UNLOCK(un->un_dirvp);
return error;
}
/*
@ -983,21 +928,19 @@ union_vn_create(struct vnode **vpp, struct union_node *un, struct lwp *l)
vap->va_type = VREG;
vap->va_mode = cmode;
vref(un->un_dirvp);
if ((error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap)) != 0) {
PNBUF_PUT(pnbuf);
return (error);
}
error = VOP_CREATE(un->un_dirvp, &vp, &cn, vap);
if (error)
return error;
if ((error = VOP_OPEN(vp, fmode, cred)) != 0) {
error = VOP_OPEN(vp, fmode, cred);
if (error) {
vput(vp);
PNBUF_PUT(pnbuf);
return (error);
return error;
}
vp->v_writecount++;
*vpp = vp;
PNBUF_PUT(pnbuf);
return (0);
return 0;
}
int
@ -1240,7 +1183,6 @@ union_check_rmdir(struct union_node *un, kauth_cred_t cred)
cn.cn_nameptr = dp->d_name;
cn.cn_namelen = dp->d_namlen;
cn.cn_hash = 0;
cn.cn_consume = 0;
error = VOP_LOOKUP(un->un_uppervp, &tvp, &cn);
if (error == ENOENT && (cn.cn_flags & ISWHITEOUT)) {
error = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: union_vnops.c,v 1.45 2011/08/12 17:41:17 hannken Exp $ */
/* $NetBSD: union_vnops.c,v 1.46 2011/08/23 07:39:37 hannken Exp $ */
/*
* Copyright (c) 1992, 1993, 1994, 1995
@ -72,7 +72,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.45 2011/08/12 17:41:17 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.46 2011/08/23 07:39:37 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -1211,7 +1211,7 @@ union_remove(void *v)
FIXUP(dun);
error = union_mkwhiteout(
MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
dun->un_uppervp, ap->a_cnp, un->un_path);
dun->un_uppervp, ap->a_cnp, un);
vput(ap->a_dvp);
vput(ap->a_vp);
}
@ -1488,7 +1488,7 @@ union_rmdir(void *v)
FIXUP(dun);
error = union_mkwhiteout(
MOUNTTOUNIONMOUNT(UNIONTOV(dun)->v_mount),
dun->un_uppervp, ap->a_cnp, un->un_path);
dun->un_uppervp, ap->a_cnp, un);
vput(ap->a_dvp);
vput(ap->a_vp);
}