Allow user created symbolic links to cover device files and directories
if the device file appears during or after the link creation. User created symbolic links are now inserted at the head of the directory entry list after the "." and ".." entries. A new directory entry flag DE_COVERED indicates that an entry is covered by a symbolic link. PR: kern/114057 Reviewed by: kib Idea from: kib Discussed on: freebsd-current (mostly silence)
This commit is contained in:
parent
2c4575477e
commit
64040d3978
@ -126,10 +126,11 @@ struct devfs_dirent {
|
||||
struct cdev_priv *de_cdp;
|
||||
int de_inode;
|
||||
int de_flags;
|
||||
#define DE_WHITEOUT 0x1
|
||||
#define DE_DOT 0x2
|
||||
#define DE_DOTDOT 0x4
|
||||
#define DE_DOOMED 0x8
|
||||
#define DE_WHITEOUT 0x01
|
||||
#define DE_DOT 0x02
|
||||
#define DE_DOTDOT 0x04
|
||||
#define DE_DOOMED 0x08
|
||||
#define DE_COVERED 0x10
|
||||
int de_holdcnt;
|
||||
struct dirent *de_dirent;
|
||||
TAILQ_ENTRY(devfs_dirent) de_list;
|
||||
@ -182,7 +183,7 @@ void devfs_unmount_final(struct devfs_mount *mp);
|
||||
struct devfs_dirent *devfs_newdirent (char *name, int namelen);
|
||||
struct devfs_dirent *devfs_parent_dirent(struct devfs_dirent *de);
|
||||
struct devfs_dirent *devfs_vmkdir (struct devfs_mount *, char *name, int namelen, struct devfs_dirent *dotdot, u_int inode);
|
||||
struct devfs_dirent *devfs_find (struct devfs_dirent *dd, const char *name, int namelen);
|
||||
struct devfs_dirent *devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
@ -158,13 +158,15 @@ devfs_free(struct cdev *cdev)
|
||||
}
|
||||
|
||||
struct devfs_dirent *
|
||||
devfs_find(struct devfs_dirent *dd, const char *name, int namelen)
|
||||
devfs_find(struct devfs_dirent *dd, const char *name, int namelen, int type)
|
||||
{
|
||||
struct devfs_dirent *de;
|
||||
|
||||
TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
|
||||
if (namelen != de->de_dirent->d_namlen)
|
||||
continue;
|
||||
if (type != 0 && type != de->de_dirent->d_type)
|
||||
continue;
|
||||
if (bcmp(name, de->de_dirent->d_name, namelen) != 0)
|
||||
continue;
|
||||
break;
|
||||
@ -235,14 +237,19 @@ devfs_vmkdir(struct devfs_mount *dmp, char *name, int namelen, struct devfs_dire
|
||||
else
|
||||
dd->de_inode = alloc_unr(devfs_inos);
|
||||
|
||||
/* Create the "." entry in the new directory */
|
||||
/*
|
||||
* "." and ".." are always the two first entries in the
|
||||
* de_dlist list.
|
||||
*
|
||||
* Create the "." entry in the new directory.
|
||||
*/
|
||||
de = devfs_newdirent(".", 1);
|
||||
de->de_dirent->d_type = DT_DIR;
|
||||
de->de_flags |= DE_DOT;
|
||||
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
|
||||
de->de_dir = dd;
|
||||
|
||||
/* Create the ".." entry in the new directory */
|
||||
/* Create the ".." entry in the new directory. */
|
||||
de = devfs_newdirent("..", 2);
|
||||
de->de_dirent->d_type = DT_DIR;
|
||||
de->de_flags |= DE_DOTDOT;
|
||||
@ -382,7 +389,7 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
|
||||
struct devfs_dirent *de;
|
||||
struct devfs_dirent *dd;
|
||||
struct cdev *pdev;
|
||||
int j;
|
||||
int de_flags, j;
|
||||
char *q, *s;
|
||||
|
||||
sx_assert(&dm->dm_lock, SX_XLOCKED);
|
||||
@ -454,12 +461,27 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
|
||||
continue;
|
||||
if (*q != '/')
|
||||
break;
|
||||
de = devfs_find(dd, s, q - s);
|
||||
de = devfs_find(dd, s, q - s, 0);
|
||||
if (de == NULL)
|
||||
de = devfs_vmkdir(dm, s, q - s, dd, 0);
|
||||
else if (de->de_dirent->d_type == DT_LNK) {
|
||||
de = devfs_find(dd, s, q - s, DT_DIR);
|
||||
if (de == NULL)
|
||||
de = devfs_vmkdir(dm, s, q - s, dd, 0);
|
||||
de->de_flags |= DE_COVERED;
|
||||
}
|
||||
s = q + 1;
|
||||
dd = de;
|
||||
KASSERT(dd->de_dirent->d_type == DT_DIR &&
|
||||
(dd->de_flags & (DE_DOT | DE_DOTDOT)) == 0,
|
||||
("%s: invalid directory (si_name=%s)",
|
||||
__func__, cdp->cdp_c.si_name));
|
||||
|
||||
}
|
||||
de_flags = 0;
|
||||
de = devfs_find(dd, s, q - s, DT_LNK);
|
||||
if (de != NULL)
|
||||
de_flags |= DE_COVERED;
|
||||
|
||||
de = devfs_newdirent(s, q - s);
|
||||
if (cdp->cdp_c.si_flags & SI_ALIAS) {
|
||||
@ -477,6 +499,7 @@ devfs_populate_loop(struct devfs_mount *dm, int cleanup)
|
||||
de->de_mode = cdp->cdp_c.si_mode;
|
||||
de->de_dirent->d_type = DT_CHR;
|
||||
}
|
||||
de->de_flags |= de_flags;
|
||||
de->de_inode = cdp->cdp_inode;
|
||||
de->de_cdp = cdp;
|
||||
#ifdef MAC
|
||||
|
@ -822,7 +822,7 @@ devfs_lookupx(struct vop_lookup_args *ap, int *dm_unlock)
|
||||
return (ENOENT);
|
||||
}
|
||||
dd = dvp->v_data;
|
||||
de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen);
|
||||
de = devfs_find(dd, cnp->cn_nameptr, cnp->cn_namelen, 0);
|
||||
while (de == NULL) { /* While(...) so we can use break */
|
||||
|
||||
if (nameiop == DELETE)
|
||||
@ -1151,7 +1151,7 @@ devfs_readdir(struct vop_readdir_args *ap)
|
||||
off = 0;
|
||||
TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
|
||||
KASSERT(dd->de_cdp != (void *)0xdeadc0de, ("%s %d\n", __func__, __LINE__));
|
||||
if (dd->de_flags & DE_WHITEOUT)
|
||||
if (dd->de_flags & (DE_COVERED | DE_WHITEOUT))
|
||||
continue;
|
||||
if (devfs_prison_check(dd, uio->uio_td))
|
||||
continue;
|
||||
@ -1232,7 +1232,7 @@ devfs_remove(struct vop_remove_args *ap)
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct devfs_dirent *dd;
|
||||
struct devfs_dirent *de;
|
||||
struct devfs_dirent *de, *de_covered;
|
||||
struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
|
||||
|
||||
sx_xlock(&dmp->dm_lock);
|
||||
@ -1240,6 +1240,12 @@ devfs_remove(struct vop_remove_args *ap)
|
||||
de = vp->v_data;
|
||||
if (de->de_cdp == NULL) {
|
||||
TAILQ_REMOVE(&dd->de_dlist, de, de_list);
|
||||
if (de->de_dirent->d_type == DT_LNK) {
|
||||
de_covered = devfs_find(dd, de->de_dirent->d_name,
|
||||
de->de_dirent->d_namlen, 0);
|
||||
if (de_covered != NULL)
|
||||
de_covered->de_flags &= ~DE_COVERED;
|
||||
}
|
||||
devfs_delete(dmp, de, 1);
|
||||
} else {
|
||||
de->de_flags |= DE_WHITEOUT;
|
||||
@ -1479,7 +1485,7 @@ devfs_symlink(struct vop_symlink_args *ap)
|
||||
{
|
||||
int i, error;
|
||||
struct devfs_dirent *dd;
|
||||
struct devfs_dirent *de;
|
||||
struct devfs_dirent *de, *de_covered, *de_dotdot;
|
||||
struct devfs_mount *dmp;
|
||||
|
||||
error = priv_check(curthread, PRIV_DEVFS_SYMLINK);
|
||||
@ -1500,7 +1506,18 @@ devfs_symlink(struct vop_symlink_args *ap)
|
||||
#ifdef MAC
|
||||
mac_devfs_create_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
|
||||
#endif
|
||||
TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
|
||||
de_covered = devfs_find(dd, de->de_dirent->d_name,
|
||||
de->de_dirent->d_namlen, 0);
|
||||
if (de_covered != NULL) {
|
||||
KASSERT((de_covered->de_flags & DE_COVERED) == 0,
|
||||
("devfs_symlink: entry %p already covered", de_covered));
|
||||
de_covered->de_flags |= DE_COVERED;
|
||||
}
|
||||
|
||||
de_dotdot = TAILQ_FIRST(&dd->de_dlist); /* "." */
|
||||
de_dotdot = TAILQ_NEXT(de_dotdot, de_list); /* ".." */
|
||||
TAILQ_INSERT_AFTER(&dd->de_dlist, de_dotdot, de, de_list);
|
||||
|
||||
return (devfs_allocv(de, ap->a_dvp->v_mount, LK_EXCLUSIVE, ap->a_vpp));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user