Subject: problem with spec_close() controlling tty hack
To: None <tech-kern@sun-lamp.cs.berkeley.edu>
From: Andrew Herbert <andrew@werple.apana.org.au>
List: tech-kern
Date: 02/10/1994 12:00:59
The hack introduced to spec_close() on 27 Jan '94 appears to sometimes
conflict with the controlling tty cleanup code in kexit(), in that under
certain circumstances it results in the session struct's s_ttyvp being
clobbered just before a vgoneall() is attempted on this vnode pointer.  The
resultant vgoneall(NULL) panics the kernel.

I'm not entirely clear on the benefits of the spec_close() hack, but
assuming it is a Good Thing, below is the counter-hack I'm using in kexit().

A preferable alternate fix which I just thought of would be to test for
!(p->p_flag & SWEXIT) in spec_close() before doing the ttyvp hack.  This
would then remove the need for kexit() to worry about pointers disappearing
from under its nose.  Patch also below.

Comments?

Andrew
--
*** kern_exit.c.unhacked	Wed Feb  9 14:26:16 1994
--- kern_exit.c	Thu Feb 10 10:34:16 1994
***************
*** 152,157 ****
--- 152,162 ----
  				if (sp->s_ttyp->t_pgrp)
  					pgsignal(sp->s_ttyp->t_pgrp, SIGHUP, 1);
  				(void) ttywait(sp->s_ttyp);
+ 				if (!sp->s_ttyvp) {
+ 					log(LOG_WARNING, "kexit(): s_ttyvp for dev(%d,%d) has disappeared!",
+ 					    major(sp->s_ttyp->t_dev), minor(sp->s_ttyp->t_dev));
+ 					goto skip;
+ 				}
  				vgoneall(sp->s_ttyvp);
  			}
  			vrele(sp->s_ttyvp);
***************
*** 162,167 ****
--- 167,173 ----
  			 * (for logging and informational purposes)
  			 */
  		}
+ skip:
  		sp->s_leader = NULL;
  	}
  	fixjobc(p, p->p_pgrp, 0);

Preferred spec_close() patch:

*** spec_vnops.c.unhacked	Thu Feb 10 11:54:40 1994
--- spec_vnops.c	Thu Feb 10 11:55:31 1994
***************
*** 460,466 ****
  		 * if the reference count is 2 (this last descriptor
  		 * plus the session), release the reference from the session.
  		 */
! 		if (vcount(vp) == 2 && p && vp == p->p_session->s_ttyvp) {
  			vrele(vp);
  			p->p_session->s_ttyvp = NULL;
  		}
--- 460,467 ----
  		 * if the reference count is 2 (this last descriptor
  		 * plus the session), release the reference from the session.
  		 */
! 		if (vcount(vp) == 2 && p && !(p->p_flag & SWEXIT) &&
! 		    vp == p->p_session->s_ttyvp) {
  			vrele(vp);
  			p->p_session->s_ttyvp = NULL;
  		}

------------------------------------------------------------------------------