xref: /reactos/drivers/filesystems/btrfs/fastio.c (revision 01e5cb0c)
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 
22 _Function_class_(FAST_IO_QUERY_BASIC_INFO)
23 #ifdef __REACTOS__
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) {
26 #else
27 static BOOLEAN fast_query_basic_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_BASIC_INFORMATION fbi,
28                                      PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
29 #endif
30     fcb* fcb;
31     ccb* ccb;
32 
33     FsRtlEnterFileSystem();
34 
35     TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fbi, IoStatus, DeviceObject);
36 
37     if (!FileObject) {
38         FsRtlExitFileSystem();
39         return FALSE;
40     }
41 
42     fcb = FileObject->FsContext;
43 
44     if (!fcb) {
45         FsRtlExitFileSystem();
46         return FALSE;
47     }
48 
49     ccb = FileObject->FsContext2;
50 
51     if (!ccb) {
52         FsRtlExitFileSystem();
53         return FALSE;
54     }
55 
56     if (!(ccb->access & (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES))) {
57         FsRtlExitFileSystem();
58         return FALSE;
59     }
60 
61     if (fcb->ads) {
62         if (!ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) {
63             FsRtlExitFileSystem();
64             return FALSE;
65         }
66 
67         fcb = ccb->fileref->parent->fcb;
68     }
69 
70     if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
71         FsRtlExitFileSystem();
72         return FALSE;
73     }
74 
75     if (fcb == fcb->Vcb->dummy_fcb) {
76         LARGE_INTEGER time;
77 
78         KeQuerySystemTime(&time);
79         fbi->CreationTime = fbi->LastAccessTime = fbi->LastWriteTime = fbi->ChangeTime = time;
80     } else {
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);
85     }
86 
87     fbi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
88 
89     IoStatus->Status = STATUS_SUCCESS;
90     IoStatus->Information = sizeof(FILE_BASIC_INFORMATION);
91 
92     ExReleaseResourceLite(fcb->Header.Resource);
93 
94     FsRtlExitFileSystem();
95 
96     return TRUE;
97 }
98 
99 _Function_class_(FAST_IO_QUERY_STANDARD_INFO)
100 #ifdef __REACTOS__
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) {
103 #else
104 static BOOLEAN fast_query_standard_info(PFILE_OBJECT FileObject, BOOLEAN wait, PFILE_STANDARD_INFORMATION fsi,
105                                         PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
106 #endif
107     fcb* fcb;
108     ccb* ccb;
109     BOOL ads;
110     ULONG adssize;
111 
112     FsRtlEnterFileSystem();
113 
114     TRACE("(%p, %u, %p, %p, %p)\n", FileObject, wait, fsi, IoStatus, DeviceObject);
115 
116     if (!FileObject) {
117         FsRtlExitFileSystem();
118         return FALSE;
119     }
120 
121     fcb = FileObject->FsContext;
122     ccb = FileObject->FsContext2;
123 
124     if (!fcb) {
125         FsRtlExitFileSystem();
126         return FALSE;
127     }
128 
129     if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
130         FsRtlExitFileSystem();
131         return FALSE;
132     }
133 
134     ads = fcb->ads;
135 
136     if (ads) {
137         struct _fcb* fcb2;
138 
139         if (!ccb || !ccb->fileref || !ccb->fileref->parent || !ccb->fileref->parent->fcb) {
140             ExReleaseResourceLite(fcb->Header.Resource);
141             FsRtlExitFileSystem();
142             return FALSE;
143         }
144 
145         adssize = fcb->adsdata.Length;
146 
147         fcb2 = ccb->fileref->parent->fcb;
148 
149         ExReleaseResourceLite(fcb->Header.Resource);
150 
151         fcb = fcb2;
152 
153         if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
154             FsRtlExitFileSystem();
155             return FALSE;
156         }
157 
158         fsi->AllocationSize.QuadPart = fsi->EndOfFile.QuadPart = adssize;
159         fsi->NumberOfLinks = fcb->inode_item.st_nlink;
160         fsi->Directory = FALSE;
161     } else {
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);
166     }
167 
168     fsi->DeletePending = ccb->fileref ? ccb->fileref->delete_on_close : FALSE;
169 
170     IoStatus->Status = STATUS_SUCCESS;
171     IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION);
172 
173     ExReleaseResourceLite(fcb->Header.Resource);
174 
175     FsRtlExitFileSystem();
176 
177     return TRUE;
178 }
179 
180 _Function_class_(FAST_IO_CHECK_IF_POSSIBLE)
181 #ifdef __REACTOS__
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) {
185 #else
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) {
189 #endif
190     fcb* fcb = FileObject->FsContext;
191     LARGE_INTEGER len2;
192 
193     UNUSED(Wait);
194     UNUSED(IoStatus);
195     UNUSED(DeviceObject);
196 
197     len2.QuadPart = Length;
198 
199     if (CheckForReadOperation) {
200         if (FsRtlFastCheckLockForRead(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
201             return TRUE;
202     } else {
203         if (!fcb->Vcb->readonly && !is_subvol_readonly(fcb->subvol, NULL) && FsRtlFastCheckLockForWrite(&fcb->lock, FileOffset, &len2, LockKey, FileObject, PsGetCurrentProcess()))
204             return TRUE;
205     }
206 
207     return FALSE;
208 }
209 
210 _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)
211 #ifdef __REACTOS__
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) {
214 #else
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) {
217 #endif
218     fcb* fcb;
219     ccb* ccb;
220     file_ref* fileref;
221 
222     FsRtlEnterFileSystem();
223 
224     TRACE("(%p, %u, %p, %p, %p)\n", FileObject, Wait, fnoi, IoStatus, DeviceObject);
225 
226     RtlZeroMemory(fnoi, sizeof(FILE_NETWORK_OPEN_INFORMATION));
227 
228     fcb = FileObject->FsContext;
229 
230     if (!fcb || fcb == fcb->Vcb->volume_fcb) {
231         FsRtlExitFileSystem();
232         return FALSE;
233     }
234 
235     ccb = FileObject->FsContext2;
236 
237     if (!ccb) {
238         FsRtlExitFileSystem();
239         return FALSE;
240     }
241 
242     fileref = ccb->fileref;
243 
244     if (fcb == fcb->Vcb->dummy_fcb) {
245         LARGE_INTEGER time;
246 
247         KeQuerySystemTime(&time);
248         fnoi->CreationTime = fnoi->LastAccessTime = fnoi->LastWriteTime = fnoi->ChangeTime = time;
249     } else {
250         INODE_ITEM* ii;
251 
252         if (fcb->ads) {
253             if (!fileref || !fileref->parent) {
254                 ERR("no fileref for stream\n");
255                 FsRtlExitFileSystem();
256                 return FALSE;
257             }
258 
259             ii = &fileref->parent->fcb->inode_item;
260         } else
261             ii = &fcb->inode_item;
262 
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);
267     }
268 
269     if (fcb->ads) {
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;
272     } else {
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;
276     }
277 
278     FsRtlExitFileSystem();
279 
280     return TRUE;
281 }
282 
283 _Function_class_(FAST_IO_ACQUIRE_FOR_MOD_WRITE)
284 #ifdef __REACTOS__
285 static NTSTATUS NTAPI fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
286 #else
287 static NTSTATUS fast_io_acquire_for_mod_write(PFILE_OBJECT FileObject, PLARGE_INTEGER EndingOffset, struct _ERESOURCE **ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
288 #endif
289     fcb* fcb;
290 
291     UNUSED(EndingOffset);
292     UNUSED(DeviceObject);
293 
294     fcb = FileObject->FsContext;
295 
296     if (!fcb)
297         return STATUS_INVALID_PARAMETER;
298 
299     // Make sure we don't get interrupted by the flush thread, which can cause a deadlock
300 
301     if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, FALSE))
302         return STATUS_CANT_WAIT;
303 
304     // Ideally this would be PagingIoResource, but that doesn't play well with copy-on-write,
305     // as we can't guarantee that we won't need to do any reallocations.
306 
307     *ResourceToRelease = fcb->Header.Resource;
308 
309     if (!ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE)) {
310         ExReleaseResourceLite(&fcb->Vcb->tree_lock);
311         return STATUS_CANT_WAIT;
312     }
313 
314     return STATUS_SUCCESS;
315 }
316 
317 _Function_class_(FAST_IO_RELEASE_FOR_MOD_WRITE)
318 #ifdef __REACTOS__
319 static NTSTATUS NTAPI fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
320 #else
321 static NTSTATUS fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE *ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
322 #endif
323     fcb* fcb;
324 
325     UNUSED(DeviceObject);
326 
327     fcb = FileObject->FsContext;
328 
329     ExReleaseResourceLite(ResourceToRelease);
330 
331     ExReleaseResourceLite(&fcb->Vcb->tree_lock);
332 
333     return STATUS_SUCCESS;
334 }
335 
336 _Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)
337 #ifdef __REACTOS__
338 static NTSTATUS NTAPI fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
339 #else
340 static NTSTATUS fast_io_acquire_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
341 #endif
342     UNUSED(FileObject);
343     UNUSED(DeviceObject);
344 
345     IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
346 
347     return STATUS_SUCCESS;
348 }
349 
350 _Function_class_(FAST_IO_RELEASE_FOR_CCFLUSH)
351 #ifdef __REACTOS__
352 static NTSTATUS NTAPI fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
353 #else
354 static NTSTATUS fast_io_release_for_ccflush(PFILE_OBJECT FileObject, PDEVICE_OBJECT DeviceObject) {
355 #endif
356     UNUSED(FileObject);
357     UNUSED(DeviceObject);
358 
359     if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP)
360         IoSetTopLevelIrp(NULL);
361 
362     return STATUS_SUCCESS;
363 }
364 
365 _Function_class_(FAST_IO_WRITE)
366 #ifdef __REACTOS__
367 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) {
368 #else
369 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) {
370 #endif
371     if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject)) {
372         fcb* fcb = FileObject->FsContext;
373 
374         fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
375 
376         return TRUE;
377     }
378 
379     return FALSE;
380 }
381 
382 void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
383     RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
384 
385     FastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
386 
387     FastIoDispatch.FastIoCheckIfPossible = fast_io_check_if_possible;
388     FastIoDispatch.FastIoQueryBasicInfo = fast_query_basic_info;
389     FastIoDispatch.FastIoQueryStandardInfo = fast_query_standard_info;
390     FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
391     FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
392     FastIoDispatch.ReleaseForModWrite = fast_io_release_for_mod_write;
393     FastIoDispatch.AcquireForCcFlush = fast_io_acquire_for_ccflush;
394     FastIoDispatch.ReleaseForCcFlush = fast_io_release_for_ccflush;
395     FastIoDispatch.FastIoWrite = fast_io_write;
396     FastIoDispatch.FastIoRead = FsRtlCopyRead;
397     FastIoDispatch.MdlRead = FsRtlMdlReadDev;
398     FastIoDispatch.MdlReadComplete = FsRtlMdlReadCompleteDev;
399     FastIoDispatch.PrepareMdlWrite = FsRtlPrepareMdlWriteDev;
400     FastIoDispatch.MdlWriteComplete = FsRtlMdlWriteCompleteDev;
401 
402     *fiod = &FastIoDispatch;
403 }
404