这次碰到的问题是,系统当时死锁了,抓了个 vmcore 来研究,现在要看层层包含的某个结构体的一个 rw_semaphore
结构体变量的信息。当时这一层层的基本结构大体是这样的:
有两个链表,分别叫做: sets
和 set_devs
; 顾名思义,第一个 sets
是一堆 set
结构体组成的链表;第二个 set_devs
是一堆 set_dev
结构体组成的链表。两个结构体如下:
1 2 3 4 5 6 7 8 9 10 11 |
|
最终任务是要找到 set_devs
这个列表里所有 set_dev
的 lock
这个信号量成员变量的信息。
首先,打开 vmcore (确保 kernel debuginfo 都在):
1
|
|
如果要分析的结构体在内核模块中,还需要用 mod -s/-S
来加载内核模块的 debuginfo.
然后找到 sets
这个链表的入口地址。很幸运,模块里这个链表是全局的,直接找到 symbol 就可以用:
1 2 3 4 5 6 7 |
|
我们就得到了一个不为空的链表的第一个元素(从上面也可以看到是唯一的一个)。由于内核里的链表只有指针没有元素内容,我们需要用类似 container_of
的机制来从成员反查链表元素的地址:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
这样我们又得到了一个链表的 LIST_HEAD 地址:
1 2 3 4 5 |
|
得到第一个元素地址后反查 set_dev
结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
找到 rw_sem
结构体信息,这正是我们想要的。然后依次往下找即可。btw, 我忘记链表是循环链表了,所以我傻乎乎地手工查了半个小时最后才发现自己重复了……
所以问题来了,crash 里面有快捷的方法可以挨个链表元素查找么……
]]>blk_unplug()
操作,也可以由一个 unplug_timer
定时器超时触发。这整个过程听起来有点像在等机场大巴,到站停靠(plug),装载乘客(攒 request),到点发车(unplug_timeout)或者人满发车(blk_unplug)。
很容易想到,unplug_timer 这个定时器的启动会发生在 plug 阶段(见 block/blk-core.c 中的实现):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
而定时器超时函数见同一个文件下的实现:
1 2 3 4 5 6 |
|
这个函数是在 blk_queue_make_request
定义的时候设置的(见 block/blk-settings.c):
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看到除了定义了超时函数,还定义了超时的时间,是 3ms. 这个 3ms 可以用来排查一系列奇怪的 I/O 性能问题。比如说在 iodepth 为 1 的情况下,发现 IOPS 是很固定的 333,那么多半就是因为请求队列没有及时 unplug 而导致定时器超时自动 unplug 了。通过简单计算得知,因为每个队列需要 3ms 传输,那一秒钟只能传送 333 个队列,即 IOPS == 333.
如果要主动 unplug,就需要调用 blk_unplug()
函数,或者 generic_unplug_device()
函数,从通用性来说,调用前者会比较好,看如下代码(block/blk-core.c):
1 2 3 4 5 6 7 8 9 10 |
|
q->unplug_fn
一般不需要自行设置,如果没有定义,会使用默认的函数,即 generic_unplug_device()
。
看完了这几个函数,可以知道,plug 完之后及时 unplug 通常是避免 IO 延迟过高的良好手段。
]]>target_core_mod
)、前端驱动模块(vhost-scsi
, iscsi
, etc)、后端驱动模块(target_core_iblock
, target_core_file
, etc)。我想要实现某种程度的模块“热升级”,具体来说,比如target_core_mod
这个核心模块升级了之后,想要和旧模块共存,新的前端和后端驱动在接入的时候直接使用新模块。
于是想当然地认为只要把编译出来的模块改个名字就好了。然而事情并没那么简单,中间碰到两个问题,首先就是本文要讲到的,导出符号(EXPORT_SYMBOL)重复的问题。其实问题很好理解,我改了个名字之后的模块(比如:target_core_mod_new.ko
,在代码中还是会导出相同的符号,所以解决方法就是在新的模块中不导出这些符号,删掉所有的EXPORT_SYMBOL()
宏。
可是问题又来了,我的后端驱动模块(比如:target_core_iblock.ko
)需要依赖新的模块的函数,在无法导出符号的情况下,我没有办法使用后端驱动模块。稍微搜了一下,找到kallsyms_lookup_name()
函数(定义),这个函数传入一个类似 module:symbol 形式的参数,用于读取/proc/kallsyms
中的符号表,找到对应的符号,然后返回符号的地址(即函数的入口)。
于是我拿了这个函数开开心心地去改代码了。以target_complete_cmd()
这个函数为例,我在后端驱动模块的代码需要调用这个函数的地方:
1 2 |
|
把它改为这样:
1 2 3 4 5 6 7 |
|
稍微验证了一下,发现可以用了,于是开始改其他的。
结果——WTF! 一共有 40+个被引用的导出符号!一个一个改的话,这后端驱动的代码还能看么?
思来想去,觉得,该改的还是得改。决定写个宏包装一下,尽量提高一下可读性。
以下省略我反复碰壁的过程,直接上成品(some ideas was inspired by this post, thanks!):
首先,新建一个头文件,把宏和一些函数指针定义都给丢到里面,比如叫import_sym.h
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
接下来改前后端驱动的代码,还是以target_core_iblock
为例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
这样就可以了。
由于不再使用EXPORT_SYMBOL()
,做出来的前后端驱动模块会不再显式依赖target_core_mod
,必须得确保 core 模块先加载,才能让前后端驱动模块加载之后找到符号地址。卸载的时候 core 模块要最后卸载,否则会碰到空指针引发 Kernel Panic。这算是这个方案的一个不完美之处吧。
现象是机器运行到一定天数(刚开始反馈集中在 208.5 天左右)就会主动挂掉,报告文章末尾的 CallTrace,所幸社区几年前就有了解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
|
且看看我这会儿能坚持多久吧。
对了,坚持用 FeedBurner 订阅的用户,跳出来冒个泡呗…… 估计已经没有多少了吧?
]]>雷蛇八歧大蛇 2013 版鼠标,短时间内不用自动休眠,系统中蓝牙连接断(预期行为),鼠标从休眠恢复后系统中的蓝牙连接却无法自动重连,只能将鼠标置为配对模式,通过系统中的蓝牙工具手工连接。
1 2 3 4 5 |
|
通过 hcidump
工具发现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
出现 Link Key Request Negative Reply 的字样,怀疑是配对的时候使用自动 key,而蓝牙工具没有保存这个自动 key,导致鼠标从休眠恢复时试图以空 key 连接,从而失败。
知道了问题,解决方法就简单了,配对的时候手工输入 key/PIN 为 1234,连接即可。
就这么一个破问题,折腾了我半天时间,内核、bluez、bluedevil 都尝试了一遍,还在人家的 Macbook 上测试了一番。差点就冲动下单换 Mac 了。 #我不是土豪#
iOS 上配置十分简单,找到 Cisco AnyConnect 这个 App 就搞定。Linux 下要把它配置得很舒服,着实花了一番功夫。
公司 VPN 用的也是 AnyConnect,我就继续用着公司的客户端(Cisco AnyConnect Secure Mobility Client), 直到今天早上我修复了笔记本上的无线网,机器有了两个 IP 为止。有了两个 IP 的 AnyConnect service 居然 segfault 了,看了一下 debug 信息,我觉得对这种闭源工具我还是别折腾了。直接换开源方案 OpenConnect.
Portage 里搜了一下,openconnect 有两个包,networkmanager-openconnect 有 libkeyring-gnome 依赖,我现在是个有洁癖的 KDE 党,果断不能装啊,于是用第二个, openconnect 命令行版…… 不行,不能这么罗里八嗦,反正最后折腾结果如下:
/etc/conf.d/openconnect
就可以了;openconnect
flag 之后编译失败,只能回退到 5.03 版本。openconnect
命令执行后,如果从终端输入密码,需要先按一个回车,再输入一遍。所以配置文件中的 tmp_SERVER <<-E
后面需要加一个空行,否则 daemon 永远启动失败,因为接收不到密码。就这些。配好之后,既可以用 NM 的 GUI 连,也可以起服务连。从此过上了永不断网(某奸商广告语)的生活~
]]>然后今天工作的时候有同事提到客户报告鄙厂产品的问题,碰到了故障(当然在内核组大牛们的努力下该问题已经解决了),我就好奇去看了一下报告者信息,然后就发现了这个笔记软件:Wiz. 看起来还挺 Geek 的,有手机端有 Linux 端有 Mac 端。于是去 gentoo-zh 的 Overlay 找了一圈(是的,5 年过去了我还在 Gentoo 的不归路上慢慢走着),找到了。
看起来样子还不错,还比较清爽,也可以格式化为 Plain Text。功能上比 BasKet 少一些,但是用着还是挺舒服的。
最不能忍受的问题是没有任务栏图标,于是接着搜。
找到了一年前某人的一个没有 Merge 的 Pull Request,然后稍微修改了一下补丁,打到源代码里,发现可以用了。
修改后的 ebuild 请猛戳。
最后,有更靠谱的笔记软件请推荐。
]]>CPU 检测到硬件错误时,内核会报 Machine-check,根据硬件错误是否可以修正(CE, Correctable Error; UCE/UE, Un-correctable Error),内核做出不同反应。CE 的话内核只把相关信息写到一个字符设备 /dev/mcelog
中,UE 的话是会在记录相关信息之余,还会做出不同处理,比如中断当前遇错的应用程序,或者 Panic. [TODO: 这块相关的内核代码还得再看几遍]
/dev/mcelog
中的信息可以用用户空间工具 mcelog 来读取。mcelog 比较有意思的一个参数是 --dmi
,可以尝试解析 ADDR 字段以获取诸如内存出厂信息,DIMM 位置等有用的信息,可是很遗憾在实际环境中这些 DIMM 信息基本上都是错的。 (mcelog 的 man page 说了,不要怪 Linux,得怪那稀奇古怪的主板厂商……)
man page 还有一个地方提到:
The kernel prefers old messages over new. If the log buffer overflows only old ones will be kept.
查看内核代码中 arch/x86/include/asm/mce.h
,有:
1 2 3 4 5 6 7 8 9 10 |
|
这里的 MCE_LOG_LEN
就是 man page 中提到的 log buffer 长度。
内核中还有个 mce_inject
模块(CONFIG_X86_MCE_INJECT=m/y
),可以用于产生一些假的 MCE 以测试相关功能。需要配合用户空间工具 mce-inject 来使用。
如果要做一个比较完整的测试,mce-test 工具可以帮忙,其中会涉及一些 RAS 特性,比如 hwpoison(Documentation/vm/hwpoison.txt
),不过我现在的活儿不怎么管测试,暂时就没去回顾这个测试工具了。
先记这些,回头把细节都搞懂了再补充……
]]>1 2 3 4 |
|
但是如果是一系列补丁中的中间几个补丁需要修改,该怎么办呢?
笨办法已经被删掉>.<
Update 1: 非常感谢 wangcong 的指点!git rebase -i
可以出色地完成这个任务,方法在 man-page 里面有详述,见 INTERACTIVE MODE 和 SPLITTING COMMITS 部分。
假设当前所在分支名为 topic ,做了 3 个补丁,打算提交给邮件列表的时候发现中间一个补丁需要更新,此时使用下列命令:
1
|
|
出现编辑窗口如下:
1 2 3 |
|
此时需要修改 commit c3751d1
,则把 pick
改为 edit
即可。保存退出后 git 会 rebase 到需要修改的 commit 处停止,此时可以直接修改内容,然后执行:
1 2 |
|
或者
1 2 3 |
|
之后执行 git rebase --continue
即可。
突然想起来一年前就请教过 wangcong 这个问题,只不过当时对 git rebase
完全不了解,后来就忘了,惭愧 -_-|||。
Update 2: 同样感谢 Iven 的指点,可以去看看他的文章: http://www.kissuki.com/?p=135
]]>Why I want CM7.1 on my machine:
I followed most of the instructions from the post in CM forum, except that I didn't install gapps-gb-20110828. For some reason, Android Market from 20110828 package continously got crashed once I opened the application. I tried with gapps-gb-20110613 and Android Market worked as normal, so I recommend using this version of gapps if you ever encountered similar issue like me.
Well... Some extra jibber-jabbers about Android Market:
Region restriction sucks... It prevents me from buying Touchdown license from market...
I do hate some apps changing their names so frequently and deprecating the old version in market. I PAID for the old one, and I still need to pay for the new one!
]]>刚以实习生身份进入 Red Hat 时,主要工作就是验 Bug。记得当时很多 Bug 的描述都很不清晰,往往一个 Bug 就浪费一两天时间去分析。有的 Bug 还不能用脚本重现,只能物理接触硬件。有一次在机房里呆了一个下午,要用针头去戳机器上的一个小孔[1],戳了我整整一个下午。类似的折腾人的 Bug 仿佛是永远都不会消失,现在我还在跟他们打交道。
一个月后,老板让我了解一个测试套件LTP,之前是他一直在维护这个工具在内部测试平台上的正常运行,交给我之后他基本上就没再怎么管过它了(直到最近,他开始往 LTP 提交内存相关的测试代码,这是后话了)。我当时的基本工作就是定期把 LTP 的稳定发布版本移植回内部测试平台,然后如果运行出错,根据运行情况如果是 LTP 的问题,就写一些补丁来修复 LTP 运行时出现的错误。从此我才正式结束和开源项目社区浅尝辄止的试水活动,开始深入社区贡献代码。为 LTP 编写补丁对我的帮助很大,一方面跟编写补丁相关的工具,比如说 git,都熟练掌握了;另一方面通过熟悉 LTP 的测试代码,了解了很多从用户空间测试内核功能的方法;而且我也学会了怎么在邮件列表里面跟开发者吵架:)
随后的几个月里,基本上就是继续了解一些公司内部的测试工具,同时照旧维护 LTP,验 Bug,写自动化测试脚本,分析测试结果。期间出错也不少,比如 Bug 回错地方让人误解这算是小事了,把巨大的二进制包 checkin 到 CVS 仓库里面(从美国那边同步一次得十几分钟)也算是小事了。有一次是让我分析自动化测试结果,结果马马虎虎没仔细看,就认为内核通过测试了,结果内核发布给客户之后被发现了问题,回过头来一看就是我当时马虎漏掉的那段,于是被老板叫过去促膝长谈了。这也是我当时跟客户关系最接近的一次,囧- -|||。还有一次是测试一个网络有关的 Bug,结果我在远程机器上做的测试,洪水般的数据包把整个公司在所有办公室的测试环境都搞挂了……所幸的是类似的问题后来从来没犯过。
而真正理解软件测试的过程是在半年后了,那时候老板让我尝试编写一个测试项目的测试计划,当然后来因为过年回家,没做成,美国的同事接过去做了。不过慢慢开始知道测试计划、测试用例和测试脚本之间的关系了。我们整个组看起来也是一个刚形成规范的组,现在组里在用的一些测试计划都是从那时候开始遵循IEEE829写的。同时组里开始招人,依据内核子系统功能划分测试任务。恰好同时隔壁组的新版测试用例管理系统(上游版本在此)上线了,每个测试项目的成员把一些具体的测试用例都写到那上面,确实看起来更规范也更清晰了一些。
2010 年上半年准备毕业设计,老板又给了我另外一个开源社区的测试套件Crackerjack来移植,作为我毕设的内容。最后移植是成功了,只是那个开源社区几乎都没人参与了,后来我向管理员要了个 commit 权限,不过因为项目活跃度太低,而且里面很多代码都已经移植到了 LTP 中,也就抛下了。
10 年中旬结束学生身份,正式入职,我的工作重心继续在内核测试工具这一块,有之前一年的积累,我敢说我是全组对测试工具第二了解的人了。同时领到了新的任务,带实习生(美其名曰:Intern Tech Lead),简而言之,就是实习生在测试时碰到问题就来找我,其中有很多问题肯定是跟测试工具相关的(吐槽:我还真是适合干这个活啊>.<)。既然继续做测试工具,我又领到一些测试工具相关的活,这些工具大多是 Python 写的,于是我又被迫无师自通地学会了 Python。在此期间我深深感受到一件事情,碰到问题,看代码是最有效的 debug 方式。当然我不推荐碰到内核问题直接去看内核代码,那对不了解的人来说是一个黑洞,一陷进去就会浪费掉好久的时间。
10 年下半年有个重要事件,RHEL6 发布了,刚好在我生日前后。公司搞了个庆祝活动,其实也就把自助餐厅搬到了公司里面而已,可能后续还有抽奖什么的,我反正没参加=.= 老大让每个组的负责人都上去讲讲心得,我老板上去之后把组里每个人感谢了一遍,说到我的时候我才发现原来我是个打杂的……因为在 RHEL6 发布前,我把组里每个人的活,除了存储测试之外,都干了一遍。kdump测试人手不足的时候,我上去顶了一个星期的班;DUP需要交接工作的时候,我就作为过渡人员测试一段时间;v7没人测的时候,我就承担了测试任务……当时就觉得挺忙的,不过多打打杂,开阔开阔眼界,也是挺开心的事情。得感谢老板让我多方面了解内核测试的内容。
11 年初,老板开始突然向 LTP 提交了很多内存测试的代码,代码被上游接受后,他把内存管理的测试连同测试计划,测试用例都丢给了我,于是我的任务又增加了一个。不过终于有机会开始直接接触内核核心组件了,心里很兴奋。可惜老板留下的代码带着一身 BUG,我花了平均每个月 20 个补丁的代价才把它们修得差不多,而且现在还在继续修。
从去年校园招聘前后开始,我就参与了一系列面试。现在组里有几个人就是我当时面试定下来的。自己主要面试的是应聘实习或者校园招聘的学生,因为自己也刚从学生过来,所以比较能理解面试者的心态。学生面试的时候一般会关心测试职位有没有技术含量,自己能不能学到东西。我总是喜欢拿自己在 Red Hat 之前一年的经历,特别是自己打杂的经历跟他们讲。我面试时也带着一些倾向性,那些偏 Geek 的,给开源社区做过贡献的,阅读过内核代码的,我就比较喜欢。不过根本一些的层次,我还是喜欢学习能力、理解能力、沟通能力强的。
有了之前一年半的测试经验积累,我对测试本身的流程也比较了解了,于是现在开始参加一些更偏向于组内的测试过程控制的事情。这才理解到,所谓 QA,不仅仅是写几个测试计划,验几个 bug 就完事的。测试周期开始前,要保证测试计划的完整;测试开始后,要定期保证测试进度;测试中发现新的 Bug,要根据严重程度及时跟进 DEV/PM 那边的状态……刚开始干这活,完全没有经验,所以一个测试周期快结束的时候,笔记本里就满是总结经验教训。而在项目进度接近尾声的时候,往往是加班的疯狂时期。我当时既承担内存测试任务,跟踪组内的测试进度,还负责了 v7 那个项目的测试管理。虽说后两项不用我自己一件一件去做,但是碰到人手交接什么的活时,经验不足的我为了保证进度,只有自己上阵了,因此加班是不可避免的。在 v7 发布进入尾声的时候,碰到了几个严重的 bug,于是我半夜跟美国那边的开发者同步跟踪进度。他一出修复版本,我就马上测试,甚至他来不及修复的时候,我就自己动手修了>.< 最后总算是把产品发布出去了,也因此搞得身心俱疲。
然后就是最近的一两个月,一边带实习生,一边准备新项目的计划阶段。最近组里的同志们似乎又被测试工具相关的问题缠住了,于是相应的,我又有点事情要忙了,~o(>_<)o~
付出的代价大,积累的经验教训多,收获就多,这东西跟玩仙剑是类似的。就算不给我涨工资,我也觉得这两年学到的东西很值得。当然是否值得是要看有没有建立在时常总结分析经验教训的基础上的。除此之外我觉得还有一些值得分享的东西:
0. 开有效率的会很有用。开会是相互沟通的重要方式,组会之前做好充分准备,尽量减少无用的讨论时间,可以提高效率。开一对一的会议对了解组员的进度和想法有很大帮助。碰到问题用邮件解释不清的时候,最好的解决方案之一就是和同事约个时间开个会。
1. 发散学习会让自己学到的东西更多。做项目不仅仅是做项目,通过项目来了解一些属于自己职责之外的东西,比如趁机会了解一些内核代码,这样会让自己进步更快。但是不能影响自己项目的进度。
2. As usual, to Be Filled... :D
]]>首先得先介绍一下我所在的公司的背景,因为不同公司对待简历有不同的风格。好多人都知道,我现在呆在 Red Hat,就是那个跟某快递公司重名的做 Linux 的公司。至少我们研发部门这边,不会因为简历没写称呼没写落款就不看,也不会因为简历排版混乱就丢在一旁,甚至发现提交的是个 Word 文档,或者联系邮箱留了个带 qq 号码的 qq 邮箱也会认真的去看——只不过第一印象和心理上已经有些想法而已。一般来说,我们喜欢排版简洁的正文简历和 pdf 简历,如果能提交个 odt 格式的也能感觉出投简历的人确实是用心的。另外不是为了装 X,我们要求中英文简历是因为,如果面试结果良好,通常把简历会转交给国外的同事看,决定是否进一步面试。
小结一下,不管简历样式有多糟糕,只要能打开,我们就会认真看。当然非常不幸地,这也是我觉得某些提交简历的同学是折翼的天使的原因。
然后是简历的内容。有些简历——真是太折翼了!一看就知道是海投用的“一简历走天下”的那种。某种程度上智联招聘起了为虎作伥的作用,可恨的是我们还不得不用智联……这些简历,“求职目标”一栏把能想到的 IT 职位估计都填遍了,互联网,软件,硬件,开发,测试,通信,嵌入式神马的都写着;然后在项目经历里面大书特书 Oracle 数据库、JavaSE/JavaEE 框架、C#,更发指的是写着有很丰富的 Windows 下某过气的图形界面库编程经验;而掌握技能里面,要么就是只写会 Java,要么就是把听说过的所有语言,从 HTML 到.Net 都写上……我能体会作为一个学生投简历时广撒网捕大鱼的心理和写简历时生怕简历单薄的心情,但是最起码投简历之前也要对应聘职位做一些分析吧,对方是"Linux""内核""测试"职位,三个关键字,至少在简历里要提到一项相关的吧……
针对简历内容,我个人有一些建议,觉得不对的就直接忽略吧。首先是求职目标,对方招什么职位,求职目标一栏就改成什么职位,或者这个职位的大类,别太大,更别写得明显不对口。其次作为学生,项目经历可能不多,那么就在教育经历和掌握技能上稍微补充一些:教育经历一栏可以把跟应聘职位相关的课程列出来,或者把所有重要课程列出来,职位相关的课程加粗醒目表示。这样面试的时候一般都会根据上过的课程问一下相关的理论知识;另外掌握技能这一栏,就要对职位描述作更细致的审察,对方要求什么技能,就写什么技能,哪怕是职位描述上写着“对 XXX 技术有热情,有自主学习能力”,也可以在技能一栏写上对应的话(自学能力不也是一种技能么)。而项目经历一栏,就别填发过传单搭过 Windows 服务器的事情了,宁愿你写一些学校学院布置过的大作业和实训。如果有 Linux 实验和大作业,完全是可以写到项目经历里面的,只要你曾做过。另外每个项目最好能多写几句,一是强调自己个人在项目中的职责,二是技术要点,三可以是项目的难点和解决方案,四可以是自己负责的部分的结果。当然写每点都要有概括成一行文字的能力,长篇大论也是不讨喜的。再小结一下,简历内容一定要有针对性,让人看得出你是用心投这个职位的;技能、知识、经历都与职位要求相关最好,无关的不写或尽量一笔带过。
接下来是一些细节的问题,想到什么说什么。比如说错别字要避免,专业词汇不要拼错;中英文简历排版最好统一,内容保持对应;描述不要夸张,特别是对于技能掌握程度的描述,避免用“精通”一词,因为还有“熟悉”“掌握”“了解”等表示程度的词语;态度要诚恳,用心写的话看的人能看出其中的态度是否诚恳。其他的暂时想不起来了,待补充。
最后是针对我个人,或者说我和我周围这群体的人觉得能加分的细节:简历中带一个技术博客或者开源项目的链接;简历后附带一段自己写的 C/Shell/Python/Perl 代码;用 LaTeX 写简历;有 RHCE 的证书。其他的又想不起来了,待补充。
不知道订阅我博客的五六百人都是什么群体,居然能忍受我半年不更新博客……要是是学生居多,希望上面的闲言碎语有一些能对你有帮助。当然希望能给我投简历,如果你是一个 Linux 和开源软件的爱好者。过一段时间如果我面试面得郁闷了,可能会发一个关于面试的碎碎念。
]]>Besides the RHBZ mentioned above, you should be able to get more information from this message in fprint mailing list.
I updated my gentoo overlay in github, too. You can emerge libfprint and fprintd after you synchronized this overlay.
]]>Before starting, here're some useful links may help those who are suffering from similar fingerprint issues like me:
If you're using a fingerprint with USB id "147e:2016", you can have a look at this thinkwiki link, The "147e:2016" item is updated recently: a Red Hat Bugzilla URL added.
This RHBZ link tried to enable TCRD4C devices, but seemed that my fingerprint was another different type since it still did not work after applied all the patches attached.
------>8------ Cutting, Let's enable T410 fingerprint ------>8------
Using Fingerprint-GUI and UPEK SDK can easily enable fingerprint reader in T410. Fingerprint-GUI provides an integration of setup GUI, authentication plugin, PAM module and the UPEK library, all of the GUI parts are written with QT4 (I don't like it :-\), released under GPL-v3 licence. However, UPEK SDK library is EULA copyrighted and seems never to release the code to us.
Notice that you still need have libfprint installed, what's more, a version >= 1.0_pre is necessary, according to the manual of Fingerprint.
Since A PAM module is integrated in Fingerprint-GUI so that your fingerprint driver can work in GDM, sudo, gnome-screensave, etc, you must remove other fingerprint PAM modules like pam_fprint or pam_thinkfinger.
For Gentoo users, I have finished two ebuilds for this application. You can find them in my github repo, fprint is also included in the repo.
I'm not good at writing ebuilds, any suggestions are welcomed.
P.S. Is there anybody know how to assert the existence of a kernel module in a ebuild? I need to judge whether `uinput.ko' exists or not among current kernel modules. Thanks.
]]>这次没有纠结于选择哪个桌面环境上,我一点也不嫌弃 GNOME 的臃肿,于是装了个 gnome-light。USE Flag 把以前用过的拿过来修改了一下,顺便提一句,在我不用 Gentoo 的这段时间听说 hal 被干掉了,所以我也追风把 hal 标记给去掉了。
启动的时候使用 grub2,本来打了 915resolution 补丁来使 grub 宽屏显示,但是打的补丁和 grub-1.98 似乎不是特别搭配,导致启动 grub 前后各有 5 秒停滞时间,加上 grub 启动过后仍然会有一个分辨率只有 640x480 的屏幕,我干脆就不用 915resolution 补丁了。使用 grub2,配上 ext4 分区,就可以不使用 initramfs 了,关键在两点,一是内核中 ACHI 选项要编译进内核,二是 kernel 行参数中不要使用 UUID。
说一下一些 Thinkpad 相关的配置:
一是声卡驱动。Thinkpad T410 的声卡应该是 CONEXANT 的,但是选择这个驱动后内核还是不认我的声卡。最后只好选择了通用驱动。
二是 hdaps,所谓的硬盘防震保护系统。portage 里面相关的三个包,一个是 hdaps 模块,一个是 GNOME 的 Applet,还有一个是 OpenGL 绘制的小程序,用来展示你的笔记本目前的水平状态。
三是 Thinkpad 相关的快捷键。目前键盘上展示的快捷键基本上都能用,除了 Fn+F6 的“摄像头、耳机”、Fn+F8 的“触摸板、小红点切换”还有麦克风静音三个按钮不能工作。根据 Thinkwiki 的这里说,Fn+F8 可以通过 thinkpad-acpi 或者 tps 使之工作,其他两个目前还没办法。不过我连 Fn+F8 都没搞定,只是自己写了个脚本,用来切换触摸板的开关(用小红点的时候肯定很讨厌触摸板开着):
#!/bin/bash
status=`synclient -l | grep TouchpadOff | awk '{print $3}'`
if [ $status -eq 0 ]
then
synclient TouchpadOff=1
notify-send "Touchpad is disabled!"
elif [ $status -eq 1 ]
then
synclient TouchpadOff=0
notify-send "Touchpad is enabled"
fi
把它保存为脚本,加上 x 权限,通过 GNOME 的键盘快捷键来控制,比如 Win+Space。
另外我给蓝牙设置了一个快捷键。笔记本上那个蓝色的 ThinkVantage 按钮没用到,就把它绑定了一个 ACPI 事件,设置为给蓝牙控制开关。事件代码如下:
event=ibm/hotkey HKEY 00000080 00001018
action=/home/caspar/.local/bin/bluetooth.sh
上述代码保存为 ACPI 事件文件,如/etc/acpi/events/bluetooth。快捷键对应的 KEY CODE 可以到 Thinkwiki 上面去找,也可以看内核的:Documentation/laptop/thinkpad-acpi.txt 文档。至于用于控制的 bluetooth.sh 脚本,则如下(代码来源仍旧是 ThinkWiki,看这里):
#!/bin/bash
NAME="tpacpi_bluetooth_sw"
find_by_name() {
NAME="$1"
test -z "${NAME}" && return 1
SYSFS_NAME=$(find -P /sys -name name -path "*/rfkill/*" -exec grep -l "${NAME}" \{\} + | head -n 1)
if [[ ! -z "${SYSFS_NAME}" && -r "${SYSFS_NAME/%name/state}" ]]; then
RESULT=${SYSFS_NAME%%/name}
echo $RESULT
return 0
fi
return 1
}
SYSFS="$(find_by_name "${NAME}")"
if [[ ! -z "${SYSFS}" && -r "${SYSFS}/state" ]]; then
case "$(cat "${SYSFS}/state")" in
0)
echo 1 > "${SYSFS}/state"
;;
1)
echo 0 > "${SYSFS}/state"
;;
esac
fi
重启 ACPI 服务就可以看到蓝牙可以被 ThinkVantage 按钮控制了。
目前还不能工作的设备有:指纹识别器,从 lshw 中看到似乎还有 HECI 控制器(Intel 似乎不想管这个咚咚了?)、温度检测设备(Thermal Subsystem)和一个 Ricoh 的外围设备。
最后向使用 Thinkpad 的同学严重推荐ThinkWiki。
P.S. 设置充电阈值:据说如果电池不怎么经常使用的话,充电不充满有利于延长电池寿命(Win7 下的配套软件是这么说的),所以可以设置一个充电阈值,把下面命令放到/etc/conf.d/local.start 去:
echo 95 > /sys/devices/platform/smapi/BAT0/stop_charge_thresh
]]>简要介绍一下这个模板。
缘起是@yegle 曾经推荐过他的同学梵高(cnMuggle)的一个北邮本科毕业论文模板,我看了一下觉得不太符合我的需求,最主要是他用了 CTeX,这玩意儿在我的机子上水土不服。作为一个 Linux+XeTeX+xeCJK 党,我就自己动手开始写。
期间参考了梵高同学的模板,当然也参考了@gnawux(apt)同学的,还有 DazzleZhang 在 apt 的基础上改进的,还有老牌的ThuThesis。当然最主要还是依靠 Google 和 CTeX 论坛,把一些稀奇古怪的问题给解决了。
今天又解决了几个大问题,同时也把插入图片、插入表格、插入公式的格式整理了一下,所以就发布 Alpha-1 版本了。地址在Google Code上。接下来要完成的主要工作就是参考文献的排版。我一看其他模板的 bst 文件,几千行的代码,吓坏了。下次再搞好了。
欢迎提 Bug~
]]>具体的问题抽象出来就是这么一种情况:
有一堆分层的目录,里面全是系统调用的相关测试代码+Makefile,结构大致如下:
├── wait4
│ ├── Makefile
│ ├── wait401.c
│ └── wait402.c
├── waitid
│ ├── waitid01
│ │ ├── Makefile
│ │ └── waitid01.c
│ ├── waitid02
│ │ ├── Makefile
│ │ └── waitid02.c
├── waitpid
│ │ ├── Makefile
│ │ └── waitpid_err_test.c
.....
现在要把这堆系统调用的测试代码移植到各硬件平台和各发行版上,因此要考虑内核版本、glibc 版本等等问题。比如说 getcpu 这个东东只在 2.6.19 及以后版本中存在并且只有 x86_64 and i386 架构才可用。而编译这堆系统调用使用的 Makefile 大致如下:
MAKEFILES_FOR_TESTCASES = $(shell find testcases -name Makefile)
TESTCASES_BY_MAKE = $(addsuffix /test,$(dir $(MAKEFILES_FOR_TESTCASES)))
$(TESTCASES_BY_MAKE):
$(MAKE) -C $(dir $@) test
因此可能的解决方案有如下几种:
FILTER_OUT_CASES = testcase1 testcase2 testcase3
ALL_MAKEFILES = $(shell find testcases -name Makefile)
FILTER_OUT_MAKEFILES = $(wildcard $(foreach filename,$(FILTER_OUT_CASES),testcases/$(filename)/Makefile))
MAKEFILES_FOR_TESTCASES = $(filter-out $(FILTER_OUT_MAKEFILES),$(ALL_MAKEFILES))
TESTCASES_BY_MAKE = $(addsuffix /test,$(dir $(MAKEFILES_FOR_TESTCASES)))
$(TESTCASES_BY_MAKE):
$(MAKE) -C $(dir $@) test
代码很平淡无奇,之所以贴出这段代码是为了温习一下 Makefile 中 wildcard,filter-out 和 foreach 的用法 :-)
这种办法在ltp上应用十分广泛,ltp 中自动从 configure 文件中生成 include/config.h,生成的 config.h 包含了一系列预处理,例如:
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_SIGNALFD_H
/* Define to 1 if you have the
#define HAVE_SYS_STAT_H 1
当内核版本不同导致系统调用不存在时,可以设置 undef 预处理;如果系统调用存在,则 define 一下。
接下去可以修改源代码,在可能会在不同内核版本上出现分歧的代码前后加上:
#ifdef HAVE_SYS_SIGNALFD_H
...
#else
int main()
{
printf("syscall not exists in this platform\");
return 1;
}
#endif
同时 ltp 还在 C 代码中判断内核版本,内核版本在
如果不使用 configure 文件,可以自己写一个 shell 脚本来生成,例如:
#!/bin/sh
CONFIG_PATH=./include/config.h
KVER=`uname -r | cut -d'-' -f 1`
KMAJVER=`echo $KVER | cut -d'.' -f 1-2`
KMINVER=`echo $KVER | cut -d'.' -f 3`
if [ "$KMAJVER" = "2.6" ] && [ $KMINVER -ge 19 ];
then
echo '#define HAVE_SYS_EPOLL_H 1' >> $CONFIG_PATH
else
echo '#ifdef HAVE_SYS_EPOLL_H' >> $CONFIG_PATH
echo '# undef HAVE_SYS_EPOLL_H' >> $CONFIG_PATH
echo '#endif' >> $CONFIG_PATH
fi
个人博客(BSP/独立的至少得有一个吧),
twitter(以及其他各种围脖们),
豆瓣,
facebook,
Google Reader(或者其他 rss 订阅工具),
feedburner/feedsky,
flickr 相册(或者 picasaweb,或者国内的 oo 和 xx),
lastfm,
youtube 订阅,
friendfeed,
……
在这个信息膨胀的社会,如何获取信息是个头疼的问题。下面列一下自己是如何把这些信息来源整合起来的,以供参考:
整合所有信息的核心就是 feed/rss,所以首先要把博客搞一个托管,或者干脆直接用自带的 feed(前者的好处是,换了博客可以不用通知别人修改你的 rss 地址)。我主要采用 feedburner,在 wordpress 里用了feedred这个插件,把自带的 feed 重定向到了 feedburner 上。因为很久很久以前 feedburner 被墙了,所以 feedsky 也用过。
然后就是 Twitter,作为一个重度 Twitter 患者,巴不得把自己博客更新、Google Reader 分享、豆瓣新鲜事、新拍的照片等一堆东西同步到 Twitter 上。这里有两种解决方案:
1. 使用TwitterFeed.com
2. 使用 FeedBurner。
前者自己摸索就好了,我更推荐后者,因为自己有种感觉 FeedBurner 同步速度很快,莫非它采用了每分钟轮询的策略?Orz……在 FeedBurner 管理界面的"Publicize"中有个"Socialize",里面可以设置把当前 feed 同步到 Twitter 上。
因此只要你的信息源有 feed,就可以同步到 Twitter 上。
接下来是 facebook、校内这类社交网站,把 twitter 同步到 facebook/校内上。
校内的话,狗狗写过一个脚本,请自行取用。facebook 的话,也有两种方式:
1. 使用 friendfeed(已被 facebook 收购鸟),
2.使用 facebook app
后者据lpf同学反映,密码老是不对。我自己是很早很早以前设置的,忘了。建议有问题的同学使用第一种方案。friendfeed 因为被 facebook 收购了,也就更好地集成在了 facebook 中(不好意思我忘了怎么集成了,自己摸索一下吧>_<)。需要注意的是 friendfeed 除了可以从 twitter 同步,还可以从其他源同步,这些源可能会和你之前设定的 Twitter 集成重复。
其他的,比如同步到新浪围脖,请自行查阅。
还有什么需要补充,欢迎留言。
]]>需求如下,非常简单:
1. 要在合适的位置打上 Logo(一般是左上角或者右上角);
2. 要能自定义页脚
3. 首页要有背景
经过半个白天加一个晚上的折腾,基本上解决了上述问题:
要打 Logo,并且自定义位置,可以使用如下语句:
\logo{\pgfputat{\pgfxy(#1,#2)}{\pgfbox[center,base]{\includegraphics[height=0.5cm]{#3}}}}
事先要包含 pgf 宏包,#1,#2 是 Logo 坐标,#3 是 Logo 路径。关于坐标,我发现用 pdflatex 编译和用 xelatex 编译时坐标表示的实际位置是不同的,反正自己手工慢慢调就是了。也可以把上述代码加个\newcommand,做成一个带参数的命令直接调用。
自定义页脚,我参考了 beamer guide 和 beamer 里面的某个宏包的写法:
%% Custom footer
\usefoottemplate{
\hbox{\tinycolouredline{structure}{
\begin{beamercolorbox}[wd=0.22\paperwidth,ht=2.4ex,dp=1.2ex,left]{author in head/foot}%
\usebeamerfont{author in head/foot}\insertshortauthor
\end{beamercolorbox}%
\begin{beamercolorbox}[wd=0.5\paperwidth,ht=2.4ex,dp=1.2ex,center]{title in head/foot}%
\usebeamerfont{title in head/foot}\insertshorttitle
\end{beamercolorbox}%
\begin{beamercolorbox}[wd=0.28\paperwidth,ht=2.4ex,dp=1.2ex,right]{date in head/foot}%
\usebeamerfont{date in head/foot}\insertshortdate{}\hspace*{0.8em}
\insertframenumber{} / \inserttotalframenumber\hspace*{4.5ex}
\end{beamercolorbox}}}%
}
需要说明的是,我始终搞不懂\tinycolouredline 的第一个参数 structure 还能用什么代替,而且上述方案有个及其大的 BUG,在页脚最左边的那列的左边有 1em 的空白,如果要给这列填充了和那个空白区与不一样的背景色,就会很难看。我也没找到消除那列空白的代码。
首页加背景就太简单了,我直接用 wallpaper 宏包,然后在第一页加入:
\ThisCenterWallPaper{1}{inc/cover}
不管是加 Logo 也好,加墙纸也好,它们都很容易被 colortheme 中定义的背景色覆盖,这可以通过\setbeamercolor 来去掉背景色,基本语法如下:
\setbeamercolor{background canvas}{bg=}
\setbeamercolor{title}{fg=black, bg=lightgray!80!white}
最后放出模板,点此下载>>>>
]]>