[BTRFS] Upgrade to 1.5

CORE-16494
This commit is contained in:
Pierre Schweitzer 2019-11-12 19:32:46 +01:00
parent c214c04964
commit 62e630de4c
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
27 changed files with 2216 additions and 566 deletions

View file

@ -1037,6 +1037,7 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
tw->address = mr->new_address; tw->address = mr->new_address;
tw->length = Vcb->superblock.node_size; tw->length = Vcb->superblock.node_size;
tw->data = (uint8_t*)mr->data; tw->data = (uint8_t*)mr->data;
tw->allocated = false;
if (IsListEmpty(&tree_writes)) if (IsListEmpty(&tree_writes))
InsertTailList(&tree_writes, &tw->list_entry); InsertTailList(&tree_writes, &tw->list_entry);
@ -1089,6 +1090,10 @@ static NTSTATUS write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
end: end:
while (!IsListEmpty(&tree_writes)) { while (!IsListEmpty(&tree_writes)) {
tree_write* tw = CONTAINING_RECORD(RemoveHeadList(&tree_writes), tree_write, list_entry); tree_write* tw = CONTAINING_RECORD(RemoveHeadList(&tree_writes), tree_write, list_entry);
if (tw->allocated)
ExFreePool(tw->data);
ExFreePool(tw); ExFreePool(tw);
} }
@ -1203,6 +1208,9 @@ end:
ExFreePool(ref); ExFreePool(ref);
} }
if (mr->data)
ExFreePool(mr->data);
ExFreePool(mr); ExFreePool(mr);
} }
@ -2187,6 +2195,9 @@ end:
ExFreePool(ref); ExFreePool(ref);
} }
if (mr->data)
ExFreePool(mr->data);
ExFreePool(mr); ExFreePool(mr);
} }
@ -3499,6 +3510,7 @@ end:
NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode) { NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE processor_mode) {
NTSTATUS Status; NTSTATUS Status;
btrfs_start_balance* bsb = (btrfs_start_balance*)data; btrfs_start_balance* bsb = (btrfs_start_balance*)data;
OBJECT_ATTRIBUTES oa;
uint8_t i; uint8_t i;
if (length < sizeof(btrfs_start_balance) || !data) if (length < sizeof(btrfs_start_balance) || !data)
@ -3599,7 +3611,9 @@ NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESS
Vcb->balance.status = STATUS_SUCCESS; Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
return Status; return Status;
@ -3613,6 +3627,7 @@ NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex
traverse_ptr tp; traverse_ptr tp;
NTSTATUS Status; NTSTATUS Status;
BALANCE_ITEM* bi; BALANCE_ITEM* bi;
OBJECT_ATTRIBUTES oa;
int i; int i;
searchkey.obj_id = BALANCE_ITEM_ID; searchkey.obj_id = BALANCE_ITEM_ID;
@ -3679,7 +3694,9 @@ NTSTATUS look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex
Vcb->balance.status = STATUS_SUCCESS; Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
return Status; return Status;
@ -3783,6 +3800,7 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESS
NTSTATUS Status; NTSTATUS Status;
int i; int i;
uint64_t num_rw_devices; uint64_t num_rw_devices;
OBJECT_ATTRIBUTES oa;
TRACE("(%p, %p, %x)\n", Vcb, data, length); TRACE("(%p, %p, %x)\n", Vcb, data, length);
@ -3876,7 +3894,9 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG length, KPROCESS
Vcb->balance.status = STATUS_SUCCESS; Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused); KeInitializeEvent(&Vcb->balance.event, NotificationEvent, !Vcb->balance.paused);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
dev->reloc = false; dev->reloc = false;

View file

