Skip to content

Commit

Permalink
s390/extmem: return correct segment type in __segment_load()
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
gerald-schaefer authored and hcahca committed Mar 1, 2023
1 parent 9b5c37b commit 8c42dd7
Showing 1 changed file with 7 additions and 5 deletions.
12 changes: 7 additions & 5 deletions arch/s390/mm/extmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,17 @@ segment_overlaps_others (struct dcss_segment *seg)

/*
* real segment loading function, called from segment_load
* Must return either an error code < 0, or the segment type code >= 0
*/
static int
__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
{
unsigned long start_addr, end_addr, dummy;
struct dcss_segment *seg;
int rc, diag_cc;
int rc, diag_cc, segtype;

start_addr = end_addr = 0;
segtype = -1;
seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
if (seg == NULL) {
rc = -ENOMEM;
Expand Down Expand Up @@ -326,9 +328,9 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
seg->res_name[8] = '\0';
strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
seg->res->name = seg->res_name;
rc = seg->vm_segtype;
if (rc == SEG_TYPE_SC ||
((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
segtype = seg->vm_segtype;
if (segtype == SEG_TYPE_SC ||
((segtype == SEG_TYPE_SR || segtype == SEG_TYPE_ER) && !do_nonshared))
seg->res->flags |= IORESOURCE_READONLY;

/* Check for overlapping resources before adding the mapping. */
Expand Down Expand Up @@ -386,7 +388,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
out_free:
kfree(seg);
out:
return rc;
return rc < 0 ? rc : segtype;
}

/*
Expand Down

0 comments on commit 8c42dd7

Please sign in to comment.