exfat文件系统(六)——exfat_get_block详解

  • Post author:
  • Post category:其他


从上一篇的exfat文件系统(五)中,我们可以了解到exfat文件系统的读写都需要一个重要的函数


exfat_get_block,而对exfat_get_block的功能的作用需要从



mpage_readpage的函数来理解,从学习中,我们可以发现exfat_get_block的主要功能是


检查page上所有的物理块是否连续,然后配合mpage_readpage提交bio操作。以下详细分析学习和研究过程。




在学习

mpage_readpage函数时,发现网络上有一篇文章很好的介绍了该函数的功能。




转摘博客:


http://blog.chinaunix.net/uid-28236237-id-4028521.html





mpage_readpage调用到do_mpage_readpage

















do_mpage_readpage详解如下:










/*



* This is the worker routine which does all the work of mapping the disk



* blocks and constructs largest possible bios, submits them for IO if the



* blocks are not contiguous on the disk.



*



* We pass a buffer_head back and forth and use its buffer_mapped() flag to



* represent the validity of its disk mapping and to decide when to do the next



* get_block() call.



*/


/*这个函数试图读取文件中的一个page大小的数据,最理想的情况下就是这个page大小



的数据都是在连续的物理磁盘上面的,然后函数只需要提交一个bio请求就可以获取



所有的数据,这个函数大部分工作在检查page上所有的物理块是否连续,检查的方法



就是调用文件系统提供的get_block函数,如果不连续,需要调用block_read_full_page



函数采用buffer 缓冲区的形式来逐个块获取数据*/



/*





1、调用get_block函数检查page中是不是所有的物理块都连续





2、如果连续调用mpage_bio_submit函数请求整个page的数据





3、如果不连续调用block_read_full_page逐个block读取



*/



static


struct

bio *

do_mpage_readpage(

struct

bio *bio,

struct

page *page,

unsigned

nr_pages,

sector_t *last_block_in_bio,

struct

buffer_head *map_bh,


unsigned


long

*first_logical_block, get_block_t get_block)

