-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAmRkoEsACgkQONu9yGCS aT6nbBAAxLX8QMuKuA8fcSFqQTZwrGAW/x7aOih1Sgkw/pttE8t8/q9sxlPZHljK UnZWzy/xjBayWA4aEskkd8pvZh7uXqcQH56UuiuzTiZwNtKQfAlvbVjsibzOk8mt leuNP1F/Kod7CFYi/o8yoo4tUrWPmNLgc5ZaAvR/FYapanpYLB/6I9u2mf8HPjRP tF1PwYPl9V7NdiAx5Liw6mczBI+v05FY7+G2tsUrnE/XM3SFOg8mwKNTksBeiZ8a vZxCwQgTohUR2yKMjSrsKnZ2sQAoskOlpc8YpdwSk2s7KZKf+QcI6Y2BhneK/A7+ BU9vQr8Y0qrciBrpZvBGLcBhcmXUQwgZBh4VKUwJCUWijSQRSjhs/3+rAyvj74rF w8hP6EDgyAb5fKSU//MAZiFqdQfzowGne2Uin/rgyhyK9l+zxRCRtY1Ra+T75Jvl 2MNU+VwvfRzzGJtP4BiuA2qoHsTqmLK2SUUrqmhyRm2D3cK17NuIJeGMwt3BXDzw g+FpXoVGmkmfl+HHQLWdqpJ654APpJgxjhK6Hjca5608V+FIW7FGScAWX2CRmpUK rTAUPloptXIuo41CI+z7hdmYSfFtJymOgd650p5ntmro+7tMRQkhhjnEDDF8y1Jr 703VIa3QkRWRE5/xGi2KM2GgEH81j0s2Nyo/7JQtiitOjqtpgJ4= =SrzM -----END PGP SIGNATURE----- Merge 5.4.243 into android11-5.4-lts Changes in 5.4.243 counter: 104-quad-8: Fix race condition between FLAG and CNTR reads wifi: brcmfmac: slab-out-of-bounds read in brcmf_get_assoc_ies() drm/fb-helper: set x/yres_virtual in drm_fb_helper_check_var bluetooth: Perform careful capability checks in hci_sock_ioctl() USB: serial: option: add UNISOC vendor and TOZED LT70C product iio: adc: palmas_gpadc: fix NULL dereference on rmmod ASoC: Intel: bytcr_rt5640: Add quirk for the Acer Iconia One 7 B1-750 asm-generic/io.h: suppress endianness warnings for readq() and writeq() USB: dwc3: fix runtime pm imbalance on probe errors USB: dwc3: fix runtime pm imbalance on unbind perf sched: Cast PTHREAD_STACK_MIN to int as it may turn into sysconf(__SC_THREAD_STACK_MIN_VALUE) staging: iio: resolver: ads1210: fix config mode debugfs: regset32: Add Runtime PM support xhci: fix debugfs register accesses while suspended MIPS: fw: Allow firmware to pass a empty env ipmi:ssif: Add send_retries increment ipmi: fix SSIF not responding under certain cond. kheaders: Use array declaration instead of char pwm: meson: Fix axg ao mux parents pwm: meson: Fix g12a ao clk81 name ring-buffer: Sync IRQ works before buffer destruction reiserfs: Add security prefix to xattr name in reiserfs_security_write() KVM: nVMX: Emulate NOPs in L2, and PAUSE if it's not intercepted i2c: omap: Fix standard mode false ACK readings Revert "ubifs: dirty_cow_znode: Fix memleak in error handling path" ubifs: Fix memleak when insert_old_idx() failed ubi: Fix return value overwrite issue in try_write_vid_and_data() ubifs: Free memory for tmpfile name selinux: fix Makefile dependencies of flask.h selinux: ensure av_permissions.h is built when needed tpm, tpm_tis: Do not skip reset of original interrupt vector erofs: stop parsing non-compact HEAD index if clusterofs is invalid erofs: fix potential overflow calculating xattr_isize drm/rockchip: Drop unbalanced obj unref drm/vgem: add missing mutex_destroy drm/probe-helper: Cancel previous job before starting new one arm64: dts: renesas: r8a77990: Remove bogus voltages from OPP table arm64: dts: renesas: r8a774c0: Remove bogus voltages from OPP table EDAC/skx: Fix overflows on the DRAM row address mapping arrays ARM: dts: qcom: ipq4019: Fix the PCI I/O port range ARM: dts: qcom: ipq8064: reduce pci IO size to 64K ARM: dts: qcom: ipq8064: Fix the PCI I/O port range media: bdisp: Add missing check for create_workqueue media: uapi: add MEDIA_BUS_FMT_METADATA_FIXED media bus format. media: av7110: prevent underflow in write_ts_to_decoder() firmware: qcom_scm: Clear download bit during reboot drm/msm: fix unbalanced pm_runtime_enable in adreno_gpu_{init, cleanup} drm/msm/adreno: Defer enabling runpm until hw_init() drm/msm/adreno: drop bogus pm_runtime_set_active() mmc: sdhci-of-esdhc: fix quirk to ignore command inhibit for data drm/lima/lima_drv: Add missing unwind goto in lima_pdev_probe() regulator: core: Consistently set mutex_owner when using ww_mutex_lock_slow() regulator: core: Avoid lockdep reports when resolving supplies x86/apic: Fix atomic update of offset in reserve_eilvt_offset() media: dm1105: Fix use after free bug in dm1105_remove due to race condition media: saa7134: fix use after free bug in saa7134_finidev due to race condition media: rcar_fdp1: simplify error check logic at fdp_open() media: rcar_fdp1: fix pm_runtime_get_sync() usage count media: rcar_fdp1: Make use of the helper function devm_platform_ioremap_resource() media: rcar_fdp1: Fix the correct variable assignments media: rcar_fdp1: Fix refcount leak in probe and remove function media: rc: gpio-ir-recv: Fix support for wake-up regulator: stm32-pwr: fix of_iomap leak x86/ioapic: Don't return 0 from arch_dynirq_lower_bound() arm64: kgdb: Set PSTATE.SS to 1 to re-enable single-step debugobject: Prevent init race with static objects timekeeping: Split jiffies seqlock tick/sched: Use tick_next_period for lockless quick check tick/sched: Reduce seqcount held scope in tick_do_update_jiffies64() tick/sched: Optimize tick_do_update_jiffies64() further tick: Get rid of tick_period tick/common: Align tick period with the HZ tick. wifi: ath6kl: minor fix for allocation size wifi: ath9k: hif_usb: fix memory leak of remain_skbs wifi: ath5k: fix an off by one check in ath5k_eeprom_read_freq_list() wifi: ath6kl: reduce WARN to dev_dbg() in callback tools: bpftool: Remove invalid \' json escape wifi: rtw88: mac: Return the original error from rtw_pwr_seq_parser() wifi: rtw88: mac: Return the original error from rtw_mac_power_switch() scm: fix MSG_CTRUNC setting condition for SO_PASSSEC vlan: partially enable SIOCSHWTSTAMP in container net/packet: annotate accesses to po->xmit net/packet: convert po->origdev to an atomic flag net/packet: convert po->auxdata to an atomic flag scsi: target: iscsit: Fix TAS handling during conn cleanup scsi: megaraid: Fix mega_cmd_done() CMDID_INT_CMDS f2fs: handle dqget error in f2fs_transfer_project_quota() rtlwifi: Start changing RT_TRACE into rtl_dbg rtlwifi: Replace RT_TRACE with rtl_dbg wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_rfreg() wifi: rtlwifi: fix incorrect error codes in rtl_debugfs_set_write_reg() bpftool: Fix bug for long instructions in program CFG dumps crypto: drbg - make drbg_prepare_hrng() handle jent instantiation errors crypto: drbg - Only fail when jent is unavailable in FIPS mode scsi: lpfc: Fix ioremap issues in lpfc_sli4_pci_mem_setup() bpf, sockmap: fix deadlocks in the sockhash and sockmap nvme: handle the persistent internal error AER nvme: fix async event trace event nvme-fcloop: fix "inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage" bpf, sockmap: Revert buggy deadlock fix in the sockhash and sockmap md/raid10: fix leak of 'r10bio->remaining' for recovery md/raid10: fix memleak for 'conf->bio_split' md: update the optimal I/O size on reshape md/raid10: fix memleak of md thread wifi: iwlwifi: make the loop for card preparation effective wifi: iwlwifi: mvm: check firmware response size ixgbe: Allow flow hash to be set via ethtool ixgbe: Enable setting RSS table to default values bpf: Don't EFAULT for getsockopt with optval=NULL netfilter: nf_tables: don't write table validation state without mutex ipv4: Fix potential uninit variable access bug in __ip_make_skb() Revert "Bluetooth: btsdio: fix use after free bug in btsdio_remove due to unfinished work" netlink: Use copy_to_user() for optval in netlink_getsockopt(). net: amd: Fix link leak when verifying config failed tcp/udp: Fix memleaks of sk and zerocopy skbs with TX timestamp. pstore: Revert pmsg_lock back to a normal mutex usb: host: xhci-rcar: remove leftover quirk handling fpga: bridge: fix kernel-doc parameter description iio: light: max44009: add missing OF device matching usb: gadget: udc: renesas_usb3: Fix use after free bug in renesas_usb3_remove due to race condition PCI: imx6: Install the fault handler only on compatible match genirq: Add IRQF_NO_AUTOEN for request_irq/nmi() ASoC: es8316: Use IRQF_NO_AUTOEN when requesting the IRQ ASoC: es8316: Handle optional IRQ assignment linux/vt_buffer.h: allow either builtin or modular for macros spi: qup: Don't skip cleanup in remove's error path spi: fsl-spi: Fix CPM/QE mode Litte Endian vmci_host: fix a race condition in vmci_host_poll() causing GPF of: Fix modalias string generation ia64: mm/contig: fix section mismatch warning/error ia64: salinfo: placate defined-but-not-used warning scripts/gdb: bail early if there are no clocks PM: domains: Fix up terminology with parent/child scripts/gdb: bail early if there are no generic PD mtd: spi-nor: cadence-quadspi: Make driver independent of flash geometry mtd: spi-nor: cadence-quadspi: Provide a way to disable DAC mode mtd: spi-nor: cadence-quadspi: Don't initialize rx_dma_complete on failure mtd: spi-nor: cadence-quadspi: Handle probe deferral while requesting DMA channel spi: cadence-quadspi: fix suspend-resume implementations uapi/linux/const.h: prefer ISO-friendly __typeof__ sh: sq: Fix incorrect element size for allocating bitmap buffer usb: chipidea: fix missing goto in `ci_hdrc_probe` usb: mtu3: fix kernel panic at qmu transfer done irq handler firmware: stratix10-svc: Fix an NULL vs IS_ERR() bug in probe tty: serial: fsl_lpuart: adjust buffer length to the intended size serial: 8250: Add missing wakeup event reporting staging: rtl8192e: Fix W_DISABLE# does not work after stop/start spmi: Add a check for remove callback when removing a SPMI driver macintosh/windfarm_smu_sat: Add missing of_node_put() powerpc/mpc512x: fix resource printk format warning powerpc/wii: fix resource printk format warnings powerpc/sysdev/tsi108: fix resource printk format warnings macintosh: via-pmu-led: requires ATA to be set powerpc/rtas: use memmove for potentially overlapping buffer copy perf/core: Fix hardlockup failure caused by perf throttle RDMA/siw: Fix potential page_array out of range access RDMA/rdmavt: Delete unnecessary NULL check rtc: omap: include header for omap_rtc_power_off_program prototype RDMA/mlx4: Prevent shift wrapping in set_user_sq_size() rtc: meson-vrtc: Use ktime_get_real_ts64() to get the current time power: supply: generic-adc-battery: fix unit scaling clk: add missing of_node_put() in "assigned-clocks" property parsing RDMA/siw: Remove namespace check from siw_netdev_event() IB/hfi1: Fix SDMA mmu_rb_node not being evicted in LRU order NFSv4.1: Always send a RECLAIM_COMPLETE after establishing lease firmware: raspberrypi: Keep count of all consumers firmware: raspberrypi: Introduce devm_rpi_firmware_get() input: raspberrypi-ts: Release firmware handle when not needed Input: raspberrypi-ts - fix refcount leak in rpi_ts_probe SUNRPC: remove the maximum number of retries in call_bind_status RDMA/mlx5: Use correct device num_ports when modify DC clocksource/drivers/davinci: Avoid trailing '\n' hidden in pr_fmt() clocksource: davinci: axe a pointless __GFP_NOFAIL clocksource/drivers/davinci: Fix memory leak in davinci_timer_register when init fails openrisc: Properly store r31 to pt_regs on unhandled exceptions ext4: fix use-after-free read in ext4_find_extent for bigalloc + inline leds: TI_LMU_COMMON: select REGMAP instead of depending on it dmaengine: mv_xor_v2: Fix an error code. pwm: mtk-disp: Don't check the return code of pwmchip_remove() pwm: mtk-disp: Adjust the clocks to avoid them mismatch pwm: mtk-disp: Disable shadow registers before setting backlight values phy: tegra: xusb: Add missing tegra_xusb_port_unregister for usb2_port and ulpi_port dmaengine: dw-edma: Fix to change for continuous transfer dmaengine: dw-edma: Fix to enable to issue dma request on DMA processing dmaengine: at_xdmac: do not enable all cyclic channels afs: Fix updating of i_size with dv jump from server parisc: Fix argument pointer in real64_call_asm() nilfs2: do not write dirty data after degenerating to read-only nilfs2: fix infinite loop in nilfs_mdt_get_block() md/raid10: fix null-ptr-deref in raid10_sync_request mailbox: zynqmp: Fix IPI isr handling mailbox: zynqmp: Fix typo in IPI documentation wifi: rtl8xxxu: RTL8192EU always needs full init clk: rockchip: rk3399: allow clk_cifout to force clk_cifout_src to reparent scripts/gdb: fix lx-timerlist for Python3 btrfs: scrub: reject unsupported scrub flags s390/dasd: fix hanging blockdevice after request requeue dm clone: call kmem_cache_destroy() in dm_clone_init() error path dm integrity: call kmem_cache_destroy() in dm_integrity_init() error path dm flakey: fix a crash with invalid table line dm ioctl: fix nested locking in table_clear() to remove deadlock concern perf auxtrace: Fix address filter entire kernel size perf intel-pt: Fix CYC timestamps after standalone CBR debugobject: Ensure pool refill (again) netfilter: nf_tables: deactivate anonymous set from preparation phase nohz: Add TICK_DEP_BIT_RCU tick/nohz: Fix cpu_is_hotpluggable() by checking with nohz subsystem mailbox: zynq: Switch to flexible array to simplify code mailbox: zynqmp: Fix counts of child nodes dm verity: skip redundant verity_handle_err() on I/O errors dm verity: fix error handling for check_at_most_once on FEC crypto: inside-secure - irq balance crypto: safexcel - Cleanup ring IRQ workqueues on load failure kernel/relay.c: fix read_pos error when multiple readers relayfs: fix out-of-bounds access in relay_file_read net/ncsi: clear Tx enable mode when handling a Config required AEN net/sched: cls_api: remove block_cb from driver_list before freeing sit: update dev->needed_headroom in ipip6_tunnel_bind_dev() net: dsa: mv88e6xxx: add mv88e6321 rsvd2cpu writeback: fix call of incorrect macro net/sched: act_mirred: Add carrier check rxrpc: Fix hard call timeout units ionic: remove noise from ethtool rxnfc error msg af_packet: Don't send zero-byte data in packet_sendmsg_spkt(). drm/amdgpu: add a missing lock for AMDGPU_SCHED ALSA: caiaq: input: Add error handling for unsupported input methods in `snd_usb_caiaq_input_init` net: dsa: mt7530: fix corrupt frames using trgmii on 40 MHz XTAL MT7621 virtio_net: split free_unused_bufs() virtio_net: suppress cpu stall when free_unused_bufs perf vendor events power9: Remove UTF-8 characters from JSON files perf map: Delete two variable initialisations before null pointer checks in sort__sym_from_cmp() perf symbols: Fix return incorrect build_id size in elf_read_build_id() btrfs: fix btrfs_prev_leaf() to not return the same key twice btrfs: don't free qgroup space unless specified btrfs: print-tree: parent bytenr must be aligned to sector size cifs: fix pcchunk length type in smb2_copychunk_range platform/x86: touchscreen_dmi: Add info for the Dexp Ursus KX210i inotify: Avoid reporting event with invalid wd sh: math-emu: fix macro redefined warning sh: init: use OF_EARLY_FLATTREE for early init sh: nmi_debug: fix return value of __setup handler remoteproc: stm32: Call of_node_put() on iteration error remoteproc: st: Call of_node_put() on iteration error ARM: dts: exynos: fix WM8960 clock name in Itop Elite ARM: dts: s5pv210: correct MIPI CSIS clock name f2fs: fix potential corruption when moving a directory drm/panel: otm8009a: Set backlight parent to panel device drm/amdgpu: fix an amdgpu_irq_put() issue in gmc_v9_0_hw_fini() drm/amdgpu/gfx: disable gfx9 cp_ecc_error_irq only when enabling legacy gfx ras drm/amdgpu: disable sdma ecc irq only when sdma RAS is enabled in suspend HID: wacom: Set a default resolution for older tablets HID: wacom: insert timestamp to packed Bluetooth (BT) events ext4: fix WARNING in mb_find_extent ext4: avoid a potential slab-out-of-bounds in ext4_group_desc_csum ext4: fix data races when using cached status extents ext4: improve error recovery code paths in __ext4_remount() ext4: fix deadlock when converting an inline directory in nojournal mode ext4: add bounds checking in get_max_inline_xattr_value_size() ext4: bail out of ext4_xattr_ibody_get() fails for any reason ext4: remove a BUG_ON in ext4_mb_release_group_pa() ext4: fix invalid free tracking in ext4_xattr_move_to_block() tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH serial: 8250: Fix serial8250_tx_empty() race with DMA Tx drbd: correctly submit flush bio on barrier PCI: pciehp: Use down_read/write_nested(reset_lock) to fix lockdep errors PCI: pciehp: Fix AB-BA deadlock between reset_lock and device_lock printk: declare printk_deferred_{enter,safe}() in include/linux/printk.h PM: domains: Restore comment indentation for generic_pm_domain.child_links drm/msm: Fix double pm_runtime_disable() call firmware: raspberrypi: fix possible memory leak in rpi_firmware_probe() drm/msm/adreno: Fix null ptr access in adreno_gpu_cleanup() drm/exynos: move to use request_irq by IRQF_NO_AUTOEN flag mm/page_alloc: fix potential deadlock on zonelist_update_seq seqlock drm/amd/display: Fix hang when skipping modeset Linux 5.4.243 Change-Id: I103e06e639a82ddc7ca60ffed98c898946b81542 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
527 lines
12 KiB
C
527 lines
12 KiB
C
/*
|
|
* Copyright (C) 2003 Sistina Software (UK) Limited.
|
|
* Copyright (C) 2004, 2010-2011 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* This file is released under the GPL.
|
|
*/
|
|
|
|
#include <linux/device-mapper.h>
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/blkdev.h>
|
|
#include <linux/bio.h>
|
|
#include <linux/slab.h>
|
|
|
|
#define DM_MSG_PREFIX "flakey"
|
|
|
|
#define all_corrupt_bio_flags_match(bio, fc) \
|
|
(((bio)->bi_opf & (fc)->corrupt_bio_flags) == (fc)->corrupt_bio_flags)
|
|
|
|
/*
|
|
* Flakey: Used for testing only, simulates intermittent,
|
|
* catastrophic device failure.
|
|
*/
|
|
struct flakey_c {
|
|
struct dm_dev *dev;
|
|
unsigned long start_time;
|
|
sector_t start;
|
|
unsigned up_interval;
|
|
unsigned down_interval;
|
|
unsigned long flags;
|
|
unsigned corrupt_bio_byte;
|
|
unsigned corrupt_bio_rw;
|
|
unsigned corrupt_bio_value;
|
|
unsigned corrupt_bio_flags;
|
|
};
|
|
|
|
enum feature_flag_bits {
|
|
DROP_WRITES,
|
|
ERROR_WRITES
|
|
};
|
|
|
|
struct per_bio_data {
|
|
bool bio_submitted;
|
|
};
|
|
|
|
static int parse_features(struct dm_arg_set *as, struct flakey_c *fc,
|
|
struct dm_target *ti)
|
|
{
|
|
int r;
|
|
unsigned argc;
|
|
const char *arg_name;
|
|
|
|
static const struct dm_arg _args[] = {
|
|
{0, 6, "Invalid number of feature args"},
|
|
{1, UINT_MAX, "Invalid corrupt bio byte"},
|
|
{0, 255, "Invalid corrupt value to write into bio byte (0-255)"},
|
|
{0, UINT_MAX, "Invalid corrupt bio flags mask"},
|
|
};
|
|
|
|
/* No feature arguments supplied. */
|
|
if (!as->argc)
|
|
return 0;
|
|
|
|
r = dm_read_arg_group(_args, as, &argc, &ti->error);
|
|
if (r)
|
|
return r;
|
|
|
|
while (argc) {
|
|
arg_name = dm_shift_arg(as);
|
|
argc--;
|
|
|
|
if (!arg_name) {
|
|
ti->error = "Insufficient feature arguments";
|
|
return -EINVAL;
|
|
}
|
|
|
|
/*
|
|
* drop_writes
|
|
*/
|
|
if (!strcasecmp(arg_name, "drop_writes")) {
|
|
if (test_and_set_bit(DROP_WRITES, &fc->flags)) {
|
|
ti->error = "Feature drop_writes duplicated";
|
|
return -EINVAL;
|
|
} else if (test_bit(ERROR_WRITES, &fc->flags)) {
|
|
ti->error = "Feature drop_writes conflicts with feature error_writes";
|
|
return -EINVAL;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* error_writes
|
|
*/
|
|
if (!strcasecmp(arg_name, "error_writes")) {
|
|
if (test_and_set_bit(ERROR_WRITES, &fc->flags)) {
|
|
ti->error = "Feature error_writes duplicated";
|
|
return -EINVAL;
|
|
|
|
} else if (test_bit(DROP_WRITES, &fc->flags)) {
|
|
ti->error = "Feature error_writes conflicts with feature drop_writes";
|
|
return -EINVAL;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>
|
|
*/
|
|
if (!strcasecmp(arg_name, "corrupt_bio_byte")) {
|
|
if (!argc) {
|
|
ti->error = "Feature corrupt_bio_byte requires parameters";
|
|
return -EINVAL;
|
|
}
|
|
|
|
r = dm_read_arg(_args + 1, as, &fc->corrupt_bio_byte, &ti->error);
|
|
if (r)
|
|
return r;
|
|
argc--;
|
|
|
|
/*
|
|
* Direction r or w?
|
|
*/
|
|
arg_name = dm_shift_arg(as);
|
|
if (arg_name && !strcasecmp(arg_name, "w"))
|
|
fc->corrupt_bio_rw = WRITE;
|
|
else if (arg_name && !strcasecmp(arg_name, "r"))
|
|
fc->corrupt_bio_rw = READ;
|
|
else {
|
|
ti->error = "Invalid corrupt bio direction (r or w)";
|
|
return -EINVAL;
|
|
}
|
|
argc--;
|
|
|
|
/*
|
|
* Value of byte (0-255) to write in place of correct one.
|
|
*/
|
|
r = dm_read_arg(_args + 2, as, &fc->corrupt_bio_value, &ti->error);
|
|
if (r)
|
|
return r;
|
|
argc--;
|
|
|
|
/*
|
|
* Only corrupt bios with these flags set.
|
|
*/
|
|
r = dm_read_arg(_args + 3, as, &fc->corrupt_bio_flags, &ti->error);
|
|
if (r)
|
|
return r;
|
|
argc--;
|
|
|
|
continue;
|
|
}
|
|
|
|
ti->error = "Unrecognised flakey feature requested";
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (test_bit(DROP_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
|
|
ti->error = "drop_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
|
|
return -EINVAL;
|
|
|
|
} else if (test_bit(ERROR_WRITES, &fc->flags) && (fc->corrupt_bio_rw == WRITE)) {
|
|
ti->error = "error_writes is incompatible with corrupt_bio_byte with the WRITE flag set";
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Construct a flakey mapping:
|
|
* <dev_path> <offset> <up interval> <down interval> [<#feature args> [<arg>]*]
|
|
*
|
|
* Feature args:
|
|
* [drop_writes]
|
|
* [corrupt_bio_byte <Nth_byte> <direction> <value> <bio_flags>]
|
|
*
|
|
* Nth_byte starts from 1 for the first byte.
|
|
* Direction is r for READ or w for WRITE.
|
|
* bio_flags is ignored if 0.
|
|
*/
|
|
static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
|
{
|
|
static const struct dm_arg _args[] = {
|
|
{0, UINT_MAX, "Invalid up interval"},
|
|
{0, UINT_MAX, "Invalid down interval"},
|
|
};
|
|
|
|
int r;
|
|
struct flakey_c *fc;
|
|
unsigned long long tmpll;
|
|
struct dm_arg_set as;
|
|
const char *devname;
|
|
char dummy;
|
|
|
|
as.argc = argc;
|
|
as.argv = argv;
|
|
|
|
if (argc < 4) {
|
|
ti->error = "Invalid argument count";
|
|
return -EINVAL;
|
|
}
|
|
|
|
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
|
|
if (!fc) {
|
|
ti->error = "Cannot allocate context";
|
|
return -ENOMEM;
|
|
}
|
|
fc->start_time = jiffies;
|
|
|
|
devname = dm_shift_arg(&as);
|
|
|
|
r = -EINVAL;
|
|
if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) {
|
|
ti->error = "Invalid device sector";
|
|
goto bad;
|
|
}
|
|
fc->start = tmpll;
|
|
|
|
r = dm_read_arg(_args, &as, &fc->up_interval, &ti->error);
|
|
if (r)
|
|
goto bad;
|
|
|
|
r = dm_read_arg(_args, &as, &fc->down_interval, &ti->error);
|
|
if (r)
|
|
goto bad;
|
|
|
|
if (!(fc->up_interval + fc->down_interval)) {
|
|
ti->error = "Total (up + down) interval is zero";
|
|
r = -EINVAL;
|
|
goto bad;
|
|
}
|
|
|
|
if (fc->up_interval + fc->down_interval < fc->up_interval) {
|
|
ti->error = "Interval overflow";
|
|
r = -EINVAL;
|
|
goto bad;
|
|
}
|
|
|
|
r = parse_features(&as, fc, ti);
|
|
if (r)
|
|
goto bad;
|
|
|
|
r = dm_get_device(ti, devname, dm_table_get_mode(ti->table), &fc->dev);
|
|
if (r) {
|
|
ti->error = "Device lookup failed";
|
|
goto bad;
|
|
}
|
|
|
|
ti->num_flush_bios = 1;
|
|
ti->num_discard_bios = 1;
|
|
ti->per_io_data_size = sizeof(struct per_bio_data);
|
|
ti->private = fc;
|
|
return 0;
|
|
|
|
bad:
|
|
kfree(fc);
|
|
return r;
|
|
}
|
|
|
|
static void flakey_dtr(struct dm_target *ti)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
|
|
dm_put_device(ti, fc->dev);
|
|
kfree(fc);
|
|
}
|
|
|
|
static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
|
|
return fc->start + dm_target_offset(ti, bi_sector);
|
|
}
|
|
|
|
static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
|
|
bio_set_dev(bio, fc->dev->bdev);
|
|
if (bio_sectors(bio) || bio_op(bio) == REQ_OP_ZONE_RESET)
|
|
bio->bi_iter.bi_sector =
|
|
flakey_map_sector(ti, bio->bi_iter.bi_sector);
|
|
}
|
|
|
|
static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
|
|
{
|
|
unsigned int corrupt_bio_byte = fc->corrupt_bio_byte - 1;
|
|
|
|
struct bvec_iter iter;
|
|
struct bio_vec bvec;
|
|
|
|
if (!bio_has_data(bio))
|
|
return;
|
|
|
|
/*
|
|
* Overwrite the Nth byte of the bio's data, on whichever page
|
|
* it falls.
|
|
*/
|
|
bio_for_each_segment(bvec, bio, iter) {
|
|
if (bio_iter_len(bio, iter) > corrupt_bio_byte) {
|
|
char *segment;
|
|
struct page *page = bio_iter_page(bio, iter);
|
|
if (unlikely(page == ZERO_PAGE(0)))
|
|
break;
|
|
segment = (page_address(page) + bio_iter_offset(bio, iter));
|
|
segment[corrupt_bio_byte] = fc->corrupt_bio_value;
|
|
DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
|
|
"(rw=%c bi_opf=%u bi_sector=%llu size=%u)\n",
|
|
bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
|
|
(bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_opf,
|
|
(unsigned long long)bio->bi_iter.bi_sector, bio->bi_iter.bi_size);
|
|
break;
|
|
}
|
|
corrupt_bio_byte -= bio_iter_len(bio, iter);
|
|
}
|
|
}
|
|
|
|
static int flakey_map(struct dm_target *ti, struct bio *bio)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
unsigned elapsed;
|
|
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
|
|
pb->bio_submitted = false;
|
|
|
|
/* Do not fail reset zone */
|
|
if (bio_op(bio) == REQ_OP_ZONE_RESET)
|
|
goto map_bio;
|
|
|
|
/* Are we alive ? */
|
|
elapsed = (jiffies - fc->start_time) / HZ;
|
|
if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) {
|
|
/*
|
|
* Flag this bio as submitted while down.
|
|
*/
|
|
pb->bio_submitted = true;
|
|
|
|
/*
|
|
* Error reads if neither corrupt_bio_byte or drop_writes or error_writes are set.
|
|
* Otherwise, flakey_end_io() will decide if the reads should be modified.
|
|
*/
|
|
if (bio_data_dir(bio) == READ) {
|
|
if (!fc->corrupt_bio_byte && !test_bit(DROP_WRITES, &fc->flags) &&
|
|
!test_bit(ERROR_WRITES, &fc->flags))
|
|
return DM_MAPIO_KILL;
|
|
goto map_bio;
|
|
}
|
|
|
|
/*
|
|
* Drop or error writes?
|
|
*/
|
|
if (test_bit(DROP_WRITES, &fc->flags)) {
|
|
bio_endio(bio);
|
|
return DM_MAPIO_SUBMITTED;
|
|
}
|
|
else if (test_bit(ERROR_WRITES, &fc->flags)) {
|
|
bio_io_error(bio);
|
|
return DM_MAPIO_SUBMITTED;
|
|
}
|
|
|
|
/*
|
|
* Corrupt matching writes.
|
|
*/
|
|
if (fc->corrupt_bio_byte) {
|
|
if (fc->corrupt_bio_rw == WRITE) {
|
|
if (all_corrupt_bio_flags_match(bio, fc))
|
|
corrupt_bio_data(bio, fc);
|
|
}
|
|
goto map_bio;
|
|
}
|
|
|
|
/*
|
|
* By default, error all I/O.
|
|
*/
|
|
return DM_MAPIO_KILL;
|
|
}
|
|
|
|
map_bio:
|
|
flakey_map_bio(ti, bio);
|
|
|
|
return DM_MAPIO_REMAPPED;
|
|
}
|
|
|
|
static int flakey_end_io(struct dm_target *ti, struct bio *bio,
|
|
blk_status_t *error)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
|
|
|
|
if (bio_op(bio) == REQ_OP_ZONE_RESET)
|
|
return DM_ENDIO_DONE;
|
|
|
|
if (!*error && pb->bio_submitted && (bio_data_dir(bio) == READ)) {
|
|
if (fc->corrupt_bio_byte) {
|
|
if ((fc->corrupt_bio_rw == READ) &&
|
|
all_corrupt_bio_flags_match(bio, fc)) {
|
|
/*
|
|
* Corrupt successful matching READs while in down state.
|
|
*/
|
|
corrupt_bio_data(bio, fc);
|
|
}
|
|
} else if (!test_bit(DROP_WRITES, &fc->flags) &&
|
|
!test_bit(ERROR_WRITES, &fc->flags)) {
|
|
/*
|
|
* Error read during the down_interval if drop_writes
|
|
* and error_writes were not configured.
|
|
*/
|
|
*error = BLK_STS_IOERR;
|
|
}
|
|
}
|
|
|
|
return DM_ENDIO_DONE;
|
|
}
|
|
|
|
static void flakey_status(struct dm_target *ti, status_type_t type,
|
|
unsigned status_flags, char *result, unsigned maxlen)
|
|
{
|
|
unsigned sz = 0;
|
|
struct flakey_c *fc = ti->private;
|
|
unsigned drop_writes, error_writes;
|
|
|
|
switch (type) {
|
|
case STATUSTYPE_INFO:
|
|
result[0] = '\0';
|
|
break;
|
|
|
|
case STATUSTYPE_TABLE:
|
|
DMEMIT("%s %llu %u %u ", fc->dev->name,
|
|
(unsigned long long)fc->start, fc->up_interval,
|
|
fc->down_interval);
|
|
|
|
drop_writes = test_bit(DROP_WRITES, &fc->flags);
|
|
error_writes = test_bit(ERROR_WRITES, &fc->flags);
|
|
DMEMIT("%u ", drop_writes + error_writes + (fc->corrupt_bio_byte > 0) * 5);
|
|
|
|
if (drop_writes)
|
|
DMEMIT("drop_writes ");
|
|
else if (error_writes)
|
|
DMEMIT("error_writes ");
|
|
|
|
if (fc->corrupt_bio_byte)
|
|
DMEMIT("corrupt_bio_byte %u %c %u %u ",
|
|
fc->corrupt_bio_byte,
|
|
(fc->corrupt_bio_rw == WRITE) ? 'w' : 'r',
|
|
fc->corrupt_bio_value, fc->corrupt_bio_flags);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int flakey_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
|
|
*bdev = fc->dev->bdev;
|
|
|
|
/*
|
|
* Only pass ioctls through if the device sizes match exactly.
|
|
*/
|
|
if (fc->start ||
|
|
ti->len != i_size_read((*bdev)->bd_inode) >> SECTOR_SHIFT)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_BLK_DEV_ZONED
|
|
static int flakey_report_zones(struct dm_target *ti,
|
|
struct dm_report_zones_args *args, unsigned int nr_zones)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
sector_t sector = flakey_map_sector(ti, args->next_sector);
|
|
|
|
args->start = fc->start;
|
|
return blkdev_report_zones(fc->dev->bdev, sector, nr_zones,
|
|
dm_report_zones_cb, args);
|
|
}
|
|
#endif
|
|
|
|
static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
|
|
{
|
|
struct flakey_c *fc = ti->private;
|
|
|
|
return fn(ti, fc->dev, fc->start, ti->len, data);
|
|
}
|
|
|
|
static struct target_type flakey_target = {
|
|
.name = "flakey",
|
|
.version = {1, 5, 0},
|
|
#ifdef CONFIG_BLK_DEV_ZONED
|
|
.features = DM_TARGET_ZONED_HM,
|
|
.report_zones = flakey_report_zones,
|
|
#endif
|
|
.module = THIS_MODULE,
|
|
.ctr = flakey_ctr,
|
|
.dtr = flakey_dtr,
|
|
.map = flakey_map,
|
|
.end_io = flakey_end_io,
|
|
.status = flakey_status,
|
|
.prepare_ioctl = flakey_prepare_ioctl,
|
|
.iterate_devices = flakey_iterate_devices,
|
|
};
|
|
|
|
static int __init dm_flakey_init(void)
|
|
{
|
|
int r = dm_register_target(&flakey_target);
|
|
|
|
if (r < 0)
|
|
DMERR("register failed %d", r);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void __exit dm_flakey_exit(void)
|
|
{
|
|
dm_unregister_target(&flakey_target);
|
|
}
|
|
|
|
/* Module hooks */
|
|
module_init(dm_flakey_init);
|
|
module_exit(dm_flakey_exit);
|
|
|
|
MODULE_DESCRIPTION(DM_NAME " flakey target");
|
|
MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
|
|
MODULE_LICENSE("GPL");
|