From owner-svn-src-all@FreeBSD.ORG Mon Feb 14 08:09:03 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6F11D106566B; Mon, 14 Feb 2011 08:09:03 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 418C68FC12; Mon, 14 Feb 2011 08:09:03 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p1E893IL084416; Mon, 14 Feb 2011 08:09:03 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p1E8937L084414; Mon, 14 Feb 2011 08:09:03 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201102140809.p1E8937L084414@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 14 Feb 2011 08:09:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r218675 - head/sys/geom/sched X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Feb 2011 08:09:03 -0000 Author: luigi Date: Mon Feb 14 08:09:02 2011 New Revision: 218675 URL: http://svn.freebsd.org/changeset/base/218675 Log: Correct a subtle bug in the 'gsched_rr' disk scheduler. The algorithm is supposed to work as follows: in order to prevent starvation, when a new client starts being served we record the start time and reset the counter of bytes served. We then switch to a new client after a certain amount of time or bytes, even if the current one still has pending requests. To avoid charging a new client the time of the first seek, we start counting time when the first request is served. Unfortunately a bug in the previous version of the code failed to set the start time in certain cases, resulting in some processes exceeding their timeslice. The fix (in this patch) is trivial, though it took a while to find out and replicate the bug. Thanks to Tommaso Caprai for investigating and fixing the problem. Submitted by: Tommaso Caprai MFC after: 1 week Modified: head/sys/geom/sched/gs_rr.c Modified: head/sys/geom/sched/gs_rr.c ============================================================================== --- head/sys/geom/sched/gs_rr.c Mon Feb 14 06:06:20 2011 (r218674) +++ head/sys/geom/sched/gs_rr.c Mon Feb 14 08:09:02 2011 (r218675) @@ -71,6 +71,7 @@ enum g_rr_state { /* possible queue flags */ enum g_rr_flags { + /* G_FLAG_COMPLETED means that the field q_slice_end is valid. */ G_FLAG_COMPLETED = 1, /* Completed a req. in the current budget. */ }; @@ -87,7 +88,7 @@ struct g_rr_queue { enum g_rr_state q_status; unsigned int q_service; /* service received so far */ - int q_slice_end; /* actual slice end in ticks */ + int q_slice_end; /* actual slice end time, in ticks */ enum g_rr_flags q_flags; /* queue flags */ struct bio_queue_head q_bioq; @@ -638,14 +639,25 @@ g_rr_done(void *data, struct bio *bp) sc->sc_in_flight--; qp = bp->bio_caller1; - if (qp == sc->sc_active && qp->q_status == G_QUEUE_BUSY) { - if (!(qp->q_flags & G_FLAG_COMPLETED)) { - qp->q_flags |= G_FLAG_COMPLETED; - /* in case we want to make the slice adaptive */ - qp->q_slice_duration = get_bounded(&me.quantum_ms, 2); - qp->q_slice_end = ticks + qp->q_slice_duration; - } + /* + * When the first request for this queue completes, update the + * duration and end of the slice. We do not do it when the + * slice starts to avoid charging to the queue the time for + * the first seek. + */ + if (!(qp->q_flags & G_FLAG_COMPLETED)) { + qp->q_flags |= G_FLAG_COMPLETED; + /* + * recompute the slice duration, in case we want + * to make it adaptive. This is not used right now. + * XXX should we do the same for q_quantum and q_wait_ticks ? + */ + qp->q_slice_duration = get_bounded(&me.quantum_ms, 2); + qp->q_slice_end = ticks + qp->q_slice_duration; + } + + if (qp == sc->sc_active && qp->q_status == G_QUEUE_BUSY) { /* The queue is trying anticipation, start the timer. */ qp->q_status = G_QUEUE_IDLING; /* may make this adaptive */