2

我目前正在使用 IOKit 开发一个虚拟 SCSI 设备驱动程序。我的驱动程序加载正常,我可以使用 ExFat、FAT32 或 HFS+ 格式化我的设备。

我还可以使用带有任何这些文件系统的 CLI 将文件复制到我的虚拟设备或从我的虚拟设备复制文件。使用 ExFat 或 FAT32,我还可以使用 Finder 从我的虚拟设备中复制或查看文件,但在驱动器格式化为 HFS+(日志式)时不能。

使用 HFS+ 时,我遇到与 Finder、Spotlight 或 Preview 相关的内核恐慌。例如,当系统在文件复制到磁盘后尝试预览文件时,就会发生这种情况。这是来自内核恐慌的示例日志:

Mon Jun 30 22:47:51 2014
panic(cpu 4 caller 0xffffff8005dd1401): "cluster_read_copy: failed to get pagelist"@/SourceCache/xnu/xnu-2422.100.13/bsd/vfs/vfs_cluster.c:3732
Backtrace (CPU 4), Frame : Return Address
0xffffff80e9aa3810 : 0xffffff8005c22fa9
0xffffff80e9aa3890 : 0xffffff8005dd1401
0xffffff80e9aa3a30 : 0xffffff8005dd0a85
0xffffff80e9aa3cf0 : 0xffffff8005f6b876
0xffffff80e9aa3d80 : 0xffffff8005dfdd21
0xffffff80e9aa3e00 : 0xffffff8005df38d5
0xffffff80e9aa3e50 : 0xffffff8005ff1cfe
0xffffff80e9aa3ef0 : 0xffffff8005ff1e79
0xffffff80e9aa3f50 : 0xffffff8006040653
0xffffff80e9aa3fb0 : 0xffffff8005cf3c56

BSD process name corresponding to current thread: Finder
Boot args: debug=0x144

Mac OS version:
13D65

Kernel version:
Darwin Kernel Version 13.2.0: Thu Apr 17 23:03:13 PDT 2014; root:xnu-2422.100.13~1/RELEASE_X86_64

这是上述恐慌日志的堆栈跟踪:

mach_kernel`panic + 201 at debug.c:353
mach_kernel`cluster_read_copy + 2001 at vfs_cluster.c:3732
mach_kernel`cluster_read_ext + 5045 at vfs_cluster.c:3441
mach_kernel`hfs_vnop_read + 566 at hfs_readwrite.c
mach_kernel`VNOP_READ + 225 at kpi_vfs.c:3247
mach_kernel`vn_read + 245 at vfs_vnops.c:939
mach_kernel`dofileread + 174 at sys_generic.c:377
mach_kernel`pread_nocancel + 137 at sys_generic.c:266
mach_kernel`unix_syscall64 + 499 at systemcalls.c:370
mach_kernel`hndl_unix_scall64 + 22

我很难确定问题,但如上所述已缩小到 HFS+。HFS+ 有什么特别的地方会导致这种情况吗?

由于问题与 VFS 和分页(?)有关,我开始怀疑我是否正确处理了 IOMemoryDe​​scriptors(我相信我是,基于我在 Apple 文档中读到的内容)。有人遇到过类似的问题吗?这通常表示特定类型的问题吗?

更新:我已经验证在 HFS+ 中禁用日志不会对上述结果产生影响。

UPDATE2:恐慌日志每次都是一致的。仅当满足以下所有条件时才会发生恐慌:

  • 使用 HFS+
  • 文件被复制到设备(对于单个文件 > 几 MB)
  • 文件是使用 Finder 复制的(但不是终端,例如)

当第一个文件完成复制到设备时,内核始终会出现恐慌。可以复制许多等于或大于几 MB 的小文件而不会引起恐慌。我什至可以使用终端将文件大文件(> 30 MB)复制到卷中并在 Finder 中读取/打开它们。

4

1 回答 1

1

内核源表明恐慌是由于对ubc_create_upl(). 该函数的源代码中的注释反过来表明返回模式如下:

 * Returns: KERN_SUCCESS        The requested upl has been created
 *      KERN_INVALID_ARGUMENT   The bufsize argument is not an even
 *                  multiple of the page size
 *      KERN_INVALID_ARGUMENT   There is no ubc_info associated with
 *                  the vnode, or there is no memory object
 *                  control associated with the ubc_info 
 *  memory_object_upl_request:KERN_INVALID_VALUE
 *                  The supplied upl_flags argument is
 *                  invalid

从反汇编和您的恐慌日志的寄存器内容(您没有在问题中提供)可能可以确定实际的返回码。并不是说这看起来会有很大帮助,因为您的代码还没有在这个特定的系统调用上被调用;我强烈怀疑您正在耗尽某些内核资源,而这恰好是某种池完全干涸的地步。正如您所说,很可能是内存描述符,因为此处创建的 UPL 将包装在内存描述符中,然后传递给挂载的块设备的 IOKit 后端。

您可以在加载驱动程序之前进行检查ioclasscountzprint然后定期再次转储它们的输出,直到崩溃,然后比较任何正在运行的输出。一个好主意是审核您的代码以进行匹配prepare()/complete()retain()/release()调用,特别是在请求内存描述符上。

2机调试也有帮助;对于一个,您可以检查 vnode 用于VNOP_READ对应的文件。如果某个文件甚至不在您设备的卷上发生任何崩溃,那么您几乎肯定会遇到一些资源耗尽或内存损坏。您将能够追踪ubc_create_upl()呼叫失败的确切原因。您还可以检测您的代码以收集数据,然后您可以在调试器中进行检查。

于 2014-07-09T08:58:43.667 回答