ext4在 `name_to_handle_at` 中会使用 `i_generation` 吗?
我的问题很直接。ext4 文件系统在 name_to_handle_at 内部创建文件句柄时,是否使用inode的 i_generation-属性?
前言
虽然我主要对基于 ext 的文件系统感兴趣(具体是 ext4),但我会尽量广泛地回答这个问题(花了我一个小时研究Linux内核与 [免责声明] 的几次提示,才大致理解它是如何精确运作的……因此,我决定在这里分享,以防将来也能帮助到其他人。此外,因为我也想把我收集的所有信息汇集到一个地方。)
答案
是的,关于 name_to_handle_at 实际上如何在内部做到这一点的一个经过整理的、抽象的思路,大致如下:
name_to_handle_at系统调用(用户态入口点)do_sys_name_to_handle()在fs/fhandle.c中(系统调用处理程序)exportfs_encode_fh()在fs/exportfs/expfs.c中(通用编码分发器)exportfs_encode_inode_fh()在fs/exportfs/expfs.c中(获取特定于文件系统的操作)nop->encode_fh(...)(文件系统特定回调,例如generic_encode_ino32_fh对ext4](https://github.com/torvalds/linux/blob/3036cd0d3328220a1858b1ab390be8b562774e8a/fs/ext4/super.c#L1673-L1679))- 文件句柄已用
i_generation、i_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`
}