{


struct

inode *inode = page->mapping->host;


const


unsigned

blkbits = inode->i_blkbits;


const


unsigned

blocks_per_page = PAGE_CACHE_SIZE >> blkbits;


const


unsigned

blocksize =

1

<< blkbits;

sector_t block_in_file;

sector_t last_block;

sector_t last_block_in_file;

sector_t blocks[MAX_BUF_PER_PAGE];


unsigned

page_block;


unsigned

first_hole = blocks_per_page;


struct

block_device *bdev = NULL;


int

length;


int

fully_mapped =

1

;


unsigned

nblocks;


unsigned

relative_block;


if

(page_has_buffers(page))


goto

confused;


/*



block_in_file 本page中的第一个block number



last_block 本page中最后一个block 的大小



last_block_in_file 文件大小求出文件的最后一个block 大小*/


block_in_file = (sector_t)page->index << (PAGE_CACHE_SHIFT – blkbits);

last_block = block_in_file + nr_pages *blocks_per_page;

last_block_in_file = (i_size_read(inode) + blocksize –

1

) >> blkbits;


/*last_block 最后等于本次对这个page操作的最后一个block大小*/



if

(last_block > last_block_in_file)

last_block = last_block_in_file;

page_block =

0

;


/*



* Map blocks using the result from the previous get_blocks call first.



*/


nblocks = map_bh->b_size >> blkbits;


/*对于普通情况mpage_readpage调用下,map_bh只是一个临时变量不会走到



下面的分支*/



if

(buffer_mapped(map_bh) && block_in_file > *first_logical_block &&

block_in_file < (*first_logical_block + nblocks))

{


unsigned

map_offset = block_in_file – *first_logical_block;


unsigned

last = nblocks – map_offset;


for

(relative_block =

0

; ; relative_block++)

{


if

(relative_block == last)

{

clear_buffer_mapped(map_bh);


break

;

}


if

(page_block == blocks_per_page)


break

;

blocks[page_block] = map_bh->b_blocknr + map_offset +

relative_block;

page_block++;

block_in_file++;

}

bdev = map_bh->b_bdev;

}


/*



* Then do more get_blocks calls until we are done with this page.



*/


map_bh->b_page = page;


/*这个循环是比较关键的路径,理解这个函数至关重要



1、page_block从0开始循环,它表示在这个page内的block大小



2、调用get_block  函数查找对应逻辑块的物理块号是多少



3、如果遇到了文件空洞、page上的物理块不连续就会跳转到confused



4、将这个page中每个逻辑块对应的物理块都保存到临时的数组blocks[] 中*/



while

(page_block < blocks_per_page)

{

map_bh->b_state =

0

;

map_bh->b_size =

0

;


//遍历页面中的块数



if

(block_in_file < last_block)

{

map_bh->b_size = (last_block – block_in_file) << blkbits;








//将文件中的块号转换成bh



if

(get_block(inode, block_in_file, map_bh,

0

))


goto

confused;

*first_logical_block = block_in_file;

}


//bh没有被映射,可能是一个文件空洞



if

(!buffer_mapped(map_bh))

{

fully_mapped =

0

;


if

(first_hole == blocks_per_page)

first_hole = page_block;

page_block++;

block_in_file++;


continue

;

}


/* some filesystems will copy data into the page during



* the get_block call, in which case we don’t want to



* read it again.  map_buffer_to_page copies the data



* we just collected from get_block into the page’s buffers



* so readpage doesn’t have to repeat the get_block call



*/









//如果块缓存区是最新的,将其数据直接copy到page



if

(buffer_uptodate(map_bh))

{

map_buffer_to_page(page, map_bh, page_block);


goto

confused;

}


if

(first_hole != blocks_per_page)


goto

confused;

/* hole -> non-hole */


/* Contiguous blocks? */









//判断请求的块缓存是不是连续的。如果不连续,就跳转到confused



if

(page_block && blocks[page_block-

1

] != map_bh->b_blocknr –

1

)


goto

confused;

nblocks = map_bh->b_size >> blkbits;


for

(relative_block =

0

; ; relative_block++)

{


if

(relative_block == nblocks)

{

clear_buffer_mapped(map_bh);


break

;

}


else


if

(page_block == blocks_per_page)


break

;

blocks[page_block] = map_bh->b_blocknr + relative_block;

page_block++;

block_in_file++;

}

bdev = map_bh->b_bdev;

}


/*如果发现文件中有洞,将整个page清0,因为文件洞的区域



物理层不会真的去磁盘上读取,必须在这里主动清零,否则



文件洞区域内容可能随机*/



if

(first_hole != blocks_per_page)

{

zero_user_segment(page, first_hole << blkbits, PAGE_CACHE_SIZE);


if

(first_hole ==

0

)

{

SetPageUptodate(page);

unlock_page(page);


goto

out;

}

}


else


if

(fully_mapped)

{

SetPageMappedToDisk(page);

}


/*



* This page will go to BIO.  Do we need to send this BIO off first?



*/



/*bio 为NULL,目前分析的场景可以跳过去*/



if

(bio && (*last_block_in_bio != blocks[

0

] –

1

))

bio = mpage_bio_submit(READ, bio);

alloc_new:


if

(bio == NULL)

{


/*重新分配一个bio结构体



blocks[0] << (blkbits – 9) 这个是page中第一个逻辑块的物理块号,



转换成物理扇区号*/


bio = mpage_alloc(bdev, blocks[

0

] << (blkbits –

9

),

min_t(

int

, nr_pages, bio_get_nr_vecs(bdev)),

GFP_KERNEL);


if

(bio == NULL)


goto

confused;

}

length = first_hole << blkbits;


if

(bio_add_page(bio, page, length,

0

) < length)

{

bio = mpage_bio_submit(READ, bio);


goto

alloc_new;

}

relative_block = block_in_file – *first_logical_block;

nblocks = map_bh->b_size >> blkbits;


if

((buffer_boundary(map_bh) && relative_block == nblocks) ||

(first_hole != blocks_per_page))

bio = mpage_bio_submit(READ, bio);


else


*last_block_in_bio = blocks[blocks_per_page –

1

];

out:


/*一切顺利,整个page中的物理块是相连的,返回一个bio*/



return

bio;

confused:


if

(bio)

bio = mpage_bio_submit(READ, bio);


/*page 中的物理块不相连,没有办法一个一个buffer去读取出来



*/



if

(!PageUptodate(page))

block_read_full_page(page, get_block);


else


unlock_page(page);


goto

out;

}















网络上找到一个介绍缓存的说明如下:







linux在读写文件的时候会先将文件逻辑映射到页面逻辑,然后会在页高速缓存中寻找文件的数据,如果找到,那么对于读操作,那么就将数据直接返回给用户,如果对于缓冲写操作,那么会将数据写到这个页高速缓存中的页面,如果没有在页高速缓存找到页面,那么会分配一个页面加入到页高速缓存,然后着手IO操作,即使不是没有在页高速缓存找到页面而是找到的页面不是uptodate的页面,那么也要着手IO,怎么IO呢,这就是涉及到2.6内核的一个新特性的新实现,这就是mpage,其实就是页面的io操作,具体实现就要用到bio结构了,vfs子系统会在页高速缓存的需要io的页面上循环进行操作,怎么操作呢,就是将一个页面分割为多个“逻辑块”,然后构造一个bio,将一个页面加入到这个bio,这样循环中的每一个页面都会加入到这个bio,最后,统一用mpage_bio_submit来提交io操作