@ -27,11 +27,26 @@
extern ERESOURCE pdo_list_lock; extern ERESOURCE pdo_list_lock;
extern LIST_ENTRY pdo_list; extern LIST_ENTRY pdo_list;
extern ERESOURCE boot_lock;
extern PDRIVER_OBJECT drvobj;
#ifndef _MSC_VER #ifndef _MSC_VER
NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR* pszFormat, ...); // not in mingw NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR* pszFormat, ...); // not in mingw
#endif #endif
// Not in any headers? Windbg knows about it though.
#define DOE_START_PENDING 0x10
// Just as much as we need - the version in mingw is truncated still further
typedef struct {
CSHORT Type;
USHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG PowerFlags;
void* Dope;
ULONG ExtensionFlags;
} DEVOBJ_EXTENSION2;
static bool get_system_root_partition(uint32_t* disk_num, uint32_t* partition_num) { static bool get_system_root_partition(uint32_t* disk_num, uint32_t* partition_num) {
NTSTATUS Status; NTSTATUS Status;
HANDLE h; HANDLE h;
@ -191,6 +206,65 @@ static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID
ERR("IoCreateSymbolicLink returned %08x\n", Status); ERR("IoCreateSymbolicLink returned %08x\n", Status);
} }
static void mountmgr_notification(BTRFS_UUID* uuid) {
UNICODE_STRING mmdevpath;
NTSTATUS Status;
PFILE_OBJECT FileObject;
PDEVICE_OBJECT mountmgr;
ULONG mmtnlen;
MOUNTMGR_TARGET_NAME* mmtn;
WCHAR* w;
#ifdef __REACTOS__
unsigned int i;
#endif
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
if (!NT_SUCCESS(Status)) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG);
if (!mmtn) {
ERR("out of memory\n");
return;
}
mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
RtlCopyMemory(mmtn->DeviceName, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR));
w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
#ifndef __REACTOS__
for (unsigned int i = 0; i < 16; i++) {
#else
for (i = 0; i < 16; i++) {
#endif
*w = hex_digit(uuid->uuid[i] >> 4); w++;
*w = hex_digit(uuid->uuid[i] & 0xf); w++;
if (i == 3 || i == 5 || i == 7 || i == 9) {
*w = L'-';
w++;
}
}
*w = L'}';
Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mmtn, mmtnlen, NULL, 0, false, NULL);
if (!NT_SUCCESS(Status)) {
ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08x\n", Status);
ExFreePool(mmtn);
return;
}
ExFreePool(mmtn);
}
/* If booting from Btrfs, Windows will pass the device object for the raw partition to /* If booting from Btrfs, Windows will pass the device object for the raw partition to
* mount_vol - which is no good to us, as we only use the \Device\Btrfs{} devices we * mount_vol - which is no good to us, as we only use the \Device\Btrfs{} devices we
* create so that RAID works correctly. * create so that RAID works correctly.
@ -205,9 +279,14 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO
uint32_t disk_num, partition_num; uint32_t disk_num, partition_num;
LIST_ENTRY* le; LIST_ENTRY* le;
bool done = false; bool done = false;
PDEVICE_OBJECT pdo_to_add = NULL;
TRACE("(%p, %p, %u)\n", DriverObject, Context, Count); TRACE("(%p, %p, %u)\n", DriverObject, Context, Count);
// wait for any PNP notifications in progress to finish
ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
ExReleaseResourceLite(&boot_lock);
if (!get_system_root_partition(&disk_num, &partition_num)) if (!get_system_root_partition(&disk_num, &partition_num))
return; return;
@ -230,19 +309,76 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO
if (vc->disk_num == disk_num && vc->part_num == partition_num) { if (vc->disk_num == disk_num && vc->part_num == partition_num) {
change_symlink(disk_num, partition_num, &pdode->uuid); change_symlink(disk_num, partition_num, &pdode->uuid);
done = true; done = true;
if (!pdode->vde)
pdo_to_add = pdode->pdo;
break; break;
} }
le2 = le2->Flink; le2 = le2->Flink;
} }
ExReleaseResourceLite(&pdode->child_lock); if (done) {
le2 = pdode->children.Flink;
while (le2 != &pdode->children) {
volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
/* On Windows 7 we need to clear the DO_SYSTEM_BOOT_PARTITION flag of
* all of our underlying partition objects - otherwise IopMountVolume
* will bugcheck with UNMOUNTABLE_BOOT_VOLUME when it tries and fails
* to mount one. */
if (vc->devobj) {
PDEVICE_OBJECT dev = vc->devobj;
ObReferenceObject(dev);
while (dev) {
PDEVICE_OBJECT dev2 = IoGetLowerDeviceObject(dev);
dev->Flags &= ~DO_SYSTEM_BOOT_PARTITION;
ObDereferenceObject(dev);
dev = dev2;
}
}
le2 = le2->Flink;
}
ExReleaseResourceLite(&pdode->child_lock);
if (done)
break; break;
}
ExReleaseResourceLite(&pdode->child_lock);
le = le->Flink; le = le->Flink;
} }
ExReleaseResourceLite(&pdo_list_lock); ExReleaseResourceLite(&pdo_list_lock);
// If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls
// in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our
// own call to AddDevice here as a result. We need to clear the DOE_START_PENDING bits, or NtOpenFile
// will return STATUS_NO_SUCH_DEVICE.
if (pdo_to_add) {
pdo_device_extension* pdode = pdo_to_add->DeviceExtension;
AddDevice(drvobj, pdo_to_add);
// To stop Windows sneakily setting DOE_START_PENDING
pdode->dont_report = true;
if (pdo_to_add->DeviceObjectExtension) {
((DEVOBJ_EXTENSION2*)pdo_to_add->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
if (pdode && pdode->vde && pdode->vde->device)
((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags &= ~DOE_START_PENDING;
}
mountmgr_notification(&pdode->uuid);
}
} }

View file

@ -86,6 +86,7 @@ uint32_t mount_no_trim = 0;
uint32_t mount_clear_cache = 0; uint32_t mount_clear_cache = 0;
uint32_t mount_allow_degraded = 0; uint32_t mount_allow_degraded = 0;
uint32_t mount_readonly = 0; uint32_t mount_readonly = 0;
uint32_t mount_no_root_dir = 0;
uint32_t no_pnp = 0; uint32_t no_pnp = 0;
bool log_started = false; bool log_started = false;
UNICODE_STRING log_device, log_file, registry_path; UNICODE_STRING log_device, log_file, registry_path;
@ -98,6 +99,8 @@ tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx;
tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp; tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp;
tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter; tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter;
tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer; tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer;
tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest;
tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks;
bool diskacc = false; bool diskacc = false;
void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL; void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL;
ERESOURCE pdo_list_lock, mapping_lock; ERESOURCE pdo_list_lock, mapping_lock;
@ -107,6 +110,7 @@ HANDLE degraded_wait_handle = NULL, mountmgr_thread_handle = NULL;
bool degraded_wait = true; bool degraded_wait = true;
KEVENT mountmgr_thread_event; KEVENT mountmgr_thread_event;
bool shutting_down = false; bool shutting_down = false;
ERESOURCE boot_lock;
#ifdef _DEBUG #ifdef _DEBUG
PFILE_OBJECT comfo = NULL; PFILE_OBJECT comfo = NULL;
@ -284,31 +288,6 @@ static void __stdcall DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
TRACE("(%p)\n", DriverObject); TRACE("(%p)\n", DriverObject);
free_cache();
IoUnregisterFileSystem(DriverObject->DeviceObject);
if (notification_entry2) {
if (fIoUnregisterPlugPlayNotificationEx)
fIoUnregisterPlugPlayNotificationEx(notification_entry2);
else
IoUnregisterPlugPlayNotification(notification_entry2);
}
if (notification_entry3) {
if (fIoUnregisterPlugPlayNotificationEx)
fIoUnregisterPlugPlayNotificationEx(notification_entry3);
else
IoUnregisterPlugPlayNotification(notification_entry3);
}
if (notification_entry) {
if (fIoUnregisterPlugPlayNotificationEx)
fIoUnregisterPlugPlayNotificationEx(notification_entry);
else
IoUnregisterPlugPlayNotification(notification_entry);
}
dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name;
dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR); dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR);
@ -504,7 +483,6 @@ static NTSTATUS __stdcall drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP
IrpSp = IoGetCurrentIrpStackLocation(Irp); IrpSp = IoGetCurrentIrpStackLocation(Irp);
// FIXME - unmount if called for volume
// FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
Status = close_file(IrpSp->FileObject, Irp); Status = close_file(IrpSp->FileObject, Irp);
@ -560,6 +538,8 @@ static NTSTATUS __stdcall drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _I
goto end; goto end;
} }
FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
fcb->Header.IsFastIoPossible = fast_io_possible(fcb); fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
@ -615,6 +595,8 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_ uint64_t* to
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
#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);
// This function exists because we have to lie about our FS type in certain situations. // 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, // 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. // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
@ -631,17 +613,10 @@ static bool lie_about_fs_type() {
ULONG_PTR wow64info; ULONG_PTR wow64info;
#endif #endif
static const WCHAR mpr[] = L"MPR.DLL"; INIT_UNICODE_STRING(mpr, L"MPR.DLL");
static const WCHAR cmd[] = L"CMD.EXE"; INIT_UNICODE_STRING(cmd, L"CMD.EXE");
static const WCHAR fsutil[] = L"FSUTIL.EXE"; INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE");
UNICODE_STRING mprus, cmdus, fsutilus; INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL");
mprus.Buffer = (WCHAR*)mpr;
mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR);
cmdus.Buffer = (WCHAR*)cmd;
cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR);
fsutilus.Buffer = (WCHAR*)fsutil;
fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR);
if (!PsGetCurrentProcess()) if (!PsGetCurrentProcess())
return false; return false;
@ -673,31 +648,40 @@ static bool lie_about_fs_type() {
LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
bool blacklist = false; bool blacklist = false;
if (entry->FullDllName.Length >= mprus.Length) { if (entry->FullDllName.Length >= usmpr.Length) {
UNICODE_STRING name; UNICODE_STRING name;
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usmpr.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = mprus.Length; name.Length = name.MaximumLength = usmpr.Length;
blacklist = FsRtlAreNamesEqual(&name, &mprus, true, NULL); blacklist = FsRtlAreNamesEqual(&name, &usmpr, true, NULL);
} }
if (!blacklist && entry->FullDllName.Length >= cmdus.Length) { if (!blacklist && entry->FullDllName.Length >= uscmd.Length) {
UNICODE_STRING name; UNICODE_STRING name;
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - uscmd.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = cmdus.Length; name.Length = name.MaximumLength = uscmd.Length;
blacklist = FsRtlAreNamesEqual(&name, &cmdus, true, NULL); blacklist = FsRtlAreNamesEqual(&name, &uscmd, true, NULL);
} }
if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) { if (!blacklist && entry->FullDllName.Length >= usfsutil.Length) {
UNICODE_STRING name; UNICODE_STRING name;
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)]; name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usfsutil.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = fsutilus.Length; name.Length = name.MaximumLength = usfsutil.Length;
blacklist = FsRtlAreNamesEqual(&name, &fsutilus, true, NULL); blacklist = FsRtlAreNamesEqual(&name, &usfsutil, true, NULL);
}
if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) {
UNICODE_STRING name;
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usstorsvc.Length) / sizeof(WCHAR)];
name.Length = name.MaximumLength = usstorsvc.Length;
blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL);
} }
if (blacklist) { if (blacklist) {
@ -1451,95 +1435,6 @@ end:
return Status; return Status;
} }
static WCHAR* file_desc_fcb(_In_ fcb* fcb) {
char s[60];
NTSTATUS Status;
UNICODE_STRING us;
ANSI_STRING as;
if (fcb->debug_desc)
return fcb->debug_desc;
if (fcb == fcb->Vcb->volume_fcb)
return L"volume FCB";
fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR), ALLOC_TAG);
if (!fcb->debug_desc)
return L"(memory error)";
// I know this is pretty hackish...
// GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
// without the CRT, which breaks drivers.
sprintf(s, "subvol %x, inode %x", (uint32_t)fcb->subvol->id, (uint32_t)fcb->inode);
as.Buffer = s;
as.Length = as.MaximumLength = (USHORT)strlen(s);
us.Buffer = fcb->debug_desc;
us.MaximumLength = 60 * sizeof(WCHAR);
us.Length = 0;
Status = RtlAnsiStringToUnicodeString(&us, &as, false);
if (!NT_SUCCESS(Status))
return L"(RtlAnsiStringToUnicodeString error)";
us.Buffer[us.Length / sizeof(WCHAR)] = 0;
return fcb->debug_desc;
}
WCHAR* file_desc_fileref(_In_ file_ref* fileref) {
NTSTATUS Status;
UNICODE_STRING fn;
ULONG reqlen;
if (fileref->debug_desc)
return fileref->debug_desc;
fn.Length = fn.MaximumLength = 0;
Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
if (Status != STATUS_BUFFER_OVERFLOW)
return L"ERROR";
if (reqlen > 0xffff - sizeof(WCHAR))
return L"(too long)";
fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG);
if (!fileref->debug_desc)
return L"(memory error)";
fn.Buffer = fileref->debug_desc;
fn.Length = 0;
fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR));
Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
if (!NT_SUCCESS(Status)) {
ExFreePool(fileref->debug_desc);
fileref->debug_desc = NULL;
return L"ERROR";
}
fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0;
return fileref->debug_desc;
}
_Ret_z_
WCHAR* file_desc(_In_ PFILE_OBJECT FileObject) {
fcb* fcb = FileObject->FsContext;
ccb* ccb = FileObject->FsContext2;
file_ref* fileref = ccb ? ccb->fileref : NULL;
if (fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE)
return L"(paging file)";
if (fileref)
return file_desc_fileref(fileref);
else
return file_desc_fcb(fcb);
}
void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) {
UNICODE_STRING fn; UNICODE_STRING fn;
NTSTATUS Status; NTSTATUS Status;
@ -1580,7 +1475,7 @@ void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match,
ExFreePool(fn.Buffer); ExFreePool(fn.Buffer);
} }
void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { static void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) {
fcb* fcb = fileref->fcb; fcb* fcb = fileref->fcb;
LIST_ENTRY* le; LIST_ENTRY* le;
NTSTATUS Status; NTSTATUS Status;
@ -1661,6 +1556,61 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ExReleaseResourceLite(&fcb->Vcb->fileref_lock); ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
} }
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);
}
void mark_fcb_dirty(_In_ fcb* fcb) { void mark_fcb_dirty(_In_ fcb* fcb) {
if (!fcb->dirty) { if (!fcb->dirty) {
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
@ -1746,9 +1696,6 @@ void reap_fcb(fcb* fcb) {
if (fcb->adsdata.Buffer) if (fcb->adsdata.Buffer)
ExFreePool(fcb->adsdata.Buffer); ExFreePool(fcb->adsdata.Buffer);
if (fcb->debug_desc)
ExFreePool(fcb->debug_desc);
while (!IsListEmpty(&fcb->extents)) { while (!IsListEmpty(&fcb->extents)) {
LIST_ENTRY* le = RemoveHeadList(&fcb->extents); LIST_ENTRY* le = RemoveHeadList(&fcb->extents);
extent* ext = CONTAINING_RECORD(le, extent, list_entry); extent* ext = CONTAINING_RECORD(le, extent, list_entry);
@ -1795,6 +1742,7 @@ void reap_fcb(fcb* fcb) {
ExFreePool(fcb->hash_ptrs_uc); ExFreePool(fcb->hash_ptrs_uc);
FsRtlUninitializeFileLock(&fcb->lock); FsRtlUninitializeFileLock(&fcb->lock);
FsRtlUninitializeOplock(fcb_oplock(fcb));
if (fcb->pool_type == NonPagedPool) if (fcb->pool_type == NonPagedPool)
ExFreePool(fcb); ExFreePool(fcb);
@ -1842,9 +1790,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
// FIXME - do delete if needed // FIXME - do delete if needed
if (fr->debug_desc)
ExFreePool(fr->debug_desc);
ExDeleteResourceLite(&fr->nonpaged->fileref_lock); ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged); ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
@ -1869,6 +1814,9 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
free_fcb(fr->fcb); free_fcb(fr->fcb);
if (fr->oldutf8.Buffer)
ExFreePool(fr->oldutf8.Buffer);
ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr); ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
} }
@ -1911,7 +1859,7 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) {
ccb = FileObject->FsContext2; ccb = FileObject->FsContext2;
TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb); TRACE("close called for fcb %p)\n", fcb);
// FIXME - make sure notification gets sent if file is being deleted // FIXME - make sure notification gets sent if file is being deleted
@ -1980,9 +1928,13 @@ void uninit(_In_ device_extension* Vcb) {
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
} }
if (Vcb->vde && Vcb->vde->mounted_device == Vcb->devobj)
Vcb->vde->mounted_device = NULL;
IoAcquireVpbSpinLock(&irql); IoAcquireVpbSpinLock(&irql);
Vcb->Vpb->Flags &= ~VPB_MOUNTED; Vcb->Vpb->Flags &= ~VPB_MOUNTED;
Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
Vcb->Vpb->DeviceObject = NULL;
IoReleaseVpbSpinLock(irql); IoReleaseVpbSpinLock(irql);
RemoveEntryList(&Vcb->list_entry); RemoveEntryList(&Vcb->list_entry);
@ -2071,6 +2023,21 @@ void uninit(_In_ device_extension* Vcb) {
le = le->Flink; le = le->Flink;
} }
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);
}
while (!IsListEmpty(&Vcb->roots)) { while (!IsListEmpty(&Vcb->roots)) {
root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root, list_entry); root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root, list_entry);
@ -2111,8 +2078,6 @@ void uninit(_In_ device_extension* Vcb) {
ExFreePool(c); ExFreePool(c);
} }
// FIXME - free any open fcbs?
while (!IsListEmpty(&Vcb->devices)) { while (!IsListEmpty(&Vcb->devices)) {
device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry);
@ -2156,6 +2121,11 @@ void uninit(_In_ device_extension* Vcb) {
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
ZwClose(Vcb->flush_thread_handle); ZwClose(Vcb->flush_thread_handle);
if (Vcb->devobj->AttachedDevice)
IoDetachDevice(Vcb->devobj);
IoDeleteDevice(Vcb->devobj);
} }
static NTSTATUS delete_fileref_fcb(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { static NTSTATUS delete_fileref_fcb(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) {
@ -2422,6 +2392,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
goto exit; goto exit;
} }
FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
// We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
// messages belonging to other devices. // messages belonging to other devices.
@ -2435,7 +2407,7 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
fileref = ccb ? ccb->fileref : NULL; fileref = ccb ? ccb->fileref : NULL;
TRACE("cleanup called for FileObject %p\n", FileObject); TRACE("cleanup called for FileObject %p\n", FileObject);
TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0); TRACE("fileref %p, refcount = %u, open_count = %u\n", fileref, fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0);
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
@ -2475,7 +2447,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIR
if (fileref && (oc == 0 || (fileref->delete_on_close && fileref->posix_delete))) { if (fileref && (oc == 0 || (fileref->delete_on_close && fileref->posix_delete))) {
if (!fcb->Vcb->removing) { if (!fcb->Vcb->removing) {
if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0 && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { // last handle closed on POSIX-deleted file 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; LIST_ENTRY rollback;
InitializeListHead(&rollback); InitializeListHead(&rollback);
@ -2647,9 +2620,8 @@ ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_ex
break; break;
} }
if (dotfile) { if (dotfile || (r->id == BTRFS_ROOT_FSTREE && inode == SUBVOL_ROOT_INODE))
att |= FILE_ATTRIBUTE_HIDDEN; att |= FILE_ATTRIBUTE_HIDDEN;
}
att |= FILE_ATTRIBUTE_ARCHIVE; att |= FILE_ATTRIBUTE_ARCHIVE;
@ -3883,7 +3855,7 @@ static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) {
} }
_Ret_maybenull_ _Ret_maybenull_
static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) {
LIST_ENTRY* le; LIST_ENTRY* le;
static const char fn[] = "default"; static const char fn[] = "default";
@ -3974,7 +3946,7 @@ end:
void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) { void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) {
TRACE("(%p, %p)\n", FileObject, ccfs); TRACE("(%p, %p)\n", FileObject, ccfs);
CcInitializeCacheMap(FileObject, ccfs, false, cache_callbacks, FileObject); CcInitializeCacheMap(FileObject, ccfs, false, &cache_callbacks, FileObject);
if (diskacc) if (diskacc)
fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING); fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING);
@ -3998,6 +3970,7 @@ uint32_t get_num_of_processors() {
static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) { static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) {
device_extension* Vcb = DeviceObject->DeviceExtension; device_extension* Vcb = DeviceObject->DeviceExtension;
OBJECT_ATTRIBUTES oa;
ULONG i; ULONG i;
Vcb->calcthreads.num_threads = get_num_of_processors(); Vcb->calcthreads.num_threads = get_num_of_processors();
@ -4014,13 +3987,15 @@ static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) {
RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads); RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads);
InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
for (i = 0; i < Vcb->calcthreads.num_threads; i++) { for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
NTSTATUS Status; NTSTATUS Status;
Vcb->calcthreads.threads[i].DeviceObject = DeviceObject; Vcb->calcthreads.threads[i].DeviceObject = DeviceObject;
KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, false); KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, false);
Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]); Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, &oa, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ULONG j; ULONG j;
@ -4201,12 +4176,7 @@ static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Out_ bool*
pnp_name.Length = 0; pnp_name.Length = 0;
} }
if (pnp_name.Length == 0) *pno_pnp = pnp_name.Length == 0;
*pno_pnp = true;
else {
*pno_pnp = false;
volume_arrival(drvobj, &pnp_name);
}
if (pnp_name.Buffer) if (pnp_name.Buffer)
ExFreePool(pnp_name.Buffer); ExFreePool(pnp_name.Buffer);
@ -4223,7 +4193,6 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f
NTSTATUS Status; NTSTATUS Status;
ULONG to_read; ULONG to_read;
superblock* sb; superblock* sb;
PDEVICE_OBJECT device2;
if (!device) if (!device)
return false; return false;
@ -4257,14 +4226,20 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_ PFILE_OBJECT f
} }
} }
device2 = device; ObReferenceObject(device);
do { while (device) {
device2->Flags &= ~DO_VERIFY_VOLUME; PDEVICE_OBJECT device2 = IoGetLowerDeviceObject(device);
device2 = IoGetLowerDeviceObject(device2);
} while (device2); device->Flags &= ~DO_VERIFY_VOLUME;
ObDereferenceObject(device);
device = device2;
}
ExFreePool(sb); ExFreePool(sb);
return true; return true;
} }
@ -4286,6 +4261,9 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
pdo_device_extension* pdode = NULL; pdo_device_extension* pdode = NULL;
volume_child* vc; volume_child* vc;
uint64_t readobjsize; uint64_t readobjsize;
OBJECT_ATTRIBUTES oa;
device_extension* real_devext;
KIRQL irql;
TRACE("(%p, %p)\n", DeviceObject, Irp); TRACE("(%p, %p)\n", DeviceObject, Irp);
@ -4297,6 +4275,12 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
IrpSp = IoGetCurrentIrpStackLocation(Irp); IrpSp = IoGetCurrentIrpStackLocation(Irp);
DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject;
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;
if (!is_btrfs_volume(DeviceToMount)) { if (!is_btrfs_volume(DeviceToMount)) {
bool not_pnp = false; bool not_pnp = false;
@ -4313,8 +4297,17 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
pdo = DeviceToMount; pdo = DeviceToMount;
while (IoGetLowerDeviceObject(pdo)) { ObReferenceObject(pdo);
pdo = IoGetLowerDeviceObject(pdo);
while (true) {
PDEVICE_OBJECT pdo2 = IoGetLowerDeviceObject(pdo);
ObDereferenceObject(pdo);
if (!pdo2)
break;
else
pdo = pdo2;
} }
ExAcquireResourceSharedLite(&pdo_list_lock, true); ExAcquireResourceSharedLite(&pdo_list_lock, true);
@ -4797,7 +4790,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
Vcb->root_file->FsContext2 = root_ccb; Vcb->root_file->FsContext2 = root_ccb;
_SEH2_TRY { _SEH2_TRY {
CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, cache_callbacks, Vcb->root_file); CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, &cache_callbacks, Vcb->root_file);
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
Status = _SEH2_GetExceptionCode(); Status = _SEH2_GetExceptionCode();
goto exit; goto exit;
@ -4816,17 +4809,23 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
le = le->Flink; le = le->Flink;
} }
IoAcquireVpbSpinLock(&irql);
NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb; NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb;
IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject; IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject;
IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED; IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED;
NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME
NewDeviceObject->Vpb->VolumeLabel[0] = '?'; NewDeviceObject->Vpb->VolumeLabel[0] = '?';
NewDeviceObject->Vpb->VolumeLabel[1] = 0; NewDeviceObject->Vpb->VolumeLabel[1] = 0;
NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any point? NewDeviceObject->Vpb->ReferenceCount++;
IoReleaseVpbSpinLock(irql);
KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, false); KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, false);
Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL, flush_thread, NewDeviceObject); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, &oa, NULL, NULL, flush_thread, NewDeviceObject);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
goto exit; goto exit;
@ -4851,6 +4850,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
if (vde) if (vde)
vde->mounted_device = NewDeviceObject; vde->mounted_device = NewDeviceObject;
Vcb->devobj = NewDeviceObject;
ExInitializeResourceLite(&Vcb->send_load_lock); ExInitializeResourceLite(&Vcb->send_load_lock);
exit: exit:
@ -5166,7 +5167,7 @@ _Function_class_(DRIVER_DISPATCH)
static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
fcb* fcb = IrpSp->FileObject->FsContext; fcb* fcb = IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL;
device_extension* Vcb = DeviceObject->DeviceExtension; device_extension* Vcb = DeviceObject->DeviceExtension;
bool top_level; bool top_level;
@ -5185,6 +5186,14 @@ static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In
TRACE("lock control\n"); TRACE("lock control\n");
if (!fcb) {
ERR("fcb was NULL\n");
Status = STATUS_INVALID_PARAMETER;
goto exit;
}
FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL); Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL);
fcb->Header.IsFastIoPossible = fast_io_possible(fcb); fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
@ -5200,13 +5209,109 @@ exit:
return Status; return Status;
} }
void do_shutdown(PIRP Irp) {
LIST_ENTRY* le;
bus_device_extension* bde;
shutting_down = true;
KeSetEvent(&mountmgr_thread_event, 0, false);
le = VcbList.Flink;
while (le != &VcbList) {
LIST_ENTRY* le2 = le->Flink;
device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
volume_device_extension* vde = Vcb->vde;
TRACE("shutting down Vcb %p\n", Vcb);
if (vde)
InterlockedIncrement(&vde->open_count);
dismount_volume(Vcb, true, Irp);
if (vde) {
NTSTATUS Status;
UNICODE_STRING mmdevpath;
PDEVICE_OBJECT mountmgr;
PFILE_OBJECT mountmgrfo;
KIRQL irql;
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
if (!NT_SUCCESS(Status))
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
else {
remove_drive_letter(mountmgr, &vde->name);
ObDereferenceObject(mountmgrfo);
}
vde->removing = true;
IoAcquireVpbSpinLock(&irql);
vde->device->Vpb->DeviceObject = vde->device;
IoReleaseVpbSpinLock(irql);
if (InterlockedDecrement(&vde->open_count) == 0)
free_vol(vde);
}
le = le2;
}
#ifdef _DEBUG
if (comfo) {
ObDereferenceObject(comfo);
comdo = NULL;
comfo = NULL;
}
#endif
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) _Dispatch_type_(IRP_MJ_SHUTDOWN)
_Function_class_(DRIVER_DISPATCH) _Function_class_(DRIVER_DISPATCH)
static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
bool top_level; bool top_level;
device_extension* Vcb = DeviceObject->DeviceExtension; device_extension* Vcb = DeviceObject->DeviceExtension;
LIST_ENTRY* le;
FsRtlEnterFileSystem(); FsRtlEnterFileSystem();
@ -5221,45 +5326,7 @@ static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PI
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
shutting_down = true; do_shutdown(Irp);
KeSetEvent(&mountmgr_thread_event, 0, false);
le = VcbList.Flink;
while (le != &VcbList) {
bool open_files;
LIST_ENTRY* le2 = le->Flink;
Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
TRACE("shutting down Vcb %p\n", Vcb);
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
Vcb->removing = true;
open_files = Vcb->open_files > 0;
if (Vcb->need_write && !Vcb->readonly) {
Status = do_write(Vcb, Irp);
if (!NT_SUCCESS(Status))
ERR("do_write returned %08x\n", Status);
}
free_trees(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
if (!open_files)
uninit(Vcb);
le = le2;
}
#ifdef _DEBUG
if (comfo) {
ObDereferenceObject(comfo);
comdo = NULL;
comfo = NULL;
}
#endif
end: end:
Irp->IoStatus.Status = Status; Irp->IoStatus.Status = Status;
@ -5380,7 +5447,7 @@ exit:
return Status; return Status;
} }
bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) { bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream) {
ULONG i; ULONG i;
if (us->Length < sizeof(WCHAR)) if (us->Length < sizeof(WCHAR))
@ -5391,7 +5458,8 @@ bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) {
for (i = 0; i < us->Length / sizeof(WCHAR); i++) { for (i = 0; i < us->Length / sizeof(WCHAR); i++) {
if (us->Buffer[i] == '/' || us->Buffer[i] == 0 || if (us->Buffer[i] == '/' || us->Buffer[i] == 0 ||
(!posix && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == ':' || us->Buffer[i] == '"' || (!posix && (us->Buffer[i] == '/' || us->Buffer[i] == ':')) ||
(!posix && !stream && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == '"' ||
us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31)))) us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31))))
return false; return false;
} }
@ -5518,7 +5586,11 @@ static void init_serial(bool first_time) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status); ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
if (first_time) { if (first_time) {
Status = PsCreateSystemThread(&serial_thread_handle, 0, NULL, NULL, NULL, serial_thread, NULL); OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&serial_thread_handle, 0, &oa, NULL, NULL, serial_thread, NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
return; return;
@ -5692,7 +5764,12 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica
goto end; goto end;
} }
ExAcquireResourceSharedLite(&pdode->child_lock, true); ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
if (pdode->vde) { // if already done, return success
Status = STATUS_SUCCESS;
goto end2;
}
volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR)); volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR));
volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this? volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this?
@ -5736,6 +5813,7 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT Physica
vde->pdo = PhysicalDeviceObject; vde->pdo = PhysicalDeviceObject;
vde->pdode = pdode; vde->pdode = pdode;
vde->removing = false; vde->removing = false;
vde->dead = false;
vde->open_count = 0; vde->open_count = 0;
Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name); Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name);
@ -5775,7 +5853,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
control_device_extension* cde; control_device_extension* cde;
bus_device_extension* bde; bus_device_extension* bde;
HANDLE regh; HANDLE regh;
OBJECT_ATTRIBUTES oa; OBJECT_ATTRIBUTES oa, system_thread_attributes;
ULONG dispos; ULONG dispos;
InitializeListHead(&uid_map_list); InitializeListHead(&uid_map_list);
@ -5844,12 +5922,16 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx"); RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx");
fCcSetAdditionalCacheAttributesEx = (tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name); fCcSetAdditionalCacheAttributesEx = (tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name);
RtlInitUnicodeString(&name, L"FsRtlCheckLockForOplockRequest");
fFsRtlCheckLockForOplockRequest = (tFsRtlCheckLockForOplockRequest)MmGetSystemRoutineAddress(&name);
} else { } else {
fPsUpdateDiskCounters = NULL; fPsUpdateDiskCounters = NULL;
fCcCopyReadEx = NULL; fCcCopyReadEx = NULL;
fCcCopyWriteEx = NULL; fCcCopyWriteEx = NULL;
fCcSetAdditionalCacheAttributesEx = NULL; fCcSetAdditionalCacheAttributesEx = NULL;
fFsRtlUpdateDiskCounters = NULL; fFsRtlUpdateDiskCounters = NULL;
fFsRtlCheckLockForOplockRequest = NULL;
} }
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) { if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) {
@ -5857,8 +5939,13 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx"); RtlInitUnicodeString(&name, L"IoUnregisterPlugPlayNotificationEx");
fIoUnregisterPlugPlayNotificationEx = (tIoUnregisterPlugPlayNotificationEx)MmGetSystemRoutineAddress(&name); fIoUnregisterPlugPlayNotificationEx = (tIoUnregisterPlugPlayNotificationEx)MmGetSystemRoutineAddress(&name);
} else
RtlInitUnicodeString(&name, L"FsRtlAreThereCurrentOrInProgressFileLocks");
fFsRtlAreThereCurrentOrInProgressFileLocks = (tFsRtlAreThereCurrentOrInProgressFileLocks)MmGetSystemRoutineAddress(&name);
} else {
fIoUnregisterPlugPlayNotificationEx = NULL; fIoUnregisterPlugPlayNotificationEx = NULL;
fFsRtlAreThereCurrentOrInProgressFileLocks = NULL;
}
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) { if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) {
UNICODE_STRING name; UNICODE_STRING name;
@ -5935,11 +6022,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
return Status; return Status;
} }
Status = init_cache(); init_cache();
if (!NT_SUCCESS(Status)) {
ERR("init_cache returned %08x\n", Status);
return Status;
}
InitializeListHead(&VcbList); InitializeListHead(&VcbList);
ExInitializeResourceLite(&global_loading_lock); ExInitializeResourceLite(&global_loading_lock);
@ -5990,10 +6073,14 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
IoInvalidateDeviceRelations(bde->buspdo, BusRelations); IoInvalidateDeviceRelations(bde->buspdo, BusRelations);
Status = PsCreateSystemThread(&degraded_wait_handle, 0, NULL, NULL, NULL, degraded_wait_thread, NULL); 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);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
WARN("PsCreateSystemThread returned %08x\n", Status); WARN("PsCreateSystemThread returned %08x\n", Status);
ExInitializeResourceLite(&boot_lock);
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, &notification_entry2); (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, &notification_entry2);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
@ -6013,7 +6100,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_S
KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, false); KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, false);
Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, NULL, NULL, NULL, mountmgr_thread, NULL); Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, &system_thread_attributes, NULL, NULL, mountmgr_thread, NULL);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
WARN("PsCreateSystemThread returned %08x\n", Status); WARN("PsCreateSystemThread returned %08x\n", Status);

