« September 2006 |
(回到Blog入口)
| November 2006 »
October 2006 歸檔
#2: 今天 Jollen 要介紹的題目是 "Mesh Router",實作平臺是 Kendin KS8695P 與 embedded Linux 系統。我們在 Kendin KS8695P (ARM9) 的平臺上嵌入 embedded Linux 系統,透過此平臺與 mesh wireless 的 embedded Linux 系統,將能實作出 mesh networking 的系統。
今天我們的重點 (Lecture 8) 是介紹 open source 解決方案與 mesh networking;同時我們也會做一個簡單的 demo。
簡報下載
#3: mesh networking 可以取代 Wi-Fi "hot spots" 的架構,並且簡省無線網路的佈署成本,由於我們以現有的 802.11a+g 的無線網卡來實作,因此可以使用許多現成的 open source 軟體來配合。以藉此達成單點對多點 (point to multipoint)、多點對多點 (multipoint to multipoint) 或是單點對單點 (point-to-point) 的架構實作。
#6: 這是我們所期望做到的規格 (specification),很有趣的是,開放源碼套件居然能滿足我們所開出的所有規格,這意謂我們的 project 需要自己開發軟體的機會幾乎是 0%;事實上,我們 90% 以上的工作都是在做系統整合 (Linux administration) 和 UI (web-based) 的開發。
#7: 這是一個實際 (real-world) 的案例,讓我們來說明我們倒底在 root filesystem 裡放了哪些東西,以及「如何加入」這些東西。
#8: 要 build 一個基本的 wireless 嵌入式 Linux 系統 (root filesystem),我們會需要這些基本的開放源碼套件,另外由於 zeroconf 遭遇到專利問題,因此我們並沒有在這份簡單裡展示 zeroconf IP 的功能。
#9: 再來是 Linux 的無線網路解決方案,在驅動程式方面,我們使用的 Atheros 與 Prism 晶片都有支援。在 user application 方面,wireless routing protocol 的解決方案是 quagga,這是一個相當知名的 open source 專案。另外,wireless tools 是必備的,因此我們要透過它來設定無線網路。
#16: 這是我們利用 iwconfig 在 Kendin 平臺上啟動無線網路的畫面,ath0 介面是 Atheros 網卡 (802.11g),eth2 是 Intersil 網路 (802.11b/g)。
#17: 我們把 ath0 設定成 "ad-hoc" 模式。
#18: 利用 'iwlist' 指令偵測 channel。
#19: 利用 'iwlist' 掃描 eth2 介面。
ps. 不知道大家還想要哪一頁的詳細講稿 @@"
在建立 embedded Linux 系統 (root filesystem) 時,程式庫相依 (library dependencies) 的議題是相當重要的一個題目。
當 root filesystem 缺少必要的 library 時,程式當然是無法執行的,甚致系統也會無法順利啟動。依據 Jollen 在「Embedded Linux / ARM9 開發實戰」的課程所提的幾個觀念,我們可以了解到在建構 embedded Linux 系統時,應具備的正確觀念與基本能力。
我們把「如何找出所需的 library」方法整理出 3 項的基本要點,依照這 3 種基本款來加入 library 將能解決幾乎所有的 library dependency 問題,這 3 種項基本要點為:
(1) 先利用 cross toolchain 的 objdump 觀察「NEEDED」的項目,加入 library。
(2) 再檢查這些 library 是否相依其它 library。
(3) 最後要檢視應用程式是否使用到需要特定 library 的「service」。
要點 1. 跟 2. 對大家來說沒有什麼問題,要點 3. 在我們的 training 課程裡,我們以建構 thttpd (embedded Web server) 的實際案例來做講解。
關於建構 thttpd 的案例
thttpd 使用到 NSS (Name Service Switch),因此若沒有將 libnss_SERVICE.so 加到 root filesystem,thttpd 在執行時可能會遇到一些奇怪的問題。舉個例子,當 thttpd 透過 /etc/passwd 去尋找 (查詢) UNIX user 時,會用到 libnss_files.so (不讀 /etc/shadow),因此會看到以下的錯誤訊息:
unknown user - root
出現這個錯誤的原因是 thttpd 讀不到 'root' 使用者,要深入探討這個問題的原理,必須從以下的程式碼片斷開始探討:
403 /* If we're root and we're going to become another user, get the uid /gid
404 ** now.
405 */
406 if ( getuid() == 0 )
407 {
408 pwd = getpwnam( user );
409 if ( pwd == (struct passwd*) 0 )
410 {
411 syslog( LOG_CRIT, "unknown user - '%.80s'", user );
412 (void) fprintf( stderr, "%s: unknown user - '%s'\n", argv0, user );
413 exit( 1 );
414 }
415 uid = pwd->pw_uid;
416 gid = pwd->pw_gid;
417 }
這段程式碼是 thttpd 2.25b 的程式片斷,位於 thttpd.c 的 main() 函數裡。關於 libnss_SERVICE.so 的議題,Jollen 打算另外再做討論,因為還會與 libc 有關係。
在這裡我們由系統建構的角度來看這個問題。因為我們已經習慣用 objdump 來觀察程式的相依 library,所以當 objdump 的畫面跟我們預期的不同時,經常一時無法反應過來。例如,以下的訊息是我們所「預期」的:
# /opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu-objdump -x thttpd|more
...
Dynamic Section:
NEEDED libcrypt.so.1
NEEDED libnss_files.so.2
NEEDED libc.so.6
...
但是實際的訊息卻是像這樣的:
# /opt/crosstool/gcc-3.4.1-glibc-2.3.3/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu-objdump -x thttpd|more
...
Dynamic Section:
NEEDED libcrypt.so.1
NEEDED libc.so.6
...
我們可以用一知半解的思考邏輯來解決問題:thttpd 呼叫到 getpwnam() 函數,此函數由 libnss_compat 提供,因此解決方案是把 libnss_files.so 加到 root filesystem 裡即可。
且慢!前面才講到 libnss_compat,怎麼後面是把 libnss_files 加到 root filesystem?是這樣的,libnss_compat 用來讀 /etc/shadow,但是現在我們只需要由 /etc/passwd 讀 Unix user,所以使用 libnss_files.so 就行了。
執行 thttpd 的話,再加上指定 username 的參數來執行:
# thttpd -p 80 -d /var/www -u root
libnss_SERVICE.so 是包含在 glibc 裡的程式庫,因此可以直接由 cross toolchain 裡取得,不必再另行建置。
有關 NSS (Name Service Switch) 可參考以下網頁:
Linux / Unix Command: nsswitch.conf - http://linux.about.com/od/commands/l/blcmdl5_nsswitc.htm
其它網路資源:
http://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html
http://mirrors.usc.edu/pub/gnu/Manuals/glibc-2.2.3/html_chapter/libc_28.html
此處我們以「service」的角度來探討這個問題:因為 thttpd 使用到 Name Service Switch,所以需要加入 libnss_SERVICE.so。另外一種探討的角度是:由 programming 的角度來思考,大家可以試著去研究這個問題,還挺好玩的!
附帶一提,如果要讀 shadow passwd 的話,是使用 libnss_compat.so。
有些 C 函數的運作會依據 localhost 的設定而有不同行為,而這些設定的做法是透過「設定檔」(eg. /etc/services) 來實現。目前在 GNU/Linux 系統底下,可以看到許多這樣的設定檔,我們把這些設定檔稱為 system database,這些資料庫主要是以文字檔方式儲存重要的系統資訊,例如: /etc/passwd 存放使用者名稱、/etc/services 存放網路服務的通訊埠 (port) 設定等等。
GNU C library 實作的 "Name Service Switch" 函數群便是用來讀取所有 system database 內容的介面!
System Database
NSS 支援 11 種資料庫名稱:aliases、ethers、group、hosts、netgroup、networks、protocols、passwd、rpc、services 與 shadow。分別說明如下。
aliases: Mail 別名
ethers: Ethernet 號碼
group: 使用者群組資料庫,即 /etc/group
hosts: Host names 與 IP 對應資料庫,即 /etc/hosts 或是利用 name server 轉換
netgroup: "hostname username domainname" 的組合稱為 netgroup
networks: 即 /etc/networks
protocols: 通訊協定資料庫,即 /etc/protocols
passwd: 使用者名稱資料庫,即 /etc/passwd
rpc: Remote procedure call 資料庫
services: 即 /etc/services 資料庫
shadow: 即 /etc/shadow 檔
NSS Service 與 Lookup
NSS 支援 7 種服務類型,說明如下。
1. nisplus (or nis+): 使用 NIS+ (NIS version 3) 服務
2, nis (or yp): 使用 NIS (NIS version 2) 服務 (也叫 YP, YellowPage)
3. dns: 使用 DNS (Domain Name Service) 服務
4. files: 使用一般的檔案讀取服務
5. db: 使用 database (.db) 檔案讀取服務
6. compat: 使用 NIS compat mode 服務
7. hesiod: 使用 Hesiod 服務做 user lookups
GNU 的實作是把每一個服務 (service) 實作成不同的 module (shared library),因此可以在 GNU/Linux 系統底下找到這些相對應的 shared libraries:
libnss_nisplus.so.2
libnss_nis.so.2
libnss_dns.so.2
libnss_files.so.2
libnss_compat.so.2
libnss_hesiod.so.2
不過其實還有下面 3 個:
/lib/libnss_ldap.so.2
/lib/libnss_winbind.so.2
/lib/libnss_wins.so.2
GNU 的 NSS module 是以 libnss_SERVICE.so.2 來命名。
在這些 module (library) 裡的函數,是無法讓程式直接使用的,因此了解這些 module 裡的函數如何被使用 (呼叫) 是一個重要且有趣的題目。
查詢前面所提 11 種資料庫資訊的動作稱為 lookup,lookup 的方法便是 NSS 的服務類型 (NSS service),也就是我們可以利用以上共 7 種方式來查詢 system database;不過,以 files、db、nis 與 nisplus 這 4 種方式是比較常用的。
由此可知,不同的 system database 可以用不同的服務來做查詢。因此,系統管理員必須告訴 NSS,我們想要他利用哪一種服務類型,來查詢 (lookup) 指定的 system database。這個動作的管理方式便是透過 /etc/nsswitch.conf 設定檔來完成。
/etc/nsswitch.conf
看一下 glibc-2.3.3 預設定 nsswitch.conf 設定檔內容如下:
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
#
passwd: db files
group: db files
shadow: db files
hosts: files dns
networks: files dns
protocols: db files
services: db files
ethers: db files
rpc: db files
netgroup: db files
這樣其實就很清楚了,例如:passwd 資料庫 (/etc/passwd) 的讀取方式 (lookup service) 有 db/files 二種。以 embedded Linux 系統來說,我們會這樣設定:
passwd: files
也就是說,直接以檔案讀取方式來查詢 /etc/passwd。那麼,之前提過的 embedded Linux 系統建置之 thttpd 個案分析,為何需要 libnss_files.so.2 檔案,觀念就很清楚了。
此外,大家也可以了解一下 red hat linux 或其它 Linux distribution 的 nsswitch.conf 設定佈署方式。
這個部份的文件主要是 glibc 的手冊,大家可參考 http://www.gnu.org/software/libc/manual/html_node/Name-Service-Switch.html#Name-Service-Switch
-- jollen
作者/陳俊宏
http://www.jollen.org
我們以一個 'gethostbyname' 的例子來說明 NSS 的運作原理
假設我們想要查詢網路上某台 host 的 IP 位址,那麼 GNU C Library 手冊告訴我們說,有一個 gethostbyname() 的函數可以使用。
不過,在真正寫 code 時,其實並不建議呼叫此函數,在說明原因前,有一句必名言是大家一定要銘記在心的:
Multi-threaded safe code must be reentrant.
由於 gethostbyname() 並非 reentrant 的版本;所以,呼叫 gethostbyname() 並不是正確寫法,我們必須改成呼叫 reentrant 的版本:gethostbyname_r()。
NSS module 裡 non-reentrant 的函數,是不能使用在 multi-threaded applications 的設計上的,但是根據 NSS manual 的解釋,其實 gethostbyename() 與 gethostbyname_r() 都會呼叫到 NSS module 裡相同的函數,原因是 NSS module 只提供 reentrant 版本的 gethostbyname() 服務。
接下來讓我們來討論,gethostbyname() 與 gethostbyname_r() 倒底會呼叫到 NSS module 裡的哪一個函數。
_nss_service_function
當我們呼叫 gethostbyname_r() 函數時 (或 gethostbyname),假設我們在 /etc/nsswitch.conf 裡有一行這樣的設定:
hosts: files
那麼根據之前 Jollen 在 Blog 裡的說明 ,此時會使用到的 NSS module 會是 libnss_files.so.2,並且以下的 routine 會被呼叫:
_nss_files_gethostbyname_r
查看一下:
# nm /lib/libnss_files.so.2 |egrep "gethostbyname"
00004320 T _nss_files_gethostbyname2_r
00003ba0 T _nss_files_gethostbyname_r
現在我們終於知道了,當我們呼叫查詢的函數 'function' 時,在 libnss_SERVICE.so.2 裡的相對應函數便會被呼叫,此函數的 naming 方式為:
_nss_service_function
另外,NSS module 僅包含 reentrant 的版本。
最後我們要講的是,gethostbyename() 與 gethostbyname_r(),或是之前提到的 getpwnam() 都是實作在 libc.so.6 裡的。For example:
# nm /lib/libc.so.6 |egrep "T.gethostbyname"
000f72b0 T gethostbyname
000f7480 T gethostbyname2
000f78c0 T gethostbyname2_r@GLIBC_2.0
000f7660 T gethostbyname2_r@@GLIBC_2.1.2
000f7b80 T gethostbyname_r@GLIBC_2.0
000f7930 T gethostbyname_r@@GLIBC_2.1.2
# nm /lib/libc.so.6 |egrep "T.getpwnam"
000acf50 T getpwnam
000ad5c0 T getpwnam_r@GLIBC_2.0
000ad440 T getpwnam_r@@GLIBC_2.1.2
這就是為什麼我們在 ldd (or objdump) 時,都看不到 libnss_SERVICE.so.6 的道理.當我們做查詢時,NSS 才去載入對應的 service module。
以下是 Linux 2.4.29 的 system call 整理表格,提供給「Embedded Linux 嵌入式系統實作演練」的讀者您做參考。這是一張很方便的表格,可以取代 unistd.h 與 "man"。
這張工具表格可以幫助我們:
1. 最主要的目的:當然是研究作業系統,了解 Linux 提供的 sytsem call service。
2. Trace kernel.
3. Writing shellcode.
供您參考 :)
Linux (kernel 2.4.29) System Call Table
1. sys_ni_syscall 為保留號碼
2. 更新日期: 2006/10/07
3. 其實與 linux 2.4.22 是相同的,因此亦可參考我們之前 (3 年前) 整理的 LSCT。
no
Syscall
Prototype decl.
0
sys_ni_syscall
long sys_ni_syscall(void)
1
sys_exit
long sys_exit(int error_code)
2
sys_fork
int sys_fork(struct pt_regs regs)
3
sys_read
ssize_t sys_read(unsigned int fd, char *buf, size_t count)
4
sys_write
ssize_t sys_write(unsigned int fd, const char *buf, size_t count)
5
sys_open
long sys_open(const char *filename, int flags, int mode)
6
sys_close
long sys_close(unsigned int fd)
7
sys_waitpid
long sys_waitpid(pid_t pid, unsigned int *stat_addr, int options)
8
sys_creat
long sys_creat(const char *pathname, int mode)
9
sys_link
long sys_link(const char *oldname, const char *newname)
10
sys_unlink
long sys_unlink(const char *pathname)
11
sys_execve
int sys_execve(struct pt_regs regs)
12
sys_chdir
long sys_chdir(const char *filename)
13
sys_time
long sys_time(int *tloc)
14
sys_mknod
long sys_mknod(const char *filename, int mode, dev_t dev)
15
sys_chmod
long sys_chmod(const char *filename, mode_t mode)
16
sys_lchown16
long sys_lchown16(const char *filename, old_uid_t user, old_gid_t group)
17
sys_ni_syscall
long sys_ni_syscall(void)
18
sys_stat
long sys_stat(char *filename, struct __old_kernel_stat *statbuf)
19
sys_lseek
off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
20
sys_getpid
long sys_getpid(void)
21
sys_mount
long sys_mount(char *dev_name, char *dir_name, char *type, unsigned long flags, void *data)
22
sys_oldumount
long sys_oldumount(char *name)
23
sys_setuid16
long sys_setuid16(old_uid_t uid)
24
sys_getuid16
long sys_getuid16(void)
25
sys_stime
long sys_stime(int *tptr)
26
sys_ptrace
int sys_ptrace(long request, long pid, long addr, long data)
27
sys_alarm
unsigned long sys_alarm(unsigned int seconds)
28
sys_fstat
long sys_fstat(unsigned int fd, struct __old_kernel_stat *statbuf)
29
sys_pause
int sys_pause(void)
30
sys_utime
long sys_utime(char *filename, struct utimbuf *times)
31
sys_ni_syscall
long sys_ni_syscall(void)
32
sys_ni_syscall
long sys_ni_syscall(void)
33
sys_access
long sys_access(const char *filename, int mode)
34
sys_nice
long sys_nice(int increment)
35
sys_ni_syscall
long sys_ni_syscall(void)
36
sys_sync
long sys_sync(void)
37
sys_kill
long sys_kill(int pid, int sig)
38
sys_rename
long sys_rename(const char *oldname, const char *newname)
39
sys_mkdir
long sys_mkdir(const char *pathname, int mode)
40
sys_rmdir
long sys_rmdir(const char *pathname)
41
sys_dup
long sys_dup(unsigned int fildes)
42
sys_pipe
int sys_pipe(unsigned long *fildes)
43
sys_times
long sys_times(struct tms *tbuf)
44
sys_ni_syscall
long sys_ni_syscall(void)
45
sys_brk
unsigned long sys_brk(unsigned long brk)
46
sys_setgid16
long sys_setgid16(old_gid_t gid)
47
sys_getgid16
long sys_getgid16(void)
48
sys_signal
unsigned long sys_signal(int sig, __sighandler_t handler)
49
sys_geteuid16
long sys_geteuid16(void)
50
sys_getegid16
long sys_getegid16(void)
51
sys_acct
long sys_acct(const char *name)
52
sys_umount
long sys_umount(char *name, int flags)
53
sys_ni_syscall
long sys_ni_syscall(void)
54
sys_ioctl
long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
55
sys_fcntl
long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
56
sys_ni_syscall
long sys_ni_syscall(void)
57
sys_setpgid
long sys_setpgid(pid_t pid, pid_t pgid)
58
sys_ni_syscall
long sys_ni_syscall(void)
59
sys_olduname
int sys_olduname(struct oldold_utsname *name)
60
sys_umask
long sys_umask(int mask)
61
sys_chroot
long sys_chroot(const char *filename)
62
sys_ustat
long sys_ustat(dev_t dev, struct ustat *ubuf)
63
sys_dup2
long sys_dup2(unsigned int oldfd, unsigned int newfd)
64
sys_getppid
long sys_getppid(void)
65
sys_getpgrp
long sys_getpgrp(void)
66
sys_setsid
long sys_setsid(void)
67
sys_sigaction
int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact)
68
sys_sgetmask
long sys_sgetmask(void)
69
sys_ssetmask
long sys_ssetmask(int newmask)
70
sys_setreuid16
long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
71
sys_setregid16
long sys_setregid16(old_gid_t rgid, old_gid_t egid)
72
sys_sigsuspend
int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
73
sys_sigpending
long sys_sigpending(old_sigset_t * set)
74
sys_sethostname
long sys_sethostname(char *name, int len)
75
sys_setrlimit
long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
76
sys_old_getrlimit
long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim)
77
sys_getrusage
long sys_getrusage(int who, struct rusage *ru)
78
sys_gettimeofday
long sys_gettimeofday(struct timeval *tv, struct timezone *tz)
79
sys_settimeofday
long sys_settimeofday(struct timeval *tv, struct timezone *tz)
80
sys_getgroups16
long sys_getgroups16(int gidsetsize, old_gid_t * grouplist)
81
sys_setgroups16
long sys_setgroups16(int gidsetsize, old_gid_t * grouplist)
82
old_select
int old_select(struct sel_arg_struct *arg)
83
sys_symlink
long sys_symlink(const char *oldname, const char *newname)
84
sys_lstat
long sys_lstat(char *filename, struct __old_kernel_stat *statbuf)
85
sys_readlink
long sys_readlink(const char *path, char *buf, int bufsiz)
86
sys_uselib
long sys_uselib(const char *library)
87
sys_swapon
long sys_swapon(const char *specialfile, int swap_flags)
88
sys_reboot
long sys_reboot(int magic1, int magic2, unsigned int cmd, void *arg)
89
old_readdir
int old_readdir(unsigned int fd, void *dirent, unsigned int count)
90
old_mmap
int old_mmap(struct mmap_arg_struct *arg)
91
sys_munmap
long sys_munmap(unsigned long addr, size_t len)
92
sys_truncate
long sys_truncate(const char *path, unsigned long length)
93
sys_ftruncate
long sys_ftruncate(unsigned int fd, unsigned long length)
94
sys_fchmod
long sys_fchmod(unsigned int fd, mode_t mode)
95
sys_fchown16
long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group)
96
sys_getpriority
long sys_getpriority(int which, int who)
97
sys_setpriority
long sys_setpriority(int which, int who, int niceval)
98
sys_ni_syscall
long sys_ni_syscall(void)
99
sys_statfs
long sys_statfs(const char *path, struct statfs *buf)
100
sys_fstatfs
long sys_fstatfs(unsigned int fd, struct statfs *buf)
101
sys_ioperm
int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
102
sys_socketcall
long sys_socketcall(int call, unsigned long *args)
103
sys_syslog
long sys_syslog(int type, char *buf, int len)
104
sys_setitimer
long sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
105
sys_getitimer
long sys_getitimer(int which, struct itimerval *value)
106
sys_newstat
long sys_newstat(char *filename, struct stat *statbuf)
107
sys_newlstat
long sys_newlstat(char *filename, struct stat *statbuf)
108
sys_newfstat
long sys_newfstat(unsigned int fd, struct stat *statbuf)
109
sys_uname
int sys_uname(struct old_utsname *name)
110
sys_iopl
int sys_iopl(unsigned long unused)
111
sys_vhangup
long sys_vhangup(void)
112
sys_ni_syscall
long sys_ni_syscall(void)
113
sys_vm86old
int sys_vm86old(struct vm86_struct *v86)
114
sys_wait4
long sys_wait4(pid_t pid, unsigned int *stat_addr, int options, struct rusage *ru)
115
sys_swapoff
long sys_swapoff(const char *specialfile)
116
sys_sysinfo
long sys_sysinfo(struct sysinfo *info)
117
sys_ipc
int sys_ipc(uint call, int first, int second, int third, void *ptr, long fifth)
118
sys_fsync
long sys_fsync(unsigned int fd)
119
sys_sigreturn
int sys_sigreturn(unsigned long __unused)
120
sys_clone
int sys_clone(struct pt_regs regs)
121
sys_setdomainname
long sys_setdomainname(char *name, int len)
122
sys_newuname
long sys_newuname(struct new_utsname *name)
123
sys_modify_ldt
int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
124
sys_adjtimex
long sys_adjtimex(struct timex *txc_p)
125
sys_mprotect
long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
126
sys_sigprocmask
long sys_sigprocmask(int how, old_sigset_t * set, old_sigset_t * oset)
127
sys_create_module
unsigned long sys_create_module(const char *name_user, size_t size)
128
sys_init_module
long sys_init_module(const char *name_user, struct module *mod_user)
129
sys_delete_module
long sys_delete_module(const char *name_user)
130
sys_get_kernel_syms
long sys_get_kernel_syms(struct kernel_sym *table)
131
sys_quotactl
long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
132
sys_getpgid
long sys_getpgid(pid_t pid)
133
sys_fchdir
long sys_fchdir(unsigned int fd)
134
sys_bdflush
long sys_bdflush(int func, long data)
135
sys_sysfs
long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
136
sys_personality
long sys_personality(u_long personality)
137
sys_ni_syscall
long sys_ni_syscall(void)
138
sys_setfsuid16
long sys_setfsuid16(old_uid_t uid)
139
sys_setfsgid16
long sys_setfsgid16(old_gid_t gid)
140
sys_llseek
long sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t * result, unsigned int origin)
141
sys_getdents
long sys_getdents(unsigned int fd, void *dirent, unsigned int count)
142
sys_select
long sys_select(int n, fd_set * inp, fd_set * outp, fd_set * exp, struct timeval *tvp)
143
sys_flock
long sys_flock(unsigned int fd, unsigned int cmd)
144
sys_msync
long sys_msync(unsigned long start, size_t len, int flags)
145
sys_readv
ssize_t sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count)
146
sys_writev
ssize_t sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count)
147
sys_getsid
long sys_getsid(pid_t pid)
148
sys_fdatasync
long sys_fdatasync(unsigned int fd)
149
sys_sysctl
long sys_sysctl(struct __sysctl_args *args)
150
sys_mlock
long sys_mlock(unsigned long start, size_t len)
151
sys_munlock
long sys_munlock(unsigned long start, size_t len)
152
sys_mlockall
long sys_mlockall(int flags)
153
sys_munlockall
long sys_munlockall(void)
154
sys_sched_setparam
long sys_sched_setparam(pid_t pid, struct sched_param *param)
155
sys_sched_getparam
long sys_sched_getparam(pid_t pid, struct sched_param *param)
156
sys_sched_setscheduler
long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param)
157
sys_sched_getscheduler
long sys_sched_getscheduler(pid_t pid)
158
sys_sched_yield
long sys_sched_yield(void)
159
sys_sched_get_priority_max
long sys_sched_get_priority_max(int policy)
160
sys_sched_get_priority_min
long sys_sched_get_priority_min(int policy)
161
sys_sched_rr_get_interval
long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
162
sys_nanosleep
long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
163
sys_mremap
unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr)
164
sys_setresuid16
long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
165
sys_getresuid16
long sys_getresuid16(old_uid_t * ruid, old_uid_t * euid, old_uid_t * suid)
166
sys_vm86
int sys_vm86(unsigned long subfunction, struct vm86plus_struct *v86)
167
sys_query_module
long sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t * ret)
168
sys_poll
long sys_poll(struct pollfd *ufds, unsigned int nfds, long timeout)
169
sys_nfsservctl
170
sys_setresgid16
long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)
171
sys_getresgid16
long sys_getresgid16(old_gid_t * rgid, old_gid_t * egid, old_gid_t * sgid)
172
sys_prctl
long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
173
sys_rt_sigreturn
int sys_rt_sigreturn(unsigned long __unused)
174
sys_rt_sigaction
long sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, size_t sigsetsize)
175
sys_rt_sigprocmask
long sys_rt_sigprocmask(int how, sigset_t * set, sigset_t * oset, size_t sigsetsize)
176
sys_rt_sigpending
long sys_rt_sigpending(sigset_t * set, size_t sigsetsize)
177
sys_rt_sigtimedwait
long sys_rt_sigtimedwait(const sigset_t * uthese, siginfo_t * uinfo, const struct timespec *uts, size_t sigsetsize)
178
sys_rt_sigqueueinfo
long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t * uinfo)
179
sys_rt_sigsuspend
int sys_rt_sigsuspend(sigset_t * unewset, size_t sigsetsize)
180
sys_pread
ssize_t sys_pread(unsigned int fd, char *buf, size_t count, loff_t pos)
181
sys_pwrite
ssize_t sys_pwrite(unsigned int fd, const char *buf, size_t count, loff_t pos)
182
sys_chown16
long sys_chown16(const char *filename, old_uid_t user, old_gid_t group)
183
sys_getcwd
long sys_getcwd(char *buf, unsigned long size)
184
sys_capget
long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
185
sys_capset
long sys_capset(cap_user_header_t header, const cap_user_data_t data)
186
sys_sigaltstack
int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
187
sys_sendfile
ssize_t sys_sendfile(int out_fd, int in_fd, off_t * offset, size_t count)
188
sys_ni_syscall
long sys_ni_syscall(void)
189
sys_ni_syscall
long sys_ni_syscall(void)
190
sys_vfork
int sys_vfork(struct pt_regs regs)
191
sys_getrlimit
long sys_getrlimit(unsigned int resource, struct rlimit *rlim)
192
sys_mmap2
long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff)
193
sys_truncate64
long sys_truncate64(const char *path, loff_t length)
194
sys_ftruncate64
long sys_ftruncate64(unsigned int fd, loff_t length)
195
sys_stat64
long sys_stat64(char *filename, struct stat64 *statbuf, long flags)
196
sys_lstat64
long sys_lstat64(char *filename, struct stat64 *statbuf, long flags)
197
sys_fstat64
long sys_fstat64(unsigned long fd, struct stat64 *statbuf, long flags)
198
sys_lchown
long sys_lchown(const char *filename, uid_t user, gid_t group)
199
sys_getuid
long sys_getuid(void)
200
sys_getgid
long sys_getgid(void)
201
sys_geteuid
long sys_geteuid(void)
202
sys_getegid
long sys_getegid(void)
203
sys_setreuid
long sys_setreuid(uid_t ruid, uid_t euid)
204
sys_setregid
long sys_setregid(gid_t rgid, gid_t egid)
205
sys_getgroups
long sys_getgroups(int gidsetsize, gid_t * grouplist)
206
sys_setgroups
long sys_setgroups(int gidsetsize, gid_t * grouplist)
207
sys_fchown
long sys_fchown(unsigned int fd, uid_t user, gid_t group)
208
sys_setresuid
long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
209
sys_getresuid
long sys_getresuid(uid_t * ruid, uid_t * euid, uid_t * suid)
210
sys_setresgid
long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
211
sys_getresgid
long sys_getresgid(gid_t * rgid, gid_t * egid, gid_t * sgid)
212
sys_chown
long sys_chown(const char *filename, uid_t user, gid_t group)
213
sys_setuid
long sys_setuid(uid_t uid)
214
sys_setgid
long sys_setgid(gid_t gid)
215
sys_setfsuid
long sys_setfsuid(uid_t uid)
216
sys_setfsgid
long sys_setfsgid(gid_t gid)
217
sys_pivot_root
long sys_pivot_root(const char *new_root, const char *put_old)
218
sys_mincore
long sys_mincore(unsigned long start, size_t len, unsigned char *vec)
219
sys_madvise
long sys_madvise(unsigned long start, size_t len, int behavior)
220
sys_getdents64
long sys_getdents64(unsigned int fd, void *dirent, unsigned int count)
221
sys_fcntl64
long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
222
sys_ni_syscall
long sys_ni_syscall(void)
223
sys_ni_syscall
long sys_ni_syscall(void)
224
sys_gettid
long sys_gettid(void)
225
sys_readahead
ssize_t sys_readahead(int fd, loff_t offset, size_t count)
226
sys_setxattr
long sys_setxattr(char *path, char *name, void *value, size_t size, int flags)
227
sys_lsetxattr
long sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags)
228
sys_fsetxattr
long sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags)
229
sys_getxattr
ssize_t sys_getxattr(char *path, char *name, void *value, size_t size)
230
sys_lgetxattr
ssize_t sys_lgetxattr(char *path, char *name, void *value, size_t size)
231
sys_fgetxattr
ssize_t sys_fgetxattr(int fd, char *name, void *value, size_t size)
232
sys_listxattr
ssize_t sys_listxattr(char *path, char *list, size_t size)
233
sys_llistxattr
ssize_t sys_llistxattr(char *path, char *list, size_t size)
234
sys_flistxattr
ssize_t sys_flistxattr(int fd, char *list, size_t size)
235
sys_removexattr
long sys_removexattr(char *path, char *name)
236
sys_lremovexattr
long sys_lremovexattr(char *path, char *name)
237
sys_fremovexattr
long sys_fremovexattr(int fd, char *name)
238
sys_tkill
long sys_tkill(int pid, int sig)
239
sys_sendfile64
ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t * offset, size_t count)
240
sys_ni_syscall
long sys_ni_syscall(void)
241
sys_ni_syscall
long sys_ni_syscall(void)
242
sys_ni_syscall
long sys_ni_syscall(void)
243
sys_ni_syscall
long sys_ni_syscall(void)
244
sys_ni_syscall
long sys_ni_syscall(void)
245
sys_ni_syscall
long sys_ni_syscall(void)
246
sys_ni_syscall
long sys_ni_syscall(void)
247
sys_ni_syscall
long sys_ni_syscall(void)
248
sys_ni_syscall
long sys_ni_syscall(void)
249
sys_ni_syscall
long sys_ni_syscall(void)
250
sys_ni_syscall
long sys_ni_syscall(void)
251
sys_ni_syscall
long sys_ni_syscall(void)
252
sys_ni_syscall
long sys_ni_syscall(void)
253
sys_ni_syscall
long sys_ni_syscall(void)
254
sys_ni_syscall
long sys_ni_syscall(void)
255
sys_ni_syscall
long sys_ni_syscall(void)
256
sys_ni_syscall
long sys_ni_syscall(void)
257
sys_ni_syscall
long sys_ni_syscall(void)
258
sys_ni_syscall
long sys_ni_syscall(void)
259
sys_ni_syscall
long sys_ni_syscall(void)
以下是 Linux 2.6.11 的 system call 整理表格,提供給「Embedded Linux 嵌入式系統實作演練」的讀者您做參考。這是一張很方便的表格,可以取代 unistd.h 與 "man"。
這張工具表格可以幫助我們:
1. 最主要的目的:當然是研究作業系統,了解 Linux 提供的 sytsem call service。
2. Trace kernel.
3. Writing shellcode.
供您參考 :)
Linux (kernel 2.6.11) System Call Table
1. sys_ni_syscall 為保留號碼
2. 更新日期: 2006/10/07
3. 第一次發佈 2.6 kernel 的 LSCT
no
Syscall
Prototype decl.
0
sys_restart_syscall
long sys_restart_syscall(void)
1
sys_exit
long sys_exit(int error_code)
2
sys_fork
int sys_fork(struct pt_regs regs)
3
sys_read
ssize_t sys_read(unsigned int fd, char __user * buf, size_t count)
4
sys_write
ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
5
sys_open
long sys_open(const char __user * filename, int flags, int mode)
6
sys_close
long sys_close(unsigned int fd)
7
sys_waitpid
long sys_waitpid(pid_t pid, int __user * stat_addr, int options)
8
sys_creat
long sys_creat(const char __user * pathname, int mode)
9
sys_link
long sys_link(const char __user * oldname, const char __user * newname)
10
sys_unlink
long sys_unlink(const char __user * pathname)
11
sys_execve
int sys_execve(struct pt_regs regs)
12
sys_chdir
long sys_chdir(const char __user * filename)
13
sys_time
long sys_time(time_t __user * tloc)
14
sys_mknod
long sys_mknod(const char __user * filename, int mode, unsigned dev)
15
sys_chmod
long sys_chmod(const char __user * filename, mode_t mode)
16
sys_lchown16
long sys_lchown16(const char __user * filename, old_uid_t user, old_gid_t group)
17
sys_ni_syscall
long sys_ni_syscall(void)
18
sys_stat
long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf)
19
sys_lseek
off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
20
sys_getpid
long sys_getpid(void)
21
sys_mount
long sys_mount(char __user * dev_name, char __user * dir_name, char __user * type, unsigned long flags, void __user * data)
22
sys_oldumount
long sys_oldumount(char __user * name)
23
sys_setuid16
long sys_setuid16(old_uid_t uid)
24
sys_getuid16
long sys_getuid16(void)
25
sys_stime
long sys_stime(time_t __user * tptr)
26
sys_ptrace
int sys_ptrace(long request, long pid, long addr, long data)
27
sys_alarm
unsigned long sys_alarm(unsigned int seconds)
28
sys_fstat
long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf)
29
sys_pause
long sys_pause(void)
30
sys_utime
long sys_utime(char __user * filename, struct utimbuf __user * times)
31
sys_ni_syscall
long sys_ni_syscall(void)
32
sys_ni_syscall
long sys_ni_syscall(void)
33
sys_access
long sys_access(const char __user * filename, int mode)
34
sys_nice
long sys_nice(int increment)
35
sys_ni_syscall
long sys_ni_syscall(void)
36
sys_sync
long sys_sync(void)
37
sys_kill
long sys_kill(int pid, int sig)
38
sys_rename
long sys_rename(const char __user * oldname, const char __user * newname)
39
sys_mkdir
long sys_mkdir(const char __user * pathname, int mode)
40
sys_rmdir
long sys_rmdir(const char __user * pathname)
41
sys_dup
long sys_dup(unsigned int fildes)
42
sys_pipe
int sys_pipe(unsigned long __user * fildes)
43
sys_times
long sys_times(struct tms __user * tbuf)
44
sys_ni_syscall
long sys_ni_syscall(void)
45
sys_brk
unsigned long sys_brk(unsigned long brk)
46
sys_setgid16
long sys_setgid16(old_gid_t gid)
47
sys_getgid16
long sys_getgid16(void)
48
sys_signal
unsigned long sys_signal(int sig, __sighandler_t handler)
49
sys_geteuid16
long sys_geteuid16(void)
50
sys_getegid16
long sys_getegid16(void)
51
sys_acct
long sys_acct(const char __user * name)
52
sys_umount
long sys_umount(char __user * name, int flags)
53
sys_ni_syscall
long sys_ni_syscall(void)
54
sys_ioctl
long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
55
sys_fcntl
long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
56
sys_ni_syscall
long sys_ni_syscall(void)
57
sys_setpgid
long sys_setpgid(pid_t pid, pid_t pgid)
58
sys_ni_syscall
long sys_ni_syscall(void)
59
sys_olduname
int sys_olduname(struct oldold_utsname __user * name)
60
sys_umask
long sys_umask(int mask)
61
sys_chroot
long sys_chroot(const char __user * filename)
62
sys_ustat
long sys_ustat(unsigned dev, struct ustat __user * ubuf)
63
sys_dup2
long sys_dup2(unsigned int oldfd, unsigned int newfd)
64
sys_getppid
long sys_getppid(void)
65
sys_getpgrp
long sys_getpgrp(void)
66
sys_setsid
long sys_setsid(void)
67
sys_sigaction
int sys_sigaction(int sig, const struct old_sigaction __user * act, struct old_sigaction __user * oact)
68
sys_sgetmask
long sys_sgetmask(void)
69
sys_ssetmask
long sys_ssetmask(int newmask)
70
sys_setreuid16
long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
71
sys_setregid16
long sys_setregid16(old_gid_t rgid, old_gid_t egid)
72
sys_sigsuspend
int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
73
sys_sigpending
long sys_sigpending(old_sigset_t __user * set)
74
sys_sethostname
long sys_sethostname(char __user * name, int len)
75
sys_setrlimit
long sys_setrlimit(unsigned int resource, struct rlimit __user * rlim)
76
sys_old_getrlimit
long sys_old_getrlimit(unsigned int resource, struct rlimit __user * rlim)
77
sys_getrusage
long sys_getrusage(int who, struct rusage __user * ru)
78
sys_gettimeofday
long sys_gettimeofday(struct timeval __user * tv, struct timezone __user * tz)
79
sys_settimeofday
long sys_settimeofday(struct timeval __user * tv, struct timezone __user * tz)
80
sys_getgroups16
long sys_getgroups16(int gidsetsize, old_gid_t __user * grouplist)
81
sys_setgroups16
long sys_setgroups16(int gidsetsize, old_gid_t __user * grouplist)
82
old_select
int old_select(struct sel_arg_struct __user * arg)
83
sys_symlink
long sys_symlink(const char __user * oldname, const char __user * newname)
84
sys_lstat
long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf)
85
sys_readlink
long sys_readlink(const char __user * path, char __user * buf, int bufsiz)
86
sys_uselib
long sys_uselib(const char __user * library)
87
sys_swapon
long sys_swapon(const char __user * specialfile, int swap_flags)
88
sys_reboot
long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)
89
old_readdir
long old_readdir(unsigned int fd, struct old_linux_dirent __user * dirent, unsigned int count)
90
old_mmap
int old_mmap(struct mmap_arg_struct __user * arg)
91
sys_munmap
long sys_munmap(unsigned long addr, size_t len)
92
sys_truncate
long sys_truncate(const char __user * path, unsigned long length)
93
sys_ftruncate
long sys_ftruncate(unsigned int fd, unsigned long length)
94
sys_fchmod
long sys_fchmod(unsigned int fd, mode_t mode)
95
sys_fchown16
long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group)
96
sys_getpriority
long sys_getpriority(int which, int who)
97
sys_setpriority
long sys_setpriority(int which, int who, int niceval)
98
sys_ni_syscall
long sys_ni_syscall(void)
99
sys_statfs
long sys_statfs(const char __user * path, struct statfs __user * buf)
100
sys_fstatfs
long sys_fstatfs(unsigned int fd, struct statfs __user * buf)
101
sys_ioperm
long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
102
sys_socketcall
long sys_socketcall(int call, unsigned long __user * args)
103
sys_syslog
long sys_syslog(int type, char __user * buf, int len)
104
sys_setitimer
long sys_setitimer(int which, struct itimerval __user * value, struct itimerval __user * ovalue)
105
sys_getitimer
long sys_getitimer(int which, struct itimerval __user * value)
106
sys_newstat
long sys_newstat(char __user * filename, struct stat __user * statbuf)
107
sys_newlstat
long sys_newlstat(char __user * filename, struct stat __user * statbuf)
108
sys_newfstat
long sys_newfstat(unsigned int fd, struct stat __user * statbuf)
109
sys_uname
int sys_uname(struct old_utsname __user * name)
110
sys_iopl
long sys_iopl(unsigned long unused)
111
sys_vhangup
long sys_vhangup(void)
112
sys_ni_syscall
long sys_ni_syscall(void)
113
sys_vm86old
int sys_vm86old(struct pt_regs regs)
114
sys_wait4
long sys_wait4(pid_t pid, int __user * stat_addr, int options, struct rusage __user * ru)
115
sys_swapoff
long sys_swapoff(const char __user * specialfile)
116
sys_sysinfo
long sys_sysinfo(struct sysinfo __user * info)
117
sys_ipc
int sys_ipc(uint call, int first, int second, int third, void __user * ptr, long fifth)
118
sys_fsync
long sys_fsync(unsigned int fd)
119
sys_sigreturn
int sys_sigreturn(unsigned long __unused)
120
sys_clone
int sys_clone(struct pt_regs regs)
121
sys_setdomainname
long sys_setdomainname(char __user * name, int len)
122
sys_newuname
long sys_newuname(struct new_utsname __user * name)
123
sys_modify_ldt
int sys_modify_ldt(int func, void __user * ptr, unsigned long bytecount)
124
sys_adjtimex
long sys_adjtimex(struct timex __user * txc_p)
125
sys_mprotect
long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
126
sys_sigprocmask
long sys_sigprocmask(int how, old_sigset_t __user * set, old_sigset_t __user * oset)
127
sys_ni_syscall
long sys_ni_syscall(void)
128
sys_init_module
long sys_init_module(void __user * umod, unsigned long len, const char __user * uargs)
129
sys_delete_module
long sys_delete_module(const char __user * name_user, unsigned int flags)
130
sys_ni_syscall
long sys_ni_syscall(void)
131
sys_quotactl
long sys_quotactl(unsigned int cmd, const char __user * special, qid_t id, void __user * addr)
132
sys_getpgid
long sys_getpgid(pid_t pid)
133
sys_fchdir
long sys_fchdir(unsigned int fd)
134
sys_bdflush
long sys_bdflush(int func, long data)
135
sys_sysfs
long sys_sysfs(int option, unsigned long arg1, unsigned long arg2)
136
sys_personality
long sys_personality(u_long personality)
137
sys_ni_syscall
long sys_ni_syscall(void)
138
sys_setfsuid16
long sys_setfsuid16(old_uid_t uid)
139
sys_setfsgid16
long sys_setfsgid16(old_gid_t gid)
140
sys_llseek
long sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t __user * result, unsigned int origin)
141
sys_getdents
long sys_getdents(unsigned int fd, struct linux_dirent __user * dirent, unsigned int count)
142
sys_select
long sys_select(int n, fd_set __user * inp, fd_set __user * outp, fd_set __user * exp, struct timeval __user * tvp)
143
sys_flock
long sys_flock(unsigned int fd, unsigned int cmd)
144
sys_msync
long sys_msync(unsigned long start, size_t len, int flags)
145
sys_readv
ssize_t sys_readv(unsigned long fd, const struct iovec __user * vec, unsigned long vlen)
146
sys_writev
ssize_t sys_writev(unsigned long fd, const struct iovec __user * vec, unsigned long vlen)
147
sys_getsid
long sys_getsid(pid_t pid)
148
sys_fdatasync
long sys_fdatasync(unsigned int fd)
149
sys_sysctl
long sys_sysctl(struct __sysctl_args __user * args)
150
sys_mlock
long sys_mlock(unsigned long start, size_t len)
151
sys_munlock
long sys_munlock(unsigned long start, size_t len)
152
sys_mlockall
long sys_mlockall(int flags)
153
sys_munlockall
long sys_munlockall(void)
154
sys_sched_setparam
long sys_sched_setparam(pid_t pid, struct sched_param __user * param)
155
sys_sched_getparam
long sys_sched_getparam(pid_t pid, struct sched_param __user * param)
156
sys_sched_setscheduler
long sys_sched_setscheduler(pid_t pid, int policy, struct sched_param __user * param)
157
sys_sched_getscheduler
long sys_sched_getscheduler(pid_t pid)
158
sys_sched_yield
long sys_sched_yield(void)
159
sys_sched_get_priority_max
long sys_sched_get_priority_max(int policy)
160
sys_sched_get_priority_min
long sys_sched_get_priority_min(int policy)
161
sys_sched_rr_get_interval
long sys_sched_rr_get_interval(pid_t pid, struct timespec __user * interval)
162
sys_nanosleep
long sys_nanosleep(struct timespec __user * rqtp, struct timespec __user * rmtp)
163
sys_mremap
unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags, unsigned long new_addr)
164
sys_setresuid16
long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
165
sys_getresuid16
long sys_getresuid16(old_uid_t __user * ruid, old_uid_t __user * euid, old_uid_t __user * suid)
166
sys_vm86
int sys_vm86(struct pt_regs regs)
167
sys_ni_syscall
long sys_ni_syscall(void)
168
sys_poll
long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout)
169
sys_nfsservctl
170
sys_setresgid16
long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)
171
sys_getresgid16
long sys_getresgid16(old_gid_t __user * rgid, old_gid_t __user * egid, old_gid_t __user * sgid)
172
sys_prctl
long sys_prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
173
sys_rt_sigreturn
int sys_rt_sigreturn(unsigned long __unused)
174
sys_rt_sigaction
long sys_rt_sigaction(int sig, const struct sigaction __user * act, struct sigaction __user * oact, size_t sigsetsize)
175
sys_rt_sigprocmask
long sys_rt_sigprocmask(int how, sigset_t __user * set, sigset_t __user * oset, size_t sigsetsize)
176
sys_rt_sigpending
long sys_rt_sigpending(sigset_t __user * set, size_t sigsetsize)
177
sys_rt_sigtimedwait
long sys_rt_sigtimedwait(const sigset_t __user * uthese, siginfo_t __user * uinfo, const struct timespec __user * uts, size_t sigsetsize)
178
sys_rt_sigqueueinfo
long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t __user * uinfo)
179
sys_rt_sigsuspend
int sys_rt_sigsuspend(struct pt_regs regs)
180
sys_pread64
ssize_t sys_pread64(unsigned int fd, char __user * buf, size_t count, loff_t pos)
181
sys_pwrite64
ssize_t sys_pwrite64(unsigned int fd, const char __user * buf, size_t count, loff_t pos)
182
sys_chown16
long sys_chown16(const char __user * filename, old_uid_t user, old_gid_t group)
183
sys_getcwd
long sys_getcwd(char __user * buf, unsigned long size)
184
sys_capget
long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
185
sys_capset
long sys_capset(cap_user_header_t header, const cap_user_data_t data)
186
sys_sigaltstack
int sys_sigaltstack(unsigned long ebx)
187
sys_sendfile
ssize_t sys_sendfile(int out_fd, int in_fd, off_t __user * offset, size_t count)
188
sys_ni_syscall
long sys_ni_syscall(void)
189
sys_ni_syscall
long sys_ni_syscall(void)
190
sys_vfork
int sys_vfork(struct pt_regs regs)
191
sys_getrlimit
long sys_getrlimit(unsigned int resource, struct rlimit __user * rlim)
192
sys_mmap2
long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff)
193
sys_truncate64
long sys_truncate64(const char __user * path, loff_t length)
194
sys_ftruncate64
long sys_ftruncate64(unsigned int fd, loff_t length)
195
sys_stat64
long sys_stat64(char __user * filename, struct stat64 __user * statbuf)
196
sys_lstat64
long sys_lstat64(char __user * filename, struct stat64 __user * statbuf)
197
sys_fstat64
long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf)
198
sys_lchown
long sys_lchown(const char __user * filename, uid_t user, gid_t group)
199
sys_getuid
long sys_getuid(void)
200
sys_getgid
long sys_getgid(void)
201
sys_geteuid
long sys_geteuid(void)
202
sys_getegid
long sys_getegid(void)
203
sys_setreuid
long sys_setreuid(uid_t ruid, uid_t euid)
204
sys_setregid
long sys_setregid(gid_t rgid, gid_t egid)
205
sys_getgroups
long sys_getgroups(int gidsetsize, gid_t __user * grouplist)
206
sys_setgroups
long sys_setgroups(int gidsetsize, gid_t __user * grouplist)
207
sys_fchown
long sys_fchown(unsigned int fd, uid_t user, gid_t group)
208
sys_setresuid
long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
209
sys_getresuid
long sys_getresuid(uid_t __user * ruid, uid_t __user * euid, uid_t __user * suid)
210
sys_setresgid
long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
211
sys_getresgid
long sys_getresgid(gid_t __user * rgid, gid_t __user * egid, gid_t __user * sgid)
212
sys_chown
long sys_chown(const char __user * filename, uid_t user, gid_t group)
213
sys_setuid
long sys_setuid(uid_t uid)
214
sys_setgid
long sys_setgid(gid_t gid)
215
sys_setfsuid
long sys_setfsuid(uid_t uid)
216
sys_setfsgid
long sys_setfsgid(gid_t gid)
217
sys_pivot_root
long sys_pivot_root(const char __user * new_root, const char __user * put_old)
218
sys_mincore
long sys_mincore(unsigned long start, size_t len, unsigned char __user * vec)
219
sys_madvise
long sys_madvise(unsigned long start, size_t len_in, int behavior)
220
sys_getdents64
long sys_getdents64(unsigned int fd, struct linux_dirent64 __user * dirent, unsigned int count)
221
sys_fcntl64
long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
222
sys_ni_syscall
long sys_ni_syscall(void)
223
sys_ni_syscall
long sys_ni_syscall(void)
224
sys_gettid
long sys_gettid(void)
225
sys_readahead
ssize_t sys_readahead(int fd, loff_t offset, size_t count)
226
sys_setxattr
long sys_setxattr(char __user * path, char __user * name, void __user * value, size_t size, int flags)
227
sys_lsetxattr
long sys_lsetxattr(char __user * path, char __user * name, void __user * value, size_t size, int flags)
228
sys_fsetxattr
long sys_fsetxattr(int fd, char __user * name, void __user * value, size_t size, int flags)
229
sys_getxattr
ssize_t sys_getxattr(char __user * path, char __user * name, void __user * value, size_t size)
230
sys_lgetxattr
ssize_t sys_lgetxattr(char __user * path, char __user * name, void __user * value, size_t size)
231
sys_fgetxattr
ssize_t sys_fgetxattr(int fd, char __user * name, void __user * value, size_t size)
232
sys_listxattr
ssize_t sys_listxattr(char __user * path, char __user * list, size_t size)
233
sys_llistxattr
ssize_t sys_llistxattr(char __user * path, char __user * list, size_t size)
234
sys_flistxattr
ssize_t sys_flistxattr(int fd, char __user * list, size_t size)
235
sys_removexattr
long sys_removexattr(char __user * path, char __user * name)
236
sys_lremovexattr
long sys_lremovexattr(char __user * path, char __user * name)
237
sys_fremovexattr
long sys_fremovexattr(int fd, char __user * name)
238
sys_tkill
long sys_tkill(int pid, int sig)
239
sys_sendfile64
ssize_t sys_sendfile64(int out_fd, int in_fd, loff_t __user * offset, size_t count)
240
sys_futex
long sys_futex(u32 __user * uaddr, int op, int val, struct timespec __user * utime, u32 __user * uaddr2, int val3)
241
sys_sched_setaffinity
long sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long __user * user_mask_ptr)
242
sys_sched_getaffinity
long sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long __user * user_mask_ptr)
243
sys_set_thread_area
int sys_set_thread_area(struct user_desc __user * u_info)
244
sys_get_thread_area
int sys_get_thread_area(struct user_desc __user * u_info)
245
sys_io_setup
long sys_io_setup(unsigned nr_events, aio_context_t __user * ctxp)
246
sys_io_destroy
long sys_io_destroy(aio_context_t ctx)
247
sys_io_getevents
long sys_io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event __user * events, struct timespec __user * timeout)
248
sys_io_submit
long sys_io_submit(aio_context_t ctx_id, long nr, struct iocb __user * __user * iocbpp)
249
sys_io_cancel
long sys_io_cancel(aio_context_t ctx_id, struct iocb __user * iocb, struct io_event __user * result)
250
sys_fadvise64
long sys_fadvise64(int fd, loff_t offset, size_t len, int advice)
251
sys_ni_syscall
long sys_ni_syscall(void)
252
sys_exit_group
void sys_exit_group(int error_code)
253
sys_lookup_dcookie
long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len)
254
sys_epoll_create
long sys_epoll_create(int size)
255
sys_epoll_ctl
long sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user * event)
256
sys_epoll_wait
long sys_epoll_wait(int epfd, struct epoll_event __user * events, int maxevents, int timeout)
257
sys_remap_file_pages
long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long __prot, unsigned long pgoff, unsigned long flags)
258
sys_set_tid_address
long sys_set_tid_address(int __user * tidptr)
259
sys_timer_create
long sys_timer_create(clockid_t which_clock, struct sigevent __user * timer_event_spec, timer_t __user * created_timer_id)
260
sys_timer_settime
long sys_timer_settime(timer_t timer_id, int flags, const struct itimerspec __user * new_setting, struct itimerspec __user * old_setting)
261
sys_timer_gettime
long sys_timer_gettime(timer_t timer_id, struct itimerspec __user * setting)
262
sys_timer_getoverrun
long sys_timer_getoverrun(timer_t timer_id)
263
sys_timer_delete
long sys_timer_delete(timer_t timer_id)
264
sys_clock_settime
long sys_clock_settime(clockid_t which_clock, const struct timespec __user * tp)
265
sys_clock_gettime
long sys_clock_gettime(clockid_t which_clock, struct timespec __user * tp)
266
sys_clock_getres
long sys_clock_getres(clockid_t which_clock, struct timespec __user * tp)
267
sys_clock_nanosleep
long sys_clock_nanosleep(clockid_t which_clock, int flags, const struct timespec __user * rqtp, struct timespec __user * rmtp)
268
sys_statfs64
long sys_statfs64(const char __user * path, size_t sz, struct statfs64 __user * buf)
269
sys_fstatfs64
long sys_fstatfs64(unsigned int fd, size_t sz, struct statfs64 __user * buf)
270
sys_tgkill
long sys_tgkill(int tgid, int pid, int sig)
271
sys_utimes
long sys_utimes(char __user * filename, struct timeval __user * utimes)
272
sys_fadvise64_64
long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
273
sys_ni_syscall
long sys_ni_syscall(void)
274
sys_mbind
long sys_mbind(unsigned long start, unsigned long len, unsigned long mode, unsigned long __user * nmask, unsigned long maxnode, unsigned flags)
275
sys_get_mempolicy
long sys_get_mempolicy(int __user * policy, unsigned long __user * nmask, unsigned long maxnode, unsigned long addr, unsigned long flags)
276
sys_set_mempolicy
long sys_set_mempolicy(int mode, unsigned long __user * nmask, unsigned long maxnode)
277
sys_mq_open
long sys_mq_open(const char __user * u_name, int oflag, mode_t mode, struct mq_attr __user * u_attr)
278
sys_mq_unlink
long sys_mq_unlink(const char __user * u_name)
279
sys_mq_timedsend
long sys_mq_timedsend(mqd_t mqdes, const char __user * u_msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user * u_abs_timeout)
280
sys_mq_timedreceive
ssize_t sys_mq_timedreceive(mqd_t mqdes, char __user * u_msg_ptr, size_t msg_len, unsigned int __user * u_msg_prio, const struct timespec __user * u_abs_timeout)
281
sys_mq_notify
long sys_mq_notify(mqd_t mqdes, const struct sigevent __user * u_notification)
282
sys_mq_getsetattr
long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user * u_mqstat, struct mq_attr __user * u_omqstat)
283
sys_ni_syscall
long sys_ni_syscall(void)
284
sys_waitid
long sys_waitid(int which, pid_t pid, struct siginfo __user * infop, int options, struct rusage __user * ru)
285
sys_ni_syscall
long sys_ni_syscall(void)
286
sys_add_key
long sys_add_key(const char __user * _type, const char __user * _description, const void __user * _payload, size_t plen, key_serial_t ringid)
287
sys_request_key
long sys_request_key(const char __user * _type, const char __user * _description, const char __user * _callout_info, key_serial_t destringid)
288
sys_keyctl
long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5)
把 Linux 提供的 sytsem call service 依分類做整理,並提供實作檔案。本表使用於 Jollen 的「2. GNU Toolchains 與 Embedded Linux Programming」課程中,在此提供給大家做參考。目前依據 Linux 2.6.11 原始碼製成,請搭配 2.6.11 以上的版本做研究。
對於 Linux system call 的研究,我們採取的策略是「依分類」來做討論,而不是依 system call 編號依序討論。透過 system
call (kernel-space 端) 的研究,我們除了可以更深入了解作業系統外,更能一探 Linux kernel 的奧妙。
20
sys_getpid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_getpid (void);
用途說明:取得目前 process 的 thread ID (process ID)。
Kernel (2.6.11 or above) 實作:
/**
* sys_getpid - return the thread group id of the current process
*
* Note, despite the name, this returns the tgid not the pid. The tgid and
* the pid are identical unless CLONE_THREAD was specified on clone() in
* which case the tgid is the same in all threads of the same group.
*
* This is SMP safe as current->tgid does not change.
*/
asmlinkage long sys_getpid(void)
{
return current->tgid ;
}
Jollen 的說明
「Linux system calls 討論」系列,我們略過關於 user-space 端的說明,因此大家必須先了解以下主題:
system call 的 wrapper function (glibc)
0x80 號軟體中斷 (i386)
sys_getpid 透過 current 巨集取得目前 process 的 ID,kernel code 都可以存取 current 巨集
(我們把此巨集當做 kernel 的 global symbol 來看) 來存取目前 process 的狀態。
current 的 data structure 為 struct task_struct :
// include/linux/sched.h
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
struct thread_info *thread_info;
atomic_t usage;
unsigned long flags; /* per process flags, defined below */
unsigned long ptrace;
int lock_depth; /* BKL lock depth */
#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
int oncpu;
#endif
int prio, static_prio;
struct list_head run_list;
prio_array_t *array;
unsigned short ioprio;
unsigned int btrace_seq;
unsigned long sleep_avg;
unsigned long long timestamp, last_ran;
unsigned long long sched_time; /* sched_clock time spent running */
enum sleep_type sleep_type;
unsigned long policy;
cpumask_t cpus_allowed;
unsigned int time_slice, first_time_slice;
#ifdef CONFIG_SCHEDSTATS
struct sched_info sched_info;
#endif
struct list_head tasks;
/*
* ptrace_list/ptrace_children forms the list of my children
* that were stolen by a ptracer.
*/
struct list_head ptrace_children;
struct list_head ptrace_list;
struct mm_struct *mm, *active_mm;
/* task state */
struct linux_binfmt *binfmt;
long exit_state;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
unsigned long personality;
unsigned did_exec:1;
pid_t pid;
pid_t tgid;
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->parent->pid)
*/
struct task_struct *real_parent; /* real parent process (when being debugged) */
struct task_struct *parent; /* parent process */
/*
* children/sibling forms the list of my children plus the
* tasks I'm ptracing.
*/
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; /* threadgroup leader */
/* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX];
struct list_head thread_group;
struct completion *vfork_done; /* for vfork() */
int __user *set_child_tid; /* CLONE_CHILD_SETTID */
int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */
unsigned long rt_priority;
cputime_t utime, stime;
unsigned long nvcsw, nivcsw; /* context switch counts */
struct timespec start_time;
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;
cputime_t it_prof_expires, it_virt_expires;
unsigned long long it_sched_expires;
struct list_head cpu_timers[3];
/* process credentials */
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
struct group_info *group_info;
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
unsigned keep_capabilities:1;
struct user_struct *user;
#ifdef CONFIG_KEYS
struct key *request_key_auth; /* assumed request_key authority */
struct key *thread_keyring; /* keyring private to this thread */
unsigned char jit_keyring; /* default keyring to attach requested keys to */
#endif
int oomkilladj; /* OOM kill score adjustment (bit shift). */
char comm[TASK_COMM_LEN]; /* executable name excluding path
- access with [gs]et_task_comm (which lock
it with task_lock())
- initialized normally by flush_old_exec */
/* file system info */
int link_count, total_link_count;
/* ipc stuff */
struct sysv_sem sysvsem;
/* CPU-specific state of this task */
struct thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
/* namespace */
struct namespace *namespace;
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
void *security;
struct audit_context *audit_context;
seccomp_t seccomp;
/* Thread group tracking */
u32 parent_exec_id;
u32 self_exec_id;
/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
spinlock_t alloc_lock;
/* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
spinlock_t proc_lock;
#ifdef CONFIG_DEBUG_MUTEXES
/* mutex deadlock detection */
struct mutex_waiter *blocked_on;
#endif
/* journalling filesystem info */
void *journal_info;
/* VM state */
struct reclaim_state *reclaim_state;
struct dentry *proc_dentry;
struct backing_dev_info *backing_dev_info;
struct io_context *io_context;
unsigned long ptrace_message;
siginfo_t *last_siginfo; /* For ptrace use. */
/*
* current io wait handle: wait queue entry to use for io waits
* If this thread is processing aio, this points at the waitqueue
* inside the currently handled kiocb. It may be NULL (i.e. default
* to a stack based synchronous wait) if its doing sync IO.
*/
wait_queue_t *io_wait;
/* i/o counters(bytes read/written, #syscalls */
u64 rchar, wchar, syscr, syscw;
#if defined(CONFIG_BSD_PROCESS_ACCT)
u64 acct_rss_mem1; /* accumulated rss usage */
u64 acct_vm_mem1; /* accumulated virtual memory usage */
clock_t acct_stimexpd; /* clock_t-converted stime since last update */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *mempolicy;
short il_next;
#endif
#ifdef CONFIG_CPUSETS
struct cpuset *cpuset;
nodemask_t mems_allowed;
int cpuset_mems_generation;
int cpuset_mem_spread_rotor;
#endif
struct robust_list_head __user *robust_list;
#ifdef CONFIG_COMPAT
struct compat_robust_list_head __user *compat_robust_list;
#endif
atomic_t fs_excl; /* holding fs exclusive resources */
struct rcu_head rcu;
/*
* cache last used pipe for splice
*/
struct pipe_inode_info *splice_pipe;
};
struct task_struct 是 Linux kernel 表示 task 的標準資料結構。
sys_getpid 傳回
current->tgid 即完成工作,其中
tgid 表示 thread group ID 即 PID。
--作者/陳俊宏 (www.jollen.org)
199
sys_getuid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_getuid (void);
用途說明:取得目前 process 的 real user ID (UID)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_getuid(void)
{
/* Only we change this so SMP safe */
return current->uid;
}
201
sys_geteuid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_geteuid (void);
用途說明:取得目前 process 的 effective real user ID (file ID bit)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_geteuid(void)
{
/* Only we change this so SMP safe */
return current->euid;
}
Jollen 的說明
在 struct task_struct 裡紀錄了 task (process) 的所有資訊,其中我們最為熟悉的 process ID 與 user ID (and group ID) 都可以由這個資料結構裡取得。讓我們來看看 wrapper function 'getuid' 的用法 (from man):
NAME
getuid, geteuid - get user identity
SYNOPSIS
#include
#include
uid_t getuid(void);
uid_t geteuid(void);
DESCRIPTION
getuid returns the real user ID of the current process.
geteuid returns the effective user ID of the current process.
The real ID corresponds to the ID of the calling process. The effec-
tive ID corresponds to the set ID bit on the file being executed.
'getuid' 所對應的 system call service 為 sys_getuid,讓我們來看一下 Linux 的實作:
asmlinkage long sys_getuid(void)
{
/* Only we change this so SMP safe */
return current->uid ;
}
嗯,果然是非常的好懂,只要懂 current 巨集的用途即可!另外,要提醒的是,'current->uid' 並非直接 return 給 user-space 的 wrapper function (getuid in our example)。(那是 return 給誰?)
在 Linux 裡有許多類似 getuid 的 system call 實作,比如 sys_geteuid 的程式碼也是直接回傳 struct task_struct 裡的 field,並不難懂。
以下是 sys_getgid 與 sys_getegid 的整理。
200
sys_getgid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_getgid (void);
用途說明:取得目前 process 的 real group ID (GID)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_getgid(void)
{
/* Only we change this so SMP safe */
return current->gid;
}
202
sys_getegid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_getegid (void);
用途說明:取得目前 process 的 effective group ID (EGID)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_getegid(void)
{
/* Only we change this so SMP safe */
return current->egid;
}
這 4 個 Linux system call 都非常的容易了解,由 Linux System Calls' Forum #1,#2 我們了解到 2 個重要的 Kernel 議題:
1. struct task_struct ;
2. The current macro.
最後還有一個 sys_gettid 的實作。
224
sys_gettid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_gettid (void);
用途說明:取得 task 的 "pid"。
Kernel (2.6.11 or above) 實作:
/* Thread ID - the internal kernel "pid" */
asmlinkage long sys_gettid(void)
{
return current->pid;
}
新一代的檔案儲存 (storage) 檔案系統 (filesystem) - ext4 已經出現在Linux 2.16.19rc1-mm1 的核心原始碼裡了!ext4 是更先進的檔案系統,他前身就是知名的 ext3 檔案系統;ext3 是目前 Linux 普遍使用的知名檔案系統。
ext4 加入了 "extent file writing" 技術的支援,這是一個能減少 "fragmentation" 並增進效能的技術。有興趣的朋友可以閱讀 Linux-watch 上的官方新聞:
http://www.linux-watch.com/news/NS3183866977.html
'-mm' 系列的 2.6 kernel 是由 Andrew Morton 所釋出的 Linux 分支,主要性質以「實驗」與「新功能」為主;'ext4' 一睹為快,搶鮮下載 (mm patch 下載官網):
ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.19-rc1/2.6.19-rc1-mm1/
並且也要下載新的 e2fsprogs 套件:
ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs-interim/
使用方法 (ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.19-rc1/2.6.19-rc1-mm1/announce.txt ):
# mke2fs -j /dev/hda1 (格式化)
# mount /dev/hda1 /wherever -t ext4dev (filesystem type 'ext4dev')
如果要使用 'extent' 功能:
# mount /dev/hda1 /wherever -t ext4dev -o extents
sys_getppid 是很有趣的一個實作常式。
當 process fork 新的 process 後,便成為該 process 的 parent process,當然,新的 process 便成為
child process。在 UNIX 的 multithreaded 程式設計的理論中,process 之間的關係是相當重要的,比如說,只有 related
process (e.g. parent process v.s. child process) 可以透過 pipe 的機制來交換資料。
process 呼叫 fork() 函數(更正確的說法是 fork system call 的 wrapper function)後,fork() 便傳回
child process 的 PID;child process 則可以透過 getppid() system call 來取得 parent process
的 PID。
64
sys_getppid
linux/kernel/timer.c
類別:Kernel Timer & Process
原型宣告:long sys_getppid (void);
用途說明:取得 parent process 的 PID。
Kernel (2.6.11 or above) 實作:
/*
* Accessing ->group_leader->real_parent is not SMP-safe, it could
* change from under us. However, rather than getting any lock
* we can use an optimistic algorithm: get the parent
* pid, and go back and check that the parent is still
* the same. If it has changed (which is extremely unlikely
* indeed), we just try again..
*
* NOTE! This depends on the fact that even if we _do_
* get an old value of "parent", we can happily dereference
* the pointer (it was and remains a dereferencable kernel pointer
* no matter what): we just can't necessarily trust the result
* until we know that the parent pointer is valid.
*
* NOTE2: ->group_leader never changes from under us.
*/
asmlinkage long sys_getppid(void)
{
int pid;
struct task_struct *me = current;
struct task_struct *parent;
parent = me->group_leader->real_parent;
for (;;) {
pid = parent->tgid;
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
{
struct task_struct *old = parent;
/*
* Make sure we read the pid before re-reading the
* parent pointer:
*/
smp_rmb();
parent = me->group_leader->real_parent;
if (old != parent)
continue;
}
#endif
break;
}
return pid;
}
Jollen 的說明
Linux kernel 內部的 getppid 實作常式 (routine) - sys_getppid 的程式碼並不難懂,
在這裡我們先忽略 SMP 與 preemptive scheduling 的議題,因此有一段落的程式碼我們故意視而不見,讓我們來討論剩下的程式碼:
asmlinkage long sys_getppid(void)
{
int pid;
struct task_struct *me = current;
struct task_struct *parent;
parent = me->group_leader->real_parent;
for (;;) {
pid = parent->tgid;
#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
{
...
}
#endif
break;
}
return pid;
}
struct task_struct 的 field - '
group_leader ' 是一個 pointer,指向 thread
(process) group 的 leader;
struct task_struct 的 field - '
real_parent '
是一個 pointer,指向 task 的 "real parent":
struct task_struct {
...
/* real parent process (when being debugged) */
struct task_struct *real_parent ;
struct task_struct *parent; /* parent process */
...
/* threadgroup leader */
struct task_struct *group_leader ;
...
}
real_parent 與 parent
在 struct task_struct 裡,我們發現一件有趣的事:怎麼會有 real_parent 與 parent
二個 field 呢?
我們姑且不去說明 parent 的用義,real_parent 指的是建立(create)此 process(task)的
process,當建立該 process 的 process(real_parent )已經不存在時(eg. terminate),real_parent
便指向 init process。
好囉,我們知道一件重要的事情了,要找到「我的爸爸」 kernel code 寫法是:
struct task_struct *me = current ; /* 我自己 */
struct task_struct *parent; /* 我爸 */
parent = me->real_parent; /* 我真正的爸(生下我的)*/
但這裡的寫法並不正確。讓我們繼續往下討論。
Group Leader
每一個 process 都是某些 process group 的成員,所有的 process group 都有一個帶班的 process(group
leader)。比如說,當 GNU/Linux 系統開機時,init process 就是所有 process 的 group leader。
因此 process 的 parent process 應該是「group leader 的 real parent」,所以我們要先索引到 process
descriptor 的 group_leader 欄位,然後再索引到 group leader 的 real_parent 。
TIP 借用一下作業系統的說法:struct task_struct 就是 process 的
process descriptor。
所以,正確的 kernel code 寫法是:
struct task_struct *me = current ; /* 我自己 */
struct task_struct *parent; /* 我爸 */
parent = me->group_leader->real_parent; /* 領班的真正爸,才是我的爸 = = "
*/
這樣就能理解 Linux 2.6 的 sys_getppid 實作了,雖然有一點不太直覺,不過看起來是頗有學問的設計。知道怎麼找到
parent process 後,再由 process descriptor 裡把 PID 拿出來就行了:
parent->tgid;
作業系統還真是有趣。
--jollen
作者/陳俊宏
http://www.jollen.org
nice() 是用來變更 process 優先序(priority)的 system call,nice() system
call 叫用(invoke)的 system call 實作常式為 sys_nice 。sys_nice 服務常式(service
routine)是 Linux 排程(scheduling)相關的服務常式中最基本(也是最古老)的一個。
34
sys_nice
linux/kernel/sched.c
類別:Scheduling
原型宣告:long sys_nice (int increment);
用途說明:變更 process 的優先序。
Kernel (2.6.11 or above) 實作:
/*
* sys_nice - change the priority of the current process.
* @increment: priority increment
*
* sys_setpriority is a more generic, but much slower function that
* does similar things.
*/
asmlinkage long sys_nice(int increment)
{
int retval;
long nice;
/*
* Setpriority might change our priority at the same moment.
* We don't have to worry. Conceptually one call occurs first
* and we have a single winner.
*/
if (increment < -40)
increment = -40;
if (increment > 40)
increment = 40;
nice = PRIO_TO_NICE(current->static_prio) + increment;
if (nice < -20)
nice = -20;
if (nice > 19)
nice = 19;
if (increment < 0 && !can_nice(current, nice))
return -EPERM;
retval = security_task_setnice(current, nice);
if (retval)
return retval;
set_user_nice(current, nice);
return 0;
}
Jollen 的說明
首先,讓我們先看一下 NICE(2) 的內容:
NAME
nice - change process priority
SYNOPSIS
#include
int nice(int inc);
DESCRIPTION
nice adds inc to the nice value for the calling pid. (A large nice
value means a low priority.) Only the superuser may specify a negative
increment, or priority increase.
參數 inc 是所要改變的 priority 數量,inc 可以是正數也可以是負數。正數表示 priority 變多(多加上
inc,表示 low
priority),若要提升 priority,inc 只要指定為負數即可;根據 NICE(2) 的說明,只有 superuser
才能指定負數,也就是把提高優先序。
nice() 會把 process 的 priority 變更為 "priority+ inc "。
sys_nice() 的實作
以下是 sys_nice() service routine 的原型:
long sys_nice(int increment)
increment 就是前面所提到的 inc 參數(透過 system call 機制傳遞,並非函數呼叫傳值)。increment 的範圍被 kernel
限定在 [40,-40] 的範圍內:
if (increment < -40)
increment = -40;
if (increment > 40)
increment = 40;
所以如果呼叫 nice() 時,指定的優先改變量超過 [40,-40] 時,是得不到預期效果的。sys_nice 接著先把 process
的 "priority" 數值轉算成 "nice" 值,然後再加上 increment(因為 increment 是一個 "nice" 值,不是
"priority" 值):
nice = PRIO_TO_NICE(current->static_prio) + increment;
得到的 "nice" 值,必須限定在 [19,-20] 的範圍內:
if (nice < -20)
nice = -20;
if (nice > 19)
nice = 19;
再來,如果 increment 小於 0,也就是 user 的 "nice" 值是負的,那就要檢查是不是可以變更此 process 的
"priority":
if (increment < 0 && !can_nice (current, nice))
return -EPERM;
不過這裡的重點是 can_nice() 所呼叫的 kernel API -
capable() ,並非 can_nice() 本身,再追一下 can_nice() 的原始碼可以找到這段:
capable(CAP_SYS_NICE)
capable() 用來檢查 process 的 "capability",不過我們先在這裡略過這個主題。
Process capability 若允許變更 priority,就修改 process 的 priority,否則 return -EPERM 。
更多關於 sys_nice()
sys_nice() 目前大概是為了要向後相容而持續存在於 Linux 原始碼裡,目前已經推薦改用 sys_setpriority() 服務常式了。因此在
Linux programming 上,我們也要改用 setpriority() system call 來取代 nice()。以下是
GETPRIORITY(2):
NAME
getpriority, setpriority - get/set program scheduling priority
SYNOPSIS
#include
#include
int getpriority(int which, int who);
int setpriority(int which, int who, int prio);
TIP "priority" 表示 process 的優先序,數字越大表示優先序越低;"nice" 指的是要改變的
priority 量,例如 -10 表示要把 priority 減少 10,即提高優先序。
--jollen
作者/陳俊宏
http://www.jollen.org
'./configure' 的設定決定 root filesystem 的架構(architecture),即 software stack 的設計。以我們「Embedded Linux 的系統管理 (x86)」課程舉出的 Nano-X project 案例來說,我們可以規劃出 2 種架構:
1. 典型的 Desktop (PC) 使用的架構 - ffplay + SDL + x11。
2. 讓 ffplay 在 Nano-X 介面裡撥放影片 - ffplay + SDL + Nano-X。
其中第 2 點是最有趣的架構,可以讓同學練習 software stack 有關的 './configure' 設定。
首先,同學要先把 FFmpeg 在 x86 上編譯完成,然後我們透過不同的 SDL 管理觀念,讓 ffplay 能夠在 X11 與 Nano-X 的介面上撥放。
不管是在 X11 上撥放影片,或是在 Nano-X 上撥放,都不必動到 FFmpeg(ffplay)。(why?)
嵌入式 Linux 系統管理 - Software Stack 的設定
如果使用 Red Hat Linux 9 (or Fedora) 預設的 SDL,ffplay 的執行畫面如下圖。
圖一:在 X11 上執行的 ffplay
這時 SDL 的編譯設定 (configure) 應該是類似這樣的:
# ./configure --prefix=/usr
--enable-video-x11
--disable-video-fbcon
--disable-nano-direct-fb
--disable-video-nanox
--disable-nanox-share-memory
--disable-alsatest
--with-nanox-pixel-type=0888
我們修改 configure 參數如下:
# ./configure --prefix=/usr
--disable-video-x11
--disable-video-fbcon
--enable-nano-direct-fb
--enable-video-nanox
--enable-nanox-share-memory
--disable-alsatest
--with-nanox-pixel-type=0888
重新編譯並安裝 SDL 後,ffplay 就能在 Nano-X 的介面下撥放影片。如果 Nano-X 的設定是支援 X11 的話,執行後的結果會是下圖的畫面。
圖二:在 Nano-X 上執行的 ffplay (Nano-X with X11)
我們怎麼讓 ffplay 可以在開機後,直接透過 VGA framebuffer 來撥放影片,而不用再進入 X11 呢?做法是:把 Nano-X 設定成支援 VGA framebuufer 即可(Nano-X with VGA FB),至於 SDL 的話,是不用再做任何調整的了!(why?) 當然 ffplay 也不用變動。所以,關於第 2 點的架構做法,可以再細分成:
2.1 ffplay + SDL + Nano-X + X11
2.2 ffplay + SDL + Nano-X + VGA fb
很值得用來練習編譯設定與觀念討論的例子。
Embedded Linux 的考量
「ffplay + SDL + Nano-X」這個架構是適合 Embedded Linux 使用的,只要讓 Nano-X 能完整支援 target device,並把 SDL 與 FFmpeg 移植到 target device,便能在 target device 上撥放影片檔。
前幾天介紹到 Linux 的一個排程(Scheduling)系統服務叫做 sys_nice() ,與 sys_nice() 相關的 system call service 是 sys_getpriority() 與 sys_setpriority() ,不過在看 kernel code 前,我們應該先試著了解 getpriority() 與 setpriority() 二個 system call 的用法。
先來了解一下 getpriority() 的用途,GETPRIORITY(2):
SYNOPSIS
#include <sys/time.h>
#include <sys/resource.h>
int getpriority(int which, int who);
getpriority() 的 which 參數用來指定要取得 priority 對象:process、process group 或 user ID。
最容易學習的方式就是讀範例,所以我們將會設計 2 個範例來執行。
which 參數:
PRIO_PROCESS :who 參數指定 process ID,傳回 process 的 priority。
PRIO_PGRP :who 參數指定 process group ID,傳回 process group 的 priority。
PRIO_USER :who 參數指定 user ID,傳回 user 的 priority 。
Jollen 寫了二個程式:
setpriority.c 與
getpriority.c 。先來測試一下。
實測結果
隨便找一個對象下手:
# ps ax
...
17349 ? S 0:02 [httpd]
...
把 PID 17349 的 scheduling priority 往上提升一級:
# ./getpriority 17349
Process (17349) Priority is 0 .
# ./setpriority
Usage: ./setpriority [pid] [priority (-20~19)]
# ./setpriority 17349 -1
OK.
# ./getpriority 17349
Process (17349) Priority is -1 .
另外,系統指令 nice 可以用來設定執行命令的 process priority:
NICE(1) FSF NICE(1)
NAME
nice - run a program with modified scheduling priority
SYNOPSIS
nice [OPTION] [COMMAND [ARG]...]
DESCRIPTION
Run COMMAND with an adjusted scheduling priority. With no COMMAND,
print the current scheduling priority. ADJUST is 10 by default. Range
goes from -20 (highest priority) to 19 (lowest).
-n, --adjustment=ADJUST
increment priority by ADJUST first
--help display this help and exit
--version
output version information and exit
程式碼
/* Program: getpriority.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
int main(int argc, char *argv[])
{
/* getpriority() 傳回的類別是 int */
int prio_process, prio_pgroup, prio_user;
pid_t pid;
if (argc != 2)
return -1;
pid = atoi(argv[1]);
prio_process = getpriority(PRIO_PROCESS, pid);
printf("Process (%d) Priority is %d.\n", pid, prio_process);
return 0;
}
/* Program: setpriority.c */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
int main(int argc, char *argv[])
{
int errno, prio;
pid_t pid;
if (argc != 3) {
printf("Usage: %s [pid] [priority (-20~20)]\n", argv[0]);
return -1;
}
pid = atoi(argv[1]);
prio = atoi(argv[2]);
errno = setpriority(PRIO_PROCESS, pid, prio);
printf("OK.\n");
return 0;
}
了解 s
etpriority() 與
getpriority() 後,就可以開始研究 system call service - 'sys_setpriority' 與 'sys_getpriority' 了。
是蟲啦,不是警告。在 Linux kernel 的 mailing list 看到一則有意思的張貼,全文 如下,Jollen 把重點用紅色標示出來:
* Jeremy Fitzhardinge wrote:
> A warning is a warning, not a BUG.
> - printk("BUG: warning at %s:%d/%s()n", __FILE__,
> + printk("WARNING at %s:%d %s()n", __FILE__,
i'm not really happy about this change.
Firstly,
most WARN_ON()s are /bugs/, not warnings ...
If it's a real
warning, a KERN_INFO printk should be done.
Secondly, the reason i changed it to the 'BUG: ...' format is that i
tried to make it easier for automated tools (and for users) to figure
out that a kernel bug happened.
Ingo
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
很重要,一定要看的概念。在 Linux kernel 裡,WARN_ON() 所秀出來的訊息格式為「BUG: xxx」,表示這是一個臭蟲。如果是警告訊息,則是用 loglevel 'KERN_INFO' 來列印訊息。
所以,這位老兄解釋的很清楚,這類的 "warning" 訊息是 kernel 的 "bug",並不是字面上所表示的「警告」訊息!
跟學弟妹的座談演講,分享自己的工作經驗,並且簡單介紹該如何進入嵌入式 Linux 領域。請按我下載
nice() 是用來變更 process 優先序(priority)的 system call 也是最古老的一個,sys_getpriority()
與 sys_setpriority() 則是取代 sys_nice() 的新實作,今天我們先討論一下 'sys_getpriority'。
96
sys_getpriority
linux/kernel/sys.c
類別:Systems
原型宣告:long sys_getpriority (int which, int who);
用途說明:取得 process 的排程優先序(Priority)。
Kernel (2.6.11 or above) 實作:
/*
* Ugh. To avoid negative return values, "getpriority()" will
* not return the normal nice-value, but a negated value that
* has been offset by 20 (ie it returns 40..1 instead of -20..19)
* to stay compatible.
*/
asmlinkage long sys_getpriority(int which, int who)
{
struct task_struct *g, *p;
struct user_struct *user;
long niceval, retval = -ESRCH;
if (which > 2 || which < 0)
return -EINVAL;
read_lock(&tasklist_lock);
switch (which) {
case PRIO_PROCESS:
if (!who)
who = current->pid;
p = find_task_by_pid(who);
if (p) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
}
break;
case PRIO_PGRP:
if (!who)
who = process_group(current);
do_each_task_pid(who, PIDTYPE_PGID, p) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
} while_each_task_pid(who, PIDTYPE_PGID, p);
break;
case PRIO_USER:
user = current->user;
if (!who)
who = current->uid;
else
if ((who != current->uid) && !(user = find_user(who)))
goto out_unlock; /* No processes for this user */
do_each_thread(g, p)
if (p->uid == who) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
}
while_each_thread(g, p);
if (who != current->uid)
free_uid(user); /* for find_user() */
break;
}
out_unlock:
read_unlock(&tasklist_lock);
return retval;
}
Jollen 的說明
讓我們來看一下 system call service - 'sys_getpriority' 的程式實作。首先是 sys_getpriority()
的參數:which 與 who ,這二個參數對應到 getpriority() 的 which 與
who 參數;如果您不是很清楚 which /who 的話,請參閱前幾天的日記 。
我們拿底下的程式片斷來討論:
switch (which ) { /* 請看 1. */
case PRIO_PROCESS : /* 請看 2. */
if (!who) /* 請看 2. */
who = current->pid;
p = find_task_by_pid (who); /* 請看 3. */
if (p) { /* 請看 4. */
niceval = 20 - task_nice (p); /* 請看 5. */
if (niceval > retval)
retval = niceval;
}
break;
...
}
說明如下:
判斷 which 參數,假設我們想要取得 process 的 priority,那麼 which 的值就是
PRIO_PROCESS 。
若 which = PRIO_PROCESS ,則 who 的值就是 process ID。因為 who
不應該為 0,所以如果 who 是 0 的話,就指定為 current 的 PID。
find_task_by_pid() 是 kernel API,用來取得 PID 的 process descriptor。
如果 p 不是 NULL,就呼叫 task_nice() ,取得 process 的「nice 值」,然後傳回
nice 值。
kernel 的 nice 值範圍為 [-20..19],但 user-space 的 nice 值是
[40,1],所以要做換算:[20-(-20)..20-19] = [40..1]。
喔!要取得 process priority 的 kernel 實作看起來還挺簡單的。我們又學到了:
kernel API - find_task_by_pid() :傳入 PID,取得該 process 的 process
descriptor。
kernel API - task_nice() :傳入 process descriptor,取得該 process 的
priority(nice 值)。
所謂的「nice 值」就是 process 的優先序(優先等級、priority)。
Linux System Calls' Forum, #1:(第20號系統服務) sys_getpid
Linux System Calls' Forum, #2:(第199,201,200,202,224號系統服務) sys_getuid,
sys_geteuid, sys_getgid, sys_getegid, sys_gettid
Linux System Calls' Forum, #4:(第34號系統服務) sys_nice
getpriority() 與 setpriority() 程式設計
在伺服器(server)技術的發展藍圖中(roadmap),虛擬伺服器(virtual server)是 Intel 近來所著墨的重點。由以往單一硬體對單一作業系統(operating system)的伺服器架構(1 physical server v.s. 1 OS),未來將會演進成為單一硬體對多個作業系統的架構(1 physical server v.s. multiple OS)。
Intel 的 Virtualization Technology 就是一個這樣的新技術。Intel 的 Virtualization Technology 可以讓處理器支援多個 OS,不過這其實是基於我們所熟悉的虛擬機器軟體(例如:VMware、QEMU、Xen等)才能達到的,所以這是一個由「processor + chipsets + BIOS + 虛擬機器軟體」互相運作所實現的技術。
Virtual Machine Monitor (VMM)
軟體實作的虛擬機器在此技術領域中被統稱為「VMM - Virtual Machine Monitor」,現在已經有支援 Intel Virtualization Technology 的 VMM 了,那就是知名的 Xen。相關的參考網址如下:
Extending Xen with Intel Virtualization Technology - http://www.intel.com/technology/itj/2006/v10i3/3-xen/1-abstract.htm
Xen - http://www.xensource.com/index.html
接下來,就是我們今天在網路上所看到的重點了!
KVM: Kernel-based Virtual Machine
今天,看到了 2.6 kernel 的 KVM patch。KVM(Kernel Virtual Machine)是 Intel's virtualization technology 的驅動程式!KVM 驅動程式目前支援 i386 與 x86_64 "host",且「All combinations are allowed except x86_64 guest on i386 host.」。
比較特殊的是 Linux 2.6 的 KVM 驅動程式支援三種模式:kernel mode、user mode 與 guest mode。KVM 驅動程式的 user-space 介面是 '/dev/kvm',因此 process 可以執行自己的 virtual machine,在一台電腦上也能執行多個 virtual machine。Guest mode:
「Guest mode has its own address
space mapping guest physical memory (which is accessible to user mode by
mmap()ing /dev/kvm). Guest mode has no access to any I/O devices; any such
access is intercepted and directed to user mode for emulation. 」。
取得 Patch 與追踪主題
[PATCH 0/7] KVM: Kernel-based Virtual Machine
[PATCH 1/7] KVM: userspace interface
[PATCH 2/7] KVM: Intel virtual mode extensions definitions
[PATCH 3/7] KVM: kvm data structures
[PATCH 5/7] KVM: mmu virtualization
[PATCH 6/7] KVM: x86 emulator
[PATCH 7/7] KVM: plumbing
關於更多 Intel 的 Virtualization Technology
可以參考的網址如下:
Make virtualization a reality - http://www.intel.com/cd/channel/reseller/asmo-na/eng/products/server/processors/250640.htm
Server Virtualization Technology - http://www.intel.com/business/bss/products/server/virtualization_wp.pdf
getpriority() 若指定 which 是 PRIO_PGRP 的話,那麼便能取得 process group 裡的「最大 priority 值」。先節錄相關 kernel code 如下:
asmlinkage long sys_getpriority(int which, int who)
{
...
case PRIO_PGRP:
if (!who)
who = process_group(current);
do_each_task_pid(who, PIDTYPE_PGID, p) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
} while_each_task_pid(who, PIDTYPE_PGID, p);
break;
...
}
接續昨天的 sys_getpriority() ,讓我們再來看一下 PRIO_PGRP 參數的實作:
1. 如果 who 是 0 的話,先呼叫 process_group() 取得 group ID。
2. 使用 do_each_task_pid 與 while_each_task_pid 巨集做迴圈。
3. 在迴圈裡面,呼叫 task_nice() 取得 process 的 priority,然後判斷目前的 nice 值是否大於先前的 nice 值。這麼做的用意是「找到 process group 裡最大的 nice 值 (lowest priority) 後回傳」。
了解 sys_getpriority() 後,要看懂 sys_setpriority() 就不是問題了。
97
sys_setpriority
linux/kernel/sys.c
類別:Systems
原型宣告:long sys_setpriority (int which, int who, int niceval);
用途說明:變更 process 的排程優先序(Priority)。
Kernel (2.6.11 or above) 實作:
asmlinkage long sys_setpriority(int which, int who, int niceval)
{
struct task_struct *g, *p;
struct user_struct *user;
int error = -EINVAL;
if (which > 2 || which < 0)
goto out;
/* normalize: avoid signed division (rounding problems) */
error = -ESRCH;
if (niceval < -20)
niceval = -20;
if (niceval > 19)
niceval = 19;
read_lock(&tasklist_lock);
switch (which) {
case PRIO_PROCESS:
if (!who)
who = current->pid;
p = find_task_by_pid(who);
if (p)
error = set_one_prio(p, niceval, error);
break;
case PRIO_PGRP:
if (!who)
who = process_group(current);
do_each_task_pid(who, PIDTYPE_PGID, p) {
error = set_one_prio(p, niceval, error);
} while_each_task_pid(who, PIDTYPE_PGID, p);
break;
case PRIO_USER:
user = current->user;
if (!who)
who = current->uid;
else
if ((who != current->uid) && !(user = find_user(who)))
goto out_unlock; /* No processes for this user */
do_each_thread(g, p)
if (p->uid == who)
error = set_one_prio(p, niceval, error);
while_each_thread(g, p);
if (who != current->uid)
free_uid(user); /* For find_user() */
break;
}
out_unlock:
read_unlock(&tasklist_lock);
out:
return error;
}
Jollen 的說明
程式一開始先判斷 which 參數的正確性,並且將 user process 所指定的 nice 值限定在 [-20..19] 的範圍內:
if (which > 2 || which < 0)
goto out;
/* normalize: avoid signed division (rounding problems) */
error = -ESRCH;
if (niceval < -20)
niceval = -20;
if (niceval > 19)
niceval = 19;
底下我們來討論 PRIO_PROCESS 與 PRIO_PGRP
參數的實作,強烈建議您先行閱讀本文最後所整理的文章,再回頭來看以下的說明,才能得到最佳學習效果。
變更 priority:PRIO_PROCESS
主要的程式片斷如下:
case PRIO_PROCESS : /* 請看 1. */
if (!who)
who = current->pid; /* 請看 1. */
p = find_task_by_pid(who); /* 請看 2. */
if (p) /* 請看 3. */
error = set_one_prio (p, niceval, error); /* 請看 3. */
break;
說明:
若 which = PRIO_PROCESS ,則 who 的值就是 process ID。因為 who
不能為 0,所以如果 who 是 0 的話,就指定為 current 的 PID。
find_task_by_pid() 是 kernel API,用來取得 PID 的 process descriptor。我們已經學過了!
如果 p 不是 NULL,就呼叫 set_one_prio() ,修改 p 的「nice 值」為
niceval 。
變更 priority:PRIO_PGRP
主要的程式片斷如下:
case PRIO_PGRP :
if (!who)
who = process_group(current);
do_each_task_pid(who, PIDTYPE_PGID, p) { /* 請看 1. */
error = set_one_prio (p, niceval, error); /* 請看 1. */
} while_each_task_pid(who, PIDTYPE_PGID, p); /* 請看 1. */
break;
說明:
在迴圈裡,逐一修改 process group 裡的 process,將其優先序變更為 niceval 。這樣的迴圈,在
sys_getpriority() 也看過一次!
二段 kernel code 都呼叫到此 kernel API:
kernel API - set_one_prio() :傳入 process descriptor 與新的 nice 值,將
process 的 priorioty 做變更。
"*_PGRP "(process group)是 kernel 2.4 的 sematics,「current->pgrp 」是
kernel 2.4 的寫法。我們未來有機會的話再做說明。
Jollen 計畫在自己的 Blog 陸續與大與分享一些 Linux kernel 的研究心得,我們的寫作方向是以重點式的心得整理為主,不過希望加入一些教學性的風格,希望對大家有幫助。到目前為止,我們與大家分享了 Linux system call service 的幾篇日記,接下來仍會再討論幾個系統服務。
故事是這樣開始的
「Linux System Calls' Forum(LSCT)」旨在討論重要的系統服務(system service),以便將來我們能用最有效率的方式研究 kernel;「Jollen 的 Linux 核心分享包」則是在討論 Linux kernel 與作業系統有關的主題,方向是「討論 kernel 實作」。
Jollen 打算以「講義配合 Blog 開講」的方式跟大家一起玩核心!「一份講義」會以多篇日記方式跟大家討論,這裡的講義是從以前的筆記、演講、內訓課程或是討論會節錄並整理而成(需要時當然也會重新編製),Jollen 打算以講義的形式來整理,因此可能並不適合當做「教材」來使用;因此,在與朋友分享這份講義的同時,也要請大家一同分享 Jollen's Blog 網站。
第一份講義請由本文最後的網址下載,在開始看 kernel 前,以下的準備工作是很重要的:
1. 準備一份 Linux 2.6.11 以上的 kernel source code。請參考以下的幾張投影片,大略了解 kernel code 的分佈與原始碼結構。
2. 準備 Source Insight。這個工具非常熱門,所以我想大家都己經有了!
3. 先備知識(enabling technology):作業系統原理是一定要啦。大家在學校都修過這門必修課,不過日記偶而也會提到參考章節,所以可以的話,也能準備一份在手邊。
發佈計畫
以目前的手稿整理狀況來看,大約會以一星期 1~2 篇日記的進度刊出,第一份講義計畫以 10 篇的篇幅來講解。
Kernel Source 結構
重要目錄:
System Call Interfaces: 實作程式碼散落於各目錄
Network System: net/ 目錄
File System: fs/ 目錄
Memory Management: mm/ 目錄, 一些 helper-routine 實作於 arch/ 目錄
Process Management: 大部份實作於 kernel/ 目錄
Interprocess Communication: ipc/ 目錄
Device Drivers: drivers/ 目錄
SELinux (Security Enhanced Linux): security/ 目錄 (only kernel 2.6 or kernel 2.4 for mobile phone)
2006.10.20:
Linux System Calls' Forum, #6:(第97號系統服務) sys_setpriority
2006.10.19:
Linux System Calls' Forum, #5:(第96號系統服務) sys_getpriority
2006.10.15:
Linux System Calls' Forum, #4:(第34號系統服務) sys_nice
2006.10.14:
Linux System Calls' Forum, #3:(第64號系統服務) sys_getppid
2006.10.12:
Linux System Calls' Forum, #2:(第199,201,200,202,224號系統服務)
sys_getuid, sys_geteuid, sys_getgid, sys_getegid, sys_gettid
2006.10.11:
Linux System Calls' Forum, #1:(第20號系統服務) sys_getpid
網路上已經有人發表初步的 ext4 filesystem benchmark 數據了,該測試報告的作者將 ext4 的 "extents" 模式開啟,I/O scheduler 為 CFQ。CFQ 是 kernel 2.6.18 之後預設的 I/O 排程法 。
由這篇測試報告來看,ext4 在「寫入」的效能表現上,大幅領先 ext3 與 raiser4;不過在其它測試項,ext4 則是與 ext3/raiser4 互有領先。但是整體來看,ext4 的整體效能表現確實比 ext3 來得優秀。
該測試報告也提到,由於 ext4 仍在開發測試階段,一切都要等穩定版出現後,再來做更進一步的評估了。測試報告原文:
http://linux.inet.hr/first_benchmarks_of_the_ext4_file_system.html
Linux-kernel mailing list 也有討論串:
http://forum.jollen.org/index.php?showtopic=6705
GNU gv 是用來讀取 PostScript 與 PDF 格式文件的利器,GNU gv 其實只是一個前端界面 (front-end),實際上 GNU gv 是由 ghostview 1.5 衍生而來的,並且使用 ghostscript 來直譯文件。
GNU gv 的官方網站:http://www.gnu.org/software/gv/
gv 的使用
我們可以在 X Window System 底下直接下命令,例如:
linux# gv Trans.PS.gz
這是利用 gv 觀看 Trans.PS.gz 文件的範例,特別的是,經由 gzip 壓縮過的 PostScript 或 PDF 文件不需解壓即可直接利用 gv 閱讀,非常的方便。
利用 gv 也可以閱讀 PDF 文件,例如:
linux# gv imug.pdf
gv 命令列的參數:
□ -ad
讀取 資源檔。-ad 參數的優先權較 -style 來得高。
□ -antialias,-noantialias
是否要使用 antialiasing 功能。
□ -arguments
gv 是 ghostscript 的 front-end,在這裡的 是要傳給 ghostscript 的參數。
□ -center,-nocenter
是否要使用自動置中功能。
□ -dsc,-nodsc
是否要使用 DSC (document structuring convention)。如果不使用 DSC (-nodsc),gv 就不會檢查文件的結構,並且直接將整個檔案傳給 ghostscript。在 -nodsc 模式下,閱讀文件時不會有頁數顯示,而且無法在文件裡移動。
□ -eof,-noeof
使用 -eof 時,當遇到結束的註解時,即表示文件的結束。有些文件,例如將兩個文件合併,雖然有結束的註解,但不表示檔案的結束,這時加上 -noeof 參數才能閱讀全部內容。
□ -pixmap,-nopixmap
如果使用 -pixmap 參數,gv 會以 pixmap 的方式將顯示過的內容保存下來,反之,-nopixmap 參數表示是由 X Server 負責這項工作,而不是 gv。
□ -v
查詢版本編號。
□ -h,-?
顯示求助畫面 (參數用法)。
□ -help
顯示較清楚的求助畫面。
□ -scale
是一個整數,指定文件的放大倍數。
□ -scalebase
設定預設的放大倍數。
□ -monochrome, -grayscale, -color
設定調色盤,即文件的顏色樣式。
□ -media
設定紙張大小。
□ -page
指定文件的標名。
□ -portrait,-landscape,-seascape,-upsidedown
設定文件的顯示位置。
□ -quiet,-noquiet
是否要以 -dQUIET 參數執行 ghostscript。
□ -resize,-noresize
設定gv是否可以自動依視窗大小調整文件的大小。
□ -safer,-nosafer
是否要以 -dSAFER 參數執行 ghostscript。
□ -spartan
和 -style gv_spartan.dat 同義。
□ -style
指定設定檔 (resource file)。這個參數的優先權比 -ad 高。
□ -swap,-noswap
是否要交換 landscape 與 seascape 的顯示方式。
□ -watch,-nowatch
使用 -watch 參數的話,預設是 gv 每一秒會檢查一次文件內容是否有改變,如果有的話,gv 即顯示新的內容。
gv 的設定
如果嫌每次都要打一堆煩人的參數,其實我們可以把這些常用的參數編輯在一個檔案裡 (resource file)。
gv 會先使用由 XFILESEARCHPATH 環境變數所指定的 resource file,如果沒有 XFILESEARCHPATH 環境變數,則使用 /usr/X11R6/lib/X11/app-defaults/GV,系統資源檔可以設定 gv 的預設執行環境。
我們可以依我們平時閱讀的習慣來設定自己的 gv 環境,個人化的 resource file 位於 ~/.gv,gv 會優先使用 ~/.gv 這個 resource file。
gv 也有提供我們 resource file 的設定範例,請由 /usr/X11R6/lib/X11/gv/ 將 gv_user.ad 複製到 ~/.gv:
linux# cp /usr/X11R6/lib/X11/gv/gv_user.ad ~/.gv
GNU gv 提供以下 3 個設定範例:
1. /usr/X11R6/lib/X11/gv/gv_class.ad
2. /usr/X11R6/lib/X11/gv/gv_system.ad
3. /usr/X11R6/lib/X11/gv/gv_user.ad
gv_user.ad 是 gv 個人 resource file 的設定範例,gv_system.ad 是系統 resource file 的設定範例,但新裝好的 gv,實際上這兩個檔案內容是一樣的。
gv 的 resource file (gv_user.ad):
!
! gv_user.ad
! User specific application defaults for gv
! Copyright (C) 1995, 1996, 1997 Johannes Plass
!
!########## gv_user_res.dat
!##### Application specific Resources
GV.pageMedia: automatic
GV.orientation: automatic
GV.fallbackOrientation: portrait
GV.swapLandscape: False
GV.autoCenter: True
GV.antialias: True
GV.respectDSC: True
GV.ignoreEOF: True
GV.confirmPrint: True
GV.reverseScrolling: False
GV.scrollingEyeGuide: True
GV.autoResize: True
GV.maximumWidth: screen-20
GV.maximumHeight: screen-44
GV.minimumWidth: 400
GV.minimumHeight: 430
GV.confirmQuit: 1
GV.watchFile: False
GV.watchFileFrequency: 1000
GV.showTitle: True
GV.miscMenuEntries: redisplay \n\
# update \n\
stop \n\
line \n\
toggle_current \n\
toggle_even \n\
toggle_odd \n\
unmark \n\
line \n\
print_all \n\
print_marked \n\
save_all \n\
save_marked
GV.scale: 0
GV.scaleBase: 1
GV.scales: Natural size, 1.000, screen \n\
Pixel based, 1.000, pixel \n\
0.100, 0.100 \n\
0.125, 0.125 \n\
0.250, 0.250 \n\
0.500, 0.500 \n\
0.707, 0.707 \n\
1.000, 1.000 \n\
1.414, 1.414 \n\
2.000, 2.000 \n\
4.000, 4.000 \n\
8.000, 8.000 \n\
10.00, 10.00
GV.medias: Letter, 612 792 \n\
# LetterSmall, 612 792 \n\
Legal, 612 1008 \n\
Statement, 396 612 \n\
Tabloid, 792 1224 \n\
Ledger, 1224 792 \n\
Folio, 612 936 \n\
Quarto, 610 780 \n\
# 7x9, 504 648 \n\
# 9x11, 648 792 \n\
# 9x12, 648 864 \n\
# 10x13, 720 936 \n\
10x14, 720 1008 \n\
Executive, 540 720 \n\
# A0, 2384 3370 \n\
# A1, 1684 2384 \n\
# A2, 1191 1684 \n\
A3, 842 1191 \n\
A4, 595 842 \n\
# A4Small, 595 842 \n\
A5, 420 595 \n\
# A6, 297 420 \n\
# A7, 210 297 \n\
# A8, 148 210 \n\
# A9, 105 148 \n\
# A10, 73 105 \n\
# B0, 2920 4127 \n\
# B1, 2064 2920 \n\
# B2, 1460 2064 \n\
# B3, 1032 1460 \n\
B4, 729 1032 \n\
B5, 516 729 \n\
# B6, 363 516 \n\
# B7, 258 363 \n\
# B8, 181 258 \n\
# B9, 127 181 \n\
# B10, 91 127 \n\
# ISOB0, 2835 4008 \n\
# ISOB1, 2004 2835 \n\
# ISOB2, 1417 2004 \n\
# ISOB3, 1001 1417 \n\
# ISOB4, 709 1001 \n\
# ISOB5, 499 709 \n\
# ISOB6, 354 499 \n\
# ISOB7, 249 354 \n\
# ISOB8, 176 249 \n\
# ISOB9, 125 176 \n\
# ISOB10, 88 125 \n\
# C0, 2599 3676 \n\
# C1, 1837 2599 \n\
# C2, 1298 1837 \n\
# C3, 918 1296 \n\
# C4, 649 918 \n\
# C5, 459 649 \n\
# C6, 323 459 \n\
# C7, 230 323 \n\
# DL, 312 624
GV.magMenu: 2, 2 \n\
4, 4 \n\
8, 8 \n\
16, 16 \n\
32, 32 \n\
64, 64
!##### Ghostview Widget
GV*Ghostview.background: white
GV*Ghostview.foreground: black
!########## gv_intern_res.dat (generated by makefile)
GV.gsInterpreter: gs
GV.gsCmdScanPDF: gs -dNODISPLAY -dQUIET -sPDFname=%s -sDSCname=%s pdf2dsc.ps -c quit
GV.gsCmdConvPDF: gs -dNODISPLAY -dQUIET -dNOPAUSE -sPSFile=%s %s -c quit
GV.gsX11Device: -sDEVICE=x11
GV.gsX11AlphaDevice: -dNOPLATFONTS -sDEVICE=x11alpha
GV.gsSafer: True
GV.gsQuiet: True
GV.gsArguments:
GV.uncompressCommand: gzip -d -c %s > %s
GV.printCommand: lpr
!########## gv_make_res.dat (generated by makefile)
GV.scratchDir: ~/
GV.defaultSaveDir: ~/
GV.fallbackPageMedia: letter
GV.useBackingPixmap: True
GV*dirs: Home\n\
Tmp\n\
/usr/doc\n\
/usr/local/doc
GV*filter: no .*
GV*filters: None\n\
*.*ps* *.pdf* no .*\n\
*.*ps* no .*\n\
*.pdf* no .*\n\
no .*
設定說明
□ antialias
是否使用 antialias 功能 (True/False)。
□ autoCenter
是否使用自動置中功能 (True/False)。
□ autoResize
是否依照目前文件的頁面大小來調整視窗 (True/False)。
□ confirmPrint
列印時是否需要額外的確認 (True/False)。
□ confirmQuit
離開時是否要確認 (0/1/2)。預設值是 1 表示文件內容有變更時 (例如轉換格式) 才確認,0 表示永遠做不確認,2 表示每次離開時都做確認。
□ scrollingEyeGuide
利用鍵盤捲動文件時是否提示上一頁的部份,使用這個參數,在捲動文件時才能分辨的出那些內容是上一頁的舊內容 (True/False)。
□ ignoreEOF
是否忽略 EOF,當 gv 遇到結束的註解時,並不表示檔案的結束,可能文件中間來雜了 EOF,設定 ignoreEOF=True 時才能完全閱讀這樣的文件 (True/False)。
□ respectDSC
是否要使用 DSC (document structuring convention)。如果不使用 DSC,gv 就不會檢查文件的結構,並且直接將整個檔案傳給 ghostscript (True/False)。在 respectDSC=False 時,閱讀文件時不會有頁數顯示,而且無法在文件裡移動。
□ swapLandscape
landscape 與 seacape 的義意是否要互相交換 (True/False)。
□ scratchDir
設定一個暫存目錄。
□ defaultSaveDir
設定一個預設的存檔目錄。
□ useBackingPixmap
False 表示由 X Server 負責暫存顯示過的內容。True 則是由 gv 以 pixmap 方式暫存顯示過的內容。
□ watchFile
是否要自動檢查文件的改變 (True/False)。
□ watchFileFrequency
設定檢查文件的時間間隔,單位為 milliseconds,這個值必須大於 500 (milliseconds)。當 WathFile 為 True 時這個設定才有效。
□ printCommand
設定列印文件的指令,%s 巨集可用在這個指令的參數上,表示要列印的文件檔名。
□ gsInterpreter
啟動 ghostscript interpreter 的命令。
□ gsCmdScanPDF
由 PDF 格式的檔案中讀取 DSC 的命令。
□ gsCmdConvPDF
將 PDF 的格式轉換成 PostScript 的命令。
□ gsX11Device
啟動 X11 的命令。
□ gsX11AlphaDevice
當 antialiasing 啟動時,執行 X11 的命令。
□ gsSafer
確認 ghostscript 是否應該以 -dSAFER 的參數啟動。
□ gsQuiet
確認 ghostscript 是否應該以 -dQUIET 的參數啟動。
□ gsArguments
設定要傳給 ghostscript 的參數。
□ dirs
設定在目錄列表時可以選擇的目錄。
□ filter
設定 gv 的目錄列表方式,語法:
<filespecs> [no <filespecs>]
例如:
GV*filter: *.ps *.pdf no .*
表示只列出 *.ps 與 *.pdf 的檔案,但不列出 "." 開頭的檔案 (隱藏檔)。
□ filters
設定 Fliters 選單中可用的目錄列表方式。
□ miscMenuEntries
設定在文件上按滑鼠右鍵的彈跳視窗內容(update/redisplay/toggle_current/toggle_even/toggle_odd/unmark/stop/print_all/print_marked/save_all/save_marked/line)。
□ showTitle
是否在 title 上顯示目前所閱讀的文件名稱。
□ maximumWidth, maximumHeight
設定主視窗的最小寬度與高度,必須是正整數,最大當然是螢幕的解析度設定。
□ minimumWidth, minimumHeight
設定主視窗的最小寬度與高度,必須是大於 200 的正整數。
□ scale
設定放大倍數。
□ scaleBase
設定預設的放大倍數,必須為正整數。
□ scales
設定在 Scale 選單中的可用的閱讀放大倍數。
□ orientation
設定預設的文件顯示位置 (portrait/landscape/seascape/upside-down/automatic)。automatic 表示由 DSC 取得。
□ fallbackOrientation
設定自動偵測失敗時的預設紙張大小,value 有 portrait/landscape/seascape/upside-down。
□ medias
設定紙張大小,在 gv 的 Media 選單中可以選擇,如果是以 "!" 或 "#" 開始,表示不列入 Media 的選單中,但仍可以被自動偵測並使用。
□ pagemedia
設定紙張大小,value 為在 paper-sizes 中的設定。value 為 automatic 的話,gv 會試著由 DSC 自動偵測大小。
□ fallbackPageMedia
設定紙張大小,value 為在 paper-sizes 中的設定。當自動偵測失敗時就使用這裡設定的大小。
gv 的操作
底下只是基本常用的按鍵,其它 gv 的操作熱鍵請參考 man gv。
□ O 開啟新檔案
□ Q 離開 gv
□ shift-ctrl-P 列印目檔的文件
□ ctrl-L 重新顯示目前這一頁
□ . 重新顯示目前這一頁
□ V 把目前文件置中
□ Home 跳到第一頁
□ End 跳到最後一頁
□ shift-up 把文件往上捲,或移動 -1 頁
□ shift-left 把文件往左移,或移動 -1 頁
□ shift-down 把文件往下捲,或移動 1 頁
□ shift-right 把文件往右移,或移動 1 頁
□ shift-up 移動 -1 頁
□ shift-down 移動 1 頁
□ c-Enter 移動 -1 頁
□ s-Enter 移動 -1 頁
□ Enter 移動 1 頁
□ B 移動 -1 頁
□ F 移動 1 頁
□ ctrl-left 移動 -5 頁
□ ctrl-right 移動 5 頁
□Insert 移動 -5 頁
□ Delete 移動 5 頁
自 kernel 2.4.1 開始,Linux 已經支援一種稱為 ReiserFS 的日誌式檔案系統。日誌式檔案系統可以提供更安全的檔案保護機制,特別是可以運用在伺服器或是商業環境的應用上。
目前有 4 種較廣為人知的日誌式檔案系統:
□ XFS
□ JFS
□ ext3 / ext4
□ ReiserFS
其中 JFS 是由 IBM 所發展,有興趣的讀者可以參考 IBM 的說明:
http://www-128.ibm.com/developerworks/linux/library/l-jfs.html
另外 XFS 是由 SGI 所發展。我們選擇目前較受觀迎的 ReiserFS 來做介紹。
ReiserFS 的特點
ReiserFS 官方網站:http://www.namesys.com/ 。
日誌式檔案系統被認為相當適合應用在大型的商業伺服器環境中。在這類的環境裡,資料完整性相當的重要。
日誌式檔案系統有著資料庫管理系統 (DBMS) 的交易機制 (Transaction) 特性,一連串的動作如果中間發生錯誤而中斷,資料可以被還原成原來的狀態,可確保資料不會因為未完成,而發生資料不完整的情形。
日誌式檔案會在分割區記錄使用資訊,檔案的寫入動作會先被記錄到記錄檔裡,進行寫入動作時如果中途發生中斷 (例如當機),而重新啟動電腦時,日誌式的檔案系統會根據記錄檔將先前未完成的動作做回覆 (roll back),因此可以保證資料不會因為寫入時發生的中斷,而產生不完整的資料。
安裝 ReiserFS V4
ReiserFS 目前搭載於 kernel 2.4 的是 V3 版,搭載於 kernel 2.6 的是 V4 版。Kernel 的 patch、設定與安裝可參考:
http://www.namesys.com/install_v4.html
另外,也需要用到 reiser4progs 工具程式,下載位置:
ftp://ftp.namesys.com/pub/reiser4progs/libaal-1.0.5.tar.gz
ftp://ftp.namesys.com/pub/reiser4progs/reiser4progs-1.0.5.tar.gz
要製作 reiser4 的分割區的話只要使用 mkfs.reiser4 工具即可:
linux# mkfs.reiser4 /dev/hda5 (範例)
要 mount reiserfs 分割區時,必須加上 -t reiser4 的參數:
linux# mount -t reiser4 /dev/hda5 /home2
如果要對 reiserfs 分割區做檢查,只要使用 fsck.reiser4 指令即可。
講義第1頁到第5頁的說明。
課前說明
作業系統(operating system)理論的教材書,與 process 和 scheduling(排程)相關的主題都是最先被討論的議題。因此,對於 Linux kernel 原始碼的研究,我們也從 process 與 scheduling 有關的部份開始講起。
Process 是執行中的程式,因此「程式如何被執行」是第一個重點,這個部份的觀念當然也包含「程式如何由儲存裝置載入」。緊接著的是,「程式載入記憶體後的佈局(layout)」,這是第二個要研究的重點。當程式被載到記憶體後,作業系統的 scheduler(排程器)便負責排程的工作與執行本文切換(context switch),這是第三個所要討論的重點。
因此,我們將會研究 Linux kernel 的 3 個「process and scheduling」議題:
1. Shell 如何載入執行檔(ELF executables)至記憶體。
2. Process 的 memory 資枓結構。
3. Linux scheduling 與 x86 context switch。
在開始進入主題前,我們先來了解一下 Linux kernel 的開機流程與 scheduler 初始化的關係。然後我們會接著討論「Process Creation」,並一併說明「 Shell 如何載入執行檔(ELF executables)至記憶體」。
編譯 Kernel 2.6 的注意事項
Kernel 2.6 的編譯必須使用 gcc 3.2 版以上,這張講義的 code 位於 init/main.c ,由這段 code 也能知道,在編譯時期(compile time)就會做 gcc 版本的檢查。
Operating System Entry Point
init/main.c:start_kernel() 是「 architecture-independent booting process」的起點(entry point),到這裡表示 kernel 的開機已經進入作業系統核心的部份(OS booting),並且完成了機器平臺(architectural)的初始化與設定工作。
用一句簡單的話來解釋:我們已經脫離 arch/ 目錄啦!start_kernel() 也被解釋為作業系統(operating system、linux kernel)的進入點。
Initialization Sequence
在 main.c 裡的 start_kernel() 函數實作中,我們能看到一大串的「initialization」函數呼叫。這些初始化函數的呼叫是有順序關係的,因此是「initialization sequence」。
在整個初始化程序中,與 scheduler 有關的初始化函數說明如下。
Scheduler Initialization Sequence
我們先來說明一下這 3 個初始化函數的主要目的,再深入討論其內部實作:
1. sched_init() :初始化排程器,包含:初始化 run queue、初始化 “idle thread”。
2. pidhash_init() :初始化 “PID” 的 hash table。
3. fork_init() :計算 kernel 能 “fork” 的最大 process 數量。
operating system, process, scheduling, Linux kernel, scheduler, context switch, ELF, process creation, run queue, idle thread, PID,
跟上我們的腳步:請先行閱讀以下的文章,再看這篇日記!
"class driver" 是 kernel 2.6 driver model 的新觀念,從系統管理面的角度來看,就是 /sysfs。現在 kernel 2.6 已經出現專門針對電池電源管理的驅動程式了:battery class。這是一個有別於以往對於電源管理的實作,雖然 "battery class" 仍只是一個初步實作的驅動程式,但未來 "battery" 與 "AC powe" 在 Linux 驅動程式新觀念底下,將會是一個獨立的 "device"。
新的 battery class 實作中,我們也看到了 OLPC(百元美金電腦)專用的電池驅動程式。程式碼目前可由 kernel 的 git 下載,並可追磫此討論串:http://forum.jollen.org/index.php?showtopic=6899
有網友來信問到,kernel 裡的 system call 實作函數中(C 函數),為什麼每一個函數原型宣告的前面都有一個 "asmlinkage" 的字串?例如:
asmlinkage long sys_nice(int increment)
"asmlinkage" 是在 i386 system call 實作中相當重要的一個 gcc 標籤(tag)。
當 system call handler 要呼叫相對應的 system call routine 時,便將一般用途暫存器的值 push 到 stack 裡,因此 system call routine 就要由 stack 來讀取 system call handler 傳遞的參數。這就是 asmlinkage 標籤的用意。
system call handler 是 assembly code,system call routine(例如:sys_nice)是 C code,當 assembly code 呼叫 C function,並且是以 stack 方式傳參數(parameter)時,在 C function 的 prototype 前面就要加上 "asmlinkage"。
加上 "asmlinkage" 後,C function 就會由 stack 取參數,而不是從 register 取參數(可能發生在程式碼最佳化後)。
更進一步的說明...
80x86 的 assembly 有 2 種傳遞參數的方法:
1. register method
2. stack method
Register method 大多使用一般用途(general-purpose)暫存器來傳遞參數,這種方法的好處是簡單且快速。另外一種傳遞參數的做法是使用 stack(堆疊),assembly code 的模式如下:
push number1
push number2
push number3
call sum
在 'sum' procedure 裡取值的方法,最簡單的做法是:
pop ax
pop ax
pop bx
pop cx
Stack Top 是放 IP,我們傳給 sum procedure 的參數由 stack 的後一個 entry 開始讀取。
其它有關 asmlinkage
1. asmlinkage 是一個定義
2. "asmlinkage" 被定義在 /usr/include/linux/linkage.h
3. 如果您看了 linkage.h ,會發現 "__attribute__" 這個語法,這是 gcc 用來定義 function attribute 的語法。
gcc 提供一種「定義函數屬性(attribute)」的語法,也就是前一篇日記我們所提到的 __attribute__ 標籤。__attribute__ 用來讓我們定義函數的行為,以便告訴 gcc 在編譯時期對此函數做一些特殊的處理或檢查動作。
以 asmlinkage 的例子來說,asmlinkage 的定義是(/usr/include/linux/linkage.h ):
#if defined __i386__
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
#elif defined __ia64__
#define asmlinkage CPP_ASMLINKAGE __attribute__((syscall_linkage))
#else
#define asmlinkage CPP_ASMLINKAGE
#endif
由此可知,以 sys_nice() 的原型宣告來說,以下的二行程式碼是等價的:
asmlinkage sys_nice(...);
__attribute__((regparm(0))) sys_nice();
"__attribute__" 寫在函數宣告之前或之後都可以(左括號前或右括號後),並接著使用一對「雙括號」來註明此函數的屬性。語法:
__attribute__((keywords)) functon_name(...);
屬性的關鍵字如下(節錄自 gcc 3.4.6 manual):
noreturn,noinline, always_inline, pure, const, nothrow, format, format_arg, no_instrument_function, section, constructor, destructor, used, unused, deprecated, weak, malloc,alias, warn_unused_result, nonnull.
regparm 的用法與用途
regparm 的語法是:regparm(number),regparm 屬性只在 Intel 386 平臺上有作用,用來指定最多可以有多少個("number" )參數(arguments)能以暫存器來傳遞,regparm(0) 表示參數都不能透過暫存器來傳遞,因此所有參數都會透過堆疊來傳遞。
更多關於__attribute__
又如,在 ARM 平臺上宣告 "__attribute((interrupt))" 表示此函數是一個 interrupt handler。
其它的屬性說明可參閱 gcc 的手冊。
__attribute__ 是重要的 gcc 用法,對系統程式(system software)的開發尤其重要,應仔細閱讀 gcc 手冊。
gcc 在 i386 / x86_64 的 machine dependent 參數 (-m) 中,有 1 個參數與參數的傳遞相關的:-mregparm=num,這個參數的用途與先前提到的 "__attribute((regparm(?))__" 作用相同*2 。
-mregparm 用來指定有多少個 integer 的參數可以透過暫存器(register)來傳遞, 以下是 -mregparm 的 man(GCC(1)):
Intel 386 and AMD x86-64 Options
...
-mregparam
Use a different function-calling convention where the first two
arguments are passed in registers.
kernel 的編譯設定中(menuconfig),也提供一個選項來設定「暫存器參數的傳遞」。這個設定位於 menuconfig 的 「Processor type and features|Use register arguments (EXPERIMENTAL) (NEW)」,Jollen 所使用的 kernel 版本是 Linux v2.6.11 (for i386),如果您的 kernel 不是 i386 或是版本不同,您可能無法在這個地方找到此設定項。
Kconfig 與 -mregparam
以下是節錄自 arch/i386/Kconfig 的內容:
config REGPARM
bool "Use register arguments (EXPERIMENTAL)"
depends on EXPERIMENTAL
default n
help
Compile the kernel with -mregparm=3. This uses a different ABI
and passes the first three arguments of a function call in registers.
This will probably break binary only modules.
This feature is only enabled for gcc-3.0 and later - earlier compilers
generate incorrect output with certain kernel constructs when
-mregparm=3 is used.
當我們把 REGPARM 設定為 'y' 後,Makefile 裡的 CONFIG_REGPARM 值也會是 'y'。當 CONFIG_REGPARM=y 時,cflags-y 便加 "-mregparm=3" 的參數,請注意 Kernel 2.6.x 必須以 3.2.x 以上的 gcc 來編譯*1 。相關的 Makefile 節錄如下(arch/i386/Makefile):
# -mregparm=3 works ok on gcc-3.0 and later
#
GCC_VERSION := $(call cc-version)
cflags-$(CONFIG_REGPARM) += $(shell if [ $(GCC_VERSION) -ge 0300 ] ; then echo "-mregparm=3"; fi ;)
# Disable unit-at-a-time mode, it makes gcc use a lot more stack
# due to the lack of sharing of stacklots.
CFLAGS += $(call cc-option,-fno-unit-at-a-time)
CFLAGS += $(cflags-y)
最後,CFLAGS 的值會加上 '$(cflgs-y)',我們知道 CFLAGS 是 gcc 的編譯參數設定變數,所以當 gcc 在編譯 kernel 時,便會套用 "-mregparm=3" 的參數。
一個有趣的應用。這是利用 IBM PowerPC 750GX 處理器,搭載 Tundra Tsi108 北橋,製作出無硬體的 server board,掛載(mount)在一個背板(backbone)後,就成為一台小型的分散式計算伺服器。以下是這台「diskless-blade server」的照片。
基本上這是一個 computation platform ,因此需要軟體「分散式計算技術」的支援。不過不拿這個可怕的題目來討論,基本上 Linux 要有一個無硬碟的計算環境,最簡單的方法是「NFS」。
(一台機器可安插 4 片 diskless server board,可做為小型的伺服器或計算平臺。)
NFS 果然是萬用解決方案,像是這種異質性平臺(host v.s. target、client v.s. server),利用 NFS 來掛載(mount)host(或server)端的 Linux distribution 到 target(或 client)端來做計算,是最簡單的方法。
唯一需要具備的能力是:
1. NFS 的設定:/etc/exports。
2. 製作 target 的 NFS bootstrap root filesystem。
3. 灌一套支援 target 端的 Linux distribution 在 host 端。
以下是這個「server board」的 block diagram。
diskless-blade server 的幾個好處是:
1. 資料存放於 remote data server。
2. 將計算(computation)與資料儲存(storage)分開:separate computation from storage。
3. 計算端(computation)的損壞不影響資料安全性。
4. 提供較佳的備援。
5. 使用 Giga lan 互連(connectivity),佈署成本(deployment)較低(see the block diagram)。
至於軟體端的解決方案,我想大家應該也都猜得到,這片伺服器板是使用 U-Boot + Linux 2.6.x 做為解決方案。
最近有朋友問到,在 Red Hat Linux 9 底下要如何安裝 bitbake 1.6。如果您是使用 Red Hat Linux 9(我們的課程學員),想要在 Red Hat Linux 9 底下安裝 bitbake 1.6 的話,需要注意以下事項(已實測成功):
1. Python 要更新至 2.3(rh9 提供的是 2.2),至於其它更新版本的 Python 經測試,則是不能使用的。我們測試過 Python 2.5,結果是無法運作。我們實測可運作的版本是 Python 2.3.5 ;另外請務必使用以下的 configure 設定:
# ./configure --enable-unicode=ucs4 --prefix=/usr
2. 安裝 Psyco (Python JIT Compiler):這是必要的,以快加 bitbake 建立套件的速度。我們測試的版本是 2006/10/23 的 snapshot,實測後可順利運作,不過更新一點的 snapshot 我想應該也不致於有太大問題。
3. 安裝 text2html library,我們實測的版本是 texi2html 1.64。
4. 安裝 xmlto ,我們使用的版本是 xmlto 0.0.18。
以下是 bitbake 1.6 在我們的 Red Hat Linux 9 下運作的畫面。