Stupidly switch buffer

master
Vitaliy Filippov 2013-05-20 03:18:55 +04:00
parent b814b86302
commit b39ce6cd68
1 changed files with 36 additions and 12 deletions

48
sftl.c
View File

@ -91,6 +91,21 @@ static void sftl_complete_seg(struct bio *bio, int err)
bio_put(bio); bio_put(bio);
} }
struct sftl_buf_info
{
struct bio *complete_bio;
void *free_buf;
};
static void sftl_complete_buf(struct bio *bio, int err)
{
struct sftl_buf_info *i = bio->bi_private;
bio_endio(i->complete_bio, err);
bio_put(bio);
kfree(i->free_buf);
kfree(i);
}
static void sftl_make_request(struct request_queue *q, struct bio *bio) static void sftl_make_request(struct request_queue *q, struct bio *bio)
{ {
struct sftl_dev *sftl = (struct sftl_dev*)q->queuedata; struct sftl_dev *sftl = (struct sftl_dev*)q->queuedata;
@ -151,20 +166,28 @@ static void sftl_make_request(struct request_queue *q, struct bio *bio)
(unsigned long)bio->bi_sector, (unsigned long)bio_sectors(bio)); (unsigned long)bio->bi_sector, (unsigned long)bio_sectors(bio));
if (sftl->buf_size >= sftl->buf_max) if (sftl->buf_size >= sftl->buf_max)
{ {
// Need to flush the buffer before completing this bio // Need to flush current buffer before completing this bio
int err = bio_submit_kern_seq(sftl->blkdev, sftl->buf, seg_clust*clust_sz+phy_sz, GFP_KERNEL, void *buf = sftl->buf;
sftl->nextfreeseg*(seg_clust*clust_blocks+1), bio, sftl_complete_seg, WRITE); struct sftl_buf_info *info = kmalloc(sizeof(struct sftl_buf_info), GFP_KERNEL);
if (err) int err;
bio_endio(bio, -EIO); info->free_buf = buf;
// FIXME Is it correct?.. I think no... info->complete_bio = bio;
// We stupidly switch buffer (there always will be a finite number of those)
sftl->buf = kmalloc(seg_clust*clust_sz + phy_sz, GFP_KERNEL);
sftl->buf_size = 0; sftl->buf_size = 0;
err = bio_submit_kern_seq(sftl->blkdev, buf, seg_clust*clust_sz+phy_sz, GFP_KERNEL,
sftl->nextfreeseg*(seg_clust*clust_blocks+1), info, sftl_complete_buf, WRITE);
if (err)
{
bio_endio(bio, -EIO);
kfree(buf);
kfree(info);
}
// FIXME Correctly adjust free segment address // FIXME Correctly adjust free segment address
sftl->nextfreeseg++; sftl->nextfreeseg++;
} }
else else
{
bio_endio(bio, 0); bio_endio(bio, 0);
}
} }
} }
@ -318,7 +341,7 @@ static void bio_map_kern_seq_endio(struct bio *bio, int err)
struct bio_seq *seq = bio->bi_private; struct bio_seq *seq = bio->bi_private;
if (err) if (err)
{ {
INFO("I/O err %d", err); INFO("I/O error %d", err);
seq->err = err; seq->err = err;
} }
if (atomic_dec_and_test(&seq->count)) if (atomic_dec_and_test(&seq->count))
@ -362,6 +385,7 @@ static long bio_submit_kern_seq(
int n = 1; int n = 1;
bio->bi_private = NULL; bio->bi_private = NULL;
bio->bi_end_io = bio_map_kern_seq_endio; bio->bi_end_io = bio_map_kern_seq_endio;
seq->err = 0;
seq->endio = endio; seq->endio = endio;
seq->private = private; seq->private = private;
data += bio->bi_size; data += bio->bi_size;
@ -382,13 +406,13 @@ static long bio_submit_kern_seq(
} }
return PTR_ERR(bio2); return PTR_ERR(bio2);
} }
data += bio2->bi_size;
len -= bio2->bi_size;
sector += bio2->bi_size >> 9;
bio2->bi_bdev = bdev; bio2->bi_bdev = bdev;
bio2->bi_sector = sector; bio2->bi_sector = sector;
bio2->bi_private = bio; bio2->bi_private = bio;
bio2->bi_end_io = bio_map_kern_seq_endio; bio2->bi_end_io = bio_map_kern_seq_endio;
data += bio2->bi_size;
len -= bio2->bi_size;
sector += bio2->bi_size >> 9;
bio = bio2; bio = bio2;
n++; n++;
} }