View file

@ -52,6 +52,7 @@ static const uint64_t superblock_addrs[] = { 0x10000, 0x4000000, 0x4000000000, 0
#define BTRFS_ROOT_CHUNK 3 #define BTRFS_ROOT_CHUNK 3
#define BTRFS_ROOT_DEVTREE 4 #define BTRFS_ROOT_DEVTREE 4
#define BTRFS_ROOT_FSTREE 5 #define BTRFS_ROOT_FSTREE 5
#define BTRFS_ROOT_TREEDIR 6
#define BTRFS_ROOT_CHECKSUM 7 #define BTRFS_ROOT_CHECKSUM 7
#define BTRFS_ROOT_UUID 9 #define BTRFS_ROOT_UUID 9
#define BTRFS_ROOT_FREE_SPACE 0xa #define BTRFS_ROOT_FREE_SPACE 0xa

View file

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,0,0 FILEVERSION 1,5,0,0
PRODUCTVERSION 1,4,0,0 PRODUCTVERSION 1,5,0,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs" VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "1.4" VALUE "FileVersion", "1.5"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19"
VALUE "OriginalFilename", "btrfs.sys" VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.4" VALUE "ProductVersion", "1.5"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -136,6 +136,12 @@ C_ASSERT(sizeof(bool) == 1);
#define finally if (1) #define finally if (1)
#endif #endif
#ifndef __REACTOS__
#ifdef __GNUC__
#define InterlockedIncrement64(a) __sync_add_and_fetch(a, 1)
#endif
#endif
#ifndef FILE_SUPPORTS_BLOCK_REFCOUNTING #ifndef FILE_SUPPORTS_BLOCK_REFCOUNTING
#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000 #define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000
#endif #endif
@ -248,6 +254,7 @@ typedef struct {
UNICODE_STRING name_uc; UNICODE_STRING name_uc;
ULONG size; ULONG size;
struct _file_ref* fileref; struct _file_ref* fileref;
bool root_dir;
LIST_ENTRY list_entry_index; LIST_ENTRY list_entry_index;
LIST_ENTRY list_entry_hash; LIST_ENTRY list_entry_hash;
LIST_ENTRY list_entry_hash_uc; LIST_ENTRY list_entry_hash_uc;
@ -285,7 +292,6 @@ typedef struct _fcb {
PKTHREAD lazy_writer_thread; PKTHREAD lazy_writer_thread;
ULONG atts; ULONG atts;
SHARE_ACCESS share_access; SHARE_ACCESS share_access;
WCHAR* debug_desc;
bool csum_loaded; bool csum_loaded;
LIST_ENTRY extents; LIST_ENTRY extents;
ANSI_STRING reparse_xattr; ANSI_STRING reparse_xattr;
@ -299,6 +305,7 @@ typedef struct _fcb {
bool marked_as_orphan; bool marked_as_orphan;
bool case_sensitive; bool case_sensitive;
bool case_sensitive_set; bool case_sensitive_set;
OPLOCK oplock;
LIST_ENTRY dir_children_index; LIST_ENTRY dir_children_index;
LIST_ENTRY dir_children_hash; LIST_ENTRY dir_children_hash;
@ -344,7 +351,6 @@ typedef struct _file_ref {
LONG refcount; LONG refcount;
LONG open_count; LONG open_count;
struct _file_ref* parent; struct _file_ref* parent;
WCHAR* debug_desc;
dir_child* dc; dir_child* dc;
bool dirty; bool dirty;
@ -652,6 +658,7 @@ typedef struct {
bool no_trim; bool no_trim;
bool clear_cache; bool clear_cache;
bool allow_degraded; bool allow_degraded;
bool no_root_dir;
} mount_options; } mount_options;
#define VCB_TYPE_FS 1 #define VCB_TYPE_FS 1
@ -729,6 +736,7 @@ typedef struct _device_extension {
uint32_t type; uint32_t type;
mount_options options; mount_options options;
PVPB Vpb; PVPB Vpb;
PDEVICE_OBJECT devobj;
struct _volume_device_extension* vde; struct _volume_device_extension* vde;
LIST_ENTRY devices; LIST_ENTRY devices;
#ifdef DEBUG_CHUNK_LOCKS #ifdef DEBUG_CHUNK_LOCKS
@ -846,6 +854,7 @@ typedef struct _volume_device_extension {
UNICODE_STRING bus_name; UNICODE_STRING bus_name;
PDEVICE_OBJECT attached_device; PDEVICE_OBJECT attached_device;
bool removing; bool removing;
bool dead;
LONG open_count; LONG open_count;
} volume_device_extension; } volume_device_extension;
@ -855,6 +864,7 @@ typedef struct pdo_device_extension {
volume_device_extension* vde; volume_device_extension* vde;
PDEVICE_OBJECT pdo; PDEVICE_OBJECT pdo;
bool removable; bool removable;
bool dont_report;
uint64_t num_children; uint64_t num_children;
uint64_t children_loaded; uint64_t children_loaded;
@ -912,6 +922,7 @@ typedef struct {
uint32_t length; uint32_t length;
uint8_t* data; uint8_t* data;
chunk* c; chunk* c;
bool allocated;
LIST_ENTRY list_entry; LIST_ENTRY list_entry;
} tree_write; } tree_write;
@ -1082,9 +1093,9 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
void uninit(_In_ device_extension* Vcb); void uninit(_In_ device_extension* Vcb);
NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize,
_Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK* iosb); _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK* iosb);
bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix); bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream);
void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream);
void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream); void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream);
#ifdef DEBUG_CHUNK_LOCKS #ifdef DEBUG_CHUNK_LOCKS
#define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock, true); InterlockedIncrement(&Vcb->chunk_locks_held); } #define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock, true); InterlockedIncrement(&Vcb->chunk_locks_held); }
@ -1094,9 +1105,6 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
#define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock) #define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock)
#endif #endif
_Ret_z_
WCHAR* file_desc(_In_ PFILE_OBJECT FileObject);
WCHAR* file_desc_fileref(_In_ file_ref* fileref);
void mark_fcb_dirty(_In_ fcb* fcb); void mark_fcb_dirty(_In_ fcb* fcb);
void mark_fileref_dirty(_In_ file_ref* fileref); void mark_fileref_dirty(_In_ file_ref* fileref);
NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ bool make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback); NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ bool make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback);
@ -1122,6 +1130,11 @@ NTSTATUS utf8_to_utf16(WCHAR* dest, ULONG dest_max, ULONG* dest_len, char* src,
NTSTATUS utf16_to_utf8(char* dest, ULONG dest_max, ULONG* dest_len, WCHAR* src, ULONG src_len); NTSTATUS utf16_to_utf8(char* dest, ULONG dest_max, ULONG* dest_len, WCHAR* src, ULONG src_len);
uint32_t get_num_of_processors(); uint32_t get_num_of_processors();
_Ret_maybenull_
root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp);
void do_shutdown(PIRP Irp);
#ifdef _MSC_VER #ifdef _MSC_VER
#define funcname __FUNCTION__ #define funcname __FUNCTION__
#else #else
@ -1143,6 +1156,7 @@ extern uint32_t mount_no_trim;
extern uint32_t mount_clear_cache; extern uint32_t mount_clear_cache;
extern uint32_t mount_allow_degraded; extern uint32_t mount_allow_degraded;
extern uint32_t mount_readonly; extern uint32_t mount_readonly;
extern uint32_t mount_no_root_dir;
extern uint32_t no_pnp; extern uint32_t no_pnp;
#ifdef _DEBUG #ifdef _DEBUG
@ -1274,9 +1288,8 @@ void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lo
_In_ volume_child* vc, _In_ bool skip_dev); _In_ volume_child* vc, _In_ bool skip_dev);
// in cache.c // in cache.c
NTSTATUS init_cache(); void init_cache();
void free_cache(); extern CACHE_MANAGER_CALLBACKS cache_callbacks;
extern CACHE_MANAGER_CALLBACKS* cache_callbacks;
// in write.c // in write.c
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write); NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write);
@ -1398,6 +1411,7 @@ void do_unlock_volume(device_extension* Vcb);
void trim_whole_device(device* dev); void trim_whole_device(device* dev);
void flush_subvol_fcbs(root* subvol); void flush_subvol_fcbs(root* subvol);
bool fcb_is_inline(fcb* fcb); bool fcb_is_inline(fcb* fcb);
NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp);
// in flushthread.c // in flushthread.c
@ -1552,6 +1566,8 @@ NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devp
_Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context); NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context);
void free_vol(volume_device_extension* vde);
// in scrub.c // in scrub.c
NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode); NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode);
NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode, void* data, ULONG length); NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode, void* data, ULONG length);
@ -1564,7 +1580,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ
NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, ULONG_PTR* retlen, KPROCESSOR_MODE processor_mode); NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, ULONG_PTR* retlen, KPROCESSOR_MODE processor_mode);
// in fsrtl.c // in fsrtl.c
NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer); NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer);
// in boot.c // in boot.c
void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG Count); void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG Count);
@ -1572,7 +1588,43 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULO
// based on function in sys/sysmacros.h // based on function in sys/sysmacros.h
#define makedev(major, minor) (((minor) & 0xFF) | (((major) & 0xFFF) << 8) | (((uint64_t)((minor) & ~0xFF)) << 12) | (((uint64_t)((major) & ~0xFFF)) << 32)) #define makedev(major, minor) (((minor) & 0xFF) | (((major) & 0xFFF) << 8) | (((uint64_t)((minor) & ~0xFF)) << 12) | (((uint64_t)((major) & ~0xFFF)) << 32))
#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable) // not in mingw yet
#ifndef _MSC_VER
typedef struct {
FSRTL_COMMON_FCB_HEADER DUMMYSTRUCTNAME;
PFAST_MUTEX FastMutex;
LIST_ENTRY FilterContexts;
EX_PUSH_LOCK PushLock;
PVOID* FileContextSupportPointer;
union {
OPLOCK Oplock;
PVOID ReservedForRemote;
};
PVOID ReservedContext;
} FSRTL_ADVANCED_FCB_HEADER_NEW;
#define FSRTL_FCB_HEADER_V2 2
#else
#define FSRTL_ADVANCED_FCB_HEADER_NEW FSRTL_ADVANCED_FCB_HEADER
#endif
static __inline POPLOCK fcb_oplock(fcb* fcb) {
if (fcb->Header.Version >= FSRTL_FCB_HEADER_V2)
return &((FSRTL_ADVANCED_FCB_HEADER_NEW*)&fcb->Header)->Oplock;
else
return &fcb->oplock;
}
static __inline FAST_IO_POSSIBLE fast_io_possible(fcb* fcb) {
if (!FsRtlOplockIsFastIoPossible(fcb_oplock(fcb)))
return FastIoIsNotPossible;
if (!FsRtlAreThereCurrentFileLocks(&fcb->lock) && !fcb->Vcb->readonly)
return FastIoIsPossible;
return FastIoIsQuestionable;
}
static __inline void print_open_trees(device_extension* Vcb) { static __inline void print_open_trees(device_extension* Vcb) {
LIST_ENTRY* le = Vcb->trees.Flink; LIST_ENTRY* le = Vcb->trees.Flink;
@ -1738,16 +1790,16 @@ static __inline uint64_t fcb_alloc_size(fcb* fcb) {
return sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size); return sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
} }
typedef BOOLEAN (*tPsIsDiskCountersEnabled)(); typedef BOOLEAN (__stdcall *tPsIsDiskCountersEnabled)();
typedef VOID (*tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64 BytesWritten, typedef VOID (__stdcall *tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64 BytesWritten,
ULONG ReadOperationCount, ULONG WriteOperationCount, ULONG FlushOperationCount); ULONG ReadOperationCount, ULONG WriteOperationCount, ULONG FlushOperationCount);
typedef BOOLEAN (*tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, typedef BOOLEAN (__stdcall *tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait,
PVOID Buffer, PETHREAD IoIssuerThread); PVOID Buffer, PETHREAD IoIssuerThread);
typedef BOOLEAN (*tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, typedef BOOLEAN (__stdcall *tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait,
PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD IoIssuerThread); PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD IoIssuerThread);
#ifndef CC_ENABLE_DISK_IO_ACCOUNTING #ifndef CC_ENABLE_DISK_IO_ACCOUNTING
#define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010 #define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010
@ -1758,22 +1810,26 @@ typedef struct _ECP_LIST ECP_LIST;
typedef struct _ECP_LIST *PECP_LIST; typedef struct _ECP_LIST *PECP_LIST;
#endif #endif
typedef VOID (*tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags); typedef VOID (__stdcall *tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags);
typedef VOID (*tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten); typedef VOID (__stdcall *tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten);
typedef NTSTATUS (*tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry); typedef NTSTATUS (__stdcall *tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry);
typedef NTSTATUS (*tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList); typedef NTSTATUS (__stdcall *tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList);
typedef NTSTATUS (*tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType, typedef NTSTATUS (__stdcall *tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType,
PVOID* NextEcpContext, ULONG* NextEcpContextSize); PVOID* NextEcpContext, ULONG* NextEcpContextSize);
typedef NTSTATUS (*tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer); typedef NTSTATUS (__stdcall *tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer);
typedef BOOLEAN (__stdcall *tFsRtlCheckLockForOplockRequest)(PFILE_LOCK FileLock, PLARGE_INTEGER AllocationSize);
typedef BOOLEAN (__stdcall *tFsRtlAreThereCurrentOrInProgressFileLocks)(PFILE_LOCK FileLock);
#ifndef __REACTOS__ #ifndef __REACTOS__
#ifndef _MSC_VER #ifndef _MSC_VER
PEPROCESS PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw PEPROCESS __stdcall PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw
#endif #endif
// not in DDK headers - taken from winternl.h // not in DDK headers - taken from winternl.h

