xref: /reactos/drivers/filesystems/btrfs/fastio.c (revision 6e0cf03d)
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