exfat_get_block就是现实“


linux在读写文件的时候会先将文件逻辑映射到页面逻辑,然后会在页高速缓存中寻找文件的数据,如果找到,那么对于读操作,那么就将数据直接返回给用户,如果对于缓冲写操作,那么会将数据写到这个页高速缓存中的页面,如果没有在页高速缓存找到页面,那么会分配一个页面加入到页高速缓存


”的操作(简单的就是说,该函数将相对于文件起始的块号转换为文件系统的逻辑块号)


。这样继续看exfat_get_block的代码就比较明白了。









exfat_get_block的详细流程图如下:















在学习exfat_get_block的代码中,我采用测试程序读方式来跟踪log,简单的读数据时,ffsMapCluster的debug log如下:

enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 1 now *clu = 3723

进入文件管家,播放一段视频(其中有暂停,快进和循环播放操作),log(部分)如下:

<6>[ 2534.253607] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 1 now *clu = 3723

<6>[ 2729.367136] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 652 now *clu = 3071

<6>[ 2729.972564] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 652 now *clu = 3071

<6>[ 2729.972739] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 652 now *clu = 3071

<6>[ 2729.972773] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 1, num_clusters = 652 now *clu = 3071

<6>[ 2736.333772] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 312 now *clu = 62722

<6>[ 2736.343226] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 0, num_clusters = 312 now *clu = 62722

<6>[ 2736.343289] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 1, num_clusters = 312 now *clu = 62722

<6>[ 2736.343516] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 1, num_clusters = 312 now *clu = 62722

<6>[ 2736.343565] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 2, num_clusters = 312 now *clu = 62722

<6>[ 2736.343627] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 3, num_clusters = 312 now *clu = 62722

<6>[ 2736.354171] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 3, num_clusters = 312 now *clu = 62722

<6>[ 2736.354232] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 4, num_clusters = 312 now *clu = 62722

<6>[ 2736.354300] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 5, num_clusters = 312 now *clu = 62722

<6>[ 2736.354361] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 6, num_clusters = 312 now *clu = 62722

<6>[ 2736.354427] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 7, num_clusters = 312 now *clu = 62722

<6>[ 2736.357080] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 7, num_clusters = 312 now *clu = 62722

<6>[ 2736.357145] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 8, num_clusters = 312 now *clu = 62722

<6>[ 2736.357215] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 9, num_clusters = 312 now *clu = 62722

<6>[ 2736.357276] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 10, num_clusters = 312 now *clu = 62722

<6>[ 2736.357338] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 11, num_clusters = 312 now *clu = 62722

<6>[ 2736.374826] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 11, num_clusters = 312 now *clu = 62722

<6>[ 2736.374894] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 12, num_clusters = 312 now *clu = 62722

<6>[ 2736.374969] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 13, num_clusters = 312 now *clu = 62722

<6>[ 2736.375037] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 14, num_clusters = 312 now *clu = 62722

<6>[ 2736.375100] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 15, num_clusters = 312 now *clu = 62722

<6>[ 2736.393375] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 15, num_clusters = 312 now *clu = 62722

<6>[ 2736.393443] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 16, num_clusters = 312 now *clu = 62722

<6>[ 2736.393510] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 17, num_clusters = 312 now *clu = 62722

<6>[ 2736.393974] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 18, num_clusters = 312 now *clu = 62722

<6>[ 2736.394047] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 19, num_clusters = 312 now *clu = 62722

<6>[ 2736.414981] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 19, num_clusters = 312 now *clu = 62722

<6>[ 2736.415049] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 20, num_clusters = 312 now *clu = 62722

<6>[ 2736.415120] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 21, num_clusters = 312 now *clu = 62722

<6>[ 2736.415183] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 22, num_clusters = 312 now *clu = 62722

<6>[ 2736.415246] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 23, num_clusters = 312 now *clu = 62722

<6>[ 2736.435625] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 23, num_clusters = 312 now *clu = 62722

<6>[ 2736.435696] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 24, num_clusters = 312 now *clu = 62722

<6>[ 2736.435820] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 25, num_clusters = 312 now *clu = 62722

