name_to_handle_atシステムコール


name_to_handle_atシステムコールは、ファイルのinodeの属性を取得し、取得したinodeでopen_by_handle_atシステムコールにてファイルパスに依存することなく、ファイル参照することです。

直接inodeによりファイルをオープンする事でファイルパスによる走査が必要なく、nfsのようにサーバのパスに変更があってもクライアントのdentryキャッシュに反映しない環境下でのファイル参照を可能とします。なお、ファイル名でなくinodeでの参照故、ファイルシステム下での移動等、inode番号に影響しない変更があっても、ファイル参照に影響しません。

検証サンプル
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

enum fid_type {
       /*
        * The root, or export point, of the filesystem.
        * (Never actually passed down to the filesystem.
        */
       FILEID_ROOT = 0,

       /*
        * 32bit inode number, 32 bit generation number.
        */
       FILEID_INO32_GEN = 1,

       /*
        * 32bit inode number, 32 bit generation number,
        * 32 bit parent directory inode number.
        */
       FILEID_INO32_GEN_PARENT = 2,

       /*
        * 64 bit object ID, 64 bit root object ID,
        * 32 bit generation number.
        */
       FILEID_BTRFS_WITHOUT_PARENT = 0x4d,

       /*
        * 64 bit object ID, 64 bit root object ID,
        * 32 bit generation number,
        * 64 bit parent object ID, 32 bit parent generation.
        */
       FILEID_BTRFS_WITH_PARENT = 0x4e,

       /*
        * 64 bit object ID, 64 bit root object ID,
        * 32 bit generation number,
        * 64 bit parent object ID, 32 bit parent generation,
        * 64 bit parent root object ID.
        */
       FILEID_BTRFS_WITH_PARENT_ROOT = 0x4f,

       /*
        * 32 bit block number, 16 bit partition reference,
        * 16 bit unused, 32 bit generation number.
        */
       FILEID_UDF_WITHOUT_PARENT = 0x51,

       /*
        * 32 bit block number, 16 bit partition reference,
        * 16 bit unused, 32 bit generation number,
        * 32 bit parent block number, 32 bit parent generation number
        */
       FILEID_UDF_WITH_PARENT = 0x52,

       /*
        * 64 bit checkpoint number, 64 bit inode number,
        * 32 bit generation number.
        */
       FILEID_NILFS_WITHOUT_PARENT = 0x61,

       /*
        * 64 bit checkpoint number, 64 bit inode number,
        * 32 bit generation number, 32 bit parent generation.
        * 64 bit parent inode number.
        */
       FILEID_NILFS_WITH_PARENT = 0x62,
};

void    main()
{
   struct file_handle *fhp;
   int mount_id;
   long unsigned int *inode_no;
   int     i;

   fhp = malloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
   if (fhp == NULL){
       exit(1);
   }

   fhp->handle_bytes = MAX_HANDLE_SZ;

   if (name_to_handle_at(AT_FDCWD, "./babakaka", fhp, &mount_id, 0) == -1){
       exit(1);
   }

   printf("%s\n", (fhp->handle_type ==  FILEID_INO32_GEN)?
                       "INO32_GEN": "OTHER");
   inode_no= (long unsigned  int *)fhp->f_handle;
   printf("mountid          %10d\n", mount_id);
   printf("inode no         %10u\n", *inode_no++);
   printf("inode gen        %10u\n", *inode_no++);
   printf("parent inode no  %10u\n", *inode_no++);
   printf("parent inode gen %10u\n", *inode_no);
}
結果
[root@localhost north]# ls -i babakaka
150750 babakaka

[root@localhost north]# ./a.out
INO32_GEN
mountid                  22
inode no             150750
inode gen        2379400899
parent inode no           0
parent inode gen          0
順に[マウントID] [親マウントID] [デバイスのメジャー番号:マイナ番号] 本件のファイルシステムは/ / rw,relatime - ext4となります。
[root@localhost north]# ps
  PID TTY          TIME CMD
 1254 pts/1    00:00:01 bash
 2065 pts/1    00:00:00 ps

[root@localhost north]# cat /proc/1254/mountinfo | grep 22
16 22 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
17 22 0:15 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
18 22 0:5 / /dev rw,nosuid,relatime - devtmpfs devtmpfs rw,size=248900k,nr_inodes=62225,mode=755
22 1 253:1 / / rw,relatime - ext4 /dev/mapper/VolGroup-lv_root rw,user_xattr,barrier=1,data=ordered
23 22 0:17 / /run rw,nosuid,nodev,relatime - tmpfs tmpfs rw,mode=755
28 14 0:22 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup cgroup rw,devices
35 22 0:29 / /media rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755
42 22 0:33 / /var/lib/nfs/rpc_pipefs rw,relatime - rpc_pipefs sunrpc rw
43 22 8:2 / /boot rw,relatime - ext4 /dev/sda2 rw,user_xattr,acl,barrier=1,data=ordered
44 22 8:17 / /mnt rw,relatime - ext3 /dev/sdb1 rw,user_xattr,acl,barrier=1,nodelalloc,data=ordered
21 22 0:34 / /misc rw,relatime - autofs /etc/auto.misc rw,fd=7,pgrp=888,timeout=300,minproto=5,maxproto=5,indirect
48 22 0:36 / /net rw,relatime - autofs -hosts rw,fd=19,pgrp=888,timeout=300,minproto=5,maxproto=5,indirect

