linux - 在 Linux 上设置 zram 设备磁盘大小有什么限制吗?
问题描述
我正在尝试在我的目标设备上创建一个zram设备。如果 zram 磁盘大小高于 100GB,我的目标无法分配内存,但磁盘大小为 50GB 或更少也没关系。
在 Linux 上设置 zram 设备磁盘大小有什么限制吗?我的目标设备只有 2GB 的 RAM 内存。
解决方案
我想你可以在 64 位平台上给出一个高达 UINT64_MAX - 4095 = 18446744073709547520 的数字。
https://github.com/torvalds/linux/blob/master/drivers/block/zram/z ram_drv.h#L101 https://github.com/torvalds/linux/blob/master/drivers/block/zram/zram_drv .c#L1506 https://github.com/torvalds/linux/blob/master/drivers/block/zram/z ram_drv.c#L901
所以我们有:
... disksize_store(...) {
u64 disksize;
...
// ok, we can give at least UINT64_MAX here.
disksize = unsigned long long memparse(...);
// PAGE_ALIGN, PAGE_SIZE = 1<<12
disksize = PAGE_ALIGN(disksize)
= (((disksize)+((PAGE_SIZE)-1))&(~((typeof(disksize))(PAGE_SIZE)-1)))
= (disksize + ((1<<12)-1))&(~((1<<12)-1))
= (disksize + 4095) & 0xfffffffffffff000
// ^^^^^^^^^^^^^^^ this can overflow
// so max number is UINT64_MAX - 4095 so it doesn't overflow
// otherwise this macro will return 0
...
if (!zram_meta_alloc(..., disksize) {
...
return ...;
}
...
zram->disksize = disksize;
...
}
那么让我们看看zram_meta_alloc:
... zram_meta_alloc(..., disksize) {
...
num_pages = disksize >> PAGE_SHIFT;
// max num_pages = 0xfffffffffffff = UINT64_MAX >> PAGE_SHIFT
... = vzalloc(num_pages * sizeof(*zram->table));
// ^^^^^^^^^^^^^^^ this can overflow
...
}
vzallloc 将 unsigned long 作为参数。ULONG_MAX 在 64 位平台上应该是 UINT64_MAX。sizeof(*zram->table)
等于sizeof(unsigned long) + sizeof(unsigned long) + [optional: + sizeof(ktime_t)] + padding
(见这里)。如果没有填充,假设 64 位平台,sizeof(unsigned long) = 8
应该等于8+8[+8] = 16 or 24
. 但无论如何,最大 num_pages 等于UINT64_MAX >> 12
,因此要在 64 位乘法上溢出它,我们需要sizeof(*zram->table) = 2^PAGE_SIZE = 4096
,并且不应该发生这种情况(除非编译器决定在 zram->table 结构中提供超过 4000 个字节的填充)。所以我们留下了 UINT64_MAX - 4095。
所以我们留下了磁盘大小的最大数量UINT64_MAX-4095
。如果给定磁盘大小等于UINT64_MAX - x
,其中0 <= x < 4095
,而不是因为 PAGE_ALIGN 宏,磁盘大小将被有效地设置为 0。可能这应该向内核开发人员提出,他们应该修改 PAGE_ALIGN 宏以支持这样的数字。
6 天前对 vzalloc 调用的调用array_size
被添加以防止此提交溢出。
推荐阅读
- python - 如何在 python pandas 数据透视表中找到总共只有一列?
- rust - 删除一个 mem::forgotten 字符串数组的正确方法是什么,该数组通过 out 指针发送到 C,然后传递回 Rust 进行删除?
- git - 为什么在没有任何更改的情况下创建另一个提交?
- arrays - 结构未填充
- javascript - 带有slug的页面导入页面中的nuxt js
- c# - 列表的通用扩展方法
不删除空值 - javascript - 我不能将 var 设置为 window.screenY
- c - 请用 libcsv 提供建议。我只需要阅读第一行
- node.js - Sequelize - 使用 AND 运算符连接查询表
- .net - 在 VB.net 网络浏览器中嵌入 Excel 实例