Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Device-mapper block-level deletion (dm dedup) & lt;3> code structure (4)

2025-01-29 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

6. Code structure (4) "small" writing process of Iram O

The previous article introduced the writing process of dm dedup, and this one introduces a special process of it.

If we receive the alignment bio but its size

< block_size,那么这时候是不能直接进行hash的。 需要将它的缺少的部分读出来,填充成一个完整的block_size才能计算hash。 接下来我们就介绍这一部分的代码流程。 static int handle_write(struct dedup_config *dc, struct bio *bio){ u64 lbn; u8 hash[MAX_DIGEST_SIZE]; struct hash_pbn_value hashpbn_value; u32 vsize; struct bio *new_bio = NULL; int r; /* If there is a data corruption make the device read-only */ if (dc->

Corrupted_blocks > dc- > fec_fixed) return-EIO; dc- > writes++; / * Read-on-write handling * / if (bio- > bi_iter.bi_size

< dc->

Block_size) {dc- > reads_on_writes++; new_bio = prepare_bio_on_write (dc, bio); if (! new_bio | | IS_ERR (new_bio)) return-ENOMEM; bio = new_bio;} / *. * /}

For "small" writing, this operation is also called reads_on_writes, or read_motify_write.

Let's take a look at how this new_bio is constructed.

Struct bio * prepare_bio_on_write (struct dedup_config * dc, struct bio * bio) {int r; sector_t lbn; uint32_t vsize; struct lbn_pbn_value lbnpbn_value; struct bio * clone; / / DMINFO ("\ nEntered prepare bio on write"); lbn = compute_sector (bio, dc); (void) sector_div (lbn, dc- > sectors_per_block) / * check for old or new lbn and fetch the appropriate pbn * / r = dc- > kvs_lbn_pbn- > kvs_lookup (dc- > kvs_lbn_pbn, (void *) & lbn, sizeof (lbn), (void *) & lbnpbn_value, & vsize); if (r =-ENODATA) clone = prepare_bio_without_pbn (dc, bio) Else if (r = 0) clone = prepare_bio_with_pbn (dc, bio, lbnpbn_value.pbn * dc- > sectors_per_block); else return ERR_PTR (r); / / DMINFO ("\ nExiting prpare_bio_on_write"); return clone;}

Let's note: what compute_sector calculates here is bio sector's lbn.

①: it has the following situations:

[Xmurmury] [XMurz]-> x/block_size=lbn [xMurmury] [Amury]-> x/block_size=lbn [XMurMury] [aMuz]-> x/block_size=lbn

They all get the same lbn=x/block_size.

② dc- > kvs_lbn_pbn- > kvs_lookup

Here we need to use the lbn just calculated to figure out whether it exists or not, there is no padding zero.

Then there are two cases, whether there is a pbn in this lbn.

1. Lbn without pbn "clone

Prepare_bio_without_pbn (dc, bio); "

Static struct bio * prepare_bio_without_pbn (struct dedup_config * dc, struct bio * bio) {int r = 0; struct bio * clone = NULL; clone = create_bio (dc, bio); if (! clone) goto out; zero_fill_bio (clone); r = merge_data (dc, bio_page (clone), bio); if (r

< 0) return ERR_PTR(r); out: return clone;} 这个很容易理解,既然不存在lbn_pbn的对应关系,那么这里就是直接填充zero。 这里用了内核提供的函数zero_fill_bio。如果我做,我可能不知道这个函数,大家要利用这个函数。 那么这里很简单,就是先创建一个null的bio,然后把这个bio的page全部填充成zero。 在和bio的进行合并。这里merge_data是代码实现的,我们看一下。 static int merge_data(struct dedup_config *dc, struct page *page, struct bio *bio){ sector_t bi_sector = bio->

Bi_iter.bi_sector; void * src_page_vaddr, * dest_page_vaddr; int position, err = 0; struct bvec_iter iter; struct bio_vec bvec; / * Relative offset in terms of sector size * / position = sector_div (bi_sector, dc- > sectors_per_block); if (! page | |! bio_page (bio)) {err =-EINVAL; goto out } / * Locating the right sector to merge * / dest_page_vaddr = page_address (page) + to_bytes (position); bio_for_each_segment (bvec, bio, iter) {src_page_vaddr = page_address (bio, iter) + bio_iter_offset (bio, iter); / * Merging Data * / memmove (dest_page_vaddr, src_page_vaddr, bio_iter_len (bio, iter)) / * Updating destinaion address * / dest_page_vaddr + = bio_iter_len (bio, iter);} out: return err;}

Those of us who develop block-level functions should also be familiar with memory and bio sectors operations.

There was a time when I was confused by segments and sectors correspondence when I wrote my own code.

This code is written clearly. Find out the location of bi_sector in block_size first.

such as

Sector [01234567] [01234567] s free page->

Position is 3.

At this time, use page_address to convert the data of [position] into ptr

Then put the data memmove on the ptr of 3456.

So what's a little complicated is that

< data >

He could also be fragmented, such as:

Sector [01234567] [01234567] [01234567] S1 free frees2 freepage->->

Here you need to memmove the contents of page,s1 and S2 of multiple segments into page respectively.

1. Lbn without pbn "clone

Prepare_bio_with_pbn (dc, bio); "

The idea here is that now that pbn is found, read out the pbn, and then overwrite the new content.

This approach is standard read-change-write, which is usually required when the I _ region_size O is less than that of the user.

Because you need block_size alignment, read an entire block_size from pbn.

Static int fetch_whole_block (struct dedup_config * dc, uint64_t pbn, struct page_list * pl) {struct dm_io_request iorq; struct dm_io_region where; unsigned long error_bits; where.bdev = dc- > data_dev- > bdev; where.sector = pbn; where.count = dc- > sectors_per_block; iorq.bi_op = REQ_OP_READ; iorq.bi_op_flags = 0 Iorq.mem.type = DM_IO_PAGE_LIST; iorq.mem.ptr.pl = pl; iorq.mem.offset = 0; iorq.notify.fn = NULL; iorq.client = dc- > io_client; return dm_io (& iorq, 1, & where, & error_bits);} static struct bio * prepare_bio_with_pbn (struct dedup_config * dc,struct bio * bio, uint64_t pbn) {int r = 0; struct page_list * pl Struct bio * clone = NULL; pl = kmalloc (sizeof (* pl), GFP_NOIO); if (! pl) goto out; / * * Since target I Band O size is 4KB currently, we need only one page to * store the data. However, if the target size increases O size increases, we need * to allocate more pages and set this linked list correctly. * / pl- > page = alloc_pages (GFP_NOIO, 0); if (! pl- > page) goto out_allocfail; pl- > next = NULL; r = fetch_whole_block (dc, pbn, pl); if (r

< 0) goto out_fail; r = merge_data(dc, pl->

Page, bio); if (r

< 0) goto out_fail; clone = create_bio(dc, bio); if (!clone) goto out_fail; copy_pages(pl->

Page, clone); out_fail: free_pages ((unsigned long) page_address (pl- > page), 0); out_allocfail: kfree (pl); out: if (r

< 0) return ERR_PTR(r); return clone;} 已经读出来的pl->

Page's pbn content and bio do merge, this and the above zero situation.

Finally, copy the merge good data into bio_new to do the next round of handle_write processing, that is, the content of the previous article.

The content of this article is relatively simple, so there is no illustration

-to be continued-

[this article is only posted by 51cto blogger "underlying Storage Technology" https://blog.51cto.com/12580077, official account release: storage Valley], if you need to reprint, please contact me, thank you.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report