为什么与Midnight Commander一起使用的文件系统代码不起作用?
我写了一个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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。