s390/extmem: return correct segment type in __segment_load()
commit 8c42dd78df148c90e48efff204cce38743906a79 upstream. Commitf05f62d042
("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:f05f62d042
("s390/vmem: get rid of memory segment list") Cc: <stable@vger.kernel.org> # 5.9+ Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
be2dad7bc9
commit
6cf48403c4
@ -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;
|
||||
@ -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. */
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user