Skip to content

Commit 8c42dd7

Browse files
gerald-schaeferhcahca
authored andcommitted
s390/extmem: return correct segment type in __segment_load()
Commit f05f62d ("s390/vmem: get rid of memory segment list") reshuffled the call to vmem_add_mapping() in __segment_load(), which now overwrites rc after it was set to contain the segment type code. As result, __segment_load() will now always return 0 on success, which corresponds to the segment type code SEG_TYPE_SW, i.e. a writeable segment. This results in a kernel crash when loading a read-only segment as dcssblk block device, and trying to write to it. Instead of reshuffling code again, make sure to return the segment type on success, and also describe this rather delicate and unexpected logic in the function comment. Also initialize new segtype variable with invalid value, to prevent possible future confusion. Fixes: f05f62d ("s390/vmem: get rid of memory segment list") Cc: <[email protected]> # 5.9+ Signed-off-by: Gerald Schaefer <[email protected]> Reviewed-by: Heiko Carstens <[email protected]> Signed-off-by: Heiko Carstens <[email protected]>
1 parent 9b5c37b commit 8c42dd7

File tree

1 file changed

+7
-5
lines changed

1 file changed

+7
-5
lines changed

arch/s390/mm/extmem.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,15 +289,17 @@ segment_overlaps_others (struct dcss_segment *seg)
289289

290290
/*
291291
* real segment loading function, called from segment_load
292+
* Must return either an error code < 0, or the segment type code >= 0
292293
*/
293294
static int
294295
__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
295296
{
296297
unsigned long start_addr, end_addr, dummy;
297298
struct dcss_segment *seg;
298-
int rc, diag_cc;
299+
int rc, diag_cc, segtype;
299300

300301
start_addr = end_addr = 0;
302+
segtype = -1;
301303
seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
302304
if (seg == NULL) {
303305
rc = -ENOMEM;
@@ -326,9 +328,9 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
326328
seg->res_name[8] = '\0';
327329
strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
328330
seg->res->name = seg->res_name;
329-
rc = seg->vm_segtype;
330-
if (rc == SEG_TYPE_SC ||
331-
((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
331+
segtype = seg->vm_segtype;
332+
if (segtype == SEG_TYPE_SC ||
333+
((segtype == SEG_TYPE_SR || segtype == SEG_TYPE_ER) && !do_nonshared))
332334
seg->res->flags |= IORESOURCE_READONLY;
333335

334336
/* Check for overlapping resources before adding the mapping. */
@@ -386,7 +388,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
386388
out_free:
387389
kfree(seg);
388390
out:
389-
return rc;
391+
return rc < 0 ? rc : segtype;
390392
}
391393

392394
/*

0 commit comments

Comments
 (0)