yaffs2應用到較老版本linux上時的問題 (移植日記)

來源:互聯網
上載者:User

2009.7.21
yaffs2 在 2.6.22的 kernel 上表現很正常,但在老的 2.6.12 上,則出現問題。

無奈之下只好閱讀 yaffs2 的代碼

fs/yaffs2/yaffs_mtdif2.c 中的  nandmtd2_ReadChunkWithTagsFromNAND 函數從nand flash 中

讀取 oob 資訊, 擷取 yaffs_ExtendedTags tags,

               if (tags){
                        memcpy(&pt, dev->spareBuffer, sizeof(pt));
                        yaffs_UnpackTags2(tags, &pt);
                        if(pt.t.chunkId  != -1)
                                {
                                printk("yaffs_UnpackTags2 chunkId = %x addr = %x/n",  pt.t.chunkId, addr);
                                int i = 0;
                                for(; i<28; i++)
                                      {
                                        printk(" %02x " , dev->spareBuffer[i]);
                                      }
                                printk("/n");
                               }

                        }
 通過和 2.6.22 的kernel 對比,探索資料位移了兩位, 我就太陽。。
後來找到下面這篇文章:

新版本核心中的MTD驅動考慮到了與yaffs2的介面問題,與yaffs2的整合一般都很順利。但是老版本就容易出現寫進去的檔案umount/mount後丟失的問題。基本上應該屬於oob中資料布局的問題。MTD中的oob(2k-page)布局:

====================
位元組0: 壞塊標記
位元組1: 保留
2-0x27: 給上層使用(yaffs)
0x28-0x3F: ECC
====================

YAFFS中與MTD最糾纏不清的就是oob中的資料存放區。yaffs需要將tag存入MTD的oob地區,寫入時通過write_ecc, 讀取時會用到read_ecc和read_oob,後者在掃描檔案系統的時候會用到,問題出在這裡:
1. NAND驅動中read_ecc和write_ecc都會小心得將yaffs2傳遞過來的oob資料寫到2-0x27的位置,
2. read_oob時,則是將整個oob從0開始都讀取出來了。導致yaffs2取到的tag資料錯誤,這是造成檔案丟失或者mout失敗的罪魁禍首。

解決的方法很簡單(只針對pagesize=2K的nand,其他的要參考driver/mtd/nand/nand_base.c中的nand_oobinfo,修改yaffs_mtdif2.c中的ReadChunkWithTagsFromNand,
1. 添加一個變數oobOffset,預設值為0, 當版本<=2.6.17並且調用read_oob時,oobOffset = 2.
2. 最後copy資料到tag結構體時,加上oobOffset即可。

參考文檔:

http://www.linux-mtd.infradead.org/tech/mtdnand/x255.html

http://www.yaffs.net/yaffs-2-specification-and-development-notes

讀的問題解決了,能正確讀到資料了,但寫資料的時候還是不正常。。

寫入資料以後, 會導致檔案丟失, 併產生:Partially written block 15 chunk 973 detected 警告。

其實根本原因還是寫入的時候,寫oob 資訊有問題。明天繼續查吧。

2009.7.22

問題終於解決了,現在我的 2.6.12 也能順暢的使用 yaffs2 了。
問題的根源還是在讀flash的 oob的時候出問題了,
2.6.12 的kernel 中 mtd->read_ecc 函數既讀取 data 也讀取 tags 但是讀tags 的時候ecc錯誤,或者說這個函數在處理  512byte/page 的 nand flash 時工作正常,
但是在讀 2k/page 的 flash 時,工作就不正常了。再看mtd->read 唯讀資料,工作OK, mtd->read_oob 唯讀oob 或者說唯讀 tags ,也正常,但是在memcpy資料的時候
需要加 2 的位移就正常了。問題找到了,不使用 mtd->read_ecc 函數 就什麼問題都沒有了,如果既需要讀資料,又需要讀oob, 那麼就分別調用 另外兩個函數。代碼:
int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device * dev, int chunkInNAND,
                       __u8 * data, yaffs_ExtendedTags * tags)
{
    struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
#if (MTD_VERSION_CODE > MTD_VERSION(2,6,17))
    struct mtd_oob_ops ops;
#endif
    size_t dummy;
    int retval = 0;
    int localData = 0;
    int tag_off = 0;
    int tag_mod = 0;
    loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;

    yaffs_PackedTags2 pt;
    memset((char*)&pt, 0, sizeof(pt) );

    T(YAFFS_TRACE_MTD,
      (TSTR
       ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
        TENDSTR), chunkInNAND, data, tags));
       
    if(dev->inbandTags){
       
        if(!data) {
            localData = 1;
            data = yaffs_GetTempBuffer(dev,__LINE__);
        }
       

    }

#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
    if (dev->inbandTags || (data && !tags))
        retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
                &dummy, data);
    else if (tags) {
        ops.mode = MTD_OOB_AUTO;
        ops.ooblen = sizeof(pt);
        ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
        ops.ooboffs = 0;
        ops.datbuf = data;
        ops.oobbuf = dev->spareBuffer;
        retval = mtd->read_oob(mtd, addr, &ops);

    }
#else
    tag_off = 2;
#if 0
    if (!dev->inbandTags && data && tags) {

        retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
                      &dummy, data, dev->spareBuffer,
                      NULL);
        tag_mod = 1;
    }
    else
    {
#endif
        if (data)
            retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
                      data);
        if (!dev->inbandTags && tags)
            {
                retval =
                    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
                          dev->spareBuffer);
                tag_mod = 2;
            }
     
#endif

    if (!dev->inbandTags && data && tags)
    {
            tag_mod = 1;
    }

    if(dev->inbandTags){
        if(tags){
            yaffs_PackedTags2TagsPart * pt2tp;
            pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk+tag_off];   
            yaffs_UnpackTags2TagsPart(tags,pt2tp);
        }
    }
    else {
        if (tags){
            memcpy(&pt, dev->spareBuffer + tag_off, sizeof(pt));   
            yaffs_UnpackTags2(tags, &pt);
        }
    }

    if(localData)
        yaffs_ReleaseTempBuffer(dev,data,__LINE__);
   
    if(tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
    {
        tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;   
    }
   
    if (retval == 0)
        return YAFFS_OK;
    else
        return YAFFS_FAIL;
}

參考文檔:
如何編寫linux下nand flash驅動

http://blog.ednchina.com/edaworld/140765/Message.aspx

Yaffs檔案系統結構

http://www.360doc.com/content/070110/14/198_325124.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.