首页 理论教育 映射函数verity_map

映射函数verity_map

时间:2023-11-22 理论教育 版权反馈
【摘要】:第一层是块设备,第二层是Device Mapper,第三层是作为Target Device的dm-verity。第二件事是调用块设备的函数generic_make_request启动对dm-verity的data device的操作。按照块设备的代码逻辑,在io操作之后,bi_end_io函数指针会被调用,对于dm-verity来说就是verity_end_io。verity_verify_io函数的定义比较长,这里省略了许多。顶层由root hash校验。首先在本函数verity_verify_io中将root hash填入这个缓冲区,然后在函数verity_verify_level中做验证,验证通过后就会将新的校验值填入这个缓冲区。

映射函数verity_map

下面要分析三个层次的代码逻辑。第一层是块设备,第二层是Device Mapper,第三层是作为Target Device的dm-verity。

1.块设备

在执行之前,代码逻辑先要在块设备架构中转上一大圈。首先看看块设备中的接口函数

978-7-111-54905-5-Part03-26.jpg

函数generic_make_request的函数主体是一个循环,循环处理每一个bio,处理bio的工作由函数指针make_request_fn所指向的函数完成。函数指针make_request_fn的赋值是在函数blk_queue_make_request中完成的:

978-7-111-54905-5-Part03-27.jpg

2.Device Mapper

上面是块设备的代码逻辑,下面看看在Device Mapper中如何赋值这个函数指针

978-7-111-54905-5-Part03-28.jpg

Device Mapper要将make_request_fn指针赋值为dm_request。dm_request的定义如下:

978-7-111-54905-5-Part03-29.jpg

代码逻辑从dm_request开始,经过一系列函数调用,最终会调用__map_bio:

978-7-111-54905-5-Part03-30.jpg

从这里,代码逻辑就进入了具体的Target Device。

3.dm-verity

“map”是一个函数指针,对于dm-verity设备,它指向函数verity_map。代码还是很简单的:(www.xing528.com)

978-7-111-54905-5-Part03-31.jpg

它主要做了两件事,第一件是将bio的bi_end_io函数指针和数据成员bi_private换掉,将原有值保存,以便以后恢复。第二件事是调用块设备的函数generic_make_request启动对dm-verity的data device的操作。按照块设备的代码逻辑,在io操作之后,bi_end_io函数指针会被调用,对于dm-verity来说就是verity_end_io。下面看看bi_end_io指针所指向的verity_end_io,就知道verity要干什么了:

978-7-111-54905-5-Part03-32.jpg

978-7-111-54905-5-Part03-33.jpg

如果读写出错,就调用verity_finish_io,此函数恢复原有的bi_end_io指针和bi_private指针:

978-7-111-54905-5-Part03-34.jpg

重要的工作在verity_work函数中:

978-7-111-54905-5-Part03-35.jpg

verity_work会调用verity_verify_io,此函数完成最重要的工作——校验。

978-7-111-54905-5-Part03-36.jpg

978-7-111-54905-5-Part03-37.jpg

verity_verify_io函数的定义比较长,这里省略了许多。函数的主体是一个循环,对io中所有的block进行校验。在循环体中又分为两部分,在标号test_block_hash之前的部分是对哈希设备进行校验,在标号test_block_hash之后的部分是对数据设备进行校验。回顾一下,dm-verity需要两个“底层”设备,一个是数据设备,用来存储数据,另一个是哈希设备,存储的是数据的校验值。

参考图13-4,在哈希设备中存储是分层的。最底层是0层,每个块中存储的是数据设备中对应块的数据的校验值;其上每层都存储着下一层的校验值。在此函数中,首先检验第0层数据的正确性。这里用了一个技巧,检验的结果是被缓存了的,如果以前检验的结果为正确,verity_verify_level(io,io->block+b,0,true)就会返回0,然后函数就直接到test_block_hash之后去执行校验数据设备的操作。如果之前没有做过校验,就要老老实实地验证哈希设备的完整性。0层由1层校验,1层由2层校验……顶层由root hash校验。函数又用了一个技巧,它是自顶向下做校验的,因为一开始“好的”校验值只有一个,就是root hash。经过root hash校验后levels-1层存储的校验值就成了“好的”校验值,又可以用它们来校验levels-2层了,以此类推直到第0层。校验操作无非是算出一个校验值,用此值和一个事先存储的校验值比较。函数中将好的校验值存储在缓冲区io_want_digest(v,io)之中。首先在本函数verity_verify_io中将root hash填入这个缓冲区,然后在函数verity_verify_level中做验证,验证通过后就会将新的校验值填入这个缓冲区。

在标号test_block_hash之前,第0层的哈希设备的数据一定是被存储在了缓冲区io_want_ digest(v,io)之中的。标号test_block_hash之后的部分所做的工作就是读出数据设备中的数据块内容,算出校验值,和io_want_digest(v,io)之中的内容进行比较,如果相同就通过了校验。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈

相关推荐