COSCUP 2015 Day 2

The second day of COSCUP 2015 was August 16, Sunday. Since we had FreedomKnight and zerng07 at the booth, and we did not find very intersting talks in the early morning, tonghuix and I gave ourselves a bit more rest and did not get up quite early. We both found the talks this year were not as attractive as last year. Part of the reason might be that this year’s theme “Open Culture” is kind of too general and it is not easy to talk about it. Or in a sense it is align with COSCUP’s philosoph “more social than tech”, which means it is more a chance of letting open source people to meet than diving into specific technical topics.

Around the booth we found some interesting swags that might be useful for future Fedora events. One is the retractable network cable as shown in the middle figure above. Such cables were distributed in COSCUP previously as gifts. I think it is quite nice because: 1) it is so useful that one can start to use it directly at the venue; 2) the central circular part is perfect for branding logo etc.; 3) it is not expensive and can be cheap with mass production. Another nice swag is shown in the rightmost figure above, a toy moe girl (optionally, with a toy laptop). As soon as she appeared on our neighboring booth, a crowd of people and cameras came around the booth. Westerners might not understand, but moe culture is quite popular among East Asia countries, and it is getting mainstream. For example, in Taiwan you can find quite a few moe girls on various posters in public. Besides, ".moe" has become a registrable top-level domain name. Since she is so eye-catching, I guess it is worth trying to make one for Fedora. Regarding design, the Fedora moe girl might be a good starting point.

At the booth I also discussed with FreedomKnight and zerng07 about Fedora community development. zerng07 is getting busier with his work, and they are trying to develop a new ambassador. It seems that currently the Taiwan contributors prefer to use the Facebook group of Fedora Chinese community for discussion. I encourage them to keep an eye on our mailing lists and attend weekly IRC meetings, where activities are more visible to the Chinese community and the whole Fedora community. I also encourage them to go outside for better communication and cooperation. When the local community grows strong enough, Taiwan can be a good candidate for FUDCon APAC.

At around 15:00 PM, almost all attendees gathered into the large hall to listent to jserv‘s last speech “Retrospect on Taiwan Open Source Ecosystem”. jserv is a long term open source contributor in Taiwan, and he has contributed talks to COSCUP for all the ten years. In the morning I caught up with his experience sharing of open source in education. To encourage new contributors, he decided this talk to be his last speech in COSCUP. In the talk, he introduced the history of open source development in Taiwan and showed quite a few impressive early projects by Taiwan open source contributors. He also motivated the young generation in Taiwan to contribute more to open source in the world.

After that was the lightning talk session. In COSCUP, a lightning talk can be not a “talk” at all, because all kinds of performance are also welcome. I had learnt the rule for a while, but this time I finally had the chance to hear an ocarina show as a lightning talk by a COSCUP volunteer! Why ocarina show? Simply because others learnt that he can play ocarina during face-to-face discussion.

At last, after a short closing speech from the lead organizer came the group photo session. All volunteers were invited on stage. An unmanned aerial vehicle (UAV) was used for taking photos, which was really cool. By the way it was also cool when the UAV flew over your head!

All in all, I enjoyed the two days of COSCUP very much. Looking into the future, I believe COSCUP can continue to be a great chance for Fedora Chinese community to gather up. Besides, non-Chinese contributors are also welcome to join to take the opportunity to meet face-to-face and get things done.

Advertisements

COSCUP 2015 Day 1

A few days ago I had the chance to attend COSCUP in Taiwan for the second time. This time I was lucky to get travel subsidy from Fedora APAC’s event budget. Below is my event report for day 1 (Aug 15, Saturday).

The venue of COSCUP 2015 is Academia Sinica, which is the same as in last year. But this time I stayed in a hotel not quite near the venue, sharing room with another Fedora ambassador tonghuix. So in the morning of day 1, we got up early and caught the Taipei MRT (Massive Rapid Transit) train. For the last mile to the venue, we took a taxi with FreedomKnight, a Fedora ambassador in Taiwan, and his girlfriend, who we happened to meet near our destination MRT station.