View file

@ -36,6 +36,7 @@
#define FSCTL_BTRFS_SEND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x846, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_BTRFS_SEND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x846, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_READ_SEND_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x847, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) #define FSCTL_BTRFS_READ_SEND_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x847, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_RESIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x848, METHOD_IN_DIRECT, FILE_ANY_ACCESS) #define FSCTL_BTRFS_RESIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x848, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
#define IOCTL_BTRFS_UNLOAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x849, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef struct { typedef struct {
uint64_t subvol; uint64_t subvol;

View file

@ -17,7 +17,7 @@
#include "btrfs_drv.h" #include "btrfs_drv.h"
CACHE_MANAGER_CALLBACKS* cache_callbacks; CACHE_MANAGER_CALLBACKS cache_callbacks;
static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) { static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) {
PFILE_OBJECT FileObject = Context; PFILE_OBJECT FileObject = Context;
@ -82,21 +82,9 @@ static void __stdcall release_from_read_ahead(PVOID Context) {
IoSetTopLevelIrp(NULL); IoSetTopLevelIrp(NULL);
} }
NTSTATUS init_cache() { void init_cache() {
cache_callbacks = ExAllocatePoolWithTag(NonPagedPool, sizeof(CACHE_MANAGER_CALLBACKS), ALLOC_TAG); cache_callbacks.AcquireForLazyWrite = acquire_for_lazy_write;
if (!cache_callbacks) { cache_callbacks.ReleaseFromLazyWrite = release_from_lazy_write;
ERR("out of memory\n"); cache_callbacks.AcquireForReadAhead = acquire_for_read_ahead;
return STATUS_INSUFFICIENT_RESOURCES; cache_callbacks.ReleaseFromReadAhead = release_from_read_ahead;
}
cache_callbacks->AcquireForLazyWrite = acquire_for_lazy_write;
cache_callbacks->ReleaseFromLazyWrite = release_from_lazy_write;
cache_callbacks->AcquireForReadAhead = acquire_for_read_ahead;
cache_callbacks->ReleaseFromReadAhead = release_from_read_ahead;
return STATUS_SUCCESS;
}
void free_cache() {
ExFreePool(cache_callbacks);
} }

View file

