Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3117

kernel-2.6.18-194.11.1.el5.src.rpm

From: Hans-Joachim Picht <hpicht@redhat.com>
Date: Fri, 13 Mar 2009 17:54:03 +0100
Subject: [s390] dasd: fix race in dasd timer handling
Message-id: 20090313165403.GA32287@redhat.com
O-Subject: [RHEL5 U4 PATCH 1/1] s390 - dasd: fix race in dasd timer handling
Bugzilla: 490128
RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com>

Description
============

If the timer expires just after we check whether it is
still pending and before mod_timer is called, then
mod_timer will setup the timer, return zero and add_timer
will be called as well although the timer is already set.

Solution: Initialize the timer variables at device creation time
and remove all timer_pending checks from dasd functions.
del_timer and mod_timer will do all the necessary
checking themselves and mod_timer will set a timer if it
is not already pending.

Bugzilla
=========

BZ 490128
https://bugzilla.redhat.com/show_bug.cgi?id=490128

Upstream status of the patch:
=============================

The patch is upstream.

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=48cae885d5a896030588978f503c73c5ed5e62b1

Test status:
============

The patch has been tested and fixes the problem.
The fix has been verified by the IBM test department.

Please ACK.

With best regards,

	--Hans

diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 6414a4c..17c7224 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -55,6 +55,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 static int dasd_flush_ccw_queue(struct dasd_device *, int);
 static void dasd_tasklet(struct dasd_device *);
 static void do_kick_device(void *data);
+static void dasd_timeout_device(unsigned long);
 
 /*
  * SECTION: Operations on the device structure.
@@ -101,6 +102,8 @@ dasd_alloc_device(void)
 		     (unsigned long) device);
 	INIT_LIST_HEAD(&device->ccw_queue);
 	init_timer(&device->timer);
+	device->timer.function = dasd_timeout_device;
+	device->timer.data = (unsigned long) device;
 	INIT_WORK(&device->kick_work, do_kick_device, device);
 	device->state = DASD_STATE_NEW;
 	device->target = DASD_STATE_NEW;
@@ -855,19 +858,10 @@ dasd_timeout_device(unsigned long ptr)
 void
 dasd_set_timer(struct dasd_device *device, int expires)
 {
-	if (expires == 0) {
-		if (timer_pending(&device->timer))
-			del_timer(&device->timer);
-		return;
-	}
-	if (timer_pending(&device->timer)) {
-		if (mod_timer(&device->timer, jiffies + expires))
-			return;
-	}
-	device->timer.function = dasd_timeout_device;
-	device->timer.data = (unsigned long) device;
-	device->timer.expires = jiffies + expires;
-	add_timer(&device->timer);
+	if (expires == 0)
+		del_timer(&device->timer);
+	else
+		mod_timer(&device->timer, jiffies + expires);
 }
 
 /*
@@ -876,8 +870,7 @@ dasd_set_timer(struct dasd_device *device, int expires)
 void
 dasd_clear_timer(struct dasd_device *device)
 {
-	if (timer_pending(&device->timer))
-		del_timer(&device->timer);
+	del_timer(&device->timer);
 }
 
 static void