daemonize(“%sd”, tr->name);
//因为一些内核线程实际上要与信号打交道,daemonize()没有做后台化工作。
//我们不能仅调用exit_sighand函数,
//因为当最终退出时这样将可能引起oop(对象指针溢出错误)。 spin_lock_irq(¤t->sighand->siglock); sigfillset(¤t->blocked);
// 重新分析是否有挂起信号并设置或清除TIF_SIGPENDING标识给当前进程 recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock); spin_lock_irq(rq->queue_lock);
while (!tr->blkcore_priv->exiting) { struct request *req;
struct mtd_blktrans_dev *dev; int res = 0;
DECLARE_WAITQUEUE(wait, current); //声明当前进程的等待队列
req = elv_next_request(rq);//从块设备的请求队列中得到下一个请求
if (!req) {//如果请求不存在
//将设备的等待线程加到等待队列中
add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irq(rq->queue_lock);
schedule(); //调度让CPU有机会执行等待的线程
remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); spin_lock_irq(rq->queue_lock); continue;
}
//如果请求存在
dev = req->rq_disk->private_data;//得到请求的设备 tr = dev->tr; //得到MTD翻译层设备操作函数集实例 spin_unlock_irq(rq->queue_lock);
down(&dev->sem); res = do_blktrans_request(tr, dev, req);//处理请求 up(&dev->sem);
spin_lock_irq(rq->queue_lock);
end_request(req, res); //从请求队列中删除请求并更新统计信息 }
spin_unlock_irq(rq->queue_lock);
//调用所有请求处理完的回调函数,并调用do_exit函数退出线程 complete_and_exit(&tr->blkcore_priv->thread_dead, 0); }
函数do_blktrans_request完成请求的具体操作,它调用MTD翻译层设备操作函数集实例中的具体函数来进行处理。函数do_blktrans_request分析如下: static int do_blktrans_request(struct mtd_blktrans_ops *tr, struct mtd_blktrans_dev *dev, struct request *req) {
unsigned long block, nsect; char *buf;
block = req->sector;
nsect = req->current_nr_sectors; buf = req->buffer;
if (!(req->flags & REQ_CMD)) return 0;
//如果读写的扇区数超出了块设备的容量,返回
if (block + nsect > get_capacity(req->rq_disk)) return 0;
//根据(rq)->flags & 1标识来判断操作方式,调用具体的设备操作函数 switch(rq_data_dir(req)) { case READ:
for (; nsect > 0; nsect--, block++, buf += 512) if (tr->readsect(dev, block, buf)) return 0; return 1;
case WRITE:
if (!tr->writesect) return 0;
for (; nsect > 0; nsect--, block++, buf += 512) if (tr->writesect(dev, block, buf)) return 0; return 1;
default:
printk(KERN_NOTICE “Unknown request %ld\\n”, rq_data_dir(req)); return 0; } }
图 函数register_mtd_user调用层次图
结构mtd_notifier是用于通知加上和去掉MTD原始设备。对于块设备来说,这个结构实例blktrans_notifier用来通知翻译层加上和去掉MTD原始设备。结构实例blktrans_notifier列出如下(在drivers/mtd/mtd_blkdevs.c中): static struct mtd_notifier blktrans_notifier = { .add = blktrans_notify_add,
.remove = blktrans_notify_remove, };
函数register_mtd_user注册MTD设备,通过分配通盘硬盘结构来激活每个MTD设备,使其出现在系统中。函数register_mtd_user调用层次图如上图。 函数register_mtd_user分析如下(在drivers/mtd/mtdcore.c中): static LIST_HEAD(mtd_notifiers);
void register_mtd_user (struct mtd_notifier *new) {
int i;
down(&mtd_table_mutex);
//将MTD块设备的通知结构实例blktrans_notifier加入 //到全局链表mtd_notifiers上
list_add(&new->list, &mtd_notifiers); //模块引用计数加1
__module_get(THIS_MODULE);
//对每个MTD块设备调用MTD通知结构实例的加设备函数 for (i=0; i< MAX_MTD_DEVICES; i++) if (mtd_table[i])
new->add(mtd_table[i]); up(&mtd_table_mutex); }
函数blktrans_notify_add通知MTD翻译层将设备加入到链表blktrans_majors中,并分配处理每个MTD分区对应的通用硬盘结构。 函数blktrans_notify_add分析如下(在drivers/mtd/mtd_blkdevs.c中):
static LIST_HEAD(blktrans_majors);
static void blktrans_notify_add(struct mtd_info *mtd) {
struct list_head *this;
if (mtd->type == MTD_ABSENT)//设备不存在 return;
//遍历每个MTD主块设备
list_for_each(this, &blktrans_majors) {
struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); tr->add_mtd(tr, mtd); } }
函数mtdblock_add_mtd分配了MTD翻译层块设备结构,初始化后加到MTD翻译层块设备链表中,函数mtdblock_add_mtd分析如下:
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) {
struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return;
memset(dev, 0, sizeof(*dev)); dev->mtd = mtd;
dev->devnum = mtd->index; dev->blksize = 512;
dev->size = mtd->size >> 9; dev->tr = tr;
if (!(mtd->flags & MTD_WRITEABLE)) dev->readonly = 1;
add_mtd_blktrans_dev(dev); }
函数add_mtd_blktrans_dev给每个MTD主设备分配设备号,并加到MTD设备链表对应位置上。然后给每个MTD设备分区分配一个通用硬盘结构,初始化这个通用硬盘结构后,再注册通用硬盘。这样通过通用硬盘就可以访问到每个MTD设备分区。