为什么与Midnight Commander一起使用的文件系统代码不起作用?

编程语言 2026-07-11

我写了一个Linux文件系统驱动,用来处理Dreamcast的可视内存单元(Visual Memory Unit,VMU)FAT风格的系统,整体上在bash 7.0.0-rc1上工作良好,例如(文件系统挂载在 /mnt)

adrian@yeow:/mnt$ ls -l
total 39
-rw-r--r-- 1 adrian adrian 5120 Sep 21  2014 EVO2_DAT.001
-rw-r--r-- 1 adrian adrian 5120 Oct  5  2014 EVO2_DAT.002
-rw-r--r-- 1 adrian adrian 5120 Oct  6  2014 EVO2_DAT.003
-rw-r--r-- 1 adrian adrian 5120 Oct  5  2014 EVO2_DAT.004
-rw-r--r-- 1 adrian adrian 5120 Oct  6  2014 EVO2_DAT.005
-rw-r--r-- 1 adrian adrian 9216 Sep 15  2014 SONIC2___S01
-rw-r--r-- 1 adrian adrian 5120 Nov 27  1998 SONICADV_INT

这正是我所预期的一切。

然而在运行Midnight Commander时,目录显示为空,尽管统计信息正确地报告,例如在窗口底部显示“81K/128K (63%)”,但没有列出任何文件。

运行strace跟踪ls时给出的输出是这样的……

1658  openat(AT_FDCWD, "/mnt", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3
1658  fstat(3, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
1658  newfstatat(AT_FDCWD, "/mnt", {st_mode=S_IFDIR|0555, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
1658  getdents64(3, 0x57d92d41d200 /\* 9 entries \*/, 32768) = 272
1658  getdents64(3, 0x57d92d41d200 /\* 0 entries \*/, 32768) = 0
1658  statx(AT_FDCWD, "/mnt", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=STATX_ATTR_MOUNT_ROOT, stx_mode=S_IFDIR|0555, stx_size=0, ...}) = 0
1658  statx(AT_FDCWD, "/mnt/..", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_ALL|STATX_MNT_ID, stx_attributes=STATX_ATTR_MOUNT_ROOT, stx_mode=S_IFDIR|0755, stx_size=4096, ...}) = 0
1658  statx(3, "EVO2_DAT.001", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0
1658  statx(3, "EVO2_DAT.002", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0
1658  statx(3, "EVO2_DAT.003", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0
1658  statx(3, "EVO2_DAT.004", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0
1658  statx(3, "EVO2_DAT.005", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0
1658  statx(3, "SONIC2___S01", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=9216, ...}) = 0
1658  statx(3, "SONICADV_INT", AT_STATX_SYNC_AS_STAT|AT_SYMLINK_NOFOLLOW, STATX_ALL, {stx_mask=STATX_BASIC_STATS|STATX_MNT_ID, stx_attributes=0, stx_mode=S_IFREG|0644, stx_size=5120, ...}) = 0

也就是说它打开 /mnt,获取一个文件描述符(3),并读取了9 个目录项等——正如我预期的。

但对mc来说,我得到的是这样的……

1818  openat(AT_FDCWD, "/mnt", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 13
1818  fstat(13, {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
1818  getdents64(13, 0x62c4999c9da0 /* 9 entries */, 32768) = 272
1818  lseek(13, 0, SEEK_SET)            = -1 ESPIPE (Illegal seek)
1818  getdents64(13, 0x62c4999c9da0 /* 0 entries */, 32768) = 0

也就是说它打开该目录,获取一个文件描述符(13),按预期查找9 个目录项,但随后调用lseek并返回失败。

这个失败的seek是不是问题的根源?我应该在我的文件系统中实现什么才算缺失?

我当前对文件操作的实现是这样的……

const struct file_operations vmufat_file_operations = {
    .llseek =   generic_file_llseek,
    .read_iter =    generic_file_read_iter,
    .write_iter =   generic_file_write_iter,
    .fsync =    generic_file_fsync,
};

那么这是否意味着我不能依赖这些通用调用?

解决方案

正如往常——把问题写清楚促使我找到答案。我需要在目录操作中也添加generic_file_llseek,与文件操作一样,一旦完成,Midnight Commander就能成功列出所有文件。

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

相关文章