-
Notifications
You must be signed in to change notification settings - Fork 416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
qcow: Fix the calculation of the number of clusters for L1 table #4767
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lv-mz Thank you for the contribution. Can you please revise your commit message based on our documentation https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/CONTRIBUTING.md?
Can you please also provide some context from the qcow spec to explain what is "l1_clusters" and why its calculation was wrong?
@likebreath Thankyou .
Variables num_l2_cluster and l1_clusters are used in the following code:
Therefore, l1_ clusters indicates the number of clusters occupied by the L1 table in the qcow file and I think the number of clusters for L1 table should be calculated as follows: For example, if the data cluster size is 64k and L1 and L2 blocks are all one cluster long, and the entyies of L1 and L2 table are 8192, then the disk space that an L1 table can manage is 8192 x 8192 x 64k = 4T. If the disk size exceeds 4T, the L1 table need two clusters. In function create_ for_ size(version: u32, size: u64) If there is any problem with my analysis, please let me know. Thank you |
qcow/src/qcow.rs
Outdated
let l2_size: u32 = cluster_size / size_of::<u64>() as u32; | ||
let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32; | ||
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, l2_size); | ||
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, cluster_size); | ||
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, l2_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
l2_size
should really be calledentries_per_cluster
given we're dividing a cluster size by size_of(u64), which really means we want the number of entries/addresses that can fit into a cluster.num_clusters
looks good given we're dividing the total size in bytes by the size of a cluster in bytes.num_l2_clusters
is fine, but we could update it for more clarity.l1_clusters
should be callednum_l1_clusters
.
So here is my suggestion to make things a bit clearer:
let entries_per_cluster: u32 = cluster_size / size_of::<u64>() as u32;
let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32;
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, entries_per_cluster);
let num_l1_clusters: u32 = div_round_up_u32(num_l2_clusters, entries_per_cluster);
So to summarize, your change looks great, but I'd like to use this opportunity to rename a few variables to increase clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sboeuf
thank you very much
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks 👍
/cc @rbradford |
let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32; | ||
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, l2_size); | ||
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, cluster_size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You missed that this is calculated a second place in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate? I don't get the point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
marvin:~/src/cloud-hypervisor (main)$ git grep "let l1_clusters = "
qcow/src/qcow.rs: let l1_clusters = div_round_up_u64(num_l2_clusters, cluster_size);
qcow/src/qcow.rs: let l1_clusters = div_round_up_u64(u64::from(header.l1_size), cluster_size);
qcow/src/qcow.rs: let l1_clusters = div_round_up_u64(l2_clusters, cluster_size);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh okay the same calculation is done somewhere else :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rbradford Thanks,
Yes, there are 9 places that need to be modified, and so I have restored the original representation of l1_clusters.
@sboeuf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danielverkamp Hi, this bit of code is essentially unmodified from crosvm. Do you think this proposed change makes sense? Looks like it can be found empirically with a disk size > 4TiB
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, the new math (and better names) look correct to me. The diff is a bit hard to read due to the renames, though, so if it were me, I might split it up into two commits just to make the bugfix part totally clear.
For the original submitter, if you're willing to send this to crosvm too once it's finalized (so the change is correctly attributed), that would be greatly appreciated! (https://crosvm.dev/book/contributing/index.html)
e9a08f9
to
c1f861d
Compare
In function create_for_size(), when calculating the number of clusters for the L1 table, it incorrectly divides the total number of entries in the L1 table by the cluster size. In fact, it should be divided by the number of entries/addresses that can fit into a cluster. Signed-off-by: lv.mengzhao <lv.mengzhao@zte.com.cn>
In function create_for_size(),it calculates l1_clusters by dividing by cluster_size, whereas it should be divided by cluster_size/size_of(u64).
This fixes: #4762