From pmedwards@eircom.net  Tue Aug 27 06:37:53 2002
Return-Path: <pmedwards@eircom.net>
Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id E759237B406
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 27 Aug 2002 06:37:52 -0700 (PDT)
Received: from mail04.svc.cra.dublin.eircom.net (mail04.svc.cra.dublin.eircom.net [159.134.118.20])
	by mx1.FreeBSD.org (Postfix) with SMTP id 9AE8343E42
	for <freebsd-gnats-submit@FreeBSD.org>; Tue, 27 Aug 2002 06:37:51 -0700 (PDT)
	(envelope-from pmedwards@eircom.net)
Received: (qmail 82948 messnum 1118165 invoked from network[159.134.237.90/chester.eircom.net]); 27 Aug 2002 13:37:50 -0000
Received: from chester.eircom.net (HELO webmail.eircom.net) (159.134.237.90)
  by mail04.svc.cra.dublin.eircom.net (qp 82948) with SMTP; 27 Aug 2002 13:37:50 -0000
Message-Id: <20020827133751.9AE8343E42@mx1.FreeBSD.org>
Date: Tue, 27 Aug 2002 14:37:21 +0100
From: "Peter Edwards" <pmedwards@eircom.net>
To: freebsd-gnats-submit@FreeBSD.org
Cc: doug@texas.net, grog@freebsd.org, pmedwards@eircom.net
Subject: (No subject)

>Number:         42080
>Category:       kern
>Synopsis:       (No subject)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    gnats-admin
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Aug 27 06:40:01 PDT 2002
>Closed-Date:    Wed Aug 28 14:36:07 PDT 2002
>Last-Modified:  Wed Aug 28 14:36:07 PDT 2002
>Originator:     
>Release:        
>Organization:
>Environment:
>Description:
 This is a multi-part message in MIME format.
 ---------6ELL480NZK8OPLUEHSDOKZRS
 Content-Type: text/plain
 Content-Transfer-Encoding: 7bit
 
 After almost seeing the problem and retracting my near-miss on
 -hackers and being pointed to this PR by Doug, I decided to have a
 look at that area of code again, and I understand the race condition
 properly now
 
 Doug's patch requries aquires splbio() to protect, but the code
 seems to be going to great lengths to avoid that. (contrary to an
 existing comment)
 
 The following patch should protect against the race without requiring
 splbio.  (I don't have a vinum config handy to test it, this is
 more of a mental exercise for myself). It works by making sure the
 inner and outer loops around the BUF_STRATEGY call finish as soon
 as all the BUF_STRATEGYs have been completed, rather than always
 decending down the (possibly inactive) requests. (ie, it only loops on the
 groups as long as there are groups for which we will do IO, and it only loops
 on the elements in the groups as long as there are elements for which we will
 do IO)
 -- 
 Peter Edwards.
 
 
 ---------6ELL480NZK8OPLUEHSDOKZRS
 Content-Type: text/plain
 Content-Disposition: attachment; filename="patch.txt"
 
 Index: vinumrequest.c
 ===================================================================
 RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/dev/vinum/vinumrequest.c,v
 retrieving revision 1.44.2.4
 diff -u -r1.44.2.4 vinumrequest.c
 --- vinumrequest.c	3 Feb 2002 07:10:26 -0000	1.44.2.4
 +++ vinumrequest.c	27 Aug 2002 13:33:26 -0000
 @@ -299,11 +299,11 @@
  int
  launch_requests(struct request *rq, int reviveok)
  {
 -    struct rqgroup *rqg;
 +    struct rqgroup *rqg, *nextrqg;
      int rqno;						    /* loop index */
      struct rqelement *rqe;				    /* current element */
      struct drive *drive;
 -    int rcount;						    /* request count */
 +    int iocount, activegroupcount;
  
      /*
       * First find out whether we're reviving, and the
 @@ -374,7 +374,10 @@
       * This loop happens without any participation
       * of the bottom half, so it requires no
       * protection.
 +     * XXX: the update of rqg->active must mirror the
 +     * calls to BUF_STRATEGY() below.
       */
 +    activegroupcount = 0;
      for (rqg = rq->rqg; rqg != NULL; rqg = rqg->next) {	    /* through the whole request chain */
  	rqg->active = rqg->count;			    /* they're all active */
  	for (rqno = 0; rqno < rqg->count; rqno++) {
 @@ -382,28 +385,31 @@
  	    if (rqe->flags & XFR_BAD_SUBDISK)		    /* this subdisk is bad, */
  		rqg->active--;				    /* one less active request */
  	}
 -	if (rqg->active)				    /* we have at least one active request, */
 +	if (rqg->active) {				    /* we have at least one active request, */
  	    rq->active++;				    /* one more active request group */
 +	    activegroupcount++;
 +	}
      }
  
      /*
       * Now fire off the requests.  In this loop the
       * bottom half could be completing requests
 -     * before we finish, so we need splbio() protection.
 +     * before we finish, so be careful to avoid manipulating rq, and avoid
 +     * accessing it if there's a possibility that the entire request may
 +     * have finished.
       */
 -    for (rqg = rq->rqg; rqg != NULL;) {			    /* through the whole request chain */
 +    for (rqg = rq->rqg; activegroupcount != 0; rqg = nextrqg) {
 +	nextrqg = rqg->next;
  	if (rqg->lockbase >= 0)				    /* this rqg needs a lock first */
  	    rqg->lock = lockrange(rqg->lockbase, rqg->rq->bp, &PLEX[rqg->plexno]);
 -	rcount = rqg->count;
 -	for (rqno = 0; rqno < rcount;) {
 +
 +	KASSERT(rqg->count >= rqg->active, ("vinum: overactive rqg"));
 +	iocount = rqg->count;
 +	if (iocount)
 +	    activegroupcount--;
 +	for (rqno = 0; iocount != 0;) {
  	    rqe = &rqg->rqe[rqno];
  
 -	    /*
 -	     * Point to next rqg before the bottom end
 -	     * changes the structures.
 -	     */
 -	    if (++rqno >= rcount)
 -		rqg = rqg->next;
  	    if ((rqe->flags & XFR_BAD_SUBDISK) == 0) {	    /* this subdisk is good, */
  		drive = &DRIVE[rqe->driveno];		    /* look at drive */
  		drive->active++;
 @@ -429,6 +435,7 @@
  #endif
  		/* fire off the request */
  		BUF_STRATEGY(&rqe->b, 0);
 +		iocount--;
  	    }
  	}
      }
 ---------6ELL480NZK8OPLUEHSDOKZRS--
>How-To-Repeat:
>Fix:
>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->closed 
State-Changed-By: keramida 
State-Changed-When: Wed Aug 28 14:35:42 PDT 2002 
State-Changed-Why:  
Followup to kern/41740 misfiled as a new PR. 

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