Namespace周りのコードを読んでいたらinodeからtask_struct構造体を取得をしているところがあって、こんなことできるんだ〜などと思ったのでどんな方法で取得するのか見てみます。
使ってた場所はproc_ns_follow_link()とかです。 ↓のように。
37 struct task_struct *task; 38 struct path ns_path; 39 void *error = ERR_PTR(-EACCES); 40 41 task = get_proc_task(inode);
関数はget_proc_task()で、fs/proc/internal.hにあります。 実装としては、2個の関数を呼んで結果を返すだけの1行関数です。関数の引数でinode構造体を受け取ってそこからtask_struct構造体を返します。
95 static inline struct task_struct *get_proc_task(struct inode *inode) 96 { 97 return get_pid_task(proc_pid(inode), PIDTYPE_PID); 98 }
では、最初にproc_pid()から見ていきましょう。 PROC_Iマクロっぽい名前ですね。このPROC_Iからpid構造体を取得してreturnしています。
90 static inline struct pid *proc_pid(struct inode *inode) 91 { 92 return PROC_I(inode)->pid; 93 } 94
PROC_I()はマクロっぽい名前の割に関数でした。 container_ofマクロを使って、inodeからproc_inode構造体を取得して返します。
75 static inline struct proc_inode *PROC_I(const struct inode *inode) 76 { 77 return container_of(inode, struct proc_inode, vfs_inode); 78 }
container_ofマクロはこれです。
799 #define container_of(ptr, type, member) ({ \ 800 const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 801 (type *)( (char *)__mptr - offsetof(type,member) );})
container_ofが展開されるとこんな感じになって、__mptjからvfs_inodeのoffsetを引いた位置がproc_inode構造体のアドレスですね。
const typeof( ((struct proc_inode *)0)->vfs_inode ) *__mptr = (inode); (struct proc_inode *)( (char *)__mptr - offsetof(struct proc_inode,vfs_inode) );
proc_inode構造体はこのようになっています。
61 struct proc_inode { 62 struct pid *pid; 63 int fd; 64 union proc_op op; 65 struct proc_dir_entry *pde; 66 struct ctl_table_header *sysctl; 67 struct ctl_table *sysctl_entry; 68 const struct proc_ns_operations *ns_ops; 69 struct inode vfs_inode; 70 };
これでproc_pid()がPROC_I(inode)->pidでpid構造体を返せている理由がわかりましたね。 このpid構造体がget_pid_task()の1番目の引数です。
2番目の引数は整数でinclude/linux/pid.hにてenum型として定義されています。
6 enum pid_type 7 { 8 PIDTYPE_PID, 9 PIDTYPE_PGID, 10 PIDTYPE_SID, 11 PIDTYPE_MAX 12 };
内容は名前の通りで、pid、pdig、sidなどの種別ですね。
では、get_pid_task()を見てみます。 ここでの処理はpid_task()とget_task_struct()くらいですね。
476 struct task_struct *get_pid_task(struct pid *pid, enum pid_type type) 477 { 478 struct task_struct *result; 479 rcu_read_lock(); 480 result = pid_task(pid, type); 481 if (result) 482 get_task_struct(result); 483 rcu_read_unlock(); 484 return result; 485 }
それではまずはpid_task()を見ます。 関数のプロトタイプから、この関数がtask_struct構造体を返すのがわかります。
434 struct task_struct *pid_task(struct pid *pid, enum pid_type type) 435 { 436 struct task_struct *result = NULL; 437 if (pid) { 438 struct hlist_node *first; 439 first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]), 440 lockdep_tasklist_lock_is_held()); 441 if (first) 442 result = hlist_entry(first, struct task_struct, pids[(type)].node); 443 } 444 return result; 445 }
hlist_node構造体はハッシュリストのノードです。 pid構造体はこのようになっています。なので、PIDTYPEがPIDなリストを取得しています。
57 struct pid 58 { 59 atomic_t count; 60 unsigned int level; 61 /* lists of tasks that use this pid */ 62 struct hlist_head tasks[PIDTYPE_MAX]; 63 struct rcu_head rcu; 64 struct upid numbers[1]; 65 }; 66
リストの取得にはhlist_first_rcu()を使っていて、これはリストの先頭要素を取得するものです。
369 /* 370 * return the first or the next element in an RCU protected hlist 371 */ 372 #define hlist_first_rcu(head) (*((struct hlist_node __rcu **)(&(head)->first)))
取得したfirstがnullでなければ、hlist_entry()でtask_struct構造体を取得します。hlist_entry()はマクロで、container_ofマクロの別名なだけです。
688 #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
これも展開してみるとこんな風になります。
800 const typeof( ((struct task_struct *)0)->pids[(type)].node) ) *__mptr = (first); \ 801 (struct task_struct *)( (char *)__mptr - offsetof(struct task_struct,pids[(type)].node)) );})
task_struct構造体にはpidsというメンバ変数があり、
1408 /* PID/PID hash table linkage. */ 1409 struct pid_link pids[PIDTYPE_MAX];
pidsはpid_link構造体型で、内容は下記のようになります。 これでfirstがtask_structのpids配列のインデックスがPIDTYPE_PIDの先頭要素となりました。
69 struct pid_link 70 { 71 struct hlist_node node; 72 struct pid *pid; 73 };
あとはoffset_ofで引き算したらtask_struct構造体の先頭アドレスが取れるので、get_proc_task()がtask_struct構造体を返すという流れがわかりました。
( ´ー`)フゥー...
- 作者: Tae Yeon Kim,Hyung Joo Song,Ji Hoon Park,Bak Lee,Ki Young Lim,Androidフレームワーク研究会
- 出版社/メーカー: パーソナルメディア
- 発売日: 2013/12/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る