Category Archives: study

Linux下HiDPI 4k显示器和普通显示器双显示器设置

经受不住诱惑,败了一个4k显示器,比较经典的 DELL P2415Q,亚马逊价格2799,还算便宜,京东至少也是28xx的价格。顺便吐槽一下亚马逊,越来越不靠谱了,东西不全,以前觉得配送还可以,这次说周末到,也是冲着周末到才这么快下单的,结果周一才到。亚马逊的购物券花完了,以后转京东试试。

要用4k显示器现在都是需要设置HiDPI的,要不然字体太小,根本没法用。参考这篇Arch的wiki,试了几个桌面环境。我当前主力用的Mate环境还不支持HiDPI设置。首先试了Cinnamon,果然支持的很不错,都自动处理好了。可惜的是主题很难看,尤其浏览器里看文字输入框,都是黑黑的一片,输入的文字也不清晰,折腾了半天也没弄好,放弃了。又先后试了Fedora26里带的几个桌面环境,lxde、xfce等,都对HiDPI支持不好。最后不得不尝试gnome,因为自从gnome3之后我就放弃使用gnome了,实在是不习惯。

惊喜的是,gnome3有个gnome-classic模式,使用习惯上基本根gnome2类似,而且对HiDPI支持很好,也是自动都设置好了,字体果然比我之前 1680×1050 的显示器好看多了(用了快8年的显示器,当时还特意买的16:10的)。下一步就是设置双显示器,因为启用了HiDPI之后,非高清的显示器上的图标和文字都变的非常大。现在就想让非高清显示器是正常的DPI,4k显示器才是HiDPI。

正好,Arch的wiki上也有关于多显示器设置这么一节,基本就是使用xrandr命令直接设置两个显示器的位置,然后把非高清显示器用 –scale 参数放大,但实际屏幕还是那么大,所以效果就是图标和文字都变小正常了。但我照着wiki上的信息和其他google来的xrandr命令照猫画虎,怎么也不对,我觉得应该设置正常了的时候,非高清显示器一开始还能正确显示,但过几秒种之后显示器就又黑屏了,很奇怪。折腾了很久,调各种参数也不对,最后想到,我的非高清显示器只有dvi和vga接口,我现在的显卡没有vga口,我用的是vga转hdmi的转接线,是不是这个转换不稳定呢?就把hdmi口拔掉,直接用DVI口,重启再重新设置,副显示器终于不黑屏了……

下面是我的具体环境和命令。Dell 4k显示器分辨率是 3840×2160,作为主显示器,菲利普显示器分辨率是 1680×1050,作为副显示器,在主显示器的左边。命令是

xrandr –output DVI-D-0 –auto –scale 2×2 –output DP-0 –auto –pos 3360×0

–output DVI-D-0: 设置副显示器,各个显示器的名称可以通过 xrandr 命令的输出看到
–auto: 自动设置模式,一般就是最大分辨率
–scale 2×2: 把宽和高都放大两倍,原来是1680×1050,那么放大之后这块屏幕的大小就变成了 3360×2100,这点很重要

–output DP-0:现在开始设置主显示器
–auto: 同上
–pos: 设置显示器位置,因为主显示器在副显示器右边,那主显示器的起始位置就是副显示器的宽度,正常的话是1680,但经过scale之后就是3360了,y轴位置不变还是0

这个设置其实根arch wiki上的很类似,就是那里的例子是主显示器在副显示器的左边,而且没有 –pos 参数(虽然下边例子里也提到了)。没有–pos参数直接用的时候,在我这里主副显示器之间会有重合,也就是有那么一块地方在两个显示器上都显示,说明两个显示器之间的位置关系没设置对,就需要用–pos参数来指定了。

这个thread对我也有一些帮助,帮我更好的理解–pos参数,–fb参数,两个显示器之间的位置关系和那些数值怎么计算等等。到此4k显示器折腾了一天加一个晚上,算是告一段落。有好显示器了是不是要写一些好代码出来啊……

杂记mutt, GPG和邮件签名

最近由于工作需要,折腾了一阵mutt的多帐号支持和GPG key的签名,和给邮件签名。比较乱,随便记一下吧。

1. mutt的多帐号支持。
这个其实以前一直也在用,只不过是用起两个mutt实例,通过不同配置文件来区分的,比如默认的工作邮箱就直接 mutt 启动,个人的gmail邮箱就做了一个alias

alias mutt-gmail="mutt -y -F ~/.mutt/muttrc.gmail

在 ~/.mutt/muttrc.gmail 中配置好gmail的信息就可以了。

但是这次的情况不太一样,申请了一个 kernel.org 的邮箱,发往这个邮箱的邮件会转发给工作邮箱,所以我想最好能在回复的时候自动判断是发给哪个帐号的,自动用正确的帐号回复。不行的话能方便的用快捷键切换帐号也可以。搜索了一下”mutt multiple account”之类的,找到一些文章,但最后发现还是这篇文章最符合我的口味。大意就是用esc-1, esc-2快捷键,通过设置 “from=<user@domain>” 来选择帐号,同时因为用的是msmtp发送邮件,所以msmtp会自动根据这个域来判断该用哪个帐号发送邮件。同时设置不同的 status_line,来显示不同的帐号信息用来做区分。最后我的设置就是

macro generic "\e1" ":set from=account@company.com\n:set status_format=\"-%r-Company: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p?Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---\"\n" "Switch to Company account"
macro generic "\e2" ":set from=account@kernel.org\n:set status_format=\"-%r-Kernel.org: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---\"\n" "Switch to kernel.org account"

这样就方便多了,虽然kernel.org的邮箱可能会很少机会用到……

2. GPG签名
折腾这个也是为了申请kernel.org的帐号,要找一些牛来来背书。如何生成自己的公私钥对等等网上信息很多,就不说了。这里就记一下怎么把别人给你签名过的公钥里的签名和其他签名合并到一起。事情是这样的,我分别找了Dave和Eric给我签名,但他们都是下载的我在keyserver上的公钥,因为是远程认证的,所以他们分别签名&加密之后发给我,我需要把他俩的签名和之前的签名都合并到一起,然后上传到keyserver上,这样这两个新签名就增加上去了。看过了gpg的manpage之后发现其实挺简单的,就是用到一个 import-options 参数

gpg --import --import-options merge-only signature.asc
gpg --send-keys <KEYID>

3. mutt中发送签名的邮件
其实这个相对简单,正常写完邮件之后,在发送之前确认按“y”之前,先按“p”,开启 “pgp-menu”,里边会有选项和提示,是签名还是去掉签名,用哪个key签名等,签好了正常发送就可以了。

4. msmtp中发送签名的邮件
因为我有一个利用msmtp的脚本,用来在命令行下发送邮件。发普通txt邮件没什么问题,只是想给邮件签名再发送的话就得好好研究下这个邮件文件该怎么写了。

正常情况下,发送一个txt邮件,需要先写好一个邮件,包括From/To/Cc等信息,比如

$ cat >email.txt <<EOF
From: someone@somewhere
To: someoneelse@somewhere

This is a test email
EOF
$ msmtp -t <email.txt

这样在配置好msmtp的情况下,用 -t 参数告诉msmtp从stdin里读取收件人信息,直接就这么发出去了。

经过查看用mutt发给自己的带签名的邮件发现,签名信息其实就是一个附件,附在正文之后,只不过类型是”multipart/signed”和”multipart/pgp-signature”。不过仿造了几次带附件的邮件正文之后,发出去的邮件都报签名无法验证,也就是签错了……网上搜了好半天也没找到怎么把一个gpg签名附在一个邮件正文之后,最后还是去查标准吧,也就是RFC3156。里边对邮件哪部分是签名的信息,哪部分是后添加的header信息都做了说明,而且更主要的一点是,被签名的部分必须是 “CRLF” 结尾的,不能是单纯的 “LF” (也就是 \n)结尾,所以需要对正文进行一次 unix2dos 的转换……折腾了10次之后,终于发出了签名正常的邮件。

基本思路是,先把需要签名的正文写到一个临时文件里,然后用 unix2dos 转换格式,然后签名,得到签名信息。然后组装邮件头,模仿正常的签名邮件的格式就好,最后附上签名信息就可以了。把最后组装好的邮件文件写到指定的文件里。一个组装好的邮件文件的例子(里边的^M表示 \r\n,也就是需要签名的正文部分)

From: <from>
To: <to>
Subject: <subject>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
        protocol="application/pgp-signature"; boundary="x8WrEFNkdXnc"
Content-Disposition: inline


--x8WrEFNkdXnc
Content-Type: text/plain; charset=us-ascii^M
Content-Disposition: inline^M
^M
This is a test^M

--x8WrEFNkdXnc
Content-Type: application/pgp-signature; name="signature.asc"

-----BEGIN PGP SIGNATURE-----

iQIcBAABAgAGBQJYQ+hsAAoJECZSqilcj+djEUMQAJoDOM6lWX0sebjEZ/fgREAh
va/xKtYl3arD6BGrzuro2OdLrfWH0W+FM+/iNlOcGxmrECGv7QCQAD2okW+jbAes
hpeAlvGYQmS4l67y31nhY6lK5F2Uc2rzOqFOGOWiU4o/XKyueOYWJAdQzBm8hYG4
G042drLfE4Vvf81lReky9ElBoDpLzz+c7ExG2GVOs/4Ry8KabxyjtIPZelfOTNh+
8rZ+RWYHzBO9VLlImVK/z4p8+jutn9Dko6l2YkYnOcoZypChUA+/uFBLtxZe8cup
BJVrPkUaxrq+wik1abRCi97UAPw420EaiY9AjDZXZR7sy1cT9QLQ69BjOS1T4icb
RiEhoIvN4ctBxaN/Jq4mA7J2O2aYto9Kq2fRwLaNtWJwZpOmUFr8fQ9q4hcY/6K/
kiYAjp+L4A8DHXk4mhzaXJP1rJVhDITnnowel1FWirG7gPUCGe1ThGFoaqmrDF3o
PUJ6rmpcHn+sH6ppG5JjeHj3PantLIhzCA0VqQ+HxrlJ/E94G+BmrVo7Rvoj5p0v
omhSNiE7FTrvw6tKeDlyM8G59qCrsJ7ITTSL6oiHbCK8IFw938Jns/QaRnrDaFIo
C3l7zjZXrMqQQqbTeO1+LjeNntD2ggY9YmR83H3g3U5YFAfHdTtON7QUY/XtMQhG
LVKbouYC9D1r3/EULPnm
=fwZa
-----END PGP SIGNATURE-----

--x8WrEFNkdXnc--

小记socks over stunnel以及msmtp的代理错误

在之前一篇文章”OpenVPN over stunnel配合dnsmasq+dnscrypt实现最佳上网体验“,把OpenVPN流量塞到了stunnel里,但有的时候我只需要一个socks代理,不需要全局VPN,比如浏览器的代理,收发gmail的代理(见”走SOCKS代理收发gmail邮件“)等等。虽然以前用ssh tunnel就能搞定,但现在ssh tunnel已经不稳定了,经常会无响应,所以需要再找一个方法。

之前折腾stunnel的时候搜索到了3proxy这个包,是一个类似squid的代理程序,不过代理的是socks。问题在于配置用户认证等等还是挺麻烦的,尤其是已经折腾完stunnel之后,再折腾用户认证就显得不必要了,因为stunnel需要证书,也就完成了用户认证这一步(自己简单使用的情况下)。更重要的是,3proxy包中还有一个叫做“socks”的程序,用来实现一个SOCKS网关,如果能把流量导入这个网关也就完成了一个不带认证的socks代理。接下来就很自然的想到把socks放入stunnel了。

socks的使用非常简单,用下边的命令就开启了一个只监听本地地址的socks网关,需要注意的是选项和参数之间不能有空格

socks -ilocalhost -p8888 -d
# -i: internal address
# -p: port number
# -d: daemonize

在VPS上运行一下就好了。这里用 -ilocalhost 是只监听本地地址,不对外提供服务,因为本身没有用户认证功能,需要用stunnel把流量转给本地的socks。

接下来配置stunnel。在VPS上配置stunnel服务端

# cat /etc/stunnel/stunnel.conf
debug = 3

; global settings
fips = no
pid =
;compression = zlib

; performance
socket = l:TCP_NODELAY=1

cert = /path/to/stunnel.pem
CAfile = /path/to/st-client.pem
verify = 3

[socks]
accept = 8887
connect = localhost:8888

accept表示监听8887端口接受外来请求,connect表示把接收到的请求转发给本地的8888端口,也就是刚刚起来的socks网关。关于stunnel key的设置可以看我之前的文章(其实也是引用的别人的文章……)。

然后在本机配置stunnel

# cat /etc/stunnel/stunnel
; debug
;foreground = yes
debug = 3

; global settings
fips = no
;compression = zlib
pid =

; performance
socket = l:TCP_NODELAY=1

; auth
cert = /path/to/st-client.pem

[socks]
client = yes
accept = 8888
connect = your.vps.ip:8887

基本上就是多了一个client = yes,说明这是client,监听本地8888端口并转发到VPS的8887端口。

到此就在本机上起了一个socks代理,地址就是 localhost:8888。配合浏览器的代理插件等使用效果更佳:)

不过我在用msmtp代理的时候遇到了问题,邮件怎么也发不出去,一直报错 “proxy failure: unknown error”。搜索了很久也没找到原因,后来clone了msmtp的代码来看,从git log里发现了 1.6.3 版本上有一个commit来修复socks相关的bug(091b31f SOCKS5: do not clobber the status byte reported by the server.),然后看了下Fedora 23自带的msmtp版本是 1.6.2,就自己编译了最新的代码试试。结果证明,果然就是这个bug引起的问题。这个问题困扰我好久了,导致我想发邮件还得起个ssh tunnel,因为不稳定还得赶紧发,发完就关掉。今天终于把这个问题解决了!

读何兆武的《上学记》

前几天偶尔翻到了《上学记》这本小书,名字起的不那么显眼,作者(何兆武 口述)我之前也没听说过,随便翻了一点就被吸引住了,然后三天的上下班地铁上就看完了。真的是很好的一本书,读起来不费劲又能有很多启发,我给五星推荐。

发现我对同类型的书很是感兴趣,先是季羡林的《留德十年》和《牛棚杂忆》,接下来就是这本《上学记》。回来搜了一下,何兆武也是民国时期求学,后来成为历史学家,研究思想史。早年在西南联大读书,跟季羡林差不多属于同一个时期的学者。《上学记》说的是何兆武从1921年出生到1950年参加工作这一段自己读书的经历,期间写到了那个时期的学术、政治、经济、民生和战争的背景,回忆他在西南联大上学七年的生活和对当时一些知名教授和同学的回忆和评价(比如冯友兰、吴晗等)。还有时不时的穿插一些古今对比和一些自己的看法。看后很受启发,能知道不少趣闻又能对当时的社会有个更真实的认识。

何兆武出生在北京,当时叫北平,30年代虽然蒋介石北伐胜利了,但是因为日本人的关系实力范围还是退出了北方,北平由29军军阀统治。按照何兆武的说法,国民党有思想路线,有理论,要宣传三民主义,而军阀就没那么多说道了,所以那时候北平的思想控制很松,结果就是各种思潮都有,左派右派自由派,各种报刊书籍也都能看到。他在北平上中学也受了这种氛围的影响,结果就是他一生都喜欢自由的学术氛围,只有提出不同见解学术才能进步。他很提倡这种自由。相对解放后情况就有变化了。这里也要说一些,书中一旦涉及这种古今对比,尤其是今比如古的时候,何兆武就点到为止,不做过多评论,但具体是什么意思已经很明白了。

后来抗战开始,日本人统治北平,北大清华和南开就迁到昆明组成西南联大,何兆武就在39年进入西南联大学习。当时从北平到昆明和不好走,日本人占了主要交通路线,只能到天津坐船到香港然后取道越南进入云南,要历时3个月。作者说虽然当时后方条件很艰苦,但很多人还是要逃到后方,就算一路艰辛也不当亡国奴。在西南联大条件也很不好,但学生们都没什么悲观的情绪,按照书中的说法,这是因为当时普遍认为抗战最终一定能够胜利的,然后一定会是一个美好的世界。人们的生活有希望,个人发展有希望,所以也就没什么失败主义的情绪。

说到北平被日本占领的时候,还提到了高丽棒子,我这才知道高丽棒子的由来……高丽是朝鲜,这个是清楚的,但棒子就是流氓的意思,所以高丽棒子是朝鲜过来的流氓,他们在日本浪人(也就是日本的流氓)手下做流氓手下的流氓,横行霸道,瞧不起中国人。因为朝鲜早就被日本征服,早一步做了亡国奴,就瞧不起还不是亡国奴的中国人。原来高丽棒子是这么一层含义。

作者说西南联大的七年是他人生最自由最惬意的一段时光,想上什么课就上什么课,可以随意转系,完全凭自己的兴趣。还回忆了对一些知名文人的印象,比如对冯友兰和吴晗就印象不佳,可能是跟他俩建国后紧跟党走有关吧,尤其冯友兰写了很多检讨,有失文人的身份。书中提到大陆四大无耻文人,就有冯友兰,吴晗,臧克家还一个我记不得了。

书中不断提到的一点是学术自由,另外还有一个观点,就是不能死板的看待事情,当事情或者问题用常规方法无法解决的时候,就需要换一套坐标系来看,换个角度。这让我想起对数的发明简化了乘除法,还有信号的傅里叶变换,把信号从时域转换到频域来处理,这样很多事情就迎刃而解了。看后很受启发。

另外让我印象深刻的一个细节,就是“白俄”这个说法,书中说白是跟赤对应的,也就是不赞同俄国红色政权的俄罗斯人。就是我不清楚跟现在白俄罗斯这个国家是否有什么关系,是只是当时的一种叫法还是就是白俄罗斯的前身,不清楚了。看了白俄罗斯国家的简介之后觉得应该就是当时的一种叫法,跟白俄罗斯国家好像没什么关系。

下边节选一些我觉得有意思的片段:

以前人们常有一种错觉,以为国民党是跟着西方走的,其实国民党的体制是学苏联的专政模式,跟西方的民主模式完全不一样。西方政党不是革命的党,没有说某个政党有自己军队的,只能通过和平手段,通过精选取得政权,西方的领袖更不可能要求党员对他个人宣誓效忠。然而国民党自我认同是个“革命的”党,蒋介石讲话时张口闭口总是“我们革命军人”如何如何,党拥有自己的武装、自己的军队,要用物理对去政权,另行一套体制,所以它必然是个专政的党,必然有一套与之相配的意识形态统治,领袖尊严神圣不容冒犯。

想要做出成绩总得有三个方面的条件,一是天赋,这点不能强求,每个人天赋不一样,这没什么可丢脸的,二是环境,这也不是每个人都能争取到的,第三就是个人的努力,但个人的努力应该得法,不能只讲拼体力,老师延长劳动时间、增加劳动强度,那是不行的。读书也一样,书读得好坏跟你拼不拼命没关系,天天开夜车,我不认为那是一条正路。当然,一个字都不看,那成文盲了,也不行,你好好地做了就是,像吃饭一样,不吃饭不行,那饿死了,但也不是吃得越多身体越好,吃多了没有用的。

我们都恨日本人,再有就是“高丽棒子”。高丽就是朝鲜,棒子是流氓,在日本浪人的手下做事。日本浪人本来是日本流氓,那些高丽棒子就是流氓手下的流氓,他们是亡国奴,可又比你高一等,因为他们是老亡国奴,你还没亡国呢,所以在他们看来,你是更下一等的亡国奴。

常有赶大车的人从乡间来,就在小商店的门前停下来歇脚。那些是真正的下层劳动人民,你从他们的装束就能看出来。一斤们掏出两个铜板,往柜台上一放,说“掌柜的,来两口酒。”掌柜就用一个小瓷杯倒上白酒递给他,并拿出一些花生放在他前面,客人就一边吃着花生,一边喝酒,一边跟掌柜的聊天,一副很悠闲的样子。其实两个人并不相识,谈的都是山南海北的琐事,然而非常亲切,就像老朋友一样。东拉西扯地聊个十多二十分钟,说声“回见”,就上路了。这个场景一次次出现在我的记忆里,让我感觉到一种人与人之间的脉脉温情。

文革的时候更是这样,每天从清晨到夜半就是学习、劳动,而且规定得非常死,学习的内容只能是捧着小红书,好好检查自己的思想。记得有个工宣队的人管我们,发现有一个人看鲁迅的书,申斥了一顿,说:“有人竟然还看与运动无关的书?!”后来又发现另一个人看马克思,应该没问题了,可也遭到了申斥,说:“告诉你,不要好高鹜远!”

真正理解历史一定要提升到哲学的高度,不然只知道姓名、知道年代,你可以知道很多零碎的知识,但不一定就意味着你理解了历史。我想任何学位都是这样,最后总得有人做出理论的总结,否则只能停留在纯技术性的层面。……我所希望的是通过学习历史得出一个全面的、高度的认识。

我想,幸福的条件有两个,一个是你必须觉得个人前途是光明的、美好的,可是这又非常模糊,非常朦胧,并不一定是什么明确的目标。另一方面,整个社会的前景,也必须是一天比一天更加美好的,如果社会整体在腐败下去,个人是不可能真正幸福的。

有一次他(丰子恺)去上海,在火车上遇到一个上海小商人,商人问他贵姓,他说姓丰,商人问是哪个“丰”,丰子恺说:“五谷丰登的丰。”。“五谷丰登是什么?”商人不知道。丰子恺想了想,说:“咸丰皇帝的丰。”“咸丰皇帝?”商人还不知道,后来又说了好几个“丰”,他都不知道。丰子恺突然想起来了,说:“哦,是汇丰银行的丰。”于是那个小商人马上惊呼:“噢——,汇丰银行!汇丰银行!”

我当时想,诗人大概可分为四等,一般吟风弄月或别愁离恨,是低等的,即所谓rhyme(韵诗)。李白的诗天马行空、睥睨一世的气魄更高一等,而杜诗则历尽沧桑,感慨深沉,似乎又再高一等。至于那些说出了人生中不可说、不能说的恍惚迷离,乃至肠断魂销、心肝破碎的愁苦和哀怨,应该是诗中最高的境界。

人总得靠着希望活着,甚至于很小的希望,比如我想发点小财,想改善一下生活,如果没有任何一点希望可以寄托的话,人就活不下去了。二战的时候,我们真诚的相信未来会是一个光明的、美好的世界,一个自由的、民主的世界,一个繁荣富足的世界,好像对这些完全没有疑问。这种信心对全世界的人民也是一种鼓舞。不知道人们是不是太容易受骗了,二战以后,无论是国际上还是国内都让我们大失所望,没有想到会有那么多的曲折。

[翻译] 非易失性内存上的文件系统支持

原文: Supporting filesystems in persistent memory September 2, 2014

前言:在今年的CLSF会议上,一个NVDIMM的话题非常火爆,大家对这种可以把内存当硬盘用的设备都很感兴趣。同时上游内核也在做DAX相关的东西,以后RHEL7上可能也是要支持的。我就趁着热呼劲儿再多看看相关文章了。

正文:
近几年来,一直有传言说非易失性内存设备(non-volatile memory – NVM)将会改变我们使用系统的方式。这种设备能够提供大量(也许是TB级别)的非易失的、能以内存的速度进行访问的存储空间。这么大量的非易失性内存可以用来做什么现在还不是很清楚,但是NVM已经引起越来越大的关注了。可能我们会在NVM上运行传统的文件系统——但是这些文件系统需要一些修改从而让用户能够得到NVM的全部性能优势。

在NVM上加上一层块设备驱动而让NVM设备看起来像普通存储设备是很容易的事情。但是,这样做会强制所有数据和系统page cache之间进行复制。既然NVM设备是可以直接访问的,那么这些复制就是效率低下的。对性能敏感的用户会尽可能的避免使用page cache来达到NVM设备的最高速度。

事实上从2005年开始,随着ext2加入了excute-in-place(XIP)支持,内核就已经对NVM设备直接访问有一定支持了。这些代码可以把可以直接寻址的设备映射到用户空间,这样文件数据就不需要通过page cache来访问了。但是使用XIP的人很少,这些代码已经多年没有更新了,并且无法在现在的文件系统上工作。

去年,Matthew Wilcox开始着手改进XIP代码,试图把它和ext4文件系统整合在一起。在整理的过程中,他发现XIP无法和同时代的文件系统很好的结合在一起,并且代码里还有很多恼人的race condition。所以,随后他的工作从改进XIP转向了代替它。这项工作由21个patch组成,受到越来越多的关注。现在已经接近完成,可以并入主线内核了。

这些patch使用了一个叫做DAX(很显然代表“direct access”)子系统代替了XIP。在块设备层上,它用以下函数替换掉了struct block_device_operations中的direct_access()函数

    long (*direct_access)(struct block_device *dev, sector_t sector,
			  void **addr, unsigned long *pfn, long size);

这个函数接收sector号和size作为参数来说明调用者想访问多少字节的数据。如果给定的空间是可以直接访问的,那么基地址(内核地址)就通过addr返回,同时相应的页帧号(page frame number)也保存在pfn中。当从用户空间直接访问这些内存的时候,页表会使用这个页帧号。

这种使用页帧号和地址的方法可能有些奇特,内核大部分时候通过struct page来处理这一级别的内存。但这在DAX的情况下是不可行的,因为一个简单的原因:非易失性内存不是普通的内存,没有和它们相关联的页结构体(page structure)。缺少页结构体产生了很多后果,也许最重要的一个是这些NVM不能被其他设备用来做DMA访问。所以在网络设备和存储设备之间做零拷贝(zero-copy)传输,像这样的操作在NVM设备上就无法实现了。Boaz Harrosh正在写一些patch来增加NVM的page structure的支持,但这项工作还处于一个早期阶段。

再把目光移向IO栈的更上一层,NVM的支持在VFS层已经做了很多所有文件系统都能用到的工作。新建了各种通用的帮助函数(helpers)用以辅助一些常见的操作(reading, writing, truncating, memory-mapping等等)。在大部分情况下,文件系统只需要在可以使用DAX的inode中标记一个新的S_DAX标志然后在正确的地方调用帮助函数就可以了。(一点点)更多的信息可以参考patchset中的文档。这个patchset在ext4中加上了一些必要的支持。

但是Andrew Morton针对这项工作有一些疑问。最主要的问题是,为什么不直接使用一个经过修改的内存文件系统(ramfs, tmpfs)?这看上去是一个很好的问题,因为这些文件系统已经是为可以直接访问的内存设计的并且做了很多优化。但问题也在这,ram-based文件系统是为ram设计的,并不能很好的适应NVM设备。

来自Dave Chinner的信对此做了详细的解释,而且这封信很值得一读。大体上概括起来说,问题归结到以下这一点上:ram-based文件系统并没有针对数据持久性做任何设计。它们在每次启动的时候都是一个全新的文件系统,并不需要处理上一次系统运行遗留下来的东西。但在另一方面,NVM需要处理更多数据持久性相关的问题,比如在NVM上存储的数据在机器重启之后也不会丢失,并且需要在系统崩溃的时候足够健壮,在升级内核之后数据也是需要依然存在的等等。这些需求ram-based文件系统都无法满足。

所以,NVM文件系统需要所有传统文件系统所拥有的工具,用来来识别磁盘上的文件系统,做检查并处理文件系统损坏的情况。为了保证持久存储上的数据一直处于一致的状态,NVM也需要各种传统文件系统所使用的技术。例如,元数据写入的顺序必须非常仔细的处理并且用屏障来保护。因为在不同内核之间的兼容性是很重要的,所以内核中的数据结构不能直接存储在文件系统中,数据必须在host format和on-disk format之间来回转换。这些都是传统文件系统做了而ram-based文件系统没有做的事情。

然后,Dave解释道,在可扩展性方面还存在一些问题:

更进一步,NVM文件系统需要可以被扩展到非常大的存储上。在不久的将来机器上会有好几十TB的NVDIMM存储容量,所以对空闲空间的管理和对已使用空间的分配/释放的并发操作,这些都会是影响NVM文件系统性能的关键问题。所以最后你需要使用块/分配组来把空间做进一步划分。这看起来很像XFS和EXT4现在做的。

然后你需要所有的索引扩展到千万级别。至少是千万级别的,其实更可能是亿或者十亿级别。因为存储好几十TB的小文件就需要对数十亿的文件进行索引。而且因为这样做基本上没有性能上的惩罚,人们就会把文件系统当作一个大的数据库来用。所以现在你又需要有一个可扩展的并且和posix兼容的文件夹结构,可扩展的空闲空间索引,动态的、可扩展的inode分配/释放操作等等。噢,为了处理机器上的上百个cpu核还需要高并发性。

作为结论,Dave指出现在内核已经有不少满足上述需求的“非易失存储实现”了,那就是XFS和EXT4文件系统(虽然Dave一直认为ext4的可扩展性有问题)。现在这两种文件系统都能够在非易失性内存的块设备上工作。但最大的问题就是没有一种方法能够让用户直接访问数据而不需要经过page cache,这就是DAX所需要提供的功能。

现在有一些工作组在从头为NVM设计文件系统。但这些工作基本都还处于早期阶段,在内核邮件列表里还没有人发出patch来,更没有申请合并到主线内核的。所以想充分利用NVM性能的用户,在未来几年是不会从这些工作上得到什么帮助了。所以说,在目前已有的文件系统上增加NVM支持是一个真实的需求,得出这样的结论也并不是不合理的。

目前来看DAX就是通往这个目标的一条路。现在所需要做的就是尽快review这些patch并让patch达到让所有相关子系统的维护者都同意合并的状态。review工作目前进行缓慢,因为patch很复杂并且修改了很多不同的子系统。但是,作为对之前review的回应,patch已经有了很多的改进,并且看起来离最终的版本不远了。也许在不久的将来DAX功能最终就会进入主线内核。

OpenVPN over stunnel配合dnsmasq+dnscrypt实现最佳上网体验

(首先还是要唠叨几句,说一下折腾这套东西的前因后果和感受,然后再写具体部署和配置内容。)

随着墙的不断升级,以前的一些方法逐渐不稳定了。我一开始只是用ssh tunnel,这样浏览器配合autoproxy/foxyproxy/switchyomega使用简单方便。后来ssh tunnel被干扰的很不稳定了,经常无响应。而且这个方法也不能用于手机。后来结识了神器shadowsocks,在手机上很欢快的用了一段时间,但最近发现ss也不是那么稳定了,尤其是手机网络,很多时候无法连接,而且iphone上不越狱的话基本无法使用ss(只有一个浏览器样式的应用,不是全局的)。然后就折腾过各种vpn,先是OpenVPN,但也知道这东西用不长久,果然一个月不到就废掉了。也试过l2tp/ipsec等vpn,但速度很慢。最后用了ocserv+openconnect的方案,用了也一个月吧,然后又开始经常连不上,或者连上之后不长时间就无法使用了。

到此,我想得另外想办法了。一开是想的是写个私有协议,其实翻墙这东西就是把自己的数据加密传给国外的代理服务器帮忙转发,结果经过加密再传回来。但自己写毕竟麻烦,虽然已经有人这么做过了。经过搜索发现了stunnel这个好东西,就是干加密转发这件事的。然后在vps上搭了一个squid一个socks服务器,stunnel负责把收到的请求往这两个服务上转发,本地也起一个stunnel监听本地的请求然后发给远端的stunnel。手机的话就用SSLdroid来转发,其实就是手机上的stunnel。这个办法到现在还挺稳定的,就是iphone上没有stunnel类的软件,如果要用就得国内再找个服务器做转发。由此就引出了现在折腾完的这一套东西。(好长的缘由……)

这件事从十月12号开始想,然后搜了搜国内的vps提供商,没什么靠谱的。又看了看阿里云,最便宜的50一个月,对我这个简单的需求来说太贵了。最后想到用自己家里的机器吧,开个DMZ或者端口转发配合动态dns就好了。先试验了DMZ和动态DNS发现能用,就开始找机器了。一开始想用自己的台式机,但常年开机噪音大还不环保。后来想到09年做GSoC的时候折腾过的龙芯盒子,拿来折腾一番终于把龙芯盒子跑起来了。这下东西都全了,开始折腾吧!

在google的过程中想,如果能把OpenVPN流量也用stunnel转发(之前试了转发ocserv的流量,认证能开始,但认证过后就无法连接到服务器,不知道为啥)就方便很多了,手机上又可以用OpenVPN了,不用每个程序设置代理了(而且好多app还不能设置代理)。试了下发现是可行的。搜索的过程中又发现了dnsmasq, dnscrypt, chnroutes, gfwlist2dnsmasq等等各种好东西。最后就形成了现在这个最终的方案。

正文开始!

基本部署

需要国外一台VPS和国内一台机器,简单起见就分别命名remote_server和local_server吧。

基本思路就是,remote_server上运行openvpn server,只监听本地请求(localhost),运行stunnel负责把openvpn的请求转发给本地的openvpn server,同时在local_server上起一个stunnel监听openvpn的连接请求,然后转发给remote_server的stunnel,其实就是把openvpn流量封装到了stunnel里穿墙出去。

然后使用chnroutes项目里得到的国内ip段的路由表,把这些路由加入到openvpn client的配置文件里,这样国内ip不走vpn,国外ip都走vpn,加快国内网站的速度。

最后在local_server上启用dnsmasq负责openvpn的域名解析请求,这样做的好处是:一是避免dns污染,把gfwlist里的域名(通过gfwlist2dnsmasq项目)请求通过dnscrypt转发出去;二是对于国内有cdn的服务可以把地址解析到国内的cdn上,上网会快很多,否则所有dns都在国外解析,很可能返回的cdn地址在国外或者跟你在不同网络(联通/电信)。

配置过程

配置OpenVPN Server

这一步我用的是有人写好的一个脚本,openvpn-install,运行之后根据提示一步步设置就好了,很简单。只是在服务器地址那个地方需要填写local_server的地址,因为最后会自动生成客户端配置文件,但客户端直连的是local_server。然后协议选择tcp,udp不可以,因为stunnel还只能准发tcp协议。最后编辑 /etc/openvpn/server.conf,做如下修改

 - push "dhcp-option DNS xxx.xxx.xxx.xxx"
 + push "dhcp-option DNS your_local_server_address_ip"
 - keepalive 10 120
 + keepalive 30 300

第一个修改是把local_server的ip当作dns推送给client,好使用我们自己的dnsmasq服务。第二个修改是把心跳时间变长30秒一次,并且300秒无心跳才认为断开了连接,这个是因为最后要添加的国内路由表比较大,会用比较长的时间,120不够长,超时之后server会认为连接失败然后重连,其实我们只是在设置路由表……其实也可以在openvpn server端推送路由表,但这样做连接的时间就更长了。

注意这里dns地址必须是ip,如果像我这样用的是动态域名绑定ip的,那么只能写个脚本监控这个ip的变化了……我就把下边这个脚本放在remote_server里的crontab了

#!/bin/bash
if [ `id -u` -ne 0 ]; then
        echo "Need root"
        exit 1
fi

ovpn_conf_file=/etc/openvpn/server.conf
latest_ip=`dig your.localserver.ddns | grep "^your.localserver" | awk '{print $5}'`
current_ip=`grep "push.*dhcp-option" $ovpn_conf_file | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+"`

if [ "$latest_ip" != "$current_ip" ]; then
        sed -i -e "s/^push.*dhcp-option.*/push \"dhcp-option DNS $latest_ip\"/" $ovpn_conf_file
        service openvpn restart
fi
exit 0

配置stunnel

remote_server:

debug = 3
fips = no
pid =
socket = l:TCP_NODELAY=1
cert = /path/to/stunnel.pem
CAfile = /path/to/client.pem
verity = 3

[openvpn]
accept = 3333
connect = localhost:4444

基本意思就是监听3333端口,转发给本地4444端口,修改端口为你自己的配置。

local_server:

debug = 3
fips = no
pid =
socket = l:TCP_NODELAY=1
cert = /path/to/client.pem

[openvpn]
client = yes
accept = 4444
connect = remote_server_address:3333

监听本地4444端口,转发到remote_server的3333端口。

关于stunnel的配置和证书的生成,我参考的是这几篇文章
[1] 通过 stunnel 搭建安全高性能的 sockts 代理服务器
[2] 使用dante-server和stunnel搭建socks代理服务器
[3] SSL HOWTO: USING OPENSSL TO GET KEYS INTO PKCS#12 FORMAT.

配置dnsmasq和dnscrypt-proxy

这两个服务都是在local_server上配置的。我用的是debian,安装dnsmasq和dnscrypt-proxy就可以了,但fedora上好像没有dnscrypt这个包,估计要自己编译安装了。

dnsmasq的配置很简单,而且配置文件里的注释说的也很清楚(就是很多……)。其实我就用了这么两行配置

interface=eth0
no-dhcp-interface=eth0
conf-dir=/etc/dnsmasq.d/,*.conf

大意就是在eth0上启用dns服务,不需要dhcp服务,并且包含/etc/dnsmasq.d/目录下的所有conf文件。

然后git clone gfwlist2dnsmasq项目,照着文档生成一份no_ipset的conf文件,然后copy到/etc/dnsmasq.d/目录就完活了。

除了gfwlist2dnsmasq之外,还看了看dnsmasq-china-list这个项目,但自己维护的域名列表gfwlist已经有一份了,而且感觉很全,还是通过gfwlist来生成感觉更好一些。

dnscrypt-proxy的配置也简单,修改配置文件,把端口改成非53,因为53端口dnsmasq已经用了。debian上是 /etc/default/dnscrypt-proxy,如果用的是systemd,还需要修改 /lib/systemd/system/dnscrypt-proxy.socket里的端口设置,然后还需要运行 systemctl daemon-reload才能生效。其他什么配置都不需要修改。

关于dnsmasq和dnscrypt的参考文档
[1] 使用一台Raspberry Pi作为家庭网关, 无障碍翻墙
[2] 使用国外 DNS 造成国内网站访问慢的解决方法
[3] 拒绝 DNS 污染,将 DNSCrypt 部署到 Openwrt 路由器上
[4] VPS 教程系列:Dnsmasq + DNSCrypt + SNI Proxy 顺畅访问 Google 配置教程

客户端配置

我这里客户端只是安卓手机,笔记本/台式机上我不需要全局vpn,浏览器有socks代理就够用了。安卓上装了官方的OpenVPN Connect,发现导入有大量路由设置的配置文件有问题,不是嫌文件太大就是设置路由的时候崩溃。最后我安装了OpenVPN for Android这个app,很好用,推荐!

这里需要配置的就是把第一步设置openvpn server的时候生成的ovpn配置文件更新一下,加入国内不走vpn的路由设置。这里用到了chnroutes这个项目,使用很方便,照着文档生成路由信息列表,然后直接cat追加到ovpn配置文件里就好了。手机客户端上导入这个配置,连接(可能会有点慢,因为路由条目很多)。

路由设置这块儿费了好大的劲儿。一开始想从server推送路由,结果官方openvpn app不支持太多路由条目(反正1000都不支持,而这个路由表有5000+行),换成openvpn for android之后发现推送太慢。但用server推送有个好处是当路由表变化的时候更新方便,在server上再弄一个crontab任务更新就好了。鉴于国内路由信息一般变化不大,就还是在客户端手动设置吧。

另外还试了一个bestroutetb项目里的路由,据项目说是根据chnroutes优化得来的,将路由条目降到了1000+,但我发现这个路由不准确,instagram基本不能用,很多图片刷不出来。所以最后还是用了chnroutes里的路由,因为这个是从APNIC的定义转换而来的。

测试

连接vpn,过程可能会有点慢。连上之后twitter,facebook,instagram都能顺利访问了,开微博看视频也很快,因为是国内的dns解析的地址走的也是国内的路由。这下做到只在必要的时候使用vpn了。

最后说一下,其实这已经不是为了用什么被墙的服务而折腾了,其实我常用的就是twitter,设置个代理完全能用,ss大部分时间也是很好用的。现在是完全就是看墙不爽,我一定要解决这个问题才折腾的。最后照例祝老校长长命百岁!

龙芯盒子上安装debian系统

(这个可得记录一下,折腾死我了)

想在家里弄一个常年开机的服务器,运行一些用于众所周知的原因的服务。然后就想起了几年前折腾过的龙芯盒子。具体来说是福龙盒子,cpu是龙芯2f。

盒子自带的系统有两个,一个是华镭(Rays),一个是Debian。两个系统都很老了,华镭已经停止支持了,网站都打不开了……更别说从源安装软件了。debian好像还是debian 5(lenny),网上找的lenny的源里的东西都不全了,很多软件404 not found,但是还依赖它们(debian官方的源也一样)。所以无法升级无法安装软件,我需要的stunnel虽然能装上,但是运行起来报错(local socket error),我也不知道为什么。

其实盒子里还有另外一个opensuse的系统,是我六年前折腾过的,从opensuse源代码开始交叉编译出来的。试着在这个系统上从源码编译stunnel,结果系统卡在了编译的过程中,什么错也没报,就那么静静的停在那了……自己折腾的系统还是不够稳定啊。

没办法,网上继续找其他系统。先后试了fedora的mips移植版(不支持2f cpu)和debian(debian的wiki里给的kernel也不支持2f……),都以失败告终。最后终于让我找到了社区版龙芯系统的老巢,找到了一份安装说明。剩下的就简单了,照着做吧,有人给做好了系统镜像,比自己折腾debian系统方便多了。我顺便还升级了pmon。

这里可以提一句的是,anheng.com.cn我这里访问很慢,可以从中科大的镜像里下载。装系统的时候会把整个硬盘都重新格式化(我自己做的系统也就这么没了……),root默认的密码一猜就猜出来了,就是loongson。进入系统之后修改源为

deb http://ftp.cn.debian.org/debian/ stable main contrib non-free
deb-src http://ftp.cn.debian.org/debian stable main contrib non-free

升级系统之后我又换成testing了,滚动升级能好一些,怕以后一下跨大版本升级会有问题。

安装配置了下stunnel,很好用!

折腾各种vpn —— 其实这是一篇广告

最近折腾了各种vpn,一开始是OpenVPN,有人写了安装配置脚本,直接运行就好了。但OpenVPN被墙的厉害,只坚持了一个月就挂掉了。后来根据Gris Ge大神的指示又试了l2tp IPSec VPN,但是速度很慢,估计是被干扰的严重。最后搭了ocserv+openconnect/anyconnect,几经周折最后是成功了,而且速度快,推送路由方便,据大神说还坚挺,目前用着还不错。具体搭建过程不说了,网上一大堆。

广告开始:
我用的digitalocean的vps,选的新加坡机房,速度快,配置好价格便宜(相对我以前用的ramhost的vps)。以前用的是384M内存20G空间,8.9刀/月,现在是512M内存20G SSD空间,5刀/月,配置也都很简单。

我的推荐链接,注册就送10刀,够用两个月的(这是本文重点中的重点)。

最后说一句,还是shadowsocks最稳定,不过相对来说有点慢,而且iOS不越狱只能用个浏览器,不太爽。

Linux下恢复误删文件

周五篮球群里有人问误删文件了怎么恢复,得知是ext4文件系统之后我推荐了ext4magic这个工具,然后又有人提到了xfs的话怎么办,正好前几天看到Dave Chinner在邮件列表里提到了这个问题,他推荐的工具是xfs_irecover。这里就稍微总结一下Linux下误删文件如何恢复。

1. 当发现误删了文件之后,立即把文件系统卸载掉,或者remount成ro状态,就是不要再写了,让数据不要被其他数据覆盖。因为大部分文件系统在删除文件的时候只是把这个文件标记成删除,把文件所使用的数据块标记成可用,但是上边的数据还没有被清除,数据还是在的。那么这个时候不再写硬盘也就保证了数据块不会被其他数据覆盖掉,也就还有希望找回来。

2. 这一步是可选的。最好把要恢复的分区做一个镜像,dd if=/dev/sda5 of=/path/to/image/file bs=4k,这样在恢复的时候在镜像上尽兴,就算恢复出错数据被毁掉了,那也是镜像。

3. 根据不同的文件系统,选用不同的工具来找回删除的文件。ext3推荐用ext3grep,ext4用ext4magic,其实ext4magic是基于ext3grep的,而且ext4magic也能处理ext2/3文件系统;xfs用xfs_irecover,xfs_irecover的manpage在这里

4. 至于能够恢复多少数据出来,那就看人品了

这里用ext4做个例子

# create ext4 fs and copy some files there
fallocate -l 16m ext4.img
losetup -f --show ext4.img
mkfs -t ext4 /dev/loop0
mount /dev/loop0 /mnt/ext4
cp  /mnt/ext4/
sync

# delete some files
rm /mnt/ext4/*

# umount the ext4 fs, this is important!
umount /dev/loop0
# make a copy of the fs
dd if=/dev/loop0 of=ext4-copy.img bs=4k
# run ext4magic on the image
ext4magic -m -d outputdir ext4-copy.img
# some sample output from the command
eguan@localhost:~/workspace/src/kernel$ sudo /home/eguan/bin/ext4magic -m ext4.img -d testdir
Warning: Activate magic-scan or disaster-recovery function, may be some command line options ignored
"testdir"  accept for recoverdir
Filesystem in use: ext4.img

Using  internal Journal at Inode 8
Activ Time after  : Sun Jun  7 22:43:54 2015
Activ Time before : Sun Jun  7 23:02:18 2015
Inode 2 is allocated
Unknown code ext2 45 #0 for block bitmap for ext4.img
Warning: error-NR 2133571363 can not found file: /
MAGIC-1 : start lost directory search
MAGIC-2 : start lost file search
--------        testdir/MAGIC-2/image/jpeg/I_0000000012.jpg
--------        testdir/MAGIC-2/image/jpeg/I_0000000013.jpg
--------        testdir/MAGIC-2/image/jpeg/I_0000000014.jpg
MAGIC-2 : start lost in journal search
MAGIC-3 : start ext4-magic-scan search
ext4magic : EXIT_SUCCESS

更多使用方法看ext4magic的manpage吧,就在源码包里。

Fedora 22上guake的双屏幕问题

Fedora22明天应该就要GA了,周末先升级到了f22,整体感觉还不错,比较显著的更改就是由yum转到dnf,但是继续用yum也是可以的。

但每次升级Fedora,都要跟guake的双屏幕问题斗争一番。不是失去焦点回不来就是只能在一个屏幕上显示。这次又是只能在第一次启动guake的屏幕上显示,不跟随鼠标来选择屏幕,虽然在配置里已经勾选了”Appear on mouse display”。曾经一度想过换一个下拉式的terminal,试了tilda和yakuake,还有xfce4-terminal的新drop-down特性(xfce4-terminal –drop-down),但都不能满足我的需求,不是不能全屏就是不能跟随鼠标移动,xfce4-terminal的下拉特性还是实验性质的,全屏之后还会变回原来的样子。最后还是继续折腾guake吧。

经过一番debug发现,选择屏幕的函数set_final_window_rect()在切换屏幕之后根本没有调用到,当然就不能跟随鼠标了。找到函数调用者,发现原来是全屏的影响

        if not self.is_fullscreen:
            window_rect = self.set_final_window_rect()

也就是说,在全屏模式下,不会切换屏幕。这个修改是因为在全屏的时候不需要给terminal发送resize信号,这个信号会导致terminal上的内容重排,有时很烦人。一个小patch去掉全屏判断就解决这个问题了,虽然需要继续忍受resize信号,但也比不能双屏幕好。

user@dhcp-13-216:~/guake$ git diff
diff --git a/src/guake/guake_app.py b/src/guake/guake_app.py
index 9b89c33..b1c4da7 100644
--- a/src/guake/guake_app.py
+++ b/src/guake/guake_app.py
@@ -663,8 +663,7 @@ class Guake(SimpleGladeApp):
         self.hidden = False

         # setting window in all desktops
-        if not self.is_fullscreen:
-            window_rect = self.set_final_window_rect()
+        window_rect = self.set_final_window_rect()
         self.get_widget('window-root').stick()

         # add tab must be called before window.show to avoid a