软件项目中,实现同一功能的源代码只保留一份是一项十分重要的最佳实践,这种做法可以带来许多显而易见的好处:
2009年的时候 kmacy@ 做了 一些初步的工作,但后续没有继续推进。 这之后 我 考虑重新把这个事给做掉,但苦于平时比较忙因此未能如愿。最终, Yoshihiro Ota 完成了大部分的工作。
这里记录一下当时所做的事情。
FreeBSD 是一个有相当长历史的项目,而 zlib 是一个很常用的库,并且当时在整个系统中有多处不同的副本, 因此我们希望这个迁移的过程尽可能平滑而尽量不要直接导致整个项目无法联编,或是需要长时间禁用某些模块的情况。
此前, Peter Wemm 在2013年把net/zlib(这是一份古老的 zlib 1.0.4 打成浆糊的版本) 能够与 ZFS 和 DTrace 中的版本并存,但他当时采用的方法是直接把几个冲突的符号改名。 此时,由于 ZFS 中附带的 zlib 版本也略显陈旧了 (1.2.3),因此,给它换成最新版本也成了一项目标。
在开工之前,首先需要摸清此时的现状。在 FreeBSD 内核中当时使用了某种版本的 zlib 的模块主要包括:
a.out
格式可执行文件的 gzip 压缩支持。它使用了一份很旧的 zlib 打成浆糊的版本,位于 sys/kern/subr_inflate.c
。sys/kern/subr_inflate.c
的 zlib 副本。sys/opencrypto/cryptodeflate.c
)。它使用的是 pppd 魔改过的 zlib 1.0.4。还有一个问题是 zlib 提供了一个 crc32 实现。crc32是一种很常用的算法, FreeBSD 中包含了 Gary S. Brown 于 1986 年撰写的一个实现。 两个实现的用法略有不同,但由于都叫 crc32 因此需要把其中一个改个名字才可以并存。
接下来是确定我们到底应该做什么。a.out
的支持已经过时(毕竟已经超过10年了,大家都应该用ELF了),
kgzldr
和 kgzip
已经不再必要(因为已经有新的功能去实现同样的目的),因此这两项功能可以直接砍掉。
魔改过的 zlib 1.0.4:Paul Mackerras 在早年对 zlib 进行了一些魔改以便适应 ppp 中的一些需要,例如 Z_PACKET_FLUSH
。
RFC 1979 Section 2.1 中规定,
deflate 的最后4个字节内容(0x00 0x00 0xFF 0xFF
)不应传出。除此之外, zlib 1.0.4 大致与最新的 zlib
相同。我们的主要目标是把这份 zlib 彻底移除。
ZFS 和 DTrace:作者采取了良好的工程实践,不对第三方代码进行不必要的改动。这份 zlib 1.2.3 的移除并没有什么技术上的特别困难。
FreeBSD 的源代码目录规范要求内核使用的代码放到 sys/
,因此首先把 zlib 挪过去。D20191, rS347244, c9083b85
为了便于逐步完成修改,我们选择了首先让两个库可以并存,然后逐渐将现有代码迁移到最新的 zlib 上的方法。
state->dummy
。D20222, rS348222, a4981878。这是早期版本 zlib 中针对编译器的一个workaround,其值对于调试意义不大。kgzldr
和 kgzip
支持。D20248, rS348225, 5e86bd60crc32()
实现拆分出来并改名为 gsb_crc32()
。D20193, rS349151, f89d2072a.out
的 gzip 压缩支持。D21099, rS350436, d4565741sys/dev/zlib
, 将当时的最新版 zlib 1.2.11 变为内核模块,砍掉 ZFS 中的 zlib (1.2.3) 并替换为新的 zlib。D19706, rS350496, 0ed1d6fbZ_SOLO
模式中(主要是为 geom_uzip 做准备)。D21156, rS350670, a15cb219DDB_CTF
改为使用 zlib 1.2.11。D21176, rS350744, 22bbc4b2总体上,除了 ng_deflate(4) 之外,大部分 zlib 1.0.4 转换为 zlib 1.2.11 的过程仅仅是把使用的头文件改为新的 zlib,并根据需要使用 sys/dev/zlib
中的分配器替换掉原有的。
这里的一个例外是 ZFS 和 DTrace,当时使用的 OpenSolaris ZFS 中做了一些额外的内存越界检查,因此它使用了自己单独的一套分配器,而现在 OpenZFS 中则是和其他分配器一样了。
采用同一套 zlib,令后续的 zlib 安全问题的修补变得容易了许多(去年的 FreeBSD zlib 安全公告也因此受益,这是后话了)。
由于 Yoshihiro Ota 和我都不是专职做这件事,整体前后用了两个月左右的时间,但由于采取的小步变动、并在提交前进行大量测试的做法,整个过程并未对用户产生可见的负面影响,
我个人对整个过程是比较满意的。