2 * Copyright (C) 2003 Sistina Software (UK) Limited.
3 * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved.
5 * This file is released under the GPL.
8 #include <linux/device-mapper.h>
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/blkdev.h>
13 #include <linux/bio.h>
14 #include <linux/slab.h>
16 #define DM_MSG_PREFIX "flakey"
19 * Flakey: Used for testing only, simulates intermittent,
20 * catastrophic device failure.
24 unsigned long start_time
;
27 unsigned down_interval
;
31 * Construct a flakey mapping: <dev_path> <offset> <up interval> <down interval>
33 static int flakey_ctr(struct dm_target
*ti
, unsigned int argc
, char **argv
)
36 unsigned long long tmp
;
39 ti
->error
= "dm-flakey: Invalid argument count";
43 fc
= kmalloc(sizeof(*fc
), GFP_KERNEL
);
45 ti
->error
= "dm-flakey: Cannot allocate linear context";
48 fc
->start_time
= jiffies
;
50 if (sscanf(argv
[1], "%llu", &tmp
) != 1) {
51 ti
->error
= "dm-flakey: Invalid device sector";
56 if (sscanf(argv
[2], "%u", &fc
->up_interval
) != 1) {
57 ti
->error
= "dm-flakey: Invalid up interval";
61 if (sscanf(argv
[3], "%u", &fc
->down_interval
) != 1) {
62 ti
->error
= "dm-flakey: Invalid down interval";
66 if (!(fc
->up_interval
+ fc
->down_interval
)) {
67 ti
->error
= "dm-flakey: Total (up + down) interval is zero";
71 if (fc
->up_interval
+ fc
->down_interval
< fc
->up_interval
) {
72 ti
->error
= "dm-flakey: Interval overflow";
76 if (dm_get_device(ti
, argv
[0], dm_table_get_mode(ti
->table
), &fc
->dev
)) {
77 ti
->error
= "dm-flakey: Device lookup failed";
81 ti
->num_flush_requests
= 1;
90 static void flakey_dtr(struct dm_target
*ti
)
92 struct flakey_c
*fc
= ti
->private;
94 dm_put_device(ti
, fc
->dev
);
98 static sector_t
flakey_map_sector(struct dm_target
*ti
, sector_t bi_sector
)
100 struct flakey_c
*fc
= ti
->private;
102 return fc
->start
+ (bi_sector
- ti
->begin
);
105 static void flakey_map_bio(struct dm_target
*ti
, struct bio
*bio
)
107 struct flakey_c
*fc
= ti
->private;
109 bio
->bi_bdev
= fc
->dev
->bdev
;
110 if (bio_sectors(bio
))
111 bio
->bi_sector
= flakey_map_sector(ti
, bio
->bi_sector
);
114 static int flakey_map(struct dm_target
*ti
, struct bio
*bio
,
115 union map_info
*map_context
)
117 struct flakey_c
*fc
= ti
->private;
121 elapsed
= (jiffies
- fc
->start_time
) / HZ
;
122 if (elapsed
% (fc
->up_interval
+ fc
->down_interval
) >= fc
->up_interval
)
125 flakey_map_bio(ti
, bio
);
127 return DM_MAPIO_REMAPPED
;
130 static int flakey_status(struct dm_target
*ti
, status_type_t type
,
131 char *result
, unsigned int maxlen
)
133 struct flakey_c
*fc
= ti
->private;
136 case STATUSTYPE_INFO
:
140 case STATUSTYPE_TABLE
:
141 snprintf(result
, maxlen
, "%s %llu %u %u", fc
->dev
->name
,
142 (unsigned long long)fc
->start
, fc
->up_interval
,
149 static int flakey_ioctl(struct dm_target
*ti
, unsigned int cmd
, unsigned long arg
)
151 struct flakey_c
*fc
= ti
->private;
153 return __blkdev_driver_ioctl(fc
->dev
->bdev
, fc
->dev
->mode
, cmd
, arg
);
156 static int flakey_merge(struct dm_target
*ti
, struct bvec_merge_data
*bvm
,
157 struct bio_vec
*biovec
, int max_size
)
159 struct flakey_c
*fc
= ti
->private;
160 struct request_queue
*q
= bdev_get_queue(fc
->dev
->bdev
);
162 if (!q
->merge_bvec_fn
)
165 bvm
->bi_bdev
= fc
->dev
->bdev
;
166 bvm
->bi_sector
= flakey_map_sector(ti
, bvm
->bi_sector
);
168 return min(max_size
, q
->merge_bvec_fn(q
, bvm
, biovec
));
171 static int flakey_iterate_devices(struct dm_target
*ti
, iterate_devices_callout_fn fn
, void *data
)
173 struct flakey_c
*fc
= ti
->private;
175 return fn(ti
, fc
->dev
, fc
->start
, ti
->len
, data
);
178 static struct target_type flakey_target
= {
180 .version
= {1, 1, 0},
181 .module
= THIS_MODULE
,
185 .status
= flakey_status
,
186 .ioctl
= flakey_ioctl
,
187 .merge
= flakey_merge
,
188 .iterate_devices
= flakey_iterate_devices
,
191 static int __init
dm_flakey_init(void)
193 int r
= dm_register_target(&flakey_target
);
196 DMERR("register failed %d", r
);
201 static void __exit
dm_flakey_exit(void)
203 dm_unregister_target(&flakey_target
);
207 module_init(dm_flakey_init
);
208 module_exit(dm_flakey_exit
);
210 MODULE_DESCRIPTION(DM_NAME
" flakey target");
211 MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
212 MODULE_LICENSE("GPL");