@ -28,6 +28,9 @@ extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer;
static const WCHAR datastring[] = L"::$DATA"; static const WCHAR datastring[] = L"::$DATA";
static const char root_dir[] = "$Root";
static const WCHAR root_dir_utf16[] = L"$Root";
// Windows 10 // Windows 10
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002 #define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100 #define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
@ -101,6 +104,7 @@ fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock); ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
FsRtlInitializeFileLock(&fcb->lock, NULL, NULL); FsRtlInitializeFileLock(&fcb->lock, NULL, NULL);
FsRtlInitializeOplock(fcb_oplock(fcb));
InitializeListHead(&fcb->extents); InitializeListHead(&fcb->extents);
InitializeListHead(&fcb->hardlinks); InitializeListHead(&fcb->hardlinks);
@ -470,6 +474,7 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extens
traverse_ptr tp, next_tp; traverse_ptr tp, next_tp;
NTSTATUS Status; NTSTATUS Status;
ULONG num_children = 0; ULONG num_children = 0;
uint64_t max_index = 2;
fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
if (!fcb->hash_ptrs) { if (!fcb->hash_ptrs) {
@ -538,6 +543,9 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extens
dc->index = tp.item->key.offset; dc->index = tp.item->key.offset;
dc->type = di->type; dc->type = di->type;
dc->fileref = NULL; dc->fileref = NULL;
dc->root_dir = false;
max_index = dc->index;
dc->utf8.MaximumLength = dc->utf8.Length = di->n; dc->utf8.MaximumLength = dc->utf8.Length = di->n;
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG); dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
@ -592,6 +600,68 @@ cont:
break; break;
} }
if (!Vcb->options.no_root_dir && fcb->inode == SUBVOL_ROOT_INODE) {
root* top_subvol;
if (Vcb->root_fileref && Vcb->root_fileref->fcb)
top_subvol = Vcb->root_fileref->fcb->subvol;
else
top_subvol = find_default_subvol(Vcb, NULL);
if (fcb->subvol == top_subvol && top_subvol->id != BTRFS_ROOT_FSTREE) {
dir_child* dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
if (!dc) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
dc->key.obj_id = BTRFS_ROOT_FSTREE;
dc->key.obj_type = TYPE_ROOT_ITEM;
dc->key.offset = 0;
dc->index = max_index + 1;
dc->type = BTRFS_TYPE_DIRECTORY;
dc->fileref = NULL;
dc->root_dir = true;
dc->utf8.MaximumLength = dc->utf8.Length = sizeof(root_dir) - sizeof(char);
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir) - sizeof(char), ALLOC_TAG);
if (!dc->utf8.Buffer) {
ERR("out of memory\n");
ExFreePool(dc);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(dc->utf8.Buffer, root_dir, sizeof(root_dir) - sizeof(char));
dc->name.MaximumLength = dc->name.Length = sizeof(root_dir_utf16) - sizeof(WCHAR);
dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir_utf16) - sizeof(WCHAR), ALLOC_TAG);
if (!dc->name.Buffer) {
ERR("out of memory\n");
ExFreePool(dc->utf8.Buffer);
ExFreePool(dc);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory(dc->name.Buffer, root_dir_utf16, sizeof(root_dir_utf16) - sizeof(WCHAR));
Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
if (!NT_SUCCESS(Status)) {
ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
ExFreePool(dc->utf8.Buffer);
ExFreePool(dc->name.Buffer);
ExFreePool(dc);
goto cont;
}
dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
insert_dir_child_into_hash_lists(fcb, dc);
}
}
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -1239,6 +1309,9 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lo
} }
} }
if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE)
fcb->atts |= FILE_ATTRIBUTE_HIDDEN;
subvol->fcbs_version++; subvol->fcbs_version++;
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
@ -1517,7 +1590,7 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id)) { if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id && !dc->root_dir)) {
fcb = Vcb->dummy_fcb; fcb = Vcb->dummy_fcb;
InterlockedIncrement(&fcb->refcount); InterlockedIncrement(&fcb->refcount);
} else { } else {
@ -1639,8 +1712,8 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv
} }
if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) { if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
WARN("passed related fileref which isn't a directory (%S) (fnus = %.*S)\n", WARN("passed related fileref which isn't a directory (fnus = %.*S)\n",
file_desc_fileref(related), fnus->Length / sizeof(WCHAR), fnus->Buffer); fnus->Length / sizeof(WCHAR), fnus->Buffer);
return STATUS_OBJECT_PATH_NOT_FOUND; return STATUS_OBJECT_PATH_NOT_FOUND;
} }
@ -1690,7 +1763,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusiv
bool cs = case_sensitive; bool cs = case_sensitive;
if (!cs) { if (!cs) {
if (streampart) if (streampart && sf->parent)
cs = sf->parent->fcb->case_sensitive; cs = sf->parent->fcb->case_sensitive;
else else
cs = sf->fcb->case_sensitive; cs = sf->fcb->case_sensitive;
@ -2223,7 +2296,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement(&parfileref->fcb->refcount); rc = InterlockedIncrement(&parfileref->fcb->refcount);
WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref)); WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
#else #else
InterlockedIncrement(&parfileref->fcb->refcount); InterlockedIncrement(&parfileref->fcb->refcount);
#endif #endif
@ -2441,9 +2514,9 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
} }
#ifndef __REACTOS__ #ifndef __REACTOS__
UINT32 dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length);
#else #else
dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length); dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length);
#endif #endif
if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) { if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) {
@ -2512,7 +2585,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr
*pfr = fileref; *pfr = fileref;
TRACE("created new file %S in subvol %I64x, inode %I64x\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode); TRACE("created new file in subvol %I64x, inode %I64x\n", fcb->subvol->id, fcb->inode);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -2557,7 +2630,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) { if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
UNICODE_STRING fpus2; UNICODE_STRING fpus2;
if (!is_file_name_valid(fpus, false)) if (!is_file_name_valid(fpus, false, true))
return STATUS_OBJECT_NAME_INVALID; return STATUS_OBJECT_NAME_INVALID;
fpus2.Length = fpus2.MaximumLength = fpus->Length; fpus2.Length = fpus2.MaximumLength = fpus->Length;
@ -2590,7 +2663,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return Status; return Status;
} else if (Status != STATUS_OBJECT_NAME_COLLISION) { } else if (Status != STATUS_OBJECT_NAME_COLLISION) {
send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
} }
ExFreePool(fpus2.Buffer); ExFreePool(fpus2.Buffer);
@ -2655,7 +2728,7 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement(&parfileref->fcb->refcount); rc = InterlockedIncrement(&parfileref->fcb->refcount);
WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref)); WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
#else #else
InterlockedIncrement(&parfileref->fcb->refcount); InterlockedIncrement(&parfileref->fcb->refcount);
#endif #endif
@ -2920,9 +2993,17 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize); Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) { if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID)) {
acec = ctx; if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
break; acec = ctx;
else {
ERR("GUID_ECP_ATOMIC_CREATE context was too short: %u bytes, expected %u\n", ctxsize,
sizeof(ATOMIC_CREATE_ECP_CONTEXT));
}
} else {
WARN("unhandled ECP {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", type.Data1, type.Data2,
type.Data3, type.Data4[0], type.Data4[1], type.Data4[2], type.Data4[3], type.Data4[4], type.Data4[5],
type.Data4[6], type.Data4[7]);
} }
} }
} while (NT_SUCCESS(Status)); } while (NT_SUCCESS(Status));
@ -3015,7 +3096,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
} else { } else {
ACCESS_MASK granted_access; ACCESS_MASK granted_access;
if (!is_file_name_valid(&fpus, false)) { if (!is_file_name_valid(&fpus, false, false)) {
Status = STATUS_OBJECT_NAME_INVALID; Status = STATUS_OBJECT_NAME_INVALID;
goto end; goto end;
} }
@ -3056,7 +3137,7 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access); IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
} }
FileObject->FsContext = fileref->fcb; FileObject->FsContext = fileref->fcb;
@ -3140,13 +3221,10 @@ static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _R
fileref->dc->type = fileref->fcb->type; fileref->dc->type = fileref->fcb->type;
goto end2;
end: end:
if (fpus.Buffer) if (fpus.Buffer)
ExFreePool(fpus.Buffer); ExFreePool(fpus.Buffer);
end2:
if (parfileref && !loaded_related) if (parfileref && !loaded_related)
free_fileref(parfileref); free_fileref(parfileref);
@ -3414,7 +3492,7 @@ static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extens
while (le != &fcb->extents) { while (le != &fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry); extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (ext->extent_data.type == EXTENT_TYPE_REGULAR) { if (!ext->ignore && ext->extent_data.type == EXTENT_TYPE_REGULAR) {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0]; EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
uint64_t len; uint64_t len;
@ -3581,7 +3659,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
return STATUS_FILE_IS_A_DIRECTORY; return STATUS_FILE_IS_A_DIRECTORY;
} }
} else if (options & FILE_DIRECTORY_FILE) { } else if (options & FILE_DIRECTORY_FILE) {
TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref)); TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", fileref->fcb->type);
free_fileref(fileref); free_fileref(fileref);
@ -3617,6 +3695,15 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
} }
} }
// FIXME - this can block waiting for network IO, while we're holding fileref_lock and tree_lock
Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, NULL, NULL, NULL);
if (!NT_SUCCESS(Status)) {
WARN("FsRtlCheckOplock returned %08x\n", Status);
free_fileref(fileref);
return Status;
}
if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
ULONG defda, oldatts, filter; ULONG defda, oldatts, filter;
LARGE_INTEGER time; LARGE_INTEGER time;
@ -3759,7 +3846,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
} }
if (dc->fileref) { if (dc->fileref) {
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback); Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -3787,7 +3874,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
fileref->parent->fcb->inode_item_changed = true; fileref->parent->fcb->inode_item_changed = true;
mark_fcb_dirty(fileref->parent->fcb); mark_fcb_dirty(fileref->parent->fcb);
send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name); queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
} else { } else {
mark_fcb_dirty(fileref->fcb); mark_fcb_dirty(fileref->fcb);
@ -3813,7 +3900,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
fileref->fcb->inode_item.st_mtime = now; fileref->fcb->inode_item.st_mtime = now;
fileref->fcb->inode_item_changed = true; fileref->fcb->inode_item_changed = true;
send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
} }
} else { } else {
if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) { if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
@ -4222,9 +4309,21 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
hl_alloc = true; hl_alloc = true;
} }
} else { } else {
ERR("couldn't find parent for subvol %I64x\n", subvol->id); if (!Vcb->options.no_root_dir && subvol->id == BTRFS_ROOT_FSTREE && Vcb->root_fileref->fcb->subvol != subvol) {
free_fcb(fcb); Status = open_fileref_by_inode(Vcb, Vcb->root_fileref->fcb->subvol, SUBVOL_ROOT_INODE, &parfr, Irp);
return STATUS_INTERNAL_ERROR; if (!NT_SUCCESS(Status)) {
ERR("open_fileref_by_inode returned %08x\n", Status);
free_fcb(fcb);
return Status;
}
name.Length = name.MaximumLength = sizeof(root_dir_utf16) - sizeof(WCHAR);
name.Buffer = (WCHAR*)root_dir_utf16;
} else {
ERR("couldn't find parent for subvol %I64x\n", subvol->id);
free_fcb(fcb);
return STATUS_INTERNAL_ERROR;
}
} }
} else { } else {
Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp); Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp);
@ -4471,7 +4570,7 @@ loaded:
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
if (RequestedDisposition == FILE_CREATE) { if (RequestedDisposition == FILE_CREATE) {
TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref)); TRACE("file already exists, returning STATUS_OBJECT_NAME_COLLISION\n");
Status = STATUS_OBJECT_NAME_COLLISION; Status = STATUS_OBJECT_NAME_COLLISION;
free_fileref(fileref); free_fileref(fileref);
@ -4788,7 +4887,7 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length / sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer); TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length / sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer);
if (IrpSp->FileObject->RelatedFileObject) if (IrpSp->FileObject->RelatedFileObject)
TRACE("related file = %S\n", file_desc(IrpSp->FileObject->RelatedFileObject)); TRACE("related file = %p\n", IrpSp->FileObject->RelatedFileObject);
// Don't lock again if we're being called from within CcCopyRead etc. // Don't lock again if we're being called from within CcCopyRead etc.
skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock); skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);

View file

@ -212,6 +212,17 @@ static NTSTATUS probe_volume(void* data, ULONG length, KPROCESSOR_MODE processor
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS ioctl_unload(PIRP Irp) {
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE), Irp->RequestorMode)) {
ERR("insufficient privileges\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
do_shutdown(Irp);
return STATUS_SUCCESS;
}
static NTSTATUS control_ioctl(PIRP Irp) { static NTSTATUS control_ioctl(PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status; NTSTATUS Status;
@ -225,6 +236,10 @@ static NTSTATUS control_ioctl(PIRP Irp) {
Status = probe_volume(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.FileSystemControl.InputBufferLength, Irp->RequestorMode); Status = probe_volume(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.FileSystemControl.InputBufferLength, Irp->RequestorMode);
break; break;
case IOCTL_BTRFS_UNLOAD:
Status = ioctl_unload(Irp);
break;
default: default:
TRACE("unhandled ioctl %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode); TRACE("unhandled ioctl %x\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
Status = STATUS_NOT_IMPLEMENTED; Status = STATUS_NOT_IMPLEMENTED;

View file

@ -209,7 +209,7 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG* len, PIRP Ir
le = le->Flink; le = le->Flink;
} }
if (r && r->parent != fcb->subvol->id) if (r && r->parent != fcb->subvol->id && (!de->dc || !de->dc->root_dir))
r = NULL; r = NULL;
inode = SUBVOL_ROOT_INODE; inode = SUBVOL_ROOT_INODE;
@ -1115,7 +1115,7 @@ static NTSTATUS notify_change_directory(device_extension* Vcb, PIRP Irp) {
// FIXME - raise exception if FCB marked for deletion? // FIXME - raise exception if FCB marked for deletion?
TRACE("%S\n", file_desc(FileObject)); TRACE("FileObject %p\n", FileObject);
if (ccb->filename.Length == 0) { if (ccb->filename.Length == 0) {
ULONG reqlen; ULONG reqlen;

View file

@ -336,15 +336,33 @@ static NTSTATUS __stdcall fast_io_release_for_ccflush(PFILE_OBJECT FileObject, P
_Function_class_(FAST_IO_WRITE) _Function_class_(FAST_IO_WRITE)
static BOOLEAN __stdcall fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) { static BOOLEAN __stdcall fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PDEVICE_OBJECT DeviceObject) {
if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject)) { fcb* fcb = FileObject->FsContext;
fcb* fcb = FileObject->FsContext; bool ret;
fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart; FsRtlEnterFileSystem();
return true; if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) {
FsRtlExitFileSystem();
return false;
} }
return false; if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, Wait)) {
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
FsRtlExitFileSystem();
return false;
}
ret = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject);
if (ret)
fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
ExReleaseResourceLite(fcb->Header.Resource);
ExReleaseResourceLite(&fcb->Vcb->tree_lock);
FsRtlExitFileSystem();
return ret;
} }
_Function_class_(FAST_IO_LOCK) _Function_class_(FAST_IO_LOCK)

