forget in block layer for ftl's

Sean Young sean at mess.org
Fri Nov 18 15:39:32 EST 2005


This is my first stab at implementing a forget functionality in the block
layer which the FTL's can use. 

See:

http://lists.infradead.org/pipermail/linux-mtd/2005-June/012858.html

Right now it's still very limited as only the FAT file system driver and
the RFD FTL uses the functionality.

Basically, I've added a blkdev_issue_forget() function to the block
layer and .forgetsect() to struct mtd_blktrans_ops.

I would really appreciate your comments on this approach.

The patch is against 2.6.15-rc1.


Sean

diff -urpN linux-2.6.14/block/ll_rw_blk.c linux-forget/block/ll_rw_blk.c
--- linux-2.6.14/block/ll_rw_blk.c	2005-11-18 06:25:51.000000000 +0100
+++ linux-forget/block/ll_rw_blk.c	2005-11-18 21:22:31.000000000 +0100
@@ -1058,6 +1058,7 @@ static char *rq_flags[] = {
 	"REQ_DRIVE_TASK",
 	"REQ_DRIVE_TASKFILE",
 	"REQ_PREEMPT",
+	"REQ_FORGET",
 	"REQ_PM_SUSPEND",
 	"REQ_PM_RESUME",
 	"REQ_PM_SHUTDOWN",
@@ -2379,6 +2380,44 @@ int blkdev_issue_flush(struct block_devi
 
 EXPORT_SYMBOL(blkdev_issue_flush);
 
+/**
+ * blkdev_issue_forget() - inform block device of stale sectors
+ * @bdev: block device to issue forget for
+ * @sector: first sector that can be forgotten
+ * @size: amount of bytes that can be forgotten
+ */
+
+void blkdev_issue_forget(struct block_device *bdev, sector_t sector, int size)
+{
+	request_queue_t *q;
+	struct request *rq;
+
+	q = bdev_get_queue(bdev);
+
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	rq->errors = 0;
+	rq->rq_disk = bdev->bd_disk;
+	rq->bio = NULL;
+	rq->buffer = NULL;
+	rq->timeout = 60*HZ;
+	rq->data = NULL;
+	rq->data_len = 0;
+	rq->flags |= REQ_FORGET | REQ_SOFTBARRIER | REQ_NOMERGE;
+	rq->sector = sector;
+	rq->current_nr_sectors = size >> 9;
+
+	if (bdev != bdev->bd_contains) {
+		struct hd_struct *p = bdev->bd_part;
+
+		rq->sector += p->start_sect;
+		rq->rq_disk = bdev->bd_contains;
+	}
+
+	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+}
+
+EXPORT_SYMBOL(blkdev_issue_forget);
+
 static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
 	int rw = rq_data_dir(rq);
diff -urpN linux-2.6.14/drivers/mtd/mtd_blkdevs.c linux-forget/drivers/mtd/mtd_blkdevs.c
--- linux-2.6.14/drivers/mtd/mtd_blkdevs.c	2005-11-18 06:26:01.000000000 +0100
+++ linux-forget/drivers/mtd/mtd_blkdevs.c	2005-11-18 21:13:52.000000000 +0100
@@ -46,6 +46,15 @@ static int do_blktrans_request(struct mt
 	nsect = req->current_nr_sectors;
 	buf = req->buffer;
 
+	if (req->flags & REQ_FORGET)  {
+		if (tr->forgetsect)
+			for (; nsect > 0; nsect--) 
+				if (tr->forgetsect(dev, block++))
+					return 0;
+
+		return 1;
+	}
+
 	if (!(req->flags & REQ_CMD))
 		return 0;
 
diff -urpN linux-2.6.14/drivers/mtd/rfd_ftl.c linux-forget/drivers/mtd/rfd_ftl.c
--- linux-2.6.14/drivers/mtd/rfd_ftl.c	2005-11-18 06:26:02.000000000 +0100
+++ linux-forget/drivers/mtd/rfd_ftl.c	2005-11-18 21:20:57.000000000 +0100
@@ -621,6 +621,19 @@ err:
 	return rc;
 }
 
+static int rfd_ftl_forgetsect(struct mtd_blktrans_dev *dev, u_long sector)
+{
+	struct partition *part = (struct partition*)dev;
+
+	u_long addr = part->sector_map[sector];
+	if (addr == -1)
+		return 0;
+
+	part->sector_map[sector] = -1;
+
+	return mark_sector_deleted(part, addr);
+}
+
 static int find_free_sector(const struct partition *part, const struct block *block)
 {
 	int i, stop;
@@ -830,10 +843,11 @@ struct mtd_blktrans_ops rfd_ftl_tr = {
 	.part_bits	= PART_BITS,
 	.readsect	= rfd_ftl_readsect,
 	.writesect	= rfd_ftl_writesect,
+	.forgetsect	= rfd_ftl_forgetsect,
 	.getgeo		= rfd_ftl_getgeo,
 	.add_mtd	= rfd_ftl_add_mtd,
 	.remove_dev	= rfd_ftl_remove_dev,
-	.owner		= THIS_MODULE,
+	.owner		= THIS_MODULE
 };
 
 static int __init init_rfd_ftl(void)
diff -urpN linux-2.6.14/fs/fat/fatent.c linux-forget/fs/fat/fatent.c
--- linux-2.6.14/fs/fat/fatent.c	2005-10-28 02:02:08.000000000 +0200
+++ linux-forget/fs/fat/fatent.c	2005-11-18 21:24:21.000000000 +0100
@@ -6,6 +6,7 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/msdos_fs.h>
+#include <linux/blkdev.h>
 
 struct fatent_operations {
 	void (*ent_blocknr)(struct super_block *, int, int *, sector_t *);
@@ -530,6 +531,10 @@ int fat_free_clusters(struct inode *inod
 	fatent_init(&fatent);
 	lock_fat(sbi);
 	do {
+		blkdev_issue_forget(sb->s_bdev, sbi->data_start + 
+				(cluster << (sbi->cluster_bits - 9)),
+				sbi->cluster_size);
+
 		cluster = fat_ent_read(inode, &fatent, cluster);
 		if (cluster < 0) {
 			err = cluster;
diff -urpN linux-2.6.14/include/linux/blkdev.h linux-forget/include/linux/blkdev.h
--- linux-2.6.14/include/linux/blkdev.h	2005-11-18 06:26:18.000000000 +0100
+++ linux-forget/include/linux/blkdev.h	2005-11-18 04:31:44.000000000 +0100
@@ -226,6 +226,7 @@ enum rq_flag_bits {
 	__REQ_DRIVE_TASK,
 	__REQ_DRIVE_TASKFILE,
 	__REQ_PREEMPT,		/* set for "ide_preempt" requests */
+	__REQ_FORGET,		/* forget sectors request */
 	__REQ_PM_SUSPEND,	/* suspend request */
 	__REQ_PM_RESUME,	/* resume request */
 	__REQ_PM_SHUTDOWN,	/* shutdown request */
@@ -256,6 +257,7 @@ enum rq_flag_bits {
 #define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
 #define REQ_DRIVE_TASKFILE	(1 << __REQ_DRIVE_TASKFILE)
 #define REQ_PREEMPT	(1 << __REQ_PREEMPT)
+#define REQ_FORGET	(1 << __REQ_FORGET)
 #define REQ_PM_SUSPEND	(1 << __REQ_PM_SUSPEND)
 #define REQ_PM_RESUME	(1 << __REQ_PM_RESUME)
 #define REQ_PM_SHUTDOWN	(1 << __REQ_PM_SHUTDOWN)
@@ -466,6 +468,7 @@ enum {
 #define blk_barrier_rq(rq)	((rq)->flags & REQ_HARDBARRIER)
 #define blk_barrier_preflush(rq)	((rq)->flags & REQ_BAR_PREFLUSH)
 #define blk_barrier_postflush(rq)	((rq)->flags & REQ_BAR_POSTFLUSH)
+#define blk_barrier_forget(rq)	((rq->flags & REQ_BAR_FORGET)
 
 #define list_entry_rq(ptr)	list_entry((ptr), struct request, queuelist)
 
@@ -691,6 +695,7 @@ extern long blk_congestion_wait(int rw, 
 
 extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
 extern int blkdev_issue_flush(struct block_device *, sector_t *);
+extern void blkdev_issue_forget(struct block_device *, sector_t, int);
 
 #define MAX_PHYS_SEGMENTS 128
 #define MAX_HW_SEGMENTS 128
diff -urpN linux-2.6.14/include/linux/mtd/blktrans.h linux-forget/include/linux/mtd/blktrans.h
--- linux-2.6.14/include/linux/mtd/blktrans.h	2005-11-18 06:26:18.000000000 +0100
+++ linux-forget/include/linux/mtd/blktrans.h	2005-11-18 05:39:32.000000000 +0100
@@ -42,6 +42,7 @@ struct mtd_blktrans_ops {
 		    unsigned long block, char *buffer);
 	int (*writesect)(struct mtd_blktrans_dev *dev,
 		     unsigned long block, char *buffer);
+	int (*forgetsect)(struct mtd_blktrans_dev *dev, unsigned long block);
 
 	/* Block layer ioctls */
 	int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);




More information about the linux-mtd mailing list