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

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

openatシステムコール


openシステムコールの相対パス検索は、ワーキングディレクトリから行いますが、openatシステムコールは、指定するファイルディスクリプタ(通常ファイルはダメです。)のディレクトリから検索します。その事以外はopenシステムコールと同じです。
#include <stdio.h>
#include <fcntl.h>

void    main()
{
   int     fd1, fd2, len;
   char    buff[64];

   fd1 = open("/proc/self", O_RDONLY);
   fd2 = openat(fd1, "comm", O_RDONLY);
   len = read(fd2, buff, sizeof(buff));
   buff[len - 1] = 0;
   printf("%s\n", buff);
   close(fd1);
   close(fd2);
}
[root@localhost kitamura]#./a.out
a.out
[root@localhost kitamura]#
検索開始ディレクトリを指定する事で、無駄な検索をスキップしようとするものです。パスはdentry(inode)として、キャッシュに蓄えられますが、場合にようってメモリー回収によりそのキャッシュが破棄される事もあります。そのような場合再度dentryの取得を行います。これはinodeの取得を意味し、物理デバイスへのアクセスをも意味します。

また、マルチスレッドアプリケーションにおいて、ある処理を行うスレッド群ごとに、パス検索開始位置を指定できるという使い方もあるわけです。

open/openatシステムコールも、do_sys_open()をコールする事で実現していて、第一引数がAT_FDCWD/ディスクリプタかの違いだけです。
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
{
       long ret;

       if (force_o_largefile())
               flags |= O_LARGEFILE;

       ret = do_sys_open(AT_FDCWD, filename, flags, mode);
        asmlinkage_protect(3, ret, filename, flags, mode);
       return ret;
}

SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags,
               int, mode)
{
       long ret;

       if (force_o_largefile())
               flags |= O_LARGEFILE;

       ret = do_sys_open(dfd, filename, flags, mode);
       asmlinkage_protect(4, ret, dfd, filename, flags, mode);
       return ret;
}
do_filp_open()で実際の処理が行われます。本内容にかかる処理は、ここでコールされるpath_init()です。path_init()でパスの検索の諸設定を行います。その設定はstruct nameidata ndに施され、以降の処理でこのndを参照して実際のパスの検索を行います。
struct file *do_filp_open(int dfd, const char *pathname,
               int open_flag, int mode, int acc_mode)
{
       struct nameidata nd;
  :
reval:
       error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
  :
}
if (*name=='/')はパスが絶対パスの場合です。set_root()でカレントプロセスのルートを取得し、nd->pathに設定します。

if (dfd == AT_FDCWD)は、openシステムコールのケースです。この場合プロセスのワーキングディレクトリが設定されています。

そして以降がopnatシステムコールのケースです。fget_light()で引数のディスクリプタに対応するfile構造体を取得し、 if (!S_ISDIR(dentry->d_inode->i_mode))で、それがディレクトリかどうかチェックします。ディレクトリならパーミッションをチェックした後、そのパスをnd->pathに設定しています。
#define AT_FDCWD                -100    
static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
{
       int retval = 0;
       int fput_needed;
       struct file *file;

       nd->last_type = LAST_ROOT; /* if there are only slashes... */
       nd->flags = flags;
       nd->depth = 0;
       nd->root.mnt = NULL;

       if (*name=='/') {
               set_root(nd);
               nd->path = nd->root;
               path_get(&nd->root);
       } else if (dfd == AT_FDCWD) {
               struct fs_struct *fs = current->fs;
               read_lock(&fs->lock);
               nd->path = fs->pwd;
               path_get(&fs->pwd);
               read_unlock(&fs->lock);
       } else {
               struct dentry *dentry;

               file = fget_light(dfd, &fput_needed);
               retval = -EBADF;
               if (!file)
                       goto out_fail;

               dentry = file->f_path.dentry;

               retval = -ENOTDIR;
               if (!S_ISDIR(dentry->d_inode->i_mode))
                       goto fput_fail;

               retval = file_permission(file, MAY_EXEC);
               if (retval)
                       goto fput_fail;

               nd->path = file->f_path;
               path_get(&file->f_path);

               fput_light(file, fput_needed);
       }
       return 0;

fput_fail:
       fput_light(file, fput_needed);
out_fail:
       return retval;
}

補足

path_get()はmnt/dentryそれぞれの参照カウンターを、アトミックにインクリメントしているだけです。

最終更新 2012/02/13 17:19:44 - north
(2012/02/13 17:18:41 作成)