From nobody@FreeBSD.org  Tue Jun 26 22:22:08 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 1781316A46E
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 26 Jun 2007 22:22:08 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 0761A13C46A
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 26 Jun 2007 22:22:08 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l5QMM7YV081919
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 26 Jun 2007 22:22:07 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l5QMM7V8081917;
	Tue, 26 Jun 2007 22:22:07 GMT
	(envelope-from nobody)
Message-Id: <200706262222.l5QMM7V8081917@www.freebsd.org>
Date: Tue, 26 Jun 2007 22:22:07 GMT
From: Stef Walter <stef@memberwebs.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: devfs symlink over device doesn't work
X-Send-Pr-Version: www-3.0

>Number:         114057
>Category:       kern
>Synopsis:       [devfs] devfs symlink over device doesn't work
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun 26 22:30:03 GMT 2007
>Closed-Date:    Wed Nov 07 16:56:05 UTC 2012
>Last-Modified:  Wed Nov 07 16:56:05 UTC 2012
>Originator:     Stef Walter
>Release:        FreeBSD 6.2
>Organization:
>Environment:
FreeBSD jail-devel-6x.ws.local 6.2-RELEASE-p1 FreeBSD 6.2-RELEASE-p1 #2: Tue Jun 26 15:55:31 UTC 2007     root@jail-devel-6x.ws.local:/usr/src/sys/i386/compile/JAIL-DEVEL  i386

>Description:
After deleting a device in devfs, any symlink placed over it results in
ENOENT.

I'll attach a patch that fixes this.

>How-To-Repeat:
  # cd /dev
  # rm console
  # touch /var/log/console
  # ln -s /var/log/console console
  # ls -l console
  ls: console: No such file or directory

>Fix:


Patch attached with submission follows:

--- sys/fs/devfs/devfs_vnops.c.orig	Mon Oct 30 15:46:29 2006
+++ sys/fs/devfs/devfs_vnops.c	Tue Jun 26 16:16:24 2007
@@ -1263,7 +1263,7 @@
 #ifdef MAC
 	mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
 #endif
-	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
+	TAILQ_INSERT_HEAD(&dd->de_dlist, de, de_list);
 	return (devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td));
 }
 


>Release-Note:
>Audit-Trail:

From: Remko Lodder <remko@FreeBSD.org>
To: Stef Walter <stef@memberwebs.com>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/114057: devfs symlink over device doesn't work
Date: Wed, 27 Jun 2007 00:51:46 +0200

 Stef Walter wrote:
 > 
 >> How-To-Repeat:
 >   # cd /dev
 >   # rm console
 >   # touch /var/log/console
 >   # ln -s /var/log/console console
 >   # ls -l console
 >   ls: console: No such file or directory
 > 
 >> Fix:
 > 
 > 
 > Patch attached with submission follows:
 > 
 > --- sys/fs/devfs/devfs_vnops.c.orig	Mon Oct 30 15:46:29 2006
 > +++ sys/fs/devfs/devfs_vnops.c	Tue Jun 26 16:16:24 2007
 > @@ -1263,7 +1263,7 @@
 >  #ifdef MAC
 >  	mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
 >  #endif
 > -	TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
 > +	TAILQ_INSERT_HEAD(&dd->de_dlist, de, de_list);
 >  	return (devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td));
 >  }
 >  
 > 
 
 (i am unfamiliar with devfs): Isn't this somethign that devfs
 maintains? If you remove something under /dev then devfs doesn't
 take that into account yet, and any new thing arriving there
 which isn't under control of devfs gets ignored? In my opinion
 now that we have devfs, that should manage everything in /dev
 and if you want to do something fancy with that, it falls outside
 of regular configurations and thus might or might not work.
 
 That said I will repeat that i am unfamiliar with devfs so the
 idea behind it might be totally different from what I think is
 the focus for devfs.
 
 Regards,
 remko
 
 -- 
 Kind regards,
 
      Remko Lodder               ** remko@elvandar.org
      FreeBSD                    ** remko@FreeBSD.org
 
      /* Quis custodiet ipsos custodes */

From: Stef Walter <stef@memberwebs.com>
To: Remko Lodder <remko@FreeBSD.org>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/114057: devfs symlink over device doesn't work
Date: Wed, 27 Jun 2007 01:55:39 +0000 (UTC)

 Remko Lodder wrote:
 > (i am unfamiliar with devfs): Isn't this somethign that devfs
 > maintains? 
 
 In the case of the main system, yes. But when you're working with jails
 or other 'secondary' devfs mounts it's often necessary to 'redirect'
 certain devices to things elsewhere via symlink.
 
 Another example might be symlinking a device to /dev/null, which this
 patch enables.
 
 > In my opinion
 > now that we have devfs, that should manage everything in /dev
 > and if you want to do something fancy with that, it falls outside
 > of regular configurations and thus might or might not work.
 
 Yes, that's generally true. However the devfs rules and symlink support
 is there for cases where you need to customize the location and/or
 presence of devices. This patch just makes it work as expected.
 
 Cheers,
 Stef Walter
 
 
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Wed Aug 11 14:38:04 UTC 2010 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114057 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/114057: commit references a PR
Date: Thu, 12 Aug 2010 15:31:01 +0000 (UTC)

 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));
  }
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jh 
State-Changed-When: Thu Aug 12 15:52:52 UTC 2010 
State-Changed-Why:  
Patched in head (r211226). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114057 
State-Changed-From-To: patched->closed 
State-Changed-By: jh 
State-Changed-When: Wed Nov 7 16:54:44 UTC 2012 
State-Changed-Why:  
Fixed in head and stable/9. 

I have no plans to MFC the fix to stable/8 unless specifically 
requested. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=114057 
>Unformatted:
