CreateDiskDeviceObject函数主要就是为了物理设备创建磁盘对象,并且查找磁盘上每个分区和创建相应的对象。具体实现代码如下:
#001 NTSTATUS
#002 NTAPI
#003 CreateDiskDeviceObject(
#004 IN PDRIVER_OBJECT DriverObject,
#005 IN PUNICODE_STRING RegistryPath,
#006 IN PDEVICE_OBJECT PortDeviceObject,
#007 IN ULONG PortNumber,
#008 IN PULONG DeviceCount,
#009 IN PIO_SCSI_CAPABILITIES PortCapabilities,
#010 IN PSCSI_INQUIRY_DATA LunInfo,
#011 IN PCLASS_INIT_DATA InitData
#012 )
#013
#014 /*++
#015
#016 Routine Description:
#017
#018 This routine creates an object for the physical device and then searches
#019 the device for partitions and creates an object for each partition.
#020
#021 Arguments:
#022
#023 DriverObject - Pointer to driver object created by system.
#024
#025 PortDeviceObject - Miniport device object.
#026
#027 PortNumber - port number. Used in creating disk objects.
#028
#029 DeviceCount - Number of previously installed devices.
#030
#031 PortCapabilities - Capabilities of this SCSI port.
#032
#033 LunInfo - LUN specific information.
#034
#035 Return Value:
#036
#037 NTSTATUS
#038
#039 --*/
#040 {
#041 CCHAR ntNameBuffer[MAXIMUM_FILENAME_LENGTH];
#042 STRING ntNameString;
#043 UNICODE_STRING ntUnicodeString;
#044 OBJECT_ATTRIBUTES objectAttributes;
#045 HANDLE handle;
#046 NTSTATUS status;
#047 PDEVICE_OBJECT deviceObject = NULL;
#048 PDEVICE_OBJECT physicalDevice;
#049 PDISK_GEOMETRY diskGeometry = NULL;
#050 PDEVICE_EXTENSION deviceExtension = NULL;
#051 PDEVICE_EXTENSION physicalDeviceExtension;
#052 UCHAR pathId = LunInfo->PathId;
#053 UCHAR targetId = LunInfo->TargetId;
#054 UCHAR lun = LunInfo->Lun;
#055 BOOLEAN writeCache;
#056 PVOID senseData = NULL;
#057 ULONG srbFlags;
#058 ULONG timeOut = 0;
#059 BOOLEAN srbListInitialized = FALSE;
#060
#061
保证运行这些代骊是非分页代码,如果是分页代码就抛出异常。
#062 PAGED_CODE();
#063
#064 //
#065 // Set up an object directory to contain the objects for this
#066 // device and all its partitions.
#067 //
#068
创建一个设备的磁盘目录对象。
#069 sprintf(ntNameBuffer,
#070 "//Device//Harddisk%lu",
#071 *DeviceCount);
#072
#073 RtlInitString(&ntNameString,
#074 ntNameBuffer);
#075
#076 status = RtlAnsiStringToUnicodeString(&ntUnicodeString,
#077 &ntNameString,
#078 TRUE);
#079
#080 if (!NT_SUCCESS(status)) {
#081 return(status);
#082 }
#083
#084 InitializeObjectAttributes(&objectAttributes,
#085 &ntUnicodeString,
#086 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
#087 NULL,
#088 NULL);
#089
调用函数ZwCreateDirectoryObject在对象管理器里创建设备目录对象。
#090 status = ZwCreateDirectoryObject(&handle,
#091 DIRECTORY_ALL_ACCESS,
#092 &objectAttributes);
#093
#094 RtlFreeUnicodeString(&ntUnicodeString);
#095
#096 if (!NT_SUCCESS(status)) {
#097
#098 DebugPrint((1,
#099 "CreateDiskDeviceObjects: Could not create directory %s/n",
#100 ntNameBuffer));
#101
#102 return(status);
#103 }
#104
#105 //
#106 // Claim the device.
#107 //
#108
从端口驱动程序里申请一个端口驱动程序对象。
#109 status = ScsiClassClaimDevice(PortDeviceObject,
#110 LunInfo,
#111 FALSE,
#112 &PortDeviceObject);
#113
#114 if (!NT_SUCCESS(status)) {
#115 ZwMakeTemporaryObject(handle);
#116 ZwClose(handle);
#117 return status;
#118 }
#119
#120 //
#121 // Create a device object for this device. Each physical disk will
#122 // have at least one device object. The required device object
#123 // describes the entire device. Its directory path is
#124 // /Device/HarddiskN/Partition0, where N = device number.
#125 //
#126
创建每个物理分区磁盘的名称。
#127 sprintf(ntNameBuffer,
#128 "//Device//Harddisk%lu//Partition0",
#129 *DeviceCount);
#130
#131
调用函数ScsiClassCreateDeviceObject为每个物理分区创建物理设备对象,并且设备驱动程序扩展的功能处理函数。
#132 status = ScsiClassCreateDeviceObject(DriverObject,
#133 ntNameBuffer,
#134 NULL,
#135 &deviceObject,
#136 InitData);
#137
#138 if (!NT_SUCCESS(status)) {
#139
#140 DebugPrint((1,
#141 "CreateDiskDeviceObjects: Can not create device object %s/n",
#142 ntNameBuffer));
#143
#144 goto CreateDiskDeviceObjectsExit;
#145 }
#146
#147 //
#148 // Indicate that IRPs should include MDLs for data transfers.
#149 //
#150
指明这个物理设备对象是直接IO缓冲区的访问方式。
#151 deviceObject->Flags |= DO_DIRECT_IO;
#152
#153 //
#154 // Check if this is during initialization. If not indicate that
#155 // system initialization already took place and this disk is ready
#156 // to be accessed.
#157 //
#158
如果这个物理设备没有在注册表里,说明它是没有被初始化的。
#159 if (!RegistryPath) {
#160 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
#161 }
#162
#163 //
#164 // Check for removable media support.
#165 //
#166
从端口驱动程序里查找到这个物理设备是可移动的设备,那么就设置为可移动的文件媒体。
#167 if (((PINQUIRYDATA)LunInfo->InquiryData)->RemovableMedia) {
#168 deviceObject->Characteristics |= FILE_REMOVABLE_MEDIA;
#169 }
#170
#171 //
#172 // Set up required stack size in device object.
#173 //
#174
设置设备栈的大小。
#175 deviceObject->StackSize = (CCHAR)PortDeviceObject->StackSize + 1;
#176
获取设备驱动对象扩展。
#177 deviceExtension = deviceObject->DeviceExtension;
#178
#179 //
#180 // Allocate spinlock for split request completion.
#181 //
#182
分配共享请求的自旋锁。
#183 KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
#184
#185 //
#186 // Initialize lock count to zero. The lock count is used to
#187 // disable the ejection mechanism on devices that support
#188 // removable media. Only the lock count in the physical
#189 // device extension is used.
#190 //
#191
#192 deviceExtension->LockCount = 0;
#193
#194 //
#195 // Save system disk number.
#196 //
#197
保存磁盘编号。
#198 deviceExtension->DeviceNumber = *DeviceCount;
#199
#200 //
#201 // Copy port device object pointer to the device extension.
#202 //
#203
#204 deviceExtension->PortDeviceObject = PortDeviceObject;
#205
#206 //
#207 // Set the alignment requirements for the device based on the
#208 // host adapter requirements
#209 //
#210
设置为主机适配器的对齐方式。
#211 if (PortDeviceObject->AlignmentRequirement > deviceObject->AlignmentRequirement) {
#212 deviceObject->AlignmentRequirement = PortDeviceObject->AlignmentRequirement;
#213 }
#214
#215 //
#216 // This is the physical device object.
#217 //
#218
设置物理设备对象。
#219 physicalDevice = deviceObject;
#220 physicalDeviceExtension = deviceExtension;
#221
#222 //
#223 // Save address of port driver capabilities.
#224 //
#225
#226 deviceExtension->PortCapabilities = PortCapabilities;
#227
#228 //
#229 // Build the lookaside list for srb's for the physical disk. Should only
#230 // need a couple.
#231 //
#232
创建一个磁盘的后备列表,以便快速访问。
#233 ScsiClassInitializeSrbLookasideList(deviceExtension,
#234 PARTITION0_LIST_SIZE);
#235
#236 srbListInitialized = TRUE;
#237
#238 //
#239 // Initialize the srb flags.
#240 //
#241
开始初始化SRB的属性。
#242 if (((PINQUIRYDATA)LunInfo->InquiryData)->CommandQueue &&
#243 PortCapabilities->TaggedQueuing) {
#244
#245 deviceExtension->SrbFlags = SRB_FLAGS_QUEUE_ACTION_ENABLE;
#246
#247 } else {
#248
#249 deviceExtension->SrbFlags = 0;
#250
#251 }
#252
#253 //
#254 // Allow queued requests if this is not removable media.
#255 //
#256
如果磁盘设备不是可移动设备,那么就创建一个队列来保存请求包。
#257 if (!(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
#258
#259 deviceExtension->SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
#260
#261 }
#262
#263 //
#264 // Look for controller that require special flags.
#265 //
#266
扫描设备的特别设置。
#267 ScanForSpecial(deviceObject,
#268 LunInfo,
#269 PortCapabilities);
#270
#271 srbFlags = deviceExtension->SrbFlags;
#272
#273 //
#274 // Allocate buffer for drive geometry.
#275 //
#276
分配磁盘物理组成属性,比如磁头个数,柱面,扇区数量等等。
#277 diskGeometry = ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
#278
#279 if (diskGeometry == NULL) {
#280
#281 DebugPrint((1,
#282 "CreateDiskDeviceObjects: Can not allocate disk geometry buffer/n"));
#283 status = STATUS_INSUFFICIENT_RESOURCES;
#284 goto CreateDiskDeviceObjectsExit;
#285 }
#286
#287 deviceExtension->DiskGeometry = diskGeometry;
#288
#289 //
#290 // Allocate request sense buffer.
#291 //
#292
#293 senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
#294
#295 if (senseData == NULL) {
#296
#297 //
#298 // The buffer can not be allocated.
#299 //
#300
#301 DebugPrint((1,
#302 "CreateDiskDeviceObjects: Can not allocate request sense buffer/n"));
#303
#304 status = STATUS_INSUFFICIENT_RESOURCES;
#305 goto CreateDiskDeviceObjectsExit;
#306 }
#307
#308 //
#309 // Set the sense data pointer in the device extension.
#310 //
#311
保存有意义的数据指针。
#312 deviceExtension->SenseData = senseData;
#313
#314 //
#315 // Physical device object will describe the entire
#316 // device, starting at byte offset 0.
#317 //
#318
设置物理设备的偏移位置。
#319 deviceExtension->StartingOffset.QuadPart = (LONGLONG)(0);
#320
#321 //
#322 // TargetId/LUN describes a device location on the SCSI bus.
#323 // This information comes from the inquiry buffer.
#324 //
#325
设置SCSI总线上标识磁盘的内容。
#326 deviceExtension->PortNumber = (UCHAR)PortNumber;
#327 deviceExtension->PathId = pathId;
#328 deviceExtension->TargetId = targetId;
#329 deviceExtension->Lun = lun;
#330
#331 //
#332 // Set timeout value in seconds.
#333 //
#334
设置磁盘设备的命令处理的超时时间。
#335 timeOut = ScsiClassQueryTimeOutRegistryValue(RegistryPath);
#336 if (timeOut) {
#337 deviceExtension->TimeOutValue = timeOut;
#338 } else {
#339 deviceExtension->TimeOutValue = SCSI_DISK_TIMEOUT;
#340 }
#341
#342 //
#343 // Back pointer to device object.
#344 //
#345
设备对象的指针。
#346 deviceExtension->DeviceObject = deviceObject;
#347
#348 //
#349 // If this is a removable device, then make sure it is not a floppy.
#350 // Perform a mode sense command to determine the media type. Note
#351 // IsFloppyDevice also checks for write cache enabled.
#352 //
#353
如果设备是软盘设备,并且设备是可移设备,不可以直接访问时就创建失败。
#354 if (IsFloppyDevice(deviceObject) && deviceObject->Characteristics & FILE_REMOVABLE_MEDIA &&
#355 (((PINQUIRYDATA)LunInfo->InquiryData)->DeviceType == DIRECT_ACCESS_DEVICE)) {
#356
#357 status = STATUS_NO_SUCH_DEVICE;
#358 goto CreateDiskDeviceObjectsExit;
#359 }
#360
关闭写缓存。
#361 DisableWriteCache(deviceObject,LunInfo);
#362
#363 writeCache = deviceExtension->DeviceFlags & DEV_WRITE_CACHE;
#364
#365 //
#366 // NOTE: At this point one device object has been successfully created.
#367 // from here on out return success.
#368 //
#369
#370 //
#371 // Do READ CAPACITY. This SCSI command
#372 // returns the number of bytes on a device.
#373 // Device extension is updated with device size.
#374 //
#375
发送命令READ CAPACITY获取设备容量的大小,比如多少G数据可以保存。
#376 status = ScsiClassReadDriveCapacity(deviceObject);
#377
#378 //
#379 // If the read capcity failed then just return, unless this is a
#380 // removable disk where a device object partition needs to be created.
#381 //
#382
#383 if (!NT_SUCCESS(status) &&
#384 !(deviceObject->Characteristics & FILE_REMOVABLE_MEDIA)) {
#385
#386 DebugPrint((1,
#387 "CreateDiskDeviceObjects: Can't read capacity for device %s/n",
#388 ntNameBuffer));
#389
#390 return(STATUS_SUCCESS);
#391
#392 } else {
#393
#394 //
#395 // Make sure the volume verification bit is off so that
#396 // IoReadPartitionTable will work.
#397 //
#398
设置可以读取分区表格了。
#399 deviceObject->Flags &= ~DO_VERIFY_VOLUME;
#400 }
#401
为磁盘所有分区创建分区设备对象,主要通过MBR的分区表格来分析有几个可以使用的分区。
#402 status = CreatePartitionDeviceObjects(deviceObject, RegistryPath);
#403
#404 if (NT_SUCCESS(status))
#405 return STATUS_SUCCESS;
#406
#407
下面是删除已经分配的内存。
#408 CreateDiskDeviceObjectsExit:
#409
#410 //
#411 // Release the device since an error occurred.
#412 //
#413
#414 ScsiClassClaimDevice(PortDeviceObject,
#415 LunInfo,
#416 TRUE,
#417 NULL);
#418
#419 if (diskGeometry != NULL) {
#420 ExFreePool(diskGeometry);
#421 }
#422
#423 if (senseData != NULL) {
#424 ExFreePool(senseData);
#425 }
#426
#427 if (deviceObject != NULL) {
#428
#429 if (srbListInitialized) {
#430 ExDeleteNPagedLookasideList(&deviceExtension->SrbLookasideListHead);
#431 }
#432
#433 IoDeleteDevice(deviceObject);
#434 }
#435
#436 //
#437 // Delete directory and return.
#438 //
#439
#440 if (!NT_SUCCESS(status)) {
#441 ZwMakeTemporaryObject(handle);
#442 }
#443
#444 ZwClose(handle);
#445
#446 return(status);
#447
#448 } // end CreateDiskDeviceObjects()