ext4在 `name_to_handle_at` 中会使用 `i_generation` 吗?

编程语言 2026-07-10

我的问题很直接。ext4 文件系统在 name_to_handle_at 内部创建文件句柄时,是否使用inode的 i_generation-属性?

前言

虽然我主要对基于 ext 的文件系统感兴趣(具体是 ext4),但我会尽量广泛地回答这个问题(花了我一个小时研究Linux内核与 [免责声明] 的几次提示,才大致理解它是如何精确运作的……因此,我决定在这里分享,以防将来也能帮助到其他人。此外,因为我也想把我收集的所有信息汇集到一个地方。)

答案

是的,关于 name_to_handle_at 实际上如何在内部做到这一点的一个经过整理的、抽象的思路,大致如下:

  1. name_to_handle_at 系统调用(用户态入口点)
  2. do_sys_name_to_handle()fs/fhandle.c 中(系统调用处理程序)
  3. exportfs_encode_fh()fs/exportfs/expfs.c 中(通用编码分发器)
  4. exportfs_encode_inode_fh()fs/exportfs/expfs.c 中(获取特定于文件系统的操作)
  5. nop->encode_fh(...)(文件系统特定回调,例如 generic_encode_ino32_fh 对ext4](https://github.com/torvalds/linux/blob/3036cd0d3328220a1858b1ab390be8b562774e8a/fs/ext4/super.c#L1673-L1679))
  6. 文件句柄已用 i_generationi_ino 和父信息填充

实质上,你可以看到在 linux/fs/fhandle.c -> name_to_handle_at 调用 do_sys_name_to_handle ,后者又调用 linux/fs/exportfs/expfs.c -> exportfs_encode_fh 调用 exportfs_encode_inode_fh 其中 const struct export_operations *nop = inode->i_sb->s_export_op; 获取到合适的操作集(对于inode所属的文件系统,例如 generic_encode_ino32_fh 对ext4](https://github.com/torvalds/linux/blob/3036cd0d3328220a1858b1ab390be8b562774e8a/fs/ext4/super.c#L1673-L1679)),最终在 nop->encode_fh(...) 用来填充文件句柄的 i_generation 等。

(对于不属于“通用编码分发器”的文件系统,你可以查找 ..._encode_fh

(如果你问我inode如何或在何处获得 [i_sb->s_export_op],我也不知道……没有研究得那么深)

另一种做法

获取文件句柄的正确方式可以在 man name_to_handle_at 找到。

然而,如果出于某种原因你想要更快且特定于ext4系统(或其他使用“通用编码”的文件系统)的实现,你可以绕过更高层次的 name_to_handle_at 接口,使用如下做法:

/*
 WARNING: This is filesystem-specific and non-portable: 
 it only reconstructs a handle that may match the current
 inode-generation encoding used by a given filesystem 
 (for example ext4). The byte layout, endianness, and 
 export format are not guaranteed, and the result is not
 a general replacement for name_to_handle_at() or 
 guaranteed to always work with open_by_handle_at().

 I made this example just to prove to myself
 that I understood corectly how ext4 specifically is handled
 by the linux-kernel.**Please,** do your research before you 
 even consider using it, because my naive brain might have 
 been missing crucial stuffs here.
*/


#define _GNU_SOURCE
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>


int main(int argc, char *argv[])
{
    if (argc != 2)
        exit(EXIT_FAILURE);

    int fd = open(argv[1], O_RDONLY);
    __u32 generation=0;

    if (ioctl(fd, FS_IOC_GETVERSION, &generation))
        exit(EXIT_FAILURE);

    struct statx stx; // plain stat might be faster? idk
    statx(fd, "", AT_EMPTY_PATH,  STATX_INO, &stx);

    // WARNING: Endianness + later use with open_by_handle_at()
    __u64 handle_bytes = ((__u64)generation << 32) | (__u32)stx.stx_ino;

    printf("8 1   "); // length + type
    for (int i = 0; i < 8; i++)
        printf(" %02x", ((unsigned char*)&handle_bytes)[i]);
    printf("\n");

    // then you may use the printed handle with 
    // the `t_open_by_handle_at.c`-example
    // at `man name_to_handle_at`
}

额外参考

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章