Chinaunix首页 | 论坛 | 博客
  • 博客访问: 837766
  • 博文数量: 90
  • 博客积分: 766
  • 博客等级: 军士长
  • 技术积分: 1867
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-18 08:42
个人简介

linux

文章分类

全部博文(90)

文章存档

2021年(2)

2020年(2)

2017年(1)

2015年(11)

2014年(1)

2013年(53)

2012年(16)

2011年(4)

分类: LINUX

2013-01-24 12:14:36

        一般的文件系统都解决了比较蛋疼的问题,坏块处理、耗损均衡和回收机制。有了这些机制,在上层才基本上可以任意多次的写同一个文件,但是实际上,同一个文件对应的却不是同一块存储区。这就是耗损均衡的关键点,有了耗损均衡势必会产生更多的垃圾块,因为在修改了文件之后,数据存放的地方已经不是以前的地方了,这意味着以前存储数据的地方的数据不再有用。在适当的时候,进行回收,如果是flash则是擦除动作。这里有一个动作就是将修改数据之后将以前的数据块标记为脏,这个动作就是耗损均衡的基本动作。
        知道这个动作就可以在操作nand flash的时候在一定范围内模拟文件系统耗损均衡的一部分功能,由于flash的擦除块在写之前必须要先擦除,这导致flash的寿命十分有限。当写数 据到flash的时候,如果不写到同一个地方,则不得不用另外一个标志来表示有效数据存放的位置,无异于拆东墙补西墙,仍然要频繁的擦写flash,来更新数据存放的位置。但如果将脏标志和数据放在一起,然后根据最后一块脏标志来判断数据的存放位置,则不需要额外的标志了。假如脏标志为‘0’,则每写一次 数据就把脏标志一起写进去,基于最后一次写的数据才是有效数据这一个规则,来查找最后一块脏数据,一旦数据全满之后,又进行擦除,全部数据变为空,然后再 来写开始的位置。这样往返,可一定程度上解决flash的寿命问题,那么为什么能够实现均衡,有下面几个基本点:
    1.在写一页还没有写过的数据页之前,不用擦除整块,这意味着,如果擦除块为64页,按页为单位,则可以写64页。
    2.脏标志的状态转换和flash的基本操作不冲突,特定是擦除动作,即他们的动作相生,却不相克。
    3.通过”脏“位来表示数据的有效性,而不是通过某个数据来判断数据存在的地方。
    经过前段时间的编码发现,状态转换十分重要,这要求状态转换必须覆盖所有的情况,且不能和软硬件的限制相冲突,这里的脏标志就是这样的,不仅能够通过这个标志来判断所有的情况,而且不和擦除这个动作想矛盾。

    最后贴出能够在整个擦除块当中,实现以页为单位的均衡处理的代码:


#include                                                                                                                                                      
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "upgrade.h"
 
#define TEST_MTD "/dev/mtd6"
#define TEST_BLOCK  (64*2048*4)
 
#ifndef ERASE_SIZE
        #define ERASE_SIZE (64*2048)
#endif
 
#ifdef WRITE_SIZE
        #define WRITE_SIZE 2048
#endif
#define FIRST_EFFC_PAGE 2048
#define DEV_LEN    12
#define LENGTH     6
#define WRITE_LIMIT_PER_BLOCKS 64*4
 
#define TEST_MALLOC_FAILED(x) do { \\\\
                        if (NULL == x) { \\\\
                                printf("malloc failed!\\\\n"); \\\\
                                exit(1);\\\\
                        } \\\\
        } while(0)
 
int override_flag;
/*
 * get the offset of the effective page
 */
int get_cur_offset(const char *mtd_dev)
{
        char buf = 0xff;
        char front,rear;
        unsigned int offset = TEST_BLOCK+FIRST_EFFC_PAGE;
 
        //init
        printf("offset:%d\\\\n" ,offset);
        read_mtd(mtd_dev,&buf,1,offset);
        front = buf;
        offset = offset + WRITE_SIZE;
        printf("offset:%d\\\\n" ,offset);
        read_mtd(mtd_dev,&buf,1,offset);
        rear = buf;
 
        printf("first:%c\\\\n" ,front);
        printf("second:%c\\\\n" ,rear);
 
        //there are datas
        while (rear=='0' && front=='0')
        {
                printf("offset:%d\\\\n" ,offset);
 
                offset += WRITE_SIZE;
 
                /* get the next mark */
                front = rear;
                read_mtd(mtd_dev,&buf,1,offset);
                rear = buf;
         
                /* system error */
                if (offset >= (TEST_BLOCK+ERASE_SIZE))
                {
                        printf("arrive at the boundary of block!\\\\n");
                        break;
                }
        }
         
        return offset;
}
 
