1af1a8899SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2935fe098SMike Snitzer /* 3935fe098SMike Snitzer * faulty.c : Multiple Devices driver for Linux 4935fe098SMike Snitzer * 5935fe098SMike Snitzer * Copyright (C) 2004 Neil Brown 6935fe098SMike Snitzer * 7935fe098SMike Snitzer * fautly-device-simulator personality for md 8935fe098SMike Snitzer */ 9935fe098SMike Snitzer 10935fe098SMike Snitzer 11935fe098SMike Snitzer /* 12935fe098SMike Snitzer * The "faulty" personality causes some requests to fail. 13935fe098SMike Snitzer * 14935fe098SMike Snitzer * Possible failure modes are: 15935fe098SMike Snitzer * reads fail "randomly" but succeed on retry 16935fe098SMike Snitzer * writes fail "randomly" but succeed on retry 17935fe098SMike Snitzer * reads for some address fail and then persist until a write 18935fe098SMike Snitzer * reads for some address fail and then persist irrespective of write 19935fe098SMike Snitzer * writes for some address fail and persist 20935fe098SMike Snitzer * all writes fail 21935fe098SMike Snitzer * 22935fe098SMike Snitzer * Different modes can be active at a time, but only 23935fe098SMike Snitzer * one can be set at array creation. Others can be added later. 24935fe098SMike Snitzer * A mode can be one-shot or recurrent with the recurrence being 25935fe098SMike Snitzer * once in every N requests. 26935fe098SMike Snitzer * The bottom 5 bits of the "layout" indicate the mode. The 27935fe098SMike Snitzer * remainder indicate a period, or 0 for one-shot. 28935fe098SMike Snitzer * 29935fe098SMike Snitzer * There is an implementation limit on the number of concurrently 30935fe098SMike Snitzer * persisting-faulty blocks. When a new fault is requested that would 31935fe098SMike Snitzer * exceed the limit, it is ignored. 32935fe098SMike Snitzer * All current faults can be clear using a layout of "0". 33935fe098SMike Snitzer * 34935fe098SMike Snitzer * Requests are always sent to the device. If they are to fail, 35935fe098SMike Snitzer * we clone the bio and insert a new b_end_io into the chain. 36935fe098SMike Snitzer */ 37935fe098SMike Snitzer 38935fe098SMike Snitzer #define WriteTransient 0 39935fe098SMike Snitzer #define ReadTransient 1 40935fe098SMike Snitzer #define WritePersistent 2 41935fe098SMike Snitzer #define ReadPersistent 3 42935fe098SMike Snitzer #define WriteAll 4 /* doesn't go to device */ 43935fe098SMike Snitzer #define ReadFixable 5 44935fe098SMike Snitzer #define Modes 6 45935fe098SMike Snitzer 46935fe098SMike Snitzer #define ClearErrors 31 47935fe098SMike Snitzer #define ClearFaults 30 48935fe098SMike Snitzer 49935fe098SMike Snitzer #define AllPersist 100 /* internal use only */ 50935fe098SMike Snitzer #define NoPersist 101 51935fe098SMike Snitzer 52935fe098SMike Snitzer #define ModeMask 0x1f 53935fe098SMike Snitzer #define ModeShift 5 54935fe098SMike Snitzer 55935fe098SMike Snitzer #define MaxFault 50 56935fe098SMike Snitzer #include <linux/blkdev.h> 57935fe098SMike Snitzer #include <linux/module.h> 58935fe098SMike Snitzer #include <linux/raid/md_u.h> 59935fe098SMike Snitzer #include <linux/slab.h> 60935fe098SMike Snitzer #include "md.h" 61935fe098SMike Snitzer #include <linux/seq_file.h> 62935fe098SMike Snitzer 63935fe098SMike Snitzer 64935fe098SMike Snitzer static void faulty_fail(struct bio *bio) 65935fe098SMike Snitzer { 66935fe098SMike Snitzer struct bio *b = bio->bi_private; 67935fe098SMike Snitzer 68935fe098SMike Snitzer b->bi_iter.bi_size = bio->bi_iter.bi_size; 69935fe098SMike Snitzer b->bi_iter.bi_sector = bio->bi_iter.bi_sector; 70935fe098SMike Snitzer 71935fe098SMike Snitzer bio_put(bio); 72935fe098SMike Snitzer 73935fe098SMike Snitzer bio_io_error(b); 74935fe098SMike Snitzer } 75935fe098SMike Snitzer 76935fe098SMike Snitzer struct faulty_conf { 77935fe098SMike Snitzer int period[Modes]; 78935fe098SMike Snitzer atomic_t counters[Modes]; 79935fe098SMike Snitzer sector_t faults[MaxFault]; 80935fe098SMike Snitzer int modes[MaxFault]; 81935fe098SMike Snitzer int nfaults; 82935fe098SMike Snitzer struct md_rdev *rdev; 83935fe098SMike Snitzer }; 84935fe098SMike Snitzer 85935fe098SMike Snitzer static int check_mode(struct faulty_conf *conf, int mode) 86935fe098SMike Snitzer { 87935fe098SMike Snitzer if (conf->period[mode] == 0 && 88935fe098SMike Snitzer atomic_read(&conf->counters[mode]) <= 0) 89935fe098SMike Snitzer return 0; /* no failure, no decrement */ 90935fe098SMike Snitzer 91935fe098SMike Snitzer 92935fe098SMike Snitzer if (atomic_dec_and_test(&conf->counters[mode])) { 93935fe098SMike Snitzer if (conf->period[mode]) 94935fe098SMike Snitzer atomic_set(&conf->counters[mode], conf->period[mode]); 95935fe098SMike Snitzer return 1; 96935fe098SMike Snitzer } 97935fe098SMike Snitzer return 0; 98935fe098SMike Snitzer } 99935fe098SMike Snitzer 100935fe098SMike Snitzer static int check_sector(struct faulty_conf *conf, sector_t start, sector_t end, int dir) 101935fe098SMike Snitzer { 102935fe098SMike Snitzer /* If we find a ReadFixable sector, we fix it ... */ 103935fe098SMike Snitzer int i; 104935fe098SMike Snitzer for (i=0; i<conf->nfaults; i++) 105935fe098SMike Snitzer if (conf->faults[i] >= start && 106935fe098SMike Snitzer conf->faults[i] < end) { 107935fe098SMike Snitzer /* found it ... */ 108935fe098SMike Snitzer switch (conf->modes[i] * 2 + dir) { 109935fe098SMike Snitzer case WritePersistent*2+WRITE: return 1; 110935fe098SMike Snitzer case ReadPersistent*2+READ: return 1; 111935fe098SMike Snitzer case ReadFixable*2+READ: return 1; 112935fe098SMike Snitzer case ReadFixable*2+WRITE: 113935fe098SMike Snitzer conf->modes[i] = NoPersist; 114935fe098SMike Snitzer return 0; 115935fe098SMike Snitzer case AllPersist*2+READ: 116935fe098SMike Snitzer case AllPersist*2+WRITE: return 1; 117935fe098SMike Snitzer default: 118935fe098SMike Snitzer return 0; 119935fe098SMike Snitzer } 120935fe098SMike Snitzer } 121935fe098SMike Snitzer return 0; 122935fe098SMike Snitzer } 123935fe098SMike Snitzer 124935fe098SMike Snitzer static void add_sector(struct faulty_conf *conf, sector_t start, int mode) 125935fe098SMike Snitzer { 126935fe098SMike Snitzer int i; 127935fe098SMike Snitzer int n = conf->nfaults; 128935fe098SMike Snitzer for (i=0; i<conf->nfaults; i++) 129935fe098SMike Snitzer if (conf->faults[i] == start) { 130935fe098SMike Snitzer switch(mode) { 131935fe098SMike Snitzer case NoPersist: conf->modes[i] = mode; return; 132935fe098SMike Snitzer case WritePersistent: 133935fe098SMike Snitzer if (conf->modes[i] == ReadPersistent || 134935fe098SMike Snitzer conf->modes[i] == ReadFixable) 135935fe098SMike Snitzer conf->modes[i] = AllPersist; 136935fe098SMike Snitzer else 137935fe098SMike Snitzer conf->modes[i] = WritePersistent; 138935fe098SMike Snitzer return; 139935fe098SMike Snitzer case ReadPersistent: 140935fe098SMike Snitzer if (conf->modes[i] == WritePersistent) 141935fe098SMike Snitzer conf->modes[i] = AllPersist; 142935fe098SMike Snitzer else 143935fe098SMike Snitzer conf->modes[i] = ReadPersistent; 144935fe098SMike Snitzer return; 145935fe098SMike Snitzer case ReadFixable: 146935fe098SMike Snitzer if (conf->modes[i] == WritePersistent || 147935fe098SMike Snitzer conf->modes[i] == ReadPersistent) 148935fe098SMike Snitzer conf->modes[i] = AllPersist; 149935fe098SMike Snitzer else 150935fe098SMike Snitzer conf->modes[i] = ReadFixable; 151935fe098SMike Snitzer return; 152935fe098SMike Snitzer } 153935fe098SMike Snitzer } else if (conf->modes[i] == NoPersist) 154935fe098SMike Snitzer n = i; 155935fe098SMike Snitzer 156935fe098SMike Snitzer if (n >= MaxFault) 157935fe098SMike Snitzer return; 158935fe098SMike Snitzer conf->faults[n] = start; 159935fe098SMike Snitzer conf->modes[n] = mode; 160935fe098SMike Snitzer if (conf->nfaults == n) 161935fe098SMike Snitzer conf->nfaults = n+1; 162935fe098SMike Snitzer } 163935fe098SMike Snitzer 164935fe098SMike Snitzer static bool faulty_make_request(struct mddev *mddev, struct bio *bio) 165935fe098SMike Snitzer { 166935fe098SMike Snitzer struct faulty_conf *conf = mddev->private; 167935fe098SMike Snitzer int failit = 0; 168935fe098SMike Snitzer 169935fe098SMike Snitzer if (bio_data_dir(bio) == WRITE) { 170935fe098SMike Snitzer /* write request */ 171935fe098SMike Snitzer if (atomic_read(&conf->counters[WriteAll])) { 172*ed00aabdSChristoph Hellwig /* special case - don't decrement, don't submit_bio_noacct, 173935fe098SMike Snitzer * just fail immediately 174935fe098SMike Snitzer */ 175935fe098SMike Snitzer bio_io_error(bio); 176935fe098SMike Snitzer return true; 177935fe098SMike Snitzer } 178935fe098SMike Snitzer 179935fe098SMike Snitzer if (check_sector(conf, bio->bi_iter.bi_sector, 180935fe098SMike Snitzer bio_end_sector(bio), WRITE)) 181935fe098SMike Snitzer failit = 1; 182935fe098SMike Snitzer if (check_mode(conf, WritePersistent)) { 183935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector, 184935fe098SMike Snitzer WritePersistent); 185935fe098SMike Snitzer failit = 1; 186935fe098SMike Snitzer } 187935fe098SMike Snitzer if (check_mode(conf, WriteTransient)) 188935fe098SMike Snitzer failit = 1; 189935fe098SMike Snitzer } else { 190935fe098SMike Snitzer /* read request */ 191935fe098SMike Snitzer if (check_sector(conf, bio->bi_iter.bi_sector, 192935fe098SMike Snitzer bio_end_sector(bio), READ)) 193935fe098SMike Snitzer failit = 1; 194935fe098SMike Snitzer if (check_mode(conf, ReadTransient)) 195935fe098SMike Snitzer failit = 1; 196935fe098SMike Snitzer if (check_mode(conf, ReadPersistent)) { 197935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector, 198935fe098SMike Snitzer ReadPersistent); 199935fe098SMike Snitzer failit = 1; 200935fe098SMike Snitzer } 201935fe098SMike Snitzer if (check_mode(conf, ReadFixable)) { 202935fe098SMike Snitzer add_sector(conf, bio->bi_iter.bi_sector, 203935fe098SMike Snitzer ReadFixable); 204935fe098SMike Snitzer failit = 1; 205935fe098SMike Snitzer } 206935fe098SMike Snitzer } 207935fe098SMike Snitzer if (failit) { 208afeee514SKent Overstreet struct bio *b = bio_clone_fast(bio, GFP_NOIO, &mddev->bio_set); 209935fe098SMike Snitzer 210935fe098SMike Snitzer bio_set_dev(b, conf->rdev->bdev); 211935fe098SMike Snitzer b->bi_private = bio; 212935fe098SMike Snitzer b->bi_end_io = faulty_fail; 213935fe098SMike Snitzer bio = b; 214935fe098SMike Snitzer } else 215935fe098SMike Snitzer bio_set_dev(bio, conf->rdev->bdev); 216935fe098SMike Snitzer 217*ed00aabdSChristoph Hellwig submit_bio_noacct(bio); 218935fe098SMike Snitzer return true; 219935fe098SMike Snitzer } 220935fe098SMike Snitzer 221935fe098SMike Snitzer static void faulty_status(struct seq_file *seq, struct mddev *mddev) 222935fe098SMike Snitzer { 223935fe098SMike Snitzer struct faulty_conf *conf = mddev->private; 224935fe098SMike Snitzer int n; 225935fe098SMike Snitzer 226935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WriteTransient])) != 0) 227935fe098SMike Snitzer seq_printf(seq, " WriteTransient=%d(%d)", 228935fe098SMike Snitzer n, conf->period[WriteTransient]); 229935fe098SMike Snitzer 230935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadTransient])) != 0) 231935fe098SMike Snitzer seq_printf(seq, " ReadTransient=%d(%d)", 232935fe098SMike Snitzer n, conf->period[ReadTransient]); 233935fe098SMike Snitzer 234935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WritePersistent])) != 0) 235935fe098SMike Snitzer seq_printf(seq, " WritePersistent=%d(%d)", 236935fe098SMike Snitzer n, conf->period[WritePersistent]); 237935fe098SMike Snitzer 238935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadPersistent])) != 0) 239935fe098SMike Snitzer seq_printf(seq, " ReadPersistent=%d(%d)", 240935fe098SMike Snitzer n, conf->period[ReadPersistent]); 241935fe098SMike Snitzer 242935fe098SMike Snitzer 243935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[ReadFixable])) != 0) 244935fe098SMike Snitzer seq_printf(seq, " ReadFixable=%d(%d)", 245935fe098SMike Snitzer n, conf->period[ReadFixable]); 246935fe098SMike Snitzer 247935fe098SMike Snitzer if ((n=atomic_read(&conf->counters[WriteAll])) != 0) 248935fe098SMike Snitzer seq_printf(seq, " WriteAll"); 249935fe098SMike Snitzer 250935fe098SMike Snitzer seq_printf(seq, " nfaults=%d", conf->nfaults); 251935fe098SMike Snitzer } 252935fe098SMike Snitzer 253935fe098SMike Snitzer 254935fe098SMike Snitzer static int faulty_reshape(struct mddev *mddev) 255935fe098SMike Snitzer { 256935fe098SMike Snitzer int mode = mddev->new_layout & ModeMask; 257935fe098SMike Snitzer int count = mddev->new_layout >> ModeShift; 258935fe098SMike Snitzer struct faulty_conf *conf = mddev->private; 259935fe098SMike Snitzer 260935fe098SMike Snitzer if (mddev->new_layout < 0) 261935fe098SMike Snitzer return 0; 262935fe098SMike Snitzer 263935fe098SMike Snitzer /* new layout */ 264935fe098SMike Snitzer if (mode == ClearFaults) 265935fe098SMike Snitzer conf->nfaults = 0; 266935fe098SMike Snitzer else if (mode == ClearErrors) { 267935fe098SMike Snitzer int i; 268935fe098SMike Snitzer for (i=0 ; i < Modes ; i++) { 269935fe098SMike Snitzer conf->period[i] = 0; 270935fe098SMike Snitzer atomic_set(&conf->counters[i], 0); 271935fe098SMike Snitzer } 272935fe098SMike Snitzer } else if (mode < Modes) { 273935fe098SMike Snitzer conf->period[mode] = count; 274935fe098SMike Snitzer if (!count) count++; 275935fe098SMike Snitzer atomic_set(&conf->counters[mode], count); 276935fe098SMike Snitzer } else 277935fe098SMike Snitzer return -EINVAL; 278935fe098SMike Snitzer mddev->new_layout = -1; 279935fe098SMike Snitzer mddev->layout = -1; /* makes sure further changes come through */ 280935fe098SMike Snitzer return 0; 281935fe098SMike Snitzer } 282935fe098SMike Snitzer 283935fe098SMike Snitzer static sector_t faulty_size(struct mddev *mddev, sector_t sectors, int raid_disks) 284935fe098SMike Snitzer { 285935fe098SMike Snitzer WARN_ONCE(raid_disks, 286935fe098SMike Snitzer "%s does not support generic reshape\n", __func__); 287935fe098SMike Snitzer 288935fe098SMike Snitzer if (sectors == 0) 289935fe098SMike Snitzer return mddev->dev_sectors; 290935fe098SMike Snitzer 291935fe098SMike Snitzer return sectors; 292935fe098SMike Snitzer } 293935fe098SMike Snitzer 294935fe098SMike Snitzer static int faulty_run(struct mddev *mddev) 295935fe098SMike Snitzer { 296935fe098SMike Snitzer struct md_rdev *rdev; 297935fe098SMike Snitzer int i; 298935fe098SMike Snitzer struct faulty_conf *conf; 299935fe098SMike Snitzer 300935fe098SMike Snitzer if (md_check_no_bitmap(mddev)) 301935fe098SMike Snitzer return -EINVAL; 302935fe098SMike Snitzer 303935fe098SMike Snitzer conf = kmalloc(sizeof(*conf), GFP_KERNEL); 304935fe098SMike Snitzer if (!conf) 305935fe098SMike Snitzer return -ENOMEM; 306935fe098SMike Snitzer 307935fe098SMike Snitzer for (i=0; i<Modes; i++) { 308935fe098SMike Snitzer atomic_set(&conf->counters[i], 0); 309935fe098SMike Snitzer conf->period[i] = 0; 310935fe098SMike Snitzer } 311935fe098SMike Snitzer conf->nfaults = 0; 312935fe098SMike Snitzer 313935fe098SMike Snitzer rdev_for_each(rdev, mddev) { 314935fe098SMike Snitzer conf->rdev = rdev; 315935fe098SMike Snitzer disk_stack_limits(mddev->gendisk, rdev->bdev, 316935fe098SMike Snitzer rdev->data_offset << 9); 317935fe098SMike Snitzer } 318935fe098SMike Snitzer 319935fe098SMike Snitzer md_set_array_sectors(mddev, faulty_size(mddev, 0, 0)); 320935fe098SMike Snitzer mddev->private = conf; 321935fe098SMike Snitzer 322935fe098SMike Snitzer faulty_reshape(mddev); 323935fe098SMike Snitzer 324935fe098SMike Snitzer return 0; 325935fe098SMike Snitzer } 326935fe098SMike Snitzer 327935fe098SMike Snitzer static void faulty_free(struct mddev *mddev, void *priv) 328935fe098SMike Snitzer { 329935fe098SMike Snitzer struct faulty_conf *conf = priv; 330935fe098SMike Snitzer 331935fe098SMike Snitzer kfree(conf); 332935fe098SMike Snitzer } 333935fe098SMike Snitzer 334935fe098SMike Snitzer static struct md_personality faulty_personality = 335935fe098SMike Snitzer { 336935fe098SMike Snitzer .name = "faulty", 337935fe098SMike Snitzer .level = LEVEL_FAULTY, 338935fe098SMike Snitzer .owner = THIS_MODULE, 339935fe098SMike Snitzer .make_request = faulty_make_request, 340935fe098SMike Snitzer .run = faulty_run, 341935fe098SMike Snitzer .free = faulty_free, 342935fe098SMike Snitzer .status = faulty_status, 343935fe098SMike Snitzer .check_reshape = faulty_reshape, 344935fe098SMike Snitzer .size = faulty_size, 345935fe098SMike Snitzer }; 346935fe098SMike Snitzer 347935fe098SMike Snitzer static int __init raid_init(void) 348935fe098SMike Snitzer { 349935fe098SMike Snitzer return register_md_personality(&faulty_personality); 350935fe098SMike Snitzer } 351935fe098SMike Snitzer 352935fe098SMike Snitzer static void raid_exit(void) 353935fe098SMike Snitzer { 354935fe098SMike Snitzer unregister_md_personality(&faulty_personality); 355935fe098SMike Snitzer } 356935fe098SMike Snitzer 357935fe098SMike Snitzer module_init(raid_init); 358935fe098SMike Snitzer module_exit(raid_exit); 359935fe098SMike Snitzer MODULE_LICENSE("GPL"); 360935fe098SMike Snitzer MODULE_DESCRIPTION("Fault injection personality for MD"); 361935fe098SMike Snitzer MODULE_ALIAS("md-personality-10"); /* faulty */ 362935fe098SMike Snitzer MODULE_ALIAS("md-faulty"); 363935fe098SMike Snitzer MODULE_ALIAS("md-level--5"); 364