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

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

tmpfsのmount


tmpfsのマウントオプションは、shmem_fs_typeのコールバック関数shmem_mountからshmem_parse_options()をコールすることで設定されます。オプションはsize,nr_blocks,nr_inodes,mode,uid,gid,mpolです。

for (;;)で、デリミタのカンマ毎にオプションをthis_char = optionsに切り出し、そのオプションを=をデリミタとして、設定値をvalueに切り出します。

sizeの時、memparse()で設定値を取得し、PAGE_CACHE_SIZEでブロック数としsbinfo->max_blocksに設定します。設定値の末尾が%なら、size *= totalram_pages/100としサイズを取得します。
size <<= PAGE_SHIFTですが、なぜ下記のようにしないのかな。とぱっと見、不思議でして・・・。で、totalram_paggeは不変値という事でした。
 totalram_pages <<= PAGE_SHIFT;
 size *= totalram_pages;

nr_blocks/nr_inodesもmemparse()で設定値し、%はありませんが、sizeに準じます。uid/gid/modeも同じですが、remountの時は設定できません。

mpolはmpol_parse_str()でメモリポリシの設定します。
static struct file_system_type shmem_fs_type = {
       .owner          = THIS_MODULE,
       .name           = "tmpfs",
       .mount          = shmem_mount,
       .kill_sb        = kill_litter_super,
};

static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
                              bool remount)
{
       char *this_char, *value, *rest;

       while (options != NULL) {
               this_char = options;
               for (;;) {
                       options = strchr(options, ',');
                       if (options == NULL)
                               break;
                       options++;
                       if (!isdigit(*options)) {
                               options[-1] = '\0';
                               break;
                       }
               }
               if (!*this_char)
                       continue;
               if ((value = strchr(this_char,'=')) != NULL) {
                       *value++ = 0;
               } else {
                       printk(KERN_ERR
                           "tmpfs: No value for mount option '%s'\n",
                           this_char);
                       return 1;
               }

               if (!strcmp(this_char,"size")) {
                       unsigned long long size;
                       size = memparse(value,&rest);
                       if (*rest == '%') {
                               size <<= PAGE_SHIFT;
                               size *= totalram_pages;
                               do_div(size, 100);
                               rest++;
                       }
                       if (*rest)
                               goto bad_val;
                       sbinfo->max_blocks =
                               DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
               } else if (!strcmp(this_char,"nr_blocks")) {
                       sbinfo->max_blocks = memparse(value, &rest);
                       if (*rest)
                               goto bad_val;
               } else if (!strcmp(this_char,"nr_inodes")) {
                       sbinfo->max_inodes = memparse(value, &rest);
                       if (*rest)
                               goto bad_val;
               } else if (!strcmp(this_char,"mode")) {
                       if (remount)
                               continue;
                       sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
                       if (*rest)
                               goto bad_val;
               } else if (!strcmp(this_char,"uid")) {
                       if (remount)
                               continue;
                       sbinfo->uid = simple_strtoul(value, &rest, 0);
                       if (*rest)
                               goto bad_val;
               } else if (!strcmp(this_char,"gid")) {
                       if (remount)
                               continue;
                       sbinfo->gid = simple_strtoul(value, &rest, 0);
                       if (*rest)
                               goto bad_val;
               } else if (!strcmp(this_char,"mpol")) {
                       if (mpol_parse_str(value, &sbinfo->mpol, 1))
                               goto bad_val;
               } else {
                       printk(KERN_ERR "tmpfs: Bad mount option %s\n",
                              this_char);
                       return 1;
               }
       }
       return 0;

bad_val:
       printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n",
              value, this_char);
       return 1;

}
末尾がG/g/M/m/K/kに応じて順次ret <<= 10(1024)単位でサイズを積算していきます。
unsigned long long memparse(const char *ptr, char **retptr)
{
       char *endptr;   /* local pointer to end of parsed string */

       unsigned long long ret = simple_strtoull(ptr, &endptr, 0);

       switch (*endptr) {
       case 'G':
       case 'g':
               ret <<= 10;
       case 'M':
       case 'm':
               ret <<= 10;
       case 'K':
       case 'k':
               ret <<= 10;
               endptr++;
       default:
               break;
       }

       if (retptr)
               *retptr = endptr;

       return ret;
}
mpol_parse_str()はNUMAでのメモリポリシを取得します。メモリポリシはNUMAのメモリノードのからのpageの取得方法を定めるものです。nodelistは:以降のノード値、flagsは=以降のフラグ(static/relative)です。

nodelistからノードをnodesに取得後、mode毎のチェックをします。

