(1)mtd块设备结构定义
static struct block_device_operations mtd_blktrans_ops = { .owner = THIS_MODULE, .open = blktrans_open, .release = blktrans_release, .locked_ioctl = blktrans_ioctl, .getgeo = blktrans_getgeo, };
(2)调用register_mtd_blktrans实现初始化操作:
int register_mtd_blktrans(struct mtd_blktrans_ops *tr) { int ret, i; /* Register the notifier if/when the first device type is registered, to prevent the link/init ordering from fucking us over. */ if (!blktrans_notifier.list.next) register_mtd_user(&blktrans_notifier); //为每个设备注册注册notifier tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); //分配内存 if (!tr->blkcore_priv) return -ENOMEM; mutex_lock(&mtd_table_mutex); ret = register_blkdev(tr->major, tr->name); //注册mtd块设备 if (ret) { printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", tr->name, tr->major, ret); kfree(tr->blkcore_priv); mutex_unlock(&mtd_table_mutex); return ret; } spin_lock_init(&tr->blkcore_priv->queue_lock);//初始化访问请求队列的自旋锁 tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);//初始化请求队列 if (!tr->blkcore_priv->rq) { unregister_blkdev(tr->major, tr->name); kfree(tr->blkcore_priv); mutex_unlock(&mtd_table_mutex); return -ENOMEM; } tr->blkcore_priv->rq->queuedata = tr; blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); //设置MTD块设备硬盘扇区的大小 if (tr->discard) blk_queue_set_discard(tr->blkcore_priv->rq, blktrans_discard_request); tr->blkshift = ffs(tr->blksize) - 1; tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, //初始化处理请求队列的的线程,后面再讲 "%sd", tr->name); if (IS_ERR(tr->blkcore_priv->thread)) { int ret = PTR_ERR(tr->blkcore_priv->thread); blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); kfree(tr->blkcore_priv); mutex_unlock(&mtd_table_mutex); return ret; } INIT_LIST_HEAD(&tr->devs); list_add(&tr->list, &blktrans_majors); for (i=0; i<MAX_MTD_DEVICES; i++) { if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT) tr->add_mtd(tr, mtd_table[i]); } mutex_unlock(&mtd_table_mutex); return 0; }
(3)请求队列的操作
上面代码中,调用blk_init_queue(mtd_blktrans_request, ...设置请求队列的处理全程为为mtd_blktrans_request,它的代码如下:
static void mtd_blktrans_request(struct request_queue *rq) { struct mtd_blktrans_ops *tr = rq->queuedata; wake_up_process(tr->blkcore_priv->thread); }
它的工作仅仅是唤醒了先前创建的内核进程,实际的工作还是在mtd_blktrans_thread做:
static int mtd_blktrans_thread(void *arg) { struct mtd_blktrans_ops *tr = arg; struct request_queue *rq = tr->blkcore_priv->rq; /* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC; spin_lock_irq(rq->queue_lock); while (!kthread_should_stop()) { struct request *req; struct mtd_blktrans_dev *dev; int res = 0; req = elv_next_request(rq); if (!req) { set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(rq->queue_lock); schedule(); spin_lock_irq(rq->queue_lock); continue; } dev = req->rq_disk->private_data; tr = dev->tr; spin_unlock_irq(rq->queue_lock); mutex_lock(&dev->lock); res = do_blktrans_request(tr, dev, req); mutex_unlock(&dev->lock); spin_lock_irq(rq->queue_lock); end_request(req, res); } spin_unlock_irq(rq->queue_lock); return 0; }
这个进程把所有的请求处理完后又将自己休眠,直到被上面的mtd_blktrans_thread唤醒。
(4)其它几个例程实现比较简单
static int blktrans_open(struct block_device *bdev, fmode_t mode) { struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; struct mtd_blktrans_ops *tr = dev->tr; int ret = -ENODEV; if (!try_module_get(dev->mtd->owner)) goto out; if (!try_module_get(tr->owner)) goto out_tr; /* FIXME: Locking. A hot pluggable device can go away (del_mtd_device can be called for it) without its module being unloaded. */ dev->mtd->usecount++; //mtd使用计数 ret = 0; if (tr->open && (ret = tr->open(dev))) { dev->mtd->usecount--; module_put(dev->mtd->owner); out_tr: module_put(tr->owner); } out: return ret; } static int blktrans_release(struct gendisk *disk, fmode_t mode) { struct mtd_blktrans_dev *dev = disk->private_data; struct mtd_blktrans_ops *tr = dev->tr; int ret = 0; if (tr->release) ret = tr->release(dev); if (!ret) { dev->mtd->usecount--; //mtd使用计数递减,如果计数为0,则释放mtd模块。 module_put(dev->mtd->owner); module_put(tr->owner); } return ret; } static int blktrans_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; if (dev->tr->getgeo) return dev->tr->getgeo(dev, geo); return -ENOTTY; } static int blktrans_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct mtd_blktrans_dev *dev = bdev->bd_disk->private_data; struct mtd_blktrans_ops *tr = dev->tr; switch (cmd) { case BLKFLSBUF: //同步操作,将缓冲区的数据写入 if (tr->flush) return tr->flush(dev); /* The core code did the work, we had nothing to do. */ return 0; default: return -ENOTTY; } }