Read maps
parent
11f555de13
commit
bf609346c3
101
sftl.c
101
sftl.c
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue