N多LUN(iscsi盘)需要分区,手动太痛苦了。只能找non-interaction型的分区工具, 比如parted这个程序。
在分区之前有一个概念需要先明白的:partition table, 也叫disklabel
之所以使用parted才需要注意到partition table, 是因为我们常常使用的fdisk已经帮我们选择了msdos类型的partition table。所以从fdisk转到parted后,会有点小疑问。
平时我们印象中:一个硬盘只能有4个主分区,或者3个主分区1个扩展分区。
这其实只是`msdos` partition table的限制。GPT就没有这种问题:http://en.wikipedia.org/wiki/GUID_Partition_Table
msdos partition table这个名词是从parted程序引用的:
[liangqingxi@hotspare ~]$ sudo /sbin/parted /dev/sdc print
Error: Unable to open /dev/sdc - unrecognised disk label.
[jessinio@niowork ~]$ sudo parted /dev/sda print
[sudo] password for jessinio:
Model: ATA ST3250310AS (scsi)
Disk /dev/sda: 250GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
但是从wikipedia里查的信息表明, 这与BIOS被广泛使用有着很大的关系(比如,BIOS的引导过程)
感觉上, 称为`PC compatibles`更好一点:
信息1. In the world of IBM PC compatibles, disks are usually partitioned using the PC BIOS's MBR Partition Table scheme instead
信息2. The role of the BIOS has changed over time; today BIOS is a legacy system, superseded by the more complex EFI (EFI), but BIOS remains in widespread use, and EFI booting has only been supported in Microsoft OS products supporting GPT and Linux Kernels 2.6.1 and greater builds
当硬盘没有、或者程序无法认别partition table时会有如下信息:
[liangqingxi@hotspare ~]$ sudo /sbin/fdisk -l /dev/sdc
Disk /dev/sdc: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk /dev/sdc doesn't contain a valid partition table
在fdisk的手册中有这样的记载:fdisk doesn’t understand GUID Partition Table (GPT)
在知道partition table这一概念后, 使用parted命令将是非常容易的. 就不记录了.
Friday, January 28, 2011
gpg使用
I. 基本概念
1. key、public key、private key
文档: http://en.wikipedia.org/wiki/Public-key_cryptography
gpg使用--gen-key 命令生成的key种类有:
(1) DSA and Elgamal (default)
(2) DSA (sign only)
(5) RSA (sign only)
DSA and Elgamal支持加密和签名
单独的DSA、RSA只支持签名
2. 加密与签名
关于签名与加密这两个概念需要明白:
Use of these keys allows protection of the authenticity of a message by creating a digital signature of a message using the private key, which can be verified using the public key. It also allows protection of the confidentiality and integrity of a message, by public key encryption, encrypting the message using the public key, which can only be decrypted using the private key.
private key 加密, public key解密,称为签名
public key 加密, private key解密, 称为加密
II. key管理
1. 查看
分为public key的查看和private key的查看:
[jessinio@niowork ~]$ gpg --list-keys
/home/jessinio/.gnupg/pubring.gpg
---------------------------------
pub 1024D/140A3126 2011-01-26
uid jessinio.liang (liang qingxi)
sub 2048g/94134411 2011-01-26
[jessinio@niowork ~]$ gpg --list-secret-keys
/home/jessinio/.gnupg/secring.gpg
---------------------------------
sec 1024D/140A3126 2011-01-26
uid jessinio.liang (liang qingxi)
ssb 2048g/94134411 2011-01-26
2. 导出/导入/删除
也分为private key和public key:
[jessinio@niowork ~]$ gpg --armor --export 140A3126
[jessinio@niowork ~]$ gpg --armor --export-secret-key 140A3126
同理,删除是使用--delete-key和--delete-secret-key子命令完成。
II. key使用
1. 签名
使用jessinio@gmail.com的private key签名
$ gpg --output doc.sig --sign doc
用户jessinio测试数据:
[jessinio@niowork ~]$ gpg --verify doc.gpg
gpg: Signature made Fri 28 Jan 2011 02:31:06 PM CST using DSA key ID 140A3126
gpg: Good signature from "jessinio.liang (liang qingxi)"
用户jessinio解开签名数据:
[jessinio@niowork ~]$ gpg --output doc --decrypt doc.gpg
1.1 detach sign
签名后的数据在没有解开的情况下是无法使用的, 所以有时为了方便数据的查看, 会把签名与数据分开, 这种叫detach sign
2. 加密/解密
使用jessinio@gmail.com的public key加密
$ gpg --output doc.gpg --encrypt --recipient jessinio@gmail.com doc
解密与解开签名了的数据是一样行为。
3. 对称加密
[jessinio@niowork tmp]$ gpg --output 11 -c testfile.tar.gz
[jessinio@niowork tmp]$ file 11
11: DOS executable (COM)
[jessinio@niowork tmp]$ diff testfile.tar.gz 11
Binary files testfile.tar.gz and 11 differ
[jessinio@niowork tmp]$ gpg --output 11.tar.gz -d 11
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
[jessinio@niowork tmp]$ diff 11.tar.gz testfile.tar.gz
[jessinio@niowork tmp]$
gpg的完整使用手册: http://www.gnupg.org/gph/en/manual.html
1. key、public key、private key
文档: http://en.wikipedia.org/wiki/Public-key_cryptography
gpg使用--gen-key 命令生成的key种类有:
(1) DSA and Elgamal (default)
(2) DSA (sign only)
(5) RSA (sign only)
DSA and Elgamal支持加密和签名
单独的DSA、RSA只支持签名
2. 加密与签名
关于签名与加密这两个概念需要明白:
Use of these keys allows protection of the authenticity of a message by creating a digital signature of a message using the private key, which can be verified using the public key. It also allows protection of the confidentiality and integrity of a message, by public key encryption, encrypting the message using the public key, which can only be decrypted using the private key.
private key 加密, public key解密,称为签名
public key 加密, private key解密, 称为加密
II. key管理
1. 查看
分为public key的查看和private key的查看:
[jessinio@niowork ~]$ gpg --list-keys
/home/jessinio/.gnupg/pubring.gpg
---------------------------------
pub 1024D/140A3126 2011-01-26
uid jessinio.liang (liang qingxi)
sub 2048g/94134411 2011-01-26
[jessinio@niowork ~]$ gpg --list-secret-keys
/home/jessinio/.gnupg/secring.gpg
---------------------------------
sec 1024D/140A3126 2011-01-26
uid jessinio.liang (liang qingxi)
ssb 2048g/94134411 2011-01-26
2. 导出/导入/删除
也分为private key和public key:
[jessinio@niowork ~]$ gpg --armor --export 140A3126
[jessinio@niowork ~]$ gpg --armor --export-secret-key 140A3126
同理,删除是使用--delete-key和--delete-secret-key子命令完成。
II. key使用
1. 签名
使用jessinio@gmail.com的private key签名
$ gpg --output doc.sig --sign doc
用户jessinio测试数据:
[jessinio@niowork ~]$ gpg --verify doc.gpg
gpg: Signature made Fri 28 Jan 2011 02:31:06 PM CST using DSA key ID 140A3126
gpg: Good signature from "jessinio.liang (liang qingxi)
用户jessinio解开签名数据:
[jessinio@niowork ~]$ gpg --output doc --decrypt doc.gpg
1.1 detach sign
签名后的数据在没有解开的情况下是无法使用的, 所以有时为了方便数据的查看, 会把签名与数据分开, 这种叫detach sign
2. 加密/解密
使用jessinio@gmail.com的public key加密
$ gpg --output doc.gpg --encrypt --recipient jessinio@gmail.com doc
解密与解开签名了的数据是一样行为。
3. 对称加密
[jessinio@niowork tmp]$ gpg --output 11 -c testfile.tar.gz
[jessinio@niowork tmp]$ file 11
11: DOS executable (COM)
[jessinio@niowork tmp]$ diff testfile.tar.gz 11
Binary files testfile.tar.gz and 11 differ
[jessinio@niowork tmp]$ gpg --output 11.tar.gz -d 11
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
[jessinio@niowork tmp]$ diff 11.tar.gz testfile.tar.gz
[jessinio@niowork tmp]$
gpg的完整使用手册: http://www.gnupg.org/gph/en/manual.html
Saturday, January 8, 2011
硬盘, 接口, RAID
本文不想记录关于RAID的种类和它的安装之类的,只是想写关于RAID与它背后的硬盘的一些简单信息。
这样有利于SA了解自己管理的硬件的一些具体情况,及正确地使用相应的工具。
我之所以会去了解这些信息, 主要是因为:
* 我无法正确了解到在RAID背后的硬盘的信息(如健康情况、容量、型号)
作为SA就基本要清楚自己管理的硬件情况。
我们平时常常会看到这样的一些名词:
* SCSI. SAS
* ATA. IDE. SATA. eSTAT
* iSCSI
发展过程: AT -> ATA -> IDE
上面的ATA都是并口(parallel)的。然后发展为串口 serial ATA。 也就是SATA
至于SCSI, 和ATA的发展有很大的相似度。 SCSI (Small Computer System Interface)也是一种接口技术, 然后发现到了串口的SAS(Serial Attached SCSI).
上面是平时常使用的硬盘接口的两大类的历史。
在了解上面的接口历史好。 先来小试牛力: 使用smartctl的'-d'参数:
了解上面的接口,就可以大概知道怎么选择这个参数了。
* 对于marvell接口, 我从来就接触过,所以不说它了。
但是,还有一个很有意思的类型: sat
关于 SAT描述如下 :
为中间产物, 也就是可以让SATA接口硬盘接收SCSI的指令集。
至于为什么Linux会把SATA硬盘命名成sdx, 是不是因为这个原因我无法查询到相关信息。
1. host adapter, 具体请见: http://en.wikipedia.org/wiki/Host_adapter
2. RAID controller, 具体请见: http://en.wikipedia.org/wiki/Disk_array_controller
上面的两个名词和平时所讲的“RAID card“是指同一种设备。
由于RAID把背后的硬盘情况隐藏了,所以SA要取得硬盘的信息就成问题。
从smartctl工具的文档:
至于世界上还有多少还没有RAID卡(芯片)生产商是smartctl目前为止还没有支持的, 我也无法查询到
还是,可以肯定的是: SA可以借助生产商自己开发的RAID硬件支持工具。比如这个URL:
这样有利于SA了解自己管理的硬件的一些具体情况,及正确地使用相应的工具。
我之所以会去了解这些信息, 主要是因为:
* 我无法正确了解到在RAID背后的硬盘的信息(如健康情况、容量、型号)
作为SA就基本要清楚自己管理的硬件情况。
接口
开始前, 也回顾一下硬件接口的变迁我们平时常常会看到这样的一些名词:
* SCSI. SAS
* ATA. IDE. SATA. eSTAT
* iSCSI
发展过程: AT -> ATA -> IDE
The current Parallel ATA standard is the result of a long history of incremental technical development, which began with the original AT Attachment interface, developed for use in early PC AT equipment. The ATA interface itself evolved in several stages from Western Digital's original Integrated Drive Electronics (IDE) interface.
上面的ATA都是并口(parallel)的。然后发展为串口 serial ATA。 也就是SATA
至于SCSI, 和ATA的发展有很大的相似度。 SCSI (Small Computer System Interface)也是一种接口技术, 然后发现到了串口的SAS(Serial Attached SCSI).
上面是平时常使用的硬盘接口的两大类的历史。
在了解上面的接口历史好。 先来小试牛力: 使用smartctl的'-d'参数:
-d TYPE, --device=TYPE
Specifies the type of the device. The valid arguments to this option are ata, scsi, sat, marvell, 3ware,N, and hpt,L/M, cciss,N or hpt,L/M/N.
Specifies the type of the device. The valid arguments to this option are ata, scsi, sat, marvell, 3ware,N, and hpt,L/M, cciss,N or hpt,L/M/N.
了解上面的接口,就可以大概知道怎么选择这个参数了。
* 对于marvell接口, 我从来就接触过,所以不说它了。
但是,还有一个很有意思的类型: sat
关于 SAT描述如下 :
The ´sat´ device type is for ATA disks that have a SCSI to ATA Translation (SAT) Layer (SATL) between the disk and the operating system.
为中间产物, 也就是可以让SATA接口硬盘接收SCSI的指令集。
至于为什么Linux会把SATA硬盘命名成sdx, 是不是因为这个原因我无法查询到相关信息。
RAID
在开始RAID硬件前, 还有几个名词要知道:1. host adapter, 具体请见: http://en.wikipedia.org/wiki/Host_adapter
2. RAID controller, 具体请见: http://en.wikipedia.org/wiki/Disk_array_controller
上面的两个名词和平时所讲的“RAID card“是指同一种设备。
由于RAID把背后的硬盘情况隐藏了,所以SA要取得硬盘的信息就成问题。
从smartctl工具的文档:
http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_RAID-Controllers
可以看出: 要得到RAID卡后面硬盘的情况,SA首先从众多的型号中找出满足自己的RAID至于世界上还有多少还没有RAID卡(芯片)生产商是smartctl目前为止还没有支持的, 我也无法查询到
还是,可以肯定的是: SA可以借助生产商自己开发的RAID硬件支持工具。比如这个URL:
http://www.lsi.com/storage_home/products_home/internal_raid/megaraid_scsi/megaraid_scsi_3200/index.html#Miscellaneous
Tuesday, January 4, 2011
linux kernel and modules
本文主要是回顾linux modules这部分的管理.
system administrator 使用的模块处理CLI命令主要是如下的工具包:
$ dpkg -S $(which modprobe)
module-init-tools: /sbin/modprobe
讲述了如何编译自己的写的module, 相当不错.
但是少了点"为什么要这样做"的解释
看URL里写的Makefile里的这句话:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
参数M是什么? 参数modules又是什么? gcc怎么没有调用? 为什么可以简单的一行命令可以完成编译?
带着问题去找答案:
$ ls -ld /lib/modules/$(uname -r)/build
lrwxrwxrwx 1 root root 40 2010-03-31 09:43 /lib/modules/2.6.31-21-generic/build -> /usr/src/linux-headers-2.6.31-21-generic
ubuntu下的/usr/src/linux-headers-2.6.31-21-generic目录下的Makefile其实就是kernel代码下的Makefile文件。所以上面的make命令中的modules参数与在kernel代码目录里的modules参数是一致的。
参数"-C"表示进入此目录, 目录下有另一个Makefile文件(/lib/modules/2.6.31-21-generic/build/Makefile), 此Makefile内的一小段代码:
62 # Use make M=dir to specify directory of external module to build
63 # Old syntax make ... SUBDIRS=$PWD is still supported
64 # Setting the environment variable KBUILD_EXTMOD take precedence
65 ifdef SUBDIRS
66 KBUILD_EXTMOD ?= $(SUBDIRS)
67 endif
68
69 ifeq ("$(origin M)", "command line")
70 KBUILD_EXTMOD := $(M)
71 endif
这已经可以解决疑问:
自己写的模块编译Makefile文件只是为/lib/modules/2.6.31-21-generic/build/Makefile 提供两个参数:
找个复杂的驱动试试是否为这样, 于是从intel官网下载了e1000e-1.2.20.tar.gz代码
234 ifeq ($(KOBJ),$(KSRC))
235 $(MAKE) -C $(KSRC) SUBDIRS=$(shell pwd) modules
236 else
237 $(MAKE) -C $(KSRC) O=$(KOBJ) SUBDIRS=$(shell pwd) modules
238 endif
239 endif
.......(还有很多不显示).......
274 default:
275 $(MAKE)
下面是编译的具体过程:
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ make
make -C /lib/modules/2.6.31-21-generic/build SUBDIRS=/tmp/e1000e-1.2.20/src modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.31-21-generic'
CC [M] /tmp/e1000e-1.2.20/src/netdev.o
CC [M] /tmp/e1000e-1.2.20/src/ethtool.o
CC [M] /tmp/e1000e-1.2.20/src/param.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_82571.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_ich8lan.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_80003es2lan.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_mac.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_nvm.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_phy.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_manage.o
CC [M] /tmp/e1000e-1.2.20/src/kcompat.o
LD [M] /tmp/e1000e-1.2.20/src/e1000e.o
Building modules, stage 2.
MODPOST 1 modules
CC /tmp/e1000e-1.2.20/src/e1000e.mod.o
LD [M] /tmp/e1000e-1.2.20/src/e1000e.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-21-generic'
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ lsmod|grep e1000e
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ sudo insmod e1000e.ko
编译与加载一路通!
insmod和rmmod组合与modprobe的区别
其实大家都知道: modprobe解决module的依赖问题. insmod和rmode不会处理这种依赖问题.
依赖的依据是: `代码中使用的module名`
CLI下可以这样查看:
$ modinfo iptable_filter|grep depends
depends: ip_tables
被依赖的ip_tables可能又依赖于其它module, 不断的向下查找. 直到depends为NULL.
depmod为处理这种问题的工具:modprobe expects an up-to-date modules.dep file, as generated by depmod
可以看出modprobe和depmod工具的关系.
使用modprobe查看依赖树:
$ modprobe --show-depends iptable_filter
insmod /lib/modules/2.6.31-21-generic/kernel/net/netfilter/x_tables.ko
insmod /lib/modules/2.6.31-21-generic/kernel/net/ipv4/netfilter/ip_tables.ko
insmod /lib/modules/2.6.31-21-generic/kernel/net/ipv4/netfilter/iptable_filter.ko
上面出现的insmod是有先后顺序的.
因为modprobe是使用了modules.dep文件, 所以面对没有放在/lib/modules下或者没有调用depmod命令去更新modules.dep文件, modprobe是无法加载模块的:
# modprobe hello
FATAL: Module hello not found.
# insmod hello.ko
# rmmod hello
modprobe除了可以方便insert和remove模块外, 还有这样一些方便的功能:
1. option
2. alias
这是通过modprobe读取/etc/modprobe.conf( /etc/modprobe.d) 文件完成.
alias主是是用于调用modprobe工具时使用管理者喜欢的模块名代替实现的module名(编译后的模块名)
* alias不会影响 lsmod 命令列出的模块名. lsmod是列出真实的模块名
module有哪些option呢?
$ /sbin/modinfo bnx2|grep parm
parm: disable_msi:Disable Message Signaled Interrupt (MSI) (int)
parm: enable_entropy:Allow bnx2 to populate the /dev/random entropy pool (int)
上面列出指定的bnx2网卡module的参数.
oldconfig - Update current config utilising a provided .config as base
silentoldconfig - Same as oldconfig, but quietly, additionally update deps
oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)
这三个参数都是利用旧kernel的configure文件. 例如:
jessinio@jessinio-laptop:~/linux-2.6.36.2$ cp /boot/config-2.6.31-21-generic ./.config
system administrator 使用的模块处理CLI命令主要是如下的工具包:
$ dpkg -S $(which modprobe)
module-init-tools: /sbin/modprobe
kernel module编译
这一篇文章: http://www.cyberciti.biz/tips/compiling-linux-kernel-module.html讲述了如何编译自己的写的module, 相当不错.
但是少了点"为什么要这样做"的解释
看URL里写的Makefile里的这句话:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
参数M是什么? 参数modules又是什么? gcc怎么没有调用? 为什么可以简单的一行命令可以完成编译?
带着问题去找答案:
$ ls -ld /lib/modules/$(uname -r)/build
lrwxrwxrwx 1 root root 40 2010-03-31 09:43 /lib/modules/2.6.31-21-generic/build -> /usr/src/linux-headers-2.6.31-21-generic
ubuntu下的/usr/src/linux-headers-2.6.31-21-generic目录下的Makefile其实就是kernel代码下的Makefile文件。所以上面的make命令中的modules参数与在kernel代码目录里的modules参数是一致的。
参数"-C"表示进入此目录, 目录下有另一个Makefile文件(/lib/modules/2.6.31-21-generic/build/Makefile), 此Makefile内的一小段代码:
62 # Use make M=dir to specify directory of external module to build
63 # Old syntax make ... SUBDIRS=$PWD is still supported
64 # Setting the environment variable KBUILD_EXTMOD take precedence
65 ifdef SUBDIRS
66 KBUILD_EXTMOD ?= $(SUBDIRS)
67 endif
68
69 ifeq ("$(origin M)", "command line")
70 KBUILD_EXTMOD := $(M)
71 endif
这已经可以解决疑问:
自己写的模块编译Makefile文件只是为/lib/modules/2.6.31-21-generic/build/Makefile 提供两个参数:
- directory of external module
- "modules"
找个复杂的驱动试试是否为这样, 于是从intel官网下载了e1000e-1.2.20.tar.gz代码
234 ifeq ($(KOBJ),$(KSRC))
235 $(MAKE) -C $(KSRC) SUBDIRS=$(shell pwd) modules
236 else
237 $(MAKE) -C $(KSRC) O=$(KOBJ) SUBDIRS=$(shell pwd) modules
238 endif
239 endif
.......(还有很多不显示).......
274 default:
275 $(MAKE)
下面是编译的具体过程:
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ make
make -C /lib/modules/2.6.31-21-generic/build SUBDIRS=/tmp/e1000e-1.2.20/src modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.31-21-generic'
CC [M] /tmp/e1000e-1.2.20/src/netdev.o
CC [M] /tmp/e1000e-1.2.20/src/ethtool.o
CC [M] /tmp/e1000e-1.2.20/src/param.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_82571.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_ich8lan.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_80003es2lan.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_mac.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_nvm.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_phy.o
CC [M] /tmp/e1000e-1.2.20/src/e1000_manage.o
CC [M] /tmp/e1000e-1.2.20/src/kcompat.o
LD [M] /tmp/e1000e-1.2.20/src/e1000e.o
Building modules, stage 2.
MODPOST 1 modules
CC /tmp/e1000e-1.2.20/src/e1000e.mod.o
LD [M] /tmp/e1000e-1.2.20/src/e1000e.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-21-generic'
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ lsmod|grep e1000e
jessinio@jessinio-laptop:/tmp/e1000e-1.2.20/src$ sudo insmod e1000e.ko
编译与加载一路通!
insmod和rmmod组合与modprobe的区别
其实大家都知道: modprobe解决module的依赖问题. insmod和rmode不会处理这种依赖问题.
依赖的依据是: `代码中使用的module名`
CLI下可以这样查看:
$ modinfo iptable_filter|grep depends
depends: ip_tables
被依赖的ip_tables可能又依赖于其它module, 不断的向下查找. 直到depends为NULL.
depmod为处理这种问题的工具:modprobe expects an up-to-date modules.dep file, as generated by depmod
可以看出modprobe和depmod工具的关系.
使用modprobe查看依赖树:
$ modprobe --show-depends iptable_filter
insmod /lib/modules/2.6.31-21-generic/kernel/net/netfilter/x_tables.ko
insmod /lib/modules/2.6.31-21-generic/kernel/net/ipv4/netfilter/ip_tables.ko
insmod /lib/modules/2.6.31-21-generic/kernel/net/ipv4/netfilter/iptable_filter.ko
上面出现的insmod是有先后顺序的.
因为modprobe是使用了modules.dep文件, 所以面对没有放在/lib/modules下或者没有调用depmod命令去更新modules.dep文件, modprobe是无法加载模块的:
# modprobe hello
FATAL: Module hello not found.
# insmod hello.ko
# rmmod hello
modprobe除了可以方便insert和remove模块外, 还有这样一些方便的功能:
1. option
2. alias
这是通过modprobe读取/etc/modprobe.conf( /etc/modprobe.d) 文件完成.
alias主是是用于调用modprobe工具时使用管理者喜欢的模块名代替实现的module名(编译后的模块名)
* alias不会影响 lsmod 命令列出的模块名. lsmod是列出真实的模块名
module有哪些option呢?
$ /sbin/modinfo bnx2|grep parm
parm: disable_msi:Disable Message Signaled Interrupt (MSI) (int)
parm: enable_entropy:Allow bnx2 to populate the /dev/random entropy pool (int)
上面列出指定的bnx2网卡module的参数.
kernel编译
jessinio@jessinio-laptop:~/linux-2.6.36.2$ make help|grep oldconfigoldconfig - Update current config utilising a provided .config as base
silentoldconfig - Same as oldconfig, but quietly, additionally update deps
oldnoconfig - Same as silentoldconfig but set new symbols to n (unset)
这三个参数都是利用旧kernel的configure文件. 例如:
jessinio@jessinio-laptop:~/linux-2.6.36.2$ cp /boot/config-2.6.31-21-generic ./.config
Tuesday, December 14, 2010
ip route
笔记
route是什么意思?
这个词的字面意思一直不知道是什么意思。 其实这不是一个汉语词汇。汉语词汇里只有一个“路由单” ,为一名词。 路由(route)有两种意思:
1. 选择某路线
2. 与"路由单"的意思一致: 指旅途所经历的地名单
选择路线的依据是"目的地".
但是随着发展, 仅仅是destination方式的route方式不能满足要求:
linux对应这种发展的具体落实:
意思大概是如下两件事物:
1. linux支持多routing tables. routing policy database (RPDB)
2. 每张表有独立的规则. policy based routing
平时使用的路由都是由destination成唯一条件(比如使用route命令打印的結果). 那么policy based routing有什么重要呢?
下面的一段话, 描述了linux在路由数据包时, policy based routing使用的多种实现方法
使用人类文字描述Linux选择线路不是很容易理解, 如下一段伪代码比较好:
if packet.routeCacheLookupKey in routeCache :
route = routeCache[ packet.routeCacheLookupKey ]
else
for rule in rpdb :
if packet.rpdbLookupKey in rule : (rule为下表的RPDB对象)
routeTable = rule[ lookupTable ] (routeTable为下表的route table对象)
if packet.routeLookupKey in routeTable :
route = route_table[ packet.routeLookup_key ]
把rpdb为routing table, 规则(rule)都在DB中, 每条rule有不同的属性(这里的属性包括上面提到的attributes).
伪代码中的LookupKey是代表下表中具体的一条属性. 所以, 其实上面的伪代码是很N多if语句的.
* 斜体字的属性是可选的. 如果存在就判断, 不存在不判断.
从上面的可以知道, route table起到:
1. 组织rule的作用
2. 同类的rule会拥有一组属性.
从上面的表中可以知道, 每个packet的destination和source是必定被用于路由, 但是不唯一确定条件.
linux system administrator查看上面的三种数据的方法:
1. route cache 表: ip route show cache
2. 每张RPDB表: ip rule list table 表名
3. 列出全部route table: ip rule show
route是什么意思?
这个词的字面意思一直不知道是什么意思。 其实这不是一个汉语词汇。汉语词汇里只有一个“路由单” ,为一名词。 路由(route)有两种意思:
1. 选择某路线
2. 与"路由单"的意思一致: 指旅途所经历的地名单
选择路线的依据是"目的地".
In the common case, route selection is based completely on the destination address. Conventional (as opposed to policy-based) IP networking relies on only the destination address to select a route for a packet.
但是随着发展, 仅仅是destination方式的route方式不能满足要求:
With the prevalence of low cost bandwidth, easily configured VPN tunnels, and increasing reliance on networks, the technique of selecting a route based solely on the destination IP address range no longer suffices for all situations.
Since kernel 2.2, linux has supported policy based routing through the use of multiple routing tables and the routing policy database (RPDB). Together, they allow a network administrator to configure a machine select different routing tables and routes based on a number of criteria.
意思大概是如下两件事物:
1. linux支持多routing tables. routing policy database (RPDB)
2. 每张表有独立的规则. policy based routing
平时使用的路由都是由destination成唯一条件(比如使用route命令打印的結果). 那么policy based routing有什么重要呢?
In fact, advanced routing could more accurately be called policy-based networking.
下面的一段话, 描述了linux在路由数据包时, policy based routing使用的多种实现方法
Selectors available for use in policy-based routing are attributes of a packet passing through the linux routing code. The source address of a packet, the ToS flags, an fwmark (a mark carried through the kernel in the data structure representing the packet), and the interface name on which the packet was received are attributes which can be used as selectors. By selecting a routing table based on packet attributes, an administrator can have granular control over the network path of any packet.
selector确定使用那张routing table. 使用人类文字描述Linux选择线路不是很容易理解, 如下一段伪代码比较好:
if packet.routeCacheLookupKey in routeCache :
route = routeCache[ packet.routeCacheLookupKey ]
else
for rule in rpdb :
if packet.rpdbLookupKey in rule : (rule为下表的RPDB对象)
routeTable = rule[ lookupTable ] (routeTable为下表的route table对象)
if packet.routeLookupKey in routeTable :
route = route_table[ packet.routeLookup_key ]
把rpdb为routing table, 规则(rule)都在DB中, 每条rule有不同的属性(这里的属性包括上面提到的attributes).
伪代码中的LookupKey是代表下表中具体的一条属性. 所以, 其实上面的伪代码是很N多if语句的.
从上面的可以知道, route table起到:
1. 组织rule的作用
2. 同类的rule会拥有一组属性.
从上面的表中可以知道, 每个packet的destination和source是必定被用于路由, 但是不唯一确定条件.
linux system administrator查看上面的三种数据的方法:
1. route cache 表: ip route show cache
2. 每张RPDB表: ip rule list table 表名
3. 列出全部route table: ip rule show
Sunday, December 12, 2010
ethernet
开始
以太网层本时很少关注. 最近一次关注是理解LVS时. 最近在看<<Guide to IP Layer NetworkAdministration with Linux>>, 做做笔记, 随便动动手. 加深记忆.
被操作的机器上只有网关的物理地址:
$ arp -n
Address HWtype HWaddress Flags Mask Iface
10.20.129.1 ether 00:0F:E2:D3:BE:B8 C eth0
进行如下动作:
$ ping 10.20.129.32
把ping动作发出的包抓下来
$ sudo tcpdump -ent -i eth0 arp or icmp
....(截掉).....
00:23:ae:93:d9:26 > Broadcast, ethertype ARP (0x0806), length 42: arp who-has 10.20.129.32 tell 10.20.129.19
00:1e:4f:ad:41:58 > 00:23:ae:93:d9:26, ethertype ARP (0x0806), length 60: arp reply 10.20.129.32 is-at 00:1e:4f:ad:41:58
00:23:ae:93:d9:26 > 00:1e:4f:ad:41:58, ethertype IPv4 (0x0800), length 98: 10.20.129.19 > 10.20.129.32: ICMP echo request, id 26119, seq 1, length 64
00:1e:4f:ad:41:58 > 00:23:ae:93:d9:26, ethertype IPv4 (0x0800), length 98: 10.20.129.32 > 10.20.129.19: ICMP echo reply, id 26119, seq 1, length 64
....(截掉).....
ICMP包在ethernet层之上, 需要使用ethernet发数据, 需要物理地址. 为了得到物理地址使用到ARP协议.
ARP过程与如下命令一致: $ sudo arping -I eth0 10.20.129.32这一条命令表示向网段内查询某IP对应的MAC地址.
查看ARP表:
$ arp -n
Address HWtype HWaddress Flags Mask Iface
10.20.129.1 ether 00:0F:E2:D3:BE:B8 C eth0
10.20.129.32 ether 00:1E:4F:AD:41:58 C eth0
增加了一个记录
arping命令 -A 参数: ARP announcement, 也称为gratuitous ARP
$ sudo arping -A -c 3 -I eth0 10.20.129.19tcpdump的抓包结果:
00:23:ae:93:d9:26 > Broadcast, ethertype ARP (0x0806), length 42: arp reply 10.20.129.19 is-at 00:23:ae:93:d9:26
00:23:ae:93:d9:26 > Broadcast, ethertype ARP (0x0806), length 42: arp reply 10.20.129.19 is-at 00:23:ae:93:d9:26
00:23:ae:93:d9:26 > Broadcast, ethertype ARP (0x0806), length 42: arp reply 10.20.129.19 is-at 00:23:ae:93:d9:26
从上面的信息看出, -A是向整个网段通知自己的IP. 默认情况下, linux 不会接受这样的包.
由arp_accept选项控制, 如下文档:
arp_accept - BOOLEAN
Define behavior for gratuitous ARP frames who's IP is not
already present in the ARP table:
0 - don't create new entries in the ARP table
1 - create new entries in the ARP table
如果看知道 gratuitous ARP 包的具体用法, 可以移步到: http://wiki.wireshark.org/Gratuitous_ARP
arping命令 -D 参数: Duplicate address detection mode (DAD)
这个参数相当有用: 用于排除网段中有IP冲突. 来个实例:root@jessinio-laptop:~# ifconfig wlan0 |head -n 2
wlan0 Link encap:Ethernet HWaddr 00:16:cf:68:5b:a7
inet addr:192.168.0.106 Bcast:192.168.0.255 Mask:255.255.255.0
root@jessinio-laptop:~# arping -D -I wlan0 192.168.0.106
ARPING 192.168.0.106 from 0.0.0.0 wlan0
Unicast reply from 192.168.0.106 [00:18:41:FE:26:5F] 90.390ms
Sent 1 probes (1 broadcast(s))
Received 1 response(s)
可以看出, 192.168.0.106 被两台机器使用, 一台是本志的00:16:cf:68:5b:a7 , 另一台是00:18:41:FE:26:5F.
抓包信息:
00:16:cf:68:5b:a7 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.0.106 (ff:ff:ff:ff:ff:ff) tell 0.0.0.0, length 28
00:18:41:fe:26:5f > 00:16:cf:68:5b:a7, ethertype ARP (0x0806), length 42: Reply 192.168.0.106 is-at 00:18:41:fe:26:5f, length 28
结束
以一个问题为结束: 使用ICMP协议能否得知网段中有其它机器使用自己的IP呢? 比如, ping自己的IP.
答案是不可以的. 因为ICMP包基本没有发出来. 回流了. 例如:
产生的数据包不会流过ethernet卡, 从route表就可以知道:
$ ip route list table local
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 10.20.129.0 dev eth0 proto kernel scope link src 10.20.129.19
local 10.20.129.19 dev eth0 proto kernel scope host src 10.20.129.19
broadcast 10.20.129.127 dev eth0 proto kernel scope link src 10.20.129.19
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
Friday, November 26, 2010
iptables与流量统计
要对机房某台机器进行临时性的 内、外网流量统计分开。这种事最好不要放到应用层统计,因为效率很成问题。第一时间想到处于网络二、三层的工具,效率不会被过多影响。 如ntop之类使用libpcap库的工具。
其实iptables也是有包统计。因为每个包都经过它。而且不用安装任何工具。
加入两条规则:
jessinio@jessinio-laptop:~$ sudo iptables -t filter -A INPUT -p all -s 174.121.79.132 -j ACCEPT
jessinio@jessinio-laptop:~$ sudo iptables -t filter -A OUTPUT -p all -d 174.121.79.132 -j ACCEPT
情况:
jessinio@jessinio-laptop:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- web124.webfaction.com anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere web124.webfaction.com
結果:
jessinio@jessinio-laptop:~$ sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 11M packets, 5033M bytes)
pkts bytes target prot opt in out source destination
10 2088 ACCEPT all -- * * 174.121.79.132 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 14M packets, 14G bytes)
pkts bytes target prot opt in out source destination
48 25152 ACCEPT all -- * * 0.0.0.0/0 174.121.79.132
其实iptables也是有包统计。因为每个包都经过它。而且不用安装任何工具。
加入两条规则:
jessinio@jessinio-laptop:~$ sudo iptables -t filter -A INPUT -p all -s 174.121.79.132 -j ACCEPT
jessinio@jessinio-laptop:~$ sudo iptables -t filter -A OUTPUT -p all -d 174.121.79.132 -j ACCEPT
情况:
jessinio@jessinio-laptop:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- web124.webfaction.com anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere web124.webfaction.com
結果:
jessinio@jessinio-laptop:~$ sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 11M packets, 5033M bytes)
pkts bytes target prot opt in out source destination
10 2088 ACCEPT all -- * * 174.121.79.132 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 14M packets, 14G bytes)
pkts bytes target prot opt in out source destination
48 25152 ACCEPT all -- * * 0.0.0.0/0 174.121.79.132
Thursday, November 18, 2010
seteuid
# ps axjf|grep -v grep|grep ftp
1 13871 13871 13871 ? -1 Ss 0 0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
13871 14146 14146 14146 ? -1 Ss 99 0:00 \_ /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
14146 14148 14146 14146 ? -1 S 509 0:00 \_ /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
id是99进程可以产生id为509的进程, 原来fork后, 子进程还是可以调用seteuid切到其它uid的, 这之前还不知道。 如下测试代码:
#!/usr/bin/python
#coding:utf-8
import os
import time
# 同一进程可以从0转成其它的
os.seteuid(99)
os.seteuid(0)
os.seteuid(99)
pid = os.fork()
# child
if pid == 0:
# 子进程还是可以使用seteuid回到0的
os.seteuid(0)
time.sleep(10)
else:
print pid
time.sleep(10)
运行结果:
[jessinio@niowork tmp]$ ps axuf|grep root.py
nobody 28559 0.0 0.0 74192 2912 pts/11 T 13:56 0:00 | \_ python root.py
root 28560 0.0 0.0 74188 1756 pts/11 T 13:56 0:00 | | \_ python root.py
1 13871 13871 13871 ? -1 Ss 0 0:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
13871 14146 14146 14146 ? -1 Ss 99 0:00 \_ /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
14146 14148 14146 14146 ? -1 S 509 0:00 \_ /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
id是99进程可以产生id为509的进程, 原来fork后, 子进程还是可以调用seteuid切到其它uid的, 这之前还不知道。 如下测试代码:
#!/usr/bin/python
#coding:utf-8
import os
import time
# 同一进程可以从0转成其它的
os.seteuid(99)
os.seteuid(0)
os.seteuid(99)
pid = os.fork()
# child
if pid == 0:
# 子进程还是可以使用seteuid回到0的
os.seteuid(0)
time.sleep(10)
else:
print pid
time.sleep(10)
运行结果:
[jessinio@niowork tmp]$ ps axuf|grep root.py
nobody 28559 0.0 0.0 74192 2912 pts/11 T 13:56 0:00 | \_ python root.py
root 28560 0.0 0.0 74188 1756 pts/11 T 13:56 0:00 | | \_ python root.py
Thursday, November 4, 2010
使用strace找出问题根本点
今天想备份一个svn仓库。但是碰到“鬼”了。如下:
$ sudo -u daemon HOME=/tmp /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo
svnsync: Revprop change blocked by pre-revprop-change hook (exit code 255) with no output.
看上去是svn的pre-revprop-change hook出了问题。但是无论我怎么折腾pre-revprop-change hook代码都不给力。
又怀疑是环境变量, 连sudo的-E都使用上了还是一个屁用。
无奈下只能使用strace看看:
$ sudo -u daemon HOME=/tmp strace -f /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo 2>&1 |less
一定要使用-f, 因为svnsync产生了子进程, 这样可以连子进程都可以被trace。
看到一句相当可疑的trace条目:
[pid 6548] chdir(".") = -1 EACCES (Permission denied)
呃。。。。。细节。原来work directory是~, 切换成daemon运行的svnsync没有权限。。。。。
这样就没有问题了:
$ cd / && sudo -u daemon HOME=/tmp /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo
真是细节。
$ sudo -u daemon HOME=/tmp /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo
svnsync: Revprop change blocked by pre-revprop-change hook (exit code 255) with no output.
看上去是svn的pre-revprop-change hook出了问题。但是无论我怎么折腾pre-revprop-change hook代码都不给力。
又怀疑是环境变量, 连sudo的-E都使用上了还是一个屁用。
无奈下只能使用strace看看:
$ sudo -u daemon HOME=/tmp strace -f /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo 2>&1 |less
一定要使用-f, 因为svnsync产生了子进程, 这样可以连子进程都可以被trace。
看到一句相当可疑的trace条目:
[pid 6548] chdir(".") = -1 EACCES (Permission denied)
呃。。。。。细节。原来work directory是~, 切换成daemon运行的svnsync没有权限。。。。。
这样就没有问题了:
$ cd / && sudo -u daemon HOME=/tmp /usr/local/subversion/bin/svnsync sync file:///data/repos/xxoo
真是细节。
Thursday, October 14, 2010
devfs与udev
/dev 目录disk-based还是kernel-based的文件系统?
这个问题一直没有分开.
从自己的实践和<<Linux操作系统之奥秘>>一书, 明显/dev是disk-based的. 本人没有使用过devfs
linux2.4 kernel时代使用devfs文件系统. linux 2.6 kernel已经去掉devfs代码了.
想查查devfs的文档都不容易, 它的作者旧blog上的文章都找不到了.
google到
* http://www.linuxjournal.com/article/6035
* http://www.ibm.com/developerworks/linux/library/l-devfs.html
从时间上看很老的, 为了确认年代, 查看了kernel的timeline, 可以确认这是"同一时代"的产物:
* http://en.wikipedia.org/wiki/Linux_kernel#Timeline
没有用过devfs. 为了求真相, 问朋友借了个redhat8环境的linux, 结果devfs没有被默认编入kernel:
# cat /boot/config-2.4.18-14 |grep DEVFS
# CONFIG_DEVFS_FS is not set
但是redhat8下的/dev的确有18 thousand entries (比较惊人)
/dev 目录disk-based还是kernel-based的文件系统? 这个问题没有环境都没法亲眼看到. 主能找到的文档里找, 有些文件是使用pseudo filesystem称呼devfs的(例如这篇: http://www.linux.org/docs/ldp/howto/SCSI-2.4-HOWTO/devfs.html)
在 http://www.linuxjournal.com/article/6035 一文中, 描述了使用devfs的好处:
1. 系统自动管理/dev下的文件
2. 可以被read only 的方法mount到系统和/dev创建在non-unix file system上
文档特殊提到了non-unix file system. 因为dev entry是还有一些额外的信息. 下面在fat32文件系统上创建一个dev entry:
[jessinio@niowork NO_NAME]$ sudo mknod dev_entry c 240 1
mknod: `dev_entry': Operation not permitted
可以确定devfs一个存在于内存的文件系统.
devfs已经被淘汰, 被udev取代. udev比devfs带来什么好处?
如果想仔细了解有什么优点, 请阅读udev作者写的文章: http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev_vs_devfs
比较深刻的是两条:
1. 可以随意命名设备文件在/dev下的entry名
2. allow everyone to not care about major/minor numbers
到这里, 又需要把视线转移到sysfs上面了.
这个问题一直没有分开.
从自己的实践和<<Linux操作系统之奥秘>>一书, 明显/dev是disk-based的. 本人没有使用过devfs
linux2.4 kernel时代使用devfs文件系统. linux 2.6 kernel已经去掉devfs代码了.
想查查devfs的文档都不容易, 它的作者旧blog上的文章都找不到了.
google到
* http://www.linuxjournal.com/article/6035
* http://www.ibm.com/developerworks/linux/library/l-devfs.html
从时间上看很老的, 为了确认年代, 查看了kernel的timeline, 可以确认这是"同一时代"的产物:
* http://en.wikipedia.org/wiki/Linux_kernel#Timeline
没有用过devfs. 为了求真相, 问朋友借了个redhat8环境的linux, 结果devfs没有被默认编入kernel:
# cat /boot/config-2.4.18-14 |grep DEVFS
# CONFIG_DEVFS_FS is not set
但是redhat8下的/dev的确有18 thousand entries (比较惊人)
/dev 目录disk-based还是kernel-based的文件系统? 这个问题没有环境都没法亲眼看到. 主能找到的文档里找, 有些文件是使用pseudo filesystem称呼devfs的(例如这篇: http://www.linux.org/docs/ldp/howto/SCSI-2.4-HOWTO/devfs.html)
在 http://www.linuxjournal.com/article/6035 一文中, 描述了使用devfs的好处:
1. 系统自动管理/dev下的文件
2. 可以被read only 的方法mount到系统和/dev创建在non-unix file system上
文档特殊提到了non-unix file system. 因为dev entry是还有一些额外的信息. 下面在fat32文件系统上创建一个dev entry:
[jessinio@niowork NO_NAME]$ sudo mknod dev_entry c 240 1
mknod: `dev_entry': Operation not permitted
可以确定devfs一个存在于内存的文件系统.
devfs已经被淘汰, 被udev取代. udev比devfs带来什么好处?
如果想仔细了解有什么优点, 请阅读udev作者写的文章: http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev_vs_devfs
比较深刻的是两条:
1. 可以随意命名设备文件在/dev下的entry名
2. allow everyone to not care about major/minor numbers
到这里, 又需要把视线转移到sysfs上面了.
Monday, October 11, 2010
足够数目的getdents调用与文件数目引发的问题
网站的速度很慢。要求给个理由。于是登机top了一把。如下
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
29131 liangqin 16 0 15068 3444 816 R 11.7 0.0 0:00.72 top
16371 kmmaster 16 0 181m 8484 3128 D 5.2 0.1 0:01.20 httpd
5726 kmmaster 15 0 182m 9352 3564 S 3.9 0.1 0:02.24 httpd
32548 kmmaster 16 0 183m 9.8m 3348 D 3.9 0.1 0:06.16 httpd
6199 kmmaster 16 0 183m 9444 3452 D 2.6 0.1 0:01.89 httpd
7697 kmmaster 16 0 182m 8848 3184 D 2.6 0.1 0:01.94 httpd
10536 kmmaster 16 0 181m 8692 3332 D 2.6 0.1 0:01.93 httpd
15102 kmmaster 16 0 181m 8420 3060 D 2.6 0.1 0:01.37 httpd
17993 kmmaster 16 0 181m 8708 3292 D 2.6 0.1 0:04.16 httpd
23185 kmmaster 16 0 182m 9420 3428 D 2.6 0.1 0:00.61 httpd
30189 kmmaster 16 0 181m 8724 3308 D 2.6 0.1 0:05.91 httpd
30337 kmmaster 16 0 183m 9.9m 3448 D 2.6 0.1 0:02.71 httpd
使用strace命令查看D状态的httpd, 都是调用getdents, stat, unlink等IO函数, 如:
stat("/tmp/sess_bc45d5d1dd8739acceff8a3e0fec0585", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
使用ls, find之类的工具都无法对此目录(指/tmp)进行数据查看。行为freeze。也是进入D状态。
本想使用python的os.listdir函数的。但这个函数是读完目录的entry后才返回list的。 也是要慢很长时间。
于是使用下面的C代码:
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
DIR *dirp = opendir("/tmp");
struct dirent *retval;
long long int t;
for(; ; ){
retval = readdir(dirp);
if (retval == NULL) {break;}
else {printf("%s\n", retval->d_name); t++;}
}
printf("%lld\n", t);
}
可以知道目录文件总数是 221346
httpd的进程数有3K!每个需要session的进程都要读/tmp目录下的entry, 这个行为会对3K数目的httpd进程有很大的影响吗?
于是自己写了个测试代码, 目的就是测试众多的readdir函数是否对进程有影响:
#coding:utf-8
import time
import os
for i in range(300):
pid = os.fork()
if pid > 0:
break
for r in range(30):
time.sleep(0.1)
os.listdir("/tmp")
代码很简单, 但是对于200K条目的directory来说, 很给力!!出现大量的D状态进程:
(........被截去......)
905 7072 0.1 0.0 84244 11628 pts/2 D+ 14:45 0:00 python listdir.py
905 7073 0.1 0.1 85136 12448 pts/2 D+ 14:45 0:00 python listdir.py
905 7074 0.1 0.1 85136 12628 pts/2 D+ 14:45 0:00 python listdir.py
905 7075 0.1 0.1 86304 13588 pts/2 D+ 14:45 0:00 python listdir.py
905 7076 0.1 0.0 84764 12264 pts/2 D+ 14:45 0:00 python listdir.py
905 7077 0.1 0.0 84504 12036 pts/2 D+ 14:45 0:00 python listdir.py
905 7078 0.1 0.1 85136 12672 pts/2 D+ 14:45 0:00 python listdir.py
905 7079 0.1 0.1 85916 13360 pts/2 D+ 14:45 0:00 python listdir.py
905 7080 0.1 0.1 85916 13448 pts/2 D+ 14:45 0:00 python listdir.py
905 7081 0.2 0.1 89728 16964 pts/2 D+ 14:45 0:00 python listdir.py
905 7082 0.2 0.1 88268 15776 pts/2 D+ 14:45 0:00 python listdir.py
905 7083 0.2 0.1 88268 15596 pts/2 D+ 14:45 0:00 python listdir.py
905 7084 0.2 0.1 87344 14820 pts/2 D+ 14:45 0:00 python listdir.py
905 7085 0.1 0.1 85136 12628 pts/2 D+ 14:45 0:00 python listdir.py
905 7086 0.2 0.1 86304 13812 pts/2 D+ 14:45 0:00 python listdir.py
(......被截去.......)
机器的内存使用量快速上升。
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
29131 liangqin 16 0 15068 3444 816 R 11.7 0.0 0:00.72 top
16371 kmmaster 16 0 181m 8484 3128 D 5.2 0.1 0:01.20 httpd
5726 kmmaster 15 0 182m 9352 3564 S 3.9 0.1 0:02.24 httpd
32548 kmmaster 16 0 183m 9.8m 3348 D 3.9 0.1 0:06.16 httpd
6199 kmmaster 16 0 183m 9444 3452 D 2.6 0.1 0:01.89 httpd
7697 kmmaster 16 0 182m 8848 3184 D 2.6 0.1 0:01.94 httpd
10536 kmmaster 16 0 181m 8692 3332 D 2.6 0.1 0:01.93 httpd
15102 kmmaster 16 0 181m 8420 3060 D 2.6 0.1 0:01.37 httpd
17993 kmmaster 16 0 181m 8708 3292 D 2.6 0.1 0:04.16 httpd
23185 kmmaster 16 0 182m 9420 3428 D 2.6 0.1 0:00.61 httpd
30189 kmmaster 16 0 181m 8724 3308 D 2.6 0.1 0:05.91 httpd
30337 kmmaster 16 0 183m 9.9m 3448 D 2.6 0.1 0:02.71 httpd
使用strace命令查看D状态的httpd, 都是调用getdents, stat, unlink等IO函数, 如:
stat("/tmp/sess_bc45d5d1dd8739acceff8a3e0fec0585", {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
使用ls, find之类的工具都无法对此目录(指/tmp)进行数据查看。行为freeze。也是进入D状态。
本想使用python的os.listdir函数的。但这个函数是读完目录的entry后才返回list的。 也是要慢很长时间。
于是使用下面的C代码:
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
DIR *dirp = opendir("/tmp");
struct dirent *retval;
long long int t;
for(; ; ){
retval = readdir(dirp);
if (retval == NULL) {break;}
else {printf("%s\n", retval->d_name); t++;}
}
printf("%lld\n", t);
}
可以知道目录文件总数是 221346
httpd的进程数有3K!每个需要session的进程都要读/tmp目录下的entry, 这个行为会对3K数目的httpd进程有很大的影响吗?
于是自己写了个测试代码, 目的就是测试众多的readdir函数是否对进程有影响:
#coding:utf-8
import time
import os
for i in range(300):
pid = os.fork()
if pid > 0:
break
for r in range(30):
time.sleep(0.1)
os.listdir("/tmp")
代码很简单, 但是对于200K条目的directory来说, 很给力!!出现大量的D状态进程:
(........被截去......)
905 7072 0.1 0.0 84244 11628 pts/2 D+ 14:45 0:00 python listdir.py
905 7073 0.1 0.1 85136 12448 pts/2 D+ 14:45 0:00 python listdir.py
905 7074 0.1 0.1 85136 12628 pts/2 D+ 14:45 0:00 python listdir.py
905 7075 0.1 0.1 86304 13588 pts/2 D+ 14:45 0:00 python listdir.py
905 7076 0.1 0.0 84764 12264 pts/2 D+ 14:45 0:00 python listdir.py
905 7077 0.1 0.0 84504 12036 pts/2 D+ 14:45 0:00 python listdir.py
905 7078 0.1 0.1 85136 12672 pts/2 D+ 14:45 0:00 python listdir.py
905 7079 0.1 0.1 85916 13360 pts/2 D+ 14:45 0:00 python listdir.py
905 7080 0.1 0.1 85916 13448 pts/2 D+ 14:45 0:00 python listdir.py
905 7081 0.2 0.1 89728 16964 pts/2 D+ 14:45 0:00 python listdir.py
905 7082 0.2 0.1 88268 15776 pts/2 D+ 14:45 0:00 python listdir.py
905 7083 0.2 0.1 88268 15596 pts/2 D+ 14:45 0:00 python listdir.py
905 7084 0.2 0.1 87344 14820 pts/2 D+ 14:45 0:00 python listdir.py
905 7085 0.1 0.1 85136 12628 pts/2 D+ 14:45 0:00 python listdir.py
905 7086 0.2 0.1 86304 13812 pts/2 D+ 14:45 0:00 python listdir.py
(......被截去.......)
机器的内存使用量快速上升。
Wednesday, October 6, 2010
broadcast
很少使用UDP协议和原始数据包, 所以对broadcast这种特殊地址使用不多。
知识总是关联在一起的。今天在看LVS-DR模式的配置时,发现对下面的配置有些不理解:
# ifconfig lo:0 IP_Adress broadcast IP_Adress netmask 255.255.255.255 up
# route add -host IP_Adress dev lo:0
* IP_Adress为IP地址。
如果只是为了配置LVS的话,就不需要理会上面的语句背后的原理,但作为技术控,很希望可以知道它背后后原理。
結果发现背后是好大一个坑,最经典的问题就是LVS的ARP问题:
* http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html
都与broadcast有关系. 先对broadcast下手:
为什么 broadcast与IP_Adress相同, 而不是常用的172.16.2.255这种特殊IP?
首先, broadcast有如下几种:
1. layer 2 broadcast
2. layer 3 broadcast
3. unicast
4. multicast
要知道broadcast的作用是"一对多", 一台机器发出的数据多台机器有兴趣接收. 这种特点是TCP协议没有的.
下面使用UDP协议来举个layer 3的例子:
接收端(调用bind函数), 这一端的机器可以多台:
import socket
import sys
x = ('<broadcast>', 51423)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(x)
(buf, address) = s.recvfrom(2048)
s.sendto("Hi", address)
发送端(调用send函数):
import socket
import sys
x = ('<broadcast>', 51423)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto("Hi", x)
(buf, address) = s.recvfrom(2048)
print "Received from %s: %s" % (address, buf)
send端使用的'<broadcast>' 很另类: 不是使用具体的IP地址, 而是使用代名词.
回到上面的ifconfig例子, 这个'<broadcast>' 其实就是NIC里的broadcast参数.
如果NIC的参数不同, '<broadcast>' 代表的意义就不同.
从发送端看:
send函数发出的数据包里的destination地址为'<broadcast>'
从接收端看:
recvfrom函数只接收destination地址为NIC里'<broadcast>' 参数的广播包.
所以, 上面的ifconfig设置明显是不想服务器接收layer 3的广播信息( 例如destination为192.168.0.255这种数据包)
broadcast还有layer 2的. 典型的例子就是arp协议. 使用的以太网广播地址: FF.FF.FF.FF.FF.FF 作为destination
linux下没有CLI接口的命令可以发出arp请求包. 因为arp功能放在kernel中(可以看手册man 7 arp), layer 3的数据压到layer 2时kernel为自动调用arp请求包(如果是需求的话).
如果要手动发出这种请求也是可以的, 比如这段代码: http://svn.pythonfr.org/public/pythonfr/utils/network/arp-flood.py
当ping一个IP时, 系统的arp表示里没有与IP对应的条目时kernel是会发出arp请求包的, 所以为了测试, 可以在清除arp条目的情况下,在两机之间ping对方.
如下代码:
import socket
soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("wlan0",0x0806)) # ether type for ARP
data = soc.recv(1024)
程序属于接收端, 程序运行后会一直block, 直到接收到一个arp请求. 向子网的所有机器询问的MAC, 所以是"一对多", 这时就需要使用到广播地址, layer 2的广播地址为FF.FF.FF.FF.FF.FF.
与layer 3相比, layer 2的广播地址不是在NIC上配置的, 但是LVS-DR模式又希望real server不要响应和发出arp请求, 于是, LVS-DR的arp问题就产生了. 也就是文章开头的route add命令的原理. 至于这个原理这里就不写了. 认真阅读下面的文章即可, 下面的文章涉及了linux kernel的多个版本, 如2.0.x, 2.2.x, 2.6.x.
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html
知识总是关联在一起的。今天在看LVS-DR模式的配置时,发现对下面的配置有些不理解:
# ifconfig lo:0 IP_Adress broadcast IP_Adress netmask 255.255.255.255 up
# route add -host IP_Adress dev lo:0
* IP_Adress为IP地址。
如果只是为了配置LVS的话,就不需要理会上面的语句背后的原理,但作为技术控,很希望可以知道它背后后原理。
結果发现背后是好大一个坑,最经典的问题就是LVS的ARP问题:
* http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html
都与broadcast有关系. 先对broadcast下手:
为什么 broadcast与IP_Adress相同, 而不是常用的172.16.2.255这种特殊IP?
首先, broadcast有如下几种:
1. layer 2 broadcast
2. layer 3 broadcast
3. unicast
4. multicast
要知道broadcast的作用是"一对多", 一台机器发出的数据多台机器有兴趣接收. 这种特点是TCP协议没有的.
下面使用UDP协议来举个layer 3的例子:
接收端(调用bind函数), 这一端的机器可以多台:
import socket
import sys
x = ('<broadcast>', 51423)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(x)
(buf, address) = s.recvfrom(2048)
s.sendto("Hi", address)
发送端(调用send函数):
import socket
import sys
x = ('<broadcast>', 51423)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto("Hi", x)
(buf, address) = s.recvfrom(2048)
print "Received from %s: %s" % (address, buf)
send端使用的'<broadcast>' 很另类: 不是使用具体的IP地址, 而是使用代名词.
回到上面的ifconfig例子, 这个'<broadcast>' 其实就是NIC里的broadcast参数.
如果NIC的参数不同, '<broadcast>' 代表的意义就不同.
从发送端看:
send函数发出的数据包里的destination地址为'<broadcast>'
从接收端看:
recvfrom函数只接收destination地址为NIC里'<broadcast>' 参数的广播包.
所以, 上面的ifconfig设置明显是不想服务器接收layer 3的广播信息( 例如destination为192.168.0.255这种数据包)
从netmask的角度可以这样思考:
ifconfig lo:0 192.168.0.10 broadcast 192.168.0.10 netmask 255.255.255.255可以变形成ifconfig lo:0 192.168.0.10 netmask 255.255.255.255
它们与
ifconfig lo:0 192.168.0.10 netmask 255.255.255.0
是属于不同的subnet, 所以192.168.0.0/24的信息对于网段192.168.0.0/32是不会接收的
这种单一的广播地址被称为 unicastifconfig lo:0 192.168.0.10 broadcast 192.168.0.10 netmask 255.255.255.255可以变形成ifconfig lo:0 192.168.0.10 netmask 255.255.255.255
它们与
ifconfig lo:0 192.168.0.10 netmask 255.255.255.0
是属于不同的subnet, 所以192.168.0.0/24的信息对于网段192.168.0.0/32是不会接收的
broadcast还有layer 2的. 典型的例子就是arp协议. 使用的以太网广播地址: FF.FF.FF.FF.FF.FF 作为destination
linux下没有CLI接口的命令可以发出arp请求包. 因为arp功能放在kernel中(可以看手册man 7 arp), layer 3的数据压到layer 2时kernel为自动调用arp请求包(如果是需求的话).
如果要手动发出这种请求也是可以的, 比如这段代码: http://svn.pythonfr.org/public/pythonfr/utils/network/arp-flood.py
当ping一个IP时, 系统的arp表示里没有与IP对应的条目时kernel是会发出arp请求包的, 所以为了测试, 可以在清除arp条目的情况下,在两机之间ping对方.
如下代码:
import socket
soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) #create the raw-socket
soc.bind(("wlan0",0x0806)) # ether type for ARP
data = soc.recv(1024)
程序属于接收端, 程序运行后会一直block, 直到接收到一个arp请求. 向子网的所有机器询问的MAC, 所以是"一对多", 这时就需要使用到广播地址, layer 2的广播地址为FF.FF.FF.FF.FF.FF.
与layer 3相比, layer 2的广播地址不是在NIC上配置的, 但是LVS-DR模式又希望real server不要响应和发出arp请求, 于是, LVS-DR的arp问题就产生了. 也就是文章开头的route add命令的原理. 至于这个原理这里就不写了. 认真阅读下面的文章即可, 下面的文章涉及了linux kernel的多个版本, 如2.0.x, 2.2.x, 2.6.x.
http://www.austintek.com/LVS/LVS-HOWTO/HOWTO/LVS-HOWTO.arp_problem.html
Monday, October 4, 2010
route table
平时在了解系统的route表和配置系统的route表时, 都是比较喜欢使用route这个命令的. 但是, 本人感觉到此命令输出的結果与一些讲解系统网络的资料对不上号的, 例如:

在Routing Decision处就和route命令的输出結果对不上号:
jessinio@jessinio-laptop:~$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.0.0 0.0.0.0 255.255.255.0 U 2 0 0 wlan0
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 wlan0
0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 wlan0
結果很明显, route输出的結果只是系统发向外面的数据包的routing, 没有陈述数据包进入系统的routing.
这种感觉待续了很久一段时间. 今天看到这样一段话:
文字中提到了,route命令得到的其实是不完全的数据. 在Linux下, 最本地化的应该是ip命令.
google找到一份很老的文档: http://linux-ip.net/html/routing-tables.html 上面写得很清楚了, 如下一小段:
iproute2工具集手册:http://www.policyrouting.org/iproute2.doc.html
在Routing Decision处就和route命令的输出結果对不上号:
jessinio@jessinio-laptop:~$ route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.0.0 0.0.0.0 255.255.255.0 U 2 0 0 wlan0
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 wlan0
0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 wlan0
結果很明显, route输出的結果只是系统发向外面的数据包的routing, 没有陈述数据包进入系统的routing.
这种感觉待续了很久一段时间. 今天看到这样一段话:
Linux has a different approach for routing than other UNIX. The way things are implemented on Linux is more flexible and powerful than traditional ways. Legacy utilities such as ifconfig and route are still valid, but incomplete. This is because they do not give access to the advanced routing layer present on Linux. The utility ip (part of iproute2) is the current tool for networking related stuff under Linux. This tool will be the focus of this section.
文字中提到了,route命令得到的其实是不完全的数据. 在Linux下, 最本地化的应该是ip命令.
google找到一份很老的文档: http://linux-ip.net/html/routing-tables.html 上面写得很清楚了, 如下一小段:
The routing table manipulated by the conventional route command is the main routing table. Additionally, the use of both ip address and ifconfig will cause the kernel to alter the local routing table (and usually the main routing table). For further documentation on how to manipulate the other routing tables, see the command description of ip route.
route命令得到和设置的仅仅是冰山一角。iproute2工具集手册:http://www.policyrouting.org/iproute2.doc.html
Saturday, September 11, 2010
block size
多处都存在block size, 概念同名但是意义不同, 相当迷惑
这哥们就是一个被迷惑的人: http://www.linuxforums.org/forum/misc/5654-linux-disk-block-size-help-please.html
上面的URL列出了如下几种block:
1. Hardware block size, "sector size"
2. Filesystem block size, "block size"
3. Kernel buffer cache block size, "block size"
4. Partition table block size, "cylinder size"
我对fdisk打印的blocks一栏很不解. 需要dig一下.
先来看看fdisk打印出来的block:
jessinio@jessinio-laptop:/ $ sudo fdisk -l
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 803218+ 83 Linux
/dev/sda2 101 30401 243392782+ 8e Linux LVM
上面的内容和下面的是一致的:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 512 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 803218+ 83 Linux
/dev/sda2 101 30401 243392782+ 8e Linux LVM
但是下面的就比较奇怪了:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 1024 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 15200 cylinders
Units = cylinders of 16065 * 1024 = 16450560 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 1606437 83 Linux
/dev/sda2 101 30401 486785565 8e Linux LVM
指定更大的硬件sector size反而block增加, 这是为什么呢?。下面是fdisk的相关代码:
sector_size变量的来源:
759 static void
760 get_sectorsize(int fd) {
761 #if defined(BLKSSZGET)
762 if (!user_set_sector_size &&
763 linux_version_code() >= MAKE_VERSION(2,3,3)) {
764 int arg;
765 if (ioctl(fd, BLKSSZGET, &arg) == 0)
766 sector_size = arg;
767 if (sector_size != DEFAULT_SECTOR_SIZE)
768 printf(_("Note: sector size is %d (not %d)\n"),
769 sector_size, DEFAULT_SECTOR_SIZE);
770 }
771 #else
772 /* maybe the user specified it; and otherwise we still
773 have the DEFAULT_SECTOR_SIZE default */
774 #endif
775 }
DEFAULT_SECTOR_SIZE 在fdisk.h中定义是
#define DEFAULT_SECTOR_SIZE 512
或者是用户指定的user_set_sector_size:sector_size = atoi(optarg);
打印时使用的代码是:
1731 unsigned int psects = get_nr_sects(p);
1732 unsigned int pblocks = psects;
1733 unsigned int podd = 0;
1734
1735 if (sector_size < 1024) {
1736 pblocks /= (1024 / sector_size);
1737 podd = psects % (1024 / sector_size);
1738 }
1739 if (sector_size > 1024)
1740 pblocks *= (sector_size / 1024);
1741 printf(
1742 "%s %c %11lu %11lu %11lu%c %2x %s\n",
1743 partname(disk_device, i+1, w+2),
1744 /* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
1745 ? '*' : '?',
1746 /* start */ (unsigned long) cround(get_partition_start(pe)),
1747 /* end */ (unsigned long) cround(get_partition_start(pe) + psects
1748 - (psects ? 1 : 0)),
1749 /* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
1750 /* type id */ p->sys_ind,
1751 /* type name */ (type = partition_type(p->sys_ind)) ?
1752 type : _("Unknown"));
1753 check_consistency(p, i);
1. 当sector_size刚好等于1024时, 打印出的正好是sector的数目。也是partition的大小(同size概念)
2. 当sector_size不等于1024时,把sector数目和sector_size结合起来換算成大小(同size概念)
可见, fdisk打印的Blocks一栏其实是partition的大小。下面测试一下:
$ sudo mount /dev/sda1 /media/disk/
$ df /media/disk/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 790556 48176 702220 7% /media/disk
790556 是文件系统总大小。
上面的fdisk -b 1024 -l 命令得到的1606437是sector的数目。这样计算:
1606437 * 512 / 1024 =803218 是约等于790556 的。partition的大小是比file system大是因为file system需要存放一些信息.
2. 不加-b参数的fdisk命令打印的Blocks一栏其实是表示partition的大小(以K为单位)
3. 还没有能力找出Kernel buffer cache block size, "block size" 这一条的实际代码
这哥们就是一个被迷惑的人: http://www.linuxforums.org/forum/misc/5654-linux-disk-block-size-help-please.html
上面的URL列出了如下几种block:
1. Hardware block size, "sector size"
2. Filesystem block size, "block size"
3. Kernel buffer cache block size, "block size"
4. Partition table block size, "cylinder size"
我对fdisk打印的blocks一栏很不解. 需要dig一下.
先来看看fdisk打印出来的block:
jessinio@jessinio-laptop:/ $ sudo fdisk -l
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 803218+ 83 Linux
/dev/sda2 101 30401 243392782+ 8e Linux LVM
上面的内容和下面的是一致的:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 512 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 803218+ 83 Linux
/dev/sda2 101 30401 243392782+ 8e Linux LVM
但是下面的就比较奇怪了:
jessinio@jessinio-laptop:/media/82d236f2-3592-4040-801c-3c2049ddfb95$ sudo fdisk -b 1024 -l
Warning: the -b (set sector size) option should be used with one specified device
Disk /dev/sda: 250.1 GB, 250059350016 bytes
255 heads, 63 sectors/track, 15200 cylinders
Units = cylinders of 16065 * 1024 = 16450560 bytes
Disk identifier: 0x00038329
Device Boot Start End Blocks Id System
/dev/sda1 * 1 100 1606437 83 Linux
/dev/sda2 101 30401 486785565 8e Linux LVM
指定更大的硬件sector size反而block增加, 这是为什么呢?。下面是fdisk的相关代码:
sector_size变量的来源:
759 static void
760 get_sectorsize(int fd) {
761 #if defined(BLKSSZGET)
762 if (!user_set_sector_size &&
763 linux_version_code() >= MAKE_VERSION(2,3,3)) {
764 int arg;
765 if (ioctl(fd, BLKSSZGET, &arg) == 0)
766 sector_size = arg;
767 if (sector_size != DEFAULT_SECTOR_SIZE)
768 printf(_("Note: sector size is %d (not %d)\n"),
769 sector_size, DEFAULT_SECTOR_SIZE);
770 }
771 #else
772 /* maybe the user specified it; and otherwise we still
773 have the DEFAULT_SECTOR_SIZE default */
774 #endif
775 }
DEFAULT_SECTOR_SIZE 在fdisk.h中定义是
#define DEFAULT_SECTOR_SIZE 512
或者是用户指定的user_set_sector_size:sector_size = atoi(optarg);
打印时使用的代码是:
1731 unsigned int psects = get_nr_sects(p);
1732 unsigned int pblocks = psects;
1733 unsigned int podd = 0;
1734
1735 if (sector_size < 1024) {
1736 pblocks /= (1024 / sector_size);
1737 podd = psects % (1024 / sector_size);
1738 }
1739 if (sector_size > 1024)
1740 pblocks *= (sector_size / 1024);
1741 printf(
1742 "%s %c %11lu %11lu %11lu%c %2x %s\n",
1743 partname(disk_device, i+1, w+2),
1744 /* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
1745 ? '*' : '?',
1746 /* start */ (unsigned long) cround(get_partition_start(pe)),
1747 /* end */ (unsigned long) cround(get_partition_start(pe) + psects
1748 - (psects ? 1 : 0)),
1749 /* odd flag on end */ (unsigned long) pblocks, podd ? '+' : ' ',
1750 /* type id */ p->sys_ind,
1751 /* type name */ (type = partition_type(p->sys_ind)) ?
1752 type : _("Unknown"));
1753 check_consistency(p, i);
1. 当sector_size刚好等于1024时, 打印出的正好是sector的数目。也是partition的大小(同size概念)
2. 当sector_size不等于1024时,把sector数目和sector_size结合起来換算成大小(同size概念)
可见, fdisk打印的Blocks一栏其实是partition的大小。下面测试一下:
$ sudo mount /dev/sda1 /media/disk/
$ df /media/disk/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 790556 48176 702220 7% /media/disk
790556 是文件系统总大小。
上面的fdisk -b 1024 -l 命令得到的1606437是sector的数目。这样计算:
1606437 * 512 / 1024 =803218 是约等于790556 的。partition的大小是比file system大是因为file system需要存放一些信息.
总
1. 要想得到一个partition占有用多少个sector的话, 可以使用fdisk -b 1024这种方式得到2. 不加-b参数的fdisk命令打印的Blocks一栏其实是表示partition的大小(以K为单位)
3. 还没有能力找出Kernel buffer cache block size, "block size" 这一条的实际代码
Wednesday, September 8, 2010
pkg-config
感觉centOS上的fuse版本太低, 还是从源代码安装。
简单编译后:
./configure --prefix=/usr/local/fuse
fuse-python-binding就无法安装。问题是fuse-python-binding的setup.py需要使用pkg-config取得编译参数。
pkg-config --list-all |grep fuse
无法找到pkg-config需要的*.pc metainfornation文件。
可以手工增加:
$ PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ pkg-config --list-all |grep fuse
fuse fuse - Filesystem in Userspace
所以, 下面的方法可以安装:
$ sudo PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ python setup.py install
[jessinio@niowork site-packages]$ /usr/local/python2.6/bin/python -c "import fuse"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "fuse.py", line 27, in <module>
from fuseparts._fuse import main, FuseGetContext, FuseInvalidate
ImportError: libfuse.so.2: cannot open shared object file: No such file or directory
需要增加lib路径:
$ sudo sh -c "echo /usr/local/fuse/lib >> /etc/ld.so.conf.d/fuse.conf "
$ sudo ldconfig
简单编译后:
./configure --prefix=/usr/local/fuse
fuse-python-binding就无法安装。问题是fuse-python-binding的setup.py需要使用pkg-config取得编译参数。
pkg-config --list-all |grep fuse
无法找到pkg-config需要的*.pc metainfornation文件。
可以手工增加:
$ PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ pkg-config --list-all |grep fuse
fuse fuse - Filesystem in Userspace
所以, 下面的方法可以安装:
$ sudo PKG_CONFIG_PATH=/usr/local/fuse/lib/pkgconfig/ python setup.py install
[jessinio@niowork site-packages]$ /usr/local/python2.6/bin/python -c "import fuse"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "fuse.py", line 27, in <module>
from fuseparts._fuse import main, FuseGetContext, FuseInvalidate
ImportError: libfuse.so.2: cannot open shared object file: No such file or directory
需要增加lib路径:
$ sudo sh -c "echo /usr/local/fuse/lib >> /etc/ld.so.conf.d/fuse.conf "
$ sudo ldconfig
Saturday, September 4, 2010
prefork服务器方式
WEB服务器一般都有两种模式处理动态服务:
1. prefork
2. thread
一种是使用多进程, 另一种是使用多线程. 它们的具体的实现方式自己其实并不清楚.
最近公司的python WEB服务使用较多的内存. 为了清楚其中的问题. 需要学习flup(django需要此库)代码. ( 人家写的代码实在好看 )
很多软件都有prefork方式, 下面是prefork模型:

每个nginx子进程都分别调用accept得到用户发来的80端口请求.
之所以每个子进程都可以调用accept得到同一个socket的请求, 是因为fork出的子进程的file descriptor是指向同一个实体.
这样实现了多进程竟争得到socket请求.
每个子进程又可以使用epoll, 线程等方式并发处理众多来自80端口的请求. fast cgi server也是类似的方法.
nginx与fast cgi server之间使用socket通信, 使用fast cgi协议.

每个flup work某一时刻只服务一个页面请求. 完成请求后可以重新接受请求.
使用prefork模型的方式。 所以在PreforkServer类中。
父进程的主体是一个loop:
119 # Main loop.
120 while self._keepGoing:
121 # Maintain minimum number of children.
122 while len(self._children) < self._maxSpare:
123 if not self._spawnChild(sock): break
可以看出, 父进程是永远期待子进程的数目为一个数值的。这个数值为maxSpare
粗粗看上去, 有些野。但是父进程是有回收子进程的策略的, 如下:
169 # See who and how many children are available.
170 availList = filter(lambda x: x[1]['avail'],
self._children.items())
171 avail = len(availList)
上面的代码可以知道, 父进程会一直收集可用的子进程。 所谓可用是没有在工作
的子进程, 可以从子进程的代码中看出, 如下:
370 # Notify parent we're no longer available.
371 self._notifyParent(parent, '\x00')
372
373 # Do the job.
374 self._jobClass(clientSock, addr, *self._jobArgs).run()
上面的代码是子进程在调用jobClass.run之前, 通知父进程自己是 no longer
available的。
父进程维护着“可用的子进程“数目是为了可以了解负载情况, 判断是否需要产生
更多的子进程, 如下:
172
173 if avail < self._minSpare:
174 # Need to spawn more children.
175 while avail < self._minSpare and \
176 len(self._children) < self._maxChildren:
177 if not self._spawnChild(sock): break
178 avail += 1
上面的代码使用了两个数据: minSpare和maxChildren。
minSpare是表示最少“可用子进程“数
maxChildren是表示最大“子进程”数, 是空闲与工作的子进程总数
如果“可用子进程”数还剩一定数据,会被回收, 如下:
179 elif avail > self._maxSpare:
180 # Too many spares, kill off the extras.
181 pids = [x[0] for x in availList]
182 pids.sort()
183 pids = pids[self._maxSpare:]
184 for pid in pids:
185 d = self._children[pid]
186 d['file'].close()
187 d['file'] = None
188 d['avail'] = False
从上面的代码可以看到, fast cgi在启动时的使用到的三个参数的作用应该是:
minspare: 最小“空闲进程数“
maxspare: 常规进程数,即fast cgi启动后, fastcgi进程数是大于等于此值
maxChildren: 最大进程数, 此值主要是用于防止内存被使用完的。
1. prefork
2. thread
一种是使用多进程, 另一种是使用多线程. 它们的具体的实现方式自己其实并不清楚.
最近公司的python WEB服务使用较多的内存. 为了清楚其中的问题. 需要学习flup(django需要此库)代码. ( 人家写的代码实在好看 )
很多软件都有prefork方式, 下面是prefork模型:
每个nginx子进程都分别调用accept得到用户发来的80端口请求.
之所以每个子进程都可以调用accept得到同一个socket的请求, 是因为fork出的子进程的file descriptor是指向同一个实体.
这样实现了多进程竟争得到socket请求.
每个子进程又可以使用epoll, 线程等方式并发处理众多来自80端口的请求. fast cgi server也是类似的方法.
nginx与fast cgi server之间使用socket通信, 使用fast cgi协议.
每个flup work某一时刻只服务一个页面请求. 完成请求后可以重新接受请求.
使用prefork模型的方式。 所以在PreforkServer类中。
父进程的主体是一个loop:
119 # Main loop.
120 while self._keepGoing:
121 # Maintain minimum number of children.
122 while len(self._children) < self._maxSpare:
123 if not self._spawnChild(sock): break
可以看出, 父进程是永远期待子进程的数目为一个数值的。这个数值为maxSpare
粗粗看上去, 有些野。但是父进程是有回收子进程的策略的, 如下:
169 # See who and how many children are available.
170 availList = filter(lambda x: x[1]['avail'],
self._children.items())
171 avail = len(availList)
上面的代码可以知道, 父进程会一直收集可用的子进程。 所谓可用是没有在工作
的子进程, 可以从子进程的代码中看出, 如下:
370 # Notify parent we're no longer available.
371 self._notifyParent(parent, '\x00')
372
373 # Do the job.
374 self._jobClass(clientSock, addr, *self._jobArgs).run()
上面的代码是子进程在调用jobClass.run之前, 通知父进程自己是 no longer
available的。
父进程维护着“可用的子进程“数目是为了可以了解负载情况, 判断是否需要产生
更多的子进程, 如下:
172
173 if avail < self._minSpare:
174 # Need to spawn more children.
175 while avail < self._minSpare and \
176 len(self._children) < self._maxChildren:
177 if not self._spawnChild(sock): break
178 avail += 1
上面的代码使用了两个数据: minSpare和maxChildren。
minSpare是表示最少“可用子进程“数
maxChildren是表示最大“子进程”数, 是空闲与工作的子进程总数
如果“可用子进程”数还剩一定数据,会被回收, 如下:
179 elif avail > self._maxSpare:
180 # Too many spares, kill off the extras.
181 pids = [x[0] for x in availList]
182 pids.sort()
183 pids = pids[self._maxSpare:]
184 for pid in pids:
185 d = self._children[pid]
186 d['file'].close()
187 d['file'] = None
188 d['avail'] = False
从上面的代码可以看到, fast cgi在启动时的使用到的三个参数的作用应该是:
minspare: 最小“空闲进程数“
maxspare: 常规进程数,即fast cgi启动后, fastcgi进程数是大于等于此值
maxChildren: 最大进程数, 此值主要是用于防止内存被使用完的。
Subscribe to:
Posts (Atom)