bio_vec[i]对应一个block或者一个page
bio面向page或者面向块,详见第五次汇报里讲解的。
1struct bio {
sector_t bi_sector; /* device address in 512 byte
……
void *backup;//结构体末尾加变量backup空指针,作用?
};
struct page {
unsigned long flags; /* Atomic flags, some possibly
……
unsigned long buffer_flag;//page结构体末尾加入这个标记,标记函数是否经过了mpage_readpages
};
buffer_flag识别函数是否经过了mpage_readpages函数。只有读文件数据经过该函数,读取目录和挂载过程不经过该函数,这个特点可以在generic_make_request()函数和回调函数中用于分辨本次IO是读文件IO(加解密),还是读取文件夹的IO(不加密))。
1 void generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
/********************/
unsigned char *address_bf;
int major;
int i,j;
unsigned long rw_flag;
unsigned long int tt,nvec;
unsigned long buffer_flag=9;
address_bf=page_address(bio->bi_io_vec[0].bv_page);
address_bf=address_bf+bio->bi_io_vec[0].bv_offset;
major=MAJOR(bio->bi_bdev->bd_dev);//求设备号,SD卡设备号179
tt=bio->bi_sector;
nvec=bio->bi_vcnt;
rw_flag=(bio->bi_rw)&WRITE;
if(major==179)
{
printk("\ngeneric: %s: tt:%ld nvec:%ld", (rw_flag)?"write":"read", tt, nvec);
for(i=0;i<nvec;i++)
{
if (bio->bi_io_vec[i].bv_page->buffer_flag == 2) //该标记在函数?中,赋值2,只有读文件时经过该函数,读目录(区)不经过。满足条件,说明是读文件,则将标记改为3.
bio->bi_io_vec[i].bv_page->buffer_flag = 3;
buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;
printk("\n%s buffer_flag:%ld", (rw_flag)?"write":"read", buffer_flag);
}
}
if((major==179)&&(rw_flag)&&(buffer_flag==3)) //(tt>1000)
{
for(i=0;i<bio->bi_io_vec[0].bv_len/512;i++)
{
printk("before write:%d\n", address_bf[i*512]);
for(j=0;j<512;j++)
{
address_bf[j+i*512]^=0xff;
}
}
}
/************************/
if (current->bio_list) {
/* make_request is active */
………
………
}
2mpage机制的回调函数:
static void mpage_end_io(struct bio *bio, int err)//bio->bi_io_vec数组对应各个数据段,每个数据段对应pages(非mpage机制每个数据段对应一个块),如:bio->bi_io_vec[0]对应一页。
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
unsigned long buffer_flag=6;
do {
struct page *page = bvec->bv_page;
if (--bvec >= bio->bi_io_vec)
prefetchw(&bvec->bv_page->flags);
if (bio_data_dir(bio) == READ) {
if (uptodate) {
/******************/
struct bio_vec *bvecx;
unsigned char *address_bf;
unsigned long int tt;
bvecx=bvec+1;
buffer_flag = bvecx->bv_page->buffer_flag;
address_bf=page_address(bvecx->bv_page);
address_bf=address_bf+bvecx->bv_offset;
tt = bio->bi_sector;//这个扇区号为绝对扇区号,generic_make_request()等函数里的bio中的扇区号为从分区表起始的相对扇区号。本特点本项目中没有用到。
printk("\nmpage_end_io:tt:%ld\n",tt);
if (buffer_flag == 3){ //(tt>1000)//buffer_flag == 3说明为读取文件,而不是目录,
//yy=tt;
int i,j;
int major=MAJOR(bio->bi_bdev->bd_dev);
printk("\nmajor:%d",major);
if(major==179)
{
for(i=0;i<bvecx->bv_len/512;i++)
{
printk("\nmpage_end_io:before read:%d\n", address_bf[i*512]);
for(j=0;j<512;j++)
{
address_bf[j+i*512]^=0xff;
}
}
}
}
/******************/
SetPageUptodate(page);
3异步读回调函数: static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
{
unsigned long flags;
struct buffer_head *first;
struct buffer_head *tmp;
struct page *page;
int page_uptodate = 1;
unsigned long buffer_flag=8;
BUG_ON(!buffer_async_read(bh));
page = bh->b_page;
buffer_flag = page->buffer_flag;
if (uptodate) {
/****************/
unsigned char *tmp1;
tmp1=(unsigned char*)bh->b_data;
unsigned long int tt = (bh->b_blocknr * (bh->b_size >> 9));
printk("\nend_buffer_async_read:tt:%ld",tt);
if (buffer_flag == 3){ //(tt>1000)
int i,j;
int major=MAJOR(bh->b_bdev->bd_dev);
if(major==179)
{
for(i=0;i<((bh->b_size)/512);i++)
{
printk("\nasync before read :%d", tmp1[i*512]);
for(j=0;j<512;j++)
{
//printk(KERN_INFO "The original data is:%d\n", tmp1[j+i*512]);
tmp1[j+i*512]^=0xff;
//printk(KERN_INFO "The encryption data is%d\n", tmp1[j+i*512]);
}
}
}
}
/*****************/
set_buffer_uptodate(bh);
}
4同步读回调函数:static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate)//(end_buffer_sync_read调用该函数)
{
if (uptodate) {
/**********/
unsigned char *tmp1;
tmp1=(unsigned char*)bh->b_data;
unsigned long int tt = (bh->b_blocknr * (bh->b_size >> 9));
unsigned long buffer_flag=7;
printk("\nnotouch:tt:%ld",tt);
buffer_flag = bh->b_page->buffer_flag;
if (buffer_flag == 3){ //(tt>1000)
int i,j;
int major=MAJOR(bh->b_bdev->bd_dev);
if(major==179)
{
for(i=0;i<((bh->b_size)/512);i++)
{
printk("\nnotouch:before read:%d", tmp1[i*512]);
for(j=0;j<512;j++)
{
//printk(KERN_INFO "The original data is:%d\n", tmp1[j+i*512]);
tmp1[j+i*512]^=0xff;
//printk(KERN_INFO "The encryption data is%d\n", tmp1[j+i*512]);
}
}
}
}
/*************/
set_buffer_uptodate(bh);
} else {
/* This happens, due to failed READA attempts. */
clear_buffer_uptodate(bh);
}
unlock_buffer(bh);
}
5触屏读取文件经过该函数,开发板通过USB连接电脑则不通过这个函数。所以用电脑读不出手机SD卡上的数据。
int mpage_readpages(struct address_space *mapping, struct list_head *pages,
unsigned nr_pages, get_block_t get_block)
{
struct bio *bio = NULL;
unsigned page_idx;
sector_t last_block_in_bio = 0;
struct buffer_head map_bh;
unsigned long first_logical_block = 0;
struct blk_plug plug;
blk_start_plug(&plug);
map_bh.b_state = 0;
map_bh.b_size = 0;
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
struct page *page = list_entry(pages->prev, struct page, lru);
prefetchw(&page->flags);
list_del(&page->lru);
if (!add_to_page_cache_lru(page, mapping,
page->index, GFP_KERNEL)) {
printk("\nmpage_readpages !add_to..");
page->buffer_flag = 2;
bio = do_mpage_readpage(bio, page,
nr_pages - page_idx,
&last_block_in_bio, &map_bh,
&first_logical_block,
get_block);
}
page_cache_release(page);
}
BUG_ON(!list_empty(pages));
if (bio)
{
printk("\nmpage_readpages if(bio)");
mpage_bio_submit(READ, bio);
}
blk_finish_plug(&plug);
return 0;
}
6 触屏写入文件经过该函数,创建目录不经过该函数,所以创建文件夹不加密,从而达到只对SD卡文件数据进行加密的目的。
static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
void *data)
{
struct mpage_data *mpd = data;
struct bio *bio = mpd->bio;
struct address_space *mapping = page->mapping;
struct inode *inode = page->mapping->host;
const unsigned blkbits = inode->i_blkbits;
unsigned long end_index;
const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
sector_t last_block;
sector_t block_in_file;
sector_t blocks[MAX_BUF_PER_PAGE];
unsigned page_block;
unsigned first_unmapped = blocks_per_page;
struct block_device *bdev = NULL;
int boundary = 0;
sector_t boundary_block = 0;
struct block_device *boundary_bdev = NULL;
int length;
struct buffer_head map_bh;
loff_t i_size = i_size_read(inode);
int ret = 0;
printk("\n__mpage_writepage\n");
page->buffer_flag = 2;
if (page_has_buffers(page)) {
struct buffer_head *head = page_buffers(page);
struct buffer_head *bh = head;
/* If they're all mapped and dirty, do it */
page_block = 0;
do {
BUG_ON(buffer_locked(bh));
if (!buffer_mapped(bh)) {
/*
………
……
confused:
if (bio)
bio = mpage_bio_submit(WRITE, bio);
if (mpd->use_writepage) {
ret = mapping->a_ops->writepage(page, wbc);
} else {
ret = -EAGAIN;
goto out;
}
/*
* The caller has a ref on the inode, so *mapping is stable
*/
mapping_set_error(mapping, ret);
out:
mpd->bio = bio;
return ret;
}
7static void do_generic_file_read(struct file *filp, loff_t *ppos,
read_descriptor_t *desc, read_actor_t actor)
{
………
readpage:
/*
* A previous I/O error may have been due to temporary
* failures, eg. multipath errors.
* PG_error will be set again if readpage fails.
*/
ClearPageError(page);
/* Start the actual read. The read will unlock the page. */
/**yyx***/
page->buffer_flag = 1;
error = mapping->a_ops->readpage(filp, page);
if (unlikely(error)) {
if (error == AOP_TRUNCATED_PAGE) {
…
}
针对:写入SD卡后,立即读取,读出内容为乱码问题。
1、修改部分代码:红色字体为修改部分
static void mpage_end_io(s truct bio *bio, int err)//bio->bi_io_vec数组对应各个数据段,每个数据段对应pages(非mpage机制每个数据段对应一个块),如:bio->bi_io_vec[0]对应一页。
{
const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
unsigned long buffer_flag=6;
int i,j;
int major=MAJOR(bio->bi_bdev->bd_dev);//求出主设备号
int nvec;
do {
struct page *page = bvec->bv_page;
if (--bvec >= bio->bi_io_vec)
prefetchw(&bvec->bv_page->flags);
if (bio_data_dir(bio) == READ) {
if (uptodate) {
/******************/
struct bio_vec *bvecx;
unsigned char *address_bf;//
unsigned long int tt;//
bvecx=bvec+1;
buffer_flag = bvecx->bv_page->buffer_flag;//page页的自定义的标记位buffer_flag
//printk("\n1111\n");
address_bf=page_address(bvecx->bv_page);//求出页的起始地址
address_bf=address_bf+bvecx->bv_offset;//页起始地址加上偏移值求出读地址
//printk("\n22222\n");
//struct buffer_head *bh;
//bh=bio->bi_private;
//printk("\n33333\n");
//unsigned char *tmp1;
//tmp1=(unsigned char*)bh->b_data;
tt = bio->bi_sector;///这个扇区号为绝对扇区号,generic_make_request()等函数里的bio中的扇区号为从分区表起始的相对扇区号。本特点本项目中没有用到。
printk("\nmpage_end_io:tt:%ld\n",tt);
if (buffer_flag == 3){ //buffer_flag是自己在page中定义的一个项,用于区分读写的是普通文件还是文件目录表,分区表之类的
if(major==179)//major是179,就是针对的是SD卡
{
for(i=0;i<bvecx->bv_len/512;i++)//bvecx->bv_len代表一个字段的长度,一个 扇区是512字节,表示有多少个扇区
{
printk("before read:%d\n", address_bf[i*512]);
for(j=0;j<512;j++)
{
address_bf[j+i*512]^=0xff;//针对每个扇区的每个字节按位取反(相当于加密)
}
}
}
}
/******************/
SetPageUptodate(page);
} else {
ClearPageUptodate(page);
SetPageError(page);
}
unlock_page(page);
} else { /* bio_data_dir(bio) == WRITE */在这部分是针对写返回的操作
struct bio_vec *bvecx;
unsigned char *address_bf;
bvecx=bvec+1;
buffer_flag = bvecx->bv_page->buffer_flag;//
address_bf=page_address(bvecx->bv_page);//
address_bf=address_bf+bvecx->bv_offset;//
if(major==179)
{nvec=bio->bi_vcnt;
//printk("\nmajor");
//printk("\ngeneric: %s: tt:%ld nvec:%ld", (rw_flag)?"write":"read", tt, nvec);
for(i=0;i<nvec;i++)//每个bio中段个数
{
if(i>1)
{
printk("%d mpage nvec= \n",i);
}
//buffer_flag=bio->bi_io_vec[i].bv_page->buffer_flag;
buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;
//address_bf=page_address(bio->bi_io_vec[i].bv_page);
//address_bf=address_bf+bio->bi_io_vec[i].bv_offset;
if (buffer_flag == 3)//如果是写SD卡返回,在generic_make_request中,如果执行generic_make_request函数,则将此标记位置为3,此位置判断是否为3,如果是3的话,就判定他执行了generic_make_request函数
{ //bio->bi_io_vec[i].bv_page->buffer_flag = 3;
//buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;
address_bf=page_address(bio->bi_io_vec[i].bv_page);//
address_bf=address_bf+bio->bi_io_vec[i].bv_offset;
memcpy(address_bf,bio->bi_io_vec[i].bv_data_address,bio->bi_io_vec[i].bv_len);//参照generic_make_request函数,在generic_make_request函数中,针对要操作的缓冲区,又申请了一个缓冲区,将原先的明文备份,此处是将备份的明文重新拷贝到原先的缓冲区中,使系统感觉不到加密,
kfree(bio->bi_io_vec[i].bv_data_address);//将申请的用于备份的缓冲区释放掉
printk("\nnvec\n");
printk("mpage success\n");
}
printk("\n end_ion success");
}
}
if (!uptodate) {
SetPageError(page);
if (page->mapping)
set_bit(AS_EIO, &page->mapping->flags);
}
end_page_writeback(page);
}
} while (bvec >= bio->bi_io_vec);
bio_put(bio);
}
void generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
/********************/
unsigned char *address_bf;
int major;
int i,k,j;
unsigned long rw_flag;
unsigned long int tt,nvec;
unsigned long buffer_flag=9;
//unsigned long check_flag;
//struct buffer_head *bh_fyk;
major=MAJOR(bio->bi_bdev->bd_dev);//求出设备的主设备号
tt=bio->bi_sector;
nvec=bio->bi_vcnt;
rw_flag=(bio->bi_rw)&WRITE;
if(major==179)//主设备号是179是SD卡
{
printk("\ngeneric: %s: tt:%ld nvec:%ld", (rw_flag)?"write":"read", tt, nvec);
for(i=0;i<nvec;i++)
{
if (bio->bi_io_vec[i].bv_page->buffer_flag == 2)
{
bio->bi_io_vec[i].bv_page->buffer_flag = 3;//该标记在函数?中,赋值2,只有读文件时经过该函数,读目录(区)不经过。满足条件,说明是读文件,则将标记改为3.
}
buffer_flag = bio->bi_io_vec[i].bv_page->buffer_flag;//置新的标志位
if (rw_flag)//如果是写
{
address_bf=page_address(bio->bi_io_vec[i].bv_page);
address_bf=address_bf+bio->bi_io_vec[i].bv_offset;//求出地址
printk("\naddress_bf:%08x, page:%08x, bio:%08x\n", (unsigned int)address_bf, (unsigned int)bio->bi_io_vec[i].bv_page, (unsigned int)bio);
if (buffer_flag==3)//注意:如果是写SD卡的话(前面已经有major和rw_flag进行判断),统一将buffer_flag置为3
{
//address_bf=page_address(bio->bi_io_vec[i].bv_page);
//address_bf=address_bf+bio->bi_io_vec[i].bv_offset;
bio->bi_io_vec[i].bv_data_address=kmalloc(bio->bi_io_vec[i].bv_len,GFP_KERNEL);//申请一块缓冲区
memcpy(bio->bi_io_vec[i].bv_data_address,address_bf,bio->bi_io_vec[i].bv_len);//将明文保存在地址为bio->bi_io_vec[i].bv_data_address的缓冲区中
for(k=0;k<bio->bi_io_vec[i].bv_len/512;k++)//具体到扇区中
{
printk("before write:%d\n", address_bf[k*512]);
for(j=0;j<512;j++)
{
address_bf[j+k*512]^=0xff;//char型数据,8位。0xff
}
}
}
}
}
//printk("\n%s buffer_flag:%ld", (rw_flag)?"write":"read", buffer_flag);
}
注:修改的结构体如下:
struct bio_vec {
struct page *bv_page;
unsigned int bv_len;
unsigned int bv_offset;
char *bv_data_address;//此处为新加的结构体项,用于保存新申请的缓冲区的指针
};
struct page {
unsigned long flags; /* Atomic flags, some possibly
* updated asynchronously */
atomic_t _count; /* Usage count, see below. */
union {
atomic_t _mapcount; /* Count of ptes mapped in mms,
* to show when page is mapped
* & limit reverse map searches.
*/
struct { /* SLUB */
u16 inuse;
u16 objects;
};
};
union {
struct {
unsigned long private; /* Mapping-private opaque data:
* usually used for buffer_heads
* if PagePrivate set; used for
* swp_entry_t if PageSwapCache;
* indicates order in the buddy
* system if PG_buddy is set.
*/
struct address_space *mapping; /* If low bit clear, points to
* inode address_space, or NULL.
* If page mapped as anonymous
* memory, low bit is set, and
* it points to anon_vma object:
* see PAGE_MAPPING_ANON below.
*/
};
#if USE_SPLIT_PTLOCKS
spinlock_t ptl;
#endif
struct kmem_cache *slab; /* SLUB: Pointer to slab */
struct page *first_page; /* Compound tail pages */
};
union {
pgoff_t index; /* Our offset within mapping. */
void *freelist; /* SLUB: freelist req. slab lock */
};
struct list_head lru; /* Pageout list, eg. active_list
* protected by zone->lru_lock !
*/
/*
* On machines where all RAM is mapped into kernel address space,
* we can simply calculate the virtual address. On machines with
* highmem some memory is mapped into kernel virtual memory
* dynamically, so we need a place to store that address.
* Note that this field could be 16 bits on x86 ... ;)
*
* Architectures with slow multiplication can define
* WANT_PAGE_VIRTUAL in asm/page.h
*/
#if defined(WANT_PAGE_VIRTUAL)
void *virtual; /* Kernel virtual address (NULL if
not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
#ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
unsigned long debug_flags; /* Use atomic bitops on this */
#endif
#ifdef CONFIG_KMEMCHECK
/*
* kmemcheck wants to track the status of each byte in a page; this
* is a pointer to such a status block. NULL if not tracked.
*/
void *shadow;
#endif
unsigned long buffer_flag;//新加一个项,用于判断读写的文件类型,以及对于后面操作的一个标记位
};
buffer_flag识别函数是否经过了mpage_readpages函数。只有读文件数据经过该函数,读取目录和挂载过程不经过该函数,这个特点可以在generic_make_request()函数和回调函数中用于分辨本次IO是读文件IO(加解密),还是读取文件夹的IO(不加密))。