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()でメモリポリシの設定します。
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に設定します。
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% /mnt2numaの取り扱いですが、エレメント毎にstruct mempolicyを管理し、その中に競合しないpageをリストされた複数のメモリノードを管理するみたいなものと・・・。CPU変数みたいなものでしょうか? この複数ノードからの取得方法が、MPOL_PREFERRED/MPOL_INTERLEAVE/MPOL_BINDだったりするものと漠然と理解しているのですが・・・。




