mtd/drivers/mtd mtdblock.c,1.57,1.58
David Woodhouse
dwmw2 at infradead.org
Sun May 18 15:59:31 EDT 2003
Update of /home/cvs/mtd/drivers/mtd
In directory phoenix.infradead.org:/tmp/cvs-serv10767
Modified Files:
mtdblock.c
Log Message:
convert mtdblock to new blktrans interface
Index: mtdblock.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/mtdblock.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -r1.57 -r1.58
--- mtdblock.c 13 Sep 2002 14:43:57 -0000 1.57
+++ mtdblock.c 18 May 2003 19:59:28 -0000 1.58
@@ -3,7 +3,8 @@
*
* $Id$
*
- * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache
+ * (C) 2000-2003 Nicolas Pitre <nico at cam.org>
+ * (C) 1999-2003 David Woodhouse <dwmw2 at infradead.org>
*/
#include <linux/config.h>
@@ -12,32 +13,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
-#include <linux/mtd/compatmac.h>
-
-#define MAJOR_NR MTD_BLOCK_MAJOR
-#define DEVICE_NAME "mtdblock"
-#define DEVICE_REQUEST mtdblock_request
-#define DEVICE_NR(device) (device)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-#define DEVICE_NO_RANDOM
-#include <linux/blk.h>
-
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-static void mtd_notify_add(struct mtd_info* mtd);
-static void mtd_notify_remove(struct mtd_info* mtd);
-static struct mtd_notifier notifier = {
- mtd_notify_add,
- mtd_notify_remove,
- NULL
-};
-static devfs_handle_t devfs_dir_handle = NULL;
-static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES];
-#endif
+#include <linux/mtd/blktrans.h>
static struct mtdblk_dev {
- struct mtd_info *mtd; /* Locked */
+ struct mtd_info *mtd;
int count;
struct semaphore cache_sem;
unsigned char *cache_data;
@@ -46,14 +25,6 @@
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
} *mtdblks[MAX_MTD_DEVICES];
-static spinlock_t mtdblks_lock;
-/* this lock is used just in kernels >= 2.5.x */
-static spinlock_t mtdblock_lock;
-
-static int mtd_sizes[MAX_MTD_DEVICES];
-static int mtd_blksizes[MAX_MTD_DEVICES];
-
-
/*
* Cache stuff...
*
@@ -137,7 +108,7 @@
return ret;
/*
- * Here we could argably set the cache state to STATE_CLEAN.
+ * Here we could argubly set the cache state to STATE_CLEAN.
* However this could lead to inconsistency since we will not
* be notified if this content is altered on the flash by other
* means. Let's declare it empty and leave buffering tasks to
@@ -263,59 +234,39 @@
return 0;
}
+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ return do_cached_read(mtdblk, block<<9, 512, buf);
+}
+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ return do_cached_write(mtdblk, block<<9, 512, buf);
+}
-static int mtdblock_open(struct inode *inode, struct file *file)
+static int mtdblock_open(struct mtd_blktrans_dev *mbd,
+ struct inode *inode, struct file *file)
{
struct mtdblk_dev *mtdblk;
- struct mtd_info *mtd;
- int dev;
+ struct mtd_info *mtd = mbd->mtd;
+ int dev = mbd->devnum;
DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
- if (!inode)
- return -EINVAL;
-
- dev = minor(inode->i_rdev);
- if (dev >= MAX_MTD_DEVICES)
- return -EINVAL;
-
- BLK_INC_USE_COUNT;
-
- mtd = get_mtd_device(NULL, dev);
- if (!mtd) {
- BLK_DEC_USE_COUNT;
- return -ENODEV;
- }
- if (MTD_ABSENT == mtd->type) {
- put_mtd_device(mtd);
- BLK_DEC_USE_COUNT;
- return -ENODEV;
- }
-
- spin_lock(&mtdblks_lock);
-
- /* If it's already open, no need to piss about. */
if (mtdblks[dev]) {
mtdblks[dev]->count++;
- spin_unlock(&mtdblks_lock);
- put_mtd_device(mtd);
return 0;
}
- /* OK, it's not open. Try to find it */
-
- /* First we have to drop the lock, because we have to
- to things which might sleep.
- */
- spin_unlock(&mtdblks_lock);
-
+ /* OK, it's not open. Create cache info for it */
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
- if (!mtdblk) {
- put_mtd_device(mtd);
- BLK_DEC_USE_COUNT;
+ if (!mtdblks)
return -ENOMEM;
- }
+
memset(mtdblk, 0, sizeof(*mtdblk));
mtdblk->count = 1;
mtdblk->mtd = mtd;
@@ -327,50 +278,25 @@
mtdblk->cache_size = mtdblk->mtd->erasesize;
mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
if (!mtdblk->cache_data) {
- put_mtd_device(mtdblk->mtd);
kfree(mtdblk);
- BLK_DEC_USE_COUNT;
return -ENOMEM;
}
}
- /* OK, we've created a new one. Add it to the list. */
-
- spin_lock(&mtdblks_lock);
-
- if (mtdblks[dev]) {
- /* Another CPU made one at the same time as us. */
- mtdblks[dev]->count++;
- spin_unlock(&mtdblks_lock);
- put_mtd_device(mtdblk->mtd);
- vfree(mtdblk->cache_data);
- kfree(mtdblk);
- return 0;
- }
-
mtdblks[dev] = mtdblk;
- mtd_sizes[dev] = mtdblk->mtd->size/1024;
- if (mtdblk->mtd->erasesize)
- mtd_blksizes[dev] = mtdblk->mtd->erasesize;
- if (mtd_blksizes[dev] > PAGE_SIZE)
- mtd_blksizes[dev] = PAGE_SIZE;
- set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));
-
- spin_unlock(&mtdblks_lock);
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
return 0;
}
-static release_t mtdblock_release(struct inode *inode, struct file *file)
+static release_t mtdblock_release(struct mtd_blktrans_dev *mbd,
+ struct inode *inode, struct file *file)
{
int dev;
struct mtdblk_dev *mtdblk;
- DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
- if (inode == NULL)
- release_return(-ENODEV);
+ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
dev = minor(inode->i_rdev);
mtdblk = mtdblks[dev];
@@ -379,172 +305,30 @@
write_cached_data(mtdblk);
up(&mtdblk->cache_sem);
- spin_lock(&mtdblks_lock);
if (!--mtdblk->count) {
/* It was the last usage. Free the device */
mtdblks[dev] = NULL;
- spin_unlock(&mtdblks_lock);
if (mtdblk->mtd->sync)
mtdblk->mtd->sync(mtdblk->mtd);
- put_mtd_device(mtdblk->mtd);
vfree(mtdblk->cache_data);
kfree(mtdblk);
- } else {
- spin_unlock(&mtdblks_lock);
}
-
DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
- BLK_DEC_USE_COUNT;
- release_return(0);
-}
-
-
-/*
- * This is a special request_fn because it is executed in a process context
- * to be able to sleep independently of the caller. The
- * io_request_lock (for <2.5) or queue_lock (for >=2.5) is held upon entry
- * and exit. The head of our request queue is considered active so there is
- * no need to dequeue requests before we are done.
- */
-static void handle_mtdblock_request(void)
-{
- struct request *req;
- struct mtdblk_dev *mtdblk;
- unsigned int res;
-
- for (;;) {
- INIT_REQUEST;
- req = CURRENT;
- spin_unlock_irq(QUEUE_LOCK(QUEUE));
- mtdblk = mtdblks[minor(req->rq_dev)];
- res = 0;
-
- if (minor(req->rq_dev) >= MAX_MTD_DEVICES)
- panic("handle_mtdblock_request(): minor out of bounds");
-
- if (!IS_REQ_CMD(req))
- goto end_req;
-
- if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))
- goto end_req;
-
- // Handle the request
- switch (rq_data_dir(req))
- {
- int err;
-
- case READ:
- down(&mtdblk->cache_sem);
- err = do_cached_read (mtdblk, req->sector << 9,
- req->current_nr_sectors << 9,
- req->buffer);
- up(&mtdblk->cache_sem);
- if (!err)
- res = 1;
- break;
-
- case WRITE:
- // Read only device
- if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) )
- break;
-
- // Do the write
- down(&mtdblk->cache_sem);
- err = do_cached_write (mtdblk, req->sector << 9,
- req->current_nr_sectors << 9,
- req->buffer);
- up(&mtdblk->cache_sem);
- if (!err)
- res = 1;
- break;
- }
-
-end_req:
- spin_lock_irq(QUEUE_LOCK(QUEUE));
- end_request(res);
- }
-}
-
-static volatile int leaving = 0;
-static DECLARE_MUTEX_LOCKED(thread_sem);
-static DECLARE_WAIT_QUEUE_HEAD(thr_wq);
-
-int mtdblock_thread(void *dummy)
-{
- struct task_struct *tsk = current;
- DECLARE_WAITQUEUE(wait, tsk);
-
- /* we might get involved when memory gets low, so use PF_MEMALLOC */
- tsk->flags |= PF_MEMALLOC;
- strcpy(tsk->comm, "mtdblockd");
- spin_lock_irq(&tsk->sigmask_lock);
- sigfillset(&tsk->blocked);
- recalc_sigpending();
- spin_unlock_irq(&tsk->sigmask_lock);
- daemonize();
-
- while (!leaving) {
- add_wait_queue(&thr_wq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irq(QUEUE_LOCK(QUEUE));
- if (QUEUE_EMPTY || QUEUE_PLUGGED) {
- spin_unlock_irq(QUEUE_LOCK(QUEUE));
- schedule();
- remove_wait_queue(&thr_wq, &wait);
- } else {
- remove_wait_queue(&thr_wq, &wait);
- set_current_state(TASK_RUNNING);
- handle_mtdblock_request();
- spin_unlock_irq(QUEUE_LOCK(QUEUE));
- }
- }
-
- up(&thread_sem);
return 0;
-}
-
-#if LINUX_VERSION_CODE < 0x20300
-#define RQFUNC_ARG void
-#else
-#define RQFUNC_ARG request_queue_t *q
-#endif
-
-static void mtdblock_request(RQFUNC_ARG)
-{
- /* Don't do anything, except wake the thread if necessary */
- wake_up(&thr_wq);
-}
+}
-static int mtdblock_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int mtdblock_ioctl(struct mtd_blktrans_dev *dev,
+ struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
{
struct mtdblk_dev *mtdblk;
mtdblk = mtdblks[minor(inode->i_rdev)];
-#ifdef PARANOIA
- if (!mtdblk)
- BUG();
-#endif
-
switch (cmd) {
- case BLKGETSIZE: /* Return device size */
- return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg);
-
-#ifdef BLKGETSIZE64
- case BLKGETSIZE64:
- return put_user((u64)mtdblk->mtd->size, (u64 *)arg);
-#endif
-
case BLKFLSBUF:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
-#endif
- fsync_dev(inode->i_rdev);
- invalidate_buffers(inode->i_rdev);
down(&mtdblk->cache_sem);
write_cached_data(mtdblk);
up(&mtdblk->cache_sem);
@@ -553,115 +337,59 @@
return 0;
default:
- return -EINVAL;
+ return -ENOTTY;
}
}
-#if LINUX_VERSION_CODE < 0x20326
-static struct file_operations mtd_fops =
-{
- open: mtdblock_open,
- ioctl: mtdblock_ioctl,
- release: mtdblock_release,
- read: block_read,
- write: block_write
-};
-#else
-static struct block_device_operations mtd_fops =
+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
- owner: THIS_MODULE,
-#endif
- open: mtdblock_open,
- release: mtdblock_release,
- ioctl: mtdblock_ioctl
-};
-#endif
+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-#ifdef CONFIG_DEVFS_FS
-/* Notification that a new device has been added. Create the devfs entry for
- * it. */
+ if (!dev)
+ return;
-static void mtd_notify_add(struct mtd_info* mtd)
-{
- char name[8];
+ memset(dev, 0, sizeof(*dev));
- if (!mtd || mtd->type == MTD_ABSENT)
- return;
+ dev->mtd = mtd;
+ dev->devnum = mtd->index;
+ dev->blksize = 512;
+ dev->size = mtd->size >> 9;
+ dev->tr = tr;
- sprintf(name, "%d", mtd->index);
- devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name,
- DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index,
- S_IFBLK | S_IRUGO | S_IWUGO,
- &mtd_fops, NULL);
+ if (!(mtd->flags & MTD_WRITEABLE))
+ dev->readonly = 1;
+
+ add_mtd_blktrans_dev(dev);
}
-static void mtd_notify_remove(struct mtd_info* mtd)
+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
{
- if (!mtd || mtd->type == MTD_ABSENT)
- return;
-
- devfs_unregister(devfs_rw_handle[mtd->index]);
+ del_mtd_blktrans_dev(dev);
+ kfree(dev);
}
-#endif
+
+struct mtd_blktrans_ops mtdblock_tr = {
+ .name = "mtdblock",
+ .major = 31,
+ .part_bits = 0,
+ .open = mtdblock_open,
+ .ioctl = mtdblock_ioctl,
+ .release = mtdblock_release,
+ .readsect = mtdblock_readsect,
+ .writesect = mtdblock_writesect,
+ .add_mtd = mtdblock_add_mtd,
+ .remove_dev = mtdblock_remove_dev,
+ .owner = THIS_MODULE,
+};
int __init init_mtdblock(void)
{
- int i;
-
- spin_lock_init(&mtdblks_lock);
- /* this lock is used just in kernels >= 2.5.x */
- spin_lock_init(&mtdblock_lock);
-
-#ifdef CONFIG_DEVFS_FS
- if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))
- {
- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
- MTD_BLOCK_MAJOR);
- return -EAGAIN;
- }
-
- devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);
- register_mtd_user(¬ifier);
-#else
- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
- MTD_BLOCK_MAJOR);
- return -EAGAIN;
- }
-#endif
-
- /* We fill it in at open() time. */
- for (i=0; i< MAX_MTD_DEVICES; i++) {
- mtd_sizes[i] = 0;
- mtd_blksizes[i] = BLOCK_SIZE;
- }
- init_waitqueue_head(&thr_wq);
- /* Allow the block size to default to BLOCK_SIZE. */
- blksize_size[MAJOR_NR] = mtd_blksizes;
- blk_size[MAJOR_NR] = mtd_sizes;
-
- BLK_INIT_QUEUE(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request, &mtdblock_lock);
-
- kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
- return 0;
+ return register_mtd_blktrans(&mtdblock_tr);
}
static void __exit cleanup_mtdblock(void)
{
- leaving = 1;
- wake_up(&thr_wq);
- down(&thread_sem);
-#ifdef CONFIG_DEVFS_FS
- unregister_mtd_user(¬ifier);
- devfs_unregister(devfs_dir_handle);
- devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);
-#else
- unregister_blkdev(MAJOR_NR,DEVICE_NAME);
-#endif
- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
- blksize_size[MAJOR_NR] = NULL;
- blk_size[MAJOR_NR] = NULL;
+ deregister_mtd_blktrans(&mtdblock_tr);
}
module_init(init_mtdblock);
More information about the linux-mtd-cvs
mailing list