<6>[ 2736.435885] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 26, num_clusters = 312 now *clu = 62722

<6>[ 2736.435951] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 27, num_clusters = 312 now *clu = 62722

<6>[ 2736.458553] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 27, num_clusters = 312 now *clu = 62722

<6>[ 2736.458621] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 28, num_clusters = 312 now *clu = 62722

<6>[ 2736.458691] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 29, num_clusters = 312 now *clu = 62722

<6>[ 2736.458755] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 30, num_clusters = 312 now *clu = 62722

<6>[ 2736.458820] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 31, num_clusters = 312 now *clu = 62722

<6>[ 2736.478704] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 31, num_clusters = 312 now *clu = 62722

<6>[ 2736.478773] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 32, num_clusters = 312 now *clu = 62722

<6>[ 2736.478842] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 33, num_clusters = 312 now *clu = 62722

<6>[ 2736.478909] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 34, num_clusters = 312 now *clu = 62722

<6>[ 2736.478973] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 35, num_clusters = 312 now *clu = 62722

<6>[ 2736.499001] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 35, num_clusters = 312 now *clu = 62722

<6>[ 2736.499068] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 36, num_clusters = 312 now *clu = 62722

<6>[ 2736.499140] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 37, num_clusters = 312 now *clu = 62722

<6>[ 2736.499206] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 38, num_clusters = 312 now *clu = 62722

<6>[ 2736.499273] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 39, num_clusters = 312 now *clu = 62722

<6>[ 2736.519611] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 39, num_clusters = 312 now *clu = 62722

<6>[ 2736.519677] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 40, num_clusters = 312 now *clu = 62722

<6>[ 2736.519744] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 41, num_clusters = 312 now *clu = 62722

<6>[ 2736.519809] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 42, num_clusters = 312 now *clu = 62722

<6>[ 2736.519873] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 43, num_clusters = 312 now *clu = 62722

<6>[ 2736.540243] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 43, num_clusters = 312 now *clu = 62722

<6>[ 2736.540312] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 44, num_clusters = 312 now *clu = 62722

<6>[ 2736.540388] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 45, num_clusters = 312 now *clu = 62722

<6>[ 2736.540454] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 46, num_clusters = 312 now *clu = 62722

<6>[ 2736.540519] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 47, num_clusters = 312 now *clu = 62722

<6>[ 2736.560914] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 47, num_clusters = 312 now *clu = 62722

<6>[ 2736.560982] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 48, num_clusters = 312 now *clu = 62722

<6>[ 2736.561051] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 49, num_clusters = 312 now *clu = 62722

<6>[ 2736.561166] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 50, num_clusters = 312 now *clu = 62722

<6>[ 2736.561230] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 51, num_clusters = 312 now *clu = 62722

<6>[ 2736.580953] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 51, num_clusters = 312 now *clu = 62722

<6>[ 2736.581020] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 52, num_clusters = 312 now *clu = 62722

<6>[ 2736.581087] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 53, num_clusters = 312 now *clu = 62722

<6>[ 2736.581150] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 54, num_clusters = 312 now *clu = 62722

<6>[ 2736.581214] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 55, num_clusters = 312 now *clu = 62722

<6>[ 2736.600991] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 55, num_clusters = 312 now *clu = 62722

<6>[ 2736.601055] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 56, num_clusters = 312 now *clu = 62722

<6>[ 2736.601120] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 57, num_clusters = 312 now *clu = 62722

<6>[ 2736.601185] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 58, num_clusters = 312 now *clu = 62722

<6>[ 2736.601245] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 59, num_clusters = 312 now *clu = 62722

<6>[ 2736.620800] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 59, num_clusters = 312 now *clu = 62722

<6>[ 2736.620867] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 60, num_clusters = 312 now *clu = 62722

<6>[ 2736.620989] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 61, num_clusters = 312 now *clu = 62722

<6>[ 2736.621053] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 62, num_clusters = 312 now *clu = 62722

<6>[ 2736.621121] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 63, num_clusters = 312 now *clu = 62722

<6>[ 2736.641751] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 63, num_clusters = 312 now *clu = 62722

<6>[ 2736.641824] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 64, num_clusters = 312 now *clu = 62722

<6>[ 2736.641894] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 65, num_clusters = 312 now *clu = 62722

<6>[ 2736.641958] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 66, num_clusters = 312 now *clu = 62722

<6>[ 2736.642032] enter [ffsMapCluster] fid->flags = 0x 3 clu_offset = 67, num_clusters = 312 now *clu = 62722

到此为止,基本理解exfat读过程。




版权声明:本文为fengxianger原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。