CPU変数


Rev.5を表示中。最新版はこちら

mount構造体でSMPのCPM変数の取り扱いです。mnt_countはマウントされている数で、mnt_writersはこのファイルシステムを書き込み処理している数です。struct mountのmnt_count/mnt_writersは下記のように展開され、SMPの時はmnt_count/mnt_writersの構造体のポインタとスピンロックの展開となっています。
struct mnt_pcp {
       int mnt_count;
       int mnt_writers;
};

struct mount {
  :
#ifdef CONFIG_SMP
       struct mnt_pcp __percpu *mnt_pcp;
       atomic_t mnt_longterm;          /* how many of the refs are longterm */
#else
       int mnt_count;
       int mnt_writers;
#endif
  :
};
処理において頻繁に参照される変数は、このようにCPU毎に変数を持たせる事で、ロックを介さないで処理できるようにしています。

mount構造体の取得時、SMPでない時は、mnt->mnt_count = 1/mnt->mnt_writers = 0としていますが、SMPの時はalloc_percpu()でthis_cpu_add()となっています。alloc_percpu()はstruct mnt_pcpをCPUの数分特定の領域からメモリーを確保します。それ故struct mountにおいてポインタとして宣言する必要があるわけです。this_cpu_add()は、上で確保したメモリの実行しているCPUのインデックスに対応するstruct mnt_pcp[]内のmnt_countに1を加算します。

このようにCPU毎に変数を割り当てると、他のCPUから参照される事はなく、この変数の更新においてスピンロックをかける必要がありません。
static struct mount *alloc_vfsmnt(const char *name)
{
       struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
       if (mnt) {
  :
#ifdef CONFIG_SMP
               mnt->mnt_pcp = alloc_percpu(struct mnt_pcp);
               if (!mnt->mnt_pcp)
                       goto out_free_devname;

               this_cpu_add(mnt->mnt_pcp->mnt_count, 1);
#else
               mnt->mnt_count = 1;
               mnt->mnt_writers = 0;
#endif
  :
}
mnt_count/mnt_writersを更新する際は、動作しているCPU変数に対して、また取得する際は、全てのCPU変数の合計としなければなりません。この場合他のCPU変数に対して参照するため、mnt_longtermを介してのスピンロックを掛ける必要があります。またロックは、CPU変数としない他のメンバーについても、更新時は必要となるわけです。SMPでない場合preempt_disable()とし、割り込みを禁止します。
static inline void mnt_add_count(struct mount *mnt, int n)
{
#ifdef CONFIG_SMP
       this_cpu_add(mnt->mnt_pcp->mnt_count, n);
#else
       preempt_disable();
       mnt->mnt_count += n;
       preempt_enable();
#endif
}

unsigned int mnt_get_count(struct mount *mnt)
{
#ifdef CONFIG_SMP
       unsigned int count = 0;
       int cpu;

       for_each_possible_cpu(cpu) {
               count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count;
       }

       return count;
#else
       return mnt->mnt_count;
#endif
}
変数をCPU変数とするかどうかは、タスク毎の更新頻度に依存すると言えそうです。CPU変数とすると、ロックの必要性がなくなる訳ですが、その分メモリを必要とします。またそのトータル数を参照する処理が多い様なケースでは、ロックを伴って全CPU変数を走査する必要があるわけです。

CPU変数の概要は、雰囲気このような感じですが、そのマクロ展開はアラビア語みたいです。

最終更新 2013/07/16 17:48:32 - north
(2012/03/23 16:19:37 作成)


検索

アクセス数
3689592
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。