Freeshell 3 号节点控制面板卡死

问题源于一个 freeshell 内的两个进程在退出过程中,mmap 加载的 exe 文件在关闭时,NFS 的 CTO(close to open)功能为保证缓存一致性,会发起 NFS 请求来检查该缓存的文件项是否过期了。如果此操作被卡住,则该进程就成了不可中断状态的僵尸进程,如下所示。

root      893850  0.0  0.0      0     0 ?        D    Aug30   0:00 [ifup]
root      893903  0.0  0.0      0     0 ?        D    Aug30   0:00 [sleep]

尽管 RPC wait 使用的是 killable,但在退出过程中的进程已经变成 uninterruptible,因此 SIGKILL 信号是不起作用的。当然可以编写内核模块,把进程状态强制改成 Ready,这样 CPU 再次调度到此进程时就会走完退出流程,但我现在没有该版本内核的编译环境。简单起见,决定白天物理重启该服务器。

内核 stack trace(两个导致问题的进程相同)

[<ffffffffa04f69b4>] rpc_wait_bit_killable+0x24/0x40 [sunrpc]
[<ffffffffa04f698d>] __rpc_wait_for_completion_task+0x2d/0x30 [sunrpc]
[<ffffffffa05b64d3>] nfs4_do_close+0x203/0x270 [nfs]
[<ffffffffa05c4565>] __nfs4_close+0xc5/0x180 [nfs]
[<ffffffffa05c4638>] nfs4_close_sync+0x18/0x20 [nfs]
[<ffffffffa05b1320>] nfs4_close_context+0x30/0x40 [nfs]
[<ffffffffa0594d33>] __put_nfs_open_context+0xb3/0x110 [nfs]
[<ffffffffa0594e45>] nfs_release+0xb5/0xd0 [nfs]
[<ffffffffa0592b31>] nfs_file_release+0x61/0x90 [nfs]
[<ffffffff811ae468>] __fput+0xf8/0x280
[<ffffffff811ae615>] fput+0x25/0x30
[<ffffffff8121d289>] removed_exe_file_vma+0x39/0x50
[<ffffffff81170978>] remove_vma+0x118/0x130
[<ffffffff81170a68>] exit_mmap+0xd8/0x190
[<ffffffff8107305c>] mmput+0x5c/0x1f0
[<ffffffff81079a09>] exit_mm+0x109/0x150
[<ffffffff8107b7d7>] do_exit+0x187/0x930
[<ffffffff8107bfd8>] do_group_exit+0x58/0xd0
[<ffffffff8107c067>] sys_exit_group+0x17/0x20
[<ffffffff8100b102>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff

为避免此问题再次出现,考虑到 freeshell 外部存储的实际情况,现已关闭 CTO(close to open)功能。

Freeshell 外部存储修复 UID 错误问题

昨晚 freeshell 外部存储上线以来,外部存储系统中的一些 UID 变成了 root(0)或 nobody(65534),导致一些文件权限问题。

经查,这是由于 NFSv4 协议并不是直接传输 UID/GID,而是在 NFS client 端由 idmap 服务将 UID/GID 转换成 username@localdomain 的形式,以字符串形式传输给 NFS server,server 端的 idmap 服务再把字符串转换成 UID/GID。也就是说,client 与 server 的主机系统中只要至少有一端的 /etc/passwd 中不存在这个 UID/GID,就会出现问题。如果是从其他 freeshell 复制过来的,复制(rsync)过程中文件首先以 root 身份创建,随后的 chown 操作失败,所以 UID 就是 0;如果是在外部存储的 freeshell 中以“不存在”的用户身份创建文件,该文件的 UID 就会被 squash 成 nobody(65534)。

NFSv3 协议使用了数字 UID/GID 传输,不依赖 idmap 服务,不仅解决了 UID/GID 问题,还减少了无谓的开销。此问题现已解决。如果您今天新建或迁移了 freeshell,请自行修复 UID/GID,因此带来的不便望能谅解。

感谢 vanabel 的 bug 报告。

Freeshell 添加一块硬盘

由于 freeshell 硬盘空间告急,现把原来用作备份的 2T 7200rpm SATA 盘用作存储。新注册的 freeshell 和 Copy、Move后的 freeshell 都将使用新硬盘作为存储。现有 freeshell 的存储位置不变,重装系统和 Move 也不会改变存储位置。

新硬盘安装在 1 号节点上,其他节点使用 NFS 挂载。NFS 的小文件读写性能不是很好,但通过调整参数,达到了可以接受的性能。各节点连接同一个交换机,目前 MTU 为 9000,NFS server 挂载参数为 rw,async,no_subtree_check,no_root_squash,NFS client 挂载参数为 rw,rsize=32768,wsize=32768,udp,timeo=15,intr vers=3,rw,rsize=32768,wsize=32768,tcp,timeo=10,retrans=5,soft,intr,sec=sys,lookupcache=all,ac,nocto

新参数主要做了如下优化,使得 NFS 的 I/O 性能与本地接近:

  1. 使用 NFSv3 取代 NFSv4 协议,这样就不需要在 client 端把 UID/GID 转换成 username@domain,在 server 端再转换回 UID/GID 了。
  2. 由于不同节点始终在访问不同的数据,关闭文件时不需要刷新缓存,即 nocto 选项。这也修复了进程退出时关闭打开的文件需要刷新缓存导致的进程卡死问题。
  3. 为避免 NFS 抽风导致应用挂死,使用 soft 选项,即查询失败时返回文件打开失败,而不是让应用程序挂起等待。使用 TCP 和更多的重传次数来提高稳定性。

初步测试结果(对比 2 号节点与 1 号节点上对 SATA 盘上 freeshell 的操作):

  • 解压 Debian wheezy minimal 系统 tar.gz 包:本地 6.925s,NFS 26.453s(NFS 比本地慢 3 倍) 本地 7.277s,NFS 19.897s(NFS 比本地慢 173%)
  • 启动虚拟机,apt-get update,生成 locale:本地 10.674s,NFS 11.458s(NFS 比本地慢 7%) 本地 11.480s,NFS 10.790s(NFS 比本地快 6%)
  • 安装 vim:本地 13.920s,NFS 16.911s(NFS 比本地慢 21%) 本地 8.911s,NFS 10.879s(NFS 比本地慢 22%)
  • 安装 build-essential:本地 51.163s,NFS 77.057s(NFS 比本地慢 50%) 本地 52.708s,NFS 50.480s(NFS 比本地快 4%)

fio 磁盘性能测试结果(老参数的,新参数的未测试)
Capture

新硬盘是 SATA 盘,性能本来就不如 SAS,再加上 NFS 和多台机器共享使用,性能可能会更差,因此仅作为磁盘空间不足时的救急方案。

如果您发现新注册的 freeshell 卡死,或者注册、复制、移动等操作长时间不能完成,请联系我们:support AT freeshell.ustc.edu.cn。

Freeshell 修复部分端口映射不一致问题

由于一些历史遗留问题,部分不存在的 freeshell 的端口映射仍然像幽灵一样存在于 ssh.freeshell.ustc.edu.cn 的 iptables 配置中,导致这些端口在控制面板中无法被映射。

为保证以后不再出现类似问题,现在不再使用 iptables 的增量更新功能,而是在每次端口映射配置发生变化时,生成完整的 iptables 配置文件,再用 iptables-restore 安装上去。非常抱歉端口映射不一致问题可能给您带来的麻烦。

感谢 Zitian Li 的 bug 报告。

Blog 修复插件不能自行访问数据库问题

背景:Blog 系统的 PHP 沙盒在 PHP 程序初始化时就自动建立了数据库连接,而且为了数据库安全不允许自行创建数据库连接。为此,我们修改了 WordPress 源码(wp-includes/wp-db.php),去掉了 mysql_connect 调用和 mysql_query 等查询函数中的 dbh(db handle)。但一些插件希望绕过 WordPress 的数据库类,自行访问数据库,这就会出问题,也就是一年半以来,blog 系统一直与这些插件不兼容。

现在我们对 PHP 沙盒进行了改进:

  • mysql_connectmysql_pconnect 不论什么参数,都返回已经建立的数据库连接。
  • mysql_select_db, mysql_close, mysql_list_db, mysql_drop_db 等函数,不论什么参数,都不做任何事并返回 false。
  • mysql_query, mysql_result 等含有可选连接参数的函数,忽略连接参数,始终使用默认连接(就好像连接参数不存在一样)。
  • 原来不支持的函数被调用时,以及 mysql_query 等函数加上连接参数调用时,会输出 E_DEPRECATED 级别的警告信息。WordPress DEBUG 模式的警告输出修改为 E_ALL & ~E_DEPRECATED,以免调试时大量此类信息充满屏幕。
  • 关闭 mysqli 支持。

如果您的插件需要访问数据库,主机名要使用 127.0.0.1(localhost);用户名、密码、数据库名任意,不管怎么填,连上的都是 PHP 沙盒自动连接的数据库。如果您发现数据库无法连接,或者某个 mysql 库函数无法使用,请联系我们:support AT blog.ustc.edu.cn

Blog 支持自己绑定的域名登录管理后台

之前自己绑定的域名登录管理后台时,example.com/wp-admin 会自动跳转到 example.blog.ustc.edu.cn/wp-admin。在管理后台中访问文章的链接却是自己绑定的域名,因此点击“查看文章”后的页面是未登录的,也就没有“编辑”、“回复”等选项。

现在对 nginx 配置和 WordPress 源码进行了修改,使得 example.blog.ustc.edu.cn 和自己绑定的域名都可以登录管理后台。建议使用您绑定的域名登录,这样查看文章页面就有管理员工具等功能了。

感谢 Yifan Gao 报 bug。

USTC Blog 支持 FTP 修改代码

USTC Blog 不小心改错代码或安装不兼容的插件后,blog 可能会无法访问。这时可以使用新推出的 FTP 服务,在线修改代码。

FTP 服务器地址是 ftp.blog.ustc.edu.cn,目前只支持 IPv4。用户名是 domain\username,其中 domain 是 xxx.blog.ustc.edu.cn 的 xxx 部分,username 是博客后台的登录用户名。密码就是博客后台的登录密码。如下图所示。

Capture

常见问题:

  1. 操作时提示 "/" points to a path which is outside the user's root directory. Some files are shared among USTC Blog users and could not be accessed.:WordPress 核心代码是在博客之间共享的,不能修改。需要修改的内容(插件、主题等)一般在 wp-content 目录中。
  2. 登录时提示 blog does not exist:请检查博客的域名。
  3. 登录时提示 Login failed. please login with correct domain\username and password combination:请检查域名、用户名和密码。
  4. 登录时提示 Sorry, you do not have WordPress administrator privileges.:请使用博客中有管理员权限的账号登录 FTP。
  5. 登录时提示 Not Activated:博客未激活或已经关闭,不能使用 FTP 功能。

如果您在使用中遇到其他问题,请联系 support AT blog.ustc.edu.cn。