/*
 * get the device node
 */
void get_mtd_device(char *device)
{
        strcpy(device,TEST_MTD);
}
 
/*
 * whether there are datas or not
 */
void existed_data(const char *device,char *flag)
{
        unsigned int offset;
 
        offset = TEST_BLOCK;
        read_mtd(device,flag,1,offset);
}
 
/*
 * mark that there are datas
 */
 
void mark_existed(const char *device,unsigned int offset)
{
        char flag = '0';
 
        write_mtd(device,&flag,1,offset);
}
 
/*
 * init erase_info
 */
void _erase_mtd(const char *device,unsigned int offset,unsigned int length)
{
        struct erase_info_user erase;
         
        memset(&erase,0,sizeof(struct erase_info_user));
        erase.start = offset;
        erase.length = length;
 
        //erase
        erase_mtd(device,&erase);
}
 
/*
 * write driver
 */
void write_flash(const char *buf,unsigned int length)
{
         
        char mtd_dev[DEV_LEN];
        char *write_buf = NULL;
        unsigned int off = 0;
        unsigned int next_off = 0;
        char flag = 0;
        int i;
 
        memset(mtd_dev,0,DEV_LEN);
        write_buf = (char *)malloc(length+1);
        TEST_MALLOC_FAILED(write_buf);
 
 
        //dirty the latest page
        get_mtd_device(mtd_dev);
         
empty_block:
        //data is existed or not
        existed_data(mtd_dev,&flag);
 
        if (0xff == flag)
        {
                printf("first\\\\n");
                //mark existed
                mark_existed(mtd_dev,TEST_BLOCK);
 
                //write data
                next_off = TEST_BLOCK + FIRST_EFFC_PAGE;
                printf("next_off:%d\\\\n" ,next_off);
                write_buf[0] = '0';
                memcpy(write_buf+1,buf,length);
                write_mtd(mtd_dev,write_buf,length+1,next_off);
                //read_mtd(mtd_dev,write_buf,length+1,next_off);
                //printf("read_buf:%s\\\\n" ,write_buf);
        }
        else
        {
                off = get_cur_offset(mtd_dev);
                if (off == TEST_BLOCK+ERASE_SIZE)
                {
                        override_flag = 1;
                        printf("\\\\n\\\\n\\\\nthird\\\\n\\\\n");
                        //erase the block and the state convert to empty
                        _erase_mtd(mtd_dev,TEST_BLOCK,ERASE_SIZE);
                        //exit(1);
                        goto empty_block;
                }
                else
                {
                        printf("second\\\\n");
                        //write the data and dirty the page
                        //next_off = off + WRITE_SIZE;
                        write_buf[0] = '0';
                        memcpy(write_buf+1,buf,length);
                        printf("write_buf:%s\\\\n" ,write_buf);
                        printf("next_off:%d\\\\n" ,next_off);
                        write_mtd(mtd_dev,write_buf,length+1,off);
                        read_mtd(mtd_dev,write_buf,length+1,off);
                        printf("read_buf:%s\\\\n" ,write_buf);
                }
        }
 
        printf("\\\\n");
         
}
/*
 * middle layer of write test
 */
void write_test_data(const char *buf,unsigned int length)
{
        write_flash(buf,length);
}
 
 
/*
 * read driver
 */
void read_flash(char *buf,unsigned int length)
{
        char mtd_dev[DEV_LEN];
        unsigned int off = 0;
        //unsigned int length = 0;
 
        memset(mtd_dev,0,12);
 
        get_mtd_device(mtd_dev);
        off = get_cur_offset(mtd_dev);
 
        read_mtd(mtd_dev,buf,length,off-WRITE_SIZE);
}
 
/*
 * middle layer of read test
 */
void read_test_data(char *buf,unsigned int length)
{
        if (length > WRITE_SIZE || NULL == buf)
                exit(1);
 
        read_flash(buf,length);
}
 
/*
 * main
 */
int main()
{
        int length = LENGTH;
        char buffer[LENGTH];
 
// length <= 2048
 
        memset(buffer,0,LENGTH);
        while (1)
        {
                write_test_data("12345",5);
                if (override_flag == 1)
                {
                        write_test_data("woshi",5);
                        break;
                }
        }
 
        read_test_data(buffer,7);
 
        printf("\\\\nbuffer:%s\\\\n" ,buffer);
 
        return 0;
}







阅读(1255) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~