内存管理-43-Swap-1-命令行工具实现
一、mkswap
基于 A13 + msm-5.4
1. 简介
源码位置: /android/external/toybox/toys/other/mkswap.c
该命令对要成为swap后端的设备的首页写一些格式化的内容(也就意味着用于swap的少一页),没有调用swap相关系统调用。
使用:
/ # mkswap --help Toybox 0.8.4-android multicall binary: https://landley.net/toybox (see toybox --help) usage: mkswap [-L LABEL] DEVICE Set up a Linux swap area on a device or file.
2. 用户空间实现
void mkswap_main(void) { /* (1) 以可读写方式打开目标设备/文件(参数 DEVICE), *toys.optargs 应该是参数如“/dev/block/zram0” */ int fd = xopen(*toys.optargs, O_RDWR), pagesize = sysconf(_SC_PAGE_SIZE); /* (2) 获取目标总长度(普通文件走 st_size,块设备优先走 ioctl(fd, BLKGETSIZE64, &size)), 可对块设备的fd进行ioctl */ off_t len = fdlength(fd); /* (3) 计算可用于 swap 的页数: pages = 总页数 - 1(预留首页用于 swap header 等元数据) */ unsigned int pages = (len / pagesize) - 1; /* (4)) toybuf 作为临时 header 缓冲区,按 unsigned int 为单位写入 */ unsigned int*swap = (unsigned int *)toybuf; /* (5) header 内部偏移: uuid 起始在 swap+3,label 起始在 swap+7 */ char *label = (char *)(swap+7), *uuid = (char *)(swap+3); /* * 写入头部。请注意,旧版本的内核在交换过程中会检查磁盘上的签名(而不是缓存中的签名), * 因此写入后需要进行同步。 * * (6) 填写 header 关键字段 * swap[0] = version(1) * swap[1] = 总页数 - 1 */ swap[0] = 1; swap[1] = pages; /* (7) 跳到 1024 偏移写 header(兼容传统 swap header 布局) */ xlseek(fd, 1024, SEEK_SET); /* (8) 生成 UUID(RFC4122 v4 风格随机 UUID) */ create_uuid(uuid); /* (9) 若指定 -L,还可以在mkswap时写入最多 15 个字符的标签 */ if (TT.L) strncpy(label, TT.L, 15); /* (10) 在偏移1024位置写 header(129 个 unsigned int),即version写的是1,last_page写的是pages */ xwrite(fd, swap, 129 * sizeof(unsigned int)); /* (11) 跳到第一页末尾写签名字符串 “SWAPSPACE2”, 这是内核 swapon 校验 swap 区是否合法的关键 */ xlseek(fd, pagesize - 10, SEEK_SET); xwrite(fd, "SWAPSPACE2", 10); //即 magic 写的是"SWAPSPACE2" /* (12) 强制落盘(旧内核在 swapon 时会直接检查磁盘内容) */ fsync(fd); /* 此宏为0,不执行 */ if (CFG_TOYBOX_FREE) close(fd); /* (13) 组织输出信息(大小、label、UUID) */ if (TT.L) sprintf(toybuf, ", LABEL=%s", label); else *toybuf = 0; printf("Swapspace size: %luk%s, UUID=%s\n", pages * (unsigned long)(pagesize/1024), toybuf, show_uuid(uuid)); }
交换区的第一页是交换区首部,内核使用数据结构 swap_header 描述交换区首部,上面主要写这个首页:
//include/linux/swap.h union swap_header { struct { char reserved[PAGE_SIZE - 10]; char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ } magic; struct { char bootbits[1024]; /* Space for disklabel etc. */ __u32 version; __u32 last_page; __u32 nr_badpages; unsigned char sws_uuid[16]; unsigned char sws_volume[16]; __u32 padding[117]; __u32 badpages[1]; } info; };
成员介绍:
前面1024字节空闲,为引导程序预留空间,这种做法使得交换区可以处在磁盘的起始位置。
成员 version 是交换区的版本号。
成员 last_page 是最后一页的页号。
成员 nr_badpages 是坏页的数量,从成员 badpages 的位置开始存放坏页的页号。
最后10字节是魔幻数,用来区分交换区格式,内核已经不支持旧的格式"SWAPSPACE",只支持格式"SWAPSPACE2"。
3. 内核空间实现
不涉及。
4. 小结
(1) swap可用空间大小是指定大小减去1个page=4k的大小。
二、swapon
1. 简介
启用swap后端设备。
源码位置: /android/external/toybox/toys/other/swapon.c
用法:
/ # swapon --help Toybox 0.8.4-android multicall binary: https://landley.net/toybox (see toybox --help) usage: swapon [-d] [-p priority] filename Enable swapping on a given device/file. -d Discard freed SSD pages -p Priority (highest priority areas allocated first)
-p指定优先级,高优先级设备被优先使用。
2. 用户空间实现
#define FLAG_d (1<<0) #define FLAG_p (1<<1) void swapon_main(void) { /* 0x70000 = SWAP_FLAG_DISCARD|SWAP_FLAG_DISCARD_ONCE|SWAP_FLAG_DISCARD_PAGES */ /* 如果&的结果是0,结果就是0。如果&的结果是1,结果是0x70000 */ int flags = (toys.optflags & FLAG_d) * 0x70000; /* 若指定了 -p 优先级参数(0..32767),flags 参数或上 0x8000 | <prio> << 0 */ /* 这里若只指定了 -d 不也会执行吗 */ if (toys.optflags) flags |= SWAP_FLAG_PREFER | (TT.p << SWAP_FLAG_PRIO_SHIFT); /* 调用swapon系统调用 */ if (swapon(*toys.optargs, flags)) perror_exit("Couldn't swapon '%s'", *toys.optargs); }
相关标志位:
SWAP_FLAG_DISCARD: 表示启用 swap discard 机制.
SWAP_FLAG_DISCARD_ONCE: 表示 swapon 时整块 swap 区域 discard 一次。可理解为上线时整盘清一遍。
SWAP_FLAG_DISCARD_PAGES: 表示运行时每当 swap 页释放时,对应块做 discard 或按页 discard。可理解为运行时边回收边清。
3. 内核空间实现
对应系统调用:
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) //mm/swapfile.c
TODO
三、swapoff
1. 简介
关闭swap后端设备。
源码位置: android/external/toybox/toys/other/swapoff.c
/ # swapoff --help Toybox 0.8.4-android multicall binary: https://landley.net/toybox (see toybox --help) usage: swapoff swapregion Disable swapping on a given swapregion.
2. 用户空间实现
void swapoff_main(void) { if (swapoff(toys.optargs[0])) perror_exit("failed to remove swaparea"); }
3. 内核空间实现
系统调用:
SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) //mm/swapfile.c
TODO
四、实验
1. file-swap
/ # dd if=/dev/zero of=/data/vendor/swap/swapfile bs=1m count=200 200+0 records in 200+0 records out 209715200 bytes (200 M) copied, 0.276512 s, 723 M/s / # / # mkswap /data/vendor/swap/swapfile Swapspace size: 204796k, UUID=54b045bd-2b52-430b-8dda-04a7946ae4b2 / # / # swapon /data/vendor/swap/swapfile -p 32759 / # cat /proc/swaps Filename Type Size Used Priority /dev/block/zram0 partition 6291452 723888 32758 /data/vendor/swap/swapfile file 204796 0 32759 / # / # swapoff /data/vendor/swap/swapfile //这样可以关闭 / # cat /proc/swaps Filename Type Size Used Priority /dev/block/zram0 partition 6291452 811068 32758
2. zram-swap
/ # swapoff /dev/block/zram0 / # cat /proc/swaps Filename Type Size Used Priority / # / # mkswap /dev/block/zram0 Swapspace size: 6291452k, UUID=c90e5ef6-2bde-40eb-9f7b-86dd027628a7 / # / # swapon /dev/block/zram0 -p 32758 / # cat /proc/swaps Filename Type Size Used Priority /dev/block/zram0 partition 6291452 0 32758
posted on 2026-03-31 11:29 Hello-World3 阅读(26) 评论(0) 收藏 举报
浙公网安备 33010602011771号