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
)
24 static BOOLEAN NTAPI
fast_query_basic_info(PFILE_OBJECT FileObject
, BOOLEAN wait
, PFILE_BASIC_INFORMATION fbi
,
25 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
27 static BOOLEAN
fast_query_basic_info(PFILE_OBJECT FileObject
, BOOLEAN wait
, PFILE_BASIC_INFORMATION fbi
,
28 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
33 FsRtlEnterFileSystem();
35 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, wait
, fbi
, IoStatus
, DeviceObject
);
38 FsRtlExitFileSystem();
42 fcb
= FileObject
->FsContext
;
45 FsRtlExitFileSystem();
49 ccb
= FileObject
->FsContext2
;
52 FsRtlExitFileSystem();
56 if (!(ccb
->access
& (FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
))) {
57 FsRtlExitFileSystem();
62 if (!ccb
->fileref
|| !ccb
->fileref
->parent
|| !ccb
->fileref
->parent
->fcb
) {
63 FsRtlExitFileSystem();
67 fcb
= ccb
->fileref
->parent
->fcb
;
70 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
71 FsRtlExitFileSystem();
75 if (fcb
== fcb
->Vcb
->dummy_fcb
) {
78 KeQuerySystemTime(&time
);
79 fbi
->CreationTime
= fbi
->LastAccessTime
= fbi
->LastWriteTime
= fbi
->ChangeTime
= time
;
81 fbi
->CreationTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.otime
);
82 fbi
->LastAccessTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_atime
);
83 fbi
->LastWriteTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_mtime
);
84 fbi
->ChangeTime
.QuadPart
= unix_time_to_win(&fcb
->inode_item
.st_ctime
);
87 fbi
->FileAttributes
= fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fcb
->atts
;
89 IoStatus
->Status
= STATUS_SUCCESS
;
90 IoStatus
->Information
= sizeof(FILE_BASIC_INFORMATION
);
92 ExReleaseResourceLite(fcb
->Header
.Resource
);
94 FsRtlExitFileSystem();
99 _Function_class_(FAST_IO_QUERY_STANDARD_INFO
)
101 static BOOLEAN NTAPI
fast_query_standard_info(PFILE_OBJECT FileObject
, BOOLEAN wait
, PFILE_STANDARD_INFORMATION fsi
,
102 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
104 static BOOLEAN
fast_query_standard_info(PFILE_OBJECT FileObject
, BOOLEAN wait
, PFILE_STANDARD_INFORMATION fsi
,
105 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
112 FsRtlEnterFileSystem();
114 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, wait
, fsi
, IoStatus
, DeviceObject
);
117 FsRtlExitFileSystem();
121 fcb
= FileObject
->FsContext
;
122 ccb
= FileObject
->FsContext2
;
125 FsRtlExitFileSystem();
129 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
130 FsRtlExitFileSystem();
139 if (!ccb
|| !ccb
->fileref
|| !ccb
->fileref
->parent
|| !ccb
->fileref
->parent
->fcb
) {
140 ExReleaseResourceLite(fcb
->Header
.Resource
);
141 FsRtlExitFileSystem();
145 adssize
= fcb
->adsdata
.Length
;
147 fcb2
= ccb
->fileref
->parent
->fcb
;
149 ExReleaseResourceLite(fcb
->Header
.Resource
);
153 if (!ExAcquireResourceSharedLite(fcb
->Header
.Resource
, wait
)) {
154 FsRtlExitFileSystem();
158 fsi
->AllocationSize
.QuadPart
= fsi
->EndOfFile
.QuadPart
= adssize
;
159 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
160 fsi
->Directory
= FALSE
;
162 fsi
->AllocationSize
.QuadPart
= fcb_alloc_size(fcb
);
163 fsi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
164 fsi
->NumberOfLinks
= fcb
->inode_item
.st_nlink
;
165 fsi
->Directory
= S_ISDIR(fcb
->inode_item
.st_mode
);
168 fsi
->DeletePending
= ccb
->fileref
? ccb
->fileref
->delete_on_close
: FALSE
;
170 IoStatus
->Status
= STATUS_SUCCESS
;
171 IoStatus
->Information
= sizeof(FILE_STANDARD_INFORMATION
);
173 ExReleaseResourceLite(fcb
->Header
.Resource
);
175 FsRtlExitFileSystem();
180 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE
)
182 static BOOLEAN NTAPI
fast_io_check_if_possible(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, ULONG Length
, BOOLEAN Wait
,
183 ULONG LockKey
, BOOLEAN CheckForReadOperation
, PIO_STATUS_BLOCK IoStatus
,
184 PDEVICE_OBJECT DeviceObject
) {
186 static BOOLEAN
fast_io_check_if_possible(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, ULONG Length
, BOOLEAN Wait
,
187 ULONG LockKey
, BOOLEAN CheckForReadOperation
, PIO_STATUS_BLOCK IoStatus
,
188 PDEVICE_OBJECT DeviceObject
) {
190 fcb
* fcb
= FileObject
->FsContext
;
195 UNUSED(DeviceObject
);
197 len2
.QuadPart
= Length
;
199 if (CheckForReadOperation
) {
200 if (FsRtlFastCheckLockForRead(&fcb
->lock
, FileOffset
, &len2
, LockKey
, FileObject
, PsGetCurrentProcess()))
203 if (!fcb
->Vcb
->readonly
&& !is_subvol_readonly(fcb
->subvol
, NULL
) && FsRtlFastCheckLockForWrite(&fcb
->lock
, FileOffset
, &len2
, LockKey
, FileObject
, PsGetCurrentProcess()))
210 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO
)
212 static BOOLEAN NTAPI
fast_io_query_network_open_info(PFILE_OBJECT FileObject
, BOOLEAN Wait
, FILE_NETWORK_OPEN_INFORMATION
* fnoi
,
213 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
215 static BOOLEAN
fast_io_query_network_open_info(PFILE_OBJECT FileObject
, BOOLEAN Wait
, FILE_NETWORK_OPEN_INFORMATION
* fnoi
,
216 PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
222 FsRtlEnterFileSystem();
224 TRACE("(%p, %u, %p, %p, %p)\n", FileObject
, Wait
, fnoi
, IoStatus
, DeviceObject
);
226 RtlZeroMemory(fnoi
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
228 fcb
= FileObject
->FsContext
;
230 if (!fcb
|| fcb
== fcb
->Vcb
->volume_fcb
) {
231 FsRtlExitFileSystem();
235 ccb
= FileObject
->FsContext2
;
238 FsRtlExitFileSystem();
242 fileref
= ccb
->fileref
;
244 if (fcb
== fcb
->Vcb
->dummy_fcb
) {
247 KeQuerySystemTime(&time
);
248 fnoi
->CreationTime
= fnoi
->LastAccessTime
= fnoi
->LastWriteTime
= fnoi
->ChangeTime
= time
;
253 if (!fileref
|| !fileref
->parent
) {
254 ERR("no fileref for stream\n");
255 FsRtlExitFileSystem();
259 ii
= &fileref
->parent
->fcb
->inode_item
;
261 ii
= &fcb
->inode_item
;
263 fnoi
->CreationTime
.QuadPart
= unix_time_to_win(&ii
->otime
);
264 fnoi
->LastAccessTime
.QuadPart
= unix_time_to_win(&ii
->st_atime
);
265 fnoi
->LastWriteTime
.QuadPart
= unix_time_to_win(&ii
->st_mtime
);
266 fnoi
->ChangeTime
.QuadPart
= unix_time_to_win(&ii
->st_ctime
);
270 fnoi
->AllocationSize
.QuadPart
= fnoi
->EndOfFile
.QuadPart
= fcb
->adsdata
.Length
;
271 fnoi
->FileAttributes
= fileref
->parent
->fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fileref
->parent
->fcb
->atts
;
273 fnoi
->AllocationSize
.QuadPart
= fcb_alloc_size(fcb
);
274 fnoi
->EndOfFile
.QuadPart
= S_ISDIR(fcb
->inode_item
.st_mode
) ? 0 : fcb
->inode_item
.st_size
;
275 fnoi
->FileAttributes
= fcb
->atts
== 0 ? FILE_ATTRIBUTE_NORMAL
: fcb
->atts
;
278 FsRtlExitFileSystem();
283 _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE
)
285 static NTSTATUS NTAPI
fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject
, PLARGE_INTEGER EndingOffset
, struct _ERESOURCE
**ResourceToRelease
, PDEVICE_OBJECT DeviceObject
) {
287 static NTSTATUS
fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject
, PLARGE_INTEGER EndingOffset
, struct _ERESOURCE
**ResourceToRelease
, PDEVICE_OBJECT DeviceObject
) {
291 UNUSED(EndingOffset
);
292 UNUSED(DeviceObject
);
294 fcb
= FileObject
->FsContext
;
297 return STATUS_INVALID_PARAMETER
;
299 *ResourceToRelease
= fcb
->Header
.PagingIoResource
;
301 if (!ExAcquireResourceSharedLite(*ResourceToRelease
, FALSE
))
302 return STATUS_CANT_WAIT
;
304 return STATUS_SUCCESS
;
307 _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE
)
309 static NTSTATUS NTAPI
fast_io_release_for_mod_write(PFILE_OBJECT FileObject
, struct _ERESOURCE
*ResourceToRelease
, PDEVICE_OBJECT DeviceObject
) {
311 static NTSTATUS
fast_io_release_for_mod_write(PFILE_OBJECT FileObject
, struct _ERESOURCE
*ResourceToRelease
, PDEVICE_OBJECT DeviceObject
) {
314 UNUSED(DeviceObject
);
316 ExReleaseResourceLite(ResourceToRelease
);
318 return STATUS_SUCCESS
;
321 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH
)
323 static NTSTATUS NTAPI
fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
325 static NTSTATUS
fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
328 UNUSED(DeviceObject
);
330 IoSetTopLevelIrp((PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
);
332 return STATUS_SUCCESS
;
335 _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH
)
337 static NTSTATUS NTAPI
fast_io_release_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
339 static NTSTATUS
fast_io_release_for_ccflush(PFILE_OBJECT FileObject
, PDEVICE_OBJECT DeviceObject
) {
342 UNUSED(DeviceObject
);
344 if (IoGetTopLevelIrp() == (PIRP
)FSRTL_CACHE_TOP_LEVEL_IRP
)
345 IoSetTopLevelIrp(NULL
);
347 return STATUS_SUCCESS
;
350 _Function_class_(FAST_IO_WRITE
)
352 static BOOLEAN NTAPI
fast_io_write(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, ULONG Length
, BOOLEAN Wait
, ULONG LockKey
, PVOID Buffer
, PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
354 static BOOLEAN
fast_io_write(PFILE_OBJECT FileObject
, PLARGE_INTEGER FileOffset
, ULONG Length
, BOOLEAN Wait
, ULONG LockKey
, PVOID Buffer
, PIO_STATUS_BLOCK IoStatus
, PDEVICE_OBJECT DeviceObject
) {
356 if (FsRtlCopyWrite(FileObject
, FileOffset
, Length
, Wait
, LockKey
, Buffer
, IoStatus
, DeviceObject
)) {
357 fcb
* fcb
= FileObject
->FsContext
;
359 fcb
->inode_item
.st_size
= fcb
->Header
.FileSize
.QuadPart
;
367 void init_fast_io_dispatch(FAST_IO_DISPATCH
** fiod
) {
368 RtlZeroMemory(&FastIoDispatch
, sizeof(FastIoDispatch
));
370 FastIoDispatch
.SizeOfFastIoDispatch
= sizeof(FAST_IO_DISPATCH
);
372 FastIoDispatch
.FastIoCheckIfPossible
= fast_io_check_if_possible
;
373 FastIoDispatch
.FastIoQueryBasicInfo
= fast_query_basic_info
;
374 FastIoDispatch
.FastIoQueryStandardInfo
= fast_query_standard_info
;
375 FastIoDispatch
.FastIoQueryNetworkOpenInfo
= fast_io_query_network_open_info
;
376 FastIoDispatch
.AcquireForModWrite
= fast_io_acquire_for_mod_write
;
377 FastIoDispatch
.ReleaseForModWrite
= fast_io_release_for_mod_write
;
378 FastIoDispatch
.AcquireForCcFlush
= fast_io_acquire_for_ccflush
;
379 FastIoDispatch
.ReleaseForCcFlush
= fast_io_release_for_ccflush
;
380 FastIoDispatch
.FastIoWrite
= fast_io_write
;
381 FastIoDispatch
.FastIoRead
= FsRtlCopyRead
;
382 FastIoDispatch
.MdlRead
= FsRtlMdlReadDev
;
383 FastIoDispatch
.MdlReadComplete
= FsRtlMdlReadCompleteDev
;
384 FastIoDispatch
.PrepareMdlWrite
= FsRtlPrepareMdlWriteDev
;
385 FastIoDispatch
.MdlWriteComplete
= FsRtlMdlWriteCompleteDev
;
387 *fiod
= &FastIoDispatch
;