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

Merge tag 'pstore-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull pstore updates from Kees Cook:
"Use normal block device I/O path for pstore/blk. (Christoph Hellwig,
Kees Cook, Pu Lehui)"

* tag 'pstore-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
pstore/blk: Include zone in pstore_device_info
pstore/blk: Fix kerndoc and redundancy on blkdev param
pstore/blk: Use the normal block device I/O path
pstore/blk: Move verify_size() macro out of function
pstore/blk: Improve failure reporting

+169 -281
+7 -7
Documentation/admin-guide/pstore-blk.rst
··· 45 45 The block device to use. Most of the time, it is a partition of block device. 46 46 It's required for pstore/blk. It is also used for MTD device. 47 47 48 - It accepts the following variants for block device: 48 + When pstore/blk is built as a module, "blkdev" accepts the following variants: 49 49 50 - 1. <hex_major><hex_minor> device number in hexadecimal represents itself; no 51 - leading 0x, for example b302. 52 - #. /dev/<disk_name> represents the device number of disk 50 + 1. /dev/<disk_name> represents the device number of disk 53 51 #. /dev/<disk_name><decimal> represents the device number of partition - device 54 52 number of disk plus the partition number 55 53 #. /dev/<disk_name>p<decimal> - same as the above; this form is used when disk 56 54 name of partitioned disk ends with a digit. 55 + 56 + When pstore/blk is built into the kernel, "blkdev" accepts the following variants: 57 + 58 + #. <hex_major><hex_minor> device number in hexadecimal representation, 59 + with no leading 0x, for example b302. 57 60 #. PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF represents the unique id of 58 61 a partition if the partition table provides it. The UUID may be either an 59 62 EFI/GPT UUID, or refer to an MSDOS partition using the format SSSSSSSS-PP, ··· 228 225 :internal: 229 226 230 227 .. kernel-doc:: include/linux/pstore_zone.h 231 - :internal: 232 - 233 - .. kernel-doc:: fs/pstore/blk.c 234 228 :internal: 235 229 236 230 .. kernel-doc:: include/linux/pstore_blk.h
+5 -5
drivers/mtd/mtdpstore.c
··· 423 423 longcnt = BITS_TO_LONGS(div_u64(mtd->size, mtd->erasesize)); 424 424 cxt->badmap = kcalloc(longcnt, sizeof(long), GFP_KERNEL); 425 425 426 - cxt->dev.total_size = mtd->size; 427 426 /* just support dmesg right now */ 428 427 cxt->dev.flags = PSTORE_FLAGS_DMESG; 429 - cxt->dev.read = mtdpstore_read; 430 - cxt->dev.write = mtdpstore_write; 431 - cxt->dev.erase = mtdpstore_erase; 432 - cxt->dev.panic_write = mtdpstore_panic_write; 428 + cxt->dev.zone.read = mtdpstore_read; 429 + cxt->dev.zone.write = mtdpstore_write; 430 + cxt->dev.zone.erase = mtdpstore_erase; 431 + cxt->dev.zone.panic_write = mtdpstore_panic_write; 432 + cxt->dev.zone.total_size = mtd->size; 433 433 434 434 ret = register_pstore_device(&cxt->dev); 435 435 if (ret) {
+154 -245
fs/pstore/blk.c
··· 8 8 9 9 #include <linux/kernel.h> 10 10 #include <linux/module.h> 11 - #include "../../block/blk.h" 12 11 #include <linux/blkdev.h> 13 12 #include <linux/string.h> 14 13 #include <linux/of.h> 15 14 #include <linux/of_address.h> 16 15 #include <linux/platform_device.h> 17 16 #include <linux/pstore_blk.h> 17 + #include <linux/fs.h> 18 + #include <linux/file.h> 19 + #include <linux/init_syscalls.h> 18 20 #include <linux/mount.h> 19 - #include <linux/uio.h> 20 21 21 22 static long kmsg_size = CONFIG_PSTORE_BLK_KMSG_SIZE; 22 23 module_param(kmsg_size, long, 0400); ··· 58 57 59 58 /* 60 59 * blkdev - the block device to use for pstore storage 61 - * 62 - * Usually, this will be a partition of a block device. 63 - * 64 - * blkdev accepts the following variants: 65 - * 1) <hex_major><hex_minor> device number in hexadecimal representation, 66 - * with no leading 0x, for example b302. 67 - * 2) /dev/<disk_name> represents the device number of disk 68 - * 3) /dev/<disk_name><decimal> represents the device number 69 - * of partition - device number of disk plus the partition number 70 - * 4) /dev/<disk_name>p<decimal> - same as the above, that form is 71 - * used when disk name of partitioned disk ends on a digit. 72 - * 5) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the 73 - * unique id of a partition if the partition table provides it. 74 - * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS 75 - * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero- 76 - * filled hex representation of the 32-bit "NT disk signature", and PP 77 - * is a zero-filled hex representation of the 1-based partition number. 78 - * 6) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to 79 - * a partition with a known unique id. 80 - * 7) <major>:<minor> major and minor number of the device separated by 81 - * a colon. 60 + * See Documentation/admin-guide/pstore-blk.rst for details. 82 61 */ 83 62 static char blkdev[80] = CONFIG_PSTORE_BLK_BLKDEV; 84 63 module_param_string(blkdev, blkdev, 80, 0400); ··· 69 88 * during the register/unregister functions. 70 89 */ 71 90 static DEFINE_MUTEX(pstore_blk_lock); 72 - static struct block_device *psblk_bdev; 73 - static struct pstore_zone_info *pstore_zone_info; 74 - 75 - struct bdev_info { 76 - dev_t devt; 77 - sector_t nr_sects; 78 - sector_t start_sect; 79 - }; 91 + static struct file *psblk_file; 92 + static struct pstore_device_info *pstore_device_info; 80 93 81 94 #define check_size(name, alignsize) ({ \ 82 95 long _##name_ = (name); \ ··· 83 108 _##name_; \ 84 109 }) 85 110 111 + #define verify_size(name, alignsize, enabled) { \ 112 + long _##name_; \ 113 + if (enabled) \ 114 + _##name_ = check_size(name, alignsize); \ 115 + else \ 116 + _##name_ = 0; \ 117 + /* Synchronize module parameters with resuls. */ \ 118 + name = _##name_ / 1024; \ 119 + dev->zone.name = _##name_; \ 120 + } 121 + 86 122 static int __register_pstore_device(struct pstore_device_info *dev) 87 123 { 88 124 int ret; 89 125 90 126 lockdep_assert_held(&pstore_blk_lock); 91 127 92 - if (!dev || !dev->total_size || !dev->read || !dev->write) 128 + if (!dev) { 129 + pr_err("NULL device info\n"); 93 130 return -EINVAL; 131 + } 132 + if (!dev->zone.total_size) { 133 + pr_err("zero sized device\n"); 134 + return -EINVAL; 135 + } 136 + if (!dev->zone.read) { 137 + pr_err("no read handler for device\n"); 138 + return -EINVAL; 139 + } 140 + if (!dev->zone.write) { 141 + pr_err("no write handler for device\n"); 142 + return -EINVAL; 143 + } 94 144 95 145 /* someone already registered before */ 96 - if (pstore_zone_info) 146 + if (pstore_device_info) 97 147 return -EBUSY; 98 - 99 - pstore_zone_info = kzalloc(sizeof(struct pstore_zone_info), GFP_KERNEL); 100 - if (!pstore_zone_info) 101 - return -ENOMEM; 102 148 103 149 /* zero means not limit on which backends to attempt to store. */ 104 150 if (!dev->flags) 105 151 dev->flags = UINT_MAX; 106 152 107 - #define verify_size(name, alignsize, enabled) { \ 108 - long _##name_; \ 109 - if (enabled) \ 110 - _##name_ = check_size(name, alignsize); \ 111 - else \ 112 - _##name_ = 0; \ 113 - name = _##name_ / 1024; \ 114 - pstore_zone_info->name = _##name_; \ 115 - } 116 - 153 + /* Copy in module parameters. */ 117 154 verify_size(kmsg_size, 4096, dev->flags & PSTORE_FLAGS_DMESG); 118 155 verify_size(pmsg_size, 4096, dev->flags & PSTORE_FLAGS_PMSG); 119 156 verify_size(console_size, 4096, dev->flags & PSTORE_FLAGS_CONSOLE); 120 157 verify_size(ftrace_size, 4096, dev->flags & PSTORE_FLAGS_FTRACE); 121 - #undef verify_size 158 + dev->zone.max_reason = max_reason; 122 159 123 - pstore_zone_info->total_size = dev->total_size; 124 - pstore_zone_info->max_reason = max_reason; 125 - pstore_zone_info->read = dev->read; 126 - pstore_zone_info->write = dev->write; 127 - pstore_zone_info->erase = dev->erase; 128 - pstore_zone_info->panic_write = dev->panic_write; 129 - pstore_zone_info->name = KBUILD_MODNAME; 130 - pstore_zone_info->owner = THIS_MODULE; 160 + /* Initialize required zone ownership details. */ 161 + dev->zone.name = KBUILD_MODNAME; 162 + dev->zone.owner = THIS_MODULE; 131 163 132 - ret = register_pstore_zone(pstore_zone_info); 133 - if (ret) { 134 - kfree(pstore_zone_info); 135 - pstore_zone_info = NULL; 136 - } 164 + ret = register_pstore_zone(&dev->zone); 165 + if (ret == 0) 166 + pstore_device_info = dev; 167 + 137 168 return ret; 138 169 } 139 170 /** ··· 166 185 static void __unregister_pstore_device(struct pstore_device_info *dev) 167 186 { 168 187 lockdep_assert_held(&pstore_blk_lock); 169 - if (pstore_zone_info && pstore_zone_info->read == dev->read) { 170 - unregister_pstore_zone(pstore_zone_info); 171 - kfree(pstore_zone_info); 172 - pstore_zone_info = NULL; 188 + if (pstore_device_info && pstore_device_info == dev) { 189 + unregister_pstore_zone(&dev->zone); 190 + pstore_device_info = NULL; 173 191 } 174 192 } 175 193 ··· 185 205 } 186 206 EXPORT_SYMBOL_GPL(unregister_pstore_device); 187 207 188 - /** 189 - * psblk_get_bdev() - open block device 190 - * 191 - * @holder: Exclusive holder identifier 192 - * @info: Information about bdev to fill in 193 - * 194 - * Return: pointer to block device on success and others on error. 195 - * 196 - * On success, the returned block_device has reference count of one. 197 - */ 198 - static struct block_device *psblk_get_bdev(void *holder, 199 - struct bdev_info *info) 200 - { 201 - struct block_device *bdev = ERR_PTR(-ENODEV); 202 - fmode_t mode = FMODE_READ | FMODE_WRITE; 203 - sector_t nr_sects; 204 - 205 - lockdep_assert_held(&pstore_blk_lock); 206 - 207 - if (pstore_zone_info) 208 - return ERR_PTR(-EBUSY); 209 - 210 - if (!blkdev[0]) 211 - return ERR_PTR(-ENODEV); 212 - 213 - if (holder) 214 - mode |= FMODE_EXCL; 215 - bdev = blkdev_get_by_path(blkdev, mode, holder); 216 - if (IS_ERR(bdev)) { 217 - dev_t devt; 218 - 219 - devt = name_to_dev_t(blkdev); 220 - if (devt == 0) 221 - return ERR_PTR(-ENODEV); 222 - bdev = blkdev_get_by_dev(devt, mode, holder); 223 - if (IS_ERR(bdev)) 224 - return bdev; 225 - } 226 - 227 - nr_sects = bdev_nr_sectors(bdev); 228 - if (!nr_sects) { 229 - pr_err("not enough space for '%s'\n", blkdev); 230 - blkdev_put(bdev, mode); 231 - return ERR_PTR(-ENOSPC); 232 - } 233 - 234 - if (info) { 235 - info->devt = bdev->bd_dev; 236 - info->nr_sects = nr_sects; 237 - info->start_sect = get_start_sect(bdev); 238 - } 239 - 240 - return bdev; 241 - } 242 - 243 - static void psblk_put_bdev(struct block_device *bdev, void *holder) 244 - { 245 - fmode_t mode = FMODE_READ | FMODE_WRITE; 246 - 247 - lockdep_assert_held(&pstore_blk_lock); 248 - 249 - if (!bdev) 250 - return; 251 - 252 - if (holder) 253 - mode |= FMODE_EXCL; 254 - blkdev_put(bdev, mode); 255 - } 256 - 257 208 static ssize_t psblk_generic_blk_read(char *buf, size_t bytes, loff_t pos) 258 209 { 259 - struct block_device *bdev = psblk_bdev; 260 - struct file file; 261 - struct kiocb kiocb; 262 - struct iov_iter iter; 263 - struct kvec iov = {.iov_base = buf, .iov_len = bytes}; 264 - 265 - if (!bdev) 266 - return -ENODEV; 267 - 268 - memset(&file, 0, sizeof(struct file)); 269 - file.f_mapping = bdev->bd_inode->i_mapping; 270 - file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME; 271 - file.f_inode = bdev->bd_inode; 272 - file_ra_state_init(&file.f_ra, file.f_mapping); 273 - 274 - init_sync_kiocb(&kiocb, &file); 275 - kiocb.ki_pos = pos; 276 - iov_iter_kvec(&iter, READ, &iov, 1, bytes); 277 - 278 - return generic_file_read_iter(&kiocb, &iter); 210 + return kernel_read(psblk_file, buf, bytes, &pos); 279 211 } 280 212 281 213 static ssize_t psblk_generic_blk_write(const char *buf, size_t bytes, 282 214 loff_t pos) 283 215 { 284 - struct block_device *bdev = psblk_bdev; 285 - struct iov_iter iter; 286 - struct kiocb kiocb; 287 - struct file file; 288 - ssize_t ret; 289 - struct kvec iov = {.iov_base = (void *)buf, .iov_len = bytes}; 290 - 291 - if (!bdev) 292 - return -ENODEV; 293 - 294 216 /* Console/Ftrace backend may handle buffer until flush dirty zones */ 295 217 if (in_interrupt() || irqs_disabled()) 296 218 return -EBUSY; 297 - 298 - memset(&file, 0, sizeof(struct file)); 299 - file.f_mapping = bdev->bd_inode->i_mapping; 300 - file.f_flags = O_DSYNC | __O_SYNC | O_NOATIME; 301 - file.f_inode = bdev->bd_inode; 302 - 303 - init_sync_kiocb(&kiocb, &file); 304 - kiocb.ki_pos = pos; 305 - iov_iter_kvec(&iter, WRITE, &iov, 1, bytes); 306 - 307 - inode_lock(bdev->bd_inode); 308 - ret = generic_write_checks(&kiocb, &iter); 309 - if (ret > 0) 310 - ret = generic_perform_write(&file, &iter, pos); 311 - inode_unlock(bdev->bd_inode); 312 - 313 - if (likely(ret > 0)) { 314 - const struct file_operations f_op = {.fsync = blkdev_fsync}; 315 - 316 - file.f_op = &f_op; 317 - kiocb.ki_pos += ret; 318 - ret = generic_write_sync(&kiocb, ret); 319 - } 320 - return ret; 219 + return kernel_write(psblk_file, buf, bytes, &pos); 321 220 } 322 221 323 222 /* 324 223 * This takes its configuration only from the module parameters now. 325 - * See psblk_get_bdev() and blkdev. 326 224 */ 327 - static int __register_pstore_blk(void) 225 + static int __register_pstore_blk(struct pstore_device_info *dev, 226 + const char *devpath) 328 227 { 329 - char bdev_name[BDEVNAME_SIZE]; 330 - struct block_device *bdev; 331 - struct pstore_device_info dev; 332 - struct bdev_info binfo; 333 - void *holder = blkdev; 228 + struct inode *inode; 334 229 int ret = -ENODEV; 335 230 336 231 lockdep_assert_held(&pstore_blk_lock); 337 232 338 - /* hold bdev exclusively */ 339 - memset(&binfo, 0, sizeof(binfo)); 340 - bdev = psblk_get_bdev(holder, &binfo); 341 - if (IS_ERR(bdev)) { 342 - pr_err("failed to open '%s'!\n", blkdev); 343 - return PTR_ERR(bdev); 233 + psblk_file = filp_open(devpath, O_RDWR | O_DSYNC | O_NOATIME | O_EXCL, 0); 234 + if (IS_ERR(psblk_file)) { 235 + ret = PTR_ERR(psblk_file); 236 + pr_err("failed to open '%s': %d!\n", devpath, ret); 237 + goto err; 344 238 } 345 239 346 - /* only allow driver matching the @blkdev */ 347 - if (!binfo.devt) { 348 - pr_debug("no major\n"); 349 - ret = -ENODEV; 350 - goto err_put_bdev; 240 + inode = file_inode(psblk_file); 241 + if (!S_ISBLK(inode->i_mode)) { 242 + pr_err("'%s' is not block device!\n", devpath); 243 + goto err_fput; 351 244 } 352 245 353 - /* psblk_bdev must be assigned before register to pstore/blk */ 354 - psblk_bdev = bdev; 246 + inode = I_BDEV(psblk_file->f_mapping->host)->bd_inode; 247 + dev->zone.total_size = i_size_read(inode); 355 248 356 - memset(&dev, 0, sizeof(dev)); 357 - dev.total_size = binfo.nr_sects << SECTOR_SHIFT; 358 - dev.read = psblk_generic_blk_read; 359 - dev.write = psblk_generic_blk_write; 360 - 361 - ret = __register_pstore_device(&dev); 249 + ret = __register_pstore_device(dev); 362 250 if (ret) 363 - goto err_put_bdev; 251 + goto err_fput; 364 252 365 - bdevname(bdev, bdev_name); 366 - pr_info("attached %s (no dedicated panic_write!)\n", bdev_name); 367 253 return 0; 368 254 369 - err_put_bdev: 370 - psblk_bdev = NULL; 371 - psblk_put_bdev(bdev, holder); 255 + err_fput: 256 + fput(psblk_file); 257 + err: 258 + psblk_file = NULL; 259 + 372 260 return ret; 373 - } 374 - 375 - static void __unregister_pstore_blk(unsigned int major) 376 - { 377 - struct pstore_device_info dev = { .read = psblk_generic_blk_read }; 378 - void *holder = blkdev; 379 - 380 - lockdep_assert_held(&pstore_blk_lock); 381 - if (psblk_bdev && MAJOR(psblk_bdev->bd_dev) == major) { 382 - __unregister_pstore_device(&dev); 383 - psblk_put_bdev(psblk_bdev, holder); 384 - psblk_bdev = NULL; 385 - } 386 261 } 387 262 388 263 /* get information of pstore/blk */ ··· 254 419 } 255 420 EXPORT_SYMBOL_GPL(pstore_blk_get_config); 256 421 422 + 423 + #ifndef MODULE 424 + static const char devname[] = "/dev/pstore-blk"; 425 + static __init const char *early_boot_devpath(const char *initial_devname) 426 + { 427 + /* 428 + * During early boot the real root file system hasn't been 429 + * mounted yet, and no device nodes are present yet. Use the 430 + * same scheme to find the device that we use for mounting 431 + * the root file system. 432 + */ 433 + dev_t dev = name_to_dev_t(initial_devname); 434 + 435 + if (!dev) { 436 + pr_err("failed to resolve '%s'!\n", initial_devname); 437 + return initial_devname; 438 + } 439 + 440 + init_unlink(devname); 441 + init_mknod(devname, S_IFBLK | 0600, new_encode_dev(dev)); 442 + 443 + return devname; 444 + } 445 + #else 446 + static inline const char *early_boot_devpath(const char *initial_devname) 447 + { 448 + return initial_devname; 449 + } 450 + #endif 451 + 452 + static int __init __best_effort_init(void) 453 + { 454 + struct pstore_device_info *best_effort_dev; 455 + int ret; 456 + 457 + /* No best-effort mode requested. */ 458 + if (!best_effort) 459 + return 0; 460 + 461 + /* Reject an empty blkdev. */ 462 + if (!blkdev[0]) { 463 + pr_err("blkdev empty with best_effort=Y\n"); 464 + return -EINVAL; 465 + } 466 + 467 + best_effort_dev = kzalloc(sizeof(*best_effort_dev), GFP_KERNEL); 468 + if (!best_effort_dev) 469 + return -ENOMEM; 470 + 471 + best_effort_dev->zone.read = psblk_generic_blk_read; 472 + best_effort_dev->zone.write = psblk_generic_blk_write; 473 + 474 + ret = __register_pstore_blk(best_effort_dev, 475 + early_boot_devpath(blkdev)); 476 + if (ret) 477 + kfree(best_effort_dev); 478 + else 479 + pr_info("attached %s (%zu) (no dedicated panic_write!)\n", 480 + blkdev, best_effort_dev->zone.total_size); 481 + 482 + return ret; 483 + } 484 + 485 + static void __exit __best_effort_exit(void) 486 + { 487 + /* 488 + * Currently, the only user of psblk_file is best_effort, so 489 + * we can assume that pstore_device_info is associated with it. 490 + * Once there are "real" blk devices, there will need to be a 491 + * dedicated pstore_blk_info, etc. 492 + */ 493 + if (psblk_file) { 494 + struct pstore_device_info *dev = pstore_device_info; 495 + 496 + __unregister_pstore_device(dev); 497 + kfree(dev); 498 + fput(psblk_file); 499 + psblk_file = NULL; 500 + } 501 + } 502 + 257 503 static int __init pstore_blk_init(void) 258 504 { 259 - int ret = 0; 505 + int ret; 260 506 261 507 mutex_lock(&pstore_blk_lock); 262 - if (!pstore_zone_info && best_effort && blkdev[0]) 263 - ret = __register_pstore_blk(); 508 + ret = __best_effort_init(); 264 509 mutex_unlock(&pstore_blk_lock); 265 510 266 511 return ret; ··· 350 435 static void __exit pstore_blk_exit(void) 351 436 { 352 437 mutex_lock(&pstore_blk_lock); 353 - if (psblk_bdev) 354 - __unregister_pstore_blk(MAJOR(psblk_bdev->bd_dev)); 355 - else { 356 - struct pstore_device_info dev = { }; 357 - 358 - if (pstore_zone_info) 359 - dev.read = pstore_zone_info->read; 360 - __unregister_pstore_device(&dev); 361 - } 438 + __best_effort_exit(); 439 + /* If we've been asked to unload, unregister any remaining device. */ 440 + __unregister_pstore_device(pstore_device_info); 362 441 mutex_unlock(&pstore_blk_lock); 363 442 } 364 443 module_exit(pstore_blk_exit);
+3 -24
include/linux/pstore_blk.h
··· 10 10 /** 11 11 * struct pstore_device_info - back-end pstore/blk driver structure. 12 12 * 13 - * @total_size: The total size in bytes pstore/blk can use. It must be greater 14 - * than 4096 and be multiple of 4096. 15 13 * @flags: Refer to macro starting with PSTORE_FLAGS defined in 16 14 * linux/pstore.h. It means what front-ends this device support. 17 15 * Zero means all backends for compatible. 18 - * @read: The general read operation. Both of the function parameters 19 - * @size and @offset are relative value to bock device (not the 20 - * whole disk). 21 - * On success, the number of bytes should be returned, others 22 - * means error. 23 - * @write: The same as @read, but the following error number: 24 - * -EBUSY means try to write again later. 25 - * -ENOMSG means to try next zone. 26 - * @erase: The general erase operation for device with special removing 27 - * job. Both of the function parameters @size and @offset are 28 - * relative value to storage. 29 - * Return 0 on success and others on failure. 30 - * @panic_write:The write operation only used for panic case. It's optional 31 - * if you do not care panic log. The parameters are relative 32 - * value to storage. 33 - * On success, the number of bytes should be returned, others 34 - * excluding -ENOMSG mean error. -ENOMSG means to try next zone. 16 + * @zone: The struct pstore_zone_info details. 17 + * 35 18 */ 36 19 struct pstore_device_info { 37 - unsigned long total_size; 38 20 unsigned int flags; 39 - pstore_zone_read_op read; 40 - pstore_zone_write_op write; 41 - pstore_zone_erase_op erase; 42 - pstore_zone_write_op panic_write; 21 + struct pstore_zone_info zone; 43 22 }; 44 23 45 24 int register_pstore_device(struct pstore_device_info *dev);