Skip to content

Commit 3ef825d

Browse files
Shida Zhangaxboe
authored andcommitted
bcache: use bio cloning for detached device requests
Previously, bcache hijacked the bi_end_io and bi_private fields of the incoming bio when the backing device was in a detached state. This is fragile and breaks if the bio is needed to be processed by other layers. This patch transitions to using a cloned bio embedded within a private structure. This ensures the original bio's metadata remains untouched. Fixes: 53280e3 ("bcache: fix improper use of bi_end_io") Co-developed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Shida Zhang <zhangshida@kylinos.cn> Acked-by: Coly Li <colyli@fnnas.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 046be7e commit 3ef825d

3 files changed

Lines changed: 54 additions & 46 deletions

File tree

drivers/md/bcache/bcache.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ struct bcache_device {
273273

274274
struct bio_set bio_split;
275275

276+
struct bio_set bio_detached;
277+
276278
unsigned int data_csum:1;
277279

278280
int (*cache_miss)(struct btree *b, struct search *s,
@@ -753,6 +755,13 @@ struct bbio {
753755
struct bio bio;
754756
};
755757

758+
struct detached_dev_io_private {
759+
struct bcache_device *d;
760+
unsigned long start_time;
761+
struct bio *orig_bio;
762+
struct bio bio;
763+
};
764+
756765
#define BTREE_PRIO USHRT_MAX
757766
#define INITIAL_PRIO 32768U
758767

drivers/md/bcache/request.c

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,68 +1077,58 @@ static CLOSURE_CALLBACK(cached_dev_nodata)
10771077
continue_at(cl, cached_dev_bio_complete, NULL);
10781078
}
10791079

1080-
struct detached_dev_io_private {
1081-
struct bcache_device *d;
1082-
unsigned long start_time;
1083-
bio_end_io_t *bi_end_io;
1084-
void *bi_private;
1085-
struct block_device *orig_bdev;
1086-
};
1087-
10881080
static void detached_dev_end_io(struct bio *bio)
10891081
{
1090-
struct detached_dev_io_private *ddip;
1091-
1092-
ddip = bio->bi_private;
1093-
bio->bi_end_io = ddip->bi_end_io;
1094-
bio->bi_private = ddip->bi_private;
1082+
struct detached_dev_io_private *ddip =
1083+
container_of(bio, struct detached_dev_io_private, bio);
1084+
struct bio *orig_bio = ddip->orig_bio;
10951085

10961086
/* Count on the bcache device */
1097-
bio_end_io_acct_remapped(bio, ddip->start_time, ddip->orig_bdev);
1087+
bio_end_io_acct(orig_bio, ddip->start_time);
10981088

10991089
if (bio->bi_status) {
1100-
struct cached_dev *dc = container_of(ddip->d,
1101-
struct cached_dev, disk);
1090+
struct cached_dev *dc = bio->bi_private;
1091+
11021092
/* should count I/O error for backing device here */
11031093
bch_count_backing_io_errors(dc, bio);
1094+
orig_bio->bi_status = bio->bi_status;
11041095
}
11051096

1106-
kfree(ddip);
1107-
bio_endio(bio);
1097+
bio_put(bio);
1098+
bio_endio(orig_bio);
11081099
}
11091100

1110-
static void detached_dev_do_request(struct bcache_device *d, struct bio *bio,
1111-
struct block_device *orig_bdev, unsigned long start_time)
1101+
static void detached_dev_do_request(struct bcache_device *d,
1102+
struct bio *orig_bio, unsigned long start_time)
11121103
{
11131104
struct detached_dev_io_private *ddip;
11141105
struct cached_dev *dc = container_of(d, struct cached_dev, disk);
1106+
struct bio *clone_bio;
11151107

1116-
/*
1117-
* no need to call closure_get(&dc->disk.cl),
1118-
* because upper layer had already opened bcache device,
1119-
* which would call closure_get(&dc->disk.cl)
1120-
*/
1121-
ddip = kzalloc(sizeof(struct detached_dev_io_private), GFP_NOIO);
1122-
if (!ddip) {
1123-
bio->bi_status = BLK_STS_RESOURCE;
1124-
bio_endio(bio);
1108+
if (bio_op(orig_bio) == REQ_OP_DISCARD &&
1109+
!bdev_max_discard_sectors(dc->bdev)) {
1110+
bio_endio(orig_bio);
11251111
return;
11261112
}
11271113

1128-
ddip->d = d;
1114+
clone_bio = bio_alloc_clone(dc->bdev, orig_bio, GFP_NOIO,
1115+
&d->bio_detached);
1116+
if (!clone_bio) {
1117+
orig_bio->bi_status = BLK_STS_RESOURCE;
1118+
bio_endio(orig_bio);
1119+
return;
1120+
}
1121+
1122+
ddip = container_of(clone_bio, struct detached_dev_io_private, bio);
11291123
/* Count on the bcache device */
1130-
ddip->orig_bdev = orig_bdev;
1124+
ddip->d = d;
11311125
ddip->start_time = start_time;
1132-
ddip->bi_end_io = bio->bi_end_io;
1133-
ddip->bi_private = bio->bi_private;
1134-
bio->bi_end_io = detached_dev_end_io;
1135-
bio->bi_private = ddip;
1136-
1137-
if ((bio_op(bio) == REQ_OP_DISCARD) &&
1138-
!bdev_max_discard_sectors(dc->bdev))
1139-
detached_dev_end_io(bio);
1140-
else
1141-
submit_bio_noacct(bio);
1126+
ddip->orig_bio = orig_bio;
1127+
1128+
clone_bio->bi_end_io = detached_dev_end_io;
1129+
clone_bio->bi_private = dc;
1130+
1131+
submit_bio_noacct(clone_bio);
11421132
}
11431133

11441134
static void quit_max_writeback_rate(struct cache_set *c,
@@ -1214,10 +1204,10 @@ void cached_dev_submit_bio(struct bio *bio)
12141204

12151205
start_time = bio_start_io_acct(bio);
12161206

1217-
bio_set_dev(bio, dc->bdev);
12181207
bio->bi_iter.bi_sector += dc->sb.data_offset;
12191208

12201209
if (cached_dev_get(dc)) {
1210+
bio_set_dev(bio, dc->bdev);
12211211
s = search_alloc(bio, d, orig_bdev, start_time);
12221212
trace_bcache_request_start(s->d, bio);
12231213

@@ -1237,9 +1227,10 @@ void cached_dev_submit_bio(struct bio *bio)
12371227
else
12381228
cached_dev_read(dc, s);
12391229
}
1240-
} else
1230+
} else {
12411231
/* I/O request sent to backing device */
1242-
detached_dev_do_request(d, bio, orig_bdev, start_time);
1232+
detached_dev_do_request(d, bio, start_time);
1233+
}
12431234
}
12441235

