mtd块设备缓冲操作---mtdblock.c
来源:互联网 发布:c语言学生成绩管理删除 编辑:程序博客网 时间:2024/05/21 20:30
这个文件中并没有增加mtd块设备,mtd块设备的代码文件是Mtd_blkdevs.c。它的功能是为mtd块设备读写提供缓冲操作。
另外还有一个文件mtdblock_ro.c,它定义的是mtd块设备缓冲的只读操作。
驱动入口:
static struct mtd_blktrans_ops mtdblock_tr = {.name= "mtdblock",.major= 31,.part_bits= 0,.blksize = 512,.open= mtdblock_open,.flush= mtdblock_flush,.release= mtdblock_release,.readsect= mtdblock_readsect,.writesect= mtdblock_writesect,.add_mtd= mtdblock_add_mtd, //增加一个mtd_blktrans_dev.remove_dev= mtdblock_remove_dev,.owner= THIS_MODULE,};static int __init init_mtdblock(void){return register_mtd_blktrans(&mtdblock_tr);}static void __exit cleanup_mtdblock(void){deregister_mtd_blktrans(&mtdblock_tr);}module_init(init_mtdblock);module_exit(cleanup_mtdblock);
缓冲数据结构定义:
static struct mtdblk_dev {struct mtd_info *mtd;int count;//使用计数struct mutex cache_mutex;unsigned char *cache_data; //缓冲区数据unsigned long cache_offset; //缓冲区数据的偏移地址(全局)unsigned int cache_size; //一般等于FLASH的擦除大小enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;} *mtdblks[MAX_MTD_DEVICES];
mtd_blktrans_dev结构:
struct mtd_blktrans_dev {struct mtd_blktrans_ops *tr;struct list_head list;struct mtd_info *mtd;struct mutex lock;int devnum; //分区序号,等于mtd->indexunsigned long size;//分区大小,单位是512字节int readonly; //是否是只读的void *blkcore_priv; //指向gen_disk结构};
mtd_blktrans_dev对应于mtd_info,每个分区有一个mtd_blktrans_dev实体。
(1)open例程
static int mtdblock_open(struct mtd_blktrans_dev *mbd){struct mtdblk_dev *mtdblk;struct mtd_info *mtd = mbd->mtd;int dev = mbd->devnum;DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");if (mtdblks[dev]) {//如果如果mtdblk_dev存在,则返回mtdblks[dev]->count++;return 0;}//mtdblk_dev不存在,则新增一个/* OK, it's not open. Create cache info for it */mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);if (!mtdblk)return -ENOMEM;mtdblk->count = 1;mtdblk->mtd = mtd;mutex_init(&mtdblk->cache_mutex);mtdblk->cache_state = STATE_EMPTY;if ( !(mtdblk->mtd->flags & MTD_NO_ERASE) && mtdblk->mtd->erasesize) {mtdblk->cache_size = mtdblk->mtd->erasesize;mtdblk->cache_data = NULL;}mtdblks[dev] = mtdblk;DEBUG(MTD_DEBUG_LEVEL1, "ok\n");return 0;}
(2)release例程
它检查检查mtdblk_dev的使用计数,若为0,则释放内存。
static int mtdblock_release(struct mtd_blktrans_dev *mbd){int dev = mbd->devnum;struct mtdblk_dev *mtdblk = mtdblks[dev]; DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");mutex_lock(&mtdblk->cache_mutex);write_cached_data(mtdblk);mutex_unlock(&mtdblk->cache_mutex);if (!--mtdblk->count) {/* It was the last usage. Free the device */mtdblks[dev] = NULL;if (mtdblk->mtd->sync)mtdblk->mtd->sync(mtdblk->mtd);vfree(mtdblk->cache_data);kfree(mtdblk);}DEBUG(MTD_DEBUG_LEVEL1, "ok\n");return 0;}
(3)writesect例程
static int mtdblock_writesect(struct mtd_blktrans_dev *dev, unsigned long block, char *buf){struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {//如果mtdblk->cache_data为空,则分配内存mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);if (!mtdblk->cache_data)return -EINTR;/* -EINTR is not really correct, but it is the best match * documented in man 2 write for all cases. We could also * return -EAGAIN sometimes, but why bother? */}return do_cached_write(mtdblk, block<<9, 512, buf);//把512字节数据写入到block<<9的地址处}static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, int len, const char *buf){struct mtd_info *mtd = mtdblk->mtd;unsigned int sect_size = mtdblk->cache_size;size_t retlen;int ret;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",mtd->name, pos, len);if (!sect_size) //直接写入return mtd->write(mtd, pos, len, &retlen, buf);///单次写入的数据大小不能超过sect_size,写入时如果小于sect_size,则先写入到cachewhile (len > 0) {unsigned long sect_start = (pos/sect_size)*sect_size;unsigned int offset = pos - sect_start;unsigned int size = sect_size - offset;if( size > len )size = len;if (size == sect_size) {//如果刚好是一个sect的大小,则不经cache直接写入/* * We are covering a whole sector. Thus there is no * need to bother with the cache while it may still be * useful for other partial writes. */ret = erase_write (mtd, pos, size, buf);if (ret)return ret;} else {//使用cache/* Partial sector: need to use the cache */if (mtdblk->cache_state == STATE_DIRTY && //如果cache有数据且cache的数据和写入的数据不在同一个sect中,则先把cache中的数据写入 mtdblk->cache_offset != sect_start) {ret = write_cached_data(mtdblk);if (ret)return ret;}if (mtdblk->cache_state == STATE_EMPTY || //如果cache中没有数据,则先把FLASH中对应的数据读出来放到cache mtdblk->cache_offset != sect_start) {/* fill the cache with the current sector */mtdblk->cache_state = STATE_EMPTY;ret = mtd->read(mtd, sect_start, sect_size,&retlen, mtdblk->cache_data);if (ret)return ret;if (retlen != sect_size)return -EIO;mtdblk->cache_offset = sect_start;mtdblk->cache_size = sect_size;mtdblk->cache_state = STATE_CLEAN;}/* write data to our local cache *///修改cache中的数据memcpy (mtdblk->cache_data + offset, buf, size);mtdblk->cache_state = STATE_DIRTY;}buf += size;pos += size;len -= size;}return 0;}static int write_cached_data (struct mtdblk_dev *mtdblk){struct mtd_info *mtd = mtdblk->mtd;int ret;if (mtdblk->cache_state != STATE_DIRTY)return 0;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" ""at 0x%lx, size 0x%x\n", mtd->name,mtdblk->cache_offset, mtdblk->cache_size);//erase_write调用mtd_info的相应操作ret = erase_write (mtd, mtdblk->cache_offset, mtdblk->cache_size, mtdblk->cache_data);if (ret)return ret;/* * 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 * the buffer cache instead. */mtdblk->cache_state = STATE_EMPTY;return 0;}
(3)readsect例程
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 do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, int len, char *buf){struct mtd_info *mtd = mtdblk->mtd;unsigned int sect_size = mtdblk->cache_size;size_t retlen;int ret;DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",mtd->name, pos, len);if (!sect_size)return mtd->read(mtd, pos, len, &retlen, buf);while (len > 0) {unsigned long sect_start = (pos/sect_size)*sect_size;unsigned int offset = pos - sect_start;unsigned int size = sect_size - offset;if (size > len)size = len;/* * Check if the requested data is already cached 检查读取的数据是否已经在cache中 * Read the requested amount of data from our internal cache if it * contains what we want, otherwise we read the data directly * from flash. */if (mtdblk->cache_state != STATE_EMPTY && mtdblk->cache_offset == sect_start) {memcpy (buf, mtdblk->cache_data + offset, size);} else {ret = mtd->read(mtd, pos, size, &retlen, buf);if (ret)return ret;if (retlen != size)return -EIO;}buf += size;pos += size;len -= size;}return 0;}
(4)flush例程
它将cache中数据写入到存储
static int mtdblock_flush(struct mtd_blktrans_dev *dev){struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];mutex_lock(&mtdblk->cache_mutex);write_cached_data(mtdblk);mutex_unlock(&mtdblk->cache_mutex);if (mtdblk->mtd->sync)mtdblk->mtd->sync(mtdblk->mtd);return 0;}
0 0
- mtd块设备缓冲操作---mtdblock.c
- MTD块设备---mtd_blkdevs.c
- Linux系统中/dev/mtd与/dev/mtdblock的区别,即MTD字符设备和块设备的区别
- Linux系统中/dev/mtd与/dev/mtdblock的区别,即MTD字符设备和块设备的区别
- Linux系统中/dev/mtd与/dev/mtdblock的区别,即MTD字符设备和块设备的区别
- Linux系统中/dev/mtd与/dev/mtdblock的区别,即MTD字符设备和块设备的区别
- mtd设备操作、jffs2
- mtd和mtdblock的区别
- mtd分区和mtdblock创建
- mtd 和 mtdblock 的区别 -- mtd
- 块设备请求的具体实现(MTD)
- mtd块设备的读写缓存问题
- mtd字符设备(mtdchar.c)
- /dev/mtd和/dev/mtdblock的区别
- /dev/mtd和/dev/mtdblock的区别
- /dev/mtd和/dev/mtdblock的区别
- /dev/mtd和/dev/mtdblock的区别
- MTD应用学习:mtd和mtdblock的区别
- spring面试题集锦(不定时更新)
- 修复由TortoiseSVN引起的bat文件关联异常
- 用jxl 从jsp页面导出数据到excel表格并下载保存
- Win7设置FTP详细过程
- android 中chromium_org模块打log的方法
- mtd块设备缓冲操作---mtdblock.c
- hadoop Unable to load native-hadoop library --解决
- windows下实现微秒级延时
- CXF javax.xml.ws.soap.SOAPFaultException: Fault occurred while processing
- 改善代码质量的6种重构模式
- 开源游戏3D引擎之Godot的专用脚本语言
- 书籍总结
- Struts2注解Convention扫描jar中的Action的设置
- 利用Cookie统计UV流量