diff options
| author | Yazen Ghannam <yazen.ghannam@amd.com> | 2026-09-03 10:43:25 -0500 |
|---|---|---|
| committer | Borislav Petkov (AMD) <bp@alien8.de> | 2026-09-10 18:05:43 -0700 |
| commit | 27600805e62f800bacf990354632eae4e487d34c (patch) | |
| tree | e8aec0ddfaa0bc264d79af632e3de3f1b75ae4c8 /drivers/mtd/tests/stresstest.c | |
| download | linux-stable-27600805e62f800bacf990354632eae4e487d34c.tar.gz linux-stable-27600805e62f800bacf990354632eae4e487d34c.zip | |
x86/amd_node: Fix PCI device reference counting in amd_smn_init()grafted
The local "root" pointer is a temporary variable used during the device
search. Therefore, refcount related to the search iterators should be cleaned
up after the search is complete.
Use the __free() cleanup macro to ensure the refcount is decremented when the
temporary pointer goes out of scope.
Additionally, increment the refcount when caching a root pointer. This ensures
the in-use refcount is separate from the temporary search refcounting.
Finally, drop the redundant "root = NULL" before the second search loop. The
pci_get_class() iterator always decrements the refcount of its "from"
argument, so the first loop can only fall through with "root" already NULL.
Fixes: 0a4b61d9c2e4 ("x86/amd_node: Fix AMD root device caching")
Closes: https://sashiko.dev/#/patchset/20260806160159.230453-1-jason.andryuk%40amd.com
Reported-by: Sashiko <sashiko-bot@kernel.org>
Assisted-by: LLM
Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
Cc: <stable@kernel.org>
Link: https://patch.msgid.link/20260903154325.74343-1-yazen.ghannam@amd.com
Diffstat (limited to 'drivers/mtd/tests/stresstest.c')
| -rw-r--r-- | drivers/mtd/tests/stresstest.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c new file mode 100644 index 000000000..944f960a4 --- /dev/null +++ b/drivers/mtd/tests/stresstest.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * Test random reads, writes and erases on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> +#include <linux/random.h> + +#include "mtd_test.h" + +static int dev = -EINVAL; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static int count = 10000; +module_param(count, int, S_IRUGO); +MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)"); + +static struct mtd_info *mtd; +static unsigned char *writebuf; +static unsigned char *readbuf; +static unsigned char *bbt; +static int *offsets; + +static int pgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; + +static int rand_eb(void) +{ + unsigned int eb; + +again: + /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ + eb = get_random_u32_below(ebcnt - 1); + if (bbt[eb]) + goto again; + return eb; +} + +static int rand_offs(void) +{ + return get_random_u32_below(bufsize); +} + +static int rand_len(int offs) +{ + return get_random_u32_below(bufsize - offs); +} + +static int do_read(void) +{ + int eb = rand_eb(); + int offs = rand_offs(); + int len = rand_len(offs); + loff_t addr; + + if (bbt[eb + 1]) { + if (offs >= mtd->erasesize) + offs -= mtd->erasesize; + if (offs + len > mtd->erasesize) + len = mtd->erasesize - offs; + } + addr = (loff_t)eb * mtd->erasesize + offs; + return mtdtest_read(mtd, addr, len, readbuf); +} + +static int do_write(void) +{ + int eb = rand_eb(), offs, err, len; + loff_t addr; + + offs = offsets[eb]; + if (offs >= mtd->erasesize) { + err = mtdtest_erase_eraseblock(mtd, eb); + if (err) + return err; + offs = offsets[eb] = 0; + } + len = rand_len(offs); + len = ((len + pgsize - 1) / pgsize) * pgsize; + if (offs + len > mtd->erasesize) { + if (bbt[eb + 1]) + len = mtd->erasesize - offs; + else { + err = mtdtest_erase_eraseblock(mtd, eb + 1); + if (err) + return err; + offsets[eb + 1] = 0; + } + } + addr = (loff_t)eb * mtd->erasesize + offs; + err = mtdtest_write(mtd, addr, len, writebuf); + if (unlikely(err)) + return err; + offs += len; + while (offs > mtd->erasesize) { + offsets[eb++] = mtd->erasesize; + offs -= mtd->erasesize; + } + offsets[eb] = offs; + return 0; +} + +static int do_operation(void) +{ + if (get_random_u32_below(2)) + return do_read(); + else + return do_write(); +} + +static int __init mtd_stresstest_init(void) +{ + int err; + int i, op; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + pr_info("Please specify a valid mtd-device via module parameter\n"); + pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + + pr_info("MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + pr_err("error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + pr_info("not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / pgsize; + + pr_info("MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + if (ebcnt < 2) { + pr_err("error: need at least 2 eraseblocks\n"); + err = -ENOSPC; + goto out_put_mtd; + } + + /* Read or write up 2 eraseblocks at a time */ + bufsize = mtd->erasesize * 2; + + err = -ENOMEM; + readbuf = vmalloc(bufsize); + writebuf = vmalloc(bufsize); + offsets = kmalloc_objs(int, ebcnt); + if (!readbuf || !writebuf || !offsets) + goto out; + for (i = 0; i < ebcnt; i++) + offsets[i] = mtd->erasesize; + get_random_bytes(writebuf, bufsize); + + bbt = kzalloc(ebcnt, GFP_KERNEL); + if (!bbt) + goto out; + err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt); + if (err) + goto out; + + /* Do operations */ + pr_info("doing operations\n"); + for (op = 0; op < count; op++) { + if ((op & 1023) == 0) + pr_info("%d operations done\n", op); + err = do_operation(); + if (err) + goto out; + + err = mtdtest_relax(); + if (err) + goto out; + } + pr_info("finished, %d operations done\n", op); + +out: + kfree(offsets); + kfree(bbt); + vfree(writebuf); + vfree(readbuf); +out_put_mtd: + put_mtd_device(mtd); + if (err) + pr_info("error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_stresstest_init); + +static void __exit mtd_stresstest_exit(void) +{ + return; +} +module_exit(mtd_stresstest_exit); + +MODULE_DESCRIPTION("Stress test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); |