File diff suppressed because it is too large Load diff

View file

@ -545,6 +545,9 @@ nextdev:
for (num = 0; num < total_num; num++) { for (num = 0; num < total_num; num++) {
if (context.stripes[num].dmdsa) if (context.stripes[num].dmdsa)
ExFreePool(context.stripes[num].dmdsa); ExFreePool(context.stripes[num].dmdsa);
if (context.stripes[num].Irp)
IoFreeIrp(context.stripes[num].Irp);
} }
ExFreePool(context.stripes); ExFreePool(context.stripes);
@ -1633,13 +1636,14 @@ NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY* tree_writes, bool no_
RtlCopyMemory(data, tw2->data, tw2->length); RtlCopyMemory(data, tw2->data, tw2->length);
RtlCopyMemory(&data[tw2->length], tw->data, tw->length); RtlCopyMemory(&data[tw2->length], tw->data, tw->length);
if (!no_free) if (!no_free || tw2->allocated)
ExFreePool(tw2->data); ExFreePool(tw2->data);
tw2->data = data; tw2->data = data;
tw2->length += tw->length; tw2->length += tw->length;
tw2->allocated = true;
if (!no_free) // FIXME - what if we allocated this just now? if (!no_free || tw->allocated)
ExFreePool(tw->data); ExFreePool(tw->data);
RemoveEntryList(&tw->list_entry); RemoveEntryList(&tw->list_entry);
@ -2025,6 +2029,7 @@ static NTSTATUS write_trees(device_extension* Vcb, PIRP Irp) {
tw->address = t->new_address; tw->address = t->new_address;
tw->length = Vcb->superblock.node_size; tw->length = Vcb->superblock.node_size;
tw->data = data; tw->data = data;
tw->allocated = false;
if (IsListEmpty(&tree_writes)) if (IsListEmpty(&tree_writes))
InsertTailList(&tree_writes, &tw->list_entry); InsertTailList(&tree_writes, &tw->list_entry);
@ -6482,8 +6487,6 @@ static NTSTATUS flush_fileref(file_ref* fileref, LIST_ENTRY* batchlist, PIRP Irp
crc32 = calc_crc32c(0xfffffffe, (uint8_t*)name->Buffer, name->Length); crc32 = calc_crc32c(0xfffffffe, (uint8_t*)name->Buffer, name->Length);
TRACE("deleting %.*S\n", file_desc_fileref(fileref));
di = ExAllocatePoolWithTag(PagedPool, sizeof(DIR_ITEM) - 1 + name->Length, ALLOC_TAG); di = ExAllocatePoolWithTag(PagedPool, sizeof(DIR_ITEM) - 1 + name->Length, ALLOC_TAG);
if (!di) { if (!di) {
ERR("out of memory\n"); ERR("out of memory\n");
@ -6750,6 +6753,9 @@ static void flush_disk_caches(device_extension* Vcb) {
LIST_ENTRY* le; LIST_ENTRY* le;
ioctl_context context; ioctl_context context;
ULONG num; ULONG num;
#ifdef __REACTOS__
unsigned int i;
#endif
context.left = 0; context.left = 0;
@ -6827,6 +6833,15 @@ nextdev:
KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL); KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL);
#ifndef __REACTOS__
for (unsigned int i = 0; i < num; i++) {
#else
for (i = 0; i < num; i++) {
#endif
if (context.stripes[i].Irp)
IoFreeIrp(context.stripes[i].Irp);
}
ExFreePool(context.stripes); ExFreePool(context.stripes);
} }

View file

@ -44,6 +44,8 @@
extern LIST_ENTRY VcbList; extern LIST_ENTRY VcbList;
extern ERESOURCE global_loading_lock; extern ERESOURCE global_loading_lock;
extern PDRIVER_OBJECT drvobj; extern PDRIVER_OBJECT drvobj;
extern tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest;
extern tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks;
static void mark_subvol_dirty(device_extension* Vcb, root* r); static void mark_subvol_dirty(device_extension* Vcb, root* r);
@ -598,7 +600,7 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject,
if (is_subvol_readonly(fcb->subvol, Irp)) if (is_subvol_readonly(fcb->subvol, Irp))
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
if (!is_file_name_valid(&nameus, posix)) if (!is_file_name_valid(&nameus, posix, false))
return STATUS_OBJECT_NAME_INVALID; return STATUS_OBJECT_NAME_INVALID;
utf8.Buffer = NULL; utf8.Buffer = NULL;
@ -820,7 +822,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
nameus.Length = nameus.MaximumLength = bcs->namelen; nameus.Length = nameus.MaximumLength = bcs->namelen;
nameus.Buffer = bcs->name; nameus.Buffer = bcs->name;
if (!is_file_name_valid(&nameus, bcs->posix)) if (!is_file_name_valid(&nameus, bcs->posix, false))
return STATUS_OBJECT_NAME_INVALID; return STATUS_OBJECT_NAME_INVALID;
utf8.Buffer = NULL; utf8.Buffer = NULL;
@ -1789,7 +1791,7 @@ static NTSTATUS set_sparse(device_extension* Vcb, PFILE_OBJECT FileObject, void*
} }
mark_fcb_dirty(fcb); mark_fcb_dirty(fcb);
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
@ -2059,7 +2061,7 @@ static NTSTATUS set_zero_data(device_extension* Vcb, PFILE_OBJECT FileObject, vo
fcb->inode_item_changed = true; fcb->inode_item_changed = true;
mark_fcb_dirty(fcb); mark_fcb_dirty(fcb);
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
fcb->subvol->root_item.ctransid = Vcb->superblock.generation; fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
fcb->subvol->root_item.ctime = now; fcb->subvol->root_item.ctime = now;
@ -2568,22 +2570,25 @@ static void update_volumes(device_extension* Vcb) {
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
} }
static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) { NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
bool open_files;
TRACE("FSCTL_DISMOUNT_VOLUME\n"); TRACE("FSCTL_DISMOUNT_VOLUME\n");
if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) if (!(Vcb->Vpb->Flags & VPB_MOUNTED))
return STATUS_SUCCESS; return STATUS_SUCCESS;
if (Vcb->disallow_dismount || Vcb->page_file_count != 0) { if (!shutdown) {
WARN("attempting to dismount boot volume or one containing a pagefile\n"); if (Vcb->disallow_dismount || Vcb->page_file_count != 0) {
return STATUS_ACCESS_DENIED; WARN("attempting to dismount boot volume or one containing a pagefile\n");
} return STATUS_ACCESS_DENIED;
}
Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT); Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status); WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
}
} }
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
@ -2603,6 +2608,8 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
Vcb->removing = true; Vcb->removing = true;
open_files = Vcb->open_files > 0;
if (Vcb->vde) { if (Vcb->vde) {
update_volumes(Vcb); update_volumes(Vcb);
Vcb->vde->mounted_device = NULL; Vcb->vde->mounted_device = NULL;
@ -2610,6 +2617,9 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
if (!open_files)
uninit(Vcb);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -3647,7 +3657,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb, PFILE_OBJECT FileObject
if (!ccb->user_set_write_time) { if (!ccb->user_set_write_time) {
fcb->inode_item.st_mtime = now; fcb->inode_item.st_mtime = now;
send_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
} }
fcb->inode_item_changed = true; fcb->inode_item_changed = true;
@ -4040,7 +4050,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
send_notification_fileref(fileref, bmn->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL); send_notification_fileref(fileref, bmn->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
if (!parccb->user_set_write_time) if (!parccb->user_set_write_time)
send_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
@ -4727,6 +4737,7 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG len, PIRP
delta = dev->devitem.num_bytes - br->size; delta = dev->devitem.num_bytes - br->size;
if (need_balance) { if (need_balance) {
OBJECT_ATTRIBUTES oa;
int i; int i;
if (Vcb->balance.thread) { if (Vcb->balance.thread) {
@ -4751,7 +4762,9 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data, ULONG len, PIRP
space_list_subtract2(&dev->space, NULL, br->size, delta, NULL, NULL); space_list_subtract2(&dev->space, NULL, br->size, delta, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL, balance_thread, Vcb); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL, balance_thread, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
goto end; goto end;
@ -4835,57 +4848,145 @@ end:
return Status; return Status;
} }
static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
NTSTATUS Status;
PIRP Irp = *Pirp;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
uint32_t fsctl = IrpSp->Parameters.FileSystemControl.FsControlCode;
PFILE_OBJECT FileObject = IrpSp->FileObject;
fcb* fcb = FileObject ? FileObject->FsContext : NULL;
ccb* ccb = FileObject ? FileObject->FsContext2 : NULL;
file_ref* fileref = ccb ? ccb->fileref : NULL;
#if (NTDDI_VERSION >= NTDDI_WIN7)
PREQUEST_OPLOCK_INPUT_BUFFER buf = NULL;
bool oplock_request = false, oplock_ack = false;
#else
bool oplock_request = false;
#endif
ULONG oplock_count = 0;
#ifdef __REACTOS__
bool shared_request;
#endif
if (!fcb) {
ERR("fcb was NULL\n");
return STATUS_INVALID_PARAMETER;
}
if (!fileref) {
ERR("fileref was NULL\n");
return STATUS_INVALID_PARAMETER;
}
if (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_DIRECTORY)
return STATUS_INVALID_PARAMETER;
#if (NTDDI_VERSION >= NTDDI_WIN7)
if (fsctl == FSCTL_REQUEST_OPLOCK) {
if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER))
return STATUS_BUFFER_TOO_SMALL;
if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))
return STATUS_BUFFER_TOO_SMALL;
buf = Irp->AssociatedIrp.SystemBuffer;
// flags are mutually exclusive
if (buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST && buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK)
return STATUS_INVALID_PARAMETER;
oplock_request = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
oplock_ack = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK;
if (!oplock_request && !oplock_ack)
return STATUS_INVALID_PARAMETER;
}
#endif
#if (NTDDI_VERSION >= NTDDI_WIN7)
bool shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2) || (fsctl == FSCTL_REQUEST_OPLOCK && !(buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_WRITE));
#else
shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2);
#endif
#if (NTDDI_VERSION >= NTDDI_WIN7)
if (fcb->type == BTRFS_TYPE_DIRECTORY && (fsctl != FSCTL_REQUEST_OPLOCK || !shared_request)) {
#else
if (fcb->type == BTRFS_TYPE_DIRECTORY && !shared_request) {
#endif
WARN("oplock requests on directories can only be for read or read-handle oplocks\n");
return STATUS_INVALID_PARAMETER;
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || fsctl == FSCTL_REQUEST_FILTER_OPLOCK ||
fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
if (shared_request) {
if (fcb->type == BTRFS_TYPE_FILE) {
if (fFsRtlCheckLockForOplockRequest)
oplock_count = !fFsRtlCheckLockForOplockRequest(&fcb->lock, &fcb->Header.AllocationSize);
else if (fFsRtlAreThereCurrentOrInProgressFileLocks)
oplock_count = fFsRtlAreThereCurrentOrInProgressFileLocks(&fcb->lock);
else
oplock_count = FsRtlAreThereCurrentFileLocks(&fcb->lock);
}
} else
oplock_count = fileref->open_count;
} else
ExAcquireResourceSharedLite(fcb->Header.Resource, true);
#if (NTDDI_VERSION >= NTDDI_WIN7)
if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||
(fsctl == FSCTL_REQUEST_OPLOCK && buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_HANDLE)) &&
#else
if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK) &&
#endif
fileref->delete_on_close) {
ExReleaseResourceLite(fcb->Header.Resource);
ExReleaseResourceLite(&Vcb->tree_lock);
return STATUS_DELETE_PENDING;
}
Status = FsRtlOplockFsctrl(fcb_oplock(fcb), Irp, oplock_count);
*Pirp = NULL;
fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
ExReleaseResourceLite(fcb->Header.Resource);
ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
}
NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) { NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
PIRP Irp = *Pirp; PIRP Irp = *Pirp;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status; NTSTATUS Status;
if (IrpSp->FileObject && IrpSp->FileObject->FsContext) {
device_extension* Vcb = DeviceObject->DeviceExtension;
if (Vcb->type == VCB_TYPE_FS)
FsRtlCheckOplock(fcb_oplock(IrpSp->FileObject->FsContext), Irp, NULL, NULL, NULL);
}
switch (type) { switch (type) {
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
case FSCTL_REQUEST_BATCH_OPLOCK:
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
case FSCTL_OPLOCK_BREAK_NOTIFY:
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
case FSCTL_REQUEST_FILTER_OPLOCK:
#if (NTDDI_VERSION >= NTDDI_WIN7) #if (NTDDI_VERSION >= NTDDI_WIN7)
case FSCTL_REQUEST_OPLOCK: case FSCTL_REQUEST_OPLOCK:
WARN("STUB: FSCTL_REQUEST_OPLOCK\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
#endif #endif
Status = fsctl_oplock(DeviceObject->DeviceExtension, Pirp);
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_REQUEST_BATCH_OPLOCK:
WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_OPLOCK_BREAK_NOTIFY:
WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case FSCTL_REQUEST_FILTER_OPLOCK:
WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
Status = STATUS_INVALID_DEVICE_REQUEST;
break; break;
case FSCTL_LOCK_VOLUME: case FSCTL_LOCK_VOLUME:
@ -4897,7 +4998,7 @@ NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
break; break;
case FSCTL_DISMOUNT_VOLUME: case FSCTL_DISMOUNT_VOLUME:
Status = dismount_volume(DeviceObject->DeviceExtension, Irp); Status = dismount_volume(DeviceObject->DeviceExtension, false, Irp);
break; break;
case FSCTL_IS_VOLUME_MOUNTED: case FSCTL_IS_VOLUME_MOUNTED:

View file

@ -29,7 +29,7 @@ IsEven(IN USHORT Digit)
return ((Digit & 1) != 1); return ((Digit & 1) != 1);
} }
NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer) NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer)
{ {
USHORT DataLength; USHORT DataLength;
ULONG ReparseTag; ULONG ReparseTag;

View file

@ -185,14 +185,15 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true); ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) { if (Vcb->root_fileref && Vcb->root_fileref->fcb && (Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref))) {
Status = STATUS_ACCESS_DENIED; ExReleaseResourceLite(&Vcb->tree_lock);
goto end; return STATUS_ACCESS_DENIED;
} }
Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE); Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
WARN("send_disks_pnp_message returned %08x\n", Status); WARN("send_disks_pnp_message returned %08x\n", Status);
goto end; ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
} }
Vcb->removing = true; Vcb->removing = true;
@ -204,16 +205,17 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("do_write returned %08x\n", Status); ERR("do_write returned %08x\n", Status);
goto end; ExReleaseResourceLite(&Vcb->tree_lock);
return Status;
} }
} }
Status = STATUS_SUCCESS;
end:
ExReleaseResourceLite(&Vcb->tree_lock); ExReleaseResourceLite(&Vcb->tree_lock);
return Status; if (Vcb->open_files == 0)
uninit(Vcb);
return STATUS_SUCCESS;
} }
static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) { static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
@ -294,7 +296,10 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) {
le = pdo_list.Flink; le = pdo_list.Flink;
while (le != &pdo_list) { while (le != &pdo_list) {
num_children++; pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
if (!pdode->dont_report)
num_children++;
le = le->Flink; le = le->Flink;
} }
@ -315,9 +320,11 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) {
while (le != &pdo_list) { while (le != &pdo_list) {
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
ObReferenceObject(pdode->pdo); if (!pdode->dont_report) {
dr->Objects[i] = pdode->pdo; ObReferenceObject(pdode->pdo);
i++; dr->Objects[i] = pdode->pdo;
i++;
}
le = le->Flink; le = le->Flink;
} }
@ -539,6 +546,29 @@ static NTSTATUS pdo_device_usage_notification(pdo_device_extension* pdode, PIRP
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS pdo_query_device_relations(PDEVICE_OBJECT pdo, PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_RELATIONS device_relations;
if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
return Irp->IoStatus.Status;
device_relations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), ALLOC_TAG);
if (!device_relations) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
device_relations->Count = 1;
device_relations->Objects[0] = pdo;
ObReferenceObject(pdo);
Irp->IoStatus.Information = (ULONG_PTR)device_relations;
return STATUS_SUCCESS;
}
static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) { static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
pdo_device_extension* pdode = pdo->DeviceExtension; pdo_device_extension* pdode = pdo->DeviceExtension;
@ -559,6 +589,8 @@ static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) {
case IRP_MN_DEVICE_USAGE_NOTIFICATION: case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return pdo_device_usage_notification(pdode, Irp); return pdo_device_usage_notification(pdode, Irp);
case IRP_MN_QUERY_DEVICE_RELATIONS:
return pdo_query_device_relations(pdo, Irp);
} }
return Irp->IoStatus.Status; return Irp->IoStatus.Status;

