I really want to write it

master
Vitaliy Filippov 2013-05-09 03:25:03 +04:00
parent c0aa4d19cb
commit 19750efd6b
2 changed files with 175 additions and 79 deletions

5
STL
View File

@ -49,9 +49,12 @@ N = index block size / 16 = phys block size / 16 = 32
<skip cost for raw NAND> = WRITE*(int(O*S/E) > int(L*S/E) ? ((O*S)%E) : 0)
Data structures:
* Mapping/version array: 8b * block count = 8MB for 4GB flash and 4096/512 map/phys sizes
* Mapping/version array: 8b * block count ~~ 8MB for 4GB flash and 4096/512 map/phys sizes
* Next block pointer: exactly 1 integer because STL flash is a ring buffer
filled with number of first free block followed or included in an empty sequence
* Free segment counter
* Free block counter
* (MAYBE) R-B tree / list of segments having at least one free block
USB flash read/write cost:
* Write <8Kb cost = 4 * (Random read <8Kb cost)

249
sftl.c
View File

@ -1,9 +1,9 @@
/*
* A sample, extra-simple block driver. Updated for kernel 2.6.31.
* Simple log-structured translation layer for FTLed flash drives
* like memory cards or USB sticks.
*
* (C) 2003 Eklektix, Inc.
* (C) 2010 Pat Patterson <pat at superpat dot com>
* Redistributable under the terms of the GNU GPL.
* (C) 2013 Vitaliy Filippov <vitalif at mail dot ru>
* Redistributable under the terms of the GNU GPL 3.0+.
*/
#include <linux/module.h>
@ -19,36 +19,39 @@
#include <linux/blkdev.h>
#include <linux/hdreg.h>
MODULE_LICENSE("Dual BSD/GPL");
static char *Version = "1.4";
static int major_num = 0;
module_param(major_num, int, 0);
static int logical_block_size = 512;
module_param(logical_block_size, int, 0);
static int nsectors = 1024; /* How big the drive is */
module_param(nsectors, int, 0);
/*
* We can tweak our hardware sector size, but the kernel talks to us
* in terms of small sectors, always.
*/
#define KERNEL_SECTOR_SIZE 512
/*
* Our request queue.
*/
static struct request_queue *Queue;
#define ERROR(fmt, args...) printk(KERN_ERR "sftl: " fmt "\n" , ## args)
#define INFO(fmt, args...) printk(KERN_INFO "sftl: " fmt "\n" , ## args)
/*
* The internal representation of our device.
*/
static struct sbd_device {
unsigned long size;
spinlock_t lock;
u8 *data;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vitaliy Filippov <vitalif@mail.ru>");
MODULE_DESCRIPTION("Log-structured translation layer for USB sticks and memory cards");
static char *Version = "0.1";
static int major_num = 0;
static int phy_sz = 512;
static int clust_sz = 4096;
static int clust_blocks = clust_sz/phy_sz;
static int seg_sz = phy_sz/16; /* in blocks */
/* The internal representation of our device */
struct sftl_dev {
u32 size; // device size in blocks
u32 *map, *ver; // block mappings and versions
u32 nextblk; // next free block pointer
u32 freeblks, freesegs; // free block count, free segment count
struct gendisk *gd;
} Device;
struct block_device *blkdev;
struct request_queue *queue;
spinlock_t spinlock;
struct mutex write_mutex;
struct list_head list;
};
/* Our block device list, used in cleanup_module */
static LIST_HEAD(blkmtd_device_list);
/*
* Handle an I/O request.
@ -109,67 +112,157 @@ int sbd_getgeo(struct block_device * block_device, struct hd_geometry * geo) {
/*
* The device operations structure.
*/
static struct block_device_operations sbd_ops = {
.owner = THIS_MODULE,
.getgeo = sbd_getgeo
static struct block_device_operations sftl_ops = {
.owner = THIS_MODULE,
.getgeo = sbd_getgeo
};
static int __init sbd_init(void) {
static int __init sftl_init(void)
{
/*
* Set up our internal device.
* Register major number
*/
Device.size = nsectors * logical_block_size;
spin_lock_init(&Device.lock);
Device.data = vmalloc(Device.size);
if (Device.data == NULL)
return -ENOMEM;
/*
* Get a request queue.
*/
Queue = blk_init_queue(sbd_request, &Device.lock);
if (Queue == NULL)
goto out;
blk_queue_logical_block_size(Queue, logical_block_size);
/*
* Get registered.
*/
major_num = register_blkdev(major_num, "sbd");
if (major_num < 0) {
printk(KERN_WARNING "sbd: unable to get major number\n");
major_num = register_blkdev(major_num, "sftl");
if (major_num < 0)
{
printk(KERN_WARNING "sftl: unable to get major number\n");
goto out;
}
/*
* And the gendisk structure.
*/
Device.gd = alloc_disk(16);
if (!Device.gd)
goto out_unregister;
Device.gd->major = major_num;
Device.gd->first_minor = 0;
Device.gd->fops = &sbd_ops;
Device.gd->private_data = &Device;
strcpy(Device.gd->disk_name, "sbd0");
set_capacity(Device.gd, nsectors);
Device.gd->queue = Queue;
add_disk(Device.gd);
return 0;
out_unregister:
unregister_blkdev(major_num, "sbd");
out:
vfree(Device.data);
return -ENOMEM;
}
static void __exit sbd_exit(void)
static void __exit sftl_exit(void)
{
del_gendisk(Device.gd);
put_disk(Device.gd);
unregister_blkdev(major_num, "sbd");
unregister_blkdev(major_num, "sftl");
blk_cleanup_queue(Queue);
vfree(Device.data);
}
module_init(sbd_init);
module_exit(sbd_exit);
module_init(sftl_init);
module_exit(sftl_exit);
static struct sftl_dev *add_device(char *devname)
{
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev;
struct sftl_dev *dev;
char *name;
if (!devname)
return NULL;
dev = kzalloc(sizeof(struct sftl_dev), GFP_KERNEL);
if (!dev)
return NULL;
/**
* Get a handle on the device
*/
bdev = blkdev_get_by_path(devname, mode, dev);
if (IS_ERR(bdev))
{
ERROR("cannot open device %s", devname);
goto devinit_err;
}
dev->blkdev = bdev;
/* if (MAJOR(bdev->bd_dev) == major_num)
{
ERROR("attempting to use an SFTL device into another SFTL device");
goto devinit_err;
}*/
mutex_init(&dev->write_mutex);
dev->segs = bdev->bd_block_size / clust_blocks / (seg_sz+1);
dev->size = dev->segs * seg_sz * clust_blocks;
dev->reserved_segs = seg_sz * (seg_sz+1);
/*
* Get a request queue
*/
spin_lock_init(&dev->spinlock);
dev->queue = blk_init_queue(sftl_request, &dev->spinlock);
if (dev->queue == NULL)
goto devinit_err;
blk_queue_logical_block_size(dev->queue, clust_sz);
/*
* And the gendisk structure
*/
dev->gd = alloc_disk(16);
if (!dev->gd)
goto devinit_err;
dev->gd->major = major_num;
dev->gd->first_minor = 0;//!!!
dev->gd->fops = &sftl_ops;
dev->gd->private_data = dev;
strcpy(dev->gd->disk_name, "sftl0");//!!!
set_capacity(dev->gd, dev->size);
dev->gd->queue = dev->queue;
add_disk(dev->gd);
list_add(&dev->list, &sftl_device_list);
INFO("/dev/sftl%d: [%s]", !!!, devname);
return dev;
devinit_err:
sftl_free_device(dev);
return NULL;
}
static inline void kill_final_newline(char *str)
{
char *newline = strrchr(str, '\n');
if (newline && !newline[1])
*newline = 0;
}
static int sftl_setup(const char *val, struct kernel_param *kp)
{
char buf[80 + 12];
char *str = buf;
char *token[2];
char *name;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
{
ERROR("parameter too long");
return 0;
}
strcpy(str, val);
kill_final_newline(str);
for (i = 0; i < 1; i++)
token[i] = strsep(&str, ",");
if (str)
{
ERROR("too much parameters");
return 0;
}
if (!token[0])
{
ERROR("underlying block device name missing");
return 0;
}
name = token[0];
if (strlen(name) + 1 > 80)
{
ERROR("device name too long");
return 0;
}
add_device(name);
return 0;
}
module_param_call(dev, sftl_setup, NULL, NULL, 0200);
MODULE_PARM_DESC(dev, "Underlying device to use. \"dev=<dev>\"");