^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2018 Red Hat, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This is a test "dust" device, which fails reads on specified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * sectors, emulating the behavior of a hard disk drive sending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * a "Read Medium Error" sense.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/device-mapper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/rbtree.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define DM_MSG_PREFIX "dust"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct badblock {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct rb_node node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) sector_t bb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) unsigned char wr_fail_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct dust_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct dm_dev *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct rb_root badblocklist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) unsigned long long badblock_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) spinlock_t dust_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) unsigned int blksz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) int sect_per_block_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int sect_per_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) sector_t start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) bool fail_read_on_bb:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) bool quiet_mode:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static struct badblock *dust_rb_search(struct rb_root *root, sector_t blk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct rb_node *node = root->rb_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) while (node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct badblock *bblk = rb_entry(node, struct badblock, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (bblk->bb > blk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) node = node->rb_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) else if (bblk->bb < blk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) node = node->rb_right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return bblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static bool dust_rb_insert(struct rb_root *root, struct badblock *new)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct badblock *bblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct rb_node **link = &root->rb_node, *parent = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) sector_t value = new->bb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) while (*link) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) parent = *link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) bblk = rb_entry(parent, struct badblock, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (bblk->bb > value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) link = &(*link)->rb_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) else if (bblk->bb < value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) link = &(*link)->rb_right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) rb_link_node(&new->node, parent, link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) rb_insert_color(&new->node, root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int dust_remove_block(struct dust_device *dd, unsigned long long block)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct badblock *bblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) bblock = dust_rb_search(&dd->badblocklist, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (bblock == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (!dd->quiet_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) DMERR("%s: block %llu not found in badblocklist",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) __func__, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) rb_erase(&bblock->node, &dd->badblocklist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) dd->badblock_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (!dd->quiet_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) DMINFO("%s: badblock removed at block %llu", __func__, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) kfree(bblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int dust_add_block(struct dust_device *dd, unsigned long long block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) unsigned char wr_fail_cnt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) struct badblock *bblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) bblock = kmalloc(sizeof(*bblock), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (bblock == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!dd->quiet_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) DMERR("%s: badblock allocation failed", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) bblock->bb = block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) bblock->wr_fail_cnt = wr_fail_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!dust_rb_insert(&dd->badblocklist, bblock)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (!dd->quiet_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) DMERR("%s: block %llu already in badblocklist",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) __func__, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) kfree(bblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) dd->badblock_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!dd->quiet_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) DMINFO("%s: badblock added at block %llu with write fail count %hhu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) __func__, block, wr_fail_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static int dust_query_block(struct dust_device *dd, unsigned long long block, char *result,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) unsigned int maxlen, unsigned int *sz_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct badblock *bblock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) unsigned int sz = *sz_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) bblock = dust_rb_search(&dd->badblocklist, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (bblock != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) DMEMIT("%s: block %llu found in badblocklist", __func__, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) DMEMIT("%s: block %llu not found in badblocklist", __func__, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int __dust_map_read(struct dust_device *dd, sector_t thisblock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct badblock *bblk = dust_rb_search(&dd->badblocklist, thisblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) if (bblk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return DM_MAPIO_KILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return DM_MAPIO_REMAPPED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) static int dust_map_read(struct dust_device *dd, sector_t thisblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) bool fail_read_on_bb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) int r = DM_MAPIO_REMAPPED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (fail_read_on_bb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) thisblock >>= dd->sect_per_block_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) r = __dust_map_read(dd, thisblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int __dust_map_write(struct dust_device *dd, sector_t thisblock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct badblock *bblk = dust_rb_search(&dd->badblocklist, thisblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (bblk && bblk->wr_fail_cnt > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) bblk->wr_fail_cnt--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return DM_MAPIO_KILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (bblk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) rb_erase(&bblk->node, &dd->badblocklist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) dd->badblock_count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) kfree(bblk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (!dd->quiet_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) sector_div(thisblock, dd->sect_per_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) DMINFO("block %llu removed from badblocklist by write",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) (unsigned long long)thisblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return DM_MAPIO_REMAPPED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) static int dust_map_write(struct dust_device *dd, sector_t thisblock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) bool fail_read_on_bb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int r = DM_MAPIO_REMAPPED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (fail_read_on_bb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) thisblock >>= dd->sect_per_block_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) r = __dust_map_write(dd, thisblock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static int dust_map(struct dm_target *ti, struct bio *bio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) bio_set_dev(bio, dd->dev->bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) bio->bi_iter.bi_sector = dd->start + dm_target_offset(ti, bio->bi_iter.bi_sector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (bio_data_dir(bio) == READ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) r = dust_map_read(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) r = dust_map_write(dd, bio->bi_iter.bi_sector, dd->fail_read_on_bb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static bool __dust_clear_badblocks(struct rb_root *tree,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) unsigned long long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct rb_node *node = NULL, *nnode = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) nnode = rb_first(tree);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (nnode == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) BUG_ON(count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) while (nnode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) node = nnode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) nnode = rb_next(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) rb_erase(node, tree);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) count--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) kfree(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) BUG_ON(count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) BUG_ON(tree->rb_node != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) static int dust_clear_badblocks(struct dust_device *dd, char *result, unsigned int maxlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) unsigned int *sz_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct rb_root badblocklist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) unsigned long long badblock_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) unsigned int sz = *sz_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) badblocklist = dd->badblocklist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) badblock_count = dd->badblock_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) dd->badblocklist = RB_ROOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) dd->badblock_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (!__dust_clear_badblocks(&badblocklist, badblock_count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) DMEMIT("%s: no badblocks found", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) DMEMIT("%s: badblocks cleared", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static int dust_list_badblocks(struct dust_device *dd, char *result, unsigned int maxlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) unsigned int *sz_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct rb_root badblocklist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct rb_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct badblock *bblk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) unsigned int sz = *sz_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) unsigned long long num = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) badblocklist = dd->badblocklist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) for (node = rb_first(&badblocklist); node; node = rb_next(node)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) bblk = rb_entry(node, struct badblock, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) DMEMIT("%llu\n", bblk->bb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) num++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (!num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) DMEMIT("No blocks in badblocklist");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * Target parameters:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * <device_path> <offset> <blksz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) * device_path: path to the block device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * offset: offset to data area from start of device_path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * blksz: block size (minimum 512, maximum 1073741824, must be a power of 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) static int dust_ctr(struct dm_target *ti, unsigned int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) struct dust_device *dd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) char dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) unsigned int blksz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) unsigned int sect_per_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) sector_t DUST_MAX_BLKSZ_SECTORS = 2097152;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) sector_t max_block_sectors = min(ti->len, DUST_MAX_BLKSZ_SECTORS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (argc != 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ti->error = "Invalid argument count";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (kstrtouint(argv[2], 10, &blksz) || !blksz) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ti->error = "Invalid block size parameter";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (blksz < 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) ti->error = "Block size must be at least 512";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (!is_power_of_2(blksz)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) ti->error = "Block size must be a power of 2";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (to_sector(blksz) > max_block_sectors) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ti->error = "Block size is too large";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) sect_per_block = (blksz >> SECTOR_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) ti->error = "Invalid device offset sector";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) dd = kzalloc(sizeof(struct dust_device), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (dd == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) ti->error = "Cannot allocate context";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dd->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) ti->error = "Device lookup failed";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) kfree(dd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) dd->sect_per_block = sect_per_block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) dd->blksz = blksz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) dd->start = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) dd->sect_per_block_shift = __ffs(sect_per_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * Whether to fail a read on a "bad" block.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * Defaults to false; enabled later by message.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) dd->fail_read_on_bb = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * Initialize bad block list rbtree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) dd->badblocklist = RB_ROOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) dd->badblock_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) spin_lock_init(&dd->dust_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) dd->quiet_mode = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) BUG_ON(dm_set_target_max_io_len(ti, dd->sect_per_block) != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) ti->num_discard_bios = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) ti->num_flush_bios = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ti->private = dd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static void dust_dtr(struct dm_target *ti)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) __dust_clear_badblocks(&dd->badblocklist, dd->badblock_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) dm_put_device(ti, dd->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) kfree(dd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static int dust_message(struct dm_target *ti, unsigned int argc, char **argv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) char *result, unsigned int maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) sector_t size = i_size_read(dd->dev->bdev->bd_inode) >> SECTOR_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) bool invalid_msg = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) int r = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) unsigned long long tmp, block;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) unsigned char wr_fail_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) unsigned int tmp_ui;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) unsigned int sz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) char dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (argc == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (!strcasecmp(argv[0], "addbadblock") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) !strcasecmp(argv[0], "removebadblock") ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) !strcasecmp(argv[0], "queryblock")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) DMERR("%s requires an additional argument", argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) } else if (!strcasecmp(argv[0], "disable")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) DMINFO("disabling read failures on bad sectors");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) dd->fail_read_on_bb = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) } else if (!strcasecmp(argv[0], "enable")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) DMINFO("enabling read failures on bad sectors");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) dd->fail_read_on_bb = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) } else if (!strcasecmp(argv[0], "countbadblocks")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) spin_lock_irqsave(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) DMEMIT("countbadblocks: %llu badblock(s) found",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) dd->badblock_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) spin_unlock_irqrestore(&dd->dust_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) r = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) } else if (!strcasecmp(argv[0], "clearbadblocks")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) r = dust_clear_badblocks(dd, result, maxlen, &sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) } else if (!strcasecmp(argv[0], "quiet")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (!dd->quiet_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) dd->quiet_mode = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) dd->quiet_mode = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) } else if (!strcasecmp(argv[0], "listbadblocks")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) r = dust_list_badblocks(dd, result, maxlen, &sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) invalid_msg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) } else if (argc == 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) block = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) sector_div(size, dd->sect_per_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (block > size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) DMERR("selected block value out of range");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (!strcasecmp(argv[0], "addbadblock"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) r = dust_add_block(dd, block, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) else if (!strcasecmp(argv[0], "removebadblock"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) r = dust_remove_block(dd, block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) else if (!strcasecmp(argv[0], "queryblock"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) r = dust_query_block(dd, block, result, maxlen, &sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) invalid_msg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) } else if (argc == 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (sscanf(argv[2], "%u%c", &tmp_ui, &dummy) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) block = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (tmp_ui > 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) DMERR("selected write fail count out of range");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) wr_fail_cnt = tmp_ui;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) sector_div(size, dd->sect_per_block);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) if (block > size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) DMERR("selected block value out of range");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (!strcasecmp(argv[0], "addbadblock"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) r = dust_add_block(dd, block, wr_fail_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) invalid_msg = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) DMERR("invalid number of arguments '%d'", argc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (invalid_msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) DMERR("unrecognized message '%s' received", argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static void dust_status(struct dm_target *ti, status_type_t type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) unsigned int status_flags, char *result, unsigned int maxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) unsigned int sz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) case STATUSTYPE_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) DMEMIT("%s %s %s", dd->dev->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) dd->fail_read_on_bb ? "fail_read_on_bad_block" : "bypass",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) dd->quiet_mode ? "quiet" : "verbose");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) case STATUSTYPE_TABLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) DMEMIT("%s %llu %u", dd->dev->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) (unsigned long long)dd->start, dd->blksz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) static int dust_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct dm_dev *dev = dd->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) *bdev = dev->bdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * Only pass ioctls through if the device sizes match exactly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (dd->start ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int dust_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) struct dust_device *dd = ti->private;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) return fn(ti, dd->dev, dd->start, ti->len, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) static struct target_type dust_target = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) .name = "dust",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) .version = {1, 0, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) .module = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) .ctr = dust_ctr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) .dtr = dust_dtr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) .iterate_devices = dust_iterate_devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) .map = dust_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) .message = dust_message,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) .status = dust_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) .prepare_ioctl = dust_prepare_ioctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) static int __init dm_dust_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) int r = dm_register_target(&dust_target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (r < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) DMERR("dm_register_target failed %d", r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static void __exit dm_dust_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) dm_unregister_target(&dust_target);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) module_init(dm_dust_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) module_exit(dm_dust_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) MODULE_DESCRIPTION(DM_NAME " dust test target");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) MODULE_AUTHOR("Bryan Gurney <dm-devel@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) MODULE_LICENSE("GPL");