Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/zcore: conditionally clear memory on reipl

Currently zcore_reipl_write() always use DIAG308_LOAD_CLEAR to ipl the
system (used by ngdump and zfcpdump to ipl the original kernel after
dumping).
Instead of 'always clear' check OS_INFO_FLAG_REIPL_CLEAR flag and use
either LOAD_CLEAR or LOAD_NORMAL diag308 subcode accordingly.
For that read os_info and check for the valid os_info flags entry
in zcore_reipl_init(). Do not return error on failure (e.g. os_info
checksum error) in order to continue dump processing, considering
that os_info could be corrupted on the panicked system.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>

authored by

Mikhail Zaslonko and committed by
Alexander Gordeev
9f70bc89 31e9ccc6

+40 -1
+40 -1
drivers/s390/char/zcore.c
··· 51 51 static struct dentry *zcore_reipl_file; 52 52 static struct dentry *zcore_hsa_file; 53 53 static struct ipl_parameter_block *zcore_ipl_block; 54 + static unsigned long os_info_flags; 54 55 55 56 static DEFINE_MUTEX(hsa_buf_mutex); 56 57 static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE); ··· 140 139 { 141 140 if (zcore_ipl_block) { 142 141 diag308(DIAG308_SET, zcore_ipl_block); 143 - diag308(DIAG308_LOAD_CLEAR, NULL); 142 + if (os_info_flags & OS_INFO_FLAG_REIPL_CLEAR) 143 + diag308(DIAG308_LOAD_CLEAR, NULL); 144 + /* Use special diag308 subcode for CCW normal ipl */ 145 + if (zcore_ipl_block->pb0_hdr.pbt == IPL_PBT_CCW) 146 + diag308(DIAG308_LOAD_NORMAL_DUMP, NULL); 147 + else 148 + diag308(DIAG308_LOAD_NORMAL, NULL); 144 149 } 145 150 return count; 146 151 } ··· 219 212 */ 220 213 static int __init zcore_reipl_init(void) 221 214 { 215 + struct os_info_entry *entry; 222 216 struct ipib_info ipib_info; 217 + unsigned long os_info_addr; 218 + struct os_info *os_info; 223 219 int rc; 224 220 225 221 rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info)); ··· 244 234 free_page((unsigned long) zcore_ipl_block); 245 235 zcore_ipl_block = NULL; 246 236 } 237 + /* 238 + * Read the bit-flags field from os_info flags entry. 239 + * Return zero even for os_info read or entry checksum errors in order 240 + * to continue dump processing, considering that os_info could be 241 + * corrupted on the panicked system. 242 + */ 243 + os_info = (void *)__get_free_page(GFP_KERNEL); 244 + if (!os_info) 245 + return -ENOMEM; 246 + rc = memcpy_hsa_kernel(&os_info_addr, __LC_OS_INFO, sizeof(os_info_addr)); 247 + if (rc) 248 + goto out; 249 + if (os_info_addr < sclp.hsa_size) 250 + rc = memcpy_hsa_kernel(os_info, os_info_addr, PAGE_SIZE); 251 + else 252 + rc = memcpy_real(os_info, os_info_addr, PAGE_SIZE); 253 + if (rc || os_info_csum(os_info) != os_info->csum) 254 + goto out; 255 + entry = &os_info->entry[OS_INFO_FLAGS_ENTRY]; 256 + if (entry->addr && entry->size) { 257 + if (entry->addr < sclp.hsa_size) 258 + rc = memcpy_hsa_kernel(&os_info_flags, entry->addr, sizeof(os_info_flags)); 259 + else 260 + rc = memcpy_real(&os_info_flags, entry->addr, sizeof(os_info_flags)); 261 + if (rc || (__force u32)csum_partial(&os_info_flags, entry->size, 0) != entry->csum) 262 + os_info_flags = 0; 263 + } 264 + out: 265 + free_page((unsigned long)os_info); 247 266 return 0; 248 267 } 249 268