find_task_by_vpidを追ってみる
kernel 2では、引数のPIDでfind_pid()をコールして、struct pidを取得します。struct pidはpid_hashをヘッドとするPIDタイプ毎(プロセスID/グループID/セッションID)のハッシュリストでリストされています。そのリストヘッドからPIDの同じものを走査することで取得します。
find_task_by_pid()はEXPORT_SYMBOLされています。
kernel 3ではfind_task_by_pid()に相当する関数は、find_task_by_vpid()になります。pidはプロセス毎のネームスペース下で仮想化されているため、vpidとなっていて、PIDとネームスペースを引数にfind_task_by_pid_ns()しています。そこではvnrとcurrent->nsproxy->pid_nsのハッシュリストとして、対応するstruct task_strucを取得します。
ただし、find_task_by_vpid()はEXPORT_SYMBOLされておらず、LKMから使うことはできません。
単に取得だけなら、get_pid_task()を使ことになります。
find_task_by_pid()はEXPORT_SYMBOLされています。
typedef struct task_struct task_t;
task_t *find_task_by_pid(int nr)
{
struct pid *pid = find_pid(PIDTYPE_PID, nr);
if (!pid)
return NULL;
return pid_task(pid->task_list.next, PIDTYPE_PID);
}
EXPORT_SYMBOL(find_task_by_pid);
inline struct pid *find_pid(enum pid_type type, int nr)
{
struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)];
struct pid *pid;
__list_for_each(elem, bucket) {
pid = list_entry(elem, struct pid, hash_chain);
if (pid->nr == nr)
return pid;
}
return NULL;
}
kernel 3ではfind_task_by_pid()に相当する関数は、find_task_by_vpid()になります。pidはプロセス毎のネームスペース下で仮想化されているため、vpidとなっていて、PIDとネームスペースを引数にfind_task_by_pid_ns()しています。そこではvnrとcurrent->nsproxy->pid_nsのハッシュリストとして、対応するstruct task_strucを取得します。
ただし、find_task_by_vpid()はEXPORT_SYMBOLされておらず、LKMから使うことはできません。
struct task_struct *find_task_by_vpid(pid_t vnr)
{
return find_task_by_pid_ns(vnr, current->nsproxy->pid_ns);
}
struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns)
{
rcu_lockdep_assert(rcu_read_lock_held(),
"find_task_by_pid_ns() needs rcu_read_lock()"
" protection");
return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID);
}
LKMで使用する場合、get_pid_task()かpid_task()を使うことになります(ただし引数はPIDでなくstruct pid)。get_pid_task()はrcu_read_lock()してpid_task()をコールしているだけです。pid_task()をEXPORT_SYMBOLとしているのは、pidからtask_structを取得し、それから他のRCUで管理されている情報を取得しなければならない一連の処理で、LKNの呼び出しサイドで、rcu_read_lock()した方がいいようなケースを想定してのことかと思います。単に取得だけなら、get_pid_task()を使ことになります。
struct task_struct *get_pid_task(struct pid *pid, enum pid_type type)
{
struct task_struct *result;
rcu_read_lock();
result = pid_task(pid, type);
if (result)
get_task_struct(result);
rcu_read_unlock();
return result;
}
EXPORT_SYMBOL_GPL(get_pid_task);
struct task_struct *pid_task(struct pid *pid, enum pid_type type)
{
struct task_struct *result = NULL;
if (pid) {
struct hlist_node *first;
first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]),
lockdep_tasklist_lock_is_held());
if (first)
result = hlist_entry(first, struct task_struct, pids[(type)].node);
}
return result;
}
EXPORT_SYMBOL(pid_task);
struct pidfind_get_pid()は、pidからstruct pidを取得します。pid_tはintでdefineされています。今後いろんな機能を付加していくための宣言だと思います(structに変更)。そこからfind_vpid()とコールしていますが、この2つも先の2つの関数のように、rcu_read_lock()の取り扱いによるものです。
struct pid *find_get_pid(pid_t nr)
{
struct pid *pid;
rcu_read_lock();
pid = get_pid(find_vpid(nr));
rcu_read_unlock();
return pid;
}
EXPORT_SYMBOL_GPL(find_get_pid);
struct pid *find_vpid(int nr)
{
return find_pid_ns(nr, current->nsproxy->pid_ns);
}
EXPORT_SYMBOL_GPL(find_vpid);
find_pid_ns()でpidとネームスペースをハッシュとして、&pid_hashのリストヘッドを取得し、PIDとネームスペースの一致するノードを走査します。find_vpid()から呼ばれる時、 nsはcurrent->nsproxy->pid_nsで、ここを任意のプロセスのネームスペースの pidを取得することが、LKMから行う事が可能となっています。
struct pid *find_pid_ns(int nr, struct pid_namespace *ns)
{
struct hlist_node *elem;
struct upid *pnr;
hlist_for_each_entry_rcu(pnr, elem,
&pid_hash[pid_hashfn(nr, ns)], pid_chain)
if (pnr->nr == nr && pnr->ns == ns)
return container_of(pnr, struct pid,
numbers[ns->level]);
return NULL;
}
EXPORT_SYMBOL_GPL(find_pid_ns);





