summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Höppner <hoeppner@linux.ibm.com>2023-10-25 15:24:37 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-12-08 08:43:24 +0100
commitf75617cc8df4155374132f0b500b0b3ebb967458 (patch)
tree846b5e8ec0e47de6b2de9a592946bee1aaa66d2a
parent3f47ef1b1c14cb304dd0713cceb7be166dd09197 (diff)
downloadlinux-f75617cc8df4155374132f0b500b0b3ebb967458.tar.gz
linux-f75617cc8df4155374132f0b500b0b3ebb967458.tar.bz2
linux-f75617cc8df4155374132f0b500b0b3ebb967458.zip
s390/dasd: protect device queue against concurrent access
commit db46cd1e0426f52999d50fa72cfa97fa39952885 upstream. In dasd_profile_start() the amount of requests on the device queue are counted. The access to the device queue is unprotected against concurrent access. With a lot of parallel I/O, especially with alias devices enabled, the device queue can change while dasd_profile_start() is accessing the queue. In the worst case this leads to a kernel panic due to incorrect pointer accesses. Fix this by taking the device lock before accessing the queue and counting the requests. Additionally the check for a valid profile data pointer can be done earlier to avoid unnecessary locking in a hot path. Cc: <stable@vger.kernel.org> Fixes: 4fa52aa7a82f ("[S390] dasd: add enhanced DASD statistics interface") Reviewed-by: Stefan Haberland <sth@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com> Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Link: https://lore.kernel.org/r/20231025132437.1223363-3-sth@linux.ibm.com Signed-off-by: Jens Axboe <axboe@kernel.dk> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/s390/block/dasd.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index c0eee7b00442..1161bbd7eb78 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -725,18 +725,20 @@ static void dasd_profile_start(struct dasd_block *block,
* we count each request only once.
*/
device = cqr->startdev;
- if (device->profile.data) {
- counter = 1; /* request is not yet queued on the start device */
- list_for_each(l, &device->ccw_queue)
- if (++counter >= 31)
- break;
- }
+ if (!device->profile.data)
+ return;
+
+ spin_lock(get_ccwdev_lock(device->cdev));
+ counter = 1; /* request is not yet queued on the start device */
+ list_for_each(l, &device->ccw_queue)
+ if (++counter >= 31)
+ break;
+ spin_unlock(get_ccwdev_lock(device->cdev));
+
spin_lock(&device->profile.lock);
- if (device->profile.data) {
- device->profile.data->dasd_io_nr_req[counter]++;
- if (rq_data_dir(req) == READ)
- device->profile.data->dasd_read_nr_req[counter]++;
- }
+ device->profile.data->dasd_io_nr_req[counter]++;
+ if (rq_data_dir(req) == READ)
+ device->profile.data->dasd_read_nr_req[counter]++;
spin_unlock(&device->profile.lock);
}