1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Persistent Storage - platform driver interface parts. 4 * 5 * Copyright (C) 2007-2008 Google, Inc. 6 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com> 7 */ 8 9 #define pr_fmt(fmt) "pstore: " fmt 10 11 #include <linux/atomic.h> 12 #include <linux/types.h> 13 #include <linux/errno.h> 14 #include <linux/init.h> 15 #include <linux/kmsg_dump.h> 16 #include <linux/console.h> 17 #include <linux/mm.h> 18 #include <linux/module.h> 19 #include <linux/pstore.h> 20 #include <linux/string.h> 21 #include <linux/timer.h> 22 #include <linux/slab.h> 23 #include <linux/uaccess.h> 24 #include <linux/jiffies.h> 25 #include <linux/vmalloc.h> 26 #include <linux/workqueue.h> 27 #include <linux/zlib.h> 28 29 #include "internal.h" 30 31 /* 32 * We defer making "oops" entries appear in pstore - see 33 * whether the system is actually still running well enough 34 * to let someone see the entry 35 */ 36 static int pstore_update_ms = -1; 37 module_param_named(update_ms, pstore_update_ms, int, 0600); 38 MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content " 39 "(default is -1, which means runtime updates are disabled; " 40 "enabling this option may not be safe; it may lead to further " 41 "corruption on Oopses)"); 42 43 /* Names should be in the same order as the enum pstore_type_id */ 44 static const char * const pstore_type_names[] = { 45 "dmesg", 46 "mce", 47 "console", 48 "ftrace", 49 "rtas", 50 "powerpc-ofw", 51 "powerpc-common", 52 "pmsg", 53 "powerpc-opal", 54 }; 55 56 static int pstore_new_entry; 57 58 static void pstore_timefunc(struct timer_list *); 59 static DEFINE_TIMER(pstore_timer, pstore_timefunc); 60 61 static void pstore_dowork(struct work_struct *); 62 static DECLARE_WORK(pstore_work, pstore_dowork); 63 64 /* 65 * psinfo_lock protects "psinfo" during calls to 66 * pstore_register(), pstore_unregister(), and 67 * the filesystem mount/unmount routines. 68 */ 69 static DEFINE_MUTEX(psinfo_lock); 70 struct pstore_info *psinfo; 71 72 static char *backend; 73 module_param(backend, charp, 0444); 74 MODULE_PARM_DESC(backend, "specific backend to use"); 75 76 /* 77 * pstore no longer implements compression via the crypto API, and only 78 * supports zlib deflate compression implemented using the zlib library 79 * interface. This removes additional complexity which is hard to justify for a 80 * diagnostic facility that has to operate in conditions where the system may 81 * have become unstable. Zlib deflate is comparatively small in terms of code 82 * size, and compresses ASCII text comparatively well. In terms of compression 83 * speed, deflate is not the best performer but for recording the log output on 84 * a kernel panic, this is not considered critical. 85 * 86 * The only remaining arguments supported by the compress= module parameter are 87 * 'deflate' and 'none'. To retain compatibility with existing installations, 88 * all other values are logged and replaced with 'deflate'. 89 */ 90 static char *compress = "deflate"; 91 module_param(compress, charp, 0444); 92 MODULE_PARM_DESC(compress, "compression to use"); 93 94 /* How much of the kernel log to snapshot */ 95 unsigned int kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES; 96 module_param(kmsg_bytes, uint, 0444); 97 MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)"); 98 99 static void *compress_workspace; 100 101 /* 102 * Compression is only used for dmesg output, which consists of low-entropy 103 * ASCII text, and so we can assume worst-case 60%. 104 */ 105 #define DMESG_COMP_PERCENT 60 106 107 static char *big_oops_buf; 108 static size_t max_compressed_size; 109 110 void pstore_set_kmsg_bytes(unsigned int bytes) 111 { 112 WRITE_ONCE(kmsg_bytes, bytes); 113 } 114 115 /* Tag each group of saved records with a sequence number */ 116 static int oopscount; 117 118 const char *pstore_type_to_name(enum pstore_type_id type) 119 { 120 BUILD_BUG_ON(ARRAY_SIZE(pstore_type_names) != PSTORE_TYPE_MAX); 121 122 if (WARN_ON_ONCE(type >= PSTORE_TYPE_MAX)) 123 return "unknown"; 124 125 return pstore_type_names[type]; 126 } 127 EXPORT_SYMBOL_GPL(pstore_type_to_name); 128 129 enum pstore_type_id pstore_name_to_type(const char *name) 130 { 131 int i; 132 133 for (i = 0; i < PSTORE_TYPE_MAX; i++) { 134 if (!strcmp(pstore_type_names[i], name)) 135 return i; 136 } 137 138 return PSTORE_TYPE_MAX; 139 } 140 EXPORT_SYMBOL_GPL(pstore_name_to_type); 141 142 static void pstore_timer_kick(void) 143 { 144 if (pstore_update_ms < 0) 145 return; 146 147 mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms)); 148 } 149 150 static bool pstore_cannot_block_path(enum kmsg_dump_reason reason) 151 { 152 /* 153 * In case of NMI path, pstore shouldn't be blocked 154 * regardless of reason. 155 */ 156 if (in_nmi()) 157 return true; 158 159 switch (reason) { 160 /* In panic case, other cpus are stopped by smp_send_stop(). */ 161 case KMSG_DUMP_PANIC: 162 /* 163 * Emergency restart shouldn't be blocked by spinning on 164 * pstore_info::buf_lock. 165 */ 166 case KMSG_DUMP_EMERG: 167 return true; 168 default: 169 return false; 170 } 171 } 172 173 static int pstore_compress(const void *in, void *out, 174 unsigned int inlen, unsigned int outlen) 175 { 176 struct z_stream_s zstream = { 177 .next_in = in, 178 .avail_in = inlen, 179 .next_out = out, 180 .avail_out = outlen, 181 .workspace = compress_workspace, 182 }; 183 int ret; 184 185 if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS)) 186 return -EINVAL; 187 188 ret = zlib_deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 189 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); 190 if (ret != Z_OK) 191 return -EINVAL; 192 193 ret = zlib_deflate(&zstream, Z_FINISH); 194 if (ret != Z_STREAM_END) 195 return -EINVAL; 196 197 ret = zlib_deflateEnd(&zstream); 198 if (ret != Z_OK) 199 pr_warn_once("zlib_deflateEnd() failed: %d\n", ret); 200 201 return zstream.total_out; 202 } 203 204 static void allocate_buf_for_compression(void) 205 { 206 size_t compressed_size; 207 char *buf; 208 209 /* Skip if not built-in or compression disabled. */ 210 if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !compress || 211 !strcmp(compress, "none")) { 212 compress = NULL; 213 return; 214 } 215 216 if (strcmp(compress, "deflate")) { 217 pr_err("Unsupported compression '%s', falling back to deflate\n", 218 compress); 219 compress = "deflate"; 220 } 221 222 /* 223 * The compression buffer only needs to be as large as the maximum 224 * uncompressed record size, since any record that would be expanded by 225 * compression is just stored uncompressed. 226 */ 227 compressed_size = (psinfo->bufsize * 100) / DMESG_COMP_PERCENT; 228 buf = kvzalloc(compressed_size, GFP_KERNEL); 229 if (!buf) { 230 pr_err("Failed %zu byte compression buffer allocation for: %s\n", 231 psinfo->bufsize, compress); 232 return; 233 } 234 235 compress_workspace = 236 vmalloc(zlib_deflate_workspacesize(MAX_WBITS, DEF_MEM_LEVEL)); 237 if (!compress_workspace) { 238 pr_err("Failed to allocate zlib deflate workspace\n"); 239 kvfree(buf); 240 return; 241 } 242 243 max_compressed_size = compressed_size; 244 /* 245 * A non-NULL big_oops_buf indicates compression is available. 246 * pstore_dump() tests it without psinfo_lock and then reads 247 * max_compressed_size, which is stored above. Publish the buffer 248 * with release semantics. 249 */ 250 smp_store_release(&big_oops_buf, buf); 251 252 pr_info("Using crash dump compression: %s\n", compress); 253 } 254 255 static void free_buf_for_compression(void) 256 { 257 if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress_workspace) { 258 vfree(compress_workspace); 259 compress_workspace = NULL; 260 } 261 262 kvfree(big_oops_buf); 263 big_oops_buf = NULL; 264 max_compressed_size = 0; 265 } 266 267 void pstore_record_init(struct pstore_record *record, 268 struct pstore_info *psinfo) 269 { 270 memset(record, 0, sizeof(*record)); 271 272 record->psi = psinfo; 273 274 /* Report zeroed timestamp if called before timekeeping has resumed. */ 275 record->time = ns_to_timespec64(ktime_get_real_fast_ns()); 276 } 277 278 /* 279 * callback from kmsg_dump. Save as much as we can (up to kmsg_bytes) from the 280 * end of the buffer. 281 */ 282 static void pstore_dump(struct kmsg_dumper *dumper, 283 struct kmsg_dump_detail *detail) 284 { 285 struct kmsg_dump_iter iter; 286 unsigned int remaining = READ_ONCE(kmsg_bytes); 287 unsigned long total = 0; 288 const char *why; 289 unsigned int part = 1; 290 unsigned long flags = 0; 291 int saved_ret = 0; 292 int ret; 293 294 why = kmsg_dump_reason_str(detail->reason); 295 296 if (pstore_cannot_block_path(detail->reason)) { 297 if (!raw_spin_trylock_irqsave(&psinfo->buf_lock, flags)) { 298 pr_err("dump skipped in %s path because of concurrent dump\n", 299 in_nmi() ? "NMI" : why); 300 return; 301 } 302 } else { 303 raw_spin_lock_irqsave(&psinfo->buf_lock, flags); 304 } 305 306 kmsg_dump_rewind(&iter); 307 308 oopscount++; 309 while (total < remaining) { 310 char *dst; 311 size_t dst_size; 312 int header_size; 313 int zipped_len = -1; 314 size_t dump_size; 315 struct pstore_record record; 316 317 pstore_record_init(&record, psinfo); 318 record.type = PSTORE_TYPE_DMESG; 319 record.count = oopscount; 320 record.reason = detail->reason; 321 record.part = part; 322 record.buf = psinfo->buf; 323 324 /* Pairs with the smp_store_release() in allocate_buf_for_compression(). */ 325 dst = smp_load_acquire(&big_oops_buf) ?: psinfo->buf; 326 dst_size = max_compressed_size ?: psinfo->bufsize; 327 328 /* Write dump header. */ 329 header_size = snprintf(dst, dst_size, "%s#%d Part%u\n", why, 330 oopscount, part); 331 dst_size -= header_size; 332 333 /* Write dump contents. */ 334 if (!kmsg_dump_get_buffer(&iter, true, dst + header_size, 335 dst_size, &dump_size)) 336 break; 337 338 if (big_oops_buf) { 339 zipped_len = pstore_compress(dst, psinfo->buf, 340 header_size + dump_size, 341 psinfo->bufsize); 342 343 if (zipped_len > 0) { 344 record.compressed = true; 345 record.size = zipped_len; 346 } else { 347 /* 348 * Compression failed, so the buffer is most 349 * likely filled with binary data that does not 350 * compress as well as ASCII text. Copy as much 351 * of the uncompressed data as possible into 352 * the pstore record, and discard the rest. 353 */ 354 record.size = psinfo->bufsize; 355 memcpy(psinfo->buf, dst, psinfo->bufsize); 356 } 357 } else { 358 record.size = header_size + dump_size; 359 } 360 361 ret = psinfo->write(&record); 362 if (ret == 0 && detail->reason == KMSG_DUMP_OOPS) { 363 pstore_new_entry = 1; 364 pstore_timer_kick(); 365 } else { 366 /* Preserve only the first non-zero returned value. */ 367 if (!saved_ret) 368 saved_ret = ret; 369 } 370 371 total += record.size; 372 part++; 373 } 374 raw_spin_unlock_irqrestore(&psinfo->buf_lock, flags); 375 376 if (saved_ret) { 377 pr_err_once("backend (%s) writing error (%d)\n", psinfo->name, 378 saved_ret); 379 } 380 } 381 382 static struct kmsg_dumper pstore_dumper = { 383 .dump = pstore_dump, 384 }; 385 386 /* 387 * Register with kmsg_dump to save last part of console log on panic. 388 */ 389 static void pstore_register_kmsg(void) 390 { 391 kmsg_dump_register(&pstore_dumper); 392 } 393 394 static void pstore_unregister_kmsg(void) 395 { 396 kmsg_dump_unregister(&pstore_dumper); 397 } 398 399 #ifdef CONFIG_PSTORE_CONSOLE 400 static void pstore_console_write(struct console *con, const char *s, unsigned c) 401 { 402 struct pstore_record record; 403 404 if (!c) 405 return; 406 407 pstore_record_init(&record, psinfo); 408 record.type = PSTORE_TYPE_CONSOLE; 409 410 record.buf = (char *)s; 411 record.size = c; 412 psinfo->write(&record); 413 } 414 415 static struct console pstore_console = { 416 .write = pstore_console_write, 417 .index = -1, 418 }; 419 420 static void pstore_register_console(void) 421 { 422 /* Show which backend is going to get console writes. */ 423 strscpy(pstore_console.name, psinfo->name, 424 sizeof(pstore_console.name)); 425 /* 426 * Always initialize flags here since prior unregister_console() 427 * calls may have changed settings (specifically CON_ENABLED). 428 */ 429 pstore_console.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME; 430 register_console(&pstore_console); 431 } 432 433 static void pstore_unregister_console(void) 434 { 435 unregister_console(&pstore_console); 436 } 437 #else 438 static void pstore_register_console(void) {} 439 static void pstore_unregister_console(void) {} 440 #endif 441 442 static int pstore_write_user_compat(struct pstore_record *record, 443 const char __user *buf) 444 { 445 int ret = 0; 446 447 if (record->buf) 448 return -EINVAL; 449 450 record->buf = vmemdup_user(buf, record->size); 451 if (IS_ERR(record->buf)) { 452 ret = PTR_ERR(record->buf); 453 goto out; 454 } 455 456 ret = record->psi->write(record); 457 458 kvfree(record->buf); 459 out: 460 record->buf = NULL; 461 462 return unlikely(ret < 0) ? ret : record->size; 463 } 464 465 /* 466 * platform specific persistent storage driver registers with 467 * us here. If pstore is already mounted, call the platform 468 * read function right away to populate the file system. If not 469 * then the pstore mount code will call us later to fill out 470 * the file system. 471 */ 472 int pstore_register(struct pstore_info *psi) 473 { 474 char *new_backend; 475 476 if (backend && strcmp(backend, psi->name)) { 477 pr_warn("backend '%s' already in use: ignoring '%s'\n", 478 backend, psi->name); 479 return -EBUSY; 480 } 481 482 /* Sanity check flags. */ 483 if (!psi->flags) { 484 pr_warn("backend '%s' must support at least one frontend\n", 485 psi->name); 486 return -EINVAL; 487 } 488 489 /* Check for required functions. */ 490 if (!psi->read || !psi->write) { 491 pr_warn("backend '%s' must implement read() and write()\n", 492 psi->name); 493 return -EINVAL; 494 } 495 496 new_backend = kstrdup(psi->name, GFP_KERNEL); 497 if (!new_backend) 498 return -ENOMEM; 499 500 mutex_lock(&psinfo_lock); 501 if (psinfo) { 502 pr_warn("backend '%s' already loaded: ignoring '%s'\n", 503 psinfo->name, psi->name); 504 mutex_unlock(&psinfo_lock); 505 kfree(new_backend); 506 return -EBUSY; 507 } 508 509 if (!psi->write_user) 510 psi->write_user = pstore_write_user_compat; 511 psinfo = psi; 512 mutex_init(&psinfo->read_mutex); 513 raw_spin_lock_init(&psinfo->buf_lock); 514 515 if (psi->flags & PSTORE_FLAGS_DMESG) 516 allocate_buf_for_compression(); 517 518 pstore_get_records(0); 519 520 if (psi->flags & PSTORE_FLAGS_DMESG) { 521 pstore_dumper.max_reason = psinfo->max_reason; 522 pstore_register_kmsg(); 523 } 524 if (psi->flags & PSTORE_FLAGS_CONSOLE) 525 pstore_register_console(); 526 if (psi->flags & PSTORE_FLAGS_FTRACE) 527 pstore_register_ftrace(); 528 if (psi->flags & PSTORE_FLAGS_PMSG) 529 pstore_register_pmsg(); 530 531 /* Start watching for new records, if desired. */ 532 pstore_timer_kick(); 533 534 /* 535 * Update the module parameter backend, so it is visible 536 * through /sys/module/pstore/parameters/backend 537 */ 538 backend = new_backend; 539 540 pr_info("Registered %s as persistent store backend\n", psi->name); 541 542 mutex_unlock(&psinfo_lock); 543 return 0; 544 } 545 EXPORT_SYMBOL_GPL(pstore_register); 546 547 void pstore_unregister(struct pstore_info *psi) 548 { 549 /* It's okay to unregister nothing. */ 550 if (!psi) 551 return; 552 553 mutex_lock(&psinfo_lock); 554 555 /* Only one backend can be registered at a time. */ 556 if (WARN_ON(psi != psinfo)) { 557 mutex_unlock(&psinfo_lock); 558 return; 559 } 560 561 /* Unregister all callbacks. */ 562 if (psi->flags & PSTORE_FLAGS_PMSG) 563 pstore_unregister_pmsg(); 564 if (psi->flags & PSTORE_FLAGS_FTRACE) 565 pstore_unregister_ftrace(); 566 if (psi->flags & PSTORE_FLAGS_CONSOLE) 567 pstore_unregister_console(); 568 if (psi->flags & PSTORE_FLAGS_DMESG) 569 pstore_unregister_kmsg(); 570 571 /* Stop timer and make sure all work has finished. */ 572 timer_delete_sync(&pstore_timer); 573 flush_work(&pstore_work); 574 575 /* Remove all backend records from filesystem tree. */ 576 pstore_put_backend_records(psi); 577 578 free_buf_for_compression(); 579 580 psinfo = NULL; 581 kfree(backend); 582 backend = NULL; 583 584 pr_info("Unregistered %s as persistent store backend\n", psi->name); 585 mutex_unlock(&psinfo_lock); 586 } 587 EXPORT_SYMBOL_GPL(pstore_unregister); 588 589 static void decompress_record(struct pstore_record *record, 590 struct z_stream_s *zstream) 591 { 592 int ret; 593 int unzipped_len; 594 char *unzipped, *workspace; 595 size_t max_uncompressed_size; 596 597 if (!IS_ENABLED(CONFIG_PSTORE_COMPRESS) || !record->compressed) 598 return; 599 600 /* Only PSTORE_TYPE_DMESG support compression. */ 601 if (record->type != PSTORE_TYPE_DMESG) { 602 pr_warn("ignored compressed record type %d\n", record->type); 603 return; 604 } 605 606 /* Missing compression buffer means compression was not initialized. */ 607 if (!zstream->workspace) { 608 pr_warn("no decompression method initialized!\n"); 609 return; 610 } 611 612 ret = zlib_inflateReset(zstream); 613 if (ret != Z_OK) { 614 pr_err("zlib_inflateReset() failed, ret = %d!\n", ret); 615 return; 616 } 617 618 /* Allocate enough space to hold max decompression and ECC. */ 619 max_uncompressed_size = 3 * psinfo->bufsize; 620 workspace = kvzalloc(max_uncompressed_size + record->ecc_notice_size, 621 GFP_KERNEL); 622 if (!workspace) 623 return; 624 625 zstream->next_in = record->buf; 626 zstream->avail_in = record->size; 627 zstream->next_out = workspace; 628 zstream->avail_out = max_uncompressed_size; 629 630 ret = zlib_inflate(zstream, Z_FINISH); 631 if (ret != Z_STREAM_END) { 632 pr_err_ratelimited("zlib_inflate() failed, ret = %d!\n", ret); 633 kvfree(workspace); 634 return; 635 } 636 637 unzipped_len = zstream->total_out; 638 639 /* Append ECC notice to decompressed buffer. */ 640 memcpy(workspace + unzipped_len, record->buf + record->size, 641 record->ecc_notice_size); 642 643 /* Copy decompressed contents into an minimum-sized allocation. */ 644 unzipped = kvmemdup(workspace, unzipped_len + record->ecc_notice_size, 645 GFP_KERNEL); 646 kvfree(workspace); 647 if (!unzipped) 648 return; 649 650 /* Swap out compressed contents with decompressed contents. */ 651 kvfree(record->buf); 652 record->buf = unzipped; 653 record->size = unzipped_len; 654 record->compressed = false; 655 } 656 657 /* 658 * Read all the records from one persistent store backend. Create 659 * files in our filesystem. Don't warn about -EEXIST errors 660 * when we are re-scanning the backing store looking to add new 661 * error records. 662 */ 663 void pstore_get_backend_records(struct pstore_info *psi, 664 struct dentry *root, int quiet) 665 { 666 int failed = 0; 667 unsigned int stop_loop = 65536; 668 struct z_stream_s zstream = {}; 669 670 if (!psi || !root) 671 return; 672 673 if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress) { 674 zstream.workspace = kvmalloc(zlib_inflate_workspacesize(), 675 GFP_KERNEL); 676 zlib_inflateInit2(&zstream, -DEF_WBITS); 677 } 678 679 mutex_lock(&psi->read_mutex); 680 if (psi->open && psi->open(psi)) 681 goto out; 682 683 /* 684 * Backend callback read() allocates record.buf. decompress_record() 685 * may reallocate record.buf. On success, pstore_mkfile() will keep 686 * the record.buf, so free it only on failure. 687 */ 688 for (; stop_loop; stop_loop--) { 689 struct pstore_record *record; 690 int rc; 691 692 record = kzalloc_obj(*record); 693 if (!record) { 694 pr_err("out of memory creating record\n"); 695 break; 696 } 697 pstore_record_init(record, psi); 698 699 record->size = psi->read(record); 700 701 /* No more records left in backend? */ 702 if (record->size <= 0) { 703 kfree(record); 704 break; 705 } 706 707 decompress_record(record, &zstream); 708 rc = pstore_mkfile(root, record); 709 if (rc) { 710 /* pstore_mkfile() did not take record, so free it. */ 711 kvfree(record->buf); 712 kfree(record->priv); 713 kfree(record); 714 if (rc != -EEXIST || !quiet) 715 failed++; 716 } 717 } 718 if (psi->close) 719 psi->close(psi); 720 out: 721 mutex_unlock(&psi->read_mutex); 722 723 if (IS_ENABLED(CONFIG_PSTORE_COMPRESS) && compress) { 724 if (zlib_inflateEnd(&zstream) != Z_OK) 725 pr_warn("zlib_inflateEnd() failed\n"); 726 kvfree(zstream.workspace); 727 } 728 729 if (failed) 730 pr_warn("failed to create %d record(s) from '%s'\n", 731 failed, psi->name); 732 if (!stop_loop) 733 pr_err("looping? Too many records seen from '%s'\n", 734 psi->name); 735 } 736 737 static void pstore_dowork(struct work_struct *work) 738 { 739 pstore_get_records(1); 740 } 741 742 static void pstore_timefunc(struct timer_list *unused) 743 { 744 if (pstore_new_entry) { 745 pstore_new_entry = 0; 746 schedule_work(&pstore_work); 747 } 748 749 pstore_timer_kick(); 750 } 751 752 static int __init pstore_init(void) 753 { 754 int ret; 755 756 ret = pstore_init_fs(); 757 if (ret) 758 free_buf_for_compression(); 759 760 return ret; 761 } 762 late_initcall(pstore_init); 763 764 static void __exit pstore_exit(void) 765 { 766 pstore_exit_fs(); 767 } 768 module_exit(pstore_exit) 769 770 MODULE_AUTHOR("Tony Luck <tony.luck@intel.com>"); 771 MODULE_DESCRIPTION("Persistent Storage - platform driver interface"); 772 MODULE_LICENSE("GPL"); 773