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だったりするものと漠然と理解しているのですが・・・。