12451236
static int cached_dev_ioctl(struct bcache_device *d, blk_mode_t mode,

drivers/md/bcache/super.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ static void bcache_device_free(struct bcache_device *d)
887887
}
888888

889889
bioset_exit(&d->bio_split);
890+
bioset_exit(&d->bio_detached);
890891
kvfree(d->full_dirty_stripes);
891892
kvfree(d->stripe_sectors_dirty);
892893

@@ -949,6 +950,11 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
949950
BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
950951
goto out_ida_remove;
951952

953+
if (bioset_init(&d->bio_detached, 4,
954+
offsetof(struct detached_dev_io_private, bio),
955+
BIOSET_NEED_BVECS|BIOSET_NEED_RESCUER))
956+
goto out_bioset_split_exit;
957+
952958
if (lim.logical_block_size > PAGE_SIZE && cached_bdev) {
953959
/*
954960
* This should only happen with BCACHE_SB_VERSION_BDEV.
@@ -964,7 +970,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
964970

965971
d->disk = blk_alloc_disk(&lim, NUMA_NO_NODE);
966972
if (IS_ERR(d->disk))
967-
goto out_bioset_exit;
973+
goto out_bioset_detach_exit;
968974

969975
set_capacity(d->disk, sectors);
970976
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", idx);
@@ -976,7 +982,9 @@ static int bcache_device_init(struct bcache_device *d, unsigned int block_size,
976982
d->disk->private_data = d;
977983
return 0;
978984

979-
out_bioset_exit:
985+
out_bioset_detach_exit:
986+
bioset_exit(&d->bio_detached);
987+
out_bioset_split_exit:
980988
bioset_exit(&d->bio_split);
981989
out_ida_remove:
982990
ida_free(&bcache_device_idx, idx);

0 commit comments

Comments
 (0)