2017-09-08 08:02:43 +00:00
/* Copyright (c) Mark Harmstone 2016-17
*
2016-03-23 20:35:05 +00:00
* This file is part of WinBtrfs .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* WinBtrfs is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public Licence as published by
* the Free Software Foundation , either version 3 of the Licence , or
* ( at your option ) any later version .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* WinBtrfs is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public Licence for more details .
2017-09-08 08:02:43 +00:00
*
2016-03-23 20:35:05 +00:00
* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs . If not , see < http : //www.gnu.org/licenses/>. */
# ifdef _DEBUG
# define DEBUG
# endif
# include "btrfs_drv.h"
2020-04-23 02:38:57 +00:00
# include "xxhash.h"
# include "crc32c.h"
2016-03-23 20:35:05 +00:00
# ifndef __REACTOS__
# ifndef _MSC_VER
# include <cpuid.h>
# else
# include <intrin.h>
# endif
2020-04-23 02:38:57 +00:00
# endif // __REACTOS__
2016-10-29 17:05:10 +00:00
# include <ntddscsi.h>
2016-03-23 20:35:05 +00:00
# include "btrfs.h"
2016-10-29 17:05:10 +00:00
# include <ata.h>
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
# ifndef _MSC_VER
# include <initguid.h>
# include <ntddstor.h>
# undef INITGUID
# endif
# include <ntdddisk.h>
# include <ntddvol.h>
# ifdef _MSC_VER
# include <initguid.h>
# include <ntddstor.h>
# undef INITGUID
# endif
2019-09-01 12:53:20 +00:00
# include <ntstrsafe.h>
2016-09-04 15:27:46 +00:00
# define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
2016-10-29 17:05:10 +00:00
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
2018-12-16 11:03:16 +00:00
BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \
2020-04-23 02:38:57 +00:00
BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD | BTRFS_INCOMPAT_FLAGS_METADATA_UUID | BTRFS_INCOMPAT_FLAGS_RAID1C34 )
2022-04-28 19:37:02 +00:00
# define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID | \
BTRFS_COMPAT_RO_FLAGS_VERITY )
2016-03-23 20:35:05 +00:00
2018-12-16 11:03:16 +00:00
static const WCHAR device_name [ ] = { ' \\ ' , ' B ' , ' t ' , ' r ' , ' f ' , ' s ' , 0 } ;
static const WCHAR dosdevice_name [ ] = { ' \\ ' , ' D ' , ' o ' , ' s ' , ' D ' , ' e ' , ' v ' , ' i ' , ' c ' , ' e ' , ' s ' , ' \\ ' , ' B ' , ' t ' , ' r ' , ' f ' , ' s ' , 0 } ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
DEFINE_GUID ( BtrfsBusInterface , 0x4d414874 , 0x6865 , 0x6761 , 0x6d , 0x65 , 0x83 , 0x69 , 0x17 , 0x9a , 0x7d , 0x1d ) ;
2016-03-23 20:35:05 +00:00
PDRIVER_OBJECT drvobj ;
2019-09-01 12:53:20 +00:00
PDEVICE_OBJECT master_devobj , busobj ;
uint64_t num_reads = 0 ;
2017-09-08 08:02:43 +00:00
LIST_ENTRY uid_map_list , gid_map_list ;
2016-03-23 20:35:05 +00:00
LIST_ENTRY VcbList ;
ERESOURCE global_loading_lock ;
2019-09-01 12:53:20 +00:00
uint32_t debug_log_level = 0 ;
uint32_t mount_compress = 0 ;
uint32_t mount_compress_force = 0 ;
uint32_t mount_compress_type = 0 ;
uint32_t mount_zlib_level = 3 ;
uint32_t mount_zstd_level = 3 ;
uint32_t mount_flush_interval = 30 ;
uint32_t mount_max_inline = 2048 ;
uint32_t mount_skip_balance = 0 ;
uint32_t mount_no_barrier = 0 ;
uint32_t mount_no_trim = 0 ;
uint32_t mount_clear_cache = 0 ;
uint32_t mount_allow_degraded = 0 ;
uint32_t mount_readonly = 0 ;
2019-11-12 18:32:46 +00:00
uint32_t mount_no_root_dir = 0 ;
2022-09-28 16:08:10 +00:00
uint32_t mount_nodatacow = 0 ;
2019-09-01 12:53:20 +00:00
uint32_t no_pnp = 0 ;
bool log_started = false ;
2016-07-27 19:24:26 +00:00
UNICODE_STRING log_device , log_file , registry_path ;
2017-09-08 08:02:43 +00:00
tPsUpdateDiskCounters fPsUpdateDiskCounters ;
tCcCopyReadEx fCcCopyReadEx ;
tCcCopyWriteEx fCcCopyWriteEx ;
tCcSetAdditionalCacheAttributesEx fCcSetAdditionalCacheAttributesEx ;
tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters ;
2019-09-01 12:53:20 +00:00
tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx ;
tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp ;
tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter ;
tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer ;
2019-11-12 18:32:46 +00:00
tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest ;
tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks ;
2019-09-01 12:53:20 +00:00
bool diskacc = false ;
2017-09-08 08:02:43 +00:00
void * notification_entry = NULL , * notification_entry2 = NULL , * notification_entry3 = NULL ;
ERESOURCE pdo_list_lock , mapping_lock ;
LIST_ENTRY pdo_list ;
2019-09-01 12:53:20 +00:00
bool finished_probing = false ;
2017-09-08 08:02:43 +00:00
HANDLE degraded_wait_handle = NULL , mountmgr_thread_handle = NULL ;
2019-09-01 12:53:20 +00:00
bool degraded_wait = true ;
2017-09-08 08:02:43 +00:00
KEVENT mountmgr_thread_event ;
2019-09-01 12:53:20 +00:00
bool shutting_down = false ;
2019-11-12 18:32:46 +00:00
ERESOURCE boot_lock ;
2022-04-28 19:31:44 +00:00
bool is_windows_8 ;
2020-04-23 02:38:57 +00:00
extern uint64_t boot_subvol ;
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
PFILE_OBJECT comfo = NULL ;
PDEVICE_OBJECT comdo = NULL ;
HANDLE log_handle = NULL ;
2017-09-08 08:02:43 +00:00
ERESOURCE log_lock ;
HANDLE serial_thread_handle = NULL ;
2019-09-01 12:53:20 +00:00
static void init_serial ( bool first_time ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
static NTSTATUS close_file ( _In_ PFILE_OBJECT FileObject , _In_ PIRP Irp ) ;
2022-04-28 19:33:48 +00:00
static void __stdcall do_xor_basic ( uint8_t * buf1 , uint8_t * buf2 , uint32_t len ) ;
xor_func do_xor = do_xor_basic ;
2016-03-23 20:35:05 +00:00
typedef struct {
KEVENT Event ;
IO_STATUS_BLOCK iosb ;
} read_context ;
2019-09-01 12:53:20 +00:00
// no longer in Windows headers??
extern BOOLEAN WdmlibRtlIsNtDdiVersionAvailable ( ULONG Version ) ;
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
2017-09-08 08:02:43 +00:00
_Function_class_ ( IO_COMPLETION_ROUTINE )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall dbg_completion ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp , _In_ PVOID conptr ) {
2016-03-23 20:35:05 +00:00
read_context * context = conptr ;
2017-09-08 08:02:43 +00:00
UNUSED ( DeviceObject ) ;
2016-03-23 20:35:05 +00:00
context - > iosb = Irp - > IoStatus ;
2019-09-01 12:53:20 +00:00
KeSetEvent ( & context - > Event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2019-09-01 12:53:20 +00:00
# define DEBUG_MESSAGE_LEN 1024
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_LONG_MESSAGES
2017-09-08 08:02:43 +00:00
void _debug_message ( _In_ const char * func , _In_ const char * file , _In_ unsigned int line , _In_ char * s , . . . ) {
2016-03-23 20:35:05 +00:00
# else
2017-09-08 08:02:43 +00:00
void _debug_message ( _In_ const char * func , _In_ char * s , . . . ) {
2016-03-23 20:35:05 +00:00
# endif
LARGE_INTEGER offset ;
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
PIRP Irp ;
va_list ap ;
2017-09-08 08:02:43 +00:00
char * buf2 , * buf ;
read_context context ;
2019-09-01 12:53:20 +00:00
uint32_t length ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
buf2 = ExAllocatePoolWithTag ( NonPagedPool , DEBUG_MESSAGE_LEN , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! buf2 ) {
DbgPrint ( " Couldn't allocate buffer in debug_message \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_LONG_MESSAGES
2020-04-23 02:38:57 +00:00
sprintf ( buf2 , " %p:%s:%s:%u: " , ( void * ) PsGetCurrentThread ( ) , func , file , line ) ;
2016-03-23 20:35:05 +00:00
# else
2020-04-23 02:38:57 +00:00
sprintf ( buf2 , " %p:%s: " , ( void * ) PsGetCurrentThread ( ) , func ) ;
2016-03-23 20:35:05 +00:00
# endif
buf = & buf2 [ strlen ( buf2 ) ] ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
va_start ( ap , s ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
RtlStringCbVPrintfA ( buf , DEBUG_MESSAGE_LEN - strlen ( buf2 ) , s , ap ) ;
ExAcquireResourceSharedLite ( & log_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! log_started | | ( log_device . Length = = 0 & & log_file . Length = = 0 ) ) {
DbgPrint ( buf2 ) ;
} else if ( log_device . Length > 0 ) {
if ( ! comdo ) {
DbgPrint ( buf2 ) ;
goto exit2 ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
length = ( uint32_t ) strlen ( buf2 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
offset . u . LowPart = 0 ;
offset . u . HighPart = 0 ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & context , sizeof ( read_context ) ) ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Irp = IoAllocateIrp ( comdo - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! Irp ) {
DbgPrint ( " IoAllocateIrp failed \n " ) ;
goto exit2 ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_WRITE ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = comfo ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( comdo - > Flags & DO_BUFFERED_IO ) {
Irp - > AssociatedIrp . SystemBuffer = buf2 ;
Irp - > Flags = IRP_BUFFERED_IO ;
} else if ( comdo - > Flags & DO_DIRECT_IO ) {
2019-09-01 12:53:20 +00:00
Irp - > MdlAddress = IoAllocateMdl ( buf2 , length , false , false , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Irp - > MdlAddress ) {
DbgPrint ( " IoAllocateMdl failed \n " ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
MmBuildMdlForNonPagedPool ( Irp - > MdlAddress ) ;
2016-03-23 20:35:05 +00:00
} else {
Irp - > UserBuffer = buf2 ;
}
IrpSp - > Parameters . Write . Length = length ;
IrpSp - > Parameters . Write . ByteOffset = offset ;
2017-09-08 08:02:43 +00:00
Irp - > UserIosb = & context . iosb ;
Irp - > UserEvent = & context . Event ;
2016-03-23 20:35:05 +00:00
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( Irp , dbg_completion , & context , true , true , true ) ;
2016-03-23 20:35:05 +00:00
Status = IoCallDriver ( comdo , Irp ) ;
if ( Status = = STATUS_PENDING ) {
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
Status = context . iosb . Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( comdo - > Flags & DO_DIRECT_IO )
2016-03-23 20:35:05 +00:00
IoFreeMdl ( Irp - > MdlAddress ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
DbgPrint ( " failed to write to COM1 - error %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
IoFreeIrp ( Irp ) ;
} else if ( log_handle ! = NULL ) {
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
length = ( uint32_t ) strlen ( buf2 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , buf2 , length , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
DbgPrint ( " failed to write to file - error %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit2 :
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & log_lock ) ;
2016-03-23 20:35:05 +00:00
va_end ( ap ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( buf2 )
ExFreePool ( buf2 ) ;
}
# endif
2019-09-01 12:53:20 +00:00
bool is_top_level ( _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
if ( ! IoGetTopLevelIrp ( ) ) {
IoSetTopLevelIrp ( Irp ) ;
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:33:48 +00:00
static void __stdcall do_xor_basic ( uint8_t * buf1 , uint8_t * buf2 , uint32_t len ) {
uint32_t j ;
# if defined(_ARM_) || defined(_ARM64_)
uint64x2_t x1 , x2 ;
if ( ( ( uintptr_t ) buf1 & 0xf ) = = 0 & & ( ( uintptr_t ) buf2 & 0xf ) = = 0 ) {
while ( len > = 16 ) {
x1 = vld1q_u64 ( ( const uint64_t * ) buf1 ) ;
x2 = vld1q_u64 ( ( const uint64_t * ) buf2 ) ;
x1 = veorq_u64 ( x1 , x2 ) ;
vst1q_u64 ( ( uint64_t * ) buf1 , x1 ) ;
buf1 + = 16 ;
buf2 + = 16 ;
len - = 16 ;
}
}
# endif
# if defined(_AMD64_) || defined(_ARM64_)
while ( len > 8 ) {
* ( uint64_t * ) buf1 ^ = * ( uint64_t * ) buf2 ;
buf1 + = 8 ;
buf2 + = 8 ;
len - = 8 ;
}
# endif
while ( len > 4 ) {
* ( uint32_t * ) buf1 ^ = * ( uint32_t * ) buf2 ;
buf1 + = 4 ;
buf2 + = 4 ;
len - = 4 ;
}
for ( j = 0 ; j < len ; j + + ) {
* buf1 ^ = * buf2 ;
buf1 + + ;
buf2 + + ;
}
}
2017-09-08 08:02:43 +00:00
_Function_class_ ( DRIVER_UNLOAD )
2019-09-01 12:53:20 +00:00
static void __stdcall DriverUnload ( _In_ PDRIVER_OBJECT DriverObject ) {
2016-03-23 20:35:05 +00:00
UNICODE_STRING dosdevice_nameW ;
2019-09-01 12:53:20 +00:00
TRACE ( " (%p) \n " , DriverObject ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
dosdevice_nameW . Buffer = ( WCHAR * ) dosdevice_name ;
dosdevice_nameW . Length = dosdevice_nameW . MaximumLength = sizeof ( dosdevice_name ) - sizeof ( WCHAR ) ;
2016-03-23 20:35:05 +00:00
IoDeleteSymbolicLink ( & dosdevice_nameW ) ;
IoDeleteDevice ( DriverObject - > DeviceObject ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & uid_map_list ) ) {
LIST_ENTRY * le = RemoveHeadList ( & uid_map_list ) ;
uid_map * um = CONTAINING_RECORD ( le , uid_map , listentry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( um - > sid ) ;
ExFreePool ( um ) ;
}
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & gid_map_list ) ) {
gid_map * gm = CONTAINING_RECORD ( RemoveHeadList ( & gid_map_list ) , gid_map , listentry ) ;
ExFreePool ( gm - > sid ) ;
ExFreePool ( gm ) ;
}
2016-03-23 20:35:05 +00:00
// FIXME - free volumes and their devpaths
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
if ( comfo )
ObDereferenceObject ( comfo ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( log_handle )
ZwClose ( log_handle ) ;
# endif
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & pdo_list_lock ) ;
2016-03-23 20:35:05 +00:00
if ( log_device . Buffer )
ExFreePool ( log_device . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( log_file . Buffer )
ExFreePool ( log_file . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( registry_path . Buffer )
ExFreePool ( registry_path . Buffer ) ;
2017-09-08 08:02:43 +00:00
# ifdef _DEBUG
ExDeleteResourceLite ( & log_lock ) ;
# endif
ExDeleteResourceLite ( & mapping_lock ) ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
static bool get_last_inode ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp , prev_tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// get last entry
searchkey . obj_id = 0xffffffffffffffff ;
searchkey . obj_type = 0xff ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , r , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:40 +00:00
if ( ( tp . item - > key . obj_type = = TYPE_INODE_ITEM | | tp . item - > key . obj_type = = TYPE_ROOT_ITEM ) & & tp . item - > key . obj_id < = BTRFS_LAST_FREE_OBJECTID ) {
2016-10-29 17:05:10 +00:00
r - > lastinode = tp . item - > key . obj_id ;
2019-09-01 12:53:20 +00:00
TRACE ( " last inode for tree %I64x is %I64x \n " , r - > id , r - > lastinode ) ;
return true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
while ( find_prev_item ( Vcb , & tp , & prev_tp , Irp ) ) {
2016-03-23 20:35:05 +00:00
tp = prev_tp ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " moving on to %I64x,%x,%I64x \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:40 +00:00
if ( ( tp . item - > key . obj_type = = TYPE_INODE_ITEM | | tp . item - > key . obj_type = = TYPE_ROOT_ITEM ) & & tp . item - > key . obj_id < = BTRFS_LAST_FREE_OBJECTID ) {
2016-03-23 20:35:05 +00:00
r - > lastinode = tp . item - > key . obj_id ;
2019-09-01 12:53:20 +00:00
TRACE ( " last inode for tree %I64x is %I64x \n " , r - > id , r - > lastinode ) ;
return true ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > lastinode = SUBVOL_ROOT_INODE ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
WARN ( " no INODE_ITEMs in tree %I64x \n " , r - > id ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
2019-09-01 12:53:20 +00:00
static bool extract_xattr ( _In_reads_bytes_ ( size ) void * item , _In_ USHORT size , _In_z_ char * name , _Out_ uint8_t * * data , _Out_ uint16_t * datalen ) {
2017-01-01 17:12:12 +00:00
DIR_ITEM * xa = ( DIR_ITEM * ) item ;
USHORT xasize ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( true ) {
2016-03-23 20:35:05 +00:00
if ( size < sizeof ( DIR_ITEM ) | | size < ( sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ) ) {
2017-01-01 17:12:12 +00:00
WARN ( " DIR_ITEM is truncated \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( xa - > n = = strlen ( name ) & & RtlCompareMemory ( name , xa - > name , xa - > n ) = = xa - > n ) {
2017-01-01 17:12:12 +00:00
TRACE ( " found xattr %s \n " , name ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
* datalen = xa - > m ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( xa - > m > 0 ) {
* data = ExAllocatePoolWithTag ( PagedPool , xa - > m , ALLOC_TAG ) ;
if ( ! * data ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( * data , & xa - > name [ xa - > n ] , xa - > m ) ;
} else
* data = NULL ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
xasize = sizeof ( DIR_ITEM ) - 1 + xa - > m + xa - > n ;
if ( size > xasize ) {
size - = xasize ;
xa = ( DIR_ITEM * ) & xa - > name [ xa - > m + xa - > n ] ;
} else
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " xattr %s not found \n " , name ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return false ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
2019-09-01 12:53:20 +00:00
bool get_xattr ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * subvol , _In_ uint64_t inode , _In_z_ char * name , _In_ uint32_t crc32 ,
_Out_ uint8_t * * data , _Out_ uint16_t * datalen , _In_opt_ PIRP Irp ) {
2017-01-01 17:12:12 +00:00
KEY searchkey ;
traverse_ptr tp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " (%p, %I64x, %I64x, %s, %08x, %p, %p) \n " , Vcb , subvol - > id , inode , name , crc32 , data , datalen ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
searchkey . obj_id = inode ;
searchkey . obj_type = TYPE_XATTR_ITEM ;
searchkey . offset = crc32 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , subvol , & tp , & searchkey , false , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " could not find item (%I64x,%x,%I64x) \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
return false ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( tp . item - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return extract_xattr ( tp . item - > data , tp . item - > size , name , data , datalen ) ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_CLOSE )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_close ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " close \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( DeviceObject = = master_devobj ) {
2016-03-23 20:35:05 +00:00
TRACE ( " Closing file system \n " ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
Status = vol_close ( DeviceObject , Irp ) ;
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
2017-09-08 08:02:43 +00:00
Status = close_file ( IrpSp - > FileObject , Irp ) ;
end :
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_DISK_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
FsRtlExitFileSystem ( ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_FLUSH_BUFFERS )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_flush_buffers ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
fcb * fcb = FileObject - > FsContext ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " flush buffers \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
2019-09-01 12:53:20 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
}
if ( ! fcb ) {
ERR ( " fcb was NULL \n " ) ;
2019-09-01 12:53:20 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fcb = = Vcb - > volume_fcb ) {
2019-09-01 12:53:20 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto end ;
}
2019-11-12 18:32:46 +00:00
FsRtlCheckOplock ( fcb_oplock ( fcb ) , Irp , NULL , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
Irp - > IoStatus . Information = 0 ;
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
Irp - > IoStatus . Status = Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > type ! = BTRFS_TYPE_DIRECTORY ) {
2019-09-01 12:53:20 +00:00
CcFlushCache ( FileObject - > SectionObjectPointer , NULL , 0 , & Irp - > IoStatus ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > Header . PagingIoResource ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . PagingIoResource , true ) ;
2016-03-23 20:35:05 +00:00
ExReleaseResourceLite ( fcb - > Header . PagingIoResource ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = Irp - > IoStatus . Status ;
}
2017-09-08 08:02:43 +00:00
end :
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
static void calculate_total_space ( _In_ device_extension * Vcb , _Out_ uint64_t * totalsize , _Out_ uint64_t * freespace ) {
uint64_t nfactor , dfactor , sectors_used ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > data_flags & BLOCK_FLAG_DUPLICATE | | Vcb - > data_flags & BLOCK_FLAG_RAID1 | | Vcb - > data_flags & BLOCK_FLAG_RAID10 ) {
nfactor = 1 ;
dfactor = 2 ;
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID5 ) {
nfactor = Vcb - > superblock . num_devices - 1 ;
dfactor = Vcb - > superblock . num_devices ;
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID6 ) {
nfactor = Vcb - > superblock . num_devices - 2 ;
dfactor = Vcb - > superblock . num_devices ;
2020-04-23 02:38:57 +00:00
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID1C3 ) {
nfactor = 1 ;
dfactor = 3 ;
} else if ( Vcb - > data_flags & BLOCK_FLAG_RAID1C4 ) {
nfactor = 1 ;
dfactor = 4 ;
2016-10-29 17:05:10 +00:00
} else {
nfactor = 1 ;
dfactor = 1 ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
sectors_used = ( Vcb - > superblock . bytes_used > > Vcb - > sector_shift ) * nfactor / dfactor ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
* totalsize = ( Vcb - > superblock . total_bytes > > Vcb - > sector_shift ) * nfactor / dfactor ;
2016-10-29 17:05:10 +00:00
* freespace = sectors_used > * totalsize ? 0 : ( * totalsize - sectors_used ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
# ifndef __REACTOS__
2022-09-28 16:08:10 +00:00
// simplified version of FsRtlAreNamesEqual, which can be a bottleneck!
static bool compare_strings ( const UNICODE_STRING * us1 , const UNICODE_STRING * us2 ) {
if ( us1 - > Length ! = us2 - > Length )
return false ;
WCHAR * s1 = us1 - > Buffer ;
WCHAR * s2 = us2 - > Buffer ;
for ( unsigned int i = 0 ; i < us1 - > Length ; i + + ) {
WCHAR c1 = * s1 ;
WCHAR c2 = * s2 ;
if ( c1 ! = c2 ) {
if ( c1 > = ' a ' & & c1 < = ' z ' )
c1 = c1 - ' a ' + ' A ' ;
if ( c2 > = ' a ' & & c2 < = ' z ' )
c2 = c2 - ' a ' + ' A ' ;
if ( c1 ! = c2 )
return false ;
}
s1 + + ;
s2 + + ;
}
return true ;
}
2019-11-12 18:32:46 +00:00
# define INIT_UNICODE_STRING(var, val) UNICODE_STRING us##var; us##var.Buffer = (WCHAR*)val; us##var.Length = us##var.MaximumLength = sizeof(val) - sizeof(WCHAR);
2017-09-08 08:02:43 +00:00
// This function exists because we have to lie about our FS type in certain situations.
// MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match,
// it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
// The command mklink refuses to create hard links on anything other than NTFS, so we have to
// blacklist cmd.exe too.
2019-09-01 12:53:20 +00:00
static bool lie_about_fs_type ( ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
PROCESS_BASIC_INFORMATION pbi ;
PPEB peb ;
LIST_ENTRY * le ;
ULONG retlen ;
2018-12-16 11:03:16 +00:00
# ifdef _AMD64_
ULONG_PTR wow64info ;
# endif
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
INIT_UNICODE_STRING ( mpr , L " MPR.DLL " ) ;
INIT_UNICODE_STRING ( cmd , L " CMD.EXE " ) ;
INIT_UNICODE_STRING ( fsutil , L " FSUTIL.EXE " ) ;
INIT_UNICODE_STRING ( storsvc , L " STORSVC.DLL " ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
/* Not doing a Volkswagen, honest! Some IFS tests won't run if not recognized FS. */
INIT_UNICODE_STRING ( ifstest , L " IFSTEST.EXE " ) ;
2017-09-08 08:02:43 +00:00
if ( ! PsGetCurrentProcess ( ) )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
# ifdef _AMD64_
Status = ZwQueryInformationProcess ( NtCurrentProcess ( ) , ProcessWow64Information , & wow64info , sizeof ( wow64info ) , NULL ) ;
if ( NT_SUCCESS ( Status ) & & wow64info ! = 0 )
2019-09-01 12:53:20 +00:00
return true ;
2018-12-16 11:03:16 +00:00
# endif
2017-09-08 08:02:43 +00:00
Status = ZwQueryInformationProcess ( NtCurrentProcess ( ) , ProcessBasicInformation , & pbi , sizeof ( pbi ) , & retlen ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwQueryInformationProcess returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
if ( ! pbi . PebBaseAddress )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
peb = pbi . PebBaseAddress ;
if ( ! peb - > Ldr )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
le = peb - > Ldr - > InMemoryOrderModuleList . Flink ;
while ( le ! = & peb - > Ldr - > InMemoryOrderModuleList ) {
LDR_DATA_TABLE_ENTRY * entry = CONTAINING_RECORD ( le , LDR_DATA_TABLE_ENTRY , InMemoryOrderLinks ) ;
2019-09-01 12:53:20 +00:00
bool blacklist = false ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( entry - > FullDllName . Length > = usmpr . Length ) {
UNICODE_STRING name ;
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - usmpr . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = usmpr . Length ;
2022-09-28 16:08:10 +00:00
blacklist = compare_strings ( & name , & usmpr ) ;
2019-11-12 18:32:46 +00:00
}
if ( ! blacklist & & entry - > FullDllName . Length > = uscmd . Length ) {
2017-09-08 08:02:43 +00:00
UNICODE_STRING name ;
2019-11-12 18:32:46 +00:00
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - uscmd . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = uscmd . Length ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
blacklist = compare_strings ( & name , & uscmd ) ;
2017-09-08 08:02:43 +00:00
}
2019-11-12 18:32:46 +00:00
if ( ! blacklist & & entry - > FullDllName . Length > = usfsutil . Length ) {
2017-09-08 08:02:43 +00:00
UNICODE_STRING name ;
2019-11-12 18:32:46 +00:00
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - usfsutil . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = usfsutil . Length ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
blacklist = compare_strings ( & name , & usfsutil ) ;
2017-09-08 08:02:43 +00:00
}
2019-11-12 18:32:46 +00:00
if ( ! blacklist & & entry - > FullDllName . Length > = usstorsvc . Length ) {
2017-09-08 08:02:43 +00:00
UNICODE_STRING name ;
2019-11-12 18:32:46 +00:00
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - usstorsvc . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = usstorsvc . Length ;
2017-09-08 08:02:43 +00:00
2022-09-28 16:08:10 +00:00
blacklist = compare_strings ( & name , & usstorsvc ) ;
2017-09-08 08:02:43 +00:00
}
2022-04-28 19:34:48 +00:00
if ( ! blacklist & & entry - > FullDllName . Length > = usifstest . Length ) {
UNICODE_STRING name ;
name . Buffer = & entry - > FullDllName . Buffer [ ( entry - > FullDllName . Length - usifstest . Length ) / sizeof ( WCHAR ) ] ;
name . Length = name . MaximumLength = usifstest . Length ;
2022-09-28 16:08:10 +00:00
blacklist = compare_strings ( & name , & usifstest ) ;
2022-04-28 19:34:48 +00:00
}
2017-09-08 08:02:43 +00:00
if ( blacklist ) {
void * * frames ;
ULONG i , num_frames ;
frames = ExAllocatePoolWithTag ( PagedPool , 256 * sizeof ( void * ) , ALLOC_TAG ) ;
if ( ! frames ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
num_frames = RtlWalkFrameChain ( frames , 256 , 1 ) ;
for ( i = 0 ; i < num_frames ; i + + ) {
// entry->Reserved3[1] appears to be the image size
if ( frames [ i ] > = entry - > DllBase & & ( ULONG_PTR ) frames [ i ] < = ( ULONG_PTR ) entry - > DllBase + ( ULONG_PTR ) entry - > Reserved3 [ 1 ] ) {
ExFreePool ( frames ) ;
2019-09-01 12:53:20 +00:00
return true ;
2017-09-08 08:02:43 +00:00
}
}
ExFreePool ( frames ) ;
}
le = le - > Flink ;
}
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
2020-04-23 02:38:57 +00:00
# endif // __REACTOS__
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
// version of RtlUTF8ToUnicodeN for Vista and below
NTSTATUS utf8_to_utf16 ( WCHAR * dest , ULONG dest_max , ULONG * dest_len , char * src , ULONG src_len ) {
NTSTATUS Status = STATUS_SUCCESS ;
uint8_t * in = ( uint8_t * ) src ;
uint16_t * out = ( uint16_t * ) dest ;
ULONG needed = 0 , left = dest_max / sizeof ( uint16_t ) ;
for ( ULONG i = 0 ; i < src_len ; i + + ) {
uint32_t cp ;
if ( ! ( in [ i ] & 0x80 ) )
cp = in [ i ] ;
else if ( ( in [ i ] & 0xe0 ) = = 0xc0 ) {
if ( i = = src_len - 1 | | ( in [ i + 1 ] & 0xc0 ) ! = 0x80 ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
} else {
cp = ( ( in [ i ] & 0x1f ) < < 6 ) | ( in [ i + 1 ] & 0x3f ) ;
i + + ;
}
} else if ( ( in [ i ] & 0xf0 ) = = 0xe0 ) {
if ( i > = src_len - 2 | | ( in [ i + 1 ] & 0xc0 ) ! = 0x80 | | ( in [ i + 2 ] & 0xc0 ) ! = 0x80 ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
} else {
cp = ( ( in [ i ] & 0xf ) < < 12 ) | ( ( in [ i + 1 ] & 0x3f ) < < 6 ) | ( in [ i + 2 ] & 0x3f ) ;
i + = 2 ;
}
} else if ( ( in [ i ] & 0xf8 ) = = 0xf0 ) {
if ( i > = src_len - 3 | | ( in [ i + 1 ] & 0xc0 ) ! = 0x80 | | ( in [ i + 2 ] & 0xc0 ) ! = 0x80 | | ( in [ i + 3 ] & 0xc0 ) ! = 0x80 ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
} else {
cp = ( ( in [ i ] & 0x7 ) < < 18 ) | ( ( in [ i + 1 ] & 0x3f ) < < 12 ) | ( ( in [ i + 2 ] & 0x3f ) < < 6 ) | ( in [ i + 3 ] & 0x3f ) ;
i + = 3 ;
}
} else {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
}
if ( cp > 0x10ffff ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
}
if ( dest ) {
if ( cp < = 0xffff ) {
if ( left < 1 )
return STATUS_BUFFER_OVERFLOW ;
* out = ( uint16_t ) cp ;
out + + ;
left - - ;
} else {
if ( left < 2 )
return STATUS_BUFFER_OVERFLOW ;
cp - = 0x10000 ;
* out = 0xd800 | ( ( cp & 0xffc00 ) > > 10 ) ;
out + + ;
* out = 0xdc00 | ( cp & 0x3ff ) ;
out + + ;
left - = 2 ;
}
}
if ( cp < = 0xffff )
needed + = sizeof ( uint16_t ) ;
else
needed + = 2 * sizeof ( uint16_t ) ;
}
if ( dest_len )
* dest_len = needed ;
return Status ;
}
// version of RtlUnicodeToUTF8N for Vista and below
NTSTATUS utf16_to_utf8 ( char * dest , ULONG dest_max , ULONG * dest_len , WCHAR * src , ULONG src_len ) {
NTSTATUS Status = STATUS_SUCCESS ;
uint16_t * in = ( uint16_t * ) src ;
uint8_t * out = ( uint8_t * ) dest ;
ULONG in_len = src_len / sizeof ( uint16_t ) ;
ULONG needed = 0 , left = dest_max ;
for ( ULONG i = 0 ; i < in_len ; i + + ) {
uint32_t cp = * in ;
in + + ;
if ( ( cp & 0xfc00 ) = = 0xd800 ) {
if ( i = = in_len - 1 | | ( * in & 0xfc00 ) ! = 0xdc00 ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
} else {
cp = ( cp & 0x3ff ) < < 10 ;
cp | = * in & 0x3ff ;
cp + = 0x10000 ;
in + + ;
i + + ;
}
} else if ( ( cp & 0xfc00 ) = = 0xdc00 ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
}
if ( cp > 0x10ffff ) {
cp = 0xfffd ;
Status = STATUS_SOME_NOT_MAPPED ;
}
if ( dest ) {
if ( cp < 0x80 ) {
if ( left < 1 )
return STATUS_BUFFER_OVERFLOW ;
* out = ( uint8_t ) cp ;
out + + ;
left - - ;
} else if ( cp < 0x800 ) {
if ( left < 2 )
return STATUS_BUFFER_OVERFLOW ;
* out = 0xc0 | ( ( cp & 0x7c0 ) > > 6 ) ;
out + + ;
* out = 0x80 | ( cp & 0x3f ) ;
out + + ;
left - = 2 ;
} else if ( cp < 0x10000 ) {
if ( left < 3 )
return STATUS_BUFFER_OVERFLOW ;
* out = 0xe0 | ( ( cp & 0xf000 ) > > 12 ) ;
out + + ;
* out = 0x80 | ( ( cp & 0xfc0 ) > > 6 ) ;
out + + ;
* out = 0x80 | ( cp & 0x3f ) ;
out + + ;
left - = 3 ;
} else {
if ( left < 4 )
return STATUS_BUFFER_OVERFLOW ;
* out = 0xf0 | ( ( cp & 0x1c0000 ) > > 18 ) ;
out + + ;
* out = 0x80 | ( ( cp & 0x3f000 ) > > 12 ) ;
out + + ;
* out = 0x80 | ( ( cp & 0xfc0 ) > > 6 ) ;
out + + ;
* out = 0x80 | ( cp & 0x3f ) ;
out + + ;
left - = 4 ;
}
}
if ( cp < 0x80 )
needed + + ;
else if ( cp < 0x800 )
needed + = 2 ;
else if ( cp < 0x10000 )
needed + = 3 ;
else
needed + = 4 ;
}
if ( dest_len )
* dest_len = needed ;
return Status ;
}
_Dispatch_type_ ( IRP_MJ_QUERY_VOLUME_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS __stdcall drv_query_volume_information ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
ULONG BytesCopied = 0 ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " query volume information \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
}
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > Parameters . QueryVolume . FsInformationClass ) {
case FileFsAttributeInformation :
{
FILE_FS_ATTRIBUTE_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
2019-09-01 12:53:20 +00:00
bool overflow = false ;
2017-09-08 08:02:43 +00:00
# ifndef __REACTOS__
2018-12-16 11:03:16 +00:00
static const WCHAR ntfs [ ] = L " NTFS " ;
# endif
static const WCHAR btrfs [ ] = L " Btrfs " ;
const WCHAR * fs_name ;
ULONG fs_name_len , orig_fs_name_len ;
# ifndef __REACTOS__
if ( Irp - > RequestorMode = = UserMode & & lie_about_fs_type ( ) ) {
fs_name = ntfs ;
orig_fs_name_len = fs_name_len = sizeof ( ntfs ) - sizeof ( WCHAR ) ;
} else {
fs_name = btrfs ;
orig_fs_name_len = fs_name_len = sizeof ( btrfs ) - sizeof ( WCHAR ) ;
}
2017-09-08 08:02:43 +00:00
# else
2018-12-16 11:03:16 +00:00
fs_name = btrfs ;
orig_fs_name_len = fs_name_len = sizeof ( btrfs ) - sizeof ( WCHAR ) ;
2017-09-08 08:02:43 +00:00
# endif
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsAttributeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( IrpSp - > Parameters . QueryVolume . Length < sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) + fs_name_len ) {
if ( IrpSp - > Parameters . QueryVolume . Length > sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) )
fs_name_len = IrpSp - > Parameters . QueryVolume . Length - sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) + sizeof ( WCHAR ) ;
else
fs_name_len = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
overflow = true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
data - > FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH |
FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS |
2016-10-29 17:05:10 +00:00
FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_SPARSE_FILES | FILE_SUPPORTS_OBJECT_IDS |
2019-06-11 10:35:19 +00:00
FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING |
FILE_SUPPORTS_POSIX_UNLINK_RENAME ;
2016-03-23 20:35:05 +00:00
if ( Vcb - > readonly )
data - > FileSystemAttributes | = FILE_READ_ONLY_VOLUME ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// should also be FILE_FILE_COMPRESSION when supported
data - > MaximumComponentNameLength = 255 ; // FIXME - check
data - > FileSystemNameLength = orig_fs_name_len ;
RtlCopyMemory ( data - > FileSystemName , fs_name , fs_name_len ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_ATTRIBUTE_INFORMATION ) - sizeof ( WCHAR ) + fs_name_len ;
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
break ;
}
case FileFsDeviceInformation :
2016-09-04 15:27:46 +00:00
{
FILE_FS_DEVICE_INFORMATION * ffdi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
TRACE ( " FileFsDeviceInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ffdi - > DeviceType = FILE_DEVICE_DISK ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
ffdi - > Characteristics = Vcb - > Vpb - > RealDevice - > Characteristics ;
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > readonly )
ffdi - > Characteristics | = FILE_READ_ONLY_DEVICE ;
else
ffdi - > Characteristics & = ~ FILE_READ_ONLY_DEVICE ;
BytesCopied = sizeof ( FILE_FS_DEVICE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
}
2016-03-23 20:35:05 +00:00
case FileFsFullSizeInformation :
{
FILE_FS_FULL_SIZE_INFORMATION * ffsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsFullSizeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
calculate_total_space ( Vcb , ( uint64_t * ) & ffsi - > TotalAllocationUnits . QuadPart , ( uint64_t * ) & ffsi - > ActualAvailableAllocationUnits . QuadPart ) ;
2016-03-23 20:35:05 +00:00
ffsi - > CallerAvailableAllocationUnits . QuadPart = ffsi - > ActualAvailableAllocationUnits . QuadPart ;
2019-09-01 12:53:20 +00:00
ffsi - > SectorsPerAllocationUnit = Vcb - > superblock . sector_size / 512 ;
ffsi - > BytesPerSector = 512 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_FULL_SIZE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileFsObjectIdInformation :
2016-07-27 19:24:26 +00:00
{
FILE_FS_OBJECTID_INFORMATION * ffoi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
TRACE ( " FileFsObjectIdInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( ffoi - > ObjectId , & Vcb - > superblock . uuid . uuid [ 0 ] , sizeof ( UCHAR ) * 16 ) ;
RtlZeroMemory ( ffoi - > ExtendedInfo , sizeof ( ffoi - > ExtendedInfo ) ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
BytesCopied = sizeof ( FILE_FS_OBJECTID_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
case FileFsSizeInformation :
{
FILE_FS_SIZE_INFORMATION * ffsi = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsSizeInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
calculate_total_space ( Vcb , ( uint64_t * ) & ffsi - > TotalAllocationUnits . QuadPart , ( uint64_t * ) & ffsi - > AvailableAllocationUnits . QuadPart ) ;
ffsi - > SectorsPerAllocationUnit = Vcb - > superblock . sector_size / 512 ;
ffsi - > BytesPerSector = 512 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
BytesCopied = sizeof ( FILE_FS_SIZE_INFORMATION ) ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
}
case FileFsVolumeInformation :
{
FILE_FS_VOLUME_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
FILE_FS_VOLUME_INFORMATION ffvi ;
2019-09-01 12:53:20 +00:00
bool overflow = false ;
2016-03-23 20:35:05 +00:00
ULONG label_len , orig_label_len ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " FileFsVolumeInformation \n " ) ;
2020-04-23 02:38:57 +00:00
TRACE ( " max length = %lu \n " , IrpSp - > Parameters . QueryVolume . Length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( NULL , 0 , & label_len , Vcb - > superblock . label , ( ULONG ) strlen ( Vcb - > superblock . label ) ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
break ;
}
2016-03-23 20:35:05 +00:00
orig_label_len = label_len ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:33:48 +00:00
if ( IrpSp - > Parameters . QueryVolume . Length < offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) + label_len ) {
if ( IrpSp - > Parameters . QueryVolume . Length > offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) )
label_len = IrpSp - > Parameters . QueryVolume . Length - offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) ;
2016-03-23 20:35:05 +00:00
else
label_len = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
overflow = true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " label_len = %lu \n " , label_len ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:33:48 +00:00
RtlZeroMemory ( & ffvi , offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) ) ;
2016-03-23 20:35:05 +00:00
ffvi . VolumeSerialNumber = Vcb - > superblock . uuid . uuid [ 12 ] < < 24 | Vcb - > superblock . uuid . uuid [ 13 ] < < 16 | Vcb - > superblock . uuid . uuid [ 14 ] < < 8 | Vcb - > superblock . uuid . uuid [ 15 ] ;
ffvi . VolumeLabelLength = orig_label_len ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:33:48 +00:00
RtlCopyMemory ( data , & ffvi , min ( offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) , IrpSp - > Parameters . QueryVolume . Length ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( label_len > 0 ) {
ULONG bytecount ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = utf8_to_utf16 ( & data - > VolumeLabel [ 0 ] , label_len , & bytecount , Vcb - > superblock . label , ( ULONG ) strlen ( Vcb - > superblock . label ) ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_TOO_SMALL ) {
2020-04-23 02:38:57 +00:00
ERR ( " utf8_to_utf16 returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
break ;
}
2020-04-23 02:38:57 +00:00
TRACE ( " label = %.*S \n " , ( int ) ( label_len / sizeof ( WCHAR ) ) , data - > VolumeLabel ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
2022-04-28 19:33:48 +00:00
BytesCopied = offsetof ( FILE_FS_VOLUME_INFORMATION , VolumeLabel ) + label_len ;
2016-03-23 20:35:05 +00:00
Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-30 14:14:27 +00:00
# ifndef __REACTOS__
2016-10-29 17:05:10 +00:00
# ifdef _MSC_VER // not in mingw yet
case FileFsSectorSizeInformation :
{
FILE_FS_SECTOR_SIZE_INFORMATION * data = Irp - > AssociatedIrp . SystemBuffer ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data - > LogicalBytesPerSector = Vcb - > superblock . sector_size ;
data - > PhysicalBytesPerSectorForAtomicity = Vcb - > superblock . sector_size ;
data - > PhysicalBytesPerSectorForPerformance = Vcb - > superblock . sector_size ;
data - > FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb - > superblock . sector_size ;
data - > ByteOffsetForSectorAlignment = 0 ;
data - > ByteOffsetForPartitionAlignment = 0 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
data - > Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > trim & & ! Vcb - > options . no_trim )
2016-10-29 17:05:10 +00:00
data - > Flags | = SSINFO_FLAGS_TRIM_ENABLED ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
BytesCopied = sizeof ( FILE_FS_SECTOR_SIZE_INFORMATION ) ;
2020-04-23 02:38:57 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
break ;
}
# endif
2016-10-30 14:14:27 +00:00
# endif /* __REACTOS__ */
2016-03-23 20:35:05 +00:00
default :
Status = STATUS_INVALID_PARAMETER ;
2016-07-27 19:24:26 +00:00
WARN ( " unknown FsInformationClass %u \n " , IrpSp - > Parameters . QueryVolume . FsInformationClass ) ;
2016-03-23 20:35:05 +00:00
break ;
}
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_OVERFLOW )
Irp - > IoStatus . Information = 0 ;
else
Irp - > IoStatus . Information = BytesCopied ;
2017-09-08 08:02:43 +00:00
end :
Irp - > IoStatus . Status = Status ;
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_DISK_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " query volume information returning %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
FsRtlExitFileSystem ( ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Function_class_ ( IO_COMPLETION_ROUTINE )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall read_completion ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp , _In_ PVOID conptr ) {
2016-03-23 20:35:05 +00:00
read_context * context = conptr ;
2017-09-08 08:02:43 +00:00
UNUSED ( DeviceObject ) ;
2016-03-23 20:35:05 +00:00
context - > iosb = Irp - > IoStatus ;
2019-09-01 12:53:20 +00:00
KeSetEvent ( & context - > Event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_MORE_PROCESSING_REQUIRED ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS create_root ( _In_ _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ uint64_t id ,
_Out_ root * * rootptr , _In_ bool no_tree , _In_ uint64_t offset , _In_opt_ PIRP Irp ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-05-05 17:26:47 +00:00
root * r ;
ROOT_ITEM * ri ;
traverse_ptr tp ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r = ExAllocatePoolWithTag ( PagedPool , sizeof ( root ) , ALLOC_TAG ) ;
if ( ! r ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( root_nonpaged ) , ALLOC_TAG ) ;
if ( ! r - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ri = ExAllocatePoolWithTag ( PagedPool , sizeof ( ROOT_ITEM ) , ALLOC_TAG ) ;
if ( ! ri ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
r - > id = id ;
r - > treeholder . address = 0 ;
r - > treeholder . generation = Vcb - > superblock . generation ;
2022-04-28 19:31:44 +00:00
r - > treeholder . tree = NULL ;
2016-05-05 17:26:47 +00:00
r - > lastinode = 0 ;
2019-09-01 12:53:20 +00:00
r - > dirty = false ;
r - > received = false ;
2017-09-08 08:02:43 +00:00
r - > reserved = NULL ;
r - > parent = 0 ;
r - > send_ops = 0 ;
2016-05-05 17:26:47 +00:00
RtlZeroMemory ( & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
r - > root_item . num_references = 1 ;
2019-05-11 09:20:02 +00:00
r - > fcbs_version = 0 ;
2019-09-01 12:53:20 +00:00
r - > checked_for_orphans = true ;
2020-04-23 02:38:57 +00:00
r - > dropped = false ;
2016-05-05 17:26:47 +00:00
InitializeListHead ( & r - > fcbs ) ;
2019-05-11 09:20:02 +00:00
RtlZeroMemory ( r - > fcbs_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( ri , & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// We ask here for a traverse_ptr to the item we're inserting, so we can
// copy some of the tree's variables
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , Vcb - > root_root , id , TYPE_ROOT_ITEM , offset , ri , sizeof ( ROOT_ITEM ) , & tp , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
ExFreePool ( ri ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ExInitializeResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > roots , & r - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( ! no_tree ) {
2022-04-28 19:31:44 +00:00
tree * t = ExAllocatePoolWithTag ( PagedPool , sizeof ( tree ) , ALLOC_TAG ) ;
if ( ! t ) {
ERR ( " out of memory \n " ) ;
delete_tree_item ( Vcb , & tp ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
ExFreePool ( ri ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
t - > nonpaged = NULL ;
t - > is_unique = true ;
t - > uniqueness_determined = true ;
t - > buf = NULL ;
r - > treeholder . tree = t ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & t - > header , sizeof ( tree_header ) ) ;
2016-05-05 17:26:47 +00:00
t - > header . fs_uuid = tp . tree - > header . fs_uuid ;
t - > header . address = 0 ;
t - > header . flags = HEADER_FLAG_MIXED_BACKREF | 1 ; // 1 == "written"? Why does the Linux driver record this?
t - > header . chunk_tree_uuid = tp . tree - > header . chunk_tree_uuid ;
t - > header . generation = Vcb - > superblock . generation ;
t - > header . tree_id = id ;
t - > header . num_items = 0 ;
t - > header . level = 0 ;
2019-09-01 12:53:20 +00:00
t - > has_address = false ;
2016-05-05 17:26:47 +00:00
t - > size = 0 ;
t - > Vcb = Vcb ;
t - > parent = NULL ;
t - > paritem = NULL ;
t - > root = r ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InitializeListHead ( & t - > itemlist ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
t - > new_address = 0 ;
2019-09-01 12:53:20 +00:00
t - > has_new_address = false ;
t - > updated_extents = false ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > trees , & t - > list_entry ) ;
2017-01-01 17:12:12 +00:00
t - > list_entry_hash . Flink = NULL ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
t - > write = true ;
Vcb - > need_write = true ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
* rootptr = r ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS set_label ( _In_ device_extension * Vcb , _In_ FILE_FS_LABEL_INFORMATION * ffli ) {
2016-03-23 20:35:05 +00:00
ULONG utf8len ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG vollen , i ;
2020-04-23 02:38:57 +00:00
TRACE ( " label = %.*S \n " , ( int ) ( ffli - > VolumeLabelLength / sizeof ( WCHAR ) ) , ffli - > VolumeLabel ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
vollen = ffli - > VolumeLabelLength ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
for ( i = 0 ; i < ffli - > VolumeLabelLength / sizeof ( WCHAR ) ; i + + ) {
if ( ffli - > VolumeLabel [ i ] = = 0 ) {
vollen = i * sizeof ( WCHAR ) ;
break ;
} else if ( ffli - > VolumeLabel [ i ] = = ' / ' | | ffli - > VolumeLabel [ i ] = = ' \\ ' ) {
Status = STATUS_INVALID_VOLUME_LABEL ;
goto end ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( vollen = = 0 ) {
utf8len = 0 ;
} else {
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , ffli - > VolumeLabel , vollen ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) )
goto end ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len > MAX_LABEL_SIZE ) {
Status = STATUS_INVALID_VOLUME_LABEL ;
goto end ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len > 0 ) {
2019-09-01 12:53:20 +00:00
Status = utf16_to_utf8 ( ( PCHAR ) & Vcb - > superblock . label , MAX_LABEL_SIZE , & utf8len , ffli - > VolumeLabel , vollen ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) )
goto release ;
} else
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( utf8len < MAX_LABEL_SIZE )
RtlZeroMemory ( Vcb - > superblock . label + utf8len , MAX_LABEL_SIZE - utf8len ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > need_write = true ;
2017-09-08 08:02:43 +00:00
release :
2016-07-27 19:24:26 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
end :
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_SET_VOLUME_INFORMATION )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_set_volume_information ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " set volume information \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( Vcb - > readonly ) {
Status = STATUS_MEDIA_WRITE_PROTECTED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > removing | | Vcb - > locked ) {
2016-05-05 17:26:47 +00:00
Status = STATUS_ACCESS_DENIED ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > Parameters . SetVolume . FsInformationClass ) {
case FileFsControlInformation :
FIXME ( " STUB: FileFsControlInformation \n " ) ;
break ;
case FileFsLabelInformation :
TRACE ( " FileFsLabelInformation \n " ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = set_label ( Vcb , Irp - > AssociatedIrp . SystemBuffer ) ;
break ;
case FileFsObjectIdInformation :
FIXME ( " STUB: FileFsObjectIdInformation \n " ) ;
break ;
default :
WARN ( " Unrecognized FsInformationClass 0x%x \n " , IrpSp - > Parameters . SetVolume . FsInformationClass ) ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
end :
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
void send_notification_fileref ( _In_ file_ref * fileref , _In_ ULONG filter_match , _In_ ULONG action , _In_opt_ PUNICODE_STRING stream ) {
2016-07-27 19:24:26 +00:00
UNICODE_STRING fn ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG reqlen ;
2016-07-27 19:24:26 +00:00
USHORT name_offset ;
2016-05-05 17:26:47 +00:00
fcb * fcb = fileref - > fcb ;
2017-09-08 08:02:43 +00:00
fn . Length = fn . MaximumLength = 0 ;
Status = fileref_get_filename ( fileref , & fn , NULL , & reqlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
2020-04-23 02:38:57 +00:00
ERR ( " fileref_get_filename returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return ;
}
if ( reqlen > 0xffff ) {
WARN ( " reqlen was too long for FsRtlNotifyFilterReportChange \n " ) ;
return ;
}
fn . Buffer = ExAllocatePoolWithTag ( PagedPool , reqlen , ALLOC_TAG ) ;
if ( ! fn . Buffer ) {
ERR ( " out of memory \n " ) ;
return ;
}
fn . MaximumLength = ( USHORT ) reqlen ;
fn . Length = 0 ;
Status = fileref_get_filename ( fileref , & fn , & name_offset , & reqlen ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " fileref_get_filename returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( fn . Buffer ) ;
2016-07-27 19:24:26 +00:00
return ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & fn , name_offset ,
2017-09-08 08:02:43 +00:00
( PSTRING ) stream , NULL , filter_match , action , NULL , NULL ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( fn . Buffer ) ;
}
2019-11-12 18:32:46 +00:00
static void send_notification_fcb ( _In_ file_ref * fileref , _In_ ULONG filter_match , _In_ ULONG action , _In_opt_ PUNICODE_STRING stream ) {
2016-07-27 19:24:26 +00:00
fcb * fcb = fileref - > fcb ;
LIST_ENTRY * le ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// no point looking for hardlinks if st_nlink == 1
if ( fileref - > fcb - > inode_item . st_nlink = = 1 ) {
2022-04-28 19:31:44 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fileref_lock , true ) ;
2017-09-08 08:02:43 +00:00
send_notification_fileref ( fileref , filter_match , action , stream ) ;
2022-04-28 19:31:44 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
2016-07-27 19:24:26 +00:00
return ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fileref_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = fcb - > hardlinks . Flink ;
while ( le ! = & fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
file_ref * parfr ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = open_fileref_by_inode ( fcb - > Vcb , fcb - > subvol , hl - > parent , & parfr , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " open_fileref_by_inode returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
else if ( ! parfr - > deleted ) {
UNICODE_STRING fn ;
ULONG pathlen ;
fn . Length = fn . MaximumLength = 0 ;
Status = fileref_get_filename ( parfr , & fn , NULL , & pathlen ) ;
if ( Status ! = STATUS_BUFFER_OVERFLOW ) {
2020-04-23 02:38:57 +00:00
ERR ( " fileref_get_filename returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( parfr ! = fcb - > Vcb - > root_fileref )
pathlen + = sizeof ( WCHAR ) ;
if ( pathlen + hl - > name . Length > 0xffff ) {
WARN ( " pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange \n " ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
break ;
}
fn . MaximumLength = ( USHORT ) ( pathlen + hl - > name . Length ) ;
fn . Buffer = ExAllocatePoolWithTag ( PagedPool , fn . MaximumLength , ALLOC_TAG ) ;
if ( ! fn . Buffer ) {
ERR ( " out of memory \n " ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
break ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
Status = fileref_get_filename ( parfr , & fn , NULL , NULL ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " fileref_get_filename returned %08lx \n " , Status ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfr ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( fn . Buffer ) ;
break ;
}
if ( parfr ! = fcb - > Vcb - > root_fileref ) {
fn . Buffer [ ( pathlen / sizeof ( WCHAR ) ) - 1 ] = ' \\ ' ;
fn . Length + = sizeof ( WCHAR ) ;
}
RtlCopyMemory ( & fn . Buffer [ pathlen / sizeof ( WCHAR ) ] , hl - > name . Buffer , hl - > name . Length ) ;
fn . Length + = hl - > name . Length ;
FsRtlNotifyFilterReportChange ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ( PSTRING ) & fn , ( USHORT ) pathlen ,
( PSTRING ) stream , NULL , filter_match , action , NULL , NULL ) ;
ExFreePool ( fn . Buffer ) ;
2019-05-11 09:20:02 +00:00
free_fileref ( parfr ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
2019-11-12 18:32:46 +00:00
typedef struct {
file_ref * fileref ;
ULONG filter_match ;
ULONG action ;
PUNICODE_STRING stream ;
PIO_WORKITEM work_item ;
} notification_fcb ;
_Function_class_ ( IO_WORKITEM_ROUTINE )
static void __stdcall notification_work_item ( PDEVICE_OBJECT DeviceObject , PVOID con ) {
notification_fcb * nf = con ;
UNUSED ( DeviceObject ) ;
ExAcquireResourceSharedLite ( & nf - > fileref - > fcb - > Vcb - > tree_lock , TRUE ) ; // protect us from fileref being reaped
send_notification_fcb ( nf - > fileref , nf - > filter_match , nf - > action , nf - > stream ) ;
free_fileref ( nf - > fileref ) ;
ExReleaseResourceLite ( & nf - > fileref - > fcb - > Vcb - > tree_lock ) ;
IoFreeWorkItem ( nf - > work_item ) ;
ExFreePool ( nf ) ;
}
void queue_notification_fcb ( _In_ file_ref * fileref , _In_ ULONG filter_match , _In_ ULONG action , _In_opt_ PUNICODE_STRING stream ) {
notification_fcb * nf ;
PIO_WORKITEM work_item ;
nf = ExAllocatePoolWithTag ( PagedPool , sizeof ( notification_fcb ) , ALLOC_TAG ) ;
if ( ! nf ) {
ERR ( " out of memory \n " ) ;
return ;
}
work_item = IoAllocateWorkItem ( master_devobj ) ;
if ( ! work_item ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( nf ) ;
return ;
}
InterlockedIncrement ( & fileref - > refcount ) ;
nf - > fileref = fileref ;
nf - > filter_match = filter_match ;
nf - > action = action ;
nf - > stream = stream ;
nf - > work_item = work_item ;
IoQueueWorkItem ( work_item , notification_work_item , DelayedWorkQueue , nf ) ;
}
2017-09-08 08:02:43 +00:00
void mark_fcb_dirty ( _In_ fcb * fcb ) {
2016-07-27 19:24:26 +00:00
if ( ! fcb - > dirty ) {
# ifdef DEBUG_FCB_REFCOUNTS
LONG rc ;
# endif
2019-09-01 12:53:20 +00:00
fcb - > dirty = true ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement ( & fcb - > refcount ) ;
WARN ( " fcb %p: refcount now %i \n " , fcb , rc ) ;
# else
InterlockedIncrement ( & fcb - > refcount ) ;
# endif
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > dirty_fcbs_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & fcb - > Vcb - > dirty_fcbs , & fcb - > list_entry_dirty ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > dirty_fcbs_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb - > Vcb - > need_write = true ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
void mark_fileref_dirty ( _In_ file_ref * fileref ) {
2016-07-27 19:24:26 +00:00
if ( ! fileref - > dirty ) {
2019-09-01 12:53:20 +00:00
fileref - > dirty = true ;
2016-07-27 19:24:26 +00:00
increase_fileref_refcount ( fileref ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fileref - > fcb - > Vcb - > dirty_filerefs_lock , true ) ;
2017-09-08 08:02:43 +00:00
InsertTailList ( & fileref - > fcb - > Vcb - > dirty_filerefs , & fileref - > list_entry_dirty ) ;
ExReleaseResourceLite ( & fileref - > fcb - > Vcb - > dirty_filerefs_lock ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fileref - > fcb - > Vcb - > need_write = true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2019-05-11 09:20:02 +00:00
void _free_fcb ( _Inout_ fcb * fcb , _In_ const char * func ) {
LONG rc = InterlockedDecrement ( & fcb - > refcount ) ;
2017-09-08 08:02:43 +00:00
# else
2019-05-11 09:20:02 +00:00
void free_fcb ( _Inout_ fcb * fcb ) {
InterlockedDecrement ( & fcb - > refcount ) ;
2017-09-08 08:02:43 +00:00
# endif
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2019-09-01 12:53:20 +00:00
ERR ( " fcb %p (%s): refcount now %i (subvol %I64x, inode %I64x) \n " , fcb , func , rc , fcb - > subvol ? fcb - > subvol - > id : 0 , fcb - > inode ) ;
2016-03-23 20:35:05 +00:00
# endif
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
void reap_fcb ( fcb * fcb ) {
2019-09-01 12:53:20 +00:00
uint8_t c = fcb - > hash > > 24 ;
2019-05-11 09:20:02 +00:00
if ( fcb - > subvol & & fcb - > subvol - > fcbs_ptrs [ c ] = = & fcb - > list_entry ) {
if ( fcb - > list_entry . Flink ! = & fcb - > subvol - > fcbs & & ( CONTAINING_RECORD ( fcb - > list_entry . Flink , struct _fcb , list_entry ) - > hash > > 24 ) = = c )
fcb - > subvol - > fcbs_ptrs [ c ] = fcb - > list_entry . Flink ;
else
fcb - > subvol - > fcbs_ptrs [ c ] = NULL ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( fcb - > list_entry . Flink ) {
2016-07-27 19:24:26 +00:00
RemoveEntryList ( & fcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( fcb - > subvol & & fcb - > subvol - > dropped & & IsListEmpty ( & fcb - > subvol - > fcbs ) ) {
ExDeleteResourceLite ( & fcb - > subvol - > nonpaged - > load_tree_lock ) ;
ExFreePool ( fcb - > subvol - > nonpaged ) ;
ExFreePool ( fcb - > subvol ) ;
}
}
2016-07-27 19:24:26 +00:00
if ( fcb - > list_entry_all . Flink )
RemoveEntryList ( & fcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & fcb - > nonpaged - > resource ) ;
ExDeleteResourceLite ( & fcb - > nonpaged - > paging_resource ) ;
2017-01-01 17:12:12 +00:00
ExDeleteResourceLite ( & fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExFreeToNPagedLookasideList ( & fcb - > Vcb - > fcb_np_lookaside , fcb - > nonpaged ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > sd )
ExFreePool ( fcb - > sd ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( fcb - > adsxattr . Buffer )
ExFreePool ( fcb - > adsxattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > reparse_xattr . Buffer )
ExFreePool ( fcb - > reparse_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( fcb - > ea_xattr . Buffer )
ExFreePool ( fcb - > ea_xattr . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fcb - > adsdata . Buffer )
ExFreePool ( fcb - > adsdata . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & fcb - > extents ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > extents ) ;
extent * ext = CONTAINING_RECORD ( le , extent , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ext - > csum )
ExFreePool ( ext - > csum ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( ext ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & fcb - > hardlinks ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > hardlinks ) ;
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
ExFreePool ( hl ) ;
}
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & fcb - > xattrs ) ) {
xattr * xa = CONTAINING_RECORD ( RemoveHeadList ( & fcb - > xattrs ) , xattr , list_entry ) ;
ExFreePool ( xa ) ;
}
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & fcb - > dir_children_index ) ) {
LIST_ENTRY * le = RemoveHeadList ( & fcb - > dir_children_index ) ;
dir_child * dc = CONTAINING_RECORD ( le , dir_child , list_entry_index ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( dc - > utf8 . Buffer ) ;
ExFreePool ( dc - > name . Buffer ) ;
ExFreePool ( dc - > name_uc . Buffer ) ;
ExFreePool ( dc ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs )
ExFreePool ( fcb - > hash_ptrs ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fcb - > hash_ptrs_uc )
ExFreePool ( fcb - > hash_ptrs_uc ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlUninitializeFileLock ( & fcb - > lock ) ;
2019-11-12 18:32:46 +00:00
FsRtlUninitializeOplock ( fcb_oplock ( fcb ) ) ;
2017-09-08 08:02:43 +00:00
if ( fcb - > pool_type = = NonPagedPool )
ExFreePool ( fcb ) ;
else
2019-05-11 09:20:02 +00:00
ExFreeToPagedLookasideList ( & fcb - > Vcb - > fcb_lookaside , fcb ) ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
void reap_fcbs ( device_extension * Vcb ) {
LIST_ENTRY * le ;
le = Vcb - > all_fcbs . Flink ;
while ( le ! = & Vcb - > all_fcbs ) {
fcb * fcb = CONTAINING_RECORD ( le , struct _fcb , list_entry_all ) ;
LIST_ENTRY * le2 = le - > Flink ;
if ( fcb - > refcount = = 0 )
reap_fcb ( fcb ) ;
le = le2 ;
}
2016-05-05 17:26:47 +00:00
}
2019-05-11 09:20:02 +00:00
void free_fileref ( _Inout_ file_ref * fr ) {
2022-04-28 19:33:48 +00:00
# if defined(_DEBUG) || defined(DEBUG_FCB_REFCOUNTS)
LONG rc = InterlockedDecrement ( & fr - > refcount ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
2017-09-08 08:02:43 +00:00
ERR ( " fileref %p: refcount now %i \n " , fr , rc ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
# ifdef _DEBUG
if ( rc < 0 ) {
2020-04-23 02:38:57 +00:00
ERR ( " fileref %p: refcount now %li \n " , fr , rc ) ;
2016-05-05 17:26:47 +00:00
int3 ;
}
# endif
2022-04-28 19:33:48 +00:00
# else
InterlockedDecrement ( & fr - > refcount ) ;
# endif
2019-05-11 09:20:02 +00:00
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
void reap_fileref ( device_extension * Vcb , file_ref * fr ) {
2016-05-05 17:26:47 +00:00
// FIXME - do we need a file_ref lock?
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - do delete if needed
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - throw error if children not empty
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fr - > fcb - > fileref = = fr )
fr - > fcb - > fileref = NULL ;
2017-09-08 08:02:43 +00:00
if ( fr - > dc ) {
if ( fr - > fcb - > ads )
fr - > dc - > size = fr - > fcb - > adsdata . Length ;
2017-01-01 17:12:12 +00:00
fr - > dc - > fileref = NULL ;
2017-09-08 08:02:43 +00:00
}
2017-01-01 17:12:12 +00:00
2016-05-05 17:26:47 +00:00
if ( fr - > list_entry . Flink )
RemoveEntryList ( & fr - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( fr - > parent )
free_fileref ( fr - > parent ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
free_fcb ( fr - > fcb ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( fr - > oldutf8 . Buffer )
ExFreePool ( fr - > oldutf8 . Buffer ) ;
2017-09-08 08:02:43 +00:00
ExFreeToPagedLookasideList ( & Vcb - > fileref_lookaside , fr ) ;
2016-03-23 20:35:05 +00:00
}
2019-05-11 09:20:02 +00:00
void reap_filerefs ( device_extension * Vcb , file_ref * fr ) {
LIST_ENTRY * le ;
// FIXME - recursion is a bad idea in kernel mode
le = fr - > children . Flink ;
while ( le ! = & fr - > children ) {
file_ref * c = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
LIST_ENTRY * le2 = le - > Flink ;
reap_filerefs ( Vcb , c ) ;
le = le2 ;
}
if ( fr - > refcount = = 0 )
reap_fileref ( Vcb , fr ) ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS close_file ( _In_ PFILE_OBJECT FileObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
fcb * fcb ;
ccb * ccb ;
2016-05-05 17:26:47 +00:00
file_ref * fileref = NULL ;
2016-10-29 17:05:10 +00:00
LONG open_files ;
2017-09-08 08:02:43 +00:00
UNUSED ( Irp ) ;
2016-03-23 20:35:05 +00:00
TRACE ( " FileObject = %p \n " , FileObject ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fcb = FileObject - > FsContext ;
if ( ! fcb ) {
TRACE ( " FCB was NULL, returning success \n " ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
open_files = InterlockedDecrement ( & fcb - > Vcb - > open_files ) ;
2016-03-23 20:35:05 +00:00
ccb = FileObject - > FsContext2 ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
TRACE ( " close called for fcb %p) \n " , fcb ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - make sure notification gets sent if file is being deleted
2017-09-08 08:02:43 +00:00
if ( ccb ) {
2016-03-23 20:35:05 +00:00
if ( ccb - > query_string . Buffer )
RtlFreeUnicodeString ( & ccb - > query_string ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ccb - > filename . Buffer )
ExFreePool ( ccb - > filename . Buffer ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// FIXME - use refcounts for fileref
fileref = ccb - > fileref ;
2017-09-08 08:02:43 +00:00
if ( fcb - > Vcb - > running_sends > 0 ) {
2019-09-01 12:53:20 +00:00
bool send_cancelled = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > send_load_lock , true ) ;
2017-09-08 08:02:43 +00:00
if ( ccb - > send ) {
2019-09-01 12:53:20 +00:00
ccb - > send - > cancelling = true ;
send_cancelled = true ;
KeSetEvent ( & ccb - > send - > cleared_event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
}
ExReleaseResourceLite ( & fcb - > Vcb - > send_load_lock ) ;
if ( send_cancelled ) {
while ( ccb - > send ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > send_load_lock , true ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > send_load_lock ) ;
}
}
}
ExFreePool ( ccb ) ;
}
CcUninitializeCacheMap ( FileObject , NULL , NULL ) ;
if ( open_files = = 0 & & fcb - > Vcb - > removing ) {
2018-12-16 11:03:16 +00:00
uninit ( fcb - > Vcb ) ;
2016-10-29 17:05:10 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( ! ( fcb - > Vcb - > Vpb - > Flags & VPB_MOUNTED ) )
2016-09-04 15:27:46 +00:00
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( fileref )
2019-05-11 09:20:02 +00:00
free_fileref ( fileref ) ;
2016-05-05 17:26:47 +00:00
else
2019-05-11 09:20:02 +00:00
free_fcb ( fcb ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2018-12-16 11:03:16 +00:00
void uninit ( _In_ device_extension * Vcb ) {
2019-09-01 12:53:20 +00:00
uint64_t i ;
2018-12-16 11:03:16 +00:00
KIRQL irql ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
LIST_ENTRY * le ;
LARGE_INTEGER time ;
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > removing ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
Vcb - > removing = true ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
}
2019-11-12 18:32:46 +00:00
if ( Vcb - > vde & & Vcb - > vde - > mounted_device = = Vcb - > devobj )
Vcb - > vde - > mounted_device = NULL ;
2018-12-16 11:03:16 +00:00
IoAcquireVpbSpinLock ( & irql ) ;
Vcb - > Vpb - > Flags & = ~ VPB_MOUNTED ;
Vcb - > Vpb - > Flags | = VPB_DIRECT_WRITES_ALLOWED ;
2019-11-12 18:32:46 +00:00
Vcb - > Vpb - > DeviceObject = NULL ;
2018-12-16 11:03:16 +00:00
IoReleaseVpbSpinLock ( irql ) ;
2020-04-23 02:38:57 +00:00
// FIXME - needs global_loading_lock to be held
if ( Vcb - > list_entry . Flink )
RemoveEntryList ( & Vcb - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > balance . thread ) {
2019-09-01 12:53:20 +00:00
Vcb - > balance . paused = false ;
Vcb - > balance . stopping = true ;
KeSetEvent ( & Vcb - > balance . event , 0 , false ) ;
KeWaitForSingleObject ( & Vcb - > balance . finished , Executive , KernelMode , false , NULL ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
if ( Vcb - > scrub . thread ) {
2019-09-01 12:53:20 +00:00
Vcb - > scrub . paused = false ;
Vcb - > scrub . stopping = true ;
KeSetEvent ( & Vcb - > scrub . event , 0 , false ) ;
KeWaitForSingleObject ( & Vcb - > scrub . finished , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
}
if ( Vcb - > running_sends ! = 0 ) {
2019-09-01 12:53:20 +00:00
bool send_cancelled = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > send_load_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = Vcb - > send_ops . Flink ;
while ( le ! = & Vcb - > send_ops ) {
send_info * send = CONTAINING_RECORD ( le , send_info , list_entry ) ;
if ( ! send - > cancelling ) {
2019-09-01 12:53:20 +00:00
send - > cancelling = true ;
send_cancelled = true ;
2017-09-08 08:02:43 +00:00
send - > ccb = NULL ;
2019-09-01 12:53:20 +00:00
KeSetEvent ( & send - > cleared_event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & Vcb - > send_load_lock ) ;
if ( send_cancelled ) {
while ( Vcb - > running_sends ! = 0 ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > send_load_lock , true ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > send_load_lock ) ;
}
}
}
2016-07-27 19:24:26 +00:00
Status = registry_mark_volume_unmounted ( & Vcb - > superblock . uuid ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_TOO_LATE )
2020-04-23 02:38:57 +00:00
WARN ( " registry_mark_volume_unmounted returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
2019-09-01 12:53:20 +00:00
Vcb - > calcthreads . threads [ i ] . quit = true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeSetEvent ( & Vcb - > calcthreads . event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & Vcb - > calcthreads . threads [ i ] . finished , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ZwClose ( Vcb - > calcthreads . threads [ i ] . handle ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( Vcb - > calcthreads . threads ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
time . QuadPart = 0 ;
KeSetTimer ( & Vcb - > flush_thread_timer , time , NULL ) ; // trigger the timer early
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & Vcb - > flush_thread_finished , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
reap_fcb ( Vcb - > volume_fcb ) ;
reap_fcb ( Vcb - > dummy_fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > root_file )
ObDereferenceObject ( Vcb - > root_file ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = Vcb - > chunks . Flink ;
while ( le ! = & Vcb - > chunks ) {
chunk * c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( c - > cache ) {
2019-05-11 09:20:02 +00:00
reap_fcb ( c - > cache ) ;
2016-07-27 19:24:26 +00:00
c - > cache = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2016-03-23 20:35:05 +00:00
2019-11-12 18:32:46 +00:00
while ( ! IsListEmpty ( & Vcb - > all_fcbs ) ) {
fcb * fcb = CONTAINING_RECORD ( Vcb - > all_fcbs . Flink , struct _fcb , list_entry_all ) ;
reap_fcb ( fcb ) ;
}
while ( ! IsListEmpty ( & Vcb - > sys_chunks ) ) {
sys_chunk * sc = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > sys_chunks ) , sys_chunk , list_entry ) ;
if ( sc - > data )
ExFreePool ( sc - > data ) ;
ExFreePool ( sc ) ;
}
2016-05-05 17:26:47 +00:00
while ( ! IsListEmpty ( & Vcb - > roots ) ) {
2017-09-08 08:02:43 +00:00
root * r = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > roots ) , root , list_entry ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
ExDeleteResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
ExFreePool ( r - > nonpaged ) ;
ExFreePool ( r ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & Vcb - > chunks ) ) {
2017-09-08 08:02:43 +00:00
chunk * c = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > chunks ) , chunk , list_entry ) ;
2016-03-23 20:35:05 +00:00
while ( ! IsListEmpty ( & c - > space ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & c - > space ) ;
2017-09-08 08:02:43 +00:00
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2016-03-23 20:35:05 +00:00
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
while ( ! IsListEmpty ( & c - > deleting ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & c - > deleting ) ;
2017-09-08 08:02:43 +00:00
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( s ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( c - > devices )
ExFreePool ( c - > devices ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
if ( c - > cache )
reap_fcb ( c - > cache ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & c - > range_locks_lock ) ;
ExDeleteResourceLite ( & c - > partial_stripes_lock ) ;
2016-09-04 15:27:46 +00:00
ExDeleteResourceLite ( & c - > lock ) ;
ExDeleteResourceLite ( & c - > changed_extents_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & Vcb - > devices ) ) {
2017-09-08 08:02:43 +00:00
device * dev = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > devices ) , device , list_entry ) ;
2017-01-01 17:12:12 +00:00
while ( ! IsListEmpty ( & dev - > space ) ) {
LIST_ENTRY * le2 = RemoveHeadList ( & dev - > space ) ;
space * s = CONTAINING_RECORD ( le2 , space , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
ExFreePool ( s ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
ExFreePool ( dev ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > scrub . stats_lock , true ) ;
2017-09-08 08:02:43 +00:00
while ( ! IsListEmpty ( & Vcb - > scrub . errors ) ) {
scrub_error * err = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > scrub . errors ) , scrub_error , list_entry ) ;
ExFreePool ( err ) ;
}
ExReleaseResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & Vcb - > fcb_lock ) ;
2019-05-11 09:20:02 +00:00
ExDeleteResourceLite ( & Vcb - > fileref_lock ) ;
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & Vcb - > load_lock ) ;
ExDeleteResourceLite ( & Vcb - > tree_lock ) ;
2016-07-27 19:24:26 +00:00
ExDeleteResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExDeleteResourceLite ( & Vcb - > scrub . stats_lock ) ;
ExDeleteResourceLite ( & Vcb - > send_load_lock ) ;
2016-10-29 17:05:10 +00:00
ExDeletePagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > traverse_ptr_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeletePagedLookasideList ( & Vcb - > fileref_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > fcb_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
2016-10-29 17:05:10 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > fcb_np_lookaside ) ;
2016-03-23 20:35:05 +00:00
ZwClose ( Vcb - > flush_thread_handle ) ;
2019-11-12 18:32:46 +00:00
if ( Vcb - > devobj - > AttachedDevice )
IoDetachDevice ( Vcb - > devobj ) ;
IoDeleteDevice ( Vcb - > devobj ) ;
2016-03-23 20:35:05 +00:00
}
2019-06-11 10:35:19 +00:00
static NTSTATUS delete_fileref_fcb ( _In_ file_ref * fileref , _In_opt_ PFILE_OBJECT FileObject , _In_opt_ PIRP Irp , _In_ LIST_ENTRY * rollback ) {
NTSTATUS Status ;
LIST_ENTRY * le ;
// excise extents
if ( fileref - > fcb - > type ! = BTRFS_TYPE_DIRECTORY & & fileref - > fcb - > inode_item . st_size > 0 ) {
Status = excise_extents ( fileref - > fcb - > Vcb , fileref - > fcb , 0 , sector_align ( fileref - > fcb - > inode_item . st_size , fileref - > fcb - > Vcb - > superblock . sector_size ) , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " excise_extents returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
return Status ;
}
}
fileref - > fcb - > Header . AllocationSize . QuadPart = 0 ;
fileref - > fcb - > Header . FileSize . QuadPart = 0 ;
fileref - > fcb - > Header . ValidDataLength . QuadPart = 0 ;
if ( FileObject ) {
CC_FILE_SIZES ccfs ;
ccfs . AllocationSize = fileref - > fcb - > Header . AllocationSize ;
ccfs . FileSize = fileref - > fcb - > Header . FileSize ;
ccfs . ValidDataLength = fileref - > fcb - > Header . ValidDataLength ;
Status = STATUS_SUCCESS ;
_SEH2_TRY {
CcSetFileSizes ( FileObject , & ccfs ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " CcSetFileSizes threw exception %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
return Status ;
}
}
2019-09-01 12:53:20 +00:00
fileref - > fcb - > deleted = true ;
2019-06-11 10:35:19 +00:00
le = fileref - > children . Flink ;
while ( le ! = & fileref - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
if ( fr2 - > fcb - > ads ) {
2019-09-01 12:53:20 +00:00
fr2 - > fcb - > deleted = true ;
2019-06-11 10:35:19 +00:00
mark_fcb_dirty ( fr2 - > fcb ) ;
}
le = le - > Flink ;
}
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS delete_fileref ( _In_ file_ref * fileref , _In_opt_ PFILE_OBJECT FileObject , _In_ bool make_orphan , _In_opt_ PIRP Irp , _In_ LIST_ENTRY * rollback ) {
2016-07-27 19:24:26 +00:00
LARGE_INTEGER newlength , time ;
BTRFS_TIME now ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
ULONG utf8len = 0 ;
2016-07-27 19:24:26 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fileref - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( fileref - > deleted ) {
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
if ( fileref - > fcb - > subvol - > send_ops > 0 ) {
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return STATUS_ACCESS_DENIED ;
}
2019-09-01 12:53:20 +00:00
fileref - > deleted = true ;
2016-07-27 19:24:26 +00:00
mark_fileref_dirty ( fileref ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// delete INODE_ITEM (0x1)
TRACE ( " nlink = %u \n " , fileref - > fcb - > inode_item . st_nlink ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! fileref - > fcb - > ads ) {
if ( fileref - > parent - > fcb - > subvol = = fileref - > fcb - > subvol ) {
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > fcb ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fileref - > fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
if ( fileref - > fcb - > inode_item . st_nlink > 1 | | make_orphan ) {
2016-07-27 19:24:26 +00:00
fileref - > fcb - > inode_item . st_nlink - - ;
fileref - > fcb - > inode_item . transid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > fcb - > inode_item . sequence + + ;
fileref - > fcb - > inode_item . st_ctime = now ;
} else {
2019-06-11 10:35:19 +00:00
Status = delete_fileref_fcb ( fileref , FileObject , Irp , rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " delete_fileref_fcb returned %08lx \n " , Status ) ;
2019-06-11 10:35:19 +00:00
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
return Status ;
2017-10-16 18:05:33 +00:00
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( fileref - > dc ) {
le = fileref - > fcb - > hardlinks . Flink ;
while ( le ! = & fileref - > fcb - > hardlinks ) {
hardlink * hl = CONTAINING_RECORD ( le , hardlink , list_entry ) ;
if ( hl - > parent = = fileref - > parent - > fcb - > inode & & hl - > index = = fileref - > dc - > index ) {
RemoveEntryList ( & hl - > list_entry ) ;
if ( hl - > name . Buffer )
ExFreePool ( hl - > name . Buffer ) ;
if ( hl - > utf8 . Buffer )
ExFreePool ( hl - > utf8 . Buffer ) ;
ExFreePool ( hl ) ;
break ;
}
le = le - > Flink ;
2016-07-27 19:24:26 +00:00
}
}
2017-09-08 08:02:43 +00:00
} else if ( fileref - > fcb - > subvol - > parent = = fileref - > parent - > fcb - > subvol - > id ) { // valid subvolume
2016-07-27 19:24:26 +00:00
if ( fileref - > fcb - > subvol - > root_item . num_references > 1 ) {
fileref - > fcb - > subvol - > root_item . num_references - - ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > fcb ) ; // so ROOT_ITEM gets updated
} else {
2017-10-16 18:05:33 +00:00
LIST_ENTRY * le ;
2016-07-27 19:24:26 +00:00
// FIXME - we need a lock here
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RemoveEntryList ( & fileref - > fcb - > subvol - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InsertTailList ( & fileref - > fcb - > Vcb - > drop_roots , & fileref - > fcb - > subvol - > list_entry ) ;
2017-10-16 18:05:33 +00:00
le = fileref - > children . Flink ;
while ( le ! = & fileref - > children ) {
file_ref * fr2 = CONTAINING_RECORD ( le , file_ref , list_entry ) ;
if ( fr2 - > fcb - > ads ) {
2019-09-01 12:53:20 +00:00
fr2 - > fcb - > deleted = true ;
2017-10-16 18:05:33 +00:00
mark_fcb_dirty ( fr2 - > fcb ) ;
}
le = le - > Flink ;
}
2016-07-27 19:24:26 +00:00
}
}
} else {
2019-09-01 12:53:20 +00:00
fileref - > fcb - > deleted = true ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > fcb ) ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
// remove dir_child from parent
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( fileref - > dc ) {
2020-04-23 02:38:57 +00:00
TRACE ( " delete file %.*S \n " , ( int ) ( fileref - > dc - > name . Length / sizeof ( WCHAR ) ) , fileref - > dc - > name . Buffer ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock , true ) ;
2017-01-01 17:12:12 +00:00
RemoveEntryList ( & fileref - > dc - > list_entry_index ) ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > fcb - > ads )
remove_dir_child_from_hash_lists ( fileref - > parent - > fcb , fileref - > dc ) ;
2017-01-01 17:12:12 +00:00
ExReleaseResourceLite ( & fileref - > parent - > fcb - > nonpaged - > dir_children_lock ) ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > oldutf8 . Buffer )
fileref - > oldutf8 = fileref - > dc - > utf8 ;
else
ExFreePool ( fileref - > dc - > utf8 . Buffer ) ;
utf8len = fileref - > dc - > utf8 . Length ;
fileref - > oldindex = fileref - > dc - > index ;
2017-01-01 17:12:12 +00:00
ExFreePool ( fileref - > dc - > name . Buffer ) ;
ExFreePool ( fileref - > dc - > name_uc . Buffer ) ;
ExFreePool ( fileref - > dc ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
fileref - > dc = NULL ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// update INODE_ITEM of parent
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fileref - > parent - > fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > parent - > fcb - > inode_item . transid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > parent - > fcb - > inode_item . sequence + + ;
fileref - > parent - > fcb - > inode_item . st_ctime = now ;
2017-09-08 08:02:43 +00:00
if ( ! fileref - > fcb - > ads ) {
2019-09-01 12:53:20 +00:00
TRACE ( " fileref->parent->fcb->inode_item.st_size (inode %I64x) was %I64x \n " , fileref - > parent - > fcb - > inode , fileref - > parent - > fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
fileref - > parent - > fcb - > inode_item . st_size - = utf8len * 2 ;
2019-09-01 12:53:20 +00:00
TRACE ( " fileref->parent->fcb->inode_item.st_size (inode %I64x) now %I64x \n " , fileref - > parent - > fcb - > inode , fileref - > parent - > fcb - > inode_item . st_size ) ;
2017-09-08 08:02:43 +00:00
fileref - > parent - > fcb - > inode_item . st_mtime = now ;
}
2016-07-27 19:24:26 +00:00
2019-09-01 12:53:20 +00:00
fileref - > parent - > fcb - > inode_item_changed = true ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( fileref - > parent - > fcb - > Header . Resource ) ;
if ( ! fileref - > fcb - > ads & & fileref - > parent - > dc )
send_notification_fcb ( fileref - > parent , FILE_NOTIFY_CHANGE_LAST_WRITE , FILE_ACTION_MODIFIED , NULL ) ;
2016-07-27 19:24:26 +00:00
mark_fcb_dirty ( fileref - > parent - > fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
fileref - > fcb - > subvol - > root_item . ctransid = fileref - > fcb - > Vcb - > superblock . generation ;
fileref - > fcb - > subvol - > root_item . ctime = now ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
newlength . QuadPart = 0 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( FileObject & & ! CcUninitializeCacheMap ( FileObject , & newlength , NULL ) )
TRACE ( " CcUninitializeCacheMap failed \n " ) ;
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_CLEANUP )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_cleanup ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
PFILE_OBJECT FileObject = IrpSp - > FileObject ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2017-09-08 08:02:43 +00:00
fcb * fcb = FileObject - > FsContext ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " cleanup \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Irp - > IoStatus . Information = 0 ;
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
goto exit ;
} else if ( DeviceObject = = master_devobj ) {
2016-03-23 20:35:05 +00:00
TRACE ( " closing file system \n " ) ;
Status = STATUS_SUCCESS ;
goto exit ;
2017-09-08 08:02:43 +00:00
} else if ( ! Vcb | | Vcb - > type ! = VCB_TYPE_FS ) {
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
if ( FileObject - > Flags & FO_CLEANUP_COMPLETE ) {
TRACE ( " FileObject %p already cleaned up \n " , FileObject ) ;
Status = STATUS_SUCCESS ;
goto exit ;
}
if ( ! fcb ) {
ERR ( " fcb was NULL \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
FsRtlCheckOplock ( fcb_oplock ( fcb ) , Irp , NULL , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
// We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
// messages belonging to other devices.
2016-05-05 17:26:47 +00:00
if ( FileObject & & FileObject - > FsContext ) {
ccb * ccb ;
file_ref * fileref ;
2019-09-01 12:53:20 +00:00
bool locked = true ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
ccb = FileObject - > FsContext2 ;
fileref = ccb ? ccb - > fileref : NULL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " cleanup called for FileObject %p \n " , FileObject ) ;
2020-04-23 02:38:57 +00:00
TRACE ( " fileref %p, refcount = %li, open_count = %li \n " , fileref , fileref ? fileref - > refcount : 0 , fileref ? fileref - > open_count : 0 ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & fcb - > Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( fcb - > Header . Resource , true ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoRemoveShareAccess ( FileObject , & fcb - > share_access ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
FsRtlFastUnlockAll ( & fcb - > lock , FileObject , IoGetRequestorProcess ( Irp ) , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ccb )
FsRtlNotifyCleanup ( fcb - > Vcb - > NotifySync , & fcb - > Vcb - > DirNotifyList , ccb ) ;
2016-05-05 17:26:47 +00:00
if ( ccb & & ccb - > options & FILE_DELETE_ON_CLOSE & & fileref )
2019-09-01 12:53:20 +00:00
fileref - > delete_on_close = true ;
2017-09-08 08:02:43 +00:00
if ( fileref & & fileref - > delete_on_close & & fcb - > type = = BTRFS_TYPE_DIRECTORY & & fcb - > inode_item . st_size > 0 & & fcb ! = fcb - > Vcb - > dummy_fcb )
2019-09-01 12:53:20 +00:00
fileref - > delete_on_close = false ;
2017-09-08 08:02:43 +00:00
if ( fcb - > Vcb - > locked & & fcb - > Vcb - > locked_fileobj = = FileObject ) {
2016-07-27 19:24:26 +00:00
TRACE ( " unlocking volume \n " ) ;
2017-09-08 08:02:43 +00:00
do_unlock_volume ( fcb - > Vcb ) ;
2016-07-27 19:24:26 +00:00
FsRtlNotifyVolumeEvent ( FileObject , FSRTL_VOLUME_UNLOCK ) ;
}
2017-09-08 08:02:43 +00:00
if ( ccb & & ccb - > reserving ) {
fcb - > subvol - > reserved = NULL ;
2019-09-01 12:53:20 +00:00
ccb - > reserving = false ;
2017-09-08 08:02:43 +00:00
// FIXME - flush all of subvol's fcbs
}
2022-04-28 19:31:44 +00:00
if ( fileref ) {
LONG oc = InterlockedDecrement ( & fileref - > open_count ) ;
# ifdef DEBUG_FCB_REFCOUNTS
ERR ( " fileref %p: open_count now %i \n " , fileref , oc ) ;
# endif
2019-06-11 10:35:19 +00:00
2022-04-28 19:31:44 +00:00
if ( oc = = 0 | | ( fileref - > delete_on_close & & fileref - > posix_delete ) ) {
if ( ! fcb - > Vcb - > removing ) {
if ( oc = = 0 & & fileref - > fcb - > inode_item . st_nlink = = 0 & & fileref ! = fcb - > Vcb - > root_fileref & &
fcb ! = fcb - > Vcb - > volume_fcb & & ! fcb - > ads ) { // last handle closed on POSIX-deleted file
LIST_ENTRY rollback ;
InitializeListHead ( & rollback ) ;
Status = delete_fileref_fcb ( fileref , FileObject , Irp , & rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref_fcb returned %08lx \n " , Status ) ;
do_rollback ( fcb - > Vcb , & rollback ) ;
ExReleaseResourceLite ( fileref - > fcb - > Header . Resource ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
goto exit ;
}
2019-06-11 10:35:19 +00:00
2022-04-28 19:31:44 +00:00
clear_rollback ( & rollback ) ;
2019-06-11 10:35:19 +00:00
2022-04-28 19:31:44 +00:00
mark_fcb_dirty ( fileref - > fcb ) ;
} else if ( fileref - > delete_on_close & & fileref ! = fcb - > Vcb - > root_fileref & & fcb ! = fcb - > Vcb - > volume_fcb ) {
LIST_ENTRY rollback ;
2019-06-11 10:35:19 +00:00
2022-04-28 19:31:44 +00:00
InitializeListHead ( & rollback ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ! fileref - > fcb - > ads | | fileref - > dc ) {
if ( fileref - > fcb - > ads ) {
send_notification_fileref ( fileref - > parent , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME ,
FILE_ACTION_REMOVED , & fileref - > dc - > name ) ;
} else
send_notification_fileref ( fileref , fcb - > type = = BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME , FILE_ACTION_REMOVED , NULL ) ;
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
locked = false ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
// fileref_lock needs to be acquired before fcb->Header.Resource
ExAcquireResourceExclusiveLite ( & fcb - > Vcb - > fileref_lock , true ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
Status = delete_fileref ( fileref , FileObject , oc > 0 & & fileref - > posix_delete , Irp , & rollback ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " delete_fileref returned %08lx \n " , Status ) ;
do_rollback ( fcb - > Vcb , & rollback ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
ExReleaseResourceLite ( & fcb - > Vcb - > fileref_lock ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
clear_rollback ( & rollback ) ;
} else if ( FileObject - > Flags & FO_CACHE_SUPPORTED & & FileObject - > SectionObjectPointer - > DataSectionObject ) {
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( locked ) {
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
locked = false ;
}
2016-03-23 20:35:05 +00:00
2022-04-28 19:31:44 +00:00
CcFlushCache ( FileObject - > SectionObjectPointer , NULL , 0 , & iosb ) ;
2020-04-23 02:38:57 +00:00
2022-04-28 19:31:44 +00:00
if ( ! NT_SUCCESS ( iosb . Status ) )
ERR ( " CcFlushCache returned %08lx \n " , iosb . Status ) ;
2020-04-23 02:38:57 +00:00
2022-04-28 19:31:44 +00:00
if ( ! ExIsResourceAcquiredSharedLite ( fcb - > Header . PagingIoResource ) ) {
ExAcquireResourceExclusiveLite ( fcb - > Header . PagingIoResource , true ) ;
ExReleaseResourceLite ( fcb - > Header . PagingIoResource ) ;
}
2016-03-23 20:35:05 +00:00
2022-04-28 19:31:44 +00:00
CcPurgeCacheSection ( FileObject - > SectionObjectPointer , NULL , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
TRACE ( " flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x) \n " ,
FileObject , fcb , fcb - > Header . AllocationSize . QuadPart , fcb - > Header . FileSize . QuadPart , fcb - > Header . ValidDataLength . QuadPart ) ;
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( fcb - > Vcb & & fcb ! = fcb - > Vcb - > volume_fcb )
CcUninitializeCacheMap ( FileObject , NULL , NULL ) ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
if ( locked )
ExReleaseResourceLite ( fcb - > Header . Resource ) ;
ExReleaseResourceLite ( & fcb - > Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
FileObject - > Flags | = FO_CLEANUP_COMPLETE ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
exit :
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
_Success_ ( return )
2019-09-01 12:53:20 +00:00
bool get_file_attributes_from_xattr ( _In_reads_bytes_ ( len ) char * val , _In_ uint16_t len , _Out_ ULONG * atts ) {
2017-01-01 17:12:12 +00:00
if ( len > 2 & & val [ 0 ] = = ' 0 ' & & val [ 1 ] = = ' x ' ) {
int i ;
ULONG dosnum = 0 ;
for ( i = 2 ; i < len ; i + + ) {
dosnum * = 0x10 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( val [ i ] > = ' 0 ' & & val [ i ] < = ' 9 ' )
dosnum | = val [ i ] - ' 0 ' ;
else if ( val [ i ] > = ' a ' & & val [ i ] < = ' f ' )
dosnum | = val [ i ] + 10 - ' a ' ;
else if ( val [ i ] > = ' A ' & & val [ i ] < = ' F ' )
dosnum | = val [ i ] + 10 - ' a ' ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
TRACE ( " DOSATTRIB: %08lx \n " , dosnum ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
* atts = dosnum ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return false ;
2017-01-01 17:12:12 +00:00
}
2019-09-01 12:53:20 +00:00
ULONG get_file_attributes ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ root * r , _In_ uint64_t inode ,
_In_ uint8_t type , _In_ bool dotfile , _In_ bool ignore_xa , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
ULONG att ;
char * eaval ;
2019-09-01 12:53:20 +00:00
uint16_t ealen ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ! ignore_xa & & get_xattr ( Vcb , r , inode , EA_DOSATTRIB , EA_DOSATTRIB_HASH , ( uint8_t * * ) & eaval , & ealen , Irp ) ) {
2017-01-01 17:12:12 +00:00
ULONG dosnum = 0 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( get_file_attributes_from_xattr ( eaval , ealen , & dosnum ) ) {
ExFreePool ( eaval ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( type = = BTRFS_TYPE_DIRECTORY )
dosnum | = FILE_ATTRIBUTE_DIRECTORY ;
else if ( type = = BTRFS_TYPE_SYMLINK )
dosnum | = FILE_ATTRIBUTE_REPARSE_POINT ;
2017-09-08 08:02:43 +00:00
if ( type ! = BTRFS_TYPE_DIRECTORY )
dosnum & = ~ FILE_ATTRIBUTE_DIRECTORY ;
2017-01-01 17:12:12 +00:00
if ( inode = = SUBVOL_ROOT_INODE ) {
if ( r - > root_item . flags & BTRFS_SUBVOL_READONLY )
dosnum | = FILE_ATTRIBUTE_READONLY ;
else
dosnum & = ~ FILE_ATTRIBUTE_READONLY ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return dosnum ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( eaval ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( type ) {
case BTRFS_TYPE_DIRECTORY :
att = FILE_ATTRIBUTE_DIRECTORY ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_TYPE_SYMLINK :
att = FILE_ATTRIBUTE_REPARSE_POINT ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
default :
att = 0 ;
break ;
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( dotfile | | ( r - > id = = BTRFS_ROOT_FSTREE & & inode = = SUBVOL_ROOT_INODE ) )
2016-03-23 20:35:05 +00:00
att | = FILE_ATTRIBUTE_HIDDEN ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
att | = FILE_ATTRIBUTE_ARCHIVE ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( inode = = SUBVOL_ROOT_INODE ) {
if ( r - > root_item . flags & BTRFS_SUBVOL_READONLY )
att | = FILE_ATTRIBUTE_READONLY ;
else
att & = ~ FILE_ATTRIBUTE_READONLY ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// FIXME - get READONLY from ii->st_mode
// FIXME - return SYSTEM for block/char devices?
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( att = = 0 )
att = FILE_ATTRIBUTE_NORMAL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return att ;
}
2019-09-01 12:53:20 +00:00
NTSTATUS sync_read_phys ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PFILE_OBJECT FileObject , _In_ uint64_t StartingOffset , _In_ ULONG Length ,
_Out_writes_bytes_ ( Length ) PUCHAR Buffer , _In_ bool override ) {
2017-09-08 08:02:43 +00:00
IO_STATUS_BLOCK IoStatus ;
2016-03-23 20:35:05 +00:00
LARGE_INTEGER Offset ;
PIRP Irp ;
PIO_STACK_LOCATION IrpSp ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
read_context context ;
2016-03-23 20:35:05 +00:00
num_reads + + ;
2017-09-08 08:02:43 +00:00
RtlZeroMemory ( & context , sizeof ( read_context ) ) ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & context . Event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
Offset . QuadPart = ( LONGLONG ) StartingOffset ;
2016-03-23 20:35:05 +00:00
2019-09-01 12:53:20 +00:00
Irp = IoAllocateIrp ( DeviceObject - > StackSize , false ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! Irp ) {
ERR ( " IoAllocateIrp failed \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Irp - > Flags | = IRP_NOCACHE ;
2016-03-23 20:35:05 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > MajorFunction = IRP_MJ_READ ;
2019-09-01 12:53:20 +00:00
IrpSp - > FileObject = FileObject ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( override )
IrpSp - > Flags | = SL_OVERRIDE_VERIFY_VOLUME ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( DeviceObject - > Flags & DO_BUFFERED_IO ) {
2017-09-08 08:02:43 +00:00
Irp - > AssociatedIrp . SystemBuffer = ExAllocatePoolWithTag ( NonPagedPool , Length , ALLOC_TAG ) ;
if ( ! Irp - > AssociatedIrp . SystemBuffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
Irp - > Flags | = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION ;
Irp - > UserBuffer = Buffer ;
2016-03-23 20:35:05 +00:00
} else if ( DeviceObject - > Flags & DO_DIRECT_IO ) {
2019-09-01 12:53:20 +00:00
Irp - > MdlAddress = IoAllocateMdl ( Buffer , Length , false , false , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Irp - > MdlAddress ) {
ERR ( " IoAllocateMdl failed \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
_SEH2_TRY {
MmProbeAndLockPages ( Irp - > MdlAddress , KernelMode , IoWriteAccess ) ;
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
} _SEH2_END ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " MmProbeAndLockPages threw exception %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
IoFreeMdl ( Irp - > MdlAddress ) ;
goto exit ;
}
} else
Irp - > UserBuffer = Buffer ;
IrpSp - > Parameters . Read . Length = Length ;
IrpSp - > Parameters . Read . ByteOffset = Offset ;
Irp - > UserIosb = & IoStatus ;
Irp - > UserEvent = & context . Event ;
2019-09-01 12:53:20 +00:00
IoSetCompletionRoutine ( Irp , read_completion , & context , true , true , true ) ;
2016-03-23 20:35:05 +00:00
Status = IoCallDriver ( DeviceObject , Irp ) ;
if ( Status = = STATUS_PENDING ) {
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & context . Event , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
Status = context . iosb . Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( DeviceObject - > Flags & DO_DIRECT_IO ) {
MmUnlockPages ( Irp - > MdlAddress ) ;
IoFreeMdl ( Irp - > MdlAddress ) ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
exit :
IoFreeIrp ( Irp ) ;
return Status ;
}
2020-04-23 02:38:57 +00:00
bool check_superblock_checksum ( superblock * sb ) {
switch ( sb - > csum_type ) {
case CSUM_TYPE_CRC32C : {
uint32_t crc32 = ~ calc_crc32c ( 0xffffffff , ( uint8_t * ) & sb - > uuid , ( ULONG ) sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
if ( crc32 = = * ( ( uint32_t * ) sb - > checksum ) )
return true ;
WARN ( " crc32 was %08x, expected %08x \n " , crc32 , * ( ( uint32_t * ) sb - > checksum ) ) ;
break ;
}
case CSUM_TYPE_XXHASH : {
uint64_t hash = XXH64 ( & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) , 0 ) ;
if ( hash = = * ( ( uint64_t * ) sb - > checksum ) )
return true ;
WARN ( " superblock hash was %I64x, expected %I64x \n " , hash , * ( ( uint64_t * ) sb - > checksum ) ) ;
break ;
}
case CSUM_TYPE_SHA256 : {
uint8_t hash [ SHA256_HASH_SIZE ] ;
calc_sha256 ( hash , & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
if ( RtlCompareMemory ( hash , sb , SHA256_HASH_SIZE ) = = SHA256_HASH_SIZE )
return true ;
WARN ( " superblock hash was invalid \n " ) ;
break ;
}
case CSUM_TYPE_BLAKE2 : {
uint8_t hash [ BLAKE2_HASH_SIZE ] ;
blake2b ( hash , sizeof ( hash ) , & sb - > uuid , sizeof ( superblock ) - sizeof ( sb - > checksum ) ) ;
if ( RtlCompareMemory ( hash , sb , BLAKE2_HASH_SIZE ) = = BLAKE2_HASH_SIZE )
return true ;
WARN ( " superblock hash was invalid \n " ) ;
break ;
}
default :
WARN ( " unrecognized csum type %x \n " , sb - > csum_type ) ;
}
return false ;
}
2019-09-01 12:53:20 +00:00
static NTSTATUS read_superblock ( _In_ device_extension * Vcb , _In_ PDEVICE_OBJECT device , _In_ PFILE_OBJECT fileobj , _In_ uint64_t length ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
superblock * sb ;
2017-09-08 08:02:43 +00:00
ULONG i , to_read ;
2019-09-01 12:53:20 +00:00
uint8_t valid_superblocks ;
2017-09-08 08:02:43 +00:00
to_read = device - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , device - > SectorSize ) ;
2016-03-23 20:35:05 +00:00
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
if ( superblock_addrs [ 0 ] + to_read > length ) {
WARN ( " device was too short to have any superblock \n " ) ;
ExFreePool ( sb ) ;
return STATUS_UNRECOGNIZED_VOLUME ;
}
2016-03-23 20:35:05 +00:00
i = 0 ;
2016-10-29 17:05:10 +00:00
valid_superblocks = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( superblock_addrs [ i ] > 0 ) {
2017-09-08 08:02:43 +00:00
if ( i > 0 & & superblock_addrs [ i ] + to_read > length )
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = sync_read_phys ( device , fileobj , superblock_addrs [ i ] , to_read , ( PUCHAR ) sb , false ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " Failed to read superblock %lu: %08lx \n " , i , Status ) ;
2016-03-23 20:35:05 +00:00
ExFreePool ( sb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( sb - > magic ! = BTRFS_MAGIC ) {
if ( i = = 0 ) {
TRACE ( " not a BTRFS volume \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
2017-01-01 17:12:12 +00:00
return STATUS_UNRECOGNIZED_VOLUME ;
}
} else {
2020-04-23 02:38:57 +00:00
TRACE ( " got superblock %lu! \n " , i ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( sb - > sector_size = = 0 )
2017-09-08 08:02:43 +00:00
WARN ( " superblock sector size was 0 \n " ) ;
2022-04-28 19:31:44 +00:00
else if ( sb - > sector_size & ( sb - > sector_size - 1 ) )
WARN ( " superblock sector size was not power of 2 \n " ) ;
2017-09-08 08:02:43 +00:00
else if ( sb - > node_size < sizeof ( tree_header ) + sizeof ( internal_node ) | | sb - > node_size > 0x10000 )
WARN ( " invalid node size %x \n " , sb - > node_size ) ;
else if ( ( sb - > node_size % sb - > sector_size ) ! = 0 )
WARN ( " node size %x was not a multiple of sector_size %x \n " , sb - > node_size , sb - > sector_size ) ;
2020-04-23 02:38:57 +00:00
else if ( check_superblock_checksum ( sb ) & & ( valid_superblocks = = 0 | | sb - > generation > Vcb - > superblock . generation ) ) {
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( & Vcb - > superblock , sb , sizeof ( superblock ) ) ;
valid_superblocks + + ;
}
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
i + + ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExFreePool ( sb ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( valid_superblocks = = 0 ) {
ERR ( " could not find any valid superblocks \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " label is %s \n " , Vcb - > superblock . label ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
NTSTATUS dev_ioctl ( _In_ PDEVICE_OBJECT DeviceObject , _In_ ULONG ControlCode , _In_reads_bytes_opt_ ( InputBufferSize ) PVOID InputBuffer , _In_ ULONG InputBufferSize ,
2019-09-01 12:53:20 +00:00
_Out_writes_bytes_opt_ ( OutputBufferSize ) PVOID OutputBuffer , _In_ ULONG OutputBufferSize , _In_ bool Override , _Out_opt_ IO_STATUS_BLOCK * iosb ) {
2016-03-23 20:35:05 +00:00
PIRP Irp ;
KEVENT Event ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-03-23 20:35:05 +00:00
IO_STATUS_BLOCK IoStatus ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & Event , NotificationEvent , false ) ;
2016-03-23 20:35:05 +00:00
Irp = IoBuildDeviceIoControlRequest ( ControlCode ,
DeviceObject ,
InputBuffer ,
InputBufferSize ,
OutputBuffer ,
OutputBufferSize ,
2019-09-01 12:53:20 +00:00
false ,
2016-03-23 20:35:05 +00:00
& Event ,
& IoStatus ) ;
if ( ! Irp ) return STATUS_INSUFFICIENT_RESOURCES ;
if ( Override ) {
2017-09-08 08:02:43 +00:00
IrpSp = IoGetNextIrpStackLocation ( Irp ) ;
IrpSp - > Flags | = SL_OVERRIDE_VERIFY_VOLUME ;
2016-03-23 20:35:05 +00:00
}
Status = IoCallDriver ( DeviceObject , Irp ) ;
if ( Status = = STATUS_PENDING ) {
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & Event , Executive , KernelMode , false , NULL ) ;
2016-03-23 20:35:05 +00:00
Status = IoStatus . Status ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( iosb )
* iosb = IoStatus ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
_Requires_exclusive_lock_held_ ( Vcb - > tree_lock )
2019-09-01 12:53:20 +00:00
static NTSTATUS add_root ( _Inout_ device_extension * Vcb , _In_ uint64_t id , _In_ uint64_t addr ,
_In_ uint64_t generation , _In_opt_ traverse_ptr * tp ) {
2016-03-23 20:35:05 +00:00
root * r = ExAllocatePoolWithTag ( PagedPool , sizeof ( root ) , ALLOC_TAG ) ;
if ( ! r ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > id = id ;
2019-09-01 12:53:20 +00:00
r - > dirty = false ;
r - > received = false ;
2017-09-08 08:02:43 +00:00
r - > reserved = NULL ;
2016-03-23 20:35:05 +00:00
r - > treeholder . address = addr ;
r - > treeholder . tree = NULL ;
2017-09-08 08:02:43 +00:00
r - > treeholder . generation = generation ;
r - > parent = 0 ;
r - > send_ops = 0 ;
2019-05-11 09:20:02 +00:00
r - > fcbs_version = 0 ;
2019-09-01 12:53:20 +00:00
r - > checked_for_orphans = false ;
2020-04-23 02:38:57 +00:00
r - > dropped = false ;
2016-05-05 17:26:47 +00:00
InitializeListHead ( & r - > fcbs ) ;
2019-05-11 09:20:02 +00:00
RtlZeroMemory ( r - > fcbs_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
2016-03-23 20:35:05 +00:00
r - > nonpaged = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( root_nonpaged ) , ALLOC_TAG ) ;
if ( ! r - > nonpaged ) {
ERR ( " out of memory \n " ) ;
ExFreePool ( r ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & r - > nonpaged - > load_tree_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
r - > lastinode = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp ) {
RtlCopyMemory ( & r - > root_item , tp - > item - > data , min ( sizeof ( ROOT_ITEM ) , tp - > item - > size ) ) ;
if ( tp - > item - > size < sizeof ( ROOT_ITEM ) )
2019-09-01 12:53:20 +00:00
RtlZeroMemory ( ( ( uint8_t * ) & r - > root_item ) + tp - > item - > size , sizeof ( ROOT_ITEM ) - tp - > item - > size ) ;
2017-09-08 08:02:43 +00:00
} else
RtlZeroMemory ( & r - > root_item , sizeof ( ROOT_ITEM ) ) ;
2016-10-29 17:05:10 +00:00
if ( ! Vcb - > readonly & & ( r - > id = = BTRFS_ROOT_ROOT | | r - > id = = BTRFS_ROOT_FSTREE | | ( r - > id > = 0x100 & & ! ( r - > id & 0xf000000000000000 ) ) ) ) { // FS tree root
// FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag)
get_last_inode ( Vcb , r , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( r - > id = = BTRFS_ROOT_ROOT & & r - > lastinode < 0x100 )
r - > lastinode = 0x100 ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InsertTailList ( & Vcb - > roots , & r - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( r - > id ) {
case BTRFS_ROOT_ROOT :
Vcb - > root_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_EXTENT :
Vcb - > extent_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_CHUNK :
Vcb - > chunk_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_DEVTREE :
Vcb - > dev_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case BTRFS_ROOT_CHECKSUM :
Vcb - > checksum_root = r ;
break ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
case BTRFS_ROOT_UUID :
Vcb - > uuid_root = r ;
break ;
2017-09-08 08:02:43 +00:00
case BTRFS_ROOT_FREE_SPACE :
Vcb - > space_root = r ;
break ;
2016-10-29 17:05:10 +00:00
case BTRFS_ROOT_DATA_RELOC :
Vcb - > data_reloc_root = r ;
2017-09-08 08:02:43 +00:00
break ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS look_for_roots ( _Requires_exclusive_lock_held_ ( _Curr_ - > tree_lock ) _In_ device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
traverse_ptr tp , next_tp ;
KEY searchkey ;
2019-09-01 12:53:20 +00:00
bool b ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = 0 ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
2019-09-01 12:53:20 +00:00
TRACE ( " (%I64x,%x,%I64x) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . obj_type = = TYPE_ROOT_ITEM ) {
ROOT_ITEM * ri = ( ROOT_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > size < offsetof ( ROOT_ITEM , byte_limit ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , offsetof ( ROOT_ITEM , byte_limit ) ) ;
2016-03-23 20:35:05 +00:00
} else {
2019-09-01 12:53:20 +00:00
TRACE ( " root %I64x - address %I64x \n " , tp . item - > key . obj_id , ri - > block_number ) ;
2017-09-08 08:02:43 +00:00
Status = add_root ( Vcb , tp . item - > key . obj_id , ri - > block_number , ri - > generation , & tp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_root returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
} else if ( tp . item - > key . obj_type = = TYPE_ROOT_BACKREF & & ! IsListEmpty ( & Vcb - > roots ) ) {
root * lastroot = CONTAINING_RECORD ( Vcb - > roots . Blink , root , list_entry ) ;
if ( lastroot - > id = = tp . item - > key . obj_id )
lastroot - > parent = tp . item - > key . offset ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( b )
2016-03-23 20:35:05 +00:00
tp = next_tp ;
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! Vcb - > readonly & & ! Vcb - > data_reloc_root ) {
root * reloc_root ;
INODE_ITEM * ii ;
2019-09-01 12:53:20 +00:00
uint16_t irlen ;
2016-10-29 17:05:10 +00:00
INODE_REF * ir ;
LARGE_INTEGER time ;
BTRFS_TIME now ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
WARN ( " data reloc root doesn't exist, creating it \n " ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = create_root ( Vcb , BTRFS_ROOT_DATA_RELOC , & reloc_root , false , 0 , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_root returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
reloc_root - > root_item . inode . generation = 1 ;
reloc_root - > root_item . inode . st_size = 3 ;
reloc_root - > root_item . inode . st_blocks = Vcb - > superblock . node_size ;
reloc_root - > root_item . inode . st_nlink = 1 ;
reloc_root - > root_item . inode . st_mode = 040755 ;
2022-04-28 19:37:02 +00:00
reloc_root - > root_item . inode . flags = 0x80000000 ;
reloc_root - > root_item . inode . flags_ro = 0xffffffff ;
2016-10-29 17:05:10 +00:00
reloc_root - > root_item . objid = SUBVOL_ROOT_INODE ;
reloc_root - > root_item . bytes_used = Vcb - > superblock . node_size ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ii = ExAllocatePoolWithTag ( PagedPool , sizeof ( INODE_ITEM ) , ALLOC_TAG ) ;
if ( ! ii ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeQuerySystemTime ( & time ) ;
win_time_to_unix ( time , & now ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlZeroMemory ( ii , sizeof ( INODE_ITEM ) ) ;
ii - > generation = Vcb - > superblock . generation ;
ii - > st_blocks = Vcb - > superblock . node_size ;
ii - > st_nlink = 1 ;
ii - > st_mode = 040755 ;
ii - > st_atime = now ;
ii - > st_ctime = now ;
ii - > st_mtime = now ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , reloc_root , SUBVOL_ROOT_INODE , TYPE_INODE_ITEM , 0 , ii , sizeof ( INODE_ITEM ) , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ii ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
irlen = ( uint16_t ) offsetof ( INODE_REF , name [ 0 ] ) + 2 ;
2016-10-29 17:05:10 +00:00
ir = ExAllocatePoolWithTag ( PagedPool , irlen , ALLOC_TAG ) ;
if ( ! ir ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ir - > index = 0 ;
ir - > n = 2 ;
ir - > name [ 0 ] = ' . ' ;
ir - > name [ 1 ] = ' . ' ;
2017-09-08 08:02:43 +00:00
Status = insert_tree_item ( Vcb , reloc_root , SUBVOL_ROOT_INODE , TYPE_INODE_REF , SUBVOL_ROOT_INODE , ir , irlen , NULL , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " insert_tree_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( ir ) ;
return Status ;
}
2016-10-29 17:05:10 +00:00
Vcb - > data_reloc_root = reloc_root ;
2019-09-01 12:53:20 +00:00
Vcb - > need_write = true ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS find_disk_holes ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_ device * dev , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp , next_tp ;
2019-09-01 12:53:20 +00:00
bool b ;
uint64_t lastaddr ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
InitializeListHead ( & dev - > space ) ;
2017-09-08 08:02:43 +00:00
searchkey . obj_id = 0 ;
searchkey . obj_type = TYPE_DEV_STATS ;
searchkey . offset = dev - > devitem . dev_id ;
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , false , Irp ) ;
2017-09-08 08:02:43 +00:00
if ( NT_SUCCESS ( Status ) & & ! keycmp ( tp . item - > key , searchkey ) )
2019-09-01 12:53:20 +00:00
RtlCopyMemory ( dev - > stats , tp . item - > data , min ( sizeof ( uint64_t ) * 5 , tp . item - > size ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = dev - > devitem . dev_id ;
searchkey . obj_type = TYPE_DEV_EXTENT ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > dev_root , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
lastaddr = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
if ( tp . item - > key . obj_id = = dev - > devitem . dev_id & & tp . item - > key . obj_type = = TYPE_DEV_EXTENT ) {
if ( tp . item - > size > = sizeof ( DEV_EXTENT ) ) {
DEV_EXTENT * de = ( DEV_EXTENT * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . offset > lastaddr ) {
2016-07-27 19:24:26 +00:00
Status = add_space_entry ( & dev - > space , NULL , lastaddr , tp . item - > key . offset - lastaddr ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_space_entry returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
lastaddr = tp . item - > key . offset + de - > length ;
} else {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DEV_EXTENT ) ) ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( b ) {
tp = next_tp ;
if ( tp . item - > key . obj_id > searchkey . obj_id | | tp . item - > key . obj_type > searchkey . obj_type )
break ;
}
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( lastaddr < dev - > devitem . num_bytes ) {
2016-07-27 19:24:26 +00:00
Status = add_space_entry ( & dev - > space , NULL , lastaddr , dev - > devitem . num_bytes - lastaddr ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " add_space_entry returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
// The Linux driver doesn't like to allocate chunks within the first megabyte of a device.
2017-09-08 08:02:43 +00:00
space_list_subtract2 ( & dev - > space , NULL , 0 , 0x100000 , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static void add_device_to_list ( _In_ device_extension * Vcb , _In_ device * dev ) {
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev2 - > devitem . dev_id > dev - > devitem . dev_id ) {
InsertHeadList ( le - > Blink , & dev - > list_entry ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & Vcb - > devices , & dev - > list_entry ) ;
}
2017-09-08 08:02:43 +00:00
_Ret_maybenull_
device * find_device_from_uuid ( _In_ device_extension * Vcb , _In_ BTRFS_UUID * uuid ) {
volume_device_extension * vde ;
pdo_device_extension * pdode ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " device %I64x, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " , dev - > devitem . dev_id ,
2017-01-01 17:12:12 +00:00
dev - > devitem . device_uuid . uuid [ 0 ] , dev - > devitem . device_uuid . uuid [ 1 ] , dev - > devitem . device_uuid . uuid [ 2 ] , dev - > devitem . device_uuid . uuid [ 3 ] , dev - > devitem . device_uuid . uuid [ 4 ] , dev - > devitem . device_uuid . uuid [ 5 ] , dev - > devitem . device_uuid . uuid [ 6 ] , dev - > devitem . device_uuid . uuid [ 7 ] ,
dev - > devitem . device_uuid . uuid [ 8 ] , dev - > devitem . device_uuid . uuid [ 9 ] , dev - > devitem . device_uuid . uuid [ 10 ] , dev - > devitem . device_uuid . uuid [ 11 ] , dev - > devitem . device_uuid . uuid [ 12 ] , dev - > devitem . device_uuid . uuid [ 13 ] , dev - > devitem . device_uuid . uuid [ 14 ] , dev - > devitem . device_uuid . uuid [ 15 ] ) ;
2017-09-08 08:02:43 +00:00
if ( RtlCompareMemory ( & dev - > devitem . device_uuid , uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " returning device %I64x \n " , dev - > devitem . dev_id ) ;
2017-01-01 17:12:12 +00:00
return dev ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
vde = Vcb - > vde ;
if ( ! vde )
goto end ;
pdode = vde - > pdode ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & pdode - > child_lock , true ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices ) {
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le , volume_child , list_entry ) ;
if ( RtlCompareMemory ( uuid , & vc - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
return NULL ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( dev , sizeof ( device ) ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj = vc - > devobj ;
2019-09-01 12:53:20 +00:00
dev - > fileobj = vc - > fileobj ;
2017-01-01 17:12:12 +00:00
dev - > devitem . device_uuid = * uuid ;
2017-09-08 08:02:43 +00:00
dev - > devitem . dev_id = vc - > devid ;
dev - > devitem . num_bytes = vc - > size ;
dev - > seeding = vc - > seeding ;
2017-01-01 17:12:12 +00:00
dev - > readonly = dev - > seeding ;
2019-09-01 12:53:20 +00:00
dev - > reloc = false ;
dev - > removable = false ;
2017-09-08 08:02:43 +00:00
dev - > disk_num = vc - > disk_num ;
dev - > part_num = vc - > part_num ;
dev - > num_trim_entries = 0 ;
InitializeListHead ( & dev - > trim_list ) ;
2017-01-01 17:12:12 +00:00
add_device_to_list ( Vcb , dev ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded + + ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
return dev ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
end :
2016-03-23 20:35:05 +00:00
WARN ( " could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " ,
uuid - > uuid [ 0 ] , uuid - > uuid [ 1 ] , uuid - > uuid [ 2 ] , uuid - > uuid [ 3 ] , uuid - > uuid [ 4 ] , uuid - > uuid [ 5 ] , uuid - > uuid [ 6 ] , uuid - > uuid [ 7 ] ,
uuid - > uuid [ 8 ] , uuid - > uuid [ 9 ] , uuid - > uuid [ 10 ] , uuid - > uuid [ 11 ] , uuid - > uuid [ 12 ] , uuid - > uuid [ 13 ] , uuid - > uuid [ 14 ] , uuid - > uuid [ 15 ] ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return NULL ;
}
2019-09-01 12:53:20 +00:00
static bool is_device_removable ( _In_ PDEVICE_OBJECT devobj ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
STORAGE_HOTPLUG_INFO shi ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( devobj , IOCTL_STORAGE_GET_HOTPLUG_INFO , NULL , 0 , & shi , sizeof ( STORAGE_HOTPLUG_INFO ) , true , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " dev_ioctl returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
return shi . MediaRemovable ! = 0 ? true : false ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
static ULONG get_device_change_count ( _In_ PDEVICE_OBJECT devobj ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
ULONG cc ;
IO_STATUS_BLOCK iosb ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( devobj , IOCTL_STORAGE_CHECK_VERIFY , NULL , 0 , & cc , sizeof ( ULONG ) , true , & iosb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " dev_ioctl returned %08lx \n " , Status ) ;
2016-07-27 19:24:26 +00:00
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( iosb . Information < sizeof ( ULONG ) ) {
ERR ( " iosb.Information was too short \n " ) ;
return 0 ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
return cc ;
}
2019-09-01 12:53:20 +00:00
void init_device ( _In_ device_extension * Vcb , _Inout_ device * dev , _In_ bool get_nums ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
2016-10-29 17:05:10 +00:00
ULONG aptelen ;
ATA_PASS_THROUGH_EX * apte ;
2017-09-08 08:02:43 +00:00
STORAGE_PROPERTY_QUERY spq ;
DEVICE_TRIM_DESCRIPTOR dtd ;
2016-07-27 19:24:26 +00:00
dev - > removable = is_device_removable ( dev - > devobj ) ;
dev - > change_count = dev - > removable ? get_device_change_count ( dev - > devobj ) : 0 ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( get_nums ) {
STORAGE_DEVICE_NUMBER sdn ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_GET_DEVICE_NUMBER , NULL , 0 ,
2019-09-01 12:53:20 +00:00
& sdn , sizeof ( STORAGE_DEVICE_NUMBER ) , true , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
WARN ( " IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
dev - > disk_num = 0xffffffff ;
dev - > part_num = 0xffffffff ;
2017-01-01 17:12:12 +00:00
} else {
dev - > disk_num = sdn . DeviceNumber ;
dev - > part_num = sdn . PartitionNumber ;
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
dev - > trim = false ;
2016-10-29 17:05:10 +00:00
dev - > readonly = dev - > seeding ;
2019-09-01 12:53:20 +00:00
dev - > reloc = false ;
2017-09-08 08:02:43 +00:00
dev - > num_trim_entries = 0 ;
2019-09-01 12:53:20 +00:00
dev - > stats_changed = false ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & dev - > trim_list ) ;
2016-10-29 17:05:10 +00:00
if ( ! dev - > readonly ) {
Status = dev_ioctl ( dev - > devobj , IOCTL_DISK_IS_WRITABLE , NULL , 0 ,
2019-09-01 12:53:20 +00:00
NULL , 0 , true , NULL ) ;
2016-10-29 17:05:10 +00:00
if ( Status = = STATUS_MEDIA_WRITE_PROTECTED )
2019-09-01 12:53:20 +00:00
dev - > readonly = true ;
2016-10-29 17:05:10 +00:00
}
aptelen = sizeof ( ATA_PASS_THROUGH_EX ) + 512 ;
apte = ExAllocatePoolWithTag ( NonPagedPool , aptelen , ALLOC_TAG ) ;
if ( ! apte ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
RtlZeroMemory ( apte , aptelen ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
apte - > Length = sizeof ( ATA_PASS_THROUGH_EX ) ;
apte - > AtaFlags = ATA_FLAGS_DATA_IN ;
apte - > DataTransferLength = aptelen - sizeof ( ATA_PASS_THROUGH_EX ) ;
apte - > TimeOutValue = 3 ;
apte - > DataBufferOffset = apte - > Length ;
2017-09-08 08:02:43 +00:00
apte - > CurrentTaskFile [ 6 ] = IDE_COMMAND_IDENTIFY ;
2016-10-29 17:05:10 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_ATA_PASS_THROUGH , apte , aptelen ,
2019-09-01 12:53:20 +00:00
apte , aptelen , true , NULL ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
TRACE ( " IOCTL_ATA_PASS_THROUGH returned %08lx for IDENTIFY DEVICE \n " , Status ) ;
2017-01-01 17:12:12 +00:00
else {
2019-09-01 12:53:20 +00:00
IDENTIFY_DEVICE_DATA * idd = ( IDENTIFY_DEVICE_DATA * ) ( ( uint8_t * ) apte + sizeof ( ATA_PASS_THROUGH_EX ) ) ;
2017-09-08 08:02:43 +00:00
if ( idd - > CommandSetSupport . FlushCache ) {
2019-09-01 12:53:20 +00:00
dev - > can_flush = true ;
2017-09-08 08:02:43 +00:00
TRACE ( " FLUSH CACHE supported \n " ) ;
} else
TRACE ( " FLUSH CACHE not supported \n " ) ;
}
ExFreePool ( apte ) ;
2019-09-01 12:53:20 +00:00
# ifdef DEBUG_TRIM_EMULATION
dev - > trim = true ;
Vcb - > trim = true ;
# else
2017-09-08 08:02:43 +00:00
spq . PropertyId = StorageDeviceTrimProperty ;
spq . QueryType = PropertyStandardQuery ;
spq . AdditionalParameters [ 0 ] = 0 ;
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_QUERY_PROPERTY , & spq , sizeof ( STORAGE_PROPERTY_QUERY ) ,
2019-09-01 12:53:20 +00:00
& dtd , sizeof ( DEVICE_TRIM_DESCRIPTOR ) , true , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( NT_SUCCESS ( Status ) ) {
if ( dtd . TrimEnabled ) {
2019-09-01 12:53:20 +00:00
dev - > trim = true ;
Vcb - > trim = true ;
2016-10-29 17:05:10 +00:00
TRACE ( " TRIM supported \n " ) ;
} else
TRACE ( " TRIM not supported \n " ) ;
}
2019-09-01 12:53:20 +00:00
# endif
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
RtlZeroMemory ( dev - > stats , sizeof ( uint64_t ) * 5 ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
static NTSTATUS load_chunk_root ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
traverse_ptr tp , next_tp ;
KEY searchkey ;
2019-09-01 12:53:20 +00:00
bool b ;
2016-03-23 20:35:05 +00:00
chunk * c ;
NTSTATUS Status ;
searchkey . obj_id = 0 ;
searchkey . obj_type = 0 ;
searchkey . offset = 0 ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Vcb - > data_flags = 0 ;
2017-01-01 17:12:12 +00:00
Vcb - > metadata_flags = 0 ;
Vcb - > system_flags = 0 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > chunk_root , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
do {
2019-09-01 12:53:20 +00:00
TRACE ( " (%I64x,%x,%I64x) \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( tp . item - > key . obj_id = = 1 & & tp . item - > key . obj_type = = TYPE_DEV_ITEM ) {
if ( tp . item - > size < sizeof ( DEV_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DEV_ITEM ) ) ;
2016-07-27 19:24:26 +00:00
} else {
DEV_ITEM * di = ( DEV_ITEM * ) tp . item - > data ;
2017-01-01 17:12:12 +00:00
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool done = false ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev - > devobj & & RtlCompareMemory ( & dev - > devitem . device_uuid , & di - > device_uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
RtlCopyMemory ( & dev - > devitem , tp . item - > data , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( le ! = Vcb - > devices . Flink )
2019-09-01 12:53:20 +00:00
init_device ( Vcb , dev , true ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
done = true ;
2016-07-27 19:24:26 +00:00
break ;
}
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
if ( ! done & & Vcb - > vde ) {
volume_device_extension * vde = Vcb - > vde ;
pdo_device_extension * pdode = vde - > pdode ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & pdode - > child_lock , true ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices ) {
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le , volume_child , list_entry ) ;
if ( RtlCompareMemory ( & di - > device_uuid , & vc - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-01-01 17:12:12 +00:00
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( dev , sizeof ( device ) ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj = vc - > devobj ;
2019-09-01 12:53:20 +00:00
dev - > fileobj = vc - > fileobj ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( & dev - > devitem , di , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
2017-09-08 08:02:43 +00:00
dev - > seeding = vc - > seeding ;
2019-09-01 12:53:20 +00:00
init_device ( Vcb , dev , false ) ;
2017-01-01 17:12:12 +00:00
2017-09-08 08:02:43 +00:00
if ( dev - > devitem . num_bytes > vc - > size ) {
2019-09-01 12:53:20 +00:00
WARN ( " device %I64x: DEV_ITEM says %I64x bytes, but Windows only reports %I64x \n " , tp . item - > key . offset ,
2017-09-08 08:02:43 +00:00
dev - > devitem . num_bytes , vc - > size ) ;
dev - > devitem . num_bytes = vc - > size ;
}
dev - > disk_num = vc - > disk_num ;
dev - > part_num = vc - > part_num ;
2017-01-01 17:12:12 +00:00
add_device_to_list ( Vcb , dev ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded + + ;
2019-09-01 12:53:20 +00:00
done = true ;
2016-07-27 19:24:26 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! done ) {
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > options . allow_degraded ) {
2019-09-01 12:53:20 +00:00
ERR ( " volume not found: device %I64x, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x \n " , tp . item - > key . offset ,
2017-09-08 08:02:43 +00:00
di - > device_uuid . uuid [ 0 ] , di - > device_uuid . uuid [ 1 ] , di - > device_uuid . uuid [ 2 ] , di - > device_uuid . uuid [ 3 ] , di - > device_uuid . uuid [ 4 ] , di - > device_uuid . uuid [ 5 ] , di - > device_uuid . uuid [ 6 ] , di - > device_uuid . uuid [ 7 ] ,
di - > device_uuid . uuid [ 8 ] , di - > device_uuid . uuid [ 9 ] , di - > device_uuid . uuid [ 10 ] , di - > device_uuid . uuid [ 11 ] , di - > device_uuid . uuid [ 12 ] , di - > device_uuid . uuid [ 13 ] , di - > device_uuid . uuid [ 14 ] , di - > device_uuid . uuid [ 15 ] ) ;
} else {
device * dev ;
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
ExReleaseResourceLite ( & pdode - > child_lock ) ;
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
RtlZeroMemory ( dev , sizeof ( device ) ) ;
// Missing device, so we keep dev->devobj as NULL
RtlCopyMemory ( & dev - > devitem , di , min ( tp . item - > size , sizeof ( DEV_ITEM ) ) ) ;
InitializeListHead ( & dev - > trim_list ) ;
add_device_to_list ( Vcb , dev ) ;
Vcb - > devices_loaded + + ;
}
2016-07-27 19:24:26 +00:00
}
} else
2019-09-01 12:53:20 +00:00
ERR ( " unexpected device %I64x found \n " , tp . item - > key . offset ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2016-07-27 19:24:26 +00:00
}
}
2016-03-23 20:35:05 +00:00
} else if ( tp . item - > key . obj_type = = TYPE_CHUNK_ITEM ) {
if ( tp . item - > size < sizeof ( CHUNK_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( CHUNK_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
} else {
2016-09-04 15:27:46 +00:00
c = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( chunk ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
c - > size = tp . item - > size ;
c - > offset = tp . item - > key . offset ;
c - > used = c - > oldused = 0 ;
2017-09-08 08:02:43 +00:00
c - > cache = c - > old_cache = NULL ;
2019-09-01 12:53:20 +00:00
c - > created = false ;
c - > readonly = false ;
c - > reloc = false ;
c - > cache_loaded = false ;
c - > changed = false ;
c - > space_changed = false ;
2017-09-08 08:02:43 +00:00
c - > balance_num = 0 ;
2016-09-04 15:27:46 +00:00
c - > chunk_item = ExAllocatePoolWithTag ( NonPagedPool , tp . item - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c - > chunk_item ) {
ERR ( " out of memory \n " ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( c ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( c - > chunk_item , tp . item - > data , tp . item - > size ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_DATA & & c - > chunk_item - > type > Vcb - > data_flags )
Vcb - > data_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_METADATA & & c - > chunk_item - > type > Vcb - > metadata_flags )
Vcb - > metadata_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_SYSTEM & & c - > chunk_item - > type > Vcb - > system_flags )
Vcb - > system_flags = c - > chunk_item - > type ;
2017-09-08 08:02:43 +00:00
if ( c - > chunk_item - > type & BLOCK_FLAG_RAID10 ) {
if ( c - > chunk_item - > sub_stripes = = 0 | | c - > chunk_item - > sub_stripes > c - > chunk_item - > num_stripes ) {
2019-09-01 12:53:20 +00:00
ERR ( " chunk %I64x: invalid stripes (num_stripes %u, sub_stripes %u) \n " , c - > offset , c - > chunk_item - > num_stripes , c - > chunk_item - > sub_stripes ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
}
2016-03-23 20:35:05 +00:00
if ( c - > chunk_item - > num_stripes > 0 ) {
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & c - > chunk_item [ 1 ] ;
2019-09-01 12:53:20 +00:00
uint16_t i ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
c - > devices = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device * ) * c - > chunk_item - > num_stripes , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! c - > devices ) {
ERR ( " out of memory \n " ) ;
2016-07-27 19:24:26 +00:00
ExFreePool ( c - > chunk_item ) ;
2016-10-29 17:05:10 +00:00
ExFreePool ( c ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
for ( i = 0 ; i < c - > chunk_item - > num_stripes ; i + + ) {
c - > devices [ i ] = find_device_from_uuid ( Vcb , & cis [ i ] . dev_uuid ) ;
2020-04-23 02:38:57 +00:00
TRACE ( " device %u = %p \n " , i , c - > devices [ i ] ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! c - > devices [ i ] ) {
ERR ( " missing device \n " ) ;
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( c - > devices [ i ] - > readonly )
2019-09-01 12:53:20 +00:00
c - > readonly = true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
} else {
2019-09-01 12:53:20 +00:00
ERR ( " chunk %I64x: number of stripes is 0 \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( c - > chunk_item ) ;
ExFreePool ( c ) ;
return STATUS_INTERNAL_ERROR ;
}
2016-09-04 15:27:46 +00:00
ExInitializeResourceLite ( & c - > lock ) ;
ExInitializeResourceLite ( & c - > changed_extents_lock ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & c - > space ) ;
2016-07-27 19:24:26 +00:00
InitializeListHead ( & c - > space_size ) ;
InitializeListHead ( & c - > deleting ) ;
InitializeListHead ( & c - > changed_extents ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & c - > range_locks ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & c - > range_locks_lock ) ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & c - > range_locks_event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & c - > partial_stripes ) ;
ExInitializeResourceLite ( & c - > partial_stripes_lock ) ;
2019-09-01 12:53:20 +00:00
c - > last_alloc_set = false ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
c - > last_stripe = 0 ;
2016-03-23 20:35:05 +00:00
InsertTailList ( & Vcb - > chunks , & c - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
c - > list_entry_balance . Flink = NULL ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
b = find_next_item ( Vcb , & tp , & next_tp , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( b )
2016-03-23 20:35:05 +00:00
tp = next_tp ;
} while ( b ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > log_to_phys_loaded = true ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > data_flags = = 0 )
Vcb - > data_flags = BLOCK_FLAG_DATA | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID0 : 0 ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > metadata_flags = = 0 )
Vcb - > metadata_flags = BLOCK_FLAG_METADATA | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > system_flags = = 0 )
Vcb - > system_flags = BLOCK_FLAG_SYSTEM | ( Vcb - > superblock . num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS ) {
Vcb - > metadata_flags | = BLOCK_FLAG_DATA ;
Vcb - > data_flags = Vcb - > metadata_flags ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
void protect_superblocks ( _Inout_ chunk * c ) {
2019-09-01 12:53:20 +00:00
uint16_t i = 0 , j ;
uint64_t off_start , off_end ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// The Linux driver also protects all the space before the first superblock.
2017-09-08 08:02:43 +00:00
// I realize this confuses physical and logical addresses, but this is what btrfs-progs does -
2016-07-27 19:24:26 +00:00
// evidently Linux assumes the chunk at 0 is always SINGLE.
if ( c - > offset < superblock_addrs [ 0 ] )
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , c - > offset , superblock_addrs [ 0 ] - c - > offset , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( superblock_addrs [ i ] ! = 0 ) {
CHUNK_ITEM * ci = c - > chunk_item ;
CHUNK_ITEM_STRIPE * cis = ( CHUNK_ITEM_STRIPE * ) & ci [ 1 ] ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ci - > type & BLOCK_FLAG_RAID0 | | ci - > type & BLOCK_FLAG_RAID10 ) {
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
2019-09-01 12:53:20 +00:00
uint16_t sub_stripes = max ( ci - > sub_stripes , 1 ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( cis [ j ] . offset + ( ci - > size * ci - > num_stripes / sub_stripes ) > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
# ifdef _DEBUG
2019-09-01 12:53:20 +00:00
uint64_t startoff ;
uint16_t startoffstripe ;
2016-07-27 19:24:26 +00:00
# endif
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " cut out superblock in chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
off_start - = off_start % ci - > stripe_length ;
off_start * = ci - > num_stripes / sub_stripes ;
off_start + = ( j / sub_stripes ) * ci - > stripe_length ;
off_end = off_start + ci - > stripe_length ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
# ifdef _DEBUG
get_raid0_offset ( off_start , ci - > stripe_length , ci - > num_stripes / sub_stripes , & startoff , & startoffstripe ) ;
TRACE ( " j = %u, startoffstripe = %u \n " , j , startoffstripe ) ;
2019-09-01 12:53:20 +00:00
TRACE ( " startoff = %I64x, superblock = %I64x \n " , startoff + cis [ j ] . offset , superblock_addrs [ i ] ) ;
2016-07-27 19:24:26 +00:00
# endif
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-10-29 17:05:10 +00:00
}
}
} else if ( ci - > type & BLOCK_FLAG_RAID5 ) {
2019-09-01 12:53:20 +00:00
uint64_t stripe_size = ci - > size / ( ci - > num_stripes - 1 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + stripe_size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " cut out superblock in chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
2017-09-08 08:02:43 +00:00
off_start - = off_start % ci - > stripe_length ;
2016-10-29 17:05:10 +00:00
off_start * = ci - > num_stripes - 1 ;
2017-09-08 08:02:43 +00:00
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , ci - > stripe_length ) ;
off_end * = ci - > num_stripes - 1 ;
2019-09-01 12:53:20 +00:00
TRACE ( " cutting out %I64x, size %I64x \n " , c - > offset + off_start , off_end - off_start ) ;
2016-10-29 17:05:10 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-10-29 17:05:10 +00:00
}
}
} else if ( ci - > type & BLOCK_FLAG_RAID6 ) {
2019-09-01 12:53:20 +00:00
uint64_t stripe_size = ci - > size / ( ci - > num_stripes - 2 ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + stripe_size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " cut out superblock in chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
off_start = superblock_addrs [ i ] - cis [ j ] . offset ;
2017-09-08 08:02:43 +00:00
off_start - = off_start % ci - > stripe_length ;
2016-10-29 17:05:10 +00:00
off_start * = ci - > num_stripes - 2 ;
2017-09-08 08:02:43 +00:00
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , ci - > stripe_length ) ;
off_end * = ci - > num_stripes - 2 ;
2019-09-01 12:53:20 +00:00
TRACE ( " cutting out %I64x, size %I64x \n " , c - > offset + off_start , off_end - off_start ) ;
2016-10-29 17:05:10 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-07-27 19:24:26 +00:00
}
}
2020-04-23 02:38:57 +00:00
} else { // SINGLE, DUPLICATE, RAID1, RAID1C3, RAID1C4
2016-07-27 19:24:26 +00:00
for ( j = 0 ; j < ci - > num_stripes ; j + + ) {
if ( cis [ j ] . offset + ci - > size > superblock_addrs [ i ] & & cis [ j ] . offset < = superblock_addrs [ i ] + sizeof ( superblock ) ) {
2019-09-01 12:53:20 +00:00
TRACE ( " cut out superblock in chunk %I64x \n " , c - > offset ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
// The Linux driver protects the whole stripe in which the superblock lives
off_start = ( ( superblock_addrs [ i ] - cis [ j ] . offset ) / c - > chunk_item - > stripe_length ) * c - > chunk_item - > stripe_length ;
off_end = sector_align ( superblock_addrs [ i ] - cis [ j ] . offset + sizeof ( superblock ) , c - > chunk_item - > stripe_length ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
space_list_subtract ( c , c - > offset + off_start , off_end - off_start , NULL ) ;
2016-07-27 19:24:26 +00:00
}
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
i + + ;
}
}
2017-09-08 08:02:43 +00:00
NTSTATUS find_chunk_usage ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
LIST_ENTRY * le = Vcb - > chunks . Flink ;
chunk * c ;
KEY searchkey ;
traverse_ptr tp ;
BLOCK_GROUP_ITEM * bgi ;
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_type = TYPE_BLOCK_GROUP_ITEM ;
2017-09-08 08:02:43 +00:00
2019-06-11 10:35:19 +00:00
Vcb - > superblock . bytes_used = 0 ;
2016-03-23 20:35:05 +00:00
while ( le ! = & Vcb - > chunks ) {
c = CONTAINING_RECORD ( le , chunk , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
searchkey . obj_id = c - > offset ;
searchkey . offset = c - > chunk_item - > size ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > extent_root , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! keycmp ( searchkey , tp . item - > key ) ) {
2016-03-23 20:35:05 +00:00
if ( tp . item - > size > = sizeof ( BLOCK_GROUP_ITEM ) ) {
bgi = ( BLOCK_GROUP_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
c - > used = c - > oldused = bgi - > used ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " chunk %I64x has %I64x bytes used \n " , c - > offset , c - > used ) ;
2019-06-11 10:35:19 +00:00
2022-04-28 19:37:02 +00:00
Vcb - > superblock . bytes_used + = bgi - > used ;
2016-03-23 20:35:05 +00:00
} else {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x;%I64x,%x,%I64x) is %u bytes, expected %Iu \n " ,
2016-03-23 20:35:05 +00:00
Vcb - > extent_root - > id , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( BLOCK_GROUP_ITEM ) ) ;
}
}
2016-10-29 17:05:10 +00:00
2016-03-23 20:35:05 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > chunk_usage_found = true ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS load_sys_chunks ( _In_ device_extension * Vcb ) {
2016-03-23 20:35:05 +00:00
KEY key ;
ULONG n = Vcb - > superblock . n ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
while ( n > 0 ) {
if ( n > sizeof ( KEY ) ) {
RtlCopyMemory ( & key , & Vcb - > superblock . sys_chunk_array [ Vcb - > superblock . n - n ] , sizeof ( KEY ) ) ;
n - = sizeof ( KEY ) ;
} else
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
TRACE ( " bootstrap: %I64x,%x,%I64x \n " , key . obj_id , key . obj_type , key . offset ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( key . obj_type = = TYPE_CHUNK_ITEM ) {
CHUNK_ITEM * ci ;
2017-09-08 08:02:43 +00:00
USHORT cisize ;
2016-03-23 20:35:05 +00:00
sys_chunk * sc ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( n < sizeof ( CHUNK_ITEM ) )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
ci = ( CHUNK_ITEM * ) & Vcb - > superblock . sys_chunk_array [ Vcb - > superblock . n - n ] ;
cisize = sizeof ( CHUNK_ITEM ) + ( ci - > num_stripes * sizeof ( CHUNK_ITEM_STRIPE ) ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( n < cisize )
return STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
sc = ExAllocatePoolWithTag ( PagedPool , sizeof ( sys_chunk ) , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! sc ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
sc - > key = key ;
sc - > size = cisize ;
sc - > data = ExAllocatePoolWithTag ( PagedPool , sc - > size , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! sc - > data ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( sc ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlCopyMemory ( sc - > data , ci , sc - > size ) ;
InsertTailList ( & Vcb - > sys_chunks , & sc - > list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
n - = cisize ;
} else {
2019-09-01 12:53:20 +00:00
ERR ( " unexpected item %I64x,%x,%I64x in bootstrap \n " , key . obj_id , key . obj_type , key . offset ) ;
2016-03-23 20:35:05 +00:00
return STATUS_INTERNAL_ERROR ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}
2017-09-08 08:02:43 +00:00
_Ret_maybenull_
2019-11-12 18:32:46 +00:00
root * find_default_subvol ( _In_ _Requires_lock_held_ ( _Curr_ - > tree_lock ) device_extension * Vcb , _In_opt_ PIRP Irp ) {
2016-05-05 17:26:47 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
static const char fn [ ] = " default " ;
2019-09-01 12:53:20 +00:00
static uint32_t crc32 = 0x8dbfc2d2 ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > options . subvol_id ! = 0 ) {
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( r - > id = = Vcb - > options . subvol_id )
return r ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
le = le - > Flink ;
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL ) {
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
KEY searchkey ;
traverse_ptr tp ;
DIR_ITEM * di ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
searchkey . obj_id = Vcb - > superblock . root_dir_objectid ;
searchkey . obj_type = TYPE_DIR_ITEM ;
searchkey . offset = crc32 ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , Vcb - > root_root , & tp , & searchkey , false , Irp ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( keycmp ( tp . item - > key , searchkey ) ) {
2019-09-01 12:53:20 +00:00
ERR ( " could not find (%I64x,%x,%I64x) in root tree \n " , searchkey . obj_id , searchkey . obj_type , searchkey . offset ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( tp . item - > size < sizeof ( DIR_ITEM ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected at least %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
di = ( DIR_ITEM * ) tp . item - > data ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( tp . item - > size < sizeof ( DIR_ITEM ) - 1 + di - > n ) {
2020-04-23 02:38:57 +00:00
ERR ( " (%I64x,%x,%I64x) was %u bytes, expected %Iu \n " , tp . item - > key . obj_id , tp . item - > key . obj_type , tp . item - > key . offset , tp . item - > size , sizeof ( DIR_ITEM ) - 1 + di - > n ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( di - > n ! = strlen ( fn ) | | RtlCompareMemory ( di - > name , fn , di - > n ) ! = di - > n ) {
ERR ( " root DIR_ITEM had same CRC32, but was not \" default \" \n " ) ;
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( di - > key . obj_type ! = TYPE_ROOT_ITEM ) {
2019-09-01 12:53:20 +00:00
ERR ( " default root has key (%I64x,%x,%I64x), expected subvolume \n " , di - > key . obj_id , di - > key . obj_type , di - > key . offset ) ;
2016-07-27 19:24:26 +00:00
goto end ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( r - > id = = di - > key . obj_id )
return r ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ERR ( " could not find root %I64x, using default instead \n " , di - > key . obj_id ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
end :
2016-05-05 17:26:47 +00:00
le = Vcb - > roots . Flink ;
while ( le ! = & Vcb - > roots ) {
root * r = CONTAINING_RECORD ( le , root , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( r - > id = = BTRFS_ROOT_FSTREE )
return r ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
return NULL ;
}
2017-09-08 08:02:43 +00:00
void init_file_cache ( _In_ PFILE_OBJECT FileObject , _In_ CC_FILE_SIZES * ccfs ) {
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %p) \n " , FileObject , ccfs ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
CcInitializeCacheMap ( FileObject , ccfs , false , & cache_callbacks , FileObject ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( diskacc )
2017-09-08 08:02:43 +00:00
fCcSetAdditionalCacheAttributesEx ( FileObject , CC_ENABLE_DISK_IO_ACCOUNTING ) ;
2017-01-01 17:12:12 +00:00
CcSetReadAheadGranularity ( FileObject , READ_AHEAD_GRANULARITY ) ;
}
2019-09-01 12:53:20 +00:00
uint32_t get_num_of_processors ( ) {
KAFFINITY p = KeQueryActiveProcessors ( ) ;
uint32_t r = 0 ;
while ( p ! = 0 ) {
if ( p & 1 )
r + + ;
p > > = 1 ;
}
return r ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS create_calc_threads ( _In_ PDEVICE_OBJECT DeviceObject ) {
2017-01-01 17:12:12 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-11-12 18:32:46 +00:00
OBJECT_ATTRIBUTES oa ;
2017-01-01 17:12:12 +00:00
ULONG i ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > calcthreads . num_threads = get_num_of_processors ( ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > calcthreads . threads = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( drv_calc_thread ) * Vcb - > calcthreads . num_threads , ALLOC_TAG ) ;
if ( ! Vcb - > calcthreads . threads ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > calcthreads . job_list ) ;
2020-04-23 02:38:57 +00:00
KeInitializeSpinLock ( & Vcb - > calcthreads . spinlock ) ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & Vcb - > calcthreads . event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlZeroMemory ( Vcb - > calcthreads . threads , sizeof ( drv_calc_thread ) * Vcb - > calcthreads . num_threads ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
InitializeObjectAttributes ( & oa , NULL , OBJ_KERNEL_HANDLE , NULL , NULL ) ;
2017-01-01 17:12:12 +00:00
for ( i = 0 ; i < Vcb - > calcthreads . num_threads ; i + + ) {
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Vcb - > calcthreads . threads [ i ] . DeviceObject = DeviceObject ;
2020-04-23 02:38:57 +00:00
Vcb - > calcthreads . threads [ i ] . number = i ;
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & Vcb - > calcthreads . threads [ i ] . finished , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
Status = PsCreateSystemThread ( & Vcb - > calcthreads . threads [ i ] . handle , 0 , & oa , NULL , NULL , calc_thread , & Vcb - > calcthreads . threads [ i ] ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
ULONG j ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
ERR ( " PsCreateSystemThread returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
for ( j = 0 ; j < i ; j + + ) {
2019-09-01 12:53:20 +00:00
Vcb - > calcthreads . threads [ i ] . quit = true ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeSetEvent ( & Vcb - > calcthreads . event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return Status ;
}
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
return STATUS_SUCCESS ;
}
2019-09-01 12:53:20 +00:00
static bool is_btrfs_volume ( _In_ PDEVICE_OBJECT DeviceObject ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
MOUNTDEV_NAME mdn , * mdn2 ;
ULONG mdnsize ;
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( DeviceObject , IOCTL_MOUNTDEV_QUERY_DEVICE_NAME , NULL , 0 , & mdn , sizeof ( MOUNTDEV_NAME ) , true , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_BUFFER_OVERFLOW ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
mdnsize = ( ULONG ) offsetof ( MOUNTDEV_NAME , Name [ 0 ] ) + mdn . NameLength ;
mdn2 = ExAllocatePoolWithTag ( PagedPool , mdnsize , ALLOC_TAG ) ;
if ( ! mdn2 ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( DeviceObject , IOCTL_MOUNTDEV_QUERY_DEVICE_NAME , NULL , 0 , mdn2 , mdnsize , true , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( mdn2 ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
2018-12-16 11:03:16 +00:00
if ( mdn2 - > NameLength > ( sizeof ( BTRFS_VOLUME_PREFIX ) - sizeof ( WCHAR ) ) & &
RtlCompareMemory ( mdn2 - > Name , BTRFS_VOLUME_PREFIX , sizeof ( BTRFS_VOLUME_PREFIX ) - sizeof ( WCHAR ) ) = = sizeof ( BTRFS_VOLUME_PREFIX ) - sizeof ( WCHAR ) ) {
2017-09-08 08:02:43 +00:00
ExFreePool ( mdn2 ) ;
2019-09-01 12:53:20 +00:00
return true ;
2017-09-08 08:02:43 +00:00
}
ExFreePool ( mdn2 ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
static NTSTATUS get_device_pnp_name_guid ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ PUNICODE_STRING pnp_name , _In_ const GUID * guid ) {
NTSTATUS Status ;
WCHAR * list = NULL , * s ;
Status = IoGetDeviceInterfaces ( ( PVOID ) guid , NULL , 0 , & list ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoGetDeviceInterfaces returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
s = list ;
while ( s [ 0 ] ! = 0 ) {
PFILE_OBJECT FileObject ;
PDEVICE_OBJECT devobj ;
UNICODE_STRING name ;
name . Length = name . MaximumLength = ( USHORT ) wcslen ( s ) * sizeof ( WCHAR ) ;
name . Buffer = s ;
if ( NT_SUCCESS ( IoGetDeviceObjectPointer ( & name , FILE_READ_ATTRIBUTES , & FileObject , & devobj ) ) ) {
if ( DeviceObject = = devobj | | DeviceObject = = FileObject - > DeviceObject ) {
ObDereferenceObject ( FileObject ) ;
pnp_name - > Buffer = ExAllocatePoolWithTag ( PagedPool , name . Length , ALLOC_TAG ) ;
if ( ! pnp_name - > Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end ;
}
RtlCopyMemory ( pnp_name - > Buffer , name . Buffer , name . Length ) ;
pnp_name - > Length = pnp_name - > MaximumLength = name . Length ;
Status = STATUS_SUCCESS ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
ObDereferenceObject ( FileObject ) ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
s = & s [ wcslen ( s ) + 1 ] ;
}
pnp_name - > Length = pnp_name - > MaximumLength = 0 ;
pnp_name - > Buffer = 0 ;
Status = STATUS_NOT_FOUND ;
end :
if ( list )
ExFreePool ( list ) ;
return Status ;
}
NTSTATUS get_device_pnp_name ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ PUNICODE_STRING pnp_name , _Out_ const GUID * * guid ) {
NTSTATUS Status ;
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_VOLUME ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_VOLUME ;
return Status ;
}
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_HIDDEN_VOLUME ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_HIDDEN_VOLUME ;
return Status ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
Status = get_device_pnp_name_guid ( DeviceObject , pnp_name , & GUID_DEVINTERFACE_DISK ) ;
if ( NT_SUCCESS ( Status ) ) {
* guid = & GUID_DEVINTERFACE_DISK ;
return Status ;
}
return STATUS_NOT_FOUND ;
}
_Success_ ( return > = 0 )
2019-09-01 12:53:20 +00:00
static NTSTATUS check_mount_device ( _In_ PDEVICE_OBJECT DeviceObject , _Out_ bool * pno_pnp ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
ULONG to_read ;
superblock * sb ;
2021-07-05 23:37:34 +00:00
// UNICODE_STRING pnp_name;
// const GUID* guid;
2017-09-08 08:02:43 +00:00
to_read = DeviceObject - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , DeviceObject - > SectorSize ) ;
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2019-09-01 12:53:20 +00:00
Status = sync_read_phys ( DeviceObject , NULL , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
}
if ( sb - > magic ! = BTRFS_MAGIC ) {
Status = STATUS_SUCCESS ;
goto end ;
}
2020-04-23 02:38:57 +00:00
if ( ! check_superblock_checksum ( sb ) ) {
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
goto end ;
}
DeviceObject - > Flags & = ~ DO_VERIFY_VOLUME ;
2021-07-05 23:37:34 +00:00
// pnp_name.Buffer = NULL;
2017-09-08 08:02:43 +00:00
2021-07-05 23:37:34 +00:00
// Status = get_device_pnp_name(DeviceObject, &pnp_name, &guid);
// if (!NT_SUCCESS(Status)) {
// WARN("get_device_pnp_name returned %08lx\n", Status);
// pnp_name.Length = 0;
// }
2017-09-08 08:02:43 +00:00
2021-07-05 23:37:34 +00:00
// *pno_pnp = pnp_name.Length == 0;
* pno_pnp = true ;
2017-09-08 08:02:43 +00:00
2021-07-05 23:37:34 +00:00
// if (pnp_name.Buffer)
// ExFreePool(pnp_name.Buffer);
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
end :
ExFreePool ( sb ) ;
return Status ;
}
2019-09-01 12:53:20 +00:00
static bool still_has_superblock ( _In_ PDEVICE_OBJECT device , _In_ PFILE_OBJECT fileobj ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
ULONG to_read ;
superblock * sb ;
if ( ! device )
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
to_read = device - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , device - > SectorSize ) ;
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
Status = sync_read_phys ( device , fileobj , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " Failed to read superblock: %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
if ( sb - > magic ! = BTRFS_MAGIC ) {
TRACE ( " not a BTRFS volume \n " ) ;
ExFreePool ( sb ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
} else {
2020-04-23 02:38:57 +00:00
if ( ! check_superblock_checksum ( sb ) ) {
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
2019-09-01 12:53:20 +00:00
return false ;
2017-09-08 08:02:43 +00:00
}
}
2019-11-12 18:32:46 +00:00
ObReferenceObject ( device ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
while ( device ) {
PDEVICE_OBJECT device2 = IoGetLowerDeviceObject ( device ) ;
device - > Flags & = ~ DO_VERIFY_VOLUME ;
ObDereferenceObject ( device ) ;
device = device2 ;
}
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
2019-11-12 18:32:46 +00:00
2019-09-01 12:53:20 +00:00
return true ;
2016-03-23 20:35:05 +00:00
}
2022-04-28 19:31:44 +00:00
static void calculate_sector_shift ( device_extension * Vcb ) {
uint32_t ss = Vcb - > superblock . sector_size ;
Vcb - > sector_shift = 0 ;
while ( ! ( ss & 1 ) ) {
Vcb - > sector_shift + + ;
ss > > = 1 ;
}
}
2017-09-08 08:02:43 +00:00
static NTSTATUS mount_vol ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2017-01-01 17:12:12 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-03-23 20:35:05 +00:00
PDEVICE_OBJECT NewDeviceObject = NULL ;
2017-09-08 08:02:43 +00:00
PDEVICE_OBJECT DeviceToMount , readobj ;
2019-09-01 12:53:20 +00:00
PFILE_OBJECT fileobj ;
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
device_extension * Vcb = NULL ;
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le , batchlist ;
2016-03-23 20:35:05 +00:00
KEY searchkey ;
traverse_ptr tp ;
2016-05-05 17:26:47 +00:00
fcb * root_fcb = NULL ;
2016-07-27 19:24:26 +00:00
ccb * root_ccb = NULL ;
2019-09-01 12:53:20 +00:00
bool init_lookaside = false ;
2017-01-01 17:12:12 +00:00
device * dev ;
2017-09-08 08:02:43 +00:00
volume_device_extension * vde = NULL ;
pdo_device_extension * pdode = NULL ;
volume_child * vc ;
2019-09-01 12:53:20 +00:00
uint64_t readobjsize ;
2019-11-12 18:32:46 +00:00
OBJECT_ATTRIBUTES oa ;
device_extension * real_devext ;
KIRQL irql ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
TRACE ( " (%p, %p) \n " , DeviceObject , Irp ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:58 +00:00
if ( DeviceObject ! = master_devobj )
return STATUS_INVALID_DEVICE_REQUEST ;
2016-03-23 20:35:05 +00:00
2017-01-01 17:12:12 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
DeviceToMount = IrpSp - > Parameters . MountVolume . DeviceObject ;
2016-03-23 20:35:05 +00:00
2019-11-12 18:32:46 +00:00
real_devext = IrpSp - > Parameters . MountVolume . Vpb - > RealDevice - > DeviceExtension ;
// Make sure we're not trying to mount the PDO
if ( IrpSp - > Parameters . MountVolume . Vpb - > RealDevice - > DriverObject = = drvobj & & real_devext - > type = = VCB_TYPE_PDO )
return STATUS_UNRECOGNIZED_VOLUME ;
2017-09-08 08:02:43 +00:00
if ( ! is_btrfs_volume ( DeviceToMount ) ) {
2019-09-01 12:53:20 +00:00
bool not_pnp = false ;
Status = check_mount_device ( DeviceToMount , & not_pnp ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " check_mount_device returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( ! not_pnp ) {
2017-09-08 08:02:43 +00:00
Status = STATUS_UNRECOGNIZED_VOLUME ;
2022-04-28 19:35:58 +00:00
goto exit ;
2017-09-08 08:02:43 +00:00
}
} else {
PDEVICE_OBJECT pdo ;
pdo = DeviceToMount ;
2019-11-12 18:32:46 +00:00
ObReferenceObject ( pdo ) ;
while ( true ) {
PDEVICE_OBJECT pdo2 = IoGetLowerDeviceObject ( pdo ) ;
ObDereferenceObject ( pdo ) ;
if ( ! pdo2 )
break ;
else
pdo = pdo2 ;
2017-09-08 08:02:43 +00:00
}
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & pdo_list_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = pdo_list . Flink ;
while ( le ! = & pdo_list ) {
2019-09-01 12:53:20 +00:00
pdo_device_extension * pdode2 = CONTAINING_RECORD ( le , pdo_device_extension , list_entry ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
if ( pdode2 - > pdo = = pdo ) {
vde = pdode2 - > vde ;
2017-09-08 08:02:43 +00:00
break ;
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & pdo_list_lock ) ;
if ( ! vde | | vde - > type ! = VCB_TYPE_VOLUME ) {
vde = NULL ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
2022-04-28 19:35:58 +00:00
goto exit ;
2017-09-08 08:02:43 +00:00
}
}
if ( vde ) {
pdode = vde - > pdode ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & pdode - > child_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = pdode - > children . Flink ;
while ( le ! = & pdode - > children ) {
LIST_ENTRY * le2 = le - > Flink ;
vc = CONTAINING_RECORD ( pdode - > children . Flink , volume_child , list_entry ) ;
2019-09-01 12:53:20 +00:00
if ( ! still_has_superblock ( vc - > devobj , vc - > fileobj ) ) {
remove_volume_child ( vde , vc , false ) ;
2017-09-08 08:02:43 +00:00
if ( pdode - > num_children = = 0 ) {
ERR ( " error - number of devices is zero \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
2022-04-28 19:35:58 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
goto exit ;
2017-09-08 08:02:43 +00:00
}
Status = STATUS_DEVICE_NOT_READY ;
2022-04-28 19:35:58 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
goto exit ;
2017-09-08 08:02:43 +00:00
}
le = le2 ;
}
if ( pdode - > num_children = = 0 | | pdode - > children_loaded = = 0 ) {
ERR ( " error - number of devices is zero \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
2022-04-28 19:35:58 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
ExConvertExclusiveToSharedLite ( & pdode - > child_lock ) ;
vc = CONTAINING_RECORD ( pdode - > children . Flink , volume_child , list_entry ) ;
readobj = vc - > devobj ;
2019-09-01 12:53:20 +00:00
fileobj = vc - > fileobj ;
2017-09-08 08:02:43 +00:00
readobjsize = vc - > size ;
vde - > device - > Characteristics & = ~ FILE_DEVICE_SECURE_OPEN ;
} else {
GET_LENGTH_INFORMATION gli ;
vc = NULL ;
readobj = DeviceToMount ;
2019-09-01 12:53:20 +00:00
fileobj = NULL ;
2017-09-08 08:02:43 +00:00
Status = dev_ioctl ( readobj , IOCTL_DISK_GET_LENGTH_INFO , NULL , 0 ,
2019-09-01 12:53:20 +00:00
& gli , sizeof ( gli ) , true , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error reading length information: %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
readobjsize = gli . Length . QuadPart ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
Status = IoCreateDevice ( drvobj , sizeof ( device_extension ) , NULL , FILE_DEVICE_DISK_FILE_SYSTEM , 0 , false , & NewDeviceObject ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCreateDevice returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
Status = STATUS_UNRECOGNIZED_VOLUME ;
2022-04-28 19:35:58 +00:00
if ( pdode )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
2016-05-05 17:26:47 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
NewDeviceObject - > Flags | = DO_DIRECT_IO ;
2017-09-08 08:02:43 +00:00
// Some programs seem to expect that the sector size will be 512, for
// FILE_NO_INTERMEDIATE_BUFFERING and the like.
NewDeviceObject - > SectorSize = min ( DeviceToMount - > SectorSize , 512 ) ;
2016-03-23 20:35:05 +00:00
Vcb = ( PVOID ) NewDeviceObject - > DeviceExtension ;
RtlZeroMemory ( Vcb , sizeof ( device_extension ) ) ;
2017-09-08 08:02:43 +00:00
Vcb - > type = VCB_TYPE_FS ;
Vcb - > vde = vde ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > tree_lock ) ;
2019-09-01 12:53:20 +00:00
Vcb - > need_write = false ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > fcb_lock ) ;
2019-05-11 09:20:02 +00:00
ExInitializeResourceLite ( & Vcb - > fileref_lock ) ;
2016-07-27 19:24:26 +00:00
ExInitializeResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExInitializeResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExInitializeResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExInitializeResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
ExInitializeResourceLite ( & Vcb - > load_lock ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > load_lock , true ) ;
2016-03-23 20:35:05 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
DeviceToMount - > Flags | = DO_DIRECT_IO ;
2019-09-01 12:53:20 +00:00
Status = read_superblock ( Vcb , readobj , fileobj , readobjsize ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2017-09-08 08:02:43 +00:00
if ( ! IoIsErrorUserInduced ( Status ) )
Status = STATUS_UNRECOGNIZED_VOLUME ;
else if ( Irp - > Tail . Overlay . Thread )
IoSetHardErrorOrVerifyDevice ( Irp , readobj ) ;
2022-04-28 19:35:58 +00:00
if ( pdode )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
if ( ! vde & & Vcb - > superblock . num_devices > 1 ) {
ERR ( " cannot mount multi-device FS with non-PNP device \n " ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_UNRECOGNIZED_VOLUME ;
2022-04-28 19:35:58 +00:00
if ( pdode )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2016-09-04 15:27:46 +00:00
Status = registry_load_volume_options ( Vcb ) ;
2016-07-27 19:24:26 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " registry_load_volume_options returned %08lx \n " , Status ) ;
2022-04-28 19:35:58 +00:00
if ( pdode )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2016-07-27 19:24:26 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( pdode & & RtlCompareMemory ( & boot_uuid , & pdode - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) & & boot_subvol ! = 0 )
Vcb - > options . subvol_id = boot_subvol ;
2017-09-08 08:02:43 +00:00
if ( pdode & & pdode - > children_loaded < pdode - > num_children & & ( ! Vcb - > options . allow_degraded | | ! finished_probing | | degraded_wait ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " could not mount as %I64u device(s) missing \n " , pdode - > num_children - pdode - > children_loaded ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_DEVICE_NOT_READY ;
2022-04-28 19:35:58 +00:00
ExReleaseResourceLite ( & pdode - > child_lock ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
2022-04-28 19:35:58 +00:00
if ( pdode ) {
// Windows holds DeviceObject->DeviceLock, guaranteeing that mount_vol is serialized
ExReleaseResourceLite ( & pdode - > child_lock ) ;
}
2016-07-27 19:24:26 +00:00
if ( Vcb - > options . ignore ) {
TRACE ( " ignoring volume \n " ) ;
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit ;
}
2016-03-23 20:35:05 +00:00
if ( Vcb - > superblock . incompat_flags & ~ INCOMPAT_SUPPORTED ) {
2019-09-01 12:53:20 +00:00
WARN ( " cannot mount because of unsupported incompat flags (%I64x) \n " , Vcb - > superblock . incompat_flags & ~ INCOMPAT_SUPPORTED ) ;
2016-03-23 20:35:05 +00:00
Status = STATUS_UNRECOGNIZED_VOLUME ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( ! ( Vcb - > superblock . incompat_flags & BTRFS_INCOMPAT_FLAGS_METADATA_UUID ) )
Vcb - > superblock . metadata_uuid = Vcb - > superblock . uuid ;
2019-09-01 12:53:20 +00:00
Vcb - > readonly = false ;
2016-03-23 20:35:05 +00:00
if ( Vcb - > superblock . compat_ro_flags & ~ COMPAT_RO_SUPPORTED ) {
2019-09-01 12:53:20 +00:00
WARN ( " mounting read-only because of unsupported flags (%I64x) \n " , Vcb - > superblock . compat_ro_flags & ~ COMPAT_RO_SUPPORTED ) ;
Vcb - > readonly = true ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( Vcb - > options . readonly )
2019-09-01 12:53:20 +00:00
Vcb - > readonly = true ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
calculate_sector_shift ( Vcb ) ;
2016-03-23 20:35:05 +00:00
Vcb - > superblock . generation + + ;
Vcb - > superblock . incompat_flags | = BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( Vcb - > superblock . log_tree_addr ! = 0 ) {
FIXME ( " FIXME - replay transaction log (clearing for now) \n " ) ;
Vcb - > superblock . log_tree_addr = 0 ;
}
switch ( Vcb - > superblock . csum_type ) {
case CSUM_TYPE_CRC32C :
Vcb - > csum_size = sizeof ( uint32_t ) ;
break ;
case CSUM_TYPE_XXHASH :
Vcb - > csum_size = sizeof ( uint64_t ) ;
break ;
case CSUM_TYPE_SHA256 :
Vcb - > csum_size = SHA256_HASH_SIZE ;
break ;
case CSUM_TYPE_BLAKE2 :
Vcb - > csum_size = BLAKE2_HASH_SIZE ;
break ;
default :
ERR ( " unrecognized csum type %x \n " , Vcb - > superblock . csum_type ) ;
break ;
}
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > devices ) ;
dev = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( device ) , ALLOC_TAG ) ;
if ( ! dev ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
dev - > devobj = readobj ;
2019-09-01 12:53:20 +00:00
dev - > fileobj = fileobj ;
2017-01-01 17:12:12 +00:00
RtlCopyMemory ( & dev - > devitem , & Vcb - > superblock . dev_item , sizeof ( DEV_ITEM ) ) ;
2017-09-08 08:02:43 +00:00
if ( dev - > devitem . num_bytes > readobjsize ) {
2019-09-01 12:53:20 +00:00
WARN ( " device %I64x: DEV_ITEM says %I64x bytes, but Windows only reports %I64x \n " , dev - > devitem . dev_id ,
2017-09-08 08:02:43 +00:00
dev - > devitem . num_bytes , readobjsize ) ;
dev - > devitem . num_bytes = readobjsize ;
}
2019-09-01 12:53:20 +00:00
dev - > seeding = Vcb - > superblock . flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? true : false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
init_device ( Vcb , dev , true ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
InsertTailList ( & Vcb - > devices , & dev - > list_entry ) ;
2016-07-27 19:24:26 +00:00
Vcb - > devices_loaded = 1 ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( DeviceToMount - > Flags & DO_SYSTEM_BOOT_PARTITION )
2019-09-01 12:53:20 +00:00
Vcb - > disallow_dismount = true ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " DeviceToMount = %p \n " , DeviceToMount ) ;
2017-01-01 17:12:12 +00:00
TRACE ( " IrpSp->Parameters.MountVolume.Vpb = %p \n " , IrpSp - > Parameters . MountVolume . Vpb ) ;
2016-03-23 20:35:05 +00:00
NewDeviceObject - > StackSize = DeviceToMount - > StackSize + 1 ;
NewDeviceObject - > Flags & = ~ DO_DEVICE_INITIALIZING ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
InitializeListHead ( & Vcb - > roots ) ;
InitializeListHead ( & Vcb - > drop_roots ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Vcb - > log_to_phys_loaded = false ;
2017-09-08 08:02:43 +00:00
add_root ( Vcb , BTRFS_ROOT_CHUNK , Vcb - > superblock . chunk_tree_addr , Vcb - > superblock . chunk_root_generation , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > chunk_root ) {
ERR ( " Could not load chunk root. \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > sys_chunks ) ;
Status = load_sys_chunks ( Vcb ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_sys_chunks returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > chunks ) ;
InitializeListHead ( & Vcb - > trees ) ;
2017-01-01 17:12:12 +00:00
InitializeListHead ( & Vcb - > trees_hash ) ;
2016-07-27 19:24:26 +00:00
InitializeListHead ( & Vcb - > all_fcbs ) ;
InitializeListHead ( & Vcb - > dirty_fcbs ) ;
InitializeListHead ( & Vcb - > dirty_filerefs ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & Vcb - > dirty_subvols ) ;
InitializeListHead ( & Vcb - > send_ops ) ;
2019-05-11 09:20:02 +00:00
ExInitializeFastMutex ( & Vcb - > trees_list_mutex ) ;
2016-03-23 20:35:05 +00:00
InitializeListHead ( & Vcb - > DirNotifyList ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & Vcb - > scrub . errors ) ;
2016-03-23 20:35:05 +00:00
FsRtlNotifyInitializeSync ( & Vcb - > NotifySync ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
ExInitializePagedLookasideList ( & Vcb - > tree_data_lookaside , NULL , NULL , 0 , sizeof ( tree_data ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > traverse_ptr_lookaside , NULL , NULL , 0 , sizeof ( traverse_ptr ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > batch_item_lookaside , NULL , NULL , 0 , sizeof ( batch_item ) , ALLOC_TAG , 0 ) ;
2017-09-08 08:02:43 +00:00
ExInitializePagedLookasideList ( & Vcb - > fileref_lookaside , NULL , NULL , 0 , sizeof ( file_ref ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > fcb_lookaside , NULL , NULL , 0 , sizeof ( fcb ) , ALLOC_TAG , 0 ) ;
ExInitializePagedLookasideList ( & Vcb - > name_bit_lookaside , NULL , NULL , 0 , sizeof ( name_bit ) , ALLOC_TAG , 0 ) ;
2016-10-29 17:05:10 +00:00
ExInitializeNPagedLookasideList ( & Vcb - > range_lock_lookaside , NULL , NULL , 0 , sizeof ( range_lock ) , ALLOC_TAG , 0 ) ;
2017-09-08 08:02:43 +00:00
ExInitializeNPagedLookasideList ( & Vcb - > fcb_np_lookaside , NULL , NULL , 0 , sizeof ( fcb_nonpaged ) , ALLOC_TAG , 0 ) ;
2019-09-01 12:53:20 +00:00
init_lookaside = true ;
2017-09-08 08:02:43 +00:00
Vcb - > Vpb = IrpSp - > Parameters . MountVolume . Vpb ;
2016-09-04 15:27:46 +00:00
Status = load_chunk_root ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_chunk_root returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > superblock . num_devices > 1 ) {
2017-09-08 08:02:43 +00:00
if ( Vcb - > devices_loaded < Vcb - > superblock . num_devices & & ( ! Vcb - > options . allow_degraded | | ! finished_probing ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " could not mount as %I64u device(s) missing \n " , Vcb - > superblock . num_devices - Vcb - > devices_loaded ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
IoRaiseInformationalHardError ( IO_ERR_INTERNAL_ERROR , NULL , NULL ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev - > readonly & & ! Vcb - > readonly ) {
2019-09-01 12:53:20 +00:00
Vcb - > readonly = true ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( dev2 - > readonly & & ! dev2 - > seeding )
2016-10-29 17:05:10 +00:00
break ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
if ( ! dev2 - > readonly ) {
2019-09-01 12:53:20 +00:00
Vcb - > readonly = false ;
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( Vcb - > readonly )
WARN ( " setting volume to readonly \n " ) ;
}
} else {
2017-01-01 17:12:12 +00:00
if ( dev - > readonly ) {
2016-10-29 17:05:10 +00:00
WARN ( " setting volume to readonly as device is readonly \n " ) ;
2019-09-01 12:53:20 +00:00
Vcb - > readonly = true ;
2016-10-29 17:05:10 +00:00
}
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
add_root ( Vcb , BTRFS_ROOT_ROOT , Vcb - > superblock . root_tree_addr , Vcb - > superblock . generation - 1 , NULL ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > root_root ) {
ERR ( " Could not load root of roots. \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = look_for_roots ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " look_for_roots returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > readonly ) {
Status = find_chunk_usage ( Vcb , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_chunk_usage returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
InitializeListHead ( & batchlist ) ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
// We've already increased the generation by one
2017-09-08 08:02:43 +00:00
if ( ! Vcb - > readonly & & (
Vcb - > options . clear_cache | |
( ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE ) & & Vcb - > superblock . generation - 1 ! = Vcb - > superblock . cache_generation ) | |
( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE & & ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID ) ) ) ) {
if ( Vcb - > options . clear_cache )
WARN ( " ClearCache option was set, clearing cache... \n " ) ;
else if ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE & & ! ( Vcb - > superblock . compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID ) )
WARN ( " clearing free-space tree created by buggy Linux driver \n " ) ;
else
2019-09-01 12:53:20 +00:00
WARN ( " generation was %I64x, free-space cache generation was %I64x; clearing cache... \n " , Vcb - > superblock . generation - 1 , Vcb - > superblock . cache_generation ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
Status = clear_free_space_cache ( Vcb , & batchlist , Irp ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " clear_free_space_cache returned %08lx \n " , Status ) ;
2016-10-29 17:05:10 +00:00
clear_batch_list ( Vcb , & batchlist ) ;
2016-05-05 17:26:47 +00:00
goto exit ;
}
}
2017-09-08 08:02:43 +00:00
Status = commit_batch_list ( Vcb , & batchlist , Irp ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " commit_batch_list returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
Vcb - > volume_fcb = create_fcb ( Vcb , NonPagedPool ) ;
2016-03-23 20:35:05 +00:00
if ( ! Vcb - > volume_fcb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Vcb - > volume_fcb - > Vcb = Vcb ;
Vcb - > volume_fcb - > sd = NULL ;
2017-09-08 08:02:43 +00:00
Vcb - > dummy_fcb = create_fcb ( Vcb , NonPagedPool ) ;
if ( ! Vcb - > dummy_fcb ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
Vcb - > dummy_fcb - > Vcb = Vcb ;
Vcb - > dummy_fcb - > type = BTRFS_TYPE_DIRECTORY ;
Vcb - > dummy_fcb - > inode = 2 ;
Vcb - > dummy_fcb - > subvol = Vcb - > root_root ;
Vcb - > dummy_fcb - > atts = FILE_ATTRIBUTE_DIRECTORY ;
Vcb - > dummy_fcb - > inode_item . st_nlink = 1 ;
Vcb - > dummy_fcb - > inode_item . st_mode = __S_IFDIR ;
Vcb - > dummy_fcb - > hash_ptrs = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! Vcb - > dummy_fcb - > hash_ptrs ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
RtlZeroMemory ( Vcb - > dummy_fcb - > hash_ptrs , sizeof ( LIST_ENTRY * ) * 256 ) ;
Vcb - > dummy_fcb - > hash_ptrs_uc = ExAllocatePoolWithTag ( PagedPool , sizeof ( LIST_ENTRY * ) * 256 , ALLOC_TAG ) ;
if ( ! Vcb - > dummy_fcb - > hash_ptrs_uc ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
RtlZeroMemory ( Vcb - > dummy_fcb - > hash_ptrs_uc , sizeof ( LIST_ENTRY * ) * 256 ) ;
root_fcb = create_fcb ( Vcb , NonPagedPool ) ;
2016-05-05 17:26:47 +00:00
if ( ! root_fcb ) {
2016-03-23 20:35:05 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
root_fcb - > Vcb = Vcb ;
root_fcb - > inode = SUBVOL_ROOT_INODE ;
2019-09-01 12:53:20 +00:00
root_fcb - > hash = calc_crc32c ( 0xffffffff , ( uint8_t * ) & root_fcb - > inode , sizeof ( uint64_t ) ) ;
2016-05-05 17:26:47 +00:00
root_fcb - > type = BTRFS_TYPE_DIRECTORY ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
# ifdef DEBUG_FCB_REFCOUNTS
WARN ( " volume FCB = %p \n " , Vcb - > volume_fcb ) ;
2016-05-05 17:26:47 +00:00
WARN ( " root FCB = %p \n " , root_fcb ) ;
2016-03-23 20:35:05 +00:00
# endif
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
root_fcb - > subvol = find_default_subvol ( Vcb , Irp ) ;
2016-03-23 20:35:05 +00:00
2016-05-05 17:26:47 +00:00
if ( ! root_fcb - > subvol ) {
2016-03-23 20:35:05 +00:00
ERR ( " could not find top subvol \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = load_dir_children ( Vcb , root_fcb , true , Irp ) ;
2017-01-01 17:12:12 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " load_dir_children returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
searchkey . obj_id = root_fcb - > inode ;
2016-03-23 20:35:05 +00:00
searchkey . obj_type = TYPE_INODE_ITEM ;
searchkey . offset = 0xffffffffffffffff ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = find_item ( Vcb , root_fcb - > subvol , & tp , & searchkey , false , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " error - find_item returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > key . obj_id ! = searchkey . obj_id | | tp . item - > key . obj_type ! = searchkey . obj_type ) {
ERR ( " couldn't find INODE_ITEM for root directory \n " ) ;
Status = STATUS_INTERNAL_ERROR ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( tp . item - > size > 0 )
2016-05-05 17:26:47 +00:00
RtlCopyMemory ( & root_fcb - > inode_item , tp . item - > data , min ( sizeof ( INODE_ITEM ) , tp . item - > size ) ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
fcb_get_sd ( root_fcb , NULL , true , Irp ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
root_fcb - > atts = get_file_attributes ( Vcb , root_fcb - > subvol , root_fcb - > inode , root_fcb - > type , false , false , Irp ) ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( root_fcb - > subvol - > id = = BTRFS_ROOT_FSTREE )
root_fcb - > atts & = ~ FILE_ATTRIBUTE_HIDDEN ;
2017-09-08 08:02:43 +00:00
Vcb - > root_fileref = create_fileref ( Vcb ) ;
2016-05-05 17:26:47 +00:00
if ( ! Vcb - > root_fileref ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
Vcb - > root_fileref - > fcb = root_fcb ;
InsertTailList ( & root_fcb - > subvol - > fcbs , & root_fcb - > list_entry ) ;
2016-07-27 19:24:26 +00:00
InsertTailList ( & Vcb - > all_fcbs , & root_fcb - > list_entry_all ) ;
2017-09-08 08:02:43 +00:00
2019-05-11 09:20:02 +00:00
root_fcb - > subvol - > fcbs_ptrs [ root_fcb - > hash > > 24 ] = & root_fcb - > list_entry ;
2016-07-27 19:24:26 +00:00
root_fcb - > fileref = Vcb - > root_fileref ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
root_ccb = ExAllocatePoolWithTag ( PagedPool , sizeof ( ccb ) , ALLOC_TAG ) ;
if ( ! root_ccb ) {
2016-05-05 17:26:47 +00:00
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Vcb - > root_file = IoCreateStreamFileObject ( NULL , DeviceToMount ) ;
Vcb - > root_file - > FsContext = root_fcb ;
2016-07-27 19:32:05 +00:00
Vcb - > root_file - > SectionObjectPointer = & root_fcb - > nonpaged - > segment_object ;
Vcb - > root_file - > Vpb = DeviceObject - > Vpb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlZeroMemory ( root_ccb , sizeof ( ccb ) ) ;
root_ccb - > NodeType = BTRFS_NODE_TYPE_CCB ;
root_ccb - > NodeSize = sizeof ( ccb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:32:05 +00:00
Vcb - > root_file - > FsContext2 = root_ccb ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:32:05 +00:00
_SEH2_TRY {
2019-11-12 18:32:46 +00:00
CcInitializeCacheMap ( Vcb - > root_file , ( PCC_FILE_SIZES ) ( & root_fcb - > Header . AllocationSize ) , false , & cache_callbacks , Vcb - > root_file ) ;
2016-07-27 19:32:05 +00:00
} _SEH2_EXCEPT ( EXCEPTION_EXECUTE_HANDLER ) {
Status = _SEH2_GetExceptionCode ( ) ;
goto exit ;
} _SEH2_END ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev2 = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = find_disk_holes ( Vcb , dev2 , Irp ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " find_disk_holes returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
IoAcquireVpbSpinLock ( & irql ) ;
2017-01-01 17:12:12 +00:00
NewDeviceObject - > Vpb = IrpSp - > Parameters . MountVolume . Vpb ;
IrpSp - > Parameters . MountVolume . Vpb - > DeviceObject = NewDeviceObject ;
IrpSp - > Parameters . MountVolume . Vpb - > Flags | = VPB_MOUNTED ;
2016-03-23 20:35:05 +00:00
NewDeviceObject - > Vpb - > VolumeLabelLength = 4 ; // FIXME
NewDeviceObject - > Vpb - > VolumeLabel [ 0 ] = ' ? ' ;
NewDeviceObject - > Vpb - > VolumeLabel [ 1 ] = 0 ;
2019-11-12 18:32:46 +00:00
NewDeviceObject - > Vpb - > ReferenceCount + + ;
IoReleaseVpbSpinLock ( irql ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & Vcb - > flush_thread_finished , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
InitializeObjectAttributes ( & oa , NULL , OBJ_KERNEL_HANDLE , NULL , NULL ) ;
Status = PsCreateSystemThread ( & Vcb - > flush_thread_handle , 0 , & oa , NULL , NULL , flush_thread , NewDeviceObject ) ;
2016-05-05 17:26:47 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " PsCreateSystemThread returned %08lx \n " , Status ) ;
2016-05-05 17:26:47 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = create_calc_threads ( NewDeviceObject ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " create_calc_threads returned %08lx \n " , Status ) ;
2017-01-01 17:12:12 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = registry_mark_volume_mounted ( & Vcb - > superblock . uuid ) ;
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " registry_mark_volume_mounted returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = look_for_balance_item ( Vcb ) ;
if ( ! NT_SUCCESS ( Status ) & & Status ! = STATUS_NOT_FOUND )
2020-04-23 02:38:57 +00:00
WARN ( " look_for_balance_item returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
if ( vde )
vde - > mounted_device = NewDeviceObject ;
2019-11-12 18:32:46 +00:00
Vcb - > devobj = NewDeviceObject ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & Vcb - > send_load_lock ) ;
2016-03-23 20:35:05 +00:00
exit :
if ( Vcb ) {
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-03-23 20:35:05 +00:00
ExReleaseResourceLite ( & Vcb - > load_lock ) ;
}
if ( ! NT_SUCCESS ( Status ) ) {
if ( Vcb ) {
2016-10-29 17:05:10 +00:00
if ( init_lookaside ) {
ExDeletePagedLookasideList ( & Vcb - > tree_data_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > traverse_ptr_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > batch_item_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeletePagedLookasideList ( & Vcb - > fileref_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > fcb_lookaside ) ;
ExDeletePagedLookasideList ( & Vcb - > name_bit_lookaside ) ;
2016-10-29 17:05:10 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
2017-09-08 08:02:43 +00:00
ExDeleteNPagedLookasideList ( & Vcb - > fcb_np_lookaside ) ;
2016-10-29 17:05:10 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( Vcb - > root_file )
ObDereferenceObject ( Vcb - > root_file ) ;
2019-05-11 09:20:02 +00:00
else if ( Vcb - > root_fileref )
free_fileref ( Vcb - > root_fileref ) ;
else if ( root_fcb )
free_fcb ( root_fcb ) ;
2016-03-23 20:35:05 +00:00
2019-05-11 09:20:02 +00:00
if ( root_fcb & & root_fcb - > refcount = = 0 )
reap_fcb ( root_fcb ) ;
if ( Vcb - > volume_fcb )
reap_fcb ( Vcb - > volume_fcb ) ;
2016-03-23 20:35:05 +00:00
ExDeleteResourceLite ( & Vcb - > tree_lock ) ;
ExDeleteResourceLite ( & Vcb - > load_lock ) ;
ExDeleteResourceLite ( & Vcb - > fcb_lock ) ;
2019-05-11 09:20:02 +00:00
ExDeleteResourceLite ( & Vcb - > fileref_lock ) ;
2016-07-27 19:24:26 +00:00
ExDeleteResourceLite ( & Vcb - > chunk_lock ) ;
2017-09-08 08:02:43 +00:00
ExDeleteResourceLite ( & Vcb - > dirty_fcbs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_filerefs_lock ) ;
ExDeleteResourceLite ( & Vcb - > dirty_subvols_lock ) ;
ExDeleteResourceLite ( & Vcb - > scrub . stats_lock ) ;
2016-03-23 20:35:05 +00:00
2017-01-01 17:12:12 +00:00
if ( Vcb - > devices . Flink ) {
while ( ! IsListEmpty ( & Vcb - > devices ) ) {
2017-09-08 08:02:43 +00:00
device * dev2 = CONTAINING_RECORD ( RemoveHeadList ( & Vcb - > devices ) , device , list_entry ) ;
ExFreePool ( dev2 ) ;
2017-01-01 17:12:12 +00:00
}
}
2016-03-23 20:35:05 +00:00
}
if ( NewDeviceObject )
IoDeleteDevice ( NewDeviceObject ) ;
2017-01-01 17:12:12 +00:00
} else {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & global_loading_lock , true ) ;
2017-01-01 17:12:12 +00:00
InsertTailList ( & VcbList , & Vcb - > list_entry ) ;
ExReleaseResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
FsRtlNotifyVolumeEvent ( Vcb - > root_file , FSRTL_VOLUME_MOUNT ) ;
2017-01-01 17:12:12 +00:00
}
2016-03-23 20:35:05 +00:00
TRACE ( " mount_vol done (status: %lx) \n " , Status ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
static NTSTATUS verify_device ( _In_ device_extension * Vcb , _Inout_ device * dev ) {
2016-09-04 15:27:46 +00:00
NTSTATUS Status ;
superblock * sb ;
2017-09-08 08:02:43 +00:00
ULONG to_read , cc ;
if ( ! dev - > devobj )
2016-09-04 15:27:46 +00:00
return STATUS_WRONG_VOLUME ;
2017-09-08 08:02:43 +00:00
if ( dev - > removable ) {
IO_STATUS_BLOCK iosb ;
2019-09-01 12:53:20 +00:00
Status = dev_ioctl ( dev - > devobj , IOCTL_STORAGE_CHECK_VERIFY , NULL , 0 , & cc , sizeof ( ULONG ) , true , & iosb ) ;
2017-09-08 08:02:43 +00:00
if ( IoIsErrorUserInduced ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08lx (user-induced) \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb - > vde ) {
pdo_device_extension * pdode = Vcb - > vde - > pdode ;
LIST_ENTRY * le2 ;
2019-09-01 12:53:20 +00:00
bool changed = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & pdode - > child_lock , true ) ;
2017-09-08 08:02:43 +00:00
le2 = pdode - > children . Flink ;
while ( le2 ! = & pdode - > children ) {
volume_child * vc = CONTAINING_RECORD ( le2 , volume_child , list_entry ) ;
if ( vc - > devobj = = dev - > devobj ) {
TRACE ( " removing device \n " ) ;
2019-09-01 12:53:20 +00:00
remove_volume_child ( Vcb - > vde , vc , true ) ;
changed = true ;
2017-09-08 08:02:43 +00:00
break ;
}
le2 = le2 - > Flink ;
}
if ( ! changed )
ExReleaseResourceLite ( & pdode - > child_lock ) ;
}
} else if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IOCTL_STORAGE_CHECK_VERIFY returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
} else if ( iosb . Information < sizeof ( ULONG ) ) {
ERR ( " iosb.Information was too short \n " ) ;
return STATUS_INTERNAL_ERROR ;
}
dev - > change_count = cc ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
to_read = dev - > devobj - > SectorSize = = 0 ? sizeof ( superblock ) : ( ULONG ) sector_align ( sizeof ( superblock ) , dev - > devobj - > SectorSize ) ;
2016-09-04 15:27:46 +00:00
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = sync_read_phys ( dev - > devobj , dev - > fileobj , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , true ) ;
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " Failed to read superblock: %08lx \n " , Status ) ;
2016-09-04 15:27:46 +00:00
ExFreePool ( sb ) ;
return Status ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( sb - > magic ! = BTRFS_MAGIC ) {
ERR ( " not a BTRFS volume \n " ) ;
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( ! check_superblock_checksum ( sb ) ) {
2017-09-08 08:02:43 +00:00
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
if ( RtlCompareMemory ( & sb - > uuid , & Vcb - > superblock . uuid , sizeof ( BTRFS_UUID ) ) ! = sizeof ( BTRFS_UUID ) ) {
2016-09-04 15:27:46 +00:00
ERR ( " different UUIDs \n " ) ;
ExFreePool ( sb ) ;
return STATUS_WRONG_VOLUME ;
}
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
ExFreePool ( sb ) ;
2017-09-08 08:02:43 +00:00
dev - > devobj - > Flags & = ~ DO_VERIFY_VOLUME ;
return STATUS_SUCCESS ;
}
static NTSTATUS verify_volume ( _In_ PDEVICE_OBJECT devobj ) {
device_extension * Vcb = devobj - > DeviceExtension ;
NTSTATUS Status ;
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
uint64_t failed_devices = 0 ;
bool locked = false , remove = false ;
2017-09-08 08:02:43 +00:00
if ( ! ( Vcb - > Vpb - > Flags & VPB_MOUNTED ) )
return STATUS_WRONG_VOLUME ;
if ( ! ExIsResourceAcquiredExclusive ( & Vcb - > tree_lock ) ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
locked = true ;
2017-09-08 08:02:43 +00:00
}
if ( Vcb - > removing ) {
if ( locked ) ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
return STATUS_WRONG_VOLUME ;
}
2022-04-28 19:31:44 +00:00
Status = STATUS_SUCCESS ;
2017-09-08 08:02:43 +00:00
InterlockedIncrement ( & Vcb - > open_files ) ; // so pnp_surprise_removal doesn't uninit the device while we're still using it
2017-01-01 17:12:12 +00:00
le = Vcb - > devices . Flink ;
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
2017-09-08 08:02:43 +00:00
Status = verify_device ( Vcb , dev ) ;
if ( ! NT_SUCCESS ( Status ) ) {
failed_devices + + ;
if ( dev - > devobj & & Vcb - > options . allow_degraded )
dev - > devobj = NULL ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
le = le - > Flink ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
InterlockedDecrement ( & Vcb - > open_files ) ;
if ( Vcb - > removing & & Vcb - > open_files = = 0 )
2019-09-01 12:53:20 +00:00
remove = true ;
2017-09-08 08:02:43 +00:00
if ( locked )
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
if ( remove ) {
2018-12-16 11:03:16 +00:00
uninit ( Vcb ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
if ( failed_devices = = 0 | | ( Vcb - > options . allow_degraded & & failed_devices < Vcb - > superblock . num_devices ) ) {
Vcb - > Vpb - > RealDevice - > Flags & = ~ DO_VERIFY_VOLUME ;
return STATUS_SUCCESS ;
}
return Status ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_FILE_SYSTEM_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_file_system_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
PIO_STACK_LOCATION IrpSp ;
2016-07-27 19:24:26 +00:00
NTSTATUS Status ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " file system control \n " ) ;
2016-03-23 20:35:05 +00:00
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
2017-09-08 08:02:43 +00:00
goto end ;
} else if ( ! Vcb | | ( Vcb - > type ! = VCB_TYPE_FS & & Vcb - > type ! = VCB_TYPE_CONTROL ) ) {
Status = STATUS_INVALID_PARAMETER ;
goto end ;
2016-07-27 19:24:26 +00:00
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = STATUS_NOT_IMPLEMENTED ;
2016-03-23 20:35:05 +00:00
IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Irp - > IoStatus . Information = 0 ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
switch ( IrpSp - > MinorFunction ) {
case IRP_MN_MOUNT_VOLUME :
TRACE ( " IRP_MN_MOUNT_VOLUME \n " ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
Status = mount_vol ( DeviceObject , Irp ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_KERNEL_CALL :
TRACE ( " IRP_MN_KERNEL_CALL \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fsctl_request ( DeviceObject , & Irp , IrpSp - > Parameters . FileSystemControl . FsControlCode ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_USER_FS_REQUEST :
TRACE ( " IRP_MN_USER_FS_REQUEST \n " ) ;
2017-09-08 08:02:43 +00:00
Status = fsctl_request ( DeviceObject , & Irp , IrpSp - > Parameters . FileSystemControl . FsControlCode ) ;
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
case IRP_MN_VERIFY_VOLUME :
2016-09-04 15:27:46 +00:00
TRACE ( " IRP_MN_VERIFY_VOLUME \n " ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
Status = verify_volume ( DeviceObject ) ;
2017-09-08 08:02:43 +00:00
2016-09-04 15:27:46 +00:00
if ( ! NT_SUCCESS ( Status ) & & Vcb - > Vpb - > Flags & VPB_MOUNTED ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
Vcb - > removing = true ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
2016-09-04 15:27:46 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
break ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
default :
break ;
}
2017-09-08 08:02:43 +00:00
end :
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
if ( Irp ) {
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
}
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
2016-07-27 19:24:26 +00:00
return Status ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_LOCK_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_lock_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2019-11-12 18:32:46 +00:00
fcb * fcb = IrpSp - > FileObject ? IrpSp - > FileObject - > FsContext : NULL ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
2017-09-08 08:02:43 +00:00
Irp - > IoStatus . Status = Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2016-07-27 19:24:26 +00:00
goto exit ;
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
TRACE ( " lock control \n " ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
if ( ! fcb ) {
ERR ( " fcb was NULL \n " ) ;
Status = STATUS_INVALID_PARAMETER ;
goto exit ;
}
FsRtlCheckOplock ( fcb_oplock ( fcb ) , Irp , NULL , NULL , NULL ) ;
2016-03-23 20:35:05 +00:00
Status = FsRtlProcessFileLock ( & fcb - > lock , Irp , NULL ) ;
2016-05-05 17:26:47 +00:00
fcb - > Header . IsFastIoPossible = fast_io_possible ( fcb ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
exit :
2020-04-23 02:38:57 +00:00
TRACE ( " returning %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
return Status ;
}
2019-11-12 18:32:46 +00:00
void do_shutdown ( PIRP Irp ) {
2018-12-16 11:03:16 +00:00
LIST_ENTRY * le ;
2019-11-12 18:32:46 +00:00
bus_device_extension * bde ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
shutting_down = true ;
KeSetEvent ( & mountmgr_thread_event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
le = VcbList . Flink ;
while ( le ! = & VcbList ) {
LIST_ENTRY * le2 = le - > Flink ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
device_extension * Vcb = CONTAINING_RECORD ( le , device_extension , list_entry ) ;
volume_device_extension * vde = Vcb - > vde ;
2020-04-23 02:38:57 +00:00
PDEVICE_OBJECT devobj = vde ? vde - > device : NULL ;
2018-08-12 16:31:15 +00:00
TRACE ( " shutting down Vcb %p \n " , Vcb ) ;
2019-11-12 18:32:46 +00:00
if ( vde )
InterlockedIncrement ( & vde - > open_count ) ;
2018-08-12 16:31:15 +00:00
2020-04-23 02:38:57 +00:00
if ( devobj )
ObReferenceObject ( devobj ) ;
2019-11-12 18:32:46 +00:00
dismount_volume ( Vcb , true , Irp ) ;
if ( vde ) {
NTSTATUS Status ;
UNICODE_STRING mmdevpath ;
PDEVICE_OBJECT mountmgr ;
PFILE_OBJECT mountmgrfo ;
KIRQL irql ;
2020-04-23 02:38:57 +00:00
PVPB newvpb ;
2019-11-12 18:32:46 +00:00
RtlInitUnicodeString ( & mmdevpath , MOUNTMGR_DEVICE_NAME ) ;
Status = IoGetDeviceObjectPointer ( & mmdevpath , FILE_READ_ATTRIBUTES , & mountmgrfo , & mountmgr ) ;
2018-08-12 16:31:15 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " IoGetDeviceObjectPointer returned %08lx \n " , Status ) ;
2019-11-12 18:32:46 +00:00
else {
remove_drive_letter ( mountmgr , & vde - > name ) ;
ObDereferenceObject ( mountmgrfo ) ;
}
2018-08-12 16:31:15 +00:00
2019-11-12 18:32:46 +00:00
vde - > removing = true ;
2018-08-12 16:31:15 +00:00
2020-04-23 02:38:57 +00:00
newvpb = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( VPB ) , ALLOC_TAG ) ;
if ( ! newvpb ) {
ERR ( " out of memory \n " ) ;
return ;
}
RtlZeroMemory ( newvpb , sizeof ( VPB ) ) ;
newvpb - > Type = IO_TYPE_VPB ;
newvpb - > Size = sizeof ( VPB ) ;
newvpb - > RealDevice = newvpb - > DeviceObject = vde - > device ;
newvpb - > Flags = VPB_DIRECT_WRITES_ALLOWED ;
2019-11-12 18:32:46 +00:00
IoAcquireVpbSpinLock ( & irql ) ;
2020-04-23 02:38:57 +00:00
vde - > device - > Vpb = newvpb ;
2019-11-12 18:32:46 +00:00
IoReleaseVpbSpinLock ( irql ) ;
2018-12-16 11:03:16 +00:00
2019-11-12 18:32:46 +00:00
if ( InterlockedDecrement ( & vde - > open_count ) = = 0 )
free_vol ( vde ) ;
}
2018-12-16 11:03:16 +00:00
2020-04-23 02:38:57 +00:00
if ( devobj )
ObDereferenceObject ( devobj ) ;
2018-12-16 11:03:16 +00:00
le = le2 ;
2018-08-12 16:31:15 +00:00
}
2017-09-08 08:02:43 +00:00
# ifdef _DEBUG
if ( comfo ) {
ObDereferenceObject ( comfo ) ;
comdo = NULL ;
comfo = NULL ;
}
# endif
2019-11-12 18:32:46 +00:00
IoUnregisterFileSystem ( master_devobj ) ;
if ( notification_entry2 ) {
if ( fIoUnregisterPlugPlayNotificationEx )
fIoUnregisterPlugPlayNotificationEx ( notification_entry2 ) ;
else
IoUnregisterPlugPlayNotification ( notification_entry2 ) ;
notification_entry2 = NULL ;
}
if ( notification_entry3 ) {
if ( fIoUnregisterPlugPlayNotificationEx )
fIoUnregisterPlugPlayNotificationEx ( notification_entry3 ) ;
else
IoUnregisterPlugPlayNotification ( notification_entry3 ) ;
notification_entry3 = NULL ;
}
if ( notification_entry ) {
if ( fIoUnregisterPlugPlayNotificationEx )
fIoUnregisterPlugPlayNotificationEx ( notification_entry ) ;
else
IoUnregisterPlugPlayNotification ( notification_entry ) ;
notification_entry = NULL ;
}
bde = busobj - > DeviceExtension ;
if ( bde - > attached_device )
IoDetachDevice ( bde - > attached_device ) ;
IoDeleteDevice ( busobj ) ;
IoDeleteDevice ( master_devobj ) ;
}
_Dispatch_type_ ( IRP_MJ_SHUTDOWN )
_Function_class_ ( DRIVER_DISPATCH )
static NTSTATUS __stdcall drv_shutdown ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
NTSTATUS Status ;
bool top_level ;
device_extension * Vcb = DeviceObject - > DeviceExtension ;
FsRtlEnterFileSystem ( ) ;
TRACE ( " shutdown \n " ) ;
top_level = is_top_level ( Irp ) ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2022-04-28 19:33:48 +00:00
Status = STATUS_INVALID_DEVICE_REQUEST ;
2019-11-12 18:32:46 +00:00
goto end ;
}
Status = STATUS_SUCCESS ;
do_shutdown ( Irp ) ;
2017-09-08 08:02:43 +00:00
end :
Irp - > IoStatus . Status = Status ;
Irp - > IoStatus . Information = 0 ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
if ( top_level )
IoSetTopLevelIrp ( NULL ) ;
FsRtlExitFileSystem ( ) ;
2016-07-27 19:24:26 +00:00
return Status ;
}
2020-04-23 02:38:57 +00:00
static bool device_still_valid ( device * dev , uint64_t expected_generation ) {
NTSTATUS Status ;
unsigned int to_read ;
superblock * sb ;
to_read = ( unsigned int ) ( dev - > devobj - > SectorSize = = 0 ? sizeof ( superblock ) : sector_align ( sizeof ( superblock ) , dev - > devobj - > SectorSize ) ) ;
sb = ExAllocatePoolWithTag ( NonPagedPool , to_read , ALLOC_TAG ) ;
if ( ! sb ) {
ERR ( " out of memory \n " ) ;
return false ;
}
Status = sync_read_phys ( dev - > devobj , dev - > fileobj , superblock_addrs [ 0 ] , to_read , ( PUCHAR ) sb , false ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " sync_read_phys returned %08lx \n " , Status ) ;
ExFreePool ( sb ) ;
return false ;
}
if ( sb - > magic ! = BTRFS_MAGIC ) {
ERR ( " magic not found \n " ) ;
ExFreePool ( sb ) ;
return false ;
}
if ( ! check_superblock_checksum ( sb ) ) {
ExFreePool ( sb ) ;
return false ;
}
if ( sb - > generation > expected_generation ) {
ERR ( " generation was %I64x, expected %I64x \n " , sb - > generation , expected_generation ) ;
ExFreePool ( sb ) ;
return false ;
}
ExFreePool ( sb ) ;
return true ;
}
_Function_class_ ( IO_WORKITEM_ROUTINE )
static void __stdcall check_after_wakeup ( PDEVICE_OBJECT DeviceObject , PVOID con ) {
device_extension * Vcb = ( device_extension * ) con ;
LIST_ENTRY * le ;
UNUSED ( DeviceObject ) ;
ExAcquireResourceExclusiveLite ( & Vcb - > tree_lock , true ) ;
le = Vcb - > devices . Flink ;
// FIXME - do reads in parallel?
while ( le ! = & Vcb - > devices ) {
device * dev = CONTAINING_RECORD ( le , device , list_entry ) ;
if ( dev - > devobj ) {
if ( ! device_still_valid ( dev , Vcb - > superblock . generation - 1 ) ) {
PDEVICE_OBJECT voldev = Vcb - > Vpb - > RealDevice ;
KIRQL irql ;
PVPB newvpb ;
WARN ( " forcing remount \n " ) ;
newvpb = ExAllocatePoolWithTag ( NonPagedPool , sizeof ( VPB ) , ALLOC_TAG ) ;
if ( ! newvpb ) {
ERR ( " out of memory \n " ) ;
return ;
}
RtlZeroMemory ( newvpb , sizeof ( VPB ) ) ;
newvpb - > Type = IO_TYPE_VPB ;
newvpb - > Size = sizeof ( VPB ) ;
newvpb - > RealDevice = voldev ;
newvpb - > Flags = VPB_DIRECT_WRITES_ALLOWED ;
Vcb - > removing = true ;
IoAcquireVpbSpinLock ( & irql ) ;
voldev - > Vpb = newvpb ;
IoReleaseVpbSpinLock ( irql ) ;
Vcb - > vde = NULL ;
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
if ( Vcb - > open_files = = 0 )
uninit ( Vcb ) ;
else { // remove from VcbList
ExAcquireResourceExclusiveLite ( & global_loading_lock , true ) ;
RemoveEntryList ( & Vcb - > list_entry ) ;
Vcb - > list_entry . Flink = NULL ;
ExReleaseResourceLite ( & global_loading_lock ) ;
}
return ;
}
}
le = le - > Flink ;
}
ExReleaseResourceLite ( & Vcb - > tree_lock ) ;
}
2017-09-08 08:02:43 +00:00
_Dispatch_type_ ( IRP_MJ_POWER )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_power ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2019-09-01 12:53:20 +00:00
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation ( Irp ) ;
2017-09-08 08:02:43 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
// no need for FsRtlEnterFileSystem, as this only ever gets called in a system thread
2017-09-08 08:02:43 +00:00
top_level = is_top_level ( Irp ) ;
Irp - > IoStatus . Information = 0 ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
2019-09-01 12:53:20 +00:00
volume_device_extension * vde = DeviceObject - > DeviceExtension ;
2017-09-08 08:02:43 +00:00
2020-04-23 02:38:57 +00:00
if ( IrpSp - > MinorFunction = = IRP_MN_QUERY_POWER & & IrpSp - > Parameters . Power . Type = = SystemPowerState & &
IrpSp - > Parameters . Power . State . SystemState ! = PowerSystemWorking & & vde - > mounted_device ) {
device_extension * Vcb2 = vde - > mounted_device - > DeviceExtension ;
/* If power state is about to go to sleep or hibernate, do a flush. We do this on IRP_MJ_QUERY_POWER
* rather than IRP_MJ_SET_POWER because we know that the hard disks are still awake . */
if ( Vcb2 ) {
ExAcquireResourceExclusiveLite ( & Vcb2 - > tree_lock , true ) ;
if ( Vcb2 - > need_write & & ! Vcb2 - > readonly ) {
TRACE ( " doing protective flush on power state change \n " ) ;
Status = do_write ( Vcb2 , NULL ) ;
} else
Status = STATUS_SUCCESS ;
free_trees ( Vcb2 ) ;
if ( ! NT_SUCCESS ( Status ) )
ERR ( " do_write returned %08lx \n " , Status ) ;
ExReleaseResourceLite ( & Vcb2 - > tree_lock ) ;
}
} else if ( IrpSp - > MinorFunction = = IRP_MN_SET_POWER & & IrpSp - > Parameters . Power . Type = = SystemPowerState & &
IrpSp - > Parameters . Power . State . SystemState = = PowerSystemWorking & & vde - > mounted_device ) {
device_extension * Vcb2 = vde - > mounted_device - > DeviceExtension ;
/* If waking up, make sure that the FS hasn't been changed while we've been out (e.g., by dual-boot Linux) */
if ( Vcb2 ) {
PIO_WORKITEM work_item ;
work_item = IoAllocateWorkItem ( DeviceObject ) ;
if ( ! work_item ) {
ERR ( " out of memory \n " ) ;
} else
IoQueueWorkItem ( work_item , check_after_wakeup , DelayedWorkQueue , Vcb2 ) ;
}
}
2019-09-01 12:53:20 +00:00
PoStartNextPowerIrp ( Irp ) ;
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = PoCallDriver ( vde - > attached_device , Irp ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_FS ) {
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = IoCallDriver ( Vcb - > Vpb - > RealDevice , Irp ) ;
2019-09-01 12:53:20 +00:00
goto exit ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_BUS ) {
bus_device_extension * bde = DeviceObject - > DeviceExtension ;
PoStartNextPowerIrp ( Irp ) ;
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = PoCallDriver ( bde - > attached_device , Irp ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
}
2019-09-01 12:53:20 +00:00
if ( IrpSp - > MinorFunction = = IRP_MN_SET_POWER | | IrpSp - > MinorFunction = = IRP_MN_QUERY_POWER )
Irp - > IoStatus . Status = STATUS_SUCCESS ;
Status = Irp - > IoStatus . Status ;
PoStartNextPowerIrp ( Irp ) ;
2017-09-08 08:02:43 +00:00
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
exit :
if ( top_level )
IoSetTopLevelIrp ( NULL ) ;
return Status ;
}
_Dispatch_type_ ( IRP_MJ_SYSTEM_CONTROL )
_Function_class_ ( DRIVER_DISPATCH )
2019-09-01 12:53:20 +00:00
static NTSTATUS __stdcall drv_system_control ( _In_ PDEVICE_OBJECT DeviceObject , _In_ PIRP Irp ) {
2017-09-08 08:02:43 +00:00
NTSTATUS Status ;
2016-07-27 19:24:26 +00:00
device_extension * Vcb = DeviceObject - > DeviceExtension ;
2019-09-01 12:53:20 +00:00
bool top_level ;
2016-03-23 20:35:05 +00:00
FsRtlEnterFileSystem ( ) ;
top_level = is_top_level ( Irp ) ;
2017-09-08 08:02:43 +00:00
Irp - > IoStatus . Information = 0 ;
if ( Vcb & & Vcb - > type = = VCB_TYPE_VOLUME ) {
volume_device_extension * vde = DeviceObject - > DeviceExtension ;
IoSkipCurrentIrpStackLocation ( Irp ) ;
2019-09-01 12:53:20 +00:00
Status = IoCallDriver ( vde - > attached_device , Irp ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
goto exit ;
2017-09-08 08:02:43 +00:00
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_FS ) {
IoSkipCurrentIrpStackLocation ( Irp ) ;
2016-03-23 20:35:05 +00:00
2017-09-08 08:02:43 +00:00
Status = IoCallDriver ( Vcb - > Vpb - > RealDevice , Irp ) ;
2019-09-01 12:53:20 +00:00
goto exit ;
} else if ( Vcb & & Vcb - > type = = VCB_TYPE_BUS ) {
bus_device_extension * bde = DeviceObject - > DeviceExtension ;
IoSkipCurrentIrpStackLocation ( Irp ) ;
Status = IoCallDriver ( bde - > attached_device , Irp ) ;
2017-09-08 08:02:43 +00:00
goto exit ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
Status = Irp - > IoStatus . Status ;
IoCompleteRequest ( Irp , IO_NO_INCREMENT ) ;
2016-07-27 19:24:26 +00:00
exit :
2017-09-08 08:02:43 +00:00
if ( top_level )
2016-03-23 20:35:05 +00:00
IoSetTopLevelIrp ( NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
FsRtlExitFileSystem ( ) ;
return Status ;
}
2022-04-28 19:34:48 +00:00
NTSTATUS check_file_name_valid ( _In_ PUNICODE_STRING us , _In_ bool posix , _In_ bool stream ) {
2016-05-05 17:26:47 +00:00
ULONG i ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Length < sizeof ( WCHAR ) )
2022-04-28 19:34:48 +00:00
return STATUS_OBJECT_NAME_INVALID ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Length > 255 * sizeof ( WCHAR ) )
2022-04-28 19:34:48 +00:00
return STATUS_OBJECT_NAME_INVALID ;
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
for ( i = 0 ; i < us - > Length / sizeof ( WCHAR ) ; i + + ) {
2017-09-08 08:02:43 +00:00
if ( us - > Buffer [ i ] = = ' / ' | | us - > Buffer [ i ] = = 0 | |
2019-11-12 18:32:46 +00:00
( ! posix & & ( us - > Buffer [ i ] = = ' / ' | | us - > Buffer [ i ] = = ' : ' ) ) | |
( ! posix & & ! stream & & ( us - > Buffer [ i ] = = ' < ' | | us - > Buffer [ i ] = = ' > ' | | us - > Buffer [ i ] = = ' " ' | |
2017-09-08 08:02:43 +00:00
us - > Buffer [ i ] = = ' | ' | | us - > Buffer [ i ] = = ' ? ' | | us - > Buffer [ i ] = = ' * ' | | ( us - > Buffer [ i ] > = 1 & & us - > Buffer [ i ] < = 31 ) ) ) )
2022-04-28 19:34:48 +00:00
return STATUS_OBJECT_NAME_INVALID ;
2022-04-28 19:35:58 +00:00
/* Don't allow unpaired surrogates ("WTF-16") */
if ( ( us - > Buffer [ i ] & 0xfc00 ) = = 0xdc00 & & ( i = = 0 | | ( ( us - > Buffer [ i - 1 ] & 0xfc00 ) ! = 0xd800 ) ) )
return STATUS_OBJECT_NAME_INVALID ;
if ( ( us - > Buffer [ i ] & 0xfc00 ) = = 0xd800 & & ( i = = ( us - > Length / sizeof ( WCHAR ) ) - 1 | | ( ( us - > Buffer [ i + 1 ] & 0xfc00 ) ! = 0xdc00 ) ) )
return STATUS_OBJECT_NAME_INVALID ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-05-05 17:26:47 +00:00
if ( us - > Buffer [ 0 ] = = ' . ' & & ( us - > Length = = sizeof ( WCHAR ) | | ( us - > Length = = 2 * sizeof ( WCHAR ) & & us - > Buffer [ 1 ] = = ' . ' ) ) )
2022-04-28 19:34:48 +00:00
return STATUS_OBJECT_NAME_INVALID ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:34:48 +00:00
/* The Linux driver expects filenames with a maximum length of 255 bytes - make sure
* that our UTF - 8 length won ' t be longer than that . */
if ( us - > Length > = 85 * sizeof ( WCHAR ) ) {
NTSTATUS Status ;
ULONG utf8len ;
Status = utf16_to_utf8 ( NULL , 0 , & utf8len , us - > Buffer , us - > Length ) ;
if ( ! NT_SUCCESS ( Status ) )
return Status ;
if ( utf8len > 255 )
return STATUS_OBJECT_NAME_INVALID ;
else if ( stream & & utf8len > 250 ) // minus five bytes for "user."
return STATUS_OBJECT_NAME_INVALID ;
}
return STATUS_SUCCESS ;
2016-03-23 20:35:05 +00:00
}
2019-09-01 12:53:20 +00:00
void chunk_lock_range ( _In_ device_extension * Vcb , _In_ chunk * c , _In_ uint64_t start , _In_ uint64_t length ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2019-09-01 12:53:20 +00:00
bool locked ;
2016-10-29 17:05:10 +00:00
range_lock * rl ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rl = ExAllocateFromNPagedLookasideList ( & Vcb - > range_lock_lookaside ) ;
if ( ! rl ) {
ERR ( " out of memory \n " ) ;
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
rl - > start = start ;
rl - > length = length ;
rl - > thread = PsGetCurrentThread ( ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
while ( true ) {
locked = false ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & c - > range_locks_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = c - > range_locks . Flink ;
while ( le ! = & c - > range_locks ) {
range_lock * rl2 = CONTAINING_RECORD ( le , range_lock , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rl2 - > start < start + length & & rl2 - > start + rl2 - > length > start & & rl2 - > thread ! = PsGetCurrentThread ( ) ) {
2019-09-01 12:53:20 +00:00
locked = true ;
2016-10-29 17:05:10 +00:00
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( ! locked ) {
InsertTailList ( & c - > range_locks , & rl - > list_entry ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
2016-10-29 17:05:10 +00:00
return ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
KeClearEvent ( & c - > range_locks_event ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & c - > range_locks_event , UserRequest , KernelMode , false , NULL ) ;
2016-10-29 17:05:10 +00:00
}
}
2019-09-01 12:53:20 +00:00
void chunk_unlock_range ( _In_ device_extension * Vcb , _In_ chunk * c , _In_ uint64_t start , _In_ uint64_t length ) {
2016-10-29 17:05:10 +00:00
LIST_ENTRY * le ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & c - > range_locks_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = c - > range_locks . Flink ;
while ( le ! = & c - > range_locks ) {
range_lock * rl = CONTAINING_RECORD ( le , range_lock , list_entry ) ;
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
if ( rl - > start = = start & & rl - > length = = length ) {
RemoveEntryList ( & rl - > list_entry ) ;
ExFreeToNPagedLookasideList ( & Vcb - > range_lock_lookaside , rl ) ;
break ;
}
2017-09-08 08:02:43 +00:00
2016-10-29 17:05:10 +00:00
le = le - > Flink ;
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeSetEvent ( & c - > range_locks_event , 0 , false ) ;
2017-09-08 08:02:43 +00:00
ExReleaseResourceLite ( & c - > range_locks_lock ) ;
}
void log_device_error ( _In_ device_extension * Vcb , _Inout_ device * dev , _In_ int error ) {
dev - > stats [ error ] + + ;
2019-09-01 12:53:20 +00:00
dev - > stats_changed = true ;
Vcb - > stats_changed = true ;
2016-10-29 17:05:10 +00:00
}
2016-03-23 20:35:05 +00:00
# ifdef _DEBUG
2017-09-08 08:02:43 +00:00
_Function_class_ ( KSTART_ROUTINE )
2019-09-01 12:53:20 +00:00
static void __stdcall serial_thread ( void * context ) {
2017-09-08 08:02:43 +00:00
LARGE_INTEGER due_time ;
KTIMER timer ;
UNUSED ( context ) ;
KeInitializeTimer ( & timer ) ;
2019-09-01 12:53:20 +00:00
due_time . QuadPart = ( uint64_t ) - 10000000 ;
2017-09-08 08:02:43 +00:00
KeSetTimer ( & timer , due_time , NULL ) ;
2019-09-01 12:53:20 +00:00
while ( true ) {
KeWaitForSingleObject ( & timer , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
init_serial ( false ) ;
2017-09-08 08:02:43 +00:00
if ( comdo )
break ;
KeSetTimer ( & timer , due_time , NULL ) ;
}
KeCancelTimer ( & timer ) ;
PsTerminateSystemThread ( STATUS_SUCCESS ) ;
serial_thread_handle = NULL ;
}
2019-09-01 12:53:20 +00:00
static void init_serial ( bool first_time ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = IoGetDeviceObjectPointer ( & log_device , FILE_WRITE_DATA , & comfo , & comdo ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoGetDeviceObjectPointer returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
if ( first_time ) {
2019-11-12 18:32:46 +00:00
OBJECT_ATTRIBUTES oa ;
InitializeObjectAttributes ( & oa , NULL , OBJ_KERNEL_HANDLE , NULL , NULL ) ;
Status = PsCreateSystemThread ( & serial_thread_handle , 0 , & oa , NULL , NULL , serial_thread , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " PsCreateSystemThread returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return ;
}
}
2016-03-23 20:35:05 +00:00
}
}
# endif
2020-04-23 02:38:57 +00:00
# if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
2017-09-08 08:02:43 +00:00
static void check_cpu ( ) {
2022-04-28 19:33:48 +00:00
bool have_sse2 = false , have_sse42 = false , have_avx2 = false ;
2022-09-28 16:08:10 +00:00
int cpu_info [ 4 ] ;
2020-04-23 02:38:57 +00:00
2022-09-28 16:08:10 +00:00
__cpuid ( cpu_info , 1 ) ;
have_sse42 = cpu_info [ 2 ] & ( 1 < < 20 ) ;
have_sse2 = cpu_info [ 3 ] & ( 1 < < 26 ) ;
2022-04-28 19:33:48 +00:00
2022-09-28 16:08:10 +00:00
__cpuidex ( cpu_info , 7 , 0 ) ;
have_avx2 = cpu_info [ 1 ] & ( 1 < < 5 ) ;
2022-04-28 19:34:24 +00:00
2022-09-28 16:08:10 +00:00
if ( have_avx2 ) {
// check Windows has enabled AVX2 - Windows 10 doesn't immediately
2022-04-28 19:34:24 +00:00
2022-09-28 16:08:10 +00:00
if ( __readcr4 ( ) & ( 1 < < 18 ) ) {
uint32_t xcr0 ;
2022-04-28 19:33:48 +00:00
2022-09-28 16:08:10 +00:00
# ifdef _MSC_VER
xcr0 = ( uint32_t ) _xgetbv ( 0 ) ;
2016-03-23 20:35:05 +00:00
# else
2022-09-28 16:08:10 +00:00
__asm__ ( " xgetbv " : " =a " ( xcr0 ) : " c " ( 0 ) : " edx " ) ;
# endif
2022-04-28 19:33:48 +00:00
2022-09-28 16:08:10 +00:00
if ( ( xcr0 & 6 ) ! = 6 )
2022-04-28 19:33:48 +00:00
have_avx2 = false ;
2022-09-28 16:08:10 +00:00
} else
have_avx2 = false ;
2022-04-28 19:31:44 +00:00
}
2016-03-23 20:35:05 +00:00
2020-04-23 02:38:57 +00:00
if ( have_sse42 ) {
2016-03-23 20:35:05 +00:00
TRACE ( " SSE4.2 is supported \n " ) ;
2020-04-23 02:38:57 +00:00
calc_crc32c = calc_crc32c_hw ;
} else
2016-03-23 20:35:05 +00:00
TRACE ( " SSE4.2 not supported \n " ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:33:48 +00:00
if ( have_sse2 ) {
2016-10-29 17:05:10 +00:00
TRACE ( " SSE2 is supported \n " ) ;
2022-04-28 19:33:48 +00:00
if ( ! have_avx2 )
do_xor = do_xor_sse2 ;
} else
2016-10-29 17:05:10 +00:00
TRACE ( " SSE2 is not supported \n " ) ;
2022-04-28 19:33:48 +00:00
if ( have_avx2 ) {
TRACE ( " AVX2 is supported \n " ) ;
do_xor = do_xor_avx2 ;
} else
TRACE ( " AVX2 is not supported \n " ) ;
2016-03-23 20:35:05 +00:00
}
# endif
# ifdef _DEBUG
static void init_logging ( ) {
2019-09-01 12:53:20 +00:00
ExAcquireResourceExclusiveLite ( & log_lock , true ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( log_device . Length > 0 )
2019-09-01 12:53:20 +00:00
init_serial ( true ) ;
2016-03-23 20:35:05 +00:00
else if ( log_file . Length > 0 ) {
NTSTATUS Status ;
OBJECT_ATTRIBUTES oa ;
IO_STATUS_BLOCK iosb ;
char * dateline ;
LARGE_INTEGER time ;
TIME_FIELDS tf ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
InitializeObjectAttributes ( & oa , & log_file , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwCreateFile ( & log_handle , FILE_WRITE_DATA , & oa , & iosb , NULL , FILE_ATTRIBUTE_NORMAL , FILE_SHARE_READ ,
FILE_OPEN_IF , FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT , NULL , 0 ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwCreateFile returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( iosb . Information = = FILE_OPENED ) { // already exists
FILE_STANDARD_INFORMATION fsi ;
FILE_POSITION_INFORMATION fpi ;
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
static const char delim [ ] = " \n --- \n " ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
// move to end of file
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwQueryInformationFile ( log_handle , & iosb , & fsi , sizeof ( FILE_STANDARD_INFORMATION ) , FileStandardInformation ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwQueryInformationFile returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
fpi . CurrentByteOffset = fsi . EndOfFile ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
Status = ZwSetInformationFile ( log_handle , & iosb , & fpi , sizeof ( FILE_POSITION_INFORMATION ) , FilePositionInformation ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwSetInformationFile returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2018-12-16 11:03:16 +00:00
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , ( void * ) delim , sizeof ( delim ) - 1 , NULL , NULL ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwWriteFile returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
dateline = ExAllocatePoolWithTag ( PagedPool , 256 , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
if ( ! dateline ) {
ERR ( " out of memory \n " ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
KeQuerySystemTime ( & time ) ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
RtlTimeToTimeFields ( & time , & tf ) ;
2017-09-08 08:02:43 +00:00
sprintf ( dateline , " Starting logging at %04i-%02i-%02i %02i:%02i:%02i \n " , tf . Year , tf . Month , tf . Day , tf . Hour , tf . Minute , tf . Second ) ;
Status = ZwWriteFile ( log_handle , NULL , NULL , NULL , & iosb , dateline , ( ULONG ) strlen ( dateline ) , NULL , NULL ) ;
ExFreePool ( dateline ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwWriteFile returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end ;
2016-03-23 20:35:05 +00:00
}
}
2017-09-08 08:02:43 +00:00
end :
ExReleaseResourceLite ( & log_lock ) ;
}
# endif
_Function_class_ ( KSTART_ROUTINE )
2019-09-01 12:53:20 +00:00
static void __stdcall degraded_wait_thread ( _In_ void * context ) {
2017-09-08 08:02:43 +00:00
KTIMER timer ;
LARGE_INTEGER delay ;
UNUSED ( context ) ;
KeInitializeTimer ( & timer ) ;
delay . QuadPart = - 30000000 ; // wait three seconds
KeSetTimer ( & timer , delay , NULL ) ;
2019-09-01 12:53:20 +00:00
KeWaitForSingleObject ( & timer , Executive , KernelMode , false , NULL ) ;
2017-09-08 08:02:43 +00:00
TRACE ( " timer expired \n " ) ;
2019-09-01 12:53:20 +00:00
degraded_wait = false ;
2017-09-08 08:02:43 +00:00
ZwClose ( degraded_wait_handle ) ;
degraded_wait_handle = NULL ;
PsTerminateSystemThread ( STATUS_SUCCESS ) ;
2016-03-23 20:35:05 +00:00
}
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
_Function_class_ ( DRIVER_ADD_DEVICE )
NTSTATUS __stdcall AddDevice ( PDRIVER_OBJECT DriverObject , PDEVICE_OBJECT PhysicalDeviceObject ) {
2017-09-08 08:02:43 +00:00
LIST_ENTRY * le ;
NTSTATUS Status ;
UNICODE_STRING volname ;
2020-04-23 02:38:57 +00:00
ULONG i ;
WCHAR * s ;
2017-09-08 08:02:43 +00:00
pdo_device_extension * pdode = NULL ;
PDEVICE_OBJECT voldev ;
volume_device_extension * vde ;
2020-04-23 02:38:57 +00:00
UNICODE_STRING arc_name_us ;
WCHAR * anp ;
static const WCHAR arc_name_prefix [ ] = L " \\ ArcName \\ btrfs( " ;
WCHAR arc_name [ ( sizeof ( arc_name_prefix ) / sizeof ( WCHAR ) ) - 1 + 37 ] ;
2017-09-08 08:02:43 +00:00
TRACE ( " (%p, %p) \n " , DriverObject , PhysicalDeviceObject ) ;
2016-03-23 20:35:05 +00:00
2022-04-28 19:33:48 +00:00
UNUSED ( DriverObject ) ;
2019-09-01 12:53:20 +00:00
ExAcquireResourceSharedLite ( & pdo_list_lock , true ) ;
2017-09-08 08:02:43 +00:00
le = pdo_list . Flink ;
while ( le ! = & pdo_list ) {
pdo_device_extension * pdode2 = CONTAINING_RECORD ( le , pdo_device_extension , list_entry ) ;
if ( pdode2 - > pdo = = PhysicalDeviceObject ) {
pdode = pdode2 ;
break ;
}
le = le - > Flink ;
}
if ( ! pdode ) {
WARN ( " unrecognized PDO %p \n " , PhysicalDeviceObject ) ;
Status = STATUS_NOT_SUPPORTED ;
goto end ;
}
2019-11-12 18:32:46 +00:00
ExAcquireResourceExclusiveLite ( & pdode - > child_lock , true ) ;
if ( pdode - > vde ) { // if already done, return success
Status = STATUS_SUCCESS ;
goto end2 ;
}
2017-09-08 08:02:43 +00:00
2018-12-16 11:03:16 +00:00
volname . Length = volname . MaximumLength = ( sizeof ( BTRFS_VOLUME_PREFIX ) - sizeof ( WCHAR ) ) + ( ( 36 + 1 ) * sizeof ( WCHAR ) ) ;
2017-09-08 08:02:43 +00:00
volname . Buffer = ExAllocatePoolWithTag ( PagedPool , volname . MaximumLength , ALLOC_TAG ) ; // FIXME - when do we free this?
if ( ! volname . Buffer ) {
ERR ( " out of memory \n " ) ;
Status = STATUS_INSUFFICIENT_RESOURCES ;
goto end2 ;
}
2018-12-16 11:03:16 +00:00
RtlCopyMemory ( volname . Buffer , BTRFS_VOLUME_PREFIX , sizeof ( BTRFS_VOLUME_PREFIX ) - sizeof ( WCHAR ) ) ;
2020-04-23 02:38:57 +00:00
RtlCopyMemory ( arc_name , arc_name_prefix , sizeof ( arc_name_prefix ) - sizeof ( WCHAR ) ) ;
anp = & arc_name [ ( sizeof ( arc_name_prefix ) / sizeof ( WCHAR ) ) - 1 ] ;
s = & volname . Buffer [ ( sizeof ( BTRFS_VOLUME_PREFIX ) / sizeof ( WCHAR ) ) - 1 ] ;
2017-09-08 08:02:43 +00:00
for ( i = 0 ; i < 16 ; i + + ) {
2020-04-23 02:38:57 +00:00
* s = * anp = hex_digit ( pdode - > uuid . uuid [ i ] > > 4 ) ;
s + + ;
anp + + ;
* s = * anp = hex_digit ( pdode - > uuid . uuid [ i ] & 0xf ) ;
s + + ;
anp + + ;
2017-09-08 08:02:43 +00:00
if ( i = = 3 | | i = = 5 | | i = = 7 | | i = = 9 ) {
2020-04-23 02:38:57 +00:00
* s = * anp = ' - ' ;
s + + ;
anp + + ;
2017-09-08 08:02:43 +00:00
}
}
2020-04-23 02:38:57 +00:00
* s = ' } ' ;
* anp = ' ) ' ;
2017-09-08 08:02:43 +00:00
Status = IoCreateDevice ( drvobj , sizeof ( volume_device_extension ) , & volname , FILE_DEVICE_DISK ,
2022-04-28 19:31:44 +00:00
is_windows_8 ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0 , false , & voldev ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCreateDevice returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
goto end2 ;
}
2020-04-23 02:38:57 +00:00
arc_name_us . Buffer = arc_name ;
arc_name_us . Length = arc_name_us . MaximumLength = sizeof ( arc_name ) ;
Status = IoCreateSymbolicLink ( & arc_name_us , & volname ) ;
if ( ! NT_SUCCESS ( Status ) )
WARN ( " IoCreateSymbolicLink returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
voldev - > SectorSize = PhysicalDeviceObject - > SectorSize ;
voldev - > Flags | = DO_DIRECT_IO ;
vde = voldev - > DeviceExtension ;
vde - > type = VCB_TYPE_VOLUME ;
vde - > name = volname ;
vde - > device = voldev ;
vde - > mounted_device = NULL ;
vde - > pdo = PhysicalDeviceObject ;
vde - > pdode = pdode ;
2019-09-01 12:53:20 +00:00
vde - > removing = false ;
2019-11-12 18:32:46 +00:00
vde - > dead = false ;
2017-09-08 08:02:43 +00:00
vde - > open_count = 0 ;
Status = IoRegisterDeviceInterface ( PhysicalDeviceObject , & GUID_DEVINTERFACE_VOLUME , NULL , & vde - > bus_name ) ;
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " IoRegisterDeviceInterface returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
vde - > attached_device = IoAttachDeviceToDeviceStack ( voldev , PhysicalDeviceObject ) ;
pdode - > vde = vde ;
if ( pdode - > removable )
voldev - > Characteristics | = FILE_REMOVABLE_MEDIA ;
2020-04-23 02:38:57 +00:00
if ( RtlCompareMemory ( & boot_uuid , & pdode - > uuid , sizeof ( BTRFS_UUID ) ) = = sizeof ( BTRFS_UUID ) ) {
voldev - > Flags | = DO_SYSTEM_BOOT_PARTITION ;
PhysicalDeviceObject - > Flags | = DO_SYSTEM_BOOT_PARTITION ;
}
2017-09-08 08:02:43 +00:00
voldev - > Flags & = ~ DO_DEVICE_INITIALIZING ;
2019-09-01 12:53:20 +00:00
Status = IoSetDeviceInterfaceState ( & vde - > bus_name , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " IoSetDeviceInterfaceState returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
Status = STATUS_SUCCESS ;
end2 :
ExReleaseResourceLite ( & pdode - > child_lock ) ;
end :
ExReleaseResourceLite ( & pdo_list_lock ) ;
return Status ;
}
_Function_class_ ( DRIVER_INITIALIZE )
2019-09-01 12:53:20 +00:00
NTSTATUS __stdcall DriverEntry ( _In_ PDRIVER_OBJECT DriverObject , _In_ PUNICODE_STRING RegistryPath ) {
2016-03-23 20:35:05 +00:00
NTSTATUS Status ;
PDEVICE_OBJECT DeviceObject ;
UNICODE_STRING device_nameW ;
UNICODE_STRING dosdevice_nameW ;
2017-01-01 17:12:12 +00:00
control_device_extension * cde ;
2019-09-01 12:53:20 +00:00
bus_device_extension * bde ;
2017-09-08 08:02:43 +00:00
HANDLE regh ;
2019-11-12 18:32:46 +00:00
OBJECT_ATTRIBUTES oa , system_thread_attributes ;
2017-09-08 08:02:43 +00:00
ULONG dispos ;
2022-04-28 19:31:44 +00:00
RTL_OSVERSIONINFOW ver ;
ver . dwOSVersionInfoSize = sizeof ( RTL_OSVERSIONINFOW ) ;
Status = RtlGetVersion ( & ver ) ;
if ( ! NT_SUCCESS ( Status ) ) {
ERR ( " RtlGetVersion returned %08lx \n " , Status ) ;
return Status ;
}
is_windows_8 = ver . dwMajorVersion > 6 | | ( ver . dwMajorVersion = = 6 & & ver . dwMinorVersion > = 2 ) ;
2017-09-08 08:02:43 +00:00
2022-04-28 19:35:58 +00:00
KeInitializeSpinLock ( & fve_data_lock ) ;
2016-03-23 20:35:05 +00:00
InitializeListHead ( & uid_map_list ) ;
2017-09-08 08:02:43 +00:00
InitializeListHead ( & gid_map_list ) ;
# ifdef _DEBUG
ExInitializeResourceLite ( & log_lock ) ;
# endif
ExInitializeResourceLite ( & mapping_lock ) ;
2016-03-23 20:35:05 +00:00
log_device . Buffer = NULL ;
log_device . Length = log_device . MaximumLength = 0 ;
log_file . Buffer = NULL ;
log_file . Length = log_file . MaximumLength = 0 ;
2016-07-27 19:24:26 +00:00
registry_path . Length = registry_path . MaximumLength = RegistryPath - > Length ;
registry_path . Buffer = ExAllocatePoolWithTag ( PagedPool , registry_path . Length , ALLOC_TAG ) ;
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
if ( ! registry_path . Buffer ) {
ERR ( " out of memory \n " ) ;
return STATUS_INSUFFICIENT_RESOURCES ;
}
2017-09-08 08:02:43 +00:00
2016-07-27 19:24:26 +00:00
RtlCopyMemory ( registry_path . Buffer , RegistryPath - > Buffer , registry_path . Length ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
read_registry ( & registry_path , false ) ;
2017-09-08 08:02:43 +00:00
# ifdef _DEBUG
if ( debug_log_level > 0 )
init_logging ( ) ;
2019-09-01 12:53:20 +00:00
log_started = true ;
2017-09-08 08:02:43 +00:00
# endif
TRACE ( " DriverEntry \n " ) ;
2020-04-23 02:38:57 +00:00
# if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
2016-03-23 20:35:05 +00:00
check_cpu ( ) ;
# endif
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ver . dwMajorVersion > 6 | | ( ver . dwMajorVersion = = 6 & & ver . dwMinorVersion > = 2 ) ) { // Windows 8 or above
2017-01-01 17:12:12 +00:00
UNICODE_STRING name ;
2017-09-08 08:02:43 +00:00
tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " PsIsDiskCountersEnabled " ) ;
2017-09-08 08:02:43 +00:00
fPsIsDiskCountersEnabled = ( tPsIsDiskCountersEnabled ) MmGetSystemRoutineAddress ( & name ) ;
if ( fPsIsDiskCountersEnabled ) {
diskacc = fPsIsDiskCountersEnabled ( ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " PsUpdateDiskCounters " ) ;
2017-09-08 08:02:43 +00:00
fPsUpdateDiskCounters = ( tPsUpdateDiskCounters ) MmGetSystemRoutineAddress ( & name ) ;
if ( ! fPsUpdateDiskCounters )
2019-09-01 12:53:20 +00:00
diskacc = false ;
2017-09-08 08:02:43 +00:00
RtlInitUnicodeString ( & name , L " FsRtlUpdateDiskCounters " ) ;
fFsRtlUpdateDiskCounters = ( tFsRtlUpdateDiskCounters ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcCopyReadEx " ) ;
2017-09-08 08:02:43 +00:00
fCcCopyReadEx = ( tCcCopyReadEx ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcCopyWriteEx " ) ;
2017-09-08 08:02:43 +00:00
fCcCopyWriteEx = ( tCcCopyWriteEx ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
RtlInitUnicodeString ( & name , L " CcSetAdditionalCacheAttributesEx " ) ;
2017-09-08 08:02:43 +00:00
fCcSetAdditionalCacheAttributesEx = ( tCcSetAdditionalCacheAttributesEx ) MmGetSystemRoutineAddress ( & name ) ;
2019-11-12 18:32:46 +00:00
RtlInitUnicodeString ( & name , L " FsRtlCheckLockForOplockRequest " ) ;
fFsRtlCheckLockForOplockRequest = ( tFsRtlCheckLockForOplockRequest ) MmGetSystemRoutineAddress ( & name ) ;
2017-01-01 17:12:12 +00:00
} else {
2017-09-08 08:02:43 +00:00
fPsUpdateDiskCounters = NULL ;
fCcCopyReadEx = NULL ;
fCcCopyWriteEx = NULL ;
fCcSetAdditionalCacheAttributesEx = NULL ;
fFsRtlUpdateDiskCounters = NULL ;
2019-11-12 18:32:46 +00:00
fFsRtlCheckLockForOplockRequest = NULL ;
2017-01-01 17:12:12 +00:00
}
2017-09-08 08:02:43 +00:00
2022-04-28 19:31:44 +00:00
if ( ver . dwMajorVersion > 6 | | ( ver . dwMajorVersion = = 6 & & ver . dwMinorVersion > = 1 ) ) { // Windows 7 or above
2019-09-01 12:53:20 +00:00
UNICODE_STRING name ;
RtlInitUnicodeString ( & name , L " IoUnregisterPlugPlayNotificationEx " ) ;
fIoUnregisterPlugPlayNotificationEx = ( tIoUnregisterPlugPlayNotificationEx ) MmGetSystemRoutineAddress ( & name ) ;
2019-11-12 18:32:46 +00:00
RtlInitUnicodeString ( & name , L " FsRtlAreThereCurrentOrInProgressFileLocks " ) ;
fFsRtlAreThereCurrentOrInProgressFileLocks = ( tFsRtlAreThereCurrentOrInProgressFileLocks ) MmGetSystemRoutineAddress ( & name ) ;
} else {
2019-09-01 12:53:20 +00:00
fIoUnregisterPlugPlayNotificationEx = NULL ;
2019-11-12 18:32:46 +00:00
fFsRtlAreThereCurrentOrInProgressFileLocks = NULL ;
}
2019-09-01 12:53:20 +00:00
2022-04-28 19:31:44 +00:00
if ( ver . dwMajorVersion > = 6 ) { // Windows Vista or above
2019-09-01 12:53:20 +00:00
UNICODE_STRING name ;
RtlInitUnicodeString ( & name , L " FsRtlGetEcpListFromIrp " ) ;
fFsRtlGetEcpListFromIrp = ( tFsRtlGetEcpListFromIrp ) MmGetSystemRoutineAddress ( & name ) ;
RtlInitUnicodeString ( & name , L " FsRtlGetNextExtraCreateParameter " ) ;
fFsRtlGetNextExtraCreateParameter = ( tFsRtlGetNextExtraCreateParameter ) MmGetSystemRoutineAddress ( & name ) ;
RtlInitUnicodeString ( & name , L " FsRtlValidateReparsePointBuffer " ) ;
fFsRtlValidateReparsePointBuffer = ( tFsRtlValidateReparsePointBuffer ) MmGetSystemRoutineAddress ( & name ) ;
} else {
fFsRtlGetEcpListFromIrp = NULL ;
fFsRtlGetNextExtraCreateParameter = NULL ;
fFsRtlValidateReparsePointBuffer = compat_FsRtlValidateReparsePointBuffer ;
}
2016-03-23 20:35:05 +00:00
drvobj = DriverObject ;
DriverObject - > DriverUnload = DriverUnload ;
2017-09-08 08:02:43 +00:00
DriverObject - > DriverExtension - > AddDevice = AddDevice ;
2018-08-21 05:05:40 +00:00
DriverObject - > MajorFunction [ IRP_MJ_CREATE ] = drv_create ;
DriverObject - > MajorFunction [ IRP_MJ_CLOSE ] = drv_close ;
DriverObject - > MajorFunction [ IRP_MJ_READ ] = drv_read ;
DriverObject - > MajorFunction [ IRP_MJ_WRITE ] = drv_write ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_INFORMATION ] = drv_query_information ;
DriverObject - > MajorFunction [ IRP_MJ_SET_INFORMATION ] = drv_set_information ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_EA ] = drv_query_ea ;
DriverObject - > MajorFunction [ IRP_MJ_SET_EA ] = drv_set_ea ;
DriverObject - > MajorFunction [ IRP_MJ_FLUSH_BUFFERS ] = drv_flush_buffers ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_VOLUME_INFORMATION ] = drv_query_volume_information ;
DriverObject - > MajorFunction [ IRP_MJ_SET_VOLUME_INFORMATION ] = drv_set_volume_information ;
DriverObject - > MajorFunction [ IRP_MJ_DIRECTORY_CONTROL ] = drv_directory_control ;
DriverObject - > MajorFunction [ IRP_MJ_FILE_SYSTEM_CONTROL ] = drv_file_system_control ;
DriverObject - > MajorFunction [ IRP_MJ_DEVICE_CONTROL ] = drv_device_control ;
DriverObject - > MajorFunction [ IRP_MJ_SHUTDOWN ] = drv_shutdown ;
DriverObject - > MajorFunction [ IRP_MJ_LOCK_CONTROL ] = drv_lock_control ;
DriverObject - > MajorFunction [ IRP_MJ_CLEANUP ] = drv_cleanup ;
DriverObject - > MajorFunction [ IRP_MJ_QUERY_SECURITY ] = drv_query_security ;
DriverObject - > MajorFunction [ IRP_MJ_SET_SECURITY ] = drv_set_security ;
DriverObject - > MajorFunction [ IRP_MJ_POWER ] = drv_power ;
DriverObject - > MajorFunction [ IRP_MJ_SYSTEM_CONTROL ] = drv_system_control ;
DriverObject - > MajorFunction [ IRP_MJ_PNP ] = drv_pnp ;
2016-03-23 20:35:05 +00:00
init_fast_io_dispatch ( & DriverObject - > FastIoDispatch ) ;
2018-12-16 11:03:16 +00:00
device_nameW . Buffer = ( WCHAR * ) device_name ;
device_nameW . Length = device_nameW . MaximumLength = sizeof ( device_name ) - sizeof ( WCHAR ) ;
dosdevice_nameW . Buffer = ( WCHAR * ) dosdevice_name ;
dosdevice_nameW . Length = dosdevice_nameW . MaximumLength = sizeof ( dosdevice_name ) - sizeof ( WCHAR ) ;
2016-03-23 20:35:05 +00:00
2017-01-01 17:12:12 +00:00
Status = IoCreateDevice ( DriverObject , sizeof ( control_device_extension ) , & device_nameW , FILE_DEVICE_DISK_FILE_SYSTEM ,
2019-09-01 12:53:20 +00:00
FILE_DEVICE_SECURE_OPEN , false , & DeviceObject ) ;
2016-03-23 20:35:05 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCreateDevice returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
master_devobj = DeviceObject ;
cde = ( control_device_extension * ) master_devobj - > DeviceExtension ;
RtlZeroMemory ( cde , sizeof ( control_device_extension ) ) ;
2017-01-01 17:12:12 +00:00
cde - > type = VCB_TYPE_CONTROL ;
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
DeviceObject - > Flags & = ~ DO_DEVICE_INITIALIZING ;
Status = IoCreateSymbolicLink ( & dosdevice_nameW , & device_nameW ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCreateSymbolicLink returned %08lx \n " , Status ) ;
2016-03-23 20:35:05 +00:00
return Status ;
}
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
init_cache ( ) ;
2016-03-23 20:35:05 +00:00
InitializeListHead ( & VcbList ) ;
ExInitializeResourceLite ( & global_loading_lock ) ;
2017-09-08 08:02:43 +00:00
ExInitializeResourceLite ( & pdo_list_lock ) ;
InitializeListHead ( & pdo_list ) ;
InitializeObjectAttributes ( & oa , RegistryPath , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE , NULL , NULL ) ;
Status = ZwCreateKey ( & regh , KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY , & oa , 0 , NULL , REG_OPTION_NON_VOLATILE , & dispos ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " ZwCreateKey returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
watch_registry ( regh ) ;
2019-09-01 12:53:20 +00:00
Status = IoCreateDevice ( DriverObject , sizeof ( bus_device_extension ) , NULL , FILE_DEVICE_UNKNOWN ,
FILE_DEVICE_SECURE_OPEN , false , & busobj ) ;
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoCreateDevice returned %08lx \n " , Status ) ;
2019-09-01 12:53:20 +00:00
return Status ;
}
bde = ( bus_device_extension * ) busobj - > DeviceExtension ;
RtlZeroMemory ( bde , sizeof ( bus_device_extension ) ) ;
bde - > type = VCB_TYPE_BUS ;
2017-09-08 08:02:43 +00:00
Status = IoReportDetectedDevice ( drvobj , InterfaceTypeUndefined , 0xFFFFFFFF , 0xFFFFFFFF ,
2019-09-01 12:53:20 +00:00
NULL , NULL , 0 , & bde - > buspdo ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) ) {
2020-04-23 02:38:57 +00:00
ERR ( " IoReportDetectedDevice returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
return Status ;
}
2019-09-01 12:53:20 +00:00
Status = IoRegisterDeviceInterface ( bde - > buspdo , & BtrfsBusInterface , NULL , & bde - > bus_name ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " IoRegisterDeviceInterface returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
bde - > attached_device = IoAttachDeviceToDeviceStack ( busobj , bde - > buspdo ) ;
busobj - > Flags & = ~ DO_DEVICE_INITIALIZING ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
Status = IoSetDeviceInterfaceState ( & bde - > bus_name , true ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " IoSetDeviceInterfaceState returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
IoInvalidateDeviceRelations ( bde - > buspdo , BusRelations ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
InitializeObjectAttributes ( & system_thread_attributes , NULL , OBJ_KERNEL_HANDLE , NULL , NULL ) ;
Status = PsCreateSystemThread ( & degraded_wait_handle , 0 , & system_thread_attributes , NULL , NULL , degraded_wait_thread , NULL ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
WARN ( " PsCreateSystemThread returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-11-12 18:32:46 +00:00
ExInitializeResourceLite ( & boot_lock ) ;
2017-09-08 08:02:43 +00:00
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
2022-04-28 19:35:58 +00:00
( PVOID ) & GUID_DEVINTERFACE_VOLUME , DriverObject , volume_notification , NULL , & notification_entry2 ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " IoRegisterPlugPlayNotification returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
2022-04-28 19:35:58 +00:00
( PVOID ) & GUID_DEVINTERFACE_HIDDEN_VOLUME , DriverObject , volume_notification , NULL , & notification_entry3 ) ;
2017-09-08 08:02:43 +00:00
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " IoRegisterPlugPlayNotification returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2017-01-01 17:12:12 +00:00
Status = IoRegisterPlugPlayNotification ( EventCategoryDeviceInterfaceChange , PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES ,
( PVOID ) & GUID_DEVINTERFACE_DISK , DriverObject , pnp_notification , DriverObject , & notification_entry ) ;
if ( ! NT_SUCCESS ( Status ) )
2020-04-23 02:38:57 +00:00
ERR ( " IoRegisterPlugPlayNotification returned %08lx \n " , Status ) ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
finished_probing = true ;
2017-09-08 08:02:43 +00:00
2019-09-01 12:53:20 +00:00
KeInitializeEvent ( & mountmgr_thread_event , NotificationEvent , false ) ;
2017-09-08 08:02:43 +00:00
2021-07-05 23:37:34 +00:00
// Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, &system_thread_attributes, NULL, NULL, mountmgr_thread, NULL);
// if (!NT_SUCCESS(Status))
// WARN("PsCreateSystemThread returned %08lx\n", Status);
2017-09-08 08:02:43 +00:00
2016-03-23 20:35:05 +00:00
IoRegisterFileSystem ( DeviceObject ) ;
2022-04-28 19:34:48 +00:00
check_system_root ( ) ;
2019-09-01 12:53:20 +00:00
2016-03-23 20:35:05 +00:00
return STATUS_SUCCESS ;
}