We arrived at the venue at about 8:30 AM, and it was about to allow registration. Quite a lot of attendees had already queued up before the gate. Shortly after that we registered by scanning the QR code. Then we looked for the booth location and set up the booth. FreedomKnight brought some Fedora 21 DVDs and I brought the badge reel which tonghuix carried from Beijing to Taipei. I tried a few ideas of placing these DVDs and settled down to a “4F” form. People started to visit our booth before we finished the preparation!

I spent the whole morning around our booth, talking with interested people about Fedora. Some of them were not familiar with Fedora, so I introduced to them that Fedora is an Linux distro similar as Ubuntu and openSUSE, but with special stress on our “Four Foundations” (aka 4F). Quite a few visitors had previous experience with Fedora, or current work experience with testing their company products on (somewhat old releases of) Fedora. I talked about Fedora.next with them and encouraged them to try out (or let their companies to try out) newer Fedora versions. Besides, we also met several guys who had used Fedora a lot but had not quite joined the local community, and I invited them to the Fedora BoF (Bird of a Feather) at night.

FreedomKnight’s girlfriend was also around our booth and helped out a lot. COSCUP continued to organize the “Dadi” game: every booth had a unique seal; anyone who had collected all booth seal stamps gained a chance in the lucky draw. There was a RPM packaging workshop which was proposed by the other Fedora ambassador in Taiwan, zerng07. Unfortunately zerng07 was not able to arrive on time due to work emergencies. FreedomKnight took the place and delivered the session.

In the afternoon, there were a workshop by tonghuix about how to use XMPP to chat, and I was asked to help with the demo. We demonstrated how to use free and open source XMPP clients both on Linux desktop and Android cellphone to chat, with and without OTR (off the record) encryption. I also took a few photos for the session.

Then at around 16:00 PM, tonghuix gave an impressive lecture on free software community management. He took many little stories from the book Zhuang Zi as examples to illustrate how and why certain management practices succeed or fail. He summarized the Tao of free software community management as “Three-Self”, which can be roughly translated as “Freedom (aka Self-will or Self-choice), Self-governance, Self-organization”.

When the day’s session almost came to an end, zerng07 finally arrived. We had him and some other Fedora community members for the BoF session in the evening. The total number of people for Fedora BoF was about ten. During the BoF we discussed the interesting differences of languages and education between mainland China and Taiwan, as well as their impact on software localization and overall cooperation of Fedora Chinese community. The Chinese glossary might need to be revived. More interaction is needed to facilitate cooperation, and more awareness and support from the whole Fedora project are also required.

bladeRF 固件与 FPGA 注记

使用 bladeRF 板卡时我们会遇到两个“镜像”:固件 (firmware) 镜像与 FPGA 镜像。二者是两个不同的概念。但是业界叫法不一,有时候会把二者混为一谈。一般而言,固件指的是嵌入到硬件设备中的软件,存放在只读存储器 (ROM) 或者闪存 (flash) 中,一般不易修改,修改的操作称为“刷新”(flashing)。固件这个名词最初和微代码相关,不过 bladeRF 里源代码是嵌入式 C 程序。FPGA 全名为可编程门阵列,其门电路、寄存器连接可以编程重构,其源程序一般是硬件描述语言 (HDL),通过综合 (synthesis) 等步骤得到二进制文件。在 bladeRF 板卡上,FPGA 只是一块 Altera 芯片。在没有内置非挥发存储时,FPGA 镜像需要每次上电时重新加载,bladeRF 就是这种情况。所以在拿到板卡时,上面已有固件,但还没有 FPGA 镜像。下面本文会具体说明在使用 bladeRF 时如何刷新固件、加载/更新 FPGA 镜像、以及如何自动加载 FPGA 镜像。注意,有时为了避免混淆,会称 FPGA 镜像为 FPGA 比特流 (bitstream),或者 FPGA 配置(因为它就是配置了门电路等组件的连接)。

刷新固件

注意:刷新固件前请先取消 FPGA 自动加载,以避免可能的冲突。FPGA 自动加载的细节参见下文。

Nuand 官方提供固件的源码,我们可以自行编译,不过这需要一套嵌入式开发工具链。Nuand 也提供构建好的固件镜像,可以直接下载使用。要刷新固件,只需在命令行执行:

bladeRF-cli -f bladeRF_fw_vX.Y.Z.img -v verbose

其中 X.Y.Z 为具体的版本号。命令完成后,需要断电重启了 bladeRF。然后可以用 bladeRF-cli 工具检查:

$ bladeRF-cli -e version

  bladeRF-cli version:        0.11.1-git-c631100
  libbladeRF version:         0.16.2-git-c631100

  Firmware version:           1.7.1-git-ca697ee
  FPGA version:               Unknown (FPGA not loaded)

看下其中 Firmware version(固件版本)是否更新。

事实上,还有另外一种刷新固件的方法,是通过进入设备的启动加载 (Bootloader) 模式(类似 Android 的 Recovery),输入一些命令完成的。不过这种方式步骤繁琐,一般不推荐使用,建议在上述简单方法遇到错误时考虑采用。具体步骤参加维基

加载 FPGA 镜像

注意到上面的示例中,FPGA version(FPGA 版本)显示为 Unknown(未知),FPGA 未加载。目前 bladeRF 使用两种 FPGA。要加载正确的 FPGA 镜像,首先需要确定手头 bladeRF 板卡的 FPGA 尺寸。它可以根据当初购买的价格判断,但更靠谱的方法是使用命令行查看:

$ bladeRF-cli -i
bladeRF> info

  Serial #:                 4f977f01eec48f5068c2ee3aeba41ba9
  VCTCXO DAC calibration:   0x8b63
  FPGA size:                40 KLE
  FPGA loaded:              yes
  USB bus:                  4
  USB address:              5
  USB speed:                SuperSpeed
  Backend:                  libusb
  Instance:                 0

交互模式下用 info 命令,或者直接在命令行下 bladeRF-cli -e info,在输出中寻找 FPGA size,就可以看到 FPGA 尺寸信息。这里示例显示板卡使用 40 KLE FPGA。事实上,FPGA 尺寸还可以通过查看 FPGA 芯片上的 EP4CExxxF23C8N 字样中 xxx 的部分来获得。

Nuand 官方提供了预先构建的 FPGA 镜像,免除用户手工编译之苦。40 KLE FPGA 对应 hostedx40.rbf 文件,以此类推。要加载 FPGA 镜像,只需使用命令 bladeRF-cli -l /path/to/fpga/file,或者交互模式下 load fpga /path/to/fpga/file,其中 /path/to/fpga/file 为 FPGA 镜像所在路径。FPGA 镜像成功加载后,板卡上的三个 LED 灯会亮起,交互模式下 version 命令可以看到 FPGA 版本不再是未知。

不过,正如前文所说,每次重新加电后,FPGA 镜像都需要重新加载。下面说下如何自动加载 FPGA 镜像。

自动加载 FPGA 镜像

bladeRF 维基上提供了两种自动加载 FPGA 镜像的方法。第一种方法基于主机软件,libbladeRF 在打开设备时,会在如下目录自动搜索合适的 FPGA 镜像:

  • $HOME/.config/Nuand/bladeRF/
  • $HOME/.Nuand/bladeRF/
  • /etc/Nuand/bladeRF/
  • /usr/share/Nuand/bladeRF/

只需将下载的 FPGA 镜像文件放在上述目录之一(没有可以新建之),即可实现 FPGA 镜像的自动加载。

另一种方式是将 FPGA 镜像写入设备的 SPI 闪存。这种方式的好处是写入后就不再依赖主机,从而可以实现脱机运行。不过这种方式比较慢,加载 x40 镜像需要大约 4 秒钟。注意绝对不要在加载完成,三个 LED 灯亮起前试图使用设备。要使用这种方式,需要执行下面命令:

bladeRF-cli -L /path/to/fpga/file

一般说来,如果没有脱机工作的需求,还是推荐第一种自动加载方法。

前面提到,刷新固件时最好取消自动加载。对于第一种方法,只需把 FPGA 镜像文件临时移走。第二种方法,则需要执行命令 bladeRF-cli -L X,以擦除写入的 FPGA 镜像。

致谢

本工作由星天科技赞助。

Fedora 上搭建 bladeRF 环境

