1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
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.
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.
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/>. */
18 #include "btrfs_drv.h"
20 FAST_IO_DISPATCH FastIoDispatch
;
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
) {
28 FsRtlEnterFileSystem();
30 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, wait
, fbi
, IoStatus
, DeviceObject
);
33 FsRtlExitFileSystem();
37 fcb
= FileObject
->FsContext
;
40 FsRtlExitFileSystem();
44 ccb
= FileObject
->FsContext2
;
47 FsRtlExitFileSystem();
51 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
52 FsRtlExitFileSystem();
57 if (!ccb
->fileref
|| !ccb
->fileref
->parent
|| !ccb
->fileref
->parent
->fcb
) {
58 FsRtlExitFileSystem();
62 fcb
= ccb
->fileref
->parent
->fcb
;
65 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
66 FsRtlExitFileSystem();
70 if (fcb
== fcb
->Vcb
->dummy_fcb
) {
73 KeQuerySystemTime(&time
);
74 fbi
->CreationTime
= fbi
->LastAccessTime
= fbi
->LastWriteTime
= fbi
->ChangeTime
= time
;
76 fbi
->CreationTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.otime
);
77 fbi
->LastAccessTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_atime
);
78 fbi
->LastWriteTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_mtime
);
79 fbi
->ChangeTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_ctime
);
82 fbi
->FileAttributes
= fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fcb
->atts
;
84 IoStatus
->Status
= STATUS_SUCCESS
;
85 IoStatus
->Information
= sizeof(FILE_BASIC_INFORMATION
);
87 ExReleaseResourceLite(fcb
->Header
.Resource
);
89 FsRtlExitFileSystem();
94 _Function_class_(FAST_IO_QUERY_STANDARD_INFO
)
95 static BOOLEAN __stdcall
fast_query_standard_info(PFILE_OBJECT FileObject
, BOOLEAN wait
, PFILE_STANDARD_INFORMATION fsi
,
96 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
102 FsRtlEnterFileSystem();
104 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, wait
, fsi
, IoStatus
, DeviceObject
);
107 FsRtlExitFileSystem();
111 fcb
= FileObject
->FsContext
;
112 ccb
= FileObject
->FsContext2
;
115 FsRtlExitFileSystem();
119 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
120 FsRtlExitFileSystem();
129 if (!ccb
|| !ccb
->fileref
|| !ccb
->fileref
->parent
|| !ccb
->fileref
->parent
->fcb
) {
130 ExReleaseResourceLite(fcb
->Header
.Resource
);
131 FsRtlExitFileSystem();
135 adssize
= fcb
->adsdata
.Length
;
137 fcb2
= ccb
->fileref
->parent
->fcb
;
139 ExReleaseResourceLite(fcb
->Header
.Resource
);
143 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
144 FsRtlExitFileSystem();
148 fsi
->AllocationSize
.QuadPart
= fsi
->EndOfFile
.QuadPart
= adssize
;
149 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
150 fsi
->Directory
= false;
152 fsi
->AllocationSize
.QuadPart
= fcb_alloc_size(fcb
);
153 fsi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
154 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
155 fsi
->Directory
= S_ISDIR(fcb
->inode_item
.st_mode
);
158 fsi
->DeletePending
= ccb
->fileref
? ccb
->fileref
->delete_on_close
: false;
160 IoStatus
->Status
= STATUS_SUCCESS
;
161 IoStatus
->Information
= sizeof(FILE_STANDARD_INFORMATION
);
163 ExReleaseResourceLite(fcb
->Header
.Resource
);
165 FsRtlExitFileSystem();
170 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE
)
171 static BOOLEAN __stdcall
fast_io_check_if_possible(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, ULONG Length
, BOOLEAN Wait
,
172 ULONG LockKey
, BOOLEAN CheckForReadOperation
, PIO_STATUS_BLOCK IoStatus
,
173 PDEVICE_OBJECT DeviceObject
) {
174 fcb
* fcb
= FileObject
->FsContext
;
179 UNUSED(DeviceObject
);
181 len2
.QuadPart
= Length
;
183 if (CheckForReadOperation
) {
184 if (FsRtlFastCheckLockForRead(&fcb
->lock
, FileOffset
, &len2
, LockKey
, FileObject
, PsGetCurrentProcess()))
187 if (!fcb
->Vcb
->readonly
&& !is_subvol_readonly(fcb
->subvol
, NULL
) && FsRtlFastCheckLockForWrite(&fcb
->lock
, FileOffset
, &len2
, LockKey
, FileObject
, PsGetCurrentProcess()))
194 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO
)
195 static BOOLEAN __stdcall
fast_io_query_network_open_info(PFILE_OBJECT FileObject
, BOOLEAN Wait
, FILE_NETWORK_OPEN_INFORMATION
* fnoi
,
196 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
201 FsRtlEnterFileSystem();
203 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, Wait
, fnoi
, IoStatus
, DeviceObject
);
205 RtlZeroMemory(fnoi
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
207 fcb
= FileObject
->FsContext
;
209 if (!fcb
|| fcb
== fcb
->Vcb
->volume_fcb
) {
210 FsRtlExitFileSystem();
214 ccb
= FileObject
->FsContext2
;
217 FsRtlExitFileSystem();
221 fileref
= ccb
->fileref
;
223 if (fcb
== fcb
->Vcb
->dummy_fcb
) {
226 KeQuerySystemTime(&time
);
227 fnoi
->CreationTime
= fnoi
->LastAccessTime
= fnoi
->LastWriteTime
= fnoi
->ChangeTime
= time
;
232 if (!fileref
|| !fileref
->parent
) {
233 ERR("no fileref for stream\n");
234 FsRtlExitFileSystem();
238 ii
= &fileref
->parent
->fcb
->inode_item
;
240 ii
= &fcb
->inode_item
;
242 fnoi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
243 fnoi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
244 fnoi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
245 fnoi
->ChangeTime
.QuadPart
= unix_time_to_win(&ii
->st_ctime
);
249 fnoi
->AllocationSize
.QuadPart
= fnoi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
250 fnoi
->FileAttributes
= fileref
->parent
->fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fileref
->parent
->fcb
->atts
;
252 fnoi
->AllocationSize
.QuadPart
= fcb_alloc_size(fcb
);
253 fnoi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
254 fnoi
->FileAttributes
= fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fcb
->atts
;
257 FsRtlExitFileSystem();
262 _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE
)
263 static NTSTATUS __stdcall
fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject
, PLARGE_INTEGER EndingOffset
,
264 struct _ERESOURCE
**ResourceToRelease
, PDEVICE_OBJECT DeviceObject
) {
267 TRACE("(%p, %I64x, %p, %p)\n", FileObject
, EndingOffset
? EndingOffset
->QuadPart
: 0, ResourceToRelease
, DeviceObject
);
269 UNUSED(EndingOffset
);
270 UNUSED(DeviceObject
);
272 fcb
= FileObject
->FsContext
;
275 return STATUS_INVALID_PARAMETER
;
277 // Make sure we don't get interrupted by the flush thread, which can cause a deadlock
279 if (!ExAcquireResourceSharedLite(&fcb
->Vcb
->tree_lock
, false))
280 return STATUS_CANT_WAIT
;
282 if (!ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, false)) {
283 ExReleaseResourceLite(&fcb
->Vcb
->tree_lock
);
284 TRACE("returning STATUS_CANT_WAIT\n");
285 return STATUS_CANT_WAIT
;
288 // Ideally this would be PagingIoResource, but that doesn't play well with copy-on-write,
289 // as we can't guarantee that we won't need to do any reallocations.
291 *ResourceToRelease
= fcb
->Header
.Resource
;
293 TRACE("returning STATUS_SUCCESS\n");
295 return STATUS_SUCCESS
;
298 _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE
)
299 static NTSTATUS __stdcall
fast_io_release_for_mod_write(PFILE_OBJECT FileObject
, struct _ERESOURCE
*ResourceToRelease
,
300 PDEVICE_OBJECT DeviceObject
) {
303 TRACE("(%p, %p, %p)\n", FileObject
, ResourceToRelease
, DeviceObject
);
305 UNUSED(DeviceObject
);
307 fcb
= FileObject
->FsContext
;
309 ExReleaseResourceLite(ResourceToRelease
);
311 ExReleaseResourceLite(&fcb
->Vcb
->tree_lock
);
313 return STATUS_SUCCESS
;
316 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH
)
317 static NTSTATUS __stdcall
fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
319 UNUSED(DeviceObject
);
321 IoSetTopLevelIrp((PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
323 return STATUS_SUCCESS
;
326 _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH
)
327 static NTSTATUS __stdcall
fast_io_release_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
329 UNUSED(DeviceObject
);
331 if (IoGetTopLevelIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
332 IoSetTopLevelIrp(NULL
);
334 return STATUS_SUCCESS
;
337 _Function_class_(FAST_IO_WRITE
)
338 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
) {
339 fcb
* fcb
= FileObject
->FsContext
;
342 FsRtlEnterFileSystem();
344 if (!ExAcquireResourceSharedLite(&fcb
->Vcb
->tree_lock
, Wait
)) {
345 FsRtlExitFileSystem();
349 if (!ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, Wait
)) {
350 ExReleaseResourceLite(&fcb
->Vcb
->tree_lock
);
351 FsRtlExitFileSystem();
355 ret
= FsRtlCopyWrite(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
, IoStatus
, DeviceObject
);
358 fcb
->inode_item
.st_size
= fcb
->Header
.FileSize
.QuadPart
;
360 ExReleaseResourceLite(fcb
->Header
.Resource
);
361 ExReleaseResourceLite(&fcb
->Vcb
->tree_lock
);
363 FsRtlExitFileSystem();
368 _Function_class_(FAST_IO_LOCK
)
369 static BOOLEAN __stdcall
fast_io_lock(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, PLARGE_INTEGER Length
, PEPROCESS ProcessId
,
370 ULONG Key
, BOOLEAN FailImmediately
, BOOLEAN ExclusiveLock
, PIO_STATUS_BLOCK IoStatus
,
371 PDEVICE_OBJECT DeviceObject
) {
373 fcb
* fcb
= FileObject
->FsContext
;
375 TRACE("(%p, %I64x, %I64x, %p, %x, %u, %u, %p, %p)\n", FileObject
, FileOffset
? FileOffset
->QuadPart
: 0, Length
? Length
->QuadPart
: 0,
376 ProcessId
, Key
, FailImmediately
, ExclusiveLock
, IoStatus
, DeviceObject
);
378 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
379 WARN("can only lock files\n");
380 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
381 IoStatus
->Information
= 0;
385 FsRtlEnterFileSystem();
386 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, true);
388 ret
= FsRtlFastLock(&fcb
->lock
, FileObject
, FileOffset
, Length
, ProcessId
, Key
, FailImmediately
,
389 ExclusiveLock
, IoStatus
, NULL
, false);
392 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
394 ExReleaseResourceLite(fcb
->Header
.Resource
);
395 FsRtlExitFileSystem();
400 _Function_class_(FAST_IO_UNLOCK_SINGLE
)
401 static BOOLEAN __stdcall
fast_io_unlock_single(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, PLARGE_INTEGER Length
, PEPROCESS ProcessId
,
402 ULONG Key
, PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
403 fcb
* fcb
= FileObject
->FsContext
;
405 TRACE("(%p, %I64x, %I64x, %p, %x, %p, %p)\n", FileObject
, FileOffset
? FileOffset
->QuadPart
: 0, Length
? Length
->QuadPart
: 0,
406 ProcessId
, Key
, IoStatus
, DeviceObject
);
408 IoStatus
->Information
= 0;
410 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
411 WARN("can only lock files\n");
412 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
416 FsRtlEnterFileSystem();
418 IoStatus
->Status
= FsRtlFastUnlockSingle(&fcb
->lock
, FileObject
, FileOffset
, Length
, ProcessId
, Key
, NULL
, false);
420 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
422 FsRtlExitFileSystem();
427 _Function_class_(FAST_IO_UNLOCK_ALL
)
428 static BOOLEAN __stdcall
fast_io_unlock_all(PFILE_OBJECT FileObject
, PEPROCESS ProcessId
, PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
429 fcb
* fcb
= FileObject
->FsContext
;
431 TRACE("(%p, %p, %p, %p)\n", FileObject
, ProcessId
, IoStatus
, DeviceObject
);
433 IoStatus
->Information
= 0;
435 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
436 WARN("can only lock files\n");
437 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
441 FsRtlEnterFileSystem();
443 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, true);
445 IoStatus
->Status
= FsRtlFastUnlockAll(&fcb
->lock
, FileObject
, ProcessId
, NULL
);
447 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
449 ExReleaseResourceLite(fcb
->Header
.Resource
);
451 FsRtlExitFileSystem();
456 _Function_class_(FAST_IO_UNLOCK_ALL_BY_KEY
)
457 static BOOLEAN __stdcall
fast_io_unlock_all_by_key(PFILE_OBJECT FileObject
, PVOID ProcessId
, ULONG Key
,
458 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
459 fcb
* fcb
= FileObject
->FsContext
;
461 TRACE("(%p, %p, %x, %p, %p)\n", FileObject
, ProcessId
, Key
, IoStatus
, DeviceObject
);
463 IoStatus
->Information
= 0;
465 if (fcb
->type
!= BTRFS_TYPE_FILE
) {
466 WARN("can only lock files\n");
467 IoStatus
->Status
= STATUS_INVALID_PARAMETER
;
471 FsRtlEnterFileSystem();
473 ExAcquireResourceSharedLite(fcb
->Header
.Resource
, true);
475 IoStatus
->Status
= FsRtlFastUnlockAllByKey(&fcb
->lock
, FileObject
, ProcessId
, Key
, NULL
);
477 fcb
->Header
.IsFastIoPossible
= fast_io_possible(fcb
);
479 ExReleaseResourceLite(fcb
->Header
.Resource
);
481 FsRtlExitFileSystem();
486 void init_fast_io_dispatch(FAST_IO_DISPATCH
** fiod
) {
487 RtlZeroMemory(&FastIoDispatch
, sizeof(FastIoDispatch
));
489 FastIoDispatch
.SizeOfFastIoDispatch
= sizeof(FAST_IO_DISPATCH
);
491 FastIoDispatch
.FastIoCheckIfPossible
= fast_io_check_if_possible
;
492 FastIoDispatch
.FastIoRead
= FsRtlCopyRead
;
493 FastIoDispatch
.FastIoWrite
= fast_io_write
;
494 FastIoDispatch
.FastIoQueryBasicInfo
= fast_query_basic_info
;
495 FastIoDispatch
.FastIoQueryStandardInfo
= fast_query_standard_info
;
496 FastIoDispatch
.FastIoLock
= fast_io_lock
;
497 FastIoDispatch
.FastIoUnlockSingle
= fast_io_unlock_single
;
498 FastIoDispatch
.FastIoUnlockAll
= fast_io_unlock_all
;
499 FastIoDispatch
.FastIoUnlockAllByKey
= fast_io_unlock_all_by_key
;
500 FastIoDispatch
.FastIoQueryNetworkOpenInfo
= fast_io_query_network_open_info
;
501 FastIoDispatch
.AcquireForModWrite
= fast_io_acquire_for_mod_write
;
502 FastIoDispatch
.MdlRead
= FsRtlMdlReadDev
;
503 FastIoDispatch
.MdlReadComplete
= FsRtlMdlReadCompleteDev
;
504 FastIoDispatch
.PrepareMdlWrite
= FsRtlPrepareMdlWriteDev
;
505 FastIoDispatch
.MdlWriteComplete
= FsRtlMdlWriteCompleteDev
;
506 FastIoDispatch
.ReleaseForModWrite
= fast_io_release_for_mod_write
;
507 FastIoDispatch
.AcquireForCcFlush
= fast_io_acquire_for_ccflush
;
508 FastIoDispatch
.ReleaseForCcFlush
= fast_io_release_for_ccflush
;
510 *fiod
= &FastIoDispatch
;