1 /* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "btrfs_drv.h"
19
20 FAST_IO_DISPATCH FastIoDispatch;
21
_Function_class_(FAST_IO_QUERY_BASIC_INFO)22 _Function_class_(FAST_IO_QUERY_BASIC_INFO)
23 static BOOLEAN __stdcall fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION fbi,
24 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
25 fcb* fcb;
26 ccb* ccb;
27
28 UNUSED(DeviceObject);
29
30 FsRtlEnterFileSystem();
31
32 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fbi, IoStatus, DeviceObject);
33
34 if (!FileObject) {
35 FsRtlExitFileSystem();
36 return false;
37 }
38
39 fcb = FileObject->FsContext;
40
41 if (!fcb) {
42 FsRtlExitFileSystem();
43 return false;
44 }
45
46 ccb = FileObject->FsContext2;
47
48 if (!ccb) {
49 FsRtlExitFileSystem();
50 return false;
51 }
52
53 if (!(ccb->access & (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES))) {
54 FsRtlExitFileSystem();
55 return false;
56 }
57
58 if (fcb->ads) {
59 if (!ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) {
60 FsRtlExitFileSystem();
61 return false;
62 }
63
64 fcb = ccb->fileref->parent->fcb;
65 }
66
67 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
68 FsRtlExitFileSystem();
69 return false;
70 }
71
72 if (fcb == fcb->Vcb->dummy_fcb) {
73 LARGE_INTEGER time;
74
75 KeQuerySystemTime(&time);
76 fbi->CreationTime = fbi->LastAccessTime = fbi->LastWriteTime = fbi->ChangeTime = time;
77 } else {
78 fbi->CreationTime.QuadPart = unix_time_to_win(&fcb->inode_item.otime);
79 fbi->LastAccessTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_atime);
80 fbi->LastWriteTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_mtime);
81 fbi->ChangeTime.QuadPart = unix_time_to_win(&fcb->inode_item.st_ctime);
82 }
83
84 fbi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
85
86 IoStatus->Status = STATUS_SUCCESS;
87 IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
88
89 ExReleaseResourceLite(fcb->Header.Resource);
90
91 FsRtlExitFileSystem();
92
93 return true;
94 }
95
_Function_class_(FAST_IO_QUERY_STANDARD_INFO)96 _Function_class_(FAST_IO_QUERY_STANDARD_INFO)
97 static BOOLEAN __stdcall fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION fsi,
98 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
99 fcb* fcb;
100 ccb* ccb;
101 bool ads;
102 ULONG adssize;
103
104 UNUSED(DeviceObject);
105
106 FsRtlEnterFileSystem();
107
108 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fsi, IoStatus, DeviceObject);
109
110 if (!FileObject) {
111 FsRtlExitFileSystem();
112 return false;
113 }
114
115 fcb = FileObject->FsContext;
116 ccb = FileObject->FsContext2;
117
118 if (!fcb) {
119 FsRtlExitFileSystem();
120 return false;
121 }
122
123 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
124 FsRtlExitFileSystem();
125 return false;
126 }
127
128 ads = fcb->ads;
129
130 if (ads) {
131 struct _fcb* fcb2;
132
133 if (!ccb || !ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) {
134 ExReleaseResourceLite(fcb->Header.Resource);
135 FsRtlExitFileSystem();
136 return false;
137 }
138
139 adssize = fcb->adsdata.Length;
140
141 fcb2 = ccb->fileref->parent->fcb;
142
143 ExReleaseResourceLite(fcb->Header.Resource);
144
145 fcb = fcb2;
146
147 if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
148 FsRtlExitFileSystem();
149 return false;
150 }
151
152 fsi->AllocationSize.QuadPart = fsi->EndOfFile.QuadPart = adssize;
153 fsi->NumberOfLinks = fcb->inode_item.st_nlink;
154 fsi->Directory = false;
155 } else {
156 fsi->AllocationSize.QuadPart = fcb_alloc_size(fcb);
157 fsi->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size;
158 fsi->NumberOfLinks = fcb->inode_item.st_nlink;
159 fsi->Directory = S_ISDIR(fcb->inode_item.st_mode);
160 }
161
162 fsi->DeletePending = ccb->fileref ? ccb->fileref->delete_on_close : false;
163
164 IoStatus->Status = STATUS_SUCCESS;
165 IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
166
167 ExReleaseResourceLite(fcb->Header.Resource);
168
169 FsRtlExitFileSystem();
170
171 return true;
172 }
173
_Function_class_(FAST_IO_CHECK_IF_POSSIBLE)174 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
175 static BOOLEAN __stdcall fast_io_check_if_possible(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait,
176 ULONG LockKey, BOOLEAN CheckForReadOperation, PIO_STATUS_BLOCK IoStatus,
177 PDEVICE_OBJECT DeviceObject) {
178 fcb* fcb = FileObject->FsContext;
179 LARGE_INTEGER len2;
180
181 UNUSED(Wait);
182 UNUSED(IoStatus);
183 UNUSED(DeviceObject);
184
185 len2.QuadPart = Length;
186
187 if (CheckForReadOperation) {
188 if (FsRtlFastCheckLockForRead(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
189 return true;
190 } else {
191 if (!fcb->Vcb->readonly && !is_subvol_readonly(fcb->subvol, NULL) && FsRtlFastCheckLockForWrite(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
192 return true;
193 }
194
195 return false;
196 }
197
_Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)198 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)
199 static BOOLEAN __stdcall fast_io_query_network_open_info(PFILE_OBJECT FileObject, BOOLEAN Wait, FILE_NETWORK_OPEN_INFORMATION* fnoi,
200 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
201 fcb* fcb;
202 ccb* ccb;
203 file_ref* fileref;
204
205 UNUSED(Wait);
206 UNUSED(IoStatus); // FIXME - really? What about IoStatus->Information?
207 UNUSED(DeviceObject);
208
209 FsRtlEnterFileSystem();
210
211 TRACE("(%p, %u, %p, %p, %p)\n", FileObject, Wait, fnoi, IoStatus, DeviceObject);
212
213 RtlZeroMemory(fnoi, sizeof(FILE_NETWORK_OPEN_INFORMATION));
214
215 fcb = FileObject->FsContext;
216
217 if (!fcb || fcb == fcb->Vcb->volume_fcb) {
218 FsRtlExitFileSystem();
219 return false;
220 }
221
222 ccb = FileObject->FsContext2;
223
224 if (!ccb) {
225 FsRtlExitFileSystem();
226 return false;
227 }
228
229 fileref = ccb->fileref;
230
231 if (fcb == fcb->Vcb->dummy_fcb) {
232 LARGE_INTEGER time;
233
234 KeQuerySystemTime(&time);
235 fnoi->CreationTime = fnoi->LastAccessTime = fnoi->LastWriteTime = fnoi->ChangeTime = time;
236 } else {
237 INODE_ITEM* ii;
238
239 if (fcb->ads) {
240 if (!fileref || !fileref->parent) {
241 ERR("no fileref for stream\n");
242 FsRtlExitFileSystem();
243 return false;
244 }
245
246 ii = &fileref->parent->fcb->inode_item;
247 } else
248 ii = &fcb->inode_item;
249
250 fnoi->CreationTime.QuadPart = unix_time_to_win(&ii->otime);
251 fnoi->LastAccessTime.QuadPart = unix_time_to_win(&ii->st_atime);
252 fnoi->LastWriteTime.QuadPart = unix_time_to_win(&ii->st_mtime);
253 fnoi->ChangeTime.QuadPart = unix_time_to_win(&ii->st_ctime);
254 }
255
256 if (fcb->ads) {
257 fnoi->AllocationSize.QuadPart = fnoi->EndOfFile.QuadPart = fcb->adsdata.Length;
258 fnoi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts;
259 } else {
260 fnoi->AllocationSize.QuadPart = fcb_alloc_size(fcb);
261 fnoi->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 : fcb->inode_item.st_size;
262 fnoi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
263 }
264
265 FsRtlExitFileSystem();
266
267 return true;
268 }
269
_Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE)270 _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE)
271 static NTSTATUS __stdcall fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset,
272 struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
273 fcb* fcb;
274
275 TRACE("(%p, %I64x, %p, %p)\n", FileObject, EndingOffset ? EndingOffset->QuadPart : 0, ResourceToRelease, DeviceObject);
276
277 UNUSED(EndingOffset);
278 UNUSED(DeviceObject);
279
280 fcb = FileObject->FsContext;
281
282 if (!fcb)
283 return STATUS_INVALID_PARAMETER;
284
285 // Make sure we don't get interrupted by the flush thread, which can cause a deadlock
286
287 if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, false))
288 return STATUS_CANT_WAIT;
289
290 if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, false)) {
291 ExReleaseResourceLite(&fcb->Vcb->tree_lock);
292 TRACE("returning STATUS_CANT_WAIT\n");
293 return STATUS_CANT_WAIT;
294 }
295
296 // Ideally this would be PagingIoResource, but that doesn't play well with copy-on-write,
297 // as we can't guarantee that we won't need to do any reallocations.
298
299 *ResourceToRelease = fcb->Header.Resource;
300
301 TRACE("returning STATUS_SUCCESS\n");
302
303 return STATUS_SUCCESS;
304 }
305
_Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE)306 _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE)
307 static NTSTATUS __stdcall fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease,
308 PDEVICE_OBJECT DeviceObject) {
309 fcb* fcb;
310
311 TRACE("(%p, %p, %p)\n", FileObject, ResourceToRelease, DeviceObject);
312
313 UNUSED(DeviceObject);
314
315 fcb = FileObject->FsContext;
316
317 ExReleaseResourceLite(ResourceToRelease);
318
319 ExReleaseResourceLite(&fcb->Vcb->tree_lock);
320
321 return STATUS_SUCCESS;
322 }
323
_Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)324 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)
325 static NTSTATUS __stdcall fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
326 UNUSED(FileObject);
327 UNUSED(DeviceObject);
328
329 IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
330
331 return STATUS_SUCCESS;
332 }
333
_Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH)334 _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH)
335 static NTSTATUS __stdcall fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
336 UNUSED(FileObject);
337 UNUSED(DeviceObject);
338
339 if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
340 IoSetTopLevelIrp(NULL);
341
342 return STATUS_SUCCESS;
343 }
344
_Function_class_(FAST_IO_WRITE)345 _Function_class_(FAST_IO_WRITE)
346 static BOOLEAN __stdcall fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
347 fcb* fcb = FileObject->FsContext;
348 bool ret;
349
350 FsRtlEnterFileSystem();
351
352 if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) {
353 FsRtlExitFileSystem();
354 return false;
355 }
356
357 ret = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
358
359 if (ret)
360 fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
361
362 ExReleaseResourceLite(&fcb->Vcb->tree_lock);
363
364 FsRtlExitFileSystem();
365
366 return ret;
367 }
368
_Function_class_(FAST_IO_LOCK)369 _Function_class_(FAST_IO_LOCK)
370 static BOOLEAN __stdcall fast_io_lock(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PLARGE_INTEGER Length, PEPROCESS ProcessId,
371 ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, PIO_STATUS_BLOCK IoStatus,
372 PDEVICE_OBJECT DeviceObject) {
373 BOOLEAN ret;
374 fcb* fcb = FileObject->FsContext;
375
376 UNUSED(DeviceObject);
377
378 TRACE("(%p, %I64x, %I64x, %p, %lx, %u, %u, %p, %p)\n", FileObject, FileOffset ? FileOffset->QuadPart : 0, Length ? Length->QuadPart : 0,
379 ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, DeviceObject);
380
381 if (fcb->type != BTRFS_TYPE_FILE) {
382 WARN("can only lock files\n");
383 IoStatus->Status = STATUS_INVALID_PARAMETER;
384 IoStatus->Information = 0;
385 return true;
386 }
387
388 FsRtlEnterFileSystem();
389 ExAcquireResourceSharedLite(fcb->Header.Resource, true);
390
391 ret = FsRtlFastLock(&fcb->lock, FileObject, FileOffset, Length, ProcessId, Key, FailImmediately,
392 ExclusiveLock, IoStatus, NULL, false);
393
394 if (ret)
395 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
396
397 ExReleaseResourceLite(fcb->Header.Resource);
398 FsRtlExitFileSystem();
399
400 return ret;
401 }
402
_Function_class_(FAST_IO_UNLOCK_SINGLE)403 _Function_class_(FAST_IO_UNLOCK_SINGLE)
404 static BOOLEAN __stdcall fast_io_unlock_single(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, PLARGE_INTEGER Length, PEPROCESS ProcessId,
405 ULONG Key, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
406 fcb* fcb = FileObject->FsContext;
407
408 UNUSED(DeviceObject);
409
410 TRACE("(%p, %I64x, %I64x, %p, %lx, %p, %p)\n", FileObject, FileOffset ? FileOffset->QuadPart : 0, Length ? Length->QuadPart : 0,
411 ProcessId, Key, IoStatus, DeviceObject);
412
413 IoStatus->Information = 0;
414
415 if (fcb->type != BTRFS_TYPE_FILE) {
416 WARN("can only lock files\n");
417 IoStatus->Status = STATUS_INVALID_PARAMETER;
418 return true;
419 }
420
421 FsRtlEnterFileSystem();
422
423 IoStatus->Status = FsRtlFastUnlockSingle(&fcb->lock, FileObject, FileOffset, Length, ProcessId, Key, NULL, false);
424
425 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
426
427 FsRtlExitFileSystem();
428
429 return true;
430 }
431
_Function_class_(FAST_IO_UNLOCK_ALL)432 _Function_class_(FAST_IO_UNLOCK_ALL)
433 static BOOLEAN __stdcall fast_io_unlock_all(PFILE_OBJECT FileObject, PEPROCESS ProcessId, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
434 fcb* fcb = FileObject->FsContext;
435
436 UNUSED(DeviceObject);
437
438 TRACE("(%p, %p, %p, %p)\n", FileObject, ProcessId, IoStatus, DeviceObject);
439
440 IoStatus->Information = 0;
441
442 if (fcb->type != BTRFS_TYPE_FILE) {
443 WARN("can only lock files\n");
444 IoStatus->Status = STATUS_INVALID_PARAMETER;
445 return true;
446 }
447
448 FsRtlEnterFileSystem();
449
450 ExAcquireResourceSharedLite(fcb->Header.Resource, true);
451
452 IoStatus->Status = FsRtlFastUnlockAll(&fcb->lock, FileObject, ProcessId, NULL);
453
454 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
455
456 ExReleaseResourceLite(fcb->Header.Resource);
457
458 FsRtlExitFileSystem();
459
460 return true;
461 }
462
_Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY)463 _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY)
464 static BOOLEAN __stdcall fast_io_unlock_all_by_key(PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key,
465 PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
466 fcb* fcb = FileObject->FsContext;
467
468 UNUSED(DeviceObject);
469
470 TRACE("(%p, %p, %lx, %p, %p)\n", FileObject, ProcessId, Key, IoStatus, DeviceObject);
471
472 IoStatus->Information = 0;
473
474 if (fcb->type != BTRFS_TYPE_FILE) {
475 WARN("can only lock files\n");
476 IoStatus->Status = STATUS_INVALID_PARAMETER;
477 return true;
478 }
479
480 FsRtlEnterFileSystem();
481
482 ExAcquireResourceSharedLite(fcb->Header.Resource, true);
483
484 IoStatus->Status = FsRtlFastUnlockAllByKey(&fcb->lock, FileObject, ProcessId, Key, NULL);
485
486 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
487
488 ExReleaseResourceLite(fcb->Header.Resource);
489
490 FsRtlExitFileSystem();
491
492 return true;
493 }
494
495 #ifdef __REACTOS__
_Function_class_(FAST_IO_ACQUIRE_FILE)496 _Function_class_(FAST_IO_ACQUIRE_FILE)
497 #endif /* __REACTOS__ */
498 static void __stdcall fast_io_acquire_for_create_section(_In_ PFILE_OBJECT FileObject) {
499 fcb* fcb;
500
501 TRACE("(%p)\n", FileObject);
502
503 if (!FileObject)
504 return;
505
506 fcb = FileObject->FsContext;
507
508 if (!fcb)
509 return;
510
511 ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
512 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
513 }
514
515 #ifdef __REACTOS__
_Function_class_(FAST_IO_RELEASE_FILE)516 _Function_class_(FAST_IO_RELEASE_FILE)
517 #endif /* __REACTOS__ */
518 static void __stdcall fast_io_release_for_create_section(_In_ PFILE_OBJECT FileObject) {
519 fcb* fcb;
520
521 TRACE("(%p)\n", FileObject);
522
523 if (!FileObject)
524 return;
525
526 fcb = FileObject->FsContext;
527
528 if (!fcb)
529 return;
530
531 ExReleaseResourceLite(fcb->Header.Resource);
532 ExReleaseResourceLite(&fcb->Vcb->tree_lock);
533 }
534
init_fast_io_dispatch(FAST_IO_DISPATCH ** fiod)535 void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
536 RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
537
538 FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
539
540 FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible;
541 FastIoDispatch.FastIoRead = FsRtlCopyRead;
542 FastIoDispatch.FastIoWrite = fast_io_write;
543 FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info;
544 FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info;
545 FastIoDispatch.FastIoLock = fast_io_lock;
546 FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single;
547 FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all;
548 FastIoDispatch.FastIoUnlockAllByKey = fast_io_unlock_all_by_key;
549 FastIoDispatch.AcquireFileForNtCreateSection = fast_io_acquire_for_create_section;
550 FastIoDispatch.ReleaseFileForNtCreateSection = fast_io_release_for_create_section;
551 FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
552 FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
553 FastIoDispatch.MdlRead = FsRtlMdlReadDev;
554 FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
555 FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
556 FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
557 FastIoDispatch.ReleaseForModWrite = fast_io_release_for_mod_write;
558 FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush;
559 FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush;
560
561 *fiod = &FastIoDispatch;
562 }
563