struct fidとしてfhp->f_handle[]にファイルのinode->i_ino/inode->i_generationが設定されます。i_generationはスーパブロックからinode取得毎にインクリメントされ、ファイルが削除され新規作成したファイルが削除したファイルのinode番号となっても、i_generationは異なり、そのようなファイルは参照できないようにするためです。なお、i32/udf下で管理されないファイルシステムは、ファイルシステム依存のnop->encode_fh()がコールされ、独自のファイルシステム属性が__u32 raw[]に設定されるようです。

NFS等でのファイルの削除/移動等、親ディレクトリinodeを更新する必要のある操作で、parent_ino/parent_genが設定されるのではと思います。dentry->d_sb->s_export_op->encode_fh()を有してないならparent_ino/parent_genを設定されずhandle->handle_typeはFILEID_INO32_GENです。

udfは、dvdのようにファイルの変更不可のファイルシステムでinodeで管理するのでなく、ブロック単位で管理されるファイルシステムの属性です。

#define MAX_HANDLE_SZ 128

struct fid {
       union {
               struct {
                       u32 ino;
                       u32 gen;
                       u32 parent_ino;
                       u32 parent_gen;
               } i32;
               struct {
                       u32 block;
                       u16 partref;
                       u16 parent_partref;
                       u32 generation;
                       u32 parent_block;
                       u32 parent_generation;
               } udf;
               __u32 raw[0];
       };
};

static long do_sys_name_to_handle(struct path *path,
                                 struct file_handle __user *ufh,
                                 int __user *mnt_id)
{
       long retval;
       struct file_handle f_handle;
       int handle_dwords, handle_bytes;
       struct file_handle *handle = NULL;

       if (!path->dentry->d_sb->s_export_op ||
           !path->dentry->d_sb->s_export_op->fh_to_dentry)
               return -EOPNOTSUPP;

       if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
               return -EFAULT;

       if (f_handle.handle_bytes > MAX_HANDLE_SZ)
               return -EINVAL;

       handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
                        GFP_KERNEL);
       if (!handle)
               return -ENOMEM;

       handle_dwords = f_handle.handle_bytes >> 2;

       retval = exportfs_encode_fh(path->dentry,
                                   (struct fid *)handle->f_handle,
                                   &handle_dwords,  0);
       handle->handle_type = retval;

       handle_bytes = handle_dwords * sizeof(u32);
       handle->handle_bytes = handle_bytes;
       if ((handle->handle_bytes > f_handle.handle_bytes) ||
           (retval == 255) || (retval == -ENOSPC)) {
               handle_bytes = 0;
               retval = -EOVERFLOW;
       } else
               retval = 0;
       if (copy_to_user(mnt_id, &real_mount(path->mnt)->mnt_id,
                        sizeof(*mnt_id)) ||
           copy_to_user(ufh, handle,
                        sizeof(struct file_handle) + handle_bytes))
               retval = -EFAULT;
       kfree(handle);
       return retval;
}

int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
               int connectable)
{
       const struct export_operations *nop = dentry->d_sb->s_export_op;
       int error;

       if (nop->encode_fh)
               error = nop->encode_fh(dentry, fid->raw, max_len, connectable);
       else
               error = export_encode_fh(dentry, fid, max_len, connectable);

       return error;
}

static int export_encode_fh(struct dentry *dentry, struct fid *fid,
               int *max_len, int connectable)
{
       struct inode * inode = dentry->d_inode;
       int len = *max_len;
       int type = FILEID_INO32_GEN;

       if (connectable && (len < 4)) {
               *max_len = 4;
               return 255;
       } else if (len < 2) {
               *max_len = 2;
               return 255;
       }

       len = 2;
       fid->i32.ino = inode->i_ino;
       fid->i32.gen = inode->i_generation;
       if (connectable && !S_ISDIR(inode->i_mode)) {
               struct inode *parent;

               spin_lock(&dentry->d_lock);
               parent = dentry->d_parent->d_inode;
               fid->i32.parent_ino = parent->i_ino;
               fid->i32.parent_gen = parent->i_generation;
               spin_unlock(&dentry->d_lock);
               len = 4;
               type = FILEID_INO32_GEN_PARENT;
       }
       *max_len = len;
       return type;
}


最終更新 2016/02/17 18:28:50 - north
(2014/05/03 21:30:23 作成)


検索

アクセス数
3576117
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。