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

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

bashのファイルID=255


bashプロセスは、ファイルIDを0/1/2の標準入出力/エラー以外に、標準エラーをdupした255のファイルIDを有しています。ただし、子プロセス(コマンド)は、255のファイルIDを継承しません。このファイルIDについててです。
#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/0
dup(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;
}

追記

当初、fdt_max.koで、init_taskと他のユーザプロセスのfdt_maxの相違は、カーネルマターかと思っていましたが、そうでなくユーザマターで、そしてbashマターであるという事です。


最終更新 2015/11/03 18:07:57 - north
(2015/11/03 17:40:49 作成)