tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: race condition between (specfs) device open and close



On 30 Dec 2014, at 09:57, matthew green <mrg%eterna.com.au@localhost> wrote:

> while trying to fix any midi/sequencer issues i've seen in the
> last year, noticed that any attempt to call 'midiplay' on more
> than one midi device at the same time, while not allowed, would
> leave the sequencer device always busy.
> 
> i tracked this down to an ugly race condition inside the
> specfs code.  the problem is that:
> 
> 	t1		t2
> 	opens dev
> 	sd_opencnt++
> 			tries to open dev
> 			sd_opencnt++
> 	closes dev
> 	since sd_opencnt is != 1, does not call close
> 	sd_opencnt--
> 			gets EBUSY
> 		sd_opencnt--
> 
> in this case, the device close routine is never called, and in
> at least the midi case, all future opens return EBUSY due to
> there already being an active open.
> 
> i've spent some time reviewing the specfs code, and i think that
> the below patch fixes these specific problems.  it certainly
> fixes the problem i have with trying to open /dev/music
> concurrently.  it may not be entirely correct or have problems
> i've not seen with it, but atf works fine, as does the last
> couple of days of random testing.
> 
> the main changes are:
> 	- introduce a "dying" flag to the specnode struture,
> 	  and use it appropriately
> 	- add a condvar between open/close and revoke, to
> 	  ensure any revoke succeeds properly.
> 
> i'd like to get this into netbsd 7, so any additional testing
> against that branch or against -current would be greatly
> appreciated.
<snip>
> @@ -397,7 +405,14 @@ spec_node_revoke(vnode_t *vp)
> 	KASSERT(sn->sn_gone == false);
> 
> 	mutex_enter(&device_lock);
> -	KASSERT(sn->sn_opencnt <= sd->sd_opencnt);
> +	sn->sn_dying = true;
> +	while (sn->sn_opencnt > sd->sd_opencnt) {
> +		/*
> +		 * Open is in progress, but not complete, must wait
> +		 * for it to complete.
> +		 */
> +		cv_wait(&specopenclose_cv, &device_lock);
> +	}
> 	if (sn->sn_opencnt != 0) {
> 		sd->sd_opencnt -= (sn->sn_opencnt - 1);
> 		sn->sn_opencnt = 1;

Will this work if we revoke a device whose cdev_open() blocks,
a TTY waiting for carrier for example?

--
J. Hannken-Illjes - hannken%eis.cs.tu-bs.de@localhost - TU Braunschweig (Germany)



Home | Main Index | Thread Index | Old Index