View file

@ -3114,7 +3114,7 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {
if (!fcb || !fcb->Vcb || !fcb->subvol) if (!fcb || !fcb->Vcb || !fcb->subvol)
return STATUS_INTERNAL_ERROR; return STATUS_INTERNAL_ERROR;
TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb); TRACE("fcb = %p\n", fcb);
TRACE("offset = %I64x, length = %x\n", start, length); TRACE("offset = %I64x, length = %x\n", start, length);
TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false", Irp->Flags & IRP_NOCACHE ? "true" : "false"); TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false", Irp->Flags & IRP_NOCACHE ? "true" : "false");
@ -3318,6 +3318,9 @@ NTSTATUS __stdcall drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto exit2; goto exit2;
} }
if (!(Irp->Flags & IRP_PAGING_IO))
FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
wait = IoIsOperationSynchronous(Irp); wait = IoIsOperationSynchronous(Irp);
// Don't offload jobs when doing paging IO - otherwise this can lead to // Don't offload jobs when doing paging IO - otherwise this can lead to

View file

@ -37,7 +37,8 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
BTRFS_UUID* uuid = &Vcb->superblock.uuid; BTRFS_UUID* uuid = &Vcb->superblock.uuid;
mount_options* options = &Vcb->options; mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus, UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus, readonlyus, zliblevelus, flushintervalus,
maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus; maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus, clearcacheus, allowdegradedus, zstdlevelus,
norootdirus;
OBJECT_ATTRIBUTES oa; OBJECT_ATTRIBUTES oa;
NTSTATUS Status; NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen; ULONG i, j, kvfilen, index, retlen;
@ -121,6 +122,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
RtlInitUnicodeString(&clearcacheus, L"ClearCache"); RtlInitUnicodeString(&clearcacheus, L"ClearCache");
RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded"); RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel"); RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
RtlInitUnicodeString(&norootdirus, L"NoRootDir");
do { do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen); Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen, &retlen);
@ -193,6 +195,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset); DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
options->zstd_level = *val; options->zstd_level = *val;
} else if (FsRtlAreNamesEqual(&norootdirus, &us, true, NULL) && kvfi->DataOffset > 0 && kvfi->DataLength > 0 && kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
options->no_root_dir = *val;
} }
} else if (Status != STATUS_NO_MORE_ENTRIES) { } else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08x\n", Status); ERR("ZwEnumerateValueKey returned %08x\n", Status);
@ -805,6 +811,7 @@ void read_registry(PUNICODE_STRING regpath, bool refresh) {
get_registry_value(h, L"AllowDegraded", REG_DWORD, &mount_allow_degraded, sizeof(mount_allow_degraded)); get_registry_value(h, L"AllowDegraded", REG_DWORD, &mount_allow_degraded, sizeof(mount_allow_degraded));
get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly)); get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly, sizeof(mount_readonly));
get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level)); get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level, sizeof(mount_zstd_level));
get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir, sizeof(mount_no_root_dir));
if (!refresh) if (!refresh)
get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp)); get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp, sizeof(no_pnp));

View file

@ -414,8 +414,6 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
fcb = fileref->fcb; fcb = fileref->fcb;
} }
TRACE("%S\n", file_desc(FileObject));
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
@ -425,7 +423,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto end; goto end;
} }
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end: end:
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
@ -488,8 +486,6 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true); ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
TRACE("%S\n", file_desc(FileObject));
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) { if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) {
ERR("buffer was too short\n"); ERR("buffer was too short\n");
Status = STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER;
@ -619,7 +615,7 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end: end:
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))

View file

@ -3265,6 +3265,7 @@ end:
NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) { NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) {
NTSTATUS Status; NTSTATUS Status;
OBJECT_ATTRIBUTES oa;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode)) if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
return STATUS_PRIVILEGE_NOT_HELD; return STATUS_PRIVILEGE_NOT_HELD;
@ -3292,7 +3293,9 @@ NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) {
Vcb->scrub.error = STATUS_SUCCESS; Vcb->scrub.error = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->scrub.event, NotificationEvent, !Vcb->scrub.paused); KeInitializeEvent(&Vcb->scrub.event, NotificationEvent, !Vcb->scrub.paused);
Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, NULL, NULL, NULL, scrub_thread, Vcb); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, &oa, NULL, NULL, scrub_thread, Vcb);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
return Status; return Status;

View file

@ -23,6 +23,7 @@
#include <windef.h> #include <windef.h>
#include <ntddstor.h> #include <ntddstor.h>
#include <ntdddisk.h> #include <ntdddisk.h>
#include <ntddvol.h>
#include <initguid.h> #include <initguid.h>
#include <wdmguid.h> #include <wdmguid.h>
@ -35,6 +36,7 @@ extern HANDLE mountmgr_thread_handle;
extern bool shutting_down; extern bool shutting_down;
extern PDEVICE_OBJECT busobj; extern PDEVICE_OBJECT busobj;
extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx; extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx;
extern ERESOURCE boot_lock;
typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath);
@ -270,8 +272,11 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
UNUSED(DriverObject); UNUSED(DriverObject);
ExAcquireResourceSharedLite(&boot_lock, TRUE);
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj); Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ExReleaseResourceLite(&boot_lock);
ERR("IoGetDeviceObjectPointer returned %08x\n", Status); ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return; return;
} }
@ -323,6 +328,8 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
end: end:
ObDereferenceObject(fileobj); ObDereferenceObject(fileobj);
ExReleaseResourceLite(&boot_lock);
} }
void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde, void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde,
@ -496,8 +503,11 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
ExAcquireResourceSharedLite(&boot_lock, TRUE);
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj); Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj, &devobj);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ExReleaseResourceLite(&boot_lock);
ERR("IoGetDeviceObjectPointer returned %08x\n", Status); ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return; return;
} }
@ -507,6 +517,10 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
if (devobj->DriverObject == DriverObject) if (devobj->DriverObject == DriverObject)
goto end; goto end;
Status = dev_ioctl(devobj, IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, true, NULL);
if (!NT_SUCCESS(Status))
TRACE("IOCTL_VOLUME_ONLINE returned %08x\n", Status);
Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), true, NULL); Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), true, NULL);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status); ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status);
@ -570,6 +584,8 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
end: end:
ObDereferenceObject(fileobj); ObDereferenceObject(fileobj);
ExReleaseResourceLite(&boot_lock);
} }
void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
@ -648,6 +664,8 @@ static void __stdcall do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) {
ExFreePool(context->name.Buffer); ExFreePool(context->name.Buffer);
IoFreeWorkItem(context->work_item); IoFreeWorkItem(context->work_item);
ExFreePool(context);
} }
static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) { static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) {
@ -655,6 +673,10 @@ static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING na
pnp_callback_context* context; pnp_callback_context* context;
work_item = IoAllocateWorkItem(master_devobj); work_item = IoAllocateWorkItem(master_devobj);
if (!work_item) {
ERR("out of memory\n");
return;
}
context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG); context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG);

View file

@ -432,7 +432,7 @@ static void get_top_level_sd(fcb* fcb) {
goto end; goto end;
} }
RtlSetOwnerSecurityDescriptor(&sd, usersid, false); Status = RtlSetOwnerSecurityDescriptor(&sd, usersid, false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status); ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status);
@ -442,11 +442,10 @@ static void get_top_level_sd(fcb* fcb) {
gid_to_sid(fcb->inode_item.st_gid, &groupsid); gid_to_sid(fcb->inode_item.st_gid, &groupsid);
if (!groupsid) { if (!groupsid) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
RtlSetGroupSecurityDescriptor(&sd, groupsid, false); Status = RtlSetGroupSecurityDescriptor(&sd, groupsid, false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status); ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status);
@ -486,7 +485,6 @@ static void get_top_level_sd(fcb* fcb) {
fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG);
if (!fcb->sd) { if (!fcb->sd) {
ERR("out of memory\n"); ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end; goto end;
} }
@ -494,6 +492,8 @@ static void get_top_level_sd(fcb* fcb) {
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status); ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status);
ExFreePool(fcb->sd);
fcb->sd = NULL;
goto end; goto end;
} }
@ -528,6 +528,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP Irp) {
&subjcont, IoGetFileObjectGenericMapping(), PagedPool); &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("SeAssignSecurityEx returned %08x\n", Status); ERR("SeAssignSecurityEx returned %08x\n", Status);
return;
} }
Status = uid_to_sid(fcb->inode_item.st_uid, &usersid); Status = uid_to_sid(fcb->inode_item.st_uid, &usersid);
@ -541,6 +542,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP Irp) {
gid_to_sid(fcb->inode_item.st_gid, &groupsid); gid_to_sid(fcb->inode_item.st_gid, &groupsid);
if (!groupsid) { if (!groupsid) {
ERR("out of memory\n"); ERR("out of memory\n");
ExFreePool(usersid);
return; return;
} }
@ -733,7 +735,7 @@ static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT FileObject
mark_fcb_dirty(fcb); mark_fcb_dirty(fcb);
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL); queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL);
end: end:
ExReleaseResourceLite(fcb->Header.Resource); ExReleaseResourceLite(fcb->Header.Resource);

View file

@ -3598,6 +3598,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ
send_info* send; send_info* send;
ULONG num_clones = 0; ULONG num_clones = 0;
root** clones = NULL; root** clones = NULL;
OBJECT_ATTRIBUTES oa;
if (!FileObject || !FileObject->FsContext || !FileObject->FsContext2 || FileObject->FsContext == Vcb->volume_fcb) if (!FileObject || !FileObject->FsContext || !FileObject->FsContext2 || FileObject->FsContext == Vcb->volume_fcb)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
@ -3810,7 +3811,9 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG datalen, PFILE_OBJ
InterlockedIncrement(&Vcb->running_sends); InterlockedIncrement(&Vcb->running_sends);
Status = PsCreateSystemThread(&send->thread, 0, NULL, NULL, NULL, send_thread, context); InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&send->thread, 0, &oa, NULL, NULL, send_thread, context);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status); ERR("PsCreateSystemThread returned %08x\n", Status);
ccb->send = NULL; ccb->send = NULL;

View file