MPOL_PREFERRED:ノードは1つでないならエラー。
MPOL_INTERLEAVE:ノードがなければ、デフォルトノードnode_statesをnode。
MPOL_LOCAL:ノードがあればエラーとし、ノード設定のないMPOL_PREFERREDに設定。
MPOL_DEFAULT:呼び出しプロセスのポリシ(たぶん)
MPOL_BIND:ノード設定値がなければエラー

みたいな感じとなり、mpol_new()でメモリポリシーを割り当て、struct shmem_sb_info *sbinfo->mpolに設定します。
int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
{
       struct mempolicy *new = NULL;
       unsigned short mode;
       unsigned short uninitialized_var(mode_flags);
       nodemask_t nodes;
       char *nodelist = strchr(str, ':');
       char *flags = strchr(str, '=');
       int err = 1;

       if (nodelist) {
               /* NUL-terminate mode or flags string */
               *nodelist++ = '\0';
               if (nodelist_parse(nodelist, nodes))
                       goto out;
               if (!nodes_subset(nodes, node_states[N_HIGH_MEMORY]))
                       goto out;
       } else
               nodes_clear(nodes);

       if (flags)
               *flags++ = '\0';        /* terminate mode string */

       for (mode = 0; mode <= MPOL_LOCAL; mode++) {
               if (!strcmp(str, policy_modes[mode])) {
                       break;
               }
       }
       if (mode > MPOL_LOCAL)
               goto out;

       switch (mode) {
       case MPOL_PREFERRED:
               if (nodelist) {
                       char *rest = nodelist;
                       while (isdigit(*rest))
                               rest++;
                       if (*rest)
                               goto out;
               }
               break;
       case MPOL_INTERLEAVE:
               if (!nodelist)
                       nodes = node_states[N_HIGH_MEMORY];
               break;
       case MPOL_LOCAL:
               if (nodelist)
                       goto out;
               mode = MPOL_PREFERRED;
               break;
       case MPOL_DEFAULT:
               if (!nodelist)
                       err = 0;
               goto out;
       case MPOL_BIND:
               if (!nodelist)
                       goto out;
       }

       mode_flags = 0;
       if (flags) {
               if (!strcmp(flags, "static"))
                       mode_flags |= MPOL_F_STATIC_NODES;
               else if (!strcmp(flags, "relative"))
                       mode_flags |= MPOL_F_RELATIVE_NODES;
               else
                       goto out;
       }

       new = mpol_new(mode, mode_flags, &nodes);
       if (IS_ERR(new))
               goto out;

       if (no_context) {
               new->w.user_nodemask = nodes;
       } else {
               int ret;
               NODEMASK_SCRATCH(scratch);
               if (scratch) {
                       task_lock(current);
                       ret = mpol_set_nodemask(new, &nodes, scratch);
                       task_unlock(current);
               } else
                       ret = -ENOMEM;
               NODEMASK_SCRATCH_FREE(scratch);
               if (ret) {
                       mpol_put(new);
                       goto out;
               }
       }
       err = 0;

out:
       if (nodelist)
               *--nodelist = ':';
       if (flags)
               *--flags = '=';
       if (!err)
               *mpol = new;
       return err;
}

補足

tmpfsのマウントのhogehogeに相当する箇所は、ブロックデバイスですが、tmpfsは物理的なブロックデバイスは不要です。それ故mountでの種々のオプションがあるわけですが。hogehogeはdfコマンド等のメッセージとして表示されるだけで、tmpfsの内部実装とまったく関係ありません。
[root@localhost ~]# mount -t tmpfs hogehoge /mnt2
[root@localhost ~]# df 
ファイルシス                1K-ブロック     使用   使用可 使用% マウント位置
devtmpfs                          115824        0   115824    0% /dev
tmpfs                             124760        0   124760    0% /dev/shm
tmpfs                             124760      620   124140    1% /run
/dev/mapper/VolGroup-lv_root     6094400  5431196   601300   91% /
tmpfs                             124760        0   124760    0% /sys/fs/cgroup
tmpfs                             124760        0   124760    0% /media
/dev/sdb1                      103212288 34458288 63511124   36% /mnt
/dev/sda2                         495844    85372   384872   19% /boot
hoge                              124760        0   124760    0% /mnt2
numaの取り扱いですが、エレメント毎にstruct mempolicyを管理し、その中に競合しないpageをリストされた複数のメモリノードを管理するみたいなものと・・・。CPU変数みたいなものでしょうか? この複数ノードからの取得方法が、MPOL_PREFERRED/MPOL_INTERLEAVE/MPOL_BINDだったりするものと漠然と理解しているのですが・・・。

最終更新 2014/02/27 18:55:07 - north
(2014/02/27 18:55:07 作成)