svn commit: r211226 - head/sys/fs/devfs

Jaakko Heinonen jh at FreeBSD.org
Thu Aug 12 15:29:07 UTC 2010


Author: jh
Date: Thu Aug 12 15:29:07 2010
New Revision: 211226
URL: http://svn.freebsd.org/changeset/base/211226

Log:
  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)

Modified:
  head/sys/fs/devfs/devfs.h
  head/sys/fs/devfs/devfs_devs.c
  head/sys/fs/devfs/devfs_vnops.c

Modified: head/sys/fs/devfs/devfs.h
==============================================================================
--- head/sys/fs/devfs/devfs.h	Thu Aug 12 15:15:30 2010	(r211225)
+++ head/sys/fs/devfs/devfs.h	Thu Aug 12 15:29:07 2010	(r211226)
@@ -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_mo
 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 */
 

Modified: head/sys/fs/devfs/devfs_devs.c
==============================================================================
--- head/sys/fs/devfs/devfs_devs.c	Thu Aug 12 15:15:30 2010	(r211225)
+++ head/sys/fs/devfs/devfs_devs.c	Thu Aug 12 15:29:07 2010	(r211226)
@@ -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, ch
 	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 *
 	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 *
 				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 *
 			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

Modified: head/sys/fs/devfs/devfs_vnops.c
==============================================================================
--- head/sys/fs/devfs/devfs_vnops.c	Thu Aug 12 15:15:30 2010	(r211225)
+++ head/sys/fs/devfs/devfs_vnops.c	Thu Aug 12 15:29:07 2010	(r211226)
@@ -822,7 +822,7 @@ devfs_lookupx(struct vop_lookup_args *ap
 		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 *a
 	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 *a
 {
 	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 *a
 #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));
 }
 


More information about the svn-src-head mailing list