*BSD News Article 14680


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!agate!howland.reston.ans.net!paladin.american.edu!news.univie.ac.at!fstgds15.tu-graz.ac.at!fstgds01.tu-graz.ac.at!not-for-mail
From: chmr@edvz.tu-graz.ac.at (Christoph Robitschko)
Newsgroups: comp.os.386bsd.bugs
Subject: Patch for hanging console
Date: 19 Apr 1993 12:13:00 +0200
Organization: Technical University of Graz, Austria
Lines: 149
Message-ID: <1qttvcINNno2@fstgds01.tu-graz.ac.at>
NNTP-Posting-Host: fstgds01.tu-graz.ac.at
X-Newsreader: TIN [version 1.1 PL7]

This patch fixes the hanging console problem. The problem was that the console
can be accessed through two drivers (major device numbers), so the
reference count on the vnode does not represent the actual use count
of the console device. Because of this, the device close routine can be
called even though the device is still open through the other major number,
such hanging the device.

To see the problem:
Log in on the /dev/vga (for pccons) or /dev/tty01 (for syscons-0.*) device,
and kill all processes that have /dev/console open (normally only syslogd).
Your shell on /dev/vga will no longer accept keyboard input, so make sure
you can log in over the network or another virtual screen. To re-enable the
console, type "sleep 1000000 < /dev/console &".

Alternatively, boot to single-user mode and type "echo > /dev/vga".

My fix creates a temporary vnode for the device where the console is 
mapped to, and keeps a reference on it as long as /dev/console is open.
The patch is based on patchkit-0.2.2 .

							Christoph


=== Cut here -- start of patch ===
*** /sys/i386/i386/cons.c.pk022	Mon Apr 19 10:46:08 1993
--- /sys/i386/i386/cons.c	Mon Apr 19 10:52:58 1993
***************
*** 56,61 ****
--- 56,62 ----
  #include "sys/tty.h"
  #include "sys/file.h"
  #include "sys/conf.h"
+ #include "sys/vnode.h"
  
  #include "cons.h"
  
*************** cninit()
*** 105,118 ****
--- 106,130 ----
  	(*cp->cn_init)(cp);
  }
  
+ static struct vnode	*cnopenvp = NULLVP;
+ 
+ 
  cnopen(dev, flag, mode, p)
  	dev_t dev;
  	int flag, mode;
  	struct proc *p;
  {
+ 	int		error;
+ 
+ 
  	if (cn_tab == NULL)
  		return (0);
  	dev = cn_tab->cn_dev;
+ 	if (cnopenvp == NULLVP)
+ 		if ((error = getdevvp(dev, &cnopenvp, VCHR))) {
+ 			printf("cnopen: getdevvp returned %d !\n", error);
+ 			return(error);
+ 		}
  	return ((*cdevsw[major(dev)].d_open)(dev, flag, mode, p));
  }
   
*************** cnclose(dev, flag, mode, p)
*** 121,130 ****
  	int flag, mode;
  	struct proc *p;
  {
  	if (cn_tab == NULL)
  		return (0);
  	dev = cn_tab->cn_dev;
! 	return ((*cdevsw[major(dev)].d_close)(dev, flag, mode, p));
  }
   
  cnread(dev, uio, flag)
--- 133,153 ----
  	int flag, mode;
  	struct proc *p;
  {
+ 	int		error;
+ 
+ 
  	if (cn_tab == NULL)
  		return (0);
  	dev = cn_tab->cn_dev;
! 	if (vcount(cnopenvp) <= 1)
! 		error = (*cdevsw[major(dev)].d_close)(dev, flag, mode, p);
! 	else
! 		error = 0;
! 	if (error == 0) {
! 		vrele(cnopenvp);
! 		cnopenvp = NULLVP;
! 	return(error);
! 	}
  }
   
  cnread(dev, uio, flag)
*** /sys/kern/vfs_subr.c.01ori	Mon Apr 19 10:53:55 1993
--- /sys/kern/vfs_subr.c	Mon Apr 19 10:58:55 1993
*************** bdevvp(dev, vpp)
*** 554,559 ****
--- 554,573 ----
  	dev_t dev;
  	struct vnode **vpp;
  {
+ 	return(getdevvp(dev, vpp, VBLK));
+ }
+ 
+ 
+ /*
+  * Create a vnode for a device.
+  * Used by bdevvp (block device) for root file system etc.,
+  * and by cnopen for console (character device).
+  */
+ getdevvp(dev, vpp, type)
+ 	dev_t dev;
+ 	struct vnode **vpp;
+ 	enum vtype type;
+ {
  	register struct vnode *vp;
  	struct vnode *nvp;
  	int error;
*************** bdevvp(dev, vpp)
*** 562,572 ****
  		return (0);
  	error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
  	if (error) {
! 		*vpp = 0;
  		return (error);
  	}
  	vp = nvp;
! 	vp->v_type = VBLK;
  	if (nvp = checkalias(vp, dev, (struct mount *)0)) {
  		vput(vp);
  		vp = nvp;
--- 576,586 ----
  		return (0);
  	error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
  	if (error) {
! 		*vpp = NULLVP;
  		return (error);
  	}
  	vp = nvp;
! 	vp->v_type = type;
  	if (nvp = checkalias(vp, dev, (struct mount *)0)) {
  		vput(vp);
  		vp = nvp;
=== End of patch ===