Read maps

master
Vitaliy Filippov 2013-05-18 03:45:11 +04:00
parent 11f555de13
commit bf609346c3
1 changed files with 71 additions and 30 deletions

101
sftl.c
View File

@ -2,7 +2,7 @@
* Simple log-structured translation layer for FTLed flash drives
* like memory cards or USB sticks.
*
* (C) 2013 Vitaliy Filippov <vitalif at mail dot ru>
* (C) 2013 Vitaliy Filippov <vitalif at mail d0t ru>
* Redistributable under the terms of the GNU GPL 3.0+.
*/
@ -31,16 +31,21 @@ MODULE_DESCRIPTION("Log-structured translation layer for USB sticks and memory c
MODULE_VERSION("0.1");
static int major_num = 0;
static int phy_sz = 512;
static int clust_sz = 4096;
static int clust_blocks = 4096/512;
static int seg_sz = 512/16; /* in blocks */
const u32 magic = 0x4C544673; // Magic: sFTL
const int phy_sz = 512;
const int clust_sz = 4096;
const int clust_blocks = 4096/512;
const int seg_sz = 512/16; /* (32) clusters */
/* Mapping element */
struct sftl_map {
u32 magic, blk, ver, crc;
u32 magic, block, ver, checksum;
};
/* Trivial checksum using some prime number */
#define sftl_map_checksum(m) ((u32)((1+(m).block+((m).magic>>16))*(1+(m).ver+((m).magic&0xFFFF))*0xC4489EF5))
/* The internal representation of our device */
struct sftl_dev {
u32 size; // device size in blocks
@ -48,7 +53,7 @@ struct sftl_dev {
u32 reserved_segs;
u32 *map, *ver; // block mappings and versions
u32 nextblk; // next free block pointer
u32 freeblks, freesegs; // free block count, free segment count
u32 freeclust, freesegs; // free block count, free segment count
struct gendisk *gd;
struct block_device *blkdev;
struct request_queue *queue;
@ -78,6 +83,7 @@ static void sftl_transfer(struct sftl_dev *dev, sector_t sector,
INFO("Beyond-end write (starting sector = %ld, count = %ld)", offset, nblocks);
return;
}
// TODO
}
@ -195,6 +201,56 @@ static void endFunc_tryKM2(struct bio *bb, int err)
}
}
static void sync_read(struct block_device *bdev, unsigned sector, void *buf, unsigned len)
{
struct bio *bb;
struct request_queue *q;
DECLARE_COMPLETION_ONSTACK(waithandle);
q = bdev_get_queue(bdev);
bb = bio_map_kern(q, buf, len, GFP_KERNEL);
if (IS_ERR(bb))
return;
bb->bi_sector = sector;
bb->bi_bdev = bdev;
bb->bi_private = &waithandle;
bb->bi_end_io = endFunc_tryKM2;
submit_bio(READ, bb);
if (!(bb->bi_flags & (1 << BIO_UPTODATE)))
{
bio_put(bb);
return;
}
wait_for_completion(&waithandle);
bio_put(bb);
}
static void read_maps(struct sftl_dev *dev)
{
struct sftl_map *buf = kmalloc(phy_sz, GFP_KERNEL);
int i, j, seg;
INFO("reading translation maps");
for (i = 0; i < dev->segs; i++)
{
sync_read(dev->blkdev, i*(seg_sz*clust_blocks+1), buf, phy_sz);
for (seg = 1, j = 0; j < seg_sz; j++)
{
if (buf[j].magic == magic && buf[j].checksum == sftl_map_checksum(buf[j]))
{
dev->map[i*seg_sz+j] = buf[j].block;
dev->ver[i*seg_sz+j] = buf[j].ver;
seg = 0;
}
else
{
dev->ver[i*seg_sz+j] = 0;
dev->freeclust++;
}
}
dev->freesegs += seg;
}
kfree(buf);
}
static struct sftl_dev *add_device(char *devname)
{
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
@ -232,9 +288,11 @@ static struct sftl_dev *add_device(char *devname)
t = dev->blkdev->bd_inode->i_size;
do_div(t, clust_sz*seg_sz + phy_sz);
dev->segs = (uint32_t)t; //!!!
dev->segs = t;
dev->size = dev->segs * seg_sz * clust_blocks;
dev->reserved_segs = seg_sz * (seg_sz+1);
dev->map = vmalloc(sizeof(u32) * dev->size);
dev->ver = vmalloc(sizeof(u32) * dev->size);
/* Get a request queue */
spin_lock_init(&dev->spinlock);
@ -265,32 +323,15 @@ static struct sftl_dev *add_device(char *devname)
snprintf(dev->gd->disk_name, 32, "sftl%d", index);
set_capacity(dev->gd, dev->size);
dev->gd->queue = dev->queue;
INFO("gd = %d %d %d", dev->gd->minors, dev->gd->major, dev->gd->first_minor);
add_disk(dev->gd);
/* Read maps from the device */
struct bio *bb;
DECLARE_COMPLETION_ONSTACK(waithandle);
bb = bio_map_kern(bdev->bd_disk->queue, buf, phy_sz, GFP_KERNEL);
if (IS_ERR(bb))
{
vfree(buf);
return;
}
bb->bi_sector = 0;
bb->bi_bdev = bdev;
bb->bi_private = &waithandle;
bb->bi_end_io = endFunc_tryKM2;
submit_bio(READ, bb);
if (!(bb->bi_flags & (1 << BIO_UPTODATE)))
{
bio_put(bb);
vfree(buf);
return;
}
read_maps(dev);
/* Add disk */
add_disk(dev->gd);
list_add(&dev->list, &sftl_device_list);
INFO("%s: translating %s; %d sectors", dev->gd->disk_name, devname, dev->size);
INFO("%s: translating %s; %d sectors; %d free", dev->gd->disk_name, devname, dev->size, dev->freeclust*clust_blocks);
return dev;
devinit_err: