無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

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されています。
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);

最終更新 2013/11/08 16:43:02 - north
(2010/01/16 18:39:56 作成)