/proc/swapsはswap_info[]のswap_info_structからswap情報を表示します。なおswapon -aコマンドは/proc/swapsを参照することで実現しています。
[root@localhost kitamura]# cat /proc/swaps
Filename Type Size Used Priority
/dev/dm-0 partition 1671164 0 0
[root@localhost kitamura]# swapon -s
Filename Type Size Used Priority
/dev/mapper/VolGroup-lv_swap partition 1671164 0 0
[root@localhost kitamura]# ls -l /dev/mapper/VolGroup-lv_swap
lrwxrwxrwx 1 root root 7 2月 8 01:23 /dev/mapper/VolGroup-lv_swap -> ../dm-0
nr_swapfilesでswap_info[]内のif (!(si->flags & SWP_USED) || !si->swap_map)でないswap_info_structを取得します。nr_swapfilesはswapoffしてもがデクリメントされることはありません。(対応するswap_info[]のメモリも解放されません。ただし使用可能スロットのsi->swap_mapは解放されます。) その使用されなくなったswap_info_structは、新たなswapに再利用することで無駄なメモリ取得/解放を無くすような実装となっています。
PAGE_SHIFTは通常12で、1pageは4Kバイトで、PAGE_SHIFT - 10はpageをkバイト単位で表示するためで、上記Size/UsedはKバイトです。
static const struct seq_operations swaps_op = {
.start = swap_start,
.next = swap_next,
.stop = swap_stop,
.show = swap_show
};
static int swap_show(struct seq_file *swap, void *v)
{
struct swap_info_struct *si = v;
struct file *file;
int len;
if (si == SEQ_START_TOKEN) {
seq_puts(swap,"Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
return 0;
}
file = si->swap_file;
len = seq_path(swap, &file->f_path, " \t\n\\");
seq_printf(swap, "%*s%s\t%u\t%u\t%d\n",
len < 40 ? 40 - len : 1, " ",
S_ISBLK(file->f_path.dentry->d_inode->i_mode) ?
"partition" : "file\t",
si->pages << (PAGE_SHIFT - 10),
si->inuse_pages << (PAGE_SHIFT - 10),
si->prio);
return 0;
}
static void *swap_start(struct seq_file *swap, loff_t *pos)
{
struct swap_info_struct *si;
int type;
loff_t l = *pos;
mutex_lock(&swapon_mutex);
if (!l)
return SEQ_START_TOKEN;
for (type = 0; type < nr_swapfiles; type++) {
smp_rmb(); /* read nr_swapfiles before swap_info[type] */
si = swap_info[type];
if (!(si->flags & SWP_USED) || !si->swap_map)
continue;
if (!--l)
return si;
}
return NULL;
}
static void *swap_next(struct seq_file *swap, void *v, loff_t *pos)
{
struct swap_info_struct *si = v;
int type;
if (v == SEQ_START_TOKEN)
type = 0;
else
type = si->type + 1;
for (; type < nr_swapfiles; type++) {
smp_rmb(); /* read nr_swapfiles before swap_info[type] */
si = swap_info[type];
if (!(si->flags & SWP_USED) || !si->swap_map)
continue;
++*pos;
return si;
}
return NULL;
}