diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-09-16 12:32:18 -0400 |
---|---|---|
committer | Martin Schwidefsky <sky@skybook.(none)> | 2008-09-16 12:34:31 -0400 |
commit | f26fd5d6e5006eae75a389c7ce74ed16761d094b (patch) | |
tree | 0d8f90e4a54d983c4cb49bd751df03d4973e40cf /drivers/s390 | |
parent | bc45eb8950b8c14487385cfd2bda1613ca8d9703 (diff) |
[S390] cio: Fix driver_data handling for ccwgroup devices.
Since 16f7f9564c3ae190954f2ec55f385a268b93ac4d, we've seen
oopses when grouping/ungrouping devices:
Unable to handle kernel pointer dereference at virtual kernel address 0000000000
114000
Oops: 0004 [#1] PREEMPT SMP
Modules linked in: bonding qeth_l2 dm_multipath sunrpc qeth_l3 dm_mod qeth chsc_
sch ccwgroup
CPU: 1 Not tainted 2.6.26-29.x.20080815-s390xdefault #1
Process iperf (pid: 24412, task: 000000003f446038, ksp: 000000003c929e08)
Krnl PSW : 0404d00180000000 000003e00006f6e6 (qeth_irq+0xda/0xb28 [qeth])
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 EA:3
Krnl GPRS: 0000000000000000 000003e000000003 0000000000000000 0000000000114ccc
000000003fb82e48 000003e00006f60c 000000000000000c 000000003ce72100
0000000000114944 000000003fb82e48 0000000000114ccc 000000003fe8fd28
000003e000066000 000003e000076128 000000003fe8fdb8 000000003fe8fd28
Krnl Code: 000003e00006f6da: bf3f2024 icm %r3,15,36(%r2)
000003e00006f6de: a774023c brc 7,3e00006fb56
000003e00006f6e2: a7280000 lhi %r2,0
>000003e00006f6e6: 5020a1a0 st %r2,416(%r10)
000003e00006f6ea: 58109000 l %r1,0(%r9)
000003e00006f6ee: a7111000 tmll %r1,4096
000003e00006f6f2: a77400f9 brc 7,3e00006f8e4
000003e00006f6f6: 8810000c srl %r1,12
Call Trace:
([<000000003fe8fd20>] 0x3fe8fd20)
[<000000000033bf2a>] ccw_device_call_handler+0xb2/0xd8
[<0000000000339e1c>] ccw_device_irq+0x124/0x164
[<0000000000339758>] io_subchannel_irq+0x8c/0x118
[<00000000003309ba>] do_IRQ+0x192/0x1bc
[<0000000000114f66>] io_return+0x0/0x8
[<00000000001149cc>] sysc_do_svc+0x0/0x22
([<0000000000114a18>] sysc_noemu+0x10/0x16)
[<00000200002e047c>] 0x200002e047c
Last Breaking-Event-Address:
[<000003e00006f6d6>] qeth_irq+0xca/0xb28 [qeth]
The problem is that dev->driver_data for a ccw device is NULL,
while it should point to the ccwgroup device it is a member of.
This happened due to incorrect cleanup if creating a ccwgroup
device failed because the ccw devices were already grouped.
Fix this by setting cdev[i] to NULL in the error handling of
ccwgroup_create_from_string() after we give up our reference and
by checking if the driver_data points to the ccwgroup device in
ccwgroup_release() just to be really sure.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index e0ce65fca4e7..9a50f245774b 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -113,7 +113,8 @@ ccwgroup_release (struct device *dev) | |||
113 | 113 | ||
114 | for (i = 0; i < gdev->count; i++) { | 114 | for (i = 0; i < gdev->count; i++) { |
115 | if (gdev->cdev[i]) { | 115 | if (gdev->cdev[i]) { |
116 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | 116 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) |
117 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | ||
117 | put_device(&gdev->cdev[i]->dev); | 118 | put_device(&gdev->cdev[i]->dev); |
118 | } | 119 | } |
119 | } | 120 | } |
@@ -296,6 +297,7 @@ error: | |||
296 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) | 297 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) |
297 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | 298 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); |
298 | put_device(&gdev->cdev[i]->dev); | 299 | put_device(&gdev->cdev[i]->dev); |
300 | gdev->cdev[i] = NULL; | ||
299 | } | 301 | } |
300 | mutex_unlock(&gdev->reg_mutex); | 302 | mutex_unlock(&gdev->reg_mutex); |
301 | put_device(&gdev->dev); | 303 | put_device(&gdev->dev); |