bladeRF 维基上介绍了在 Linux 系统上搭建 bladeRF 环境的步骤,不过原文是英文的,另外其中一些具体选择不尽合理。本文以 Fedora 系统为示例,提供一个中文版的 bladeRF 环境搭建指南,并着重介绍和维基上的不同点。比较可能有一定的时效性,但一些原则应该足够通用。本文的比较基准是当前的维基版本

安装依赖

维基上建议安装 “Development Tools” “Development Libraries” 两个软件包组,但我们只需要其中的一部分软件包,其中有些可能已经安装过了,而像 cvs 等并不必须。如果你像我一样有“洁癖”,不希望安装不需要的软件包,那么可以用如下的命令安装必须的依赖(未严格验证,在我这里绝大多数包都在之前安装过了):

sudo yum install git doxygen gettext glibc-devel ncurses-devel readline-devel zlib-devel boost-devel
sudo yum install libusbx libusbx-devel cmake wget gcc-c++

注意其中是 libusbx 而非 libusb,后者是 0.x 系列的版本,而非 1.x 系列。Debian/Ubuntu 系的用户会注意到软件包命名上的差异 (devel 而非 dev)。

维基上推荐安装 libtecla,以增强 bladeRF-cli 交互模式的编辑功能。不过 Fedora 软件源里目前还没有这个包,所以需要手动下载,解压缩,使用经典的 ./configure; make; sudo make install 三部曲安装。

构建 bladeRF

在终端下进入打算用来放置 bladeRF 源码的目录,用 git 将 bladeRF 的源码库克隆下来:

cd /path/to/bladeRF/directory
git clone https://github.com/Nuand/bladeRF.git

切换到源码目录中的 host 目录,创建一个 build 目录用来存放构建过程的中间文件。这种使用单独的构建目录的方式称为树外构建 (out of tree build),相对于直接在源码目录构建,好处在于生成的中间文件不会分散在源码目录里,方便清理,另外可以用多个构建目录构建出互不干扰的不同参数下的版本。之后切换到构建目录,然后就是标准的 cmake ..; make; sudo make install 三部曲了。注意这里 cmake 时启用了 INSTALL_UDEV_RULES 宏,使得安装时把 udev 规则文件也安装到系统中。

cd bladeRF/host/
mkdir build
cd build
cmake -DINSTALL_UDEV_RULES=ON ../
make
sudo make install

很遗憾的是这里安装的 udev 规则文件使用了 plugdev 群组,不是 Fedora 下的标准做法。可以参考之前的博文修改 udev 规则文件。

为了让新安装的 bladeRF 库文件可以被二进制文件使用,我们需要用 ldconfig 刷新系统动态库的缓存。上面的构建过程会将 bladeRF 安装到 /usr/local 下,而其中的库文件目录 /usr/local/lib{,64} 不在 ldconfig 的默认搜索路径里。所以我们可以将它们添加到 /etc/ld.so.conf 里。添加之后文件内容如下:

/usr/local/lib
/usr/local/lib64
include ld.so.conf.d/*.conf

之后,用 sudo ldconfig 刷新缓存即可。可以用 ldd /usr/local/bin/bladeRF-cli 命令检查 bladeRF 库文件是否被找到。连上 bladeRF 设备,用 bladeRF-cli -p 命令看下是否能够发现设备。更多操作见于另一个维基页

构建 GNU Radio 与 gr-osmosdr

通过上述步骤,就可以操作 bladeRF 板卡了。但是,要想便捷地为 bladeRF 开发软件无线电应用,最好再构建一下 GNU Radio 和 gr-osmosdr。GNU Radio 是一个开源的软件无线电开发平台,提供众多的信号处理模块和简单易用的图形界面开发环境。gr-osmosdr 适配 GNU Radio,为众多硬件板卡(除了 bladeRF 之外还有 HackRF 等)提供一个统一的软件接口。

GNU Radio 依赖比较多,编译安装相对麻烦,一般推荐使用 build-gnuradio 脚本。但是因为其中涉及到从网络下载诸多软件以及编译安装,效率受网速和电脑硬件性能限制,耗时较长。另外,脚本的健壮性不高,所以很容易中途退出。这个脚本很长,但实际上是把整个构建过程划分为几个步骤,放在几个函数里先后执行的。我建议阅读这个 Shell 脚本,每次运行其中的一步或几步,必要时手动完成一些配置。对于新手,这会是一个很好的通过阅读代码学习 Shell 编程的机会。

具体的构建步骤可以在维基或这里找到,这里就不再赘述。只是提几点注意事项:

  • 如果你像我一样,除了 bladeRF 之外,还会使用 Ettus 公司的 USRP 系列设备,那么记得先构建 UHD,然后构建 GNU Radio。
  • build-gnuradio 脚本在 cmake 时,有时用了树外构建,但有时又没用。建议始终用树外构建。
  • 编译 GNU Radio 时,并行 make (make -j N 其中 N 大于 1)时有时会编译失败(竞态条件?),直接 make 就可以正常编译通过,虽然速度会慢很多。什么?make 也会出错?那考虑换一个 git 提交重新编译,并向上游报 BUG 吧。

构建成功 GNU Radio 后,构建 gr-osmosdr 就显得小菜一碟了,标准的 cmake 构建三部曲,项目不大,编译过程也能很快完成。

全部构建完成后,可以使用如下命令用 bladeRF 看一下频谱,检验是否大功告成。其中 FPGA 映像可以从 Nuand 网站下载。此外,最新固件也可以从官网下载。

osmocom_fft -a bladerf=0,fpga=<your FPGA image> -s 2000000 -f 446000000

致谢

本工作由星天科技赞助。

Fedora 上可插拔设备授权:向 plugdev 群组说不

最近,我发现 Fedora 系统上没有 plugdev 群组,而是使用动态 ACL 的方式允许普通用户访问可插拔设备等。

事情的缘由是我在折腾软件无线电 (SDR),更特别的说就是 bladeRF,它在编译安装时会自动安装相应的 udev 规则,以使得普通用户可以访问这块板卡。它提供的 udev 规则文件为 /etc/udev/rules.d/88-nuand.rules,内容如下:

# nuand bladeRF
ATTR{idVendor}=="1d50", ATTR{idProduct}=="6066", MODE="660", GROUP="plugdev"

# Reserved for future bladeRF-specific bootloader
ATTR{idVendor}=="1d50", ATTR{idProduct}=="6081", MODE="660", GROUP="plugdev"

# Cypress Bootloader
ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f3", MODE="660", GROUP="plugdev"

其含义是将 bladeRF (以及相关设备)的权限设为仅属主和群组可读写,群组设为 plugdev。类似的使用 plugdev 群组的 udev 规则设置,在许多涉及可插拔外设的上游项目里都会看到。

然而事实上 Fedora 系统上是没有 plugdev 群组的。bladeRF 维基建议手动建立该群组,并将当前用户添加进去。 但这种做法其实是不被 Fedora 推荐的,原因是这种静态的设备管理群组

  • 不安全。考虑这样的一个场景:一个 SSH 远程登录的用户可以访问物理主机的摄像头、麦克风,只要他是该群组的成员。
  • 不灵活。需要手动地维护该群组的成员列表,新增用户还需要注销当前会话重启会话才能使用该设备。
  • 不具体。plugdev 群组的用户可以使用任何可插拔设备,不论这个设备是手机、摄像头还是麦克风。

Fedora 支持动态的权限控制 (ACL),可以根据用户会话状态、物理座位(seat)配置来决定是否授权设备。在这种机制下,udev 规则文件可以是简单的一行

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", 
  ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="000[456]" 
  ENV{ID_<some_name>}="1"

这里的 ID_<some_name> 是设备的一个“合适”的类别,例如 ID_CDROM, ID_MEDIA_PLAYER 等。它会出现在 Systemd 的 uaccess 规则文件 70-uaccess.rules 中,这个文件会授权此类设备给活跃用户。

遗憾的是,目前 uaccess 规则文件里并没有一个软件无线电有关的设备类别。所以暂时只能像如下的 udev 规则文件中那样,直接给设备加上 uaccess 的标签:

SUBSYSTEM!="usb", GOTO="nuand_rules_end"
ACTION!="add", GOTO="nuand_rules_end"

ATTR{idVendor}=="1d50", ATTR{idProduct}=="6066", TAG+="uaccess"

# Reserved for future bladeRF-specific bootloader
ATTR{idVendor}=="1d50", ATTR{idProduct}=="6081", TAG+="uaccess"

# Cypress Bootloader
ATTR{idVendor}=="04b4", ATTR{idProduct}=="00f3", TAG+="uaccess"

LABEL="nuand_rules_end"

注意 udev 规则文件命名时开头的数字编号需要小于 70,此时 uaccess 才会生效。如果设备已经连接到电脑上,要使新添加的或新修改的规则生效,还需要 udevadm trigger 一下。

事实上,邮件列表并不推荐上述做法,udev 与 Systemd 开发者 Kay Sievers 表示设备规则文件不应该直接设置 uaccess 这一标签。我已经在 systemd-devel 邮件列表上请求添加一个软件无线电相关的设备类别,得到了肯定的回应,并最终在这次提交中添加了 ID_SOFTWARE_RADIO。在不远的将来,带有这一改动的 Systemd 进入主流发行版后,我们将可以通过在 udev 规则文件中使用类似 ENV{ID_SOFTWARE_RADIO}="bladerf" 的语句,让普通用户以一种更安全灵活的方式使用软件无线电外设。

清空旧电脑上的 Linux

最近我把个人资料迁移到了一个新笔记本电脑上,旧电脑不再使用了,需要清除上面的个人数据。旧电脑是 Windows XP 与 Linux (Fedora 19) 的双系统,个人资料在 Linux 下,所以任务是清空 Linux 系统,保留原有 XP 可用。

由于重要的数据都已导出,所以这给了我一次在实体机上尝试 rm -rf / 的绝佳机会。众所周知,这项操作需要 root 权限 (su/sudo),而且 GNU 的 rm 默认已不再允许在顶级根目录下这样做,所以真实的命令是:

sudo rm -rf --no-preserve-root /

我是在原 Linux 系统图形界面的虚拟终端里做此操作的。过了一会儿,突然虚拟终端不见了,桌面背景等都还在。在图形界面试图新建虚拟终端无效。于是我切到控制台终端,发现控制台一直是等待状态,没法登录。(猜想是相应的程序都没了。)切回图形界面后发现鼠标键盘失去响应,但桌面背景还在。此时已经做不了什么有意义的操作,于是按电源键关机了。

之后用 Live USB 开机登录,挂载硬盘分区,发现原 Linux 的文件并没有全删光,还残留若干空目录,也有非空目录下有残余文件,$HOME 下也有几个残余文件(视频目录里有东西!$HOME 下还留着一个 PDF 文档!),不过所剩无几。

不过我们知道,Linux 下的 rm 本质上是去掉文件系统中的链接 (unlink),硬盘上的数据并没有擦除。使用数据恢复工具还是有可能找回其内容的。要真正地清空硬盘分区,需要进行“低格”,即低层格式化。Linux 上的 dd 命令可以做到这一点。如下 /dev/sda7 是一个 Linux 分区,我们通过往上面写入全零 (/dev/zero) 来擦除数据(使用 /dev/urandom 写入随机数也是可以的)。

[liveuser@localhost~]$ sudo dd if=/dev/zero of=/dev/sda7 & pid=$!

注意其中用的是一个 & 号,意为放后台运行。后面将进程号赋值给 pid 变量,是为了后面可以方便地查询进度,毕竟受限于磁盘 IO,dd 对于几百 GB 的硬盘是很慢的。可以通过向 dd 命令发送 USR1 信号获取当前进度:

[liveuser@localhost ~]$ sudo kill -USR1 $pid
[liveuser@localhost ~]$ 512417+0 records in
512417+0 records out
262357504 bytes (262 MB) copied, 17.5086 s, 15.0 MB/s

由于耗时实在太长,我是晚上把电脑一直开着,第二天去看的结果。最终擦写完成后会显示类似下面的信息:

[liveuser@localhost~]$ dd: writing to ‘/dev/sda7’: No space left on device
210183058+0 records in
210183057+0 records out
107613725184 bytes (108 GB) copied, 8295.38 s, 13.0 MB/s

可见,这个 108 GB 的分区用了两个多小时才擦写完。类似地对每个 Linux 分区执行上述 dd 命令,即可把所有数据擦除干净。有人会建议多擦写几次(3次?)以更加确定数据不会被恢复。不管怎样,注意务必写对分区编号,不然把(未备份的)有用数据擦掉了就出大事了。(如果你要清空整个硬盘的话,注意把硬盘设备名弄对。)

清除数据的任务到此就宣告结束了。不过,对于双系统来说,正常的引导是通过 GRUB 来实现的,而 /boot 分区或文件在前面已经被擦除了,所以开机会进入 GRUB 的 rescue shell 中。我没有搞明白如何在这里引导进入 XP 系统,于是用 Windows 系统光盘恢复引导。由于手头没有 XP 安装盘,当时用的是一个 Server 2003 的安装盘。不过操作是一样的,这个文档里有详细说明。简单来讲,就是进入 Windows 安装盘修复模式后执行 fixmbr 命令。

迎回 FvwmButtons

先介绍下背景。我使用 Fvwm 做窗口管理器,用 FvwmButtons 做了一个任务栏,还做了一个类似 Unity 或 GNOME Shell 侧栏的应用程序快捷启动器栏,并且把工作区切换器(一个 FvwmPager)嵌在里面。我用比较多的 GTK 或 GNOME 程序,但不开 gnome-session。为了使 GNOME 控制中心的设置生效,我在 Fvwm 配置中在初始化阶段启动 gnome-settings-daemon。

这样的配置一直工作地很好,但升到 Fedora 18 之后,同样的配置下,进入桌面后会卡死几秒钟,之后 CPU 负荷很快达到并保持 100%,用 htop 查看是两个 FvwmButtons 进程占用了很高的 CPU,不得不用 SIGKILL 信号杀死。当我注释掉一个 FvwmButtons 后,高 CPU 负荷的问题出现的机率大为减少,但还是偶有发生。两个 FvwmButtons 都注释掉,CPU 不会 100%。这时进入桌面后再手动开两个 FvwmButtons,也不会再有 CPU 持续 100% 的问题。这一诡异的问题使我很长一段时间内都要进入桌面后再开启两个工具栏。之前还集中精力调试过一次,以为可能是 race condition 之类的问题,试图通过调整启动过程中两个 FvwmButtons 的启动顺序位次来解决,但后面测试表明这不是有效的解决手段,问题还会不时出现。

随着我升级到 Fedora 18 还有一个有关 Fvwm 的问题出现:使用 Fvwm 的 Restart 命令重启桌面后,通知区域的部分图标(如 Fcitx、NetworkManager)会丢失。尽管相应的主程序还在运行可以使用,但没有这一小图标一些事情就做不了或不方便做了。我的通知区域由 stalonetray 提供,它被嵌在任务栏中。与此同时,经常收到 ABRT 报告说 control-center 遇到问题等。此外,程序的字体大小会变小(恢复默认值),而不是我配置的字体大小。这一问题使得 Restart 重启桌面不再有用,这在使用 Fedora 16 和更早时是没有过的。

近日我又对这些问题有了兴趣。首先我关心的是通知区域图标丢失的问题。通过对 Fvwm 配置中重启时调用的函数 StartFunc 的调试,我发现问题在于其中有一行 killall stalonetray。它是用来杀死已有的 stalonetray 进程的。正常来讲,这里杀死旧进程后,开启 FvwmButtons 任务栏时会启动新的 stalonetray 进程。(根据版本库记录,去年的 4 月份做的这样配置,参考自论坛讨论。)然而在 Fedora 18 上,杀死 stalonetray 进程后,gnome-settings-daemon 进程就挂掉了!事实上,我可以在命令行下启动 gnome-settings-daemon(它在 /usr/libexec/ 目录下)和 stalonetray,然后命令行 killall stalonetray,这时 gnome-settings-daemon 会报一大段错误,退出程序。于是,问题解决需要不杀掉 stalonetray。最终的解决方案是 StartFunc 中删除 killall 这一行,并且在 FvwmButtons 配置中做如下改动(diff 格式):

-*FvwmButtonsTop: (3x1, Frame 0, Left, Swallow(Close,Kill,UseOld) "stalonetray" `Exec exec stalonetray`)
+*FvwmButtonsTop: (3x1, Frame 0, Left, Swallow(NoClose,UseOld) "stalonetray" `Exec exec stalonetray`)

其中关键是 NoClose,它使得每次 Restart 之后 FvwmButtons 被自动杀掉时,stalonetray 会被吐出 (unswallow),之后再启动 FvwmButtons 任务栏后又会吞入 (swallow)。stalonetray 进程一直活着,其中的图标也不会丢失了。事实上,最初我对字体大小变化的问题并不敏感,没有意识到这正是 gnome-settings-daemon 相关的反应。之前一直怀疑 stalonetray 不够可靠,浪费了好些时间。滑稽的是,这和我去年 4 月份做的修改恰好相反,只是那是 Fvwm 是 2.6.4,现在是 2.6.5,而 stalonetray 是许久没有版本更新了。也许这里的 bug 报告使得 NoClose 作用于 stalonetray 变正常了。

这一问题解决之后,我又试图调查进入桌面时卡死数秒的问题。为了找出可疑的进程,我在控制台终端登录,在 GDM 登录 Fvwm 之前,启动一行命令(主要目的是每隔一秒打印出占用 CPU 最高的 10 个进程):

sleep 2; while true; do ps aux --sort=-pcpu | head -n 10; sleep 1; done | tee test/log

很遗憾这样得到的输出没有多大帮助,若干个进程(fvwm, gnome-settings-daemon, nm-applet)都会短时间内占用不少的 CPU,但没有哪个看起来特别突出。最后真正有效的排查方法很土,就是将 Fvwm 的启动函数内容全部注释,然后逐个加入,测试观察。测试结果表明,问题出在 gnome-settings-daemon 上。不启动这个进程时,Fvwm 进入桌面没有可以感觉到的卡顿,很快就加载好自启动程序。而一加入 gnome-settings-daemon,进入桌面时就会遇到数秒内 CPU 负荷很高桌面卡死的现象。在桌面里,手工启动 gnome-settings-daemon 也有类似反应。这使我 Google 了一下 “gnome-settings-daemon high cpu”,结果的确看到了一些 bug 报告,包括 GNOME Bugzilla 的这个。不过这里的问题和我遇到的并不一样,这里的问题是 gnome-settings-daemon 的 CPU 负荷持续居高不下,而且和 NumLock 有关系。我的确试了其中的与 NumLock 相关的一行修复,不过对我的情形没有什么帮助。

定位到问题在于 gnome-settings-daemon 使我意识到,在 Fvwm 的 InitFunc 里启动它是不行的,至少对 Fedora 18 上的 gnome-settings-daemon 3.6.4 是不行的。于是我考虑把启动它提前,让它不在 InitFunc 执行期间和更后面制造麻烦。具体来讲,我在 Fvwm 配置文件中删除了启动 gnome-settings-daemon 这一行。然后把 /usr/share/xsessions/fvwm.desktop 文件中 Exec 一行修改如下:

Exec=/home/alick/bin/startfvwm

这里的 startfvwm 内容如下(记得要给它可执行权限!):

#!/bin/sh
/usr/libexec/gnome-settings-daemon &
sleep 5
fvwm

后续测试表明这样确实解决了进入桌面时卡死的问题,尽管在进入前引入了 5 秒的延时。(我试过设置成 2 秒,结果这时重启机器后第一次进入 Fvwm 时,仍会要一段时间的卡死。)之后 Fvwm Restart 或注销重新登录时都能很快准备好桌面。笔记本睡眠、台式机24小时工作会弱化这个延时的负面影响。

值得一提的是,我起初尝试 Archlinux 维基中提到的 .xprofile,期望 GDM 在启动 xsession 前先执行它。测试发现在我的 Fedora 18 上 GDM 是无视这个文件的。粗略 grep 了一下 /etc/gdm//etc/X11/xinit/ 下的文件,也没有 xprofile 出现的痕迹。