bashのファイルID=255
bashプロセスは、ファイルIDを0/1/2の標準入出力/エラー以外に、標準エラーをdupした255のファイルIDを有しています。ただし、子プロセス(コマンド)は、255のファイルIDを継承しません。このファイルIDについててです。
32ビット環境でのinit taskは32で、current taskは256となっています。ここでのcurrent taskは、bashの子プロセスのinsmodコマンドとなります。
fdt->max_fdsはカーネル/ユーザプロセスに関係なく、デフォルトはBITS_PER_LONGの(32/64)ですが、親プロセスの最大ファイルIDがBITS_PER_LONG単位の数値のデフォルトを超えていれば、それがfdt->max_fdsとなります。
そのブロック数を2のべき乗で丸めたものを、ファイル数としてfdt->max_fds = nrとします。
#include "stdio.h" int main() { while (1) sleep(10); return 0; }
[root@localhost test]# ./child_of_bash & [1] 1294 [root@localhost test]# ps PID TTY TIME CMD 1183 pts/0 00:00:00 bash 1294 pts/0 00:00:00 child_of_bash 1295 pts/0 00:00:00 ps
[root@localhost test]# ls -l /proc/1183/fd/ 合計 0 lrwx------ 1 root root 64 11月 4 01:10 0 -> /dev/pts/0 lrwx------ 1 root root 64 11月 4 01:10 1 -> /dev/pts/0 lrwx------ 1 root root 64 11月 4 01:10 2 -> /dev/pts/0 lrwx------ 1 root root 64 11月 4 01:19 255 -> /dev/pts/0
[root@localhost test]# ls -l /proc/1294/fd/ 合計 0 lrwx------ 1 root root 64 11月 4 01:19 0 -> /dev/pts/0 lrwx------ 1 root root 64 11月 4 01:19 1 -> /dev/pts/0 lrwx------ 1 root root 64 11月 4 01:18 2 -> /dev/pts/0dup(2) = 3でファイルID=3を標準エラーとし、dup2(3, 255) = 255ファイルID=3をファイルID=255にdupし、fcntl64(255, F_SETFD, FD_CLOEXEC)としています。
[root@localhost test]# strace /bin/bash : gettimeofday({1446482940, 993197}, NULL) = 0 getpgrp() = 1269 dup(2) = 3 getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=4*1024}) = 0 fcntl64(255, F_GETFD) = -1 EBADF (Bad file descriptor) dup2(3, 255) = 255 close(3) = 0 ioctl(255, TIOCGPGRP, [1269]) = 0 setpgid(0, 1271) = 0 rt_sigprocmask(SIG_BLOCK, [CHLD TSTP TTIN TTOU], [], 8) = 0 ioctl(255, SNDRV_TIMER_IOCTL_SELECT or TIOCSPGRP, [1271]) = 0 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 ioctl(255, TIOCGPGRP, [1271]) = 0 fcntl64(255, F_SETFD, FD_CLOEXEC) = 0 :fdt->max_fdsはプロセスの最大ファイルIDを数静的に確保している領域で、この値を超える場合、制限内で動的に領域が拡張されます。
32ビット環境でのinit taskは32で、current taskは256となっています。ここでのcurrent taskは、bashの子プロセスのinsmodコマンドとなります。
fdt->max_fdsはカーネル/ユーザプロセスに関係なく、デフォルトはBITS_PER_LONGの(32/64)ですが、親プロセスの最大ファイルIDがBITS_PER_LONG単位の数値のデフォルトを超えていれば、それがfdt->max_fdsとなります。
#include <linux/kernel.h> #include <linux/module.h> #include <linux/pagemap.h> #include <linux/fdtable.h> MODULE_LICENSE("GPL"); static int __init babakaka_init(void) { struct files_struct *files1 = init_task.files; struct files_struct *files2 = current->files; struct fdtable *fdt; fdt = files_fdtable(files1); printk(" init task:%d\n", fdt->max_fds); fdt = files_fdtable(files2); printk("current task:%d\n", fdt->max_fds); return -1; } module_init(babakaka_init)
[root@localhost lkm]# insmod fdt_max.ko insmod: error inserting 'fdt_max.ko': -1 Operation not permitted [root@localhost lkm]# dmesg : [ 1844.510588] init task:32 [ 1844.510593] current task:256子プロセス作成時、copy_process()で親プロセスのタスク情報を設定され、ファイルに関してcopy_files()がコールされます。CLONE_FILESは親プロセスのそれを共有しますが、そうでないとdup_fd()がコールされます。
static int copy_files(unsigned long clone_flags, struct task_struct *tsk) { struct files_struct *oldf, *newf; int error = 0; oldf = current->files; if (!oldf) goto out; if (clone_flags & CLONE_FILES) { atomic_inc(&oldf->count); goto out; } newf = dup_fd(oldf, &error); if (!newf) goto out; tsk->files = newf; error = 0; out: return error; }new_fdt->max_fds = NR_OPEN_DEFAULTとしますが、open_files = count_open_files(old_fdt)で親プロセスのオープンされている最大ファイルIDを取得します。それがデフォルトより大きいなら、alloc_fdtable()で親プロセスの最大ファイルID値で設定しなおします。
#define NR_OPEN_DEFAULT BITS_PER_LONG struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) { struct files_struct *newf; struct file **old_fds, **new_fds; int open_files, size, i; struct fdtable *old_fdt, *new_fdt; *errorp = -ENOMEM; newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); if (!newf) goto out; atomic_set(&newf->count, 1); spin_lock_init(&newf->file_lock); newf->next_fd = 0; new_fdt = &newf->fdtab; new_fdt->max_fds = NR_OPEN_DEFAULT; new_fdt->close_on_exec = (fd_set *)&newf->close_on_exec_init; new_fdt->open_fds = (fd_set *)&newf->open_fds_init; new_fdt->fd = &newf->fd_array[0]; new_fdt->next = NULL; spin_lock(&oldf->file_lock); old_fdt = files_fdtable(oldf); open_files = count_open_files(old_fdt); while (unlikely(open_files > new_fdt->max_fds)) { spin_unlock(&oldf->file_lock); if (new_fdt != &newf->fdtab) __free_fdtable(new_fdt); new_fdt = alloc_fdtable(open_files - 1); if (!new_fdt) { *errorp = -ENOMEM; goto out_release; } if (unlikely(new_fdt->max_fds < open_files)) { __free_fdtable(new_fdt); *errorp = -EMFILE; goto out_release; } spin_lock(&oldf->file_lock); old_fdt = files_fdtable(oldf); open_files = count_open_files(old_fdt); } old_fds = old_fdt->fd; new_fds = new_fdt->fd; memcpy(new_fdt->open_fds->fds_bits, old_fdt->open_fds->fds_bits, open_files/8); memcpy(new_fdt->close_on_exec->fds_bits, old_fdt->close_on_exec->fds_bits, open_files/8); for (i = open_files; i != 0; i--) { struct file *f = *old_fds++; if (f) { get_file(f); } else { FD_CLR(open_files - i, new_fdt->open_fds); } rcu_assign_pointer(*new_fds++, f); } spin_unlock(&oldf->file_lock); size = (new_fdt->max_fds - open_files) * sizeof(struct file *); memset(new_fds, 0, size); if (new_fdt->max_fds > open_files) { int left = (new_fdt->max_fds-open_files)/8; int start = open_files / (8 * sizeof(unsigned long)); memset(&new_fdt->open_fds->fds_bits[start], 0, left); memset(&new_fdt->close_on_exec->fds_bits[start], 0, left); } rcu_assign_pointer(newf->fdt, new_fdt); return newf; out_release: kmem_cache_free(files_cachep, newf); out: return NULL; }1024バイトブロック(1024 / sizeof(struct file *)は、ブロック単位で管理できるファイルIDの数),
そのブロック数を2のべき乗で丸めたものを、ファイル数としてfdt->max_fds = nrとします。
static struct fdtable * alloc_fdtable(unsigned int nr) { struct fdtable *fdt; char *data; nr /= (1024 / sizeof(struct file *)); nr = roundup_pow_of_two(nr + 1); nr *= (1024 / sizeof(struct file *)); if (unlikely(nr > sysctl_nr_open)) nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1; fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); if (!fdt) goto out; fdt->max_fds = nr; data = alloc_fdmem(nr * sizeof(struct file *)); if (!data) goto out_fdt; fdt->fd = (struct file **)data; data = alloc_fdmem(max_t(unsigned int, 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES)); if (!data) goto out_arr; fdt->open_fds = (fd_set *)data; data += nr / BITS_PER_BYTE; fdt->close_on_exec = (fd_set *)data; fdt->next = NULL; return fdt; out_arr: free_fdmem(fdt->fd); out_fdt: kfree(fdt); out: return NULL; }