Reorder vop's alphabetically.

Smarter use of devfs_allocv() (from bp@)
 Introduce devfs_find()
 ".." fixes to devfs_lookup (from bp@)
This commit is contained in:
Poul-Henning Kamp 2000-08-27 14:46:36 +00:00
parent 62ddc84e08
commit c32d0a1dcd
4 changed files with 281 additions and 248 deletions

View File

@ -88,6 +88,8 @@ extern unsigned devfs_generation;
extern vop_t **devfs_vnodeop_p;
extern vop_t **devfs_specop_p;
int devfs_allocv __P((struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p));
struct devfs_dirent * devfs_find __P((struct devfs_dirent *dd, const char *name, int namelen));
int devfs_populate __P((struct devfs_mount *dm));
struct devfs_dirent * devfs_newdirent __P((char *name, int namelen));
void devfs_purge __P((struct devfs_dirent *dd));

View File

@ -41,6 +41,21 @@
#define DEVFS_INTERN
#include <fs/devfs/devfs.h>
struct devfs_dirent *
devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
{
struct devfs_dirent *de;
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
if (namelen != de->de_dirent->d_namlen)
continue;
if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
continue;
break;
}
return (de);
}
struct devfs_dirent *
devfs_newdirent(char *name, int namelen)
{
@ -161,25 +176,20 @@ devfs_populate(struct devfs_mount *dm)
continue;
dd = dm->dm_basedir;
s = dev->si_name;
nextdir:
for (q = s; *q != '/' && *q != '\0'; q++)
continue;
if (*q == '/') {
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
if (de->de_dirent->d_namlen != q - s)
continue;
if (bcmp(de->de_dirent->d_name, s, q - s))
continue;
goto fdir;
for (;;) {
for (q = s; *q != '/' && *q != '\0'; q++)
continue;
if (*q != '/')
break;
de = devfs_find(dd, s, q - s);
if (de == NULL) {
de = devfs_vmkdir(s, q - s, dd);
de->de_inode = dm->dm_inode++;
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
dd->de_links++;
}
de = devfs_vmkdir(s, q - s, dd);
de->de_inode = dm->dm_inode++;
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
dd->de_links++;
fdir:
s = q + 1;
dd = de;
goto nextdir;
}
de = devfs_newdirent(s, q - s);
if (dev->si_flags & SI_ALIAS) {
@ -200,6 +210,7 @@ devfs_populate(struct devfs_mount *dm)
de->de_dirent->d_type = DT_CHR;
}
dm->dm_dirent[i] = de;
de->de_dir = dd;
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
#if 0
printf("Add ino%d %s\n", i, dev->si_name);

View File

@ -67,43 +67,39 @@ devfs_mount(mp, path, data, ndp, p)
struct nameidata *ndp;
struct proc *p;
{
int error = 0;
int error;
u_int size;
struct devfs_mount *fmp;
struct vnode *rvp;
error = 0;
/*
* Update is a no-op
* XXX: flag changes.
*/
if (mp->mnt_flag & MNT_UPDATE)
return (EOPNOTSUPP);
MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount), M_DEVFS, M_WAITOK);
MALLOC(fmp, struct devfs_mount *, sizeof(struct devfs_mount),
M_DEVFS, M_WAITOK);
bzero(fmp, sizeof(*fmp));
error = getnewvnode(VT_DEVFS, mp, devfs_vnodeop_p, &rvp);
if (error) {
FREE(fmp, M_DEVFS);
return (error);
}
vhold(rvp);
rvp->v_type = VDIR;
rvp->v_flag |= VROOT;
mp->mnt_flag |= MNT_LOCAL;
mp->mnt_data = (qaddr_t) fmp;
vfs_getnewfsid(mp);
fmp->dm_inode = NDEVINO;
fmp->dm_root = rvp;
fmp->dm_rootdir = devfs_vmkdir("(root)", 6, NULL);
fmp->dm_rootdir->de_inode = 2;
rvp->v_data = fmp->dm_rootdir;
fmp->dm_basedir = fmp->dm_rootdir;
error = devfs_root(mp, &rvp);
if (error) {
FREE(fmp, M_DEVFS);
return (error);
}
VOP_UNLOCK(rvp, 0, p);
if (path != NULL) {
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
} else {
@ -127,55 +123,47 @@ devfs_unmount(mp, mntflags, p)
{
int error;
int flags = 0;
struct vnode *rootvp = VFSTODEVFS(mp)->dm_root;
struct vnode *rootvp;
struct devfs_mount *fmp;
fmp = (struct devfs_mount*) mp->mnt_data;
error = devfs_root(mp, &rootvp);
if (error)
return (error);
fmp = VFSTODEVFS(mp);
if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
/*
* Clear out buffer cache. I don't think we
* ever get anything cached at this level at the
* moment, but who knows...
*/
if (rootvp->v_usecount > 2)
return (EBUSY);
devfs_purge(fmp->dm_rootdir);
error = vflush(mp, rootvp, flags);
if (error)
return (error);
/*
* Release reference on underlying root vnode
*/
vput(rootvp);
vrele(rootvp);
/*
* And blow it away for future re-use
*/
vgone(rootvp);
/*
* Finally, throw away the devfs_mount structure
*/
free(mp->mnt_data, M_DEVFS);
mp->mnt_data = 0;
free(fmp, M_DEVFS);
return 0;
}
/* Return locked reference to root. */
static int
devfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
struct proc *p = curproc; /* XXX */
int error;
struct proc *p;
struct vnode *vp;
struct devfs_mount *dmp;
/*
* Return locked reference to root.
*/
vp = VFSTODEVFS(mp)->dm_root;
VREF(vp);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
p = curproc; /* XXX */
dmp = VFSTODEVFS(mp);
error = devfs_allocv(dmp->dm_rootdir, mp, &vp, p);
if (error)
return (error);
vp->v_flag |= VROOT;
*vpp = vp;
return (0);
}

View File

@ -67,16 +67,18 @@ static int devfs_setattr __P((struct vop_setattr_args *ap));
static int devfs_symlink __P((struct vop_symlink_args *ap));
static int
int
devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct proc *p)
{
int error;
struct vnode *vp;
if (p == NULL)
p = curproc; /* XXX */
loop:
vp = de->de_vnode;
if (vp != NULL) {
if (vget(vp, 0, p ? p : curproc))
if (vget(vp, LK_EXCLUSIVE, p ? p : curproc))
goto loop;
*vpp = vp;
return (0);
@ -101,148 +103,10 @@ devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, stru
vp->v_data = de;
de->de_vnode = vp;
vhold(vp);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
*vpp = vp;
return (0);
}
/*
* vp is the current namei directory
* ndp is the name to locate in that directory...
*/
static int
devfs_lookup(ap)
struct vop_lookup_args /* {
struct vnode * a_dvp;
struct vnode ** a_vpp;
struct componentname * a_cnp;
} */ *ap;
{
struct componentname *cnp = ap->a_cnp;
struct vnode **vpp = ap->a_vpp;
struct vnode *dvp = ap->a_dvp;
char *pname = cnp->cn_nameptr;
struct proc *p = cnp->cn_proc;
struct devfs_dirent *dd;
struct devfs_dirent *de;
struct devfs_mount *dmp;
dev_t cdev;
int error, cloned, i;
char specname[SPECNAMELEN + 1];
*vpp = NULLVP;
#if 0
error = VOP_ACCESS(dvp, VEXEC, cred, cnp->cn_proc);
if (error)
return (error);
#endif
VOP_UNLOCK(dvp, 0, p);
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
cloned = 0;
dmp = VFSTODEVFS(dvp->v_mount);
again:
devfs_populate(dmp);
dd = dvp->v_data;
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
if (cnp->cn_namelen != de->de_dirent->d_namlen)
continue;
if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, de->de_dirent->d_namlen) != 0)
continue;
goto found;
}
if (!cloned) {
/*
* OK, we didn't have an entry for the name we were asked for
* so we try to see if anybody can create it on demand.
* We need to construct the full "devname" for this device
* relative to "basedir" or the clone functions would not
* be able to tell "/dev/foo" from "/dev/bar/foo"
*/
i = SPECNAMELEN;
specname[i] = '\0';
i -= cnp->cn_namelen;
if (i < 0)
goto noclone;
bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen);
de = dd;
while (de != dmp->dm_basedir) {
i--;
if (i < 0)
goto noclone;
specname[i] = '/';
i -= de->de_dirent->d_namlen;
if (i < 0)
goto noclone;
bcopy(de->de_dirent->d_name, specname + i,
de->de_dirent->d_namlen);
de = TAILQ_FIRST(&de->de_dlist); /* "." */
de = TAILQ_NEXT(de, de_list); /* ".." */
de = de->de_dir;
}
#if 0
printf("Finished specname: %d \"%s\"\n", i, specname + i);
#endif
cdev = NODEV;
EVENTHANDLER_INVOKE(devfs_clone, specname + i,
strlen(specname + i), &cdev);
#if 0
printf("cloned %s -> %p %s\n", specname + i, cdev,
cdev == NODEV ? "NODEV" : cdev->si_name);
#endif
if (cdev != NODEV) {
cloned = 1;
goto again;
}
}
noclone:
/* No luck, too bad. */
if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
(cnp->cn_flags & ISLASTCN)) {
cnp->cn_flags |= SAVENAME;
if (!(cnp->cn_flags & LOCKPARENT))
VOP_UNLOCK(dvp, 0, p);
return (EJUSTRETURN);
} else {
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (ENOENT);
}
found:
error = devfs_allocv(de, dvp->v_mount, vpp, p);
if (error != 0) {
vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (error);
}
if ((cnp->cn_nameiop == DELETE) && (cnp->cn_flags & ISLASTCN)) {
if (*vpp == dvp) {
VREF(dvp);
*vpp = dvp;
return (0);
}
VREF(*vpp);
if (!(cnp->cn_flags & LOCKPARENT))
VOP_UNLOCK(dvp, 0, p);
return (0);
}
vn_lock(*vpp, LK_SHARED | LK_RETRY, p);
if (!(cnp->cn_flags & LOCKPARENT))
VOP_UNLOCK(dvp, 0, p);
return (0);
}
static int
devfs_access(ap)
@ -323,43 +187,186 @@ devfs_getattr(ap)
}
static int
devfs_setattr(ap)
struct vop_setattr_args /* {
struct vnode *a_vp;
struct vattr *a_vap;
struct ucred *a_cred;
struct proc *a_p;
devfs_lookup(ap)
struct vop_lookup_args /* {
struct vnode * a_dvp;
struct vnode ** a_vpp;
struct componentname * a_cnp;
} */ *ap;
{
struct devfs_dirent *de;
int c;
struct componentname *cnp;
struct vnode *dvp, **vpp;
struct proc *p;
struct devfs_dirent *de, *dd;
struct devfs_mount *dmp;
dev_t cdev;
int error, cloned, i, flags, nameiop;
char specname[SPECNAMELEN + 1], *pname;
de = ap->a_vp->v_data;
if (ap->a_vp->v_type == VDIR)
de = de->de_dir;
cnp = ap->a_cnp;
vpp = ap->a_vpp;
dvp = ap->a_dvp;
pname = cnp->cn_nameptr;
p = cnp->cn_proc;
flags = cnp->cn_flags;
nameiop = cnp->cn_nameiop;
dmp = VFSTODEVFS(dvp->v_mount);
cloned = 0;
dd = dvp->v_data;
*vpp = NULLVP;
c = 0;
if (ap->a_vap->va_flags != VNOVAL)
if (nameiop == RENAME)
return (EOPNOTSUPP);
if (ap->a_vap->va_uid != (uid_t)VNOVAL) {
de->de_uid = ap->a_vap->va_uid;
c = 1;
}
if (ap->a_vap->va_gid != (gid_t)VNOVAL) {
de->de_gid = ap->a_vap->va_gid;
c = 1;
}
if (ap->a_vap->va_mode != (mode_t)VNOVAL) {
de->de_mode = ap->a_vap->va_mode;
c = 1;
}
if (ap->a_vap->va_atime.tv_sec != VNOVAL)
de->de_atime = ap->a_vap->va_atime;
if (ap->a_vap->va_mtime.tv_sec != VNOVAL)
de->de_mtime = ap->a_vap->va_mtime;
if (c)
getnanotime(&de->de_ctime);
if (dvp->v_type != VDIR)
return (ENOTDIR);
if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT))
return (EIO);
error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_proc);
if (error)
return (error);
if (cnp->cn_namelen == 1 && *pname == '.') {
if (nameiop != LOOKUP)
return (EINVAL);
*vpp = dvp;
VREF(dvp);
return (0);
}
if (flags & ISDOTDOT) {
if (nameiop != LOOKUP)
return (EINVAL);
VOP_UNLOCK(dvp, 0, p);
de = TAILQ_FIRST(&dd->de_dlist); /* "." */
de = TAILQ_NEXT(de, de_list); /* ".." */
de = de->de_dir;
error = devfs_allocv(de, dvp->v_mount, vpp, p);
if (error) {
vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
return (error);
}
if ((flags & LOCKPARENT) && (flags & ISLASTCN))
error = vn_lock(dvp, LK_EXCLUSIVE, p);
if (error)
vput(*vpp);
return (error);
}
devfs_populate(dmp);
dd = dvp->v_data;
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
if (cnp->cn_namelen != de->de_dirent->d_namlen)
continue;
if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
de->de_dirent->d_namlen) != 0)
continue;
goto found;
}
/*
* OK, we didn't have an entry for the name we were asked for
* so we try to see if anybody can create it on demand.
* We need to construct the full "devname" for this device
* relative to "basedir" or the clone functions would not
* be able to tell "/dev/foo" from "/dev/bar/foo"
*/
i = SPECNAMELEN;
specname[i] = '\0';
i -= cnp->cn_namelen;
if (i < 0)
goto notfound;
bcopy(cnp->cn_nameptr, specname + i, cnp->cn_namelen);
de = dd;
while (de != dmp->dm_basedir) {
i--;
if (i < 0)
goto notfound;
specname[i] = '/';
i -= de->de_dirent->d_namlen;
if (i < 0)
goto notfound;
bcopy(de->de_dirent->d_name, specname + i,
de->de_dirent->d_namlen);
de = TAILQ_FIRST(&de->de_dlist); /* "." */
de = TAILQ_NEXT(de, de_list); /* ".." */
de = de->de_dir;
}
#if 0
printf("Finished specname: %d \"%s\"\n", i, specname + i);
#endif
cdev = NODEV;
EVENTHANDLER_INVOKE(devfs_clone, specname + i,
strlen(specname + i), &cdev);
#if 0
printf("cloned %s -> %p %s\n", specname + i, cdev,
cdev == NODEV ? "NODEV" : cdev->si_name);
#endif
if (cdev == NODEV)
goto notfound;
devfs_populate(dmp);
dd = dvp->v_data;
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
if (cnp->cn_namelen != de->de_dirent->d_namlen)
continue;
if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
de->de_dirent->d_namlen) != 0)
continue;
goto found;
}
notfound:
if ((nameiop == CREATE || nameiop == RENAME) &&
(flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
cnp->cn_flags |= SAVENAME;
if (!(flags & LOCKPARENT))
VOP_UNLOCK(dvp, 0, p);
return (EJUSTRETURN);
}
return (ENOENT);
found:
if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
if (error)
return (error);
if (*vpp == dvp) {
VREF(dvp);
*vpp = dvp;
return (0);
}
error = devfs_allocv(de, dvp->v_mount, vpp, p);
if (error)
return (error);
if (!(flags & LOCKPARENT))
VOP_UNLOCK(dvp, 0, p);
return (0);
}
error = devfs_allocv(de, dvp->v_mount, vpp, p);
if (error)
return (error);
if (!(flags & LOCKPARENT) || !(flags & ISLASTCN))
VOP_UNLOCK(dvp, 0, p);
return (0);
}
/* ARGSUSED */
static int
devfs_print(ap)
struct vop_print_args /* {
struct vnode *a_vp;
} */ *ap;
{
printf("tag VT_DEVFS, devfs vnode\n");
return (0);
}
@ -515,6 +522,47 @@ devfs_revoke(ap)
return (0);
}
static int
devfs_setattr(ap)
struct vop_setattr_args /* {
struct vnode *a_vp;
struct vattr *a_vap;
struct ucred *a_cred;
struct proc *a_p;
} */ *ap;
{
struct devfs_dirent *de;
int c;
de = ap->a_vp->v_data;
if (ap->a_vp->v_type == VDIR)
de = de->de_dir;
c = 0;
if (ap->a_vap->va_flags != VNOVAL)
return (EOPNOTSUPP);
if (ap->a_vap->va_uid != (uid_t)VNOVAL) {
de->de_uid = ap->a_vap->va_uid;
c = 1;
}
if (ap->a_vap->va_gid != (gid_t)VNOVAL) {
de->de_gid = ap->a_vap->va_gid;
c = 1;
}
if (ap->a_vap->va_mode != (mode_t)VNOVAL) {
de->de_mode = ap->a_vap->va_mode;
c = 1;
}
if (ap->a_vap->va_atime.tv_sec != VNOVAL)
de->de_atime = ap->a_vap->va_atime;
if (ap->a_vap->va_mtime.tv_sec != VNOVAL)
de->de_mtime = ap->a_vap->va_mtime;
if (c)
getnanotime(&de->de_ctime);
return (0);
}
static int
devfs_symlink(ap)
struct vop_symlink_args /* {
@ -530,7 +578,7 @@ devfs_symlink(ap)
struct devfs_dirent *de;
struct devfs_mount *dmp;
dmp = (struct devfs_mount *)ap->a_dvp->v_mount->mnt_data;
dmp = VFSTODEVFS(ap->a_dvp->v_mount);
dd = ap->a_dvp->v_data;
de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
de->de_uid = 0;
@ -543,27 +591,11 @@ devfs_symlink(ap)
bcopy(ap->a_target, de->de_symlink, i);
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0);
VREF(*(ap->a_vpp));
return (0);
}
/*
* Print out the contents of a devfs vnode.
*/
/* ARGSUSED */
static int
devfs_print(ap)
struct vop_print_args /* {
struct vnode *a_vp;
} */ *ap;
{
printf("tag VT_DEVFS, devfs vnode\n");
return (0);
}
/*
* Kernfs "should never get here" operation
* DEVFS "should never get here" operation
*/
static int
devfs_badop()