@ -31,6 +31,7 @@ extern PDEVICE_OBJECT busobj;
extern ERESOURCE pdo_list_lock; extern ERESOURCE pdo_list_lock;
extern LIST_ENTRY pdo_list; extern LIST_ENTRY pdo_list;
extern UNICODE_STRING registry_path; extern UNICODE_STRING registry_path;
extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx;
NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension; volume_device_extension* vde = DeviceObject->DeviceExtension;
@ -46,6 +47,51 @@ NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
void free_vol(volume_device_extension* vde) {
PDEVICE_OBJECT pdo;
vde->dead = true;
if (vde->mounted_device) {
device_extension* Vcb = vde->mounted_device->DeviceExtension;
Vcb->vde = NULL;
}
if (vde->name.Buffer)
ExFreePool(vde->name.Buffer);
ExDeleteResourceLite(&vde->pdode->child_lock);
if (vde->pdo->AttachedDevice)
IoDetachDevice(vde->pdo);
while (!IsListEmpty(&vde->pdode->children)) {
volume_child* vc = CONTAINING_RECORD(RemoveHeadList(&vde->pdode->children), volume_child, list_entry);
if (vc->notification_entry) {
if (fIoUnregisterPlugPlayNotificationEx)
fIoUnregisterPlugPlayNotificationEx(vc->notification_entry);
else
IoUnregisterPlugPlayNotification(vc->notification_entry);
}
if (vc->pnp_name.Buffer)
ExFreePool(vc->pnp_name.Buffer);
ExFreePool(vc);
}
if (no_pnp)
ExFreePool(vde->pdode);
pdo = vde->pdo;
IoDeleteDevice(vde->device);
if (!no_pnp)
IoDeleteDevice(pdo);
}
NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension; volume_device_extension* vde = DeviceObject->DeviceExtension;
pdo_device_extension* pdode = vde->pdode; pdo_device_extension* pdode = vde->pdode;
@ -54,47 +100,22 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Information = 0; Irp->IoStatus.Information = 0;
if (vde->dead)
return STATUS_SUCCESS;
ExAcquireResourceExclusiveLite(&pdo_list_lock, true); ExAcquireResourceExclusiveLite(&pdo_list_lock, true);
if (vde->dead) {
ExReleaseResourceLite(&pdo_list_lock);
return STATUS_SUCCESS;
}
ExAcquireResourceSharedLite(&pdode->child_lock, true); ExAcquireResourceSharedLite(&pdode->child_lock, true);
if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) { if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) {
NTSTATUS Status;
UNICODE_STRING mmdevpath;
PDEVICE_OBJECT mountmgr;
PFILE_OBJECT mountmgrfo;
PDEVICE_OBJECT pdo;
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
if (!NT_SUCCESS(Status))
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
else {
remove_drive_letter(mountmgr, &vde->name);
ObDereferenceObject(mountmgrfo);
}
if (vde->mounted_device) {
device_extension* Vcb = vde->mounted_device->DeviceExtension;
Vcb->vde = NULL;
}
if (vde->name.Buffer)
ExFreePool(vde->name.Buffer);
ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdode->child_lock);
ExDeleteResourceLite(&pdode->child_lock);
if (vde->pdo->AttachedDevice) free_vol(vde);
IoDetachDevice(vde->pdo);
pdo = vde->pdo;
IoDeleteDevice(vde->device);
if (!no_pnp)
IoDeleteDevice(pdo);
} else } else
ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdode->child_lock);
@ -767,6 +788,8 @@ static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP Irp) {
ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdode->child_lock);
IoFreeIrp(Irp2);
return Status; return Status;
} }
@ -998,20 +1021,118 @@ end:
} }
typedef struct { typedef struct {
PIO_WORKITEM work_item; LIST_ENTRY list_entry;
pdo_device_extension* pdode; UNICODE_STRING name;
} drive_letter_callback_context; NTSTATUS Status;
BTRFS_UUID uuid;
} drive_letter_removal;
static void drive_letter_callback2(pdo_device_extension* pdode, PDEVICE_OBJECT mountmgr) {
LIST_ENTRY* le;
LIST_ENTRY dlrlist;
InitializeListHead(&dlrlist);
ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
le = pdode->children.Flink;
while (le != &pdode->children) {
drive_letter_removal* dlr;
volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
dlr = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_removal), ALLOC_TAG);
if (!dlr) {
ERR("out of memory\n");
while (!IsListEmpty(&dlrlist)) {
dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry);
ExFreePool(dlr->name.Buffer);
ExFreePool(dlr);
}
ExReleaseResourceLite(&pdode->child_lock);
return;
}
dlr->name.Length = dlr->name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR));
dlr->name.Buffer = ExAllocatePoolWithTag(PagedPool, dlr->name.Length, ALLOC_TAG);
if (!dlr->name.Buffer) {
ERR("out of memory\n");
ExFreePool(dlr);
while (!IsListEmpty(&dlrlist)) {
dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry);
ExFreePool(dlr->name.Buffer);
ExFreePool(dlr);
}
ExReleaseResourceLite(&pdode->child_lock);
return;
}
RtlCopyMemory(dlr->name.Buffer, L"\\??", 3 * sizeof(WCHAR));
RtlCopyMemory(&dlr->name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length);
dlr->uuid = vc->uuid;
InsertTailList(&dlrlist, &dlr->list_entry);
le = le->Flink;
}
ExReleaseResourceLite(&pdode->child_lock);
le = dlrlist.Flink;
while (le != &dlrlist) {
drive_letter_removal* dlr = CONTAINING_RECORD(le, drive_letter_removal, list_entry);
dlr->Status = remove_drive_letter(mountmgr, &dlr->name);
if (!NT_SUCCESS(dlr->Status) && dlr->Status != STATUS_NOT_FOUND)
WARN("remove_drive_letter returned %08x\n", dlr->Status);
le = le->Flink;
}
// set vc->had_drive_letter
ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
while (!IsListEmpty(&dlrlist)) {
drive_letter_removal* dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry);
le = pdode->children.Flink;
while (le != &pdode->children) {
volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
if (RtlCompareMemory(&vc->uuid, &dlr->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
vc->had_drive_letter = NT_SUCCESS(dlr->Status);
break;
}
le = le->Flink;
}
ExFreePool(dlr->name.Buffer);
ExFreePool(dlr);
}
ExReleaseResourceLite(&pdode->child_lock);
}
_Function_class_(IO_WORKITEM_ROUTINE) _Function_class_(IO_WORKITEM_ROUTINE)
static void __stdcall drive_letter_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { static void __stdcall drive_letter_callback(pdo_device_extension* pdode) {
drive_letter_callback_context* context = con;
NTSTATUS Status; NTSTATUS Status;
UNICODE_STRING mmdevpath; UNICODE_STRING mmdevpath;
PDEVICE_OBJECT mountmgr; PDEVICE_OBJECT mountmgr;
PFILE_OBJECT mountmgrfo; PFILE_OBJECT mountmgrfo;
LIST_ENTRY* le;
UNUSED(DeviceObject);
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
@ -1020,86 +1141,9 @@ static void __stdcall drive_letter_callback(PDEVICE_OBJECT DeviceObject, PVOID c
return; return;
} }
ExAcquireResourceSharedLite(&pdo_list_lock, true); drive_letter_callback2(pdode, mountmgr);
le = pdo_list.Flink;
while (le != &pdo_list) {
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
if (pdode == context->pdode) {
LIST_ENTRY* le2;
ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
le2 = pdode->children.Flink;
while (le2 != &pdode->children) {
UNICODE_STRING name;
volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR));
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
if (!name.Buffer) {
ERR("out of memory\n");
ExReleaseResourceLite(&pdode->child_lock);
ExReleaseResourceLite(&pdo_list_lock);
ObDereferenceObject(mountmgrfo);
IoFreeWorkItem(context->work_item);
return;
}
RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR));
RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length);
Status = remove_drive_letter(mountmgr, &name);
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
WARN("remove_drive_letter returned %08x\n", Status);
ExFreePool(name.Buffer);
vc->had_drive_letter = NT_SUCCESS(Status);
le2 = le2->Flink;
}
ExReleaseResourceLite(&pdode->child_lock);
ExReleaseResourceLite(&pdo_list_lock);
ObDereferenceObject(mountmgrfo);
IoFreeWorkItem(context->work_item);
return;
}
le = le->Flink;
}
ExReleaseResourceLite(&pdo_list_lock);
ObDereferenceObject(mountmgrfo); ObDereferenceObject(mountmgrfo);
IoFreeWorkItem(context->work_item);
}
static void add_drive_letter_work_item(pdo_device_extension* pdode) {
PIO_WORKITEM work_item;
drive_letter_callback_context* context;
work_item = IoAllocateWorkItem(master_devobj);
context = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_callback_context), ALLOC_TAG);
if (!context) {
ERR("out of memory\n");
IoFreeWorkItem(work_item);
return;
}
context->work_item = work_item;
context->pdode = pdode;
IoQueueWorkItem(work_item, drive_letter_callback, DelayedWorkQueue, context);
} }
void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, ULONG disk_num, ULONG part_num) { void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, ULONG disk_num, ULONG part_num) {
@ -1112,6 +1156,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length,
bool inserted = false, new_pdo = false; bool inserted = false, new_pdo = false;
pdo_device_extension* pdode = NULL; pdo_device_extension* pdode = NULL;
PDEVICE_OBJECT pdo = NULL; PDEVICE_OBJECT pdo = NULL;
bool process_drive_letters = false;
if (devpath->Length == 0) if (devpath->Length == 0)
return; return;
@ -1312,7 +1357,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length,
WARN("IoSetDeviceInterfaceState returned %08x\n", Status); WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
} }
add_drive_letter_work_item(pdode); process_drive_letters = true;
} }
ExReleaseResourceLite(&pdode->child_lock); ExReleaseResourceLite(&pdode->child_lock);
@ -1322,6 +1367,9 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length,
ExReleaseResourceLite(&pdo_list_lock); ExReleaseResourceLite(&pdo_list_lock);
if (process_drive_letters)
drive_letter_callback(pdode);
if (new_pdo) { if (new_pdo) {
if (no_pnp) if (no_pnp)
AddDevice(drvobj, pdo); AddDevice(drvobj, pdo);

View file

@ -4164,7 +4164,7 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
TRACE("(%p, %p, %I64x, %p, %x, %u, %u)\n", Vcb, FileObject, offset.QuadPart, buf, *length, paging_io, no_cache); TRACE("(%p, %p, %I64x, %p, %x, %u, %u)\n", Vcb, FileObject, offset.QuadPart, buf, *length, paging_io, no_cache);
if (*length == 0) { if (*length == 0) {
WARN("returning success for zero-length write\n"); TRACE("returning success for zero-length write\n");
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -4231,20 +4231,18 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
acquired_tree_lock = true; acquired_tree_lock = true;
} }
if (no_cache) { if (pagefile) {
if (pagefile) { if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) { Status = STATUS_PENDING;
Status = STATUS_PENDING; goto end;
goto end; } else
} else acquired_fcb_lock = true;
acquired_fcb_lock = true; } else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) {
} else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) { if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) {
if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) { Status = STATUS_PENDING;
Status = STATUS_PENDING; goto end;
goto end; } else
} else acquired_fcb_lock = true;
acquired_fcb_lock = true;
}
} }
newlength = fcb->ads ? fcb->adsdata.Length : fcb->inode_item.st_size; newlength = fcb->ads ? fcb->adsdata.Length : fcb->inode_item.st_size;
@ -4258,7 +4256,6 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
if (paging_io) { if (paging_io) {
if (off64 >= newlength) { if (off64 >= newlength) {
TRACE("paging IO tried to write beyond end of file (file size = %I64x, offset = %I64x, length = %x)\n", newlength, off64, *length); TRACE("paging IO tried to write beyond end of file (file size = %I64x, offset = %I64x, length = %x)\n", newlength, off64, *length);
TRACE("filename %S\n", file_desc(FileObject));
TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n", TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n",
fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
@ -4354,8 +4351,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
} _SEH2_END; } _SEH2_END;
if (changed_length) { if (changed_length) {
send_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE, queue_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE,
fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL); fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name : NULL);
} }
goto end; goto end;
@ -4609,8 +4606,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
if (filter != 0) if (filter != 0)
send_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED, queue_notification_fcb(fcb->ads ? fileref->parent : fileref, filter, fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED,
fcb->ads && fileref->dc ? &fileref->dc->name : NULL); fcb->ads && fileref->dc ? &fileref->dc->name : NULL);
end: end:
if (NT_SUCCESS(Status) && FileObject->Flags & FO_SYNCHRONOUS_IO && !paging_io) { if (NT_SUCCESS(Status) && FileObject->Flags & FO_SYNCHRONOUS_IO && !paging_io) {
@ -4779,6 +4776,9 @@ NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->MdlAddress = NULL; Irp->MdlAddress = NULL;
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} else { } else {
if (!(Irp->Flags & IRP_PAGING_IO))
FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
// Don't offload jobs when doing paging IO - otherwise this can lead to // Don't offload jobs when doing paging IO - otherwise this can lead to
// deadlocks in CcCopyWrite. // deadlocks in CcCopyWrite.
if (Irp->Flags & IRP_PAGING_IO) if (Irp->Flags & IRP_PAGING_IO)

View file

@ -3,7 +3,7 @@
The following FSD are shared with: https://github.com/maharmstone/btrfs. The following FSD are shared with: https://github.com/maharmstone/btrfs.
reactos/drivers/filesystems/btrfs # Synced to 1.4 reactos/drivers/filesystems/btrfs # Synced to 1.5
reactos/dll/shellext/shellbtrfs # Synced to 1.1 reactos/dll/shellext/shellbtrfs # Synced to 1.1
reactos/sdk/lib/fslib/btrfslib # Synced to 1.4 reactos/sdk/lib/fslib/btrfslib # Synced to 1.4