Upgrade the driver to release 0.66.
CORE-11295 #resolve #comment Committed in r71411
svn path=/trunk/; revision=71411
BOOLEAN bExt3Writable;
BOOLEAN bExt2;
BOOLEAN bExt3;
- UCHAR Codepage[CODEPAGE_MAXLEN];
-} EXT2_VOLUME_PROPERTY;
+ CHAR Codepage[CODEPAGE_MAXLEN];
+} EXT2_VOLUME_PROPERTY, *PEXT2_VOLUME_PROPERTY;
#ifdef __cplusplus
typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY {
} EXT2_VOLUME_PROPERTY2, *PEXT2_VOLUME_PROPERTY2;
-#define EXT2_VPROP3_AUTOMOUNT 0x0000000000000001
+#define EXT2_VPROP3_AUTOMOUNT (1ULL << 0)
+#define EXT2_VPROP3_USERIDS (1ULL << 1)
+#ifdef __cplusplus
+typedef struct _EXT2_VOLUME_PROPERTY3:EXT2_VOLUME_PROPERTY2 {
+#else // __cplusplus
typedef struct _EXT2_VOLUME_PROPERTY3 {
- EXT2_VOLUME_PROPERTY2 Prop2;
- unsigned __int64 Flags;
- int AutoMount:1;
- int Reserved1:31;
- int Reserved2[31];
+ EXT2_VOLUME_PROPERTY2 ;
+#endif // __cplusplus
+ unsigned __int64 Flags2;
+ ULONG AutoMount:1;
+ ULONG EIDS:1;
+ ULONG Reserved1:30;
+ USHORT uid;
+ USHORT gid;
+ USHORT euid;
+ USHORT egid;
+ ULONG Reserved2[29];
} EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3;
/* Ext2Fsd driver version and built time */
/* STRUCTS & CONSTS******************************************************/
-#define EXT2FSD_VERSION "0.63"
+#define EXT2FSD_VERSION "0.66"
/* WDK DEFINITIONS ******************************************************/
#define CEILING_ALIGNED(T, A, B) (((A) + (B) - 1) & (~((T)(B) - 1)))
#define COCKLOFT_ALIGNED(T, A, B) (((A) + (B)) & (~((T)(B) - 1)))
+
+
+/*
+ * Compile-time assertion: (Lustre version)
+ *
+ * Check an invariant described by a constant expression at compile time by
+ * forcing a compiler error if it does not hold. \a cond must be a constant
+ * expression as defined by the ISO C Standard:
+ *
+ * 6.8.4.2 The switch statement
+ * ....
+ * [#3] The expression of each case label shall be an integer
+ * constant expression and no two of the case constant
+ * expressions in the same switch statement shall have the same
+ * value after conversion...
+ *
+ */
+
+#define CL_ASSERT(cond) do {switch('x') {case (cond): case 0: break;}} while (0)
+
/* File System Releated *************************************************/
#define DRIVER_NAME "Ext2Fsd"
#define HIDING_SUFFIX L"HidingSuffix"
#define AUTO_MOUNT L"AutoMount"
#define MOUNT_POINT L"MountPoint"
+#define UID L"uid"
+#define GID L"gid"
+#define EUID L"euid"
+#define EGID L"egid"
#define DOS_DEVICE_NAME L"\\DosDevices\\Ext2Fsd"
// Data that is not specific to a mounted volume
//
+typedef VOID (NTAPI *EXT2_REAPER_RELEASE)(PVOID);
+
+typedef struct _EXT2_REAPER {
+ KEVENT Engine;
+ KEVENT Wait;
+ EXT2_REAPER_RELEASE Free;
+ ULONG Flags;
+} EXT2_REAPER, *PEXT2_REAPER;
+
+#define EXT2_REAPER_FLAG_STOP (1 << 0)
+
typedef struct _EXT2_GLOBAL {
/* Identifier for this structure */
/* Table of pointers to the fast I/O entry points */
FAST_IO_DISPATCH FastIoDispatch;
+ /* Filter callbacks */
+ FS_FILTER_CALLBACKS FilterCallbacks;
+
/* Table of pointers to the Cache Manager callbacks */
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks;
LIST_ENTRY VcbList;
/* Cleaning thread related: resource cleaner */
- struct {
- KEVENT Engine;
- KEVENT Wait;
- } Reaper;
+ EXT2_REAPER McbReaper;
+ EXT2_REAPER bhReaper;
/* Look Aside table of IRP_CONTEXT, FCB, MCB, CCB */
NPAGED_LOOKASIDE_LIST Ext2IrpContextLookasideList;
/* User specified global codepage name */
struct {
+ WCHAR PageName[CODEPAGE_MAXLEN];
UCHAR AnsiName[CODEPAGE_MAXLEN];
struct nls_table * PageTable;
} Codepage;
/* global hiding patterns */
+ WCHAR wHidingPrefix[HIDINGPAT_LEN];
+ WCHAR wHidingSuffix[HIDINGPAT_LEN];
BOOLEAN bHidingPrefix;
CHAR sHidingPrefix[HIDINGPAT_LEN];
BOOLEAN bHidingSuffix;
/* Common header */
EXT2_FCBVCB;
- // Resource for metadata (super block, tables)
- ERESOURCE MetaLock;
+ // Resource for metadata (inode)
+ ERESOURCE MetaInode;
+
+ // Resource for metadata (block)
+ ERESOURCE MetaBlock;
// Resource for Mcb (Meta data control block)
ERESOURCE McbLock;
BOOLEAN IsExt3fs;
PEXT2_SUPER_BLOCK SuperBlock;
- /*
- // Bitmap Block per group
- PRTL_BITMAP BlockBitMaps;
- PRTL_BITMAP InodeBitMaps;
- */
-
// Block / Cluster size
ULONG BlockSize;
#define VCB_USER_IDS 0x00000040 /* uid/gid specified by user */
#define VCB_USER_EIDS 0x00000080 /* euid/egid specified by user */
+#define VCB_BEING_DROPPED 0x00002000
#define VCB_FORCE_WRITING 0x00004000
#define VCB_DEVICE_REMOVED 0x00008000
#define VCB_JOURNAL_RECOVER 0x00080000
PMDL
Ext2CreateMdl (
IN PVOID Buffer,
- IN BOOLEAN bPaged,
IN ULONG Length,
IN LOCK_OPERATION Operation
);
VOID NTAPI
Ext2NoOpRelease (IN PVOID Fcb);
-VOID NTAPI
-Ext2AcquireForCreateSection (
- IN PFILE_OBJECT FileObject
-);
-
-VOID NTAPI
-Ext2ReleaseForCreateSection (
- IN PFILE_OBJECT FileObject
-);
-
-NTSTATUS NTAPI
-Ext2AcquireFileForModWrite (
- IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER EndingOffset,
- OUT PERESOURCE *ResourceToRelease,
- IN PDEVICE_OBJECT DeviceObject
-);
-
-NTSTATUS NTAPI
-Ext2ReleaseFileForModWrite (
- IN PFILE_OBJECT FileObject,
- IN PERESOURCE ResourceToRelease,
- IN PDEVICE_OBJECT DeviceObject
-);
-
-NTSTATUS NTAPI
-Ext2AcquireFileForCcFlush (
- IN PFILE_OBJECT FileObject,
- IN PDEVICE_OBJECT DeviceObject
-);
-
-NTSTATUS NTAPI
-Ext2ReleaseFileForCcFlush (
- IN PFILE_OBJECT FileObject,
- IN PDEVICE_OBJECT DeviceObject
-);
-
-
//
// Create.c
//
NTSTATUS
Ext2ProcessGlobalProperty(
IN PDEVICE_OBJECT DeviceObject,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length
);
NTSTATUS
Ext2ProcessVolumeProperty(
IN PEXT2_VCB Vcb,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length
);
NTSTATUS
Ext2ProcessUserProperty(
IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length
);
OUT PULONG Inode
);
+NTSTATUS
+Ext2UpdateGroupDirStat(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Group
+);
+
NTSTATUS
Ext2FreeInode(
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
IN PEXT2_FCB Dcb,
- IN PEXT2_MCB Mcb
+ IN PEXT2_MCB Mcb,
+ IN umode_t mode
);
NTSTATUS
OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject);
+VOID
+NTAPI
+Ext2AcquireForCreateSection (
+ IN PFILE_OBJECT FileObject
+);
+
+VOID
+NTAPI
+Ext2ReleaseForCreateSection (
+ IN PFILE_OBJECT FileObject
+);
+
+NTSTATUS
+NTAPI
+Ext2AcquireFileForModWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER EndingOffset,
+ OUT PERESOURCE *ResourceToRelease,
+ IN PDEVICE_OBJECT DeviceObject
+);
+
+NTSTATUS
+NTAPI
+Ext2ReleaseFileForModWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PERESOURCE ResourceToRelease,
+ IN PDEVICE_OBJECT DeviceObject
+);
+
+NTSTATUS
+NTAPI
+Ext2AcquireFileForCcFlush (
+ IN PFILE_OBJECT FileObject,
+ IN PDEVICE_OBJECT DeviceObject
+);
+
+NTSTATUS
+NTAPI
+Ext2ReleaseFileForCcFlush (
+ IN PFILE_OBJECT FileObject,
+ IN PDEVICE_OBJECT DeviceObject
+);
+
+
+NTSTATUS
+NTAPI
+Ext2PreAcquireForCreateSection(
+ IN PFS_FILTER_CALLBACK_DATA cd,
+ OUT PVOID *cc
+ );
//
// FileInfo.c
// Init.c
//
+NTSTATUS
+Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath);
BOOLEAN
-Ext2QueryGlobalParameters (IN PUNICODE_STRING RegistryPath);
+Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath);
VOID NTAPI
DriverUnload (IN PDRIVER_OBJECT DriverObject);
// Memory.c
//
+VOID
+NTAPI
+Ext2McbReaperThread(
+ PVOID Context
+);
+
+VOID
+NTAPI
+Ext2bhReaperThread(
+ PVOID Context
+);
+
+
PEXT2_IRP_CONTEXT
Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp );
);
NTSTATUS
-Ext2StartReaperThread();
+Ext2StartReaper(PEXT2_REAPER, EXT2_REAPER_RELEASE);
+VOID
+NTAPI
+Ext2StopReaper(PEXT2_REAPER Reaper);
//
// Misc.c
OUT PULONG dwReturn
);
+
VOID
Ext2StartFloppyFlushDpc (
PEXT2_VCB Vcb,
//
typedef struct {
- volatile int counter;
+ volatile LONG counter;
} atomic_t;
#define ATOMIC_INIT(i) (i)
return (InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i) + i);
}
-#endif /* LINUX_ATOMIC_H */
\ No newline at end of file
+#endif /* LINUX_ATOMIC_H */
/*
* third extended-fs super-block data in memory
*/
+
+struct ext3_gd {
+ ext3_fsblk_t block;
+ struct ext4_group_desc *gd;
+ struct buffer_head *bh;
+};
+
struct ext3_sb_info {
+ ERESOURCE s_gd_lock;
+ struct ext3_gd *s_gd;
+
unsigned long s_desc_size; /* size of group desc */
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
int s_addr_per_block_bits;
int s_desc_per_block_bits;
- ext3_fsblk_t *s_group_desc;
#if 0
unsigned long s_frag_size; /* Size of a fragment in bytes */
PFILE_OBJECT bd_volume; /* streaming object file */
LARGE_MCB bd_extents; /* dirty extents */
- spinlock_t bd_bh_lock; /**/
- kmem_cache_t * bd_bh_cache; /* memory cache for buffer_head */
- struct rb_root bd_bh_root; /* buffer_head red-black tree root */
+ kmem_cache_t * bd_bh_cache;/* memory cache for buffer_head */
+ ERESOURCE bd_bh_lock; /* lock for bh tree and reaper list */
+ struct rb_root bd_bh_root; /* buffer_head red-black tree root */
+ LIST_ENTRY bd_bh_free; /* reaper list */
+ KEVENT bd_bh_notify; /* notification event for cleanup */
};
//
* for backward compatibility reasons (e.g. submit_bh).
*/
struct buffer_head {
+ LIST_ENTRY b_link; /* to be added to reaper list */
unsigned long b_state; /* buffer state bitmap (see above) */
struct page *b_page; /* the page this bh is mapped to */
PMDL b_mdl; /* MDL of the locked buffer */
// struct list_head b_assoc_buffers; /* associated with another mapping */
// struct address_space *b_assoc_map; /* mapping this buffer is associated with */
atomic_t b_count; /* users using this buffer_head */
- struct rb_node b_rb_node; /* Red-black tree node entry */
+ struct rb_node b_rb_node; /* Red-black tree node entry */
+
+ LARGE_INTEGER b_ts_creat; /* creation time*/
+ LARGE_INTEGER b_ts_drop; /* drop time (to be released) */
};
PMDL
Ext2CreateMdl (
IN PVOID Buffer,
- IN BOOLEAN bPaged,
IN ULONG Length,
- IN LOCK_OPERATION Operation
+ IN LOCK_OPERATION op
)
{
NTSTATUS Status;
Status = STATUS_INSUFFICIENT_RESOURCES;
} else {
_SEH2_TRY {
- if (bPaged) {
- MmProbeAndLockPages(Mdl, KernelMode, Operation);
+ if (MmIsNonPagedSystemAddressValid(Buffer)) {
+ MmBuildMdlForNonPagedPool(Mdl);
} else {
- MmBuildMdlForNonPagedPool (Mdl);
+ MmProbeAndLockPages(Mdl, KernelMode, op);
}
Status = STATUS_SUCCESS;
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
while (Mdl) {
PMDL Next;
Next = Mdl->Next;
+ Mdl->Next = NULL;
if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) {
MmUnlockPages (Mdl);
}
BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN FcbResourceAcquired = FALSE;
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
+ BOOLEAN SymLinkDelete = FALSE;
_SEH2_TRY {
}
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
- SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
+ if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
+ SymLinkDelete = TRUE;
+ } else {
+ SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
+ }
}
//
}
}
- if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
+ if (SymLinkDelete ||
+ (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
+ Fcb->OpenHandleCount == 0) ) {
- if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) {
-
- //
- // Ext2DeleteFile will acquire these lock inside
- //
+ //
+ // Ext2DeleteFile will acquire these lock inside
+ //
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- FcbResourceAcquired = FALSE;
- }
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ FcbResourceAcquired = FALSE;
+ }
- //
- // this file is to be deleted ...
- //
- if (Ccb->SymLink) {
- Mcb = Ccb->SymLink;
- FileObject->DeletePending = FALSE;
- }
+ //
+ // this file is to be deleted ...
+ //
+ if (Ccb->SymLink) {
+ Mcb = Ccb->SymLink;
+ FileObject->DeletePending = FALSE;
+ }
- Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
-
- if (NT_SUCCESS(Status)) {
- if (IsMcbDirectory(Mcb)) {
- Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- FILE_ACTION_REMOVED );
- } else {
- Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- FILE_ACTION_REMOVED );
- }
+ Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
+
+ if (NT_SUCCESS(Status)) {
+ if (IsMcbDirectory(Mcb)) {
+ Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ FILE_ACTION_REMOVED );
+ } else {
+ Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
+ FILE_NOTIFY_CHANGE_FILE_NAME,
+ FILE_ACTION_REMOVED );
}
+ }
- //
- // re-acquire the main resource lock
- //
-
- FcbResourceAcquired =
- ExAcquireResourceExclusiveLite(
- &Fcb->MainResource,
- TRUE
- );
+ //
+ // re-acquire the main resource lock
+ //
- SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
+ FcbResourceAcquired =
+ ExAcquireResourceExclusiveLite(
+ &Fcb->MainResource,
+ TRUE
+ );
+ if (!SymLinkDelete) {
+ SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
if (CcIsFileCached(FileObject)) {
CcSetFileSizes(FileObject,
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n",
Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb));
#endif
- if (!ExAcquireResourceSharedLite(
- &Fcb->PagingIoResource, Wait)) {
+ if (!ExAcquireResourceExclusiveLite(Fcb->Header.Resource, Wait)) {
return FALSE;
}
Fcb->LazyWriterThread = PsGetCurrentThread();
ASSERT(IoGetTopLevelIrp() == NULL);
-
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
return TRUE;
//
// On a readonly filesystem this function still has to exist but it
// doesn't need to do anything.
- PEXT2_FCB Fcb;
-
- Fcb = (PEXT2_FCB) Context;
+ PEXT2_FCB Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL);
ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread());
Fcb->LazyWriterThread = NULL;
- ExReleaseResourceLite(&Fcb->PagingIoResource);
+ ExReleaseResourceLite(Fcb->Header.Resource);
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
IoSetTopLevelIrp( NULL );
Ext2AcquireForReadAhead (IN PVOID Context,
IN BOOLEAN Wait)
{
- PEXT2_FCB Fcb;
-
- Fcb = (PEXT2_FCB) Context;
+ PEXT2_FCB Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL);
-
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n",
Fcb->Mcb->Inode.i_ino, Fcb));
- if (!ExAcquireResourceSharedLite(
- &Fcb->MainResource, Wait ))
+ if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait))
return FALSE;
-
ASSERT(IoGetTopLevelIrp() == NULL);
-
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
return TRUE;
VOID NTAPI
Ext2ReleaseFromReadAhead (IN PVOID Context)
{
- PEXT2_FCB Fcb;
-
- Fcb = (PEXT2_FCB) Context;
+ PEXT2_FCB Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL);
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n",
Fcb->Mcb->Inode.i_ino, Fcb));
- IoSetTopLevelIrp( NULL );
-
- ExReleaseResourceLite(&Fcb->MainResource);
+ IoSetTopLevelIrp(NULL);
+ ExReleaseResourceLite(Fcb->Header.Resource);
}
BOOLEAN NTAPI
return;
}
-
-VOID NTAPI
-Ext2AcquireForCreateSection (
- IN PFILE_OBJECT FileObject
-)
-
-{
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- if (Fcb->Header.Resource != NULL) {
- ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
- }
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForCreateSection: Fcb=%p\n", Fcb));
-}
-
-VOID NTAPI
-Ext2ReleaseForCreateSection (
- IN PFILE_OBJECT FileObject
-)
-
-{
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseForCreateSection: Fcb=%p\n", Fcb));
-
- if (Fcb->Header.Resource != NULL) {
- ExReleaseResourceLite(Fcb->Header.Resource);
- }
-}
-
-
-NTSTATUS NTAPI
-Ext2AcquireFileForModWrite (
- IN PFILE_OBJECT FileObject,
- IN PLARGE_INTEGER EndingOffset,
- OUT PERESOURCE *ResourceToRelease,
- IN PDEVICE_OBJECT DeviceObject
-)
-
-{
- BOOLEAN ResourceAcquired = FALSE;
-
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- if (Fcb->Header.PagingIoResource != NULL) {
- *ResourceToRelease = Fcb->Header.PagingIoResource;
- } else {
- *ResourceToRelease = Fcb->Header.Resource;
- }
-
- ResourceAcquired = ExAcquireResourceSharedLite(*ResourceToRelease, FALSE);
- if (!ResourceAcquired) {
- *ResourceToRelease = NULL;
- }
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireFileForModWrite: Fcb=%p Acquired=%d\n",
- Fcb, ResourceAcquired));
-
- return (ResourceAcquired ? STATUS_SUCCESS : STATUS_CANT_WAIT);
-}
-
-NTSTATUS NTAPI
-Ext2ReleaseFileForModWrite (
- IN PFILE_OBJECT FileObject,
- IN PERESOURCE ResourceToRelease,
- IN PDEVICE_OBJECT DeviceObject
-)
-{
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFileForModWrite: Fcb=%p\n", Fcb));
-
- if (ResourceToRelease != NULL) {
- ASSERT(ResourceToRelease == Fcb->Header.PagingIoResource ||
- ResourceToRelease == Fcb->Header.Resource);
- ExReleaseResourceLite(ResourceToRelease);
- } else {
- DbgBreak();
- }
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS NTAPI
-Ext2AcquireFileForCcFlush (
- IN PFILE_OBJECT FileObject,
- IN PDEVICE_OBJECT DeviceObject
-)
-{
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- if (Fcb->Header.PagingIoResource != NULL) {
- ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE);
- }
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireFileForCcFlush: Fcb=%p\n", Fcb));
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS NTAPI
-Ext2ReleaseFileForCcFlush (
- IN PFILE_OBJECT FileObject,
- IN PDEVICE_OBJECT DeviceObject
-)
-{
- PEXT2_FCB Fcb = FileObject->FsContext;
-
- DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFileForCcFlush: Fcb=%p\n", Fcb));
-
- if (Fcb->Header.PagingIoResource != NULL) {
- ExReleaseResourceLite(Fcb->Header.PagingIoResource);
- }
-
- return STATUS_SUCCESS;
-}
}
/* read the symlink target path */
- if (Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) {
+ if (!Mcb->Inode.i_blocks) {
OemName.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]);
OemName.Length = (USHORT)Mcb->Inode.i_size;
#ifndef __REACTOS__
LONG i = 0;
#endif
+
PathName = FileName;
Mcb = NULL;
//
// check the oplock state of the file
//
+
Status = FsRtlCheckOplock( &Fcb->Oplock,
IrpContext->Irp,
IrpContext,
Inode.i_ino = iNo;
Inode.i_ctime = Inode.i_mtime =
Inode.i_atime = Ext2LinuxTime(SysTime);
- Inode.i_uid = Vcb->uid;
- Inode.i_gid = Vcb->gid;
+ if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) {
+ Inode.i_uid = Vcb->uid;
+ Inode.i_gid = Vcb->gid;
+ } else {
+ Inode.i_uid = Parent->Mcb->Inode.i_uid;
+ Inode.i_gid = Parent->Mcb->Inode.i_gid;
+ }
Inode.i_generation = Parent->Inode->i_generation;
Inode.i_mode = S_IPERMISSION_MASK &
Parent->Inode->i_mode;
NTSTATUS
Ext2ProcessGlobalProperty(
IN PDEVICE_OBJECT DeviceObject,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property3,
IN ULONG Length
)
{
+ PEXT2_VOLUME_PROPERTY3 Property2 = (PVOID)Property3;
+ PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3;
+ struct nls_table * PageTable = NULL;
+
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN GlobalDataResourceAcquired = FALSE;
- struct nls_table * PageTable = NULL;
_SEH2_TRY {
ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
GlobalDataResourceAcquired = TRUE;
- if (Property->bReadonly) {
- ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
- ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
- } else {
- SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
- if (Property->bExt3Writable) {
- SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
- } else {
- ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
- }
- }
- PageTable = load_nls(Property->Codepage);
- if (PageTable) {
- memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
- Ext2Global->Codepage.PageTable = PageTable;
- }
+ switch (Property->Command) {
+
+ case APP_CMD_SET_PROPERTY3:
- if (Property->Command == APP_CMD_SET_PROPERTY2 ||
- Property->Command == APP_CMD_SET_PROPERTY3 ) {
+ if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) {
+ if (Property3->AutoMount)
+ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ else
+ ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ }
+
+ case APP_CMD_SET_PROPERTY2:
RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN);
- if ((Ext2Global->bHidingPrefix = Property->bHidingPrefix)) {
+ if ((Ext2Global->bHidingPrefix = Property2->bHidingPrefix)) {
RtlCopyMemory( Ext2Global->sHidingPrefix,
- Property->sHidingPrefix,
+ Property2->sHidingPrefix,
HIDINGPAT_LEN - 1);
}
RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN);
- if ((Ext2Global->bHidingSuffix = Property->bHidingSuffix)) {
+ if ((Ext2Global->bHidingSuffix = Property2->bHidingSuffix)) {
RtlCopyMemory( Ext2Global->sHidingSuffix,
- Property->sHidingSuffix,
+ Property2->sHidingSuffix,
HIDINGPAT_LEN - 1);
}
- }
- if (Property->Command == APP_CMD_SET_PROPERTY3) {
+ case APP_CMD_SET_PROPERTY:
- PEXT2_VOLUME_PROPERTY3 Prop3 = (PEXT2_VOLUME_PROPERTY3)Property;
+ if (Property->bReadonly) {
+ ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
+ ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
+ } else {
+ SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
+ if (Property->bExt3Writable) {
+ SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
+ } else {
+ ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
+ }
+ }
- if (Prop3->Flags & EXT2_VPROP3_AUTOMOUNT) {
- if (Prop3->AutoMount)
- SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
- else
- ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ PageTable = load_nls(Property->Codepage);
+ if (PageTable) {
+ memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
+ Ext2Global->Codepage.PageTable = PageTable;
}
+
+ break;
+
+ default:
+ break;
}
} _SEH2_FINALLY {
NTSTATUS
Ext2ProcessVolumeProperty(
IN PEXT2_VCB Vcb,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property3,
IN ULONG Length
)
{
- NTSTATUS Status = STATUS_SUCCESS;
- BOOLEAN VcbResourceAcquired = FALSE;
struct nls_table * PageTable = NULL;
+ PEXT2_VOLUME_PROPERTY2 Property2 = (PVOID)Property3;
+ PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3;
+ NTSTATUS Status = STATUS_SUCCESS;
+ BOOLEAN VcbResourceAcquired = FALSE;
_SEH2_TRY {
VcbResourceAcquired = TRUE;
if (Property->Command == APP_CMD_SET_PROPERTY ||
- Property->Command == APP_CMD_QUERY_PROPERTY) {
+ Property->Command == APP_CMD_QUERY_PROPERTY) {
if (Length < sizeof(EXT2_VOLUME_PROPERTY)) {
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE;
}
+ } else if (Property->Command == APP_CMD_SET_PROPERTY3 ||
+ Property->Command == APP_CMD_QUERY_PROPERTY3) {
+ if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) {
+ Status = STATUS_INVALID_PARAMETER;
+ _SEH2_LEAVE;
+ }
}
switch (Property->Command) {
- case APP_CMD_SET_PROPERTY:
+ case APP_CMD_SET_PROPERTY3:
+
+ if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) {
+ if (Property3->AutoMount)
+ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ else
+ ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ }
+ if (Property3->Flags2 & EXT2_VPROP3_USERIDS) {
+ SetFlag(Vcb->Flags, VCB_USER_IDS);
+ Vcb->uid = Property3->uid;
+ Vcb->gid = Property3->gid;
+ if (Property3->EIDS) {
+ Vcb->euid = Property3->euid;
+ Vcb->egid = Property3->egid;
+ SetFlag(Vcb->Flags, VCB_USER_EIDS);
+ } else {
+ Vcb->euid = Vcb->egid = 0;
+ ClearFlag(Vcb->Flags, VCB_USER_EIDS);
+ }
+ } else {
+ ClearFlag(Vcb->Flags, VCB_USER_IDS);
+ ClearFlag(Vcb->Flags, VCB_USER_EIDS);
+ Vcb->uid = Vcb->gid = 0;
+ Vcb->euid = Vcb->egid = 0;
+ }
+
case APP_CMD_SET_PROPERTY2:
- if (Property->bReadonly) {
+ RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN);
+ if (Vcb->bHidingPrefix == Property2->bHidingPrefix) {
+ RtlCopyMemory( Vcb->sHidingPrefix,
+ Property2->sHidingPrefix,
+ HIDINGPAT_LEN - 1);
+ }
+
+ RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
+ if (Vcb->bHidingSuffix == Property2->bHidingSuffix) {
+ RtlCopyMemory( Vcb->sHidingSuffix,
+ Property2->sHidingSuffix,
+ HIDINGPAT_LEN - 1);
+ }
+ Vcb->DrvLetter = Property2->DrvLetter;
- Ext2FlushFiles(NULL, Vcb, FALSE);
- Ext2FlushVolume(NULL, Vcb, FALSE);
+ case APP_CMD_SET_PROPERTY:
+
+ if (Property->bReadonly) {
+ if (IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) {
+ Ext2FlushFiles(NULL, Vcb, FALSE);
+ Ext2FlushVolume(NULL, Vcb, FALSE);
+ }
SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
} else {
Ext2InitializeLabel(Vcb, Vcb->SuperBlock);
}
- if (Property->Command == APP_CMD_SET_PROPERTY2) {
+ break;
+
+ case APP_CMD_QUERY_PROPERTY3:
- RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN);
- if ((Vcb->bHidingPrefix = Property->bHidingPrefix) != 0) {
- RtlCopyMemory( Vcb->sHidingPrefix,
- Property->sHidingPrefix,
- HIDINGPAT_LEN - 1);
- }
+ if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
+ SetFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT);
+ Property3->AutoMount = TRUE;
+ } else {
+ ClearFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT);
+ Property3->AutoMount = FALSE;
+ }
- RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
- if ((Vcb->bHidingSuffix = Property->bHidingSuffix) != 0) {
- RtlCopyMemory( Vcb->sHidingSuffix,
- Property->sHidingSuffix,
- HIDINGPAT_LEN - 1);
+ if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) {
+ SetFlag(Property3->Flags2, EXT2_VPROP3_USERIDS);
+ Property3->uid = Vcb->uid;
+ Property3->gid = Vcb->gid;
+ if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) {
+ Property3->EIDS = TRUE;
+ Property3->euid = Vcb->euid;
+ Property3->egid = Vcb->egid;
+ } else {
+ Property3->EIDS = FALSE;
}
+ } else {
+ ClearFlag(Property3->Flags2, EXT2_VPROP3_USERIDS);
+ }
+
+ case APP_CMD_QUERY_PROPERTY2:
+
+ RtlCopyMemory(Property2->UUID, Vcb->SuperBlock->s_uuid, 16);
+ Property2->DrvLetter = Vcb->DrvLetter;
- Vcb->DrvLetter = Property->DrvLetter;
+ if (Property2->bHidingPrefix == Vcb->bHidingPrefix) {
+ RtlCopyMemory( Property2->sHidingPrefix,
+ Vcb->sHidingPrefix,
+ HIDINGPAT_LEN);
+ } else {
+ RtlZeroMemory( Property2->sHidingPrefix,
+ HIDINGPAT_LEN);
}
- break;
+ if (Property2->bHidingSuffix == Vcb->bHidingSuffix) {
+ RtlCopyMemory( Property2->sHidingSuffix,
+ Vcb->sHidingSuffix,
+ HIDINGPAT_LEN);
+ } else {
+ RtlZeroMemory( Property2->sHidingSuffix,
+ HIDINGPAT_LEN);
+ }
case APP_CMD_QUERY_PROPERTY:
- case APP_CMD_QUERY_PROPERTY2:
Property->bExt2 = TRUE;
Property->bExt3 = Vcb->IsExt3fs;
} else {
strncpy(Property->Codepage, "default", CODEPAGE_MAXLEN);
}
-
- if (Property->Command == APP_CMD_QUERY_PROPERTY2) {
-
- RtlCopyMemory(Property->UUID, Vcb->SuperBlock->s_uuid, 16);
-
- Property->DrvLetter = Vcb->DrvLetter;
-
- if ((Property->bHidingPrefix = Vcb->bHidingPrefix) != 0) {
- RtlCopyMemory( Property->sHidingPrefix,
- Vcb->sHidingPrefix,
- HIDINGPAT_LEN);
- } else {
- RtlZeroMemory( Property->sHidingPrefix,
- HIDINGPAT_LEN);
- }
-
- if ((Property->bHidingSuffix = Vcb->bHidingSuffix) != 0) {
- RtlCopyMemory( Property->sHidingSuffix,
- Vcb->sHidingSuffix,
- HIDINGPAT_LEN);
- } else {
- RtlZeroMemory( Property->sHidingSuffix,
- HIDINGPAT_LEN);
- }
- }
-
break;
default:
NTSTATUS
Ext2ProcessUserProperty(
IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VOLUME_PROPERTY2 Property,
+ IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length
)
{
return TRUE;
}
+VOID
+Ext2PutGroup(IN PEXT2_VCB Vcb)
+{
+ struct ext3_sb_info *sbi = &Vcb->sbi;
+ unsigned long i;
+
+
+ if (NULL == Vcb->sbi.s_gd) {
+ return;
+ }
+
+ for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
+ if (Vcb->sbi.s_gd[i].bh)
+ fini_bh(&sbi->s_gd[i].bh);
+ }
+
+ kfree(Vcb->sbi.s_gd);
+ Vcb->sbi.s_gd = NULL;
+}
+
+
BOOLEAN
Ext2LoadGroup(IN PEXT2_VCB Vcb)
{
struct ext3_sb_info *sbi = &Vcb->sbi;
ext3_fsblk_t sb_block = 1;
unsigned long i;
+ BOOLEAN rc = FALSE;
- if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
- sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
- }
+ _SEH2_TRY {
- if (NULL == sbi->s_group_desc) {
- sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(ext3_fsblk_t),
- GFP_KERNEL);
- }
- if (sbi->s_group_desc == NULL) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
- return FALSE;
- }
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
- for (i = 0; i < sbi->s_gdb_count; i++) {
- sbi->s_group_desc[i] = descriptor_loc(sb, sb_block, i);
- if (!sbi->s_group_desc[i]) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i));
- return FALSE;
+ if (NULL == sbi->s_gd) {
+ sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
+ GFP_KERNEL);
+ }
+ if (sbi->s_gd == NULL) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
+ _SEH2_LEAVE;
}
- }
- if (!ext4_check_descriptors(sb)) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n"));
- return FALSE;
- }
+ if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
+ sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
+ }
- return TRUE;
+ for (i = 0; i < sbi->s_gdb_count; i++) {
+ sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i);
+ if (!sbi->s_gd[i].block) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
+ _SEH2_LEAVE;
+ }
+ sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
+ if (!sbi->s_gd[i].bh) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i));
+ _SEH2_LEAVE;
+ }
+ sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
+ }
+
+ if (!ext4_check_descriptors(sb)) {
+ DbgBreak();
+ DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n"));
+ _SEH2_LEAVE;
+ }
+
+ rc = TRUE;
+
+ } _SEH2_FINALLY {
+
+ if (!rc)
+ Ext2PutGroup(Vcb);
+
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ } _SEH2_END;
+
+ return rc;
}
Ext2DropGroup(IN PEXT2_VCB Vcb)
{
struct ext3_sb_info *sbi = &Vcb->sbi;
+ LARGE_INTEGER timeout;
unsigned long i;
- if (NULL == sbi->s_group_desc) {
+ /* do nothing if Vcb is not initialized yet */
+ if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
return;
- }
- kfree(sbi->s_group_desc);
- sbi->s_group_desc = NULL;
+ _SEH2_TRY {
+ SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+ Ext2PutGroup(Vcb);
+ } _SEH2_FINALLY {
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ } _SEH2_END;
+
+ timeout.QuadPart = (LONGLONG)-10*1000*1000;
+ KeWaitForSingleObject(&Vcb->bd.bd_bh_notify,
+ Executive, KernelMode,
+ FALSE, &timeout);
+ ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
}
BOOLEAN
*Block = 0;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
/* validate the hint group and hint block */
if (GroupHint >= Vcb->sbi.s_groups_count) {
errorout:
- ExReleaseResourceLite(&Vcb->MetaLock);
+ ExReleaseResourceLite(&Vcb->MetaBlock);
if (bh)
fini_bh(&bh);
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
Block, Block + Number));
if (gb)
fini_bh(&gb);
- ExReleaseResourceLite(&Vcb->MetaLock);
+ ExReleaseResourceLite(&Vcb->MetaBlock);
return Status;
}
*Inode = dwInode = 0XFFFFFFFF;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
if (GroupHint >= Vcb->sbi.s_groups_count)
GroupHint = GroupHint % Vcb->sbi.s_groups_count;
break;
}
- fini_bh(&gb);
+ fini_bh(&gb);
}
}
errorout:
- ExReleaseResourceLite(&Vcb->MetaLock);
+ ExReleaseResourceLite(&Vcb->MetaInode);
if (bh)
fini_bh(&bh);
return Status;
}
+NTSTATUS
+Ext2UpdateGroupDirStat(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG group
+ )
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ NTSTATUS status;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
+
+ /* get group desc */
+ gd = ext4_get_group_desc(sb, group, &gb);
+ if (!gd) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ /* update group_desc and super_block */
+ ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1);
+ Ext2SaveGroup(IrpContext, Vcb, group);
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+ status = STATUS_SUCCESS;
+
+errorout:
+
+ ExReleaseResourceLite(&Vcb->MetaInode);
+
+ if (gb)
+ fini_bh(&gb);
+
+ return status;
+}
+
+
NTSTATUS
Ext2FreeInode(
IN PEXT2_IRP_CONTEXT IrpContext,
NTSTATUS Status = STATUS_UNSUCCESSFUL;
- ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
Group = (Inode - 1) / INODES_PER_GROUP;
dwIno = (Inode - 1) % INODES_PER_GROUP;
errorout:
- ExReleaseResourceLite(&Vcb->MetaLock);
+ ExReleaseResourceLite(&Vcb->MetaInode);
if (bh)
fini_bh(&bh);
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
IN PEXT2_FCB Dcb,
- IN PEXT2_MCB Mcb
+ IN PEXT2_MCB Mcb,
+ IN umode_t mode
)
{
struct inode *dir = Dcb->Inode;
if (le32_to_cpu(de->inode) != inode->i_ino)
_SEH2_LEAVE;
- ext3_set_de_type(inode->i_sb, de, inode->i_mode);
+ ext3_set_de_type(inode->i_sb, de, mode);
mark_buffer_dirty(bh);
-
- //if (!inode->i_nlink)
- // ext3_orphan_add(handle, inode);
+ if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) {
+ } else if (S_ISDIR(inode->i_mode)) {
+ ext3_dec_count(dir);
+ } else if (S_ISDIR(mode)) {
+ ext3_inc_count(dir);
+ }
dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
ext3_mark_inode_dirty(IrpContext, dir);
+ inode->i_mode = mode;
+ ext3_mark_inode_dirty(IrpContext, inode);
+
Status = STATUS_SUCCESS;
} _SEH2_FINALLY {
__le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
struct ext4_group_desc *gdp)
{
- __u16 crc = 0;
+ int offset;
+ __u16 crc = 0;
+ __le32 le_group = cpu_to_le32(block_group);
- if (sbi->s_es->s_feature_ro_compat &
- cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
- int offset = offsetof(struct ext4_group_desc, bg_checksum);
- __le32 le_group = cpu_to_le32(block_group);
+ /* old crc16 code */
+ if (!(sbi->s_es->s_feature_ro_compat &
+ cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
+ return 0;
- crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
- crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
- crc = crc16(crc, (__u8 *)gdp, offset);
- offset += sizeof(gdp->bg_checksum); /* skip checksum */
- /* for checksum of struct ext4_group_desc do the rest...*/
- if ((sbi->s_es->s_feature_incompat &
- cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
- offset < le16_to_cpu(sbi->s_es->s_desc_size))
- crc = crc16(crc, (__u8 *)gdp + offset,
- le16_to_cpu(sbi->s_es->s_desc_size) -
- offset);
- }
+ offset = offsetof(struct ext4_group_desc, bg_checksum);
+
+ crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
+ crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
+ crc = crc16(crc, (__u8 *)gdp, offset);
+ offset += sizeof(gdp->bg_checksum); /* skip checksum */
+ /* for checksum of struct ext4_group_desc do the rest...*/
+ if ((sbi->s_es->s_feature_incompat &
+ cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
+ offset < le16_to_cpu(sbi->s_es->s_desc_size))
+ crc = crc16(crc, (__u8 *)gdp + offset,
+ le16_to_cpu(sbi->s_es->s_desc_size) -
+ offset);
- return cpu_to_le16(crc);
+ return cpu_to_le16(crc);
}
int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
ext4_group_t block_group, struct buffer_head **bh)
{
struct ext4_group_desc *desc = NULL;
- struct buffer_head *gb = NULL;
struct ext3_sb_info *sbi = EXT3_SB(sb);
PEXT2_VCB vcb = sb->s_priv;
-
- unsigned int group;
- unsigned int offset;
+ ext4_group_t group;
+ ext4_group_t offset;
if (bh)
*bh = NULL;
return NULL;
}
- smp_rmb();
-
- group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
- offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
- if (!sbi->s_group_desc || !sbi->s_group_desc[group]) {
- Ext2LoadGroup(vcb);
- }
+ _SEH2_TRY {
- if (!sbi->s_group_desc[group]) {
- ext4_error(sb, "ext4_get_group_desc",
- "Group descriptor not loaded - "
- "block_group = %u, group = %u, desc = %u",
- block_group, group, offset);
- goto errorout;
- }
+ group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+ offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
- gb = sb_getblk(sb, sbi->s_group_desc[group]);
- if (!gb) {
- ext4_error(sb, "ext4_get_group_desc",
- "failed to load group - "
- "block_group = %u, group = %u, desc = %u",
- block_group, group, offset);
- goto errorout;
- }
-
- desc = (struct ext4_group_desc *)(gb->b_data +
- offset * EXT4_DESC_SIZE(sb));
- if (bh)
- *bh = gb;
- else
- fini_bh(&gb);
+ if (!sbi->s_gd || !sbi->s_gd[group].block ||
+ !sbi->s_gd[group].bh) {
+ if (!Ext2LoadGroup(vcb)) {
+ _SEH2_LEAVE;
+ }
+ }
-errorout:
+ desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
+ offset * EXT4_DESC_SIZE(sb));
+ if (bh) {
+ atomic_inc(&sbi->s_gd[group].bh->b_count);
+ *bh = sbi->s_gd[group].bh;
+ }
+ } _SEH2_FINALLY {
+ /* do cleanup */
+ } _SEH2_END;
return desc;
}
+
/**
* ext4_count_free_blocks() -- count filesystem free blocks
* @sb: superblock
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
"Checksum for group %u failed (%u!=%u)\n",
i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
- gdp)), le16_to_cpu(gdp->bg_checksum));
+ gdp)),
+ le16_to_cpu(gdp->bg_checksum));
if (!IsVcbReadOnly(Vcb)) {
__brelse(bh);
return 0;
#pragma warning(disable: 4244)
#endif
+
/*
* used by extent splitting.
*/
return err;
}
+static int ext4_ext_shrink_indepth(void *icb,
+ handle_t *handle,
+ struct inode *inode,
+ unsigned int flags,
+ int *shrinked)
+{
+ struct ext4_extent_header *eh, *neh;
+ struct ext4_extent_idx *ix;
+ struct buffer_head *bh = NULL;
+ ext4_fsblk_t block;
+ int err = 0, depth = ext_depth(inode);
+ int neh_entries;
+ *shrinked = 0;
+
+ if (!depth)
+ return 0;
+
+ eh = ext_inode_hdr(inode);
+ if (le16_to_cpu(eh->eh_entries) != 1)
+ return 0;
+
+ ix = EXT_FIRST_INDEX(eh);
+ block = ext4_idx_pblock(ix);
+ bh = extents_bread(inode->i_sb, block);
+ if (!bh)
+ goto out;
+
+ /* set size of new block */
+ neh = ext_block_hdr(bh);
+ neh_entries = le16_to_cpu(neh->eh_entries);
+ if (!neh->eh_depth &&
+ neh_entries > ext4_ext_space_root(inode, 0))
+ goto out;
+
+ if (neh->eh_depth &&
+ neh_entries > ext4_ext_space_root_idx(inode, 0))
+ goto out;
+
+ /* old root could have indexes or leaves
+ * so calculate e_max right way */
+ if (neh->eh_depth)
+ eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
+ else
+ eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
+
+ eh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC);
+ eh->eh_entries = neh_entries;
+ if (neh->eh_depth) {
+ memmove(EXT_FIRST_INDEX(eh),
+ EXT_FIRST_INDEX(neh),
+ sizeof(struct ext4_extent_idx) * neh_entries);
+ } else {
+ memmove(EXT_FIRST_EXTENT(eh),
+ EXT_FIRST_EXTENT(neh),
+ sizeof(struct ext4_extent) * neh_entries);
+ }
+ le16_add_cpu(&eh->eh_depth, -1);
+
+ ext4_mark_inode_dirty(icb, handle, inode);
+ *shrinked = 1;
+out:
+ if (bh)
+ extents_brelse(bh);
+
+ if (*shrinked)
+ ext4_free_blocks(icb, handle, inode, NULL,
+ block, 1, flags);
+
+ return err;
+}
+
/*
* ext4_ext_create_new_leaf:
* finds empty index and adds new leaf.
* with leaves.
*/
ext4_lblk_t
-ext4_ext_next_allocated_block(struct ext4_ext_path *path)
+ext4_ext_next_allocated_block(struct ext4_ext_path *path, int at)
{
- int depth;
-
- depth = path->p_depth;
-
- if (depth == 0 && path->p_ext == NULL)
+ if (at == 0 && !path->p_ext && !path->p_idx)
return EXT_MAX_BLOCKS;
- while (depth >= 0) {
- if (depth == path->p_depth) {
+ while (at >= 0) {
+ if (at == path->p_depth) {
/* leaf */
- if (path[depth].p_ext &&
- path[depth].p_ext !=
- EXT_LAST_EXTENT(path[depth].p_hdr))
- return le32_to_cpu(path[depth].p_ext[1].ee_block);
+ if (path[at].p_ext &&
+ path[at].p_ext !=
+ EXT_LAST_EXTENT(path[at].p_hdr))
+ return le32_to_cpu(path[at].p_ext[1].ee_block);
} else {
/* index */
- if (path[depth].p_idx !=
- EXT_LAST_INDEX(path[depth].p_hdr))
- return le32_to_cpu(path[depth].p_idx[1].ei_block);
+ if (path[at].p_idx !=
+ EXT_LAST_INDEX(path[at].p_hdr))
+ return le32_to_cpu(path[at].p_idx[1].ei_block);
}
- depth--;
+ at--;
}
return EXT_MAX_BLOCKS;
/*
* ext4_ext_correct_indexes:
- * if leaf gets modified and modified extent is first in the leaf,
+ * if leaf/node gets modified and modified extent/index
+ * is first in the leaf/node,
* then we have to correct all indexes above.
- * TODO: do we need to correct tree in all cases?
*/
-static int ext4_ext_correct_indexes(void *icb, handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path)
+static int ext4_ext_correct_indexes(void *icb, handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path *path,
+ int at)
{
struct ext4_extent_header *eh;
int depth = ext_depth(inode);
__le32 border;
int k, err = 0;
- eh = path[depth].p_hdr;
- ex = path[depth].p_ext;
+ assert(at >= 0);
+ if (!at)
+ return 0;
- if (unlikely(ex == NULL || eh == NULL)) {
- EXT4_ERROR_INODE(inode,
- "ex %p == NULL or eh %p == NULL", ex, eh);
- return -EIO;
- }
+ if (depth == at) {
+ eh = path[at].p_hdr;
+ ex = path[at].p_ext;
- if (depth == 0) {
- /* there is no tree at all */
- return 0;
- }
+ if (ex == NULL || eh == NULL)
+ return -EIO;
- if (ex != EXT_FIRST_EXTENT(eh)) {
- /* we correct tree if first leaf got modified only */
- return 0;
- }
+ if (at == 0) {
+ /* there is no tree at all */
+ return 0;
+ }
- /*
- * TODO: we need correction if border is smaller than current one
- */
- k = depth - 1;
- border = path[depth].p_ext->ee_block;
- err = ext4_ext_get_access(icb, handle, inode, path + k);
- if (err)
- return err;
- path[k].p_idx->ei_block = border;
- err = ext4_ext_dirty(icb, handle, inode, path + k);
- if (err)
- return err;
+ if (ex != EXT_FIRST_EXTENT(eh)) {
+ /* we correct tree if first leaf got modified only */
+ return 0;
+ }
- while (k--) {
- /* change all left-side indexes */
- if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
- break;
- err = ext4_ext_get_access(icb, handle, inode, path + k);
- if (err)
- break;
+ k = at - 1;
+ border = path[at].p_ext->ee_block;
path[k].p_idx->ei_block = border;
err = ext4_ext_dirty(icb, handle, inode, path + k);
if (err)
+ return err;
+
+ } else {
+ border = path[at].p_idx->ei_block;
+ k = at;
+ }
+
+ while (k) {
+ /* change all left-side indexes */
+ if (path[k].p_idx != EXT_FIRST_INDEX(path[k].p_hdr))
break;
+ path[k-1].p_idx->ei_block = border;
+ err = ext4_ext_dirty(icb, handle, inode, path + k-1);
+ if (err)
+ break;
+
+ k--;
}
return err;
if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
ext4_ext_try_to_merge(icb, handle, inode, path, nearex);
+ depth = ext_depth(inode);
/* time to correct all indexes above */
- err = ext4_ext_correct_indexes(icb, handle, inode, path);
+ err = ext4_ext_correct_indexes(icb, handle,
+ inode, path, depth);
if (err)
goto cleanup;
return ret;
}
-static int ext4_remove_blocks(void *icb, handle_t *handle, struct inode *inode,
- struct ext4_extent *ex,
- unsigned long from, unsigned long to)
+static void ext4_ext_remove_blocks(
+ void *icb,
+ handle_t *handle,
+ struct inode *inode, struct ext4_extent *ex,
+ ext4_lblk_t from, ext4_lblk_t to)
{
- struct buffer_head *bh;
- int i;
+ int len = to - from + 1;
+ ext4_lblk_t num;
+ ext4_fsblk_t start;
+ num = from - le32_to_cpu(ex->ee_block);
+ start = ext4_ext_pblock(ex) + num;
+ ext_debug("Freeing %lu at %I64u, %d\n", from, start, len);
+ ext4_free_blocks(icb, handle, inode, NULL,
+ start, len, 0);
+}
- if (from >= le32_to_cpu(ex->ee_block)
- && to == le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) {
- /* tail removal */
- unsigned long num, start;
- num = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - from;
- start = ext4_ext_pblock(ex) + ext4_ext_get_actual_len(ex) - num;
- ext4_free_blocks(icb, handle, inode, NULL, start, num, 0);
- } else if (from == le32_to_cpu(ex->ee_block)
- && to <= le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) {
+static int ext4_ext_remove_idx(void *icb,
+ handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path *path,
+ int depth)
+{
+ int err, i = depth;
+ ext4_fsblk_t leaf;
+
+ /* free index block */
+ leaf = ext4_idx_pblock(path[i].p_idx);
+
+ if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) {
+ int len = EXT_LAST_INDEX(path[i].p_hdr) - path[i].p_idx;
+ memmove(path[i].p_idx, path[i].p_idx + 1,
+ len * sizeof(struct ext4_extent_idx));
+ }
+
+ le16_add_cpu(&path[i].p_hdr->eh_entries, -1);
+ err = ext4_ext_dirty(icb, handle, inode, path + i);
+ if (err)
+ return err;
+
+ ext_debug("IDX: Freeing %lu at %I64u, %d\n",
+ le32_to_cpu(path[i].p_idx->ei_block), leaf, 1);
+ ext4_free_blocks(icb, handle, inode, NULL,
+ leaf, 1, 0);
+ return err;
+}
+
+static int ext4_ext_amalgamate(void *icb,
+ handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path *path,
+ int at)
+{
+ int new_entries, right_entries;
+ int depth = ext_depth(inode);
+ struct ext4_ext_path *right_path = NULL;
+ ext4_lblk_t now;
+ int ret = 0;
+ if (!at)
+ return 0;
+
+ now = ext4_ext_next_allocated_block(path, at - 1);
+ if (now == EXT_MAX_BLOCKS)
+ goto out;
+
+ right_path = ext4_find_extent(inode, now, NULL, 0);
+ if (IS_ERR(right_path)) {
+ ret = PTR_ERR(right_path);
+ right_path = NULL;
+ goto out;
+ }
+
+ right_entries = le16_to_cpu(right_path[at].p_hdr->eh_entries);
+ new_entries = le16_to_cpu(path[at].p_hdr->eh_entries) +
+ right_entries;
+ if (new_entries > path[at].p_hdr->eh_max) {
+ ret = 0;
+ goto out;
+ }
+ if (at == depth) {
+ struct ext4_extent *last_ex = EXT_LAST_EXTENT(path[at].p_hdr);
+ memmove(last_ex + 1,
+ EXT_FIRST_EXTENT(right_path[at].p_hdr),
+ right_entries * sizeof(struct ext4_extent));
} else {
+ struct ext4_extent_idx *last_ix = EXT_LAST_INDEX(path[at].p_hdr);
+ memmove(last_ix + 1,
+ EXT_FIRST_INDEX(right_path[at].p_hdr),
+ right_entries * sizeof(struct ext4_extent_idx));
}
- return 0;
+ path[at].p_hdr->eh_entries = cpu_to_le16(new_entries);
+ right_path[at].p_hdr->eh_entries = 0;
+ ext4_ext_dirty(icb, handle, inode, path + at);
+
+ /*
+ * remove the empty node from index block above.
+ */
+ depth = at;
+ while (depth > 0) {
+ struct ext4_extent_header *eh = right_path[depth].p_hdr;
+ if (eh->eh_entries == 0 && right_path[depth].p_bh != NULL) {
+ ext4_ext_drop_refs(right_path + depth);
+ ret = ext4_ext_remove_idx(icb, handle, inode, right_path, depth - 1);
+ if (ret)
+ goto out;
+
+ } else
+ break;
+
+ depth--;
+ }
+ ret = ext4_ext_correct_indexes(icb, handle,
+ inode, right_path, depth);
+out:
+ if (right_path) {
+ ext4_ext_drop_refs(right_path);
+ kfree(right_path);
+ }
+
+ return ret;
+}
+
+static int ext4_ext_balance(void *icb,
+ handle_t *handle,
+ struct inode *inode,
+ struct ext4_ext_path **path,
+ int at)
+{
+ int ret, shrinked = 0;
+ int depth = at;
+
+ while (depth > 0) {
+ ret = ext4_ext_amalgamate(icb, handle,
+ inode, *path, depth);
+ if (ret)
+ goto out;
+
+ depth--;
+ }
+ do {
+ ret = ext4_ext_shrink_indepth(icb, handle,
+ inode, 0, &shrinked);
+ } while (!ret && shrinked);
+
+out:
+ return ret;
}
/*
- * routine removes index from the index block
- * it's used in truncate case only. thus all requests are for
- * last index in the block only
+ * NOTE: After removal, path should not be reused.
*/
-int ext4_ext_rm_idx(void *icb, handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path)
+int ext4_ext_remove_extent(void *icb,
+ handle_t *handle,
+ struct inode *inode, struct ext4_ext_path **path)
{
- int err;
- ext4_fsblk_t leaf;
+ int len;
+ int err = 0;
+ ext4_lblk_t start;
+ uint16_t new_entries;
+ int depth = ext_depth(inode);
+ struct ext4_extent *ex = (*path)[depth].p_ext,
+ *ex2 = ex + 1;
+ struct ext4_extent_header *eh = (*path)[depth].p_hdr;
+ if (!ex)
+ return -EINVAL;
+
+ start = le32_to_cpu(ex->ee_block);
+ len = ext4_ext_get_actual_len(ex);
+ new_entries = le16_to_cpu(eh->eh_entries) - 1;
+
+ ext4_ext_remove_blocks(icb, handle,
+ inode, ex, start, start + len - 1);
+ if (ex2 <= EXT_LAST_EXTENT(eh))
+ memmove(ex, ex2,
+ (EXT_LAST_EXTENT(eh) - ex2 + 1) * sizeof(struct ext4_extent));
+ eh->eh_entries = cpu_to_le16(new_entries);
+
+ ext4_ext_dirty(icb, handle, inode, (*path) + depth);
+
+ /*
+ * If the node is free, then we should
+ * remove it from index block above.
+ */
+ while (depth > 0) {
+ eh = (*path)[depth].p_hdr;
+ if (eh->eh_entries == 0 && (*path)[depth].p_bh != NULL) {
+ ext4_ext_drop_refs((*path) + depth);
+ err = ext4_ext_remove_idx(icb, handle,
+ inode, *path, depth - 1);
+ if (err)
+ break;
+
+ } else
+ break;
+
+ depth--;
+ }
+ err = ext4_ext_correct_indexes(icb, handle,
+ inode, *path, depth);
+
+ if ((*path)->p_hdr->eh_entries == 0) {
+ /*
+ * truncate to zero freed all the tree,
+ * so we need to correct eh_depth
+ */
+ ext_inode_hdr(inode)->eh_depth = 0;
+ ext_inode_hdr(inode)->eh_max =
+ cpu_to_le16(ext4_ext_space_root(inode, 0));
+ err = ext4_ext_dirty(icb, handle, inode, *path);
+ }
+ err = ext4_ext_balance(icb, handle, inode, path, depth);
- /* free index block */
- path--;
- leaf = ext4_idx_pblock(path->p_idx);
- BUG_ON(path->p_hdr->eh_entries == 0);
- if ((err = ext4_ext_get_access(icb, handle, inode, path)))
- return err;
- path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
- if ((err = ext4_ext_dirty(icb, handle, inode, path)))
- return err;
- ext4_free_blocks(icb, handle, inode, NULL, leaf, 1, 0);
return err;
}
-static int
-ext4_ext_rm_leaf(void *icb, handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path, unsigned long start)
+int __ext4_ext_truncate(void *icb,
+ handle_t *handle,
+ struct inode *inode,
+ ext4_lblk_t from, ext4_lblk_t to)
{
- int err = 0, correct_index = 0;
- int depth = ext_depth(inode), credits;
- struct ext4_extent_header *eh;
- unsigned a, b, block, num;
- unsigned long ex_ee_block;
- unsigned short ex_ee_len;
+ int depth = ext_depth(inode), ret = -EIO;
struct ext4_extent *ex;
+ struct ext4_ext_path *path = NULL, *npath;
+ ext4_lblk_t now = from;
- /* the header must be checked already in ext4_ext_remove_space() */
- if (!path[depth].p_hdr)
- path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
- eh = path[depth].p_hdr;
- BUG_ON(eh == NULL);
-
- /* find where to start removing */
- ex = EXT_LAST_EXTENT(eh);
-
- ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = ext4_ext_get_actual_len(ex);
-
- while (ex >= EXT_FIRST_EXTENT(eh) &&
- ex_ee_block + ex_ee_len > start) {
- path[depth].p_ext = ex;
-
- a = ex_ee_block > start ? ex_ee_block : start;
- b = (unsigned long long)ex_ee_block + ex_ee_len - 1 <
- EXT_MAX_BLOCKS ? ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCKS;
-
-
- if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) {
- block = 0;
- num = 0;
- BUG();
- } else if (a != ex_ee_block) {
- /* remove tail of the extent */
- block = ex_ee_block;
- num = a - block;
- } else if (b != ex_ee_block + ex_ee_len - 1) {
- /* remove head of the extent */
- block = a;
- num = b - a;
- /* there is no "make a hole" API yet */
- BUG();
- } else {
- /* remove whole extent: excellent! */
- block = ex_ee_block;
- num = 0;
- BUG_ON(a != ex_ee_block);
- BUG_ON(b != ex_ee_block + ex_ee_len - 1);
- }
+ if (to < from)
+ return -EINVAL;
- /* at present, extent can't cross block group */
- /* leaf + bitmap + group desc + sb + inode */
- credits = 5;
- if (ex == EXT_FIRST_EXTENT(eh)) {
- correct_index = 1;
- credits += (ext_depth(inode)) + 1;
- }
+ npath = ext4_find_extent(inode, from, &path, 0);
+ if (IS_ERR(npath))
+ goto out;
- /*handle = ext4_ext_journal_restart(icb, handle, credits);*/
- /*if (IS_ERR(icb, handle)) {*/
- /*err = PTR_ERR(icb, handle);*/
- /*goto out;*/
- /*}*/
+ path = npath;
+ ex = path[depth].p_ext;
+ if (!ex)
+ goto out;
- err = ext4_ext_get_access(icb, handle, inode, path + depth);
- if (err)
- goto out;
+ if (from < le32_to_cpu(ex->ee_block) &&
+ to < le32_to_cpu(ex->ee_block)) {
+ ret = 0;
+ goto out;
+ }
+ /* If we do remove_space inside the range of an extent */
+ if ((le32_to_cpu(ex->ee_block) < from) &&
+ (to < le32_to_cpu(ex->ee_block) +
+ ext4_ext_get_actual_len(ex) - 1)) {
- err = ext4_remove_blocks(icb, handle, inode, ex, a, b);
- if (err)
- goto out;
+ struct ext4_extent newex;
+ int unwritten = ext4_ext_is_unwritten(ex);
+ ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
+ int len = ext4_ext_get_actual_len(ex);
+ ext4_fsblk_t newblock =
+ to + 1 - ee_block + ext4_ext_pblock(ex);
- if (num == 0) {
- /* this extent is removed entirely mark slot unused */
- ext4_ext_store_pblock(ex, 0);
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
- }
+ ex->ee_len = cpu_to_le16(from - ee_block);
+ if (unwritten)
+ ext4_ext_mark_unwritten(ex);
- ex->ee_block = cpu_to_le32(block);
- ex->ee_len = cpu_to_le16(num);
+ ext4_ext_dirty(icb, handle, inode, path + depth);
- err = ext4_ext_dirty(icb, handle, inode, path + depth);
- if (err)
+ ext4_ext_remove_blocks(icb, handle,
+ inode,
+ ex, from, to);
+
+ newex.ee_block = cpu_to_le32(to + 1);
+ newex.ee_len = cpu_to_le16(ee_block + len - 1 - to);
+ ext4_ext_store_pblock(&newex, newblock);
+ if (unwritten)
+ ext4_ext_mark_unwritten(&newex);
+
+ ret = ext4_ext_insert_extent(icb, handle,
+ inode, &path, &newex, 0);
+ goto out;
+ }
+ if (le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 < from) {
+ now = ext4_ext_next_allocated_block(path, depth);
+ npath = ext4_find_extent(inode, now, &path, 0);
+ if (IS_ERR(npath))
goto out;
- ex--;
- ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = ext4_ext_get_actual_len(ex);
+ path = npath;
+ ex = path[depth].p_ext;
}
+ while (ex &&
+ le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 >= now &&
+ le32_to_cpu(ex->ee_block) <= to) {
+ int len, new_len = 0;
+ int unwritten;
+ ext4_lblk_t start, new_start;
+ ext4_fsblk_t newblock;
+
+ new_start = start = le32_to_cpu(ex->ee_block);
+ len = ext4_ext_get_actual_len(ex);
+ newblock = ext4_ext_pblock(ex);
+ if (start < from) {
+ len -= from - start;
+ new_len = from - start;
+ start = from;
+ } else {
+ if (start + len - 1 > to) {
+ new_len = start + len - 1 - to;
+ len -= new_len;
+ new_start = to + 1;
+ newblock += to + 1 - start;
+ }
+ }
- if (correct_index && eh->eh_entries)
- err = ext4_ext_correct_indexes(icb, handle, inode, path);
+ now = ext4_ext_next_allocated_block(path, depth);
+ if (!new_len) {
+ ret = ext4_ext_remove_extent(icb, handle,
+ inode, &path);
+ if (ret)
+ goto out;
- /* if this leaf is free, then we should
- * remove it from index block above */
- if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
- err = ext4_ext_rm_idx(icb, handle, inode, path + depth);
+ } else {
+ ext4_ext_remove_blocks(icb, handle,
+ inode,
+ ex, start, start + len - 1);
+ ex->ee_block = cpu_to_le32(new_start);
+ unwritten = ext4_ext_is_unwritten(ex);
+ ex->ee_len = cpu_to_le16(new_len);
+ ext4_ext_store_pblock(ex, newblock);
+ if (unwritten)
+ ext4_ext_mark_unwritten(ex);
+ ext4_ext_dirty(icb, handle,
+ inode, path + depth);
+ }
+ npath = ext4_find_extent(inode, now, &path, 0);
+ if (IS_ERR(npath))
+ goto out;
+
+ path = npath;
+ depth = ext_depth(inode);
+ ex = path[depth].p_ext;
+ }
out:
- return err;
+ if (path) {
+ ext4_ext_drop_refs(path);
+ kfree(path);
+ }
+
+ if (IS_ERR(npath))
+ ret = PTR_ERR(npath);
+
+ return ret;
}
/*
return err;
}
-/*
- * returns 1 if current index have to be freed (even partial)
- */
-static inline int
-ext4_ext_more_to_rm(struct ext4_ext_path *path)
-{
- BUG_ON(path->p_idx == NULL);
-
- if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
- return 0;
-
- /*
- * if truncate on deeper level happened it it wasn't partial
- * so we have to consider current index for truncation
- */
- if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block)
- return 0;
- return 1;
-}
-
-int ext4_ext_remove_space(void *icb, struct inode *inode, unsigned long start)
-{
-#ifndef __REACTOS__
- struct super_block *sb = inode->i_sb;
-#endif
- int depth = ext_depth(inode);
- struct ext4_ext_path *path;
- handle_t *handle = NULL;
- int i = 0, err = 0;
-
- /* probably first extent we're gonna free will be last in block */
- /*handle = ext4_journal_start(inode, depth + 1);*/
- /*if (IS_ERR(icb, handle))*/
- /*return PTR_ERR(icb, handle);*/
-
- /*
- * we start scanning from right side freeing all the blocks
- * after i_size and walking into the deep
- */
- path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
- if (path == NULL) {
- ext4_journal_stop(icb, handle);
- return -ENOMEM;
- }
- memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
- path[0].p_hdr = ext_inode_hdr(inode);
- if (ext4_ext_check_inode(inode)) {
- err = -EIO;
- goto out;
- }
- path[0].p_depth = depth;
-
- while (i >= 0 && err == 0) {
- if (i == depth) {
- /* this is leaf block */
- err = ext4_ext_rm_leaf(icb, handle, inode, path, start);
- /* root level have p_bh == NULL, extents_brelse() eats this */
- extents_brelse(path[i].p_bh);
- path[i].p_bh = NULL;
- i--;
- continue;
- }
-
- /* this is index block */
- if (!path[i].p_hdr) {
- path[i].p_hdr = ext_block_hdr(path[i].p_bh);
- }
-
- if (!path[i].p_idx) {
- /* this level hasn't touched yet */
- path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
- path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
- } else {
- /* we've already was here, see at next index */
- path[i].p_idx--;
- }
-
- if (ext4_ext_more_to_rm(path + i)) {
- struct buffer_head *bh;
- /* go to the next level */
- memset(path + i + 1, 0, sizeof(*path));
- bh = read_extent_tree_block(inode, ext4_idx_pblock(path[i].p_idx), path[0].p_depth - (i + 1), 0);
- if (IS_ERR(bh)) {
- /* should we reset i_size? */
- err = -EIO;
- break;
- }
- path[i+1].p_bh = bh;
-
- /* put actual number of indexes to know is this
- * number got changed at the next iteration */
- path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
- i++;
- } else {
- /* we finish processing this index, go up */
- if (path[i].p_hdr->eh_entries == 0 && i > 0) {
- /* index is empty, remove it
- * handle must be already prepared by the
- * truncatei_leaf() */
- err = ext4_ext_rm_idx(icb, handle, inode, path + i);
- }
- /* root level have p_bh == NULL, extents_brelse() eats this */
- extents_brelse(path[i].p_bh);
- path[i].p_bh = NULL;
- i--;
- }
- }
-
- /* TODO: flexible tree reduction should be here */
- if (path->p_hdr->eh_entries == 0) {
- /*
- * truncate to zero freed all the tree
- * so, we need to correct eh_depth
- */
- err = ext4_ext_get_access(icb, handle, inode, path);
- if (err == 0) {
- ext_inode_hdr(inode)->eh_depth = 0;
- ext_inode_hdr(inode)->eh_max =
- cpu_to_le16(ext4_ext_space_root(inode, 0));
- err = ext4_ext_dirty(icb, handle, inode, path);
- }
- }
-out:
- if (path) {
- ext4_ext_drop_refs(path);
- kfree(path);
- }
- ext4_journal_stop(icb, handle);
-
- return err;
-}
-
int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode)
{
struct ext4_extent_header *eh;
/* find next allocated block so that we know how many
* blocks we can allocate without ovelapping next extent */
- next = ext4_ext_next_allocated_block(path);
+ next = ext4_ext_next_allocated_block(path, depth);
BUG_ON(next <= iblock);
allocated = next - iblock;
if (flags & EXT4_GET_BLOCKS_PRE_IO && max_blocks > EXT_UNWRITTEN_MAX_LEN)
int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start)
{
- int ret = ext4_ext_remove_space(icb, inode, start);
+ int ret = __ext4_ext_truncate(icb, NULL, inode,
+ start, EXT_MAX_BLOCKS);
/* Save modifications on i_blocks field of the inode. */
if (!ret)
/* DEFINITIONS *************************************************************/
+#define FASTIO_DEBUG_LEVEL DL_NVR
+
+
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Ext2FastIoRead)
_SEH2_LEAVE;
}
- if (ExAcquireResourceExclusiveLite(&Fcb->MainResource, Wait))
- Locked = TRUE;
- else
+ if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait)) {
_SEH2_LEAVE;
+ }
+ Locked = TRUE;
if (IsWritingToEof(*FileOffset) ||
+ Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length ||
Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) {
Status = FALSE;
_SEH2_LEAVE;
}
+ if (Locked) {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ Locked = FALSE;
+ }
+
Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
LockKey, Buffer, IoStatus, DeviceObject);
if (Status) {
if (IoStatus)
Length = (ULONG)IoStatus->Information;
- if (Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length)
- Fcb->Header.ValidDataLength.QuadPart = FileOffset->QuadPart + Length;
}
} _SEH2_FINALLY {
if (Locked) {
- ExReleaseResourceLite(&Fcb->MainResource);
+ ExReleaseResourceLite(Fcb->Header.Resource);
}
FsRtlExitFileSystem();
return bResult;
}
+
+
+VOID NTAPI
+Ext2AcquireForCreateSection (
+ IN PFILE_OBJECT FileObject
+)
+
+{
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ if (Fcb->Header.Resource != NULL) {
+ ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
+ }
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireForCreateSection: Fcb=%p\n", Fcb));
+}
+
+VOID NTAPI
+Ext2ReleaseForCreateSection (
+ IN PFILE_OBJECT FileObject
+)
+{
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseForCreateSection: Fcb=%p\n", Fcb));
+
+ if (Fcb->Header.Resource != NULL) {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ }
+}
+
+
+NTSTATUS NTAPI
+Ext2AcquireFileForModWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PLARGE_INTEGER EndingOffset,
+ OUT PERESOURCE *ResourceToRelease,
+ IN PDEVICE_OBJECT DeviceObject
+)
+
+{
+ BOOLEAN ResourceAcquired = FALSE;
+
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ *ResourceToRelease = Fcb->Header.Resource;
+ ResourceAcquired = ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE);
+ if (!ResourceAcquired) {
+ *ResourceToRelease = NULL;
+ }
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForModWrite: Fcb=%p Acquired=%d\n",
+ Fcb, ResourceAcquired));
+
+ return (ResourceAcquired ? STATUS_SUCCESS : STATUS_CANT_WAIT);
+}
+
+NTSTATUS NTAPI
+Ext2ReleaseFileForModWrite (
+ IN PFILE_OBJECT FileObject,
+ IN PERESOURCE ResourceToRelease,
+ IN PDEVICE_OBJECT DeviceObject
+)
+{
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForModWrite: Fcb=%p\n", Fcb));
+
+ if (ResourceToRelease != NULL) {
+ ASSERT(ResourceToRelease == Fcb->Header.Resource);
+ ExReleaseResourceLite(ResourceToRelease);
+ } else {
+ DbgBreak();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+Ext2AcquireFileForCcFlush (
+ IN PFILE_OBJECT FileObject,
+ IN PDEVICE_OBJECT DeviceObject
+)
+{
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ if (Fcb->Header.Resource != NULL) {
+ ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
+ }
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForCcFlush: Fcb=%p\n", Fcb));
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NTAPI
+Ext2ReleaseFileForCcFlush (
+ IN PFILE_OBJECT FileObject,
+ IN PDEVICE_OBJECT DeviceObject
+)
+{
+ PEXT2_FCB Fcb = FileObject->FsContext;
+
+ DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForCcFlush: Fcb=%p\n", Fcb));
+
+ if (Fcb->Header.Resource != NULL) {
+ ExReleaseResourceLite(Fcb->Header.Resource);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS NTAPI
+Ext2PreAcquireForCreateSection(
+ IN PFS_FILTER_CALLBACK_DATA cd,
+ OUT PVOID *cc
+ )
+{
+ PEXT2_FCB Fcb = (PEXT2_FCB)cd->FileObject->FsContext;
+ NTSTATUS status;
+
+ ASSERT(cd->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION);
+ ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE);
+ if (cd->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) {
+ status = STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
+ } else if (Fcb->ShareAccess.Writers == 0) {
+ status = STATUS_FILE_LOCKED_WITH_ONLY_READERS;
+ } else {
+ status = STATUS_FILE_LOCKED_WITH_WRITERS;
+ }
+
+ return status;
+}
VcbMainResourceAcquired = TRUE;
}
- if (IsVcbReadOnly(Vcb)) {
- if (FileInformationClass != FilePositionInformation) {
- Status = STATUS_MEDIA_WRITE_PROTECTED;
- _SEH2_LEAVE;
- }
- }
-
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
Status = STATUS_ACCESS_DENIED;
_SEH2_LEAVE;
Mcb = Fcb->Mcb;
}
+ if (FileInformationClass != FilePositionInformation) {
+ if (IsVcbReadOnly(Vcb)) {
+ Status = STATUS_MEDIA_WRITE_PROTECTED;
+ _SEH2_LEAVE;
+ }
+ if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
+ Status = STATUS_ACCESS_DENIED;
+ _SEH2_LEAVE;
+ }
+ }
+
if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
((FileInformationClass == FileEndOfFileInformation) ||
(FileInformationClass == FileValidDataLengthInformation) ||
DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n",
&Mcb->FullName));
- /* always allow deleting on symlinks */
- if (Ccb->SymLink == NULL) {
+ if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
+ /* always allow deleting on symlinks */
+ } else {
status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb);
}
DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
+ /* discard buffer_headers for group_desc */
+ Ext2DropGroup(Vcb);
+
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
ExReleaseResourceLite(&Vcb->PagingIoResource);
_SEH2_TRY {
- if (!Mcb || !IsInodeSymLink(&Mcb->Inode)) {
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
+ !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
Status = STATUS_NOT_A_REPARSE_POINT;
_SEH2_LEAVE;
}
return Status;
}
-
NTSTATUS
Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
{
}
}
+ /* free all data blocks of the inode (to be set as symlink) */
+ {
+ LARGE_INTEGER zero = {0};
+ Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
+ }
+
+ /* decrease dir count of group desc and vcb stat */
+ if (S_ISDIR(Mcb->Inode.i_mode)) {
+
+ ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
+ Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
+
+ /* drop extra reference for dir inode */
+ ext3_dec_count(&Mcb->Inode);
+ }
+
/* overwrite inode mode as type SYMLINK */
- Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
OemNameLength, &BytesWritten);
if (NT_SUCCESS(Status)) {
- Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
+ Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
+ S_IFLNK | S_IRWXUGO);
}
} _SEH2_FINALLY {
}
}
- if (!Mcb) {
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
+ !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
Status = STATUS_NOT_A_REPARSE_POINT;
_SEH2_LEAVE;
}
if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE;
}
- if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
- SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
- }
- ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
- ClearFlag(Mcb->Inode.i_flags, S_IFLNK);
- Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
- if (NT_SUCCESS(Status)) {
- Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
- }
+
+ /* inode is to be removed */
+ SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
} _SEH2_FINALLY {
FlushBeforePurge = FALSE;
}
+ /* discard buffer_headers for group_desc */
+ Ext2DropGroup(Vcb);
+
FcbListEntry= NULL;
InitializeListHead(&FcbList);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, Ext2QueryGlobalParameters)
+#pragma alloc_text(INIT, Ext2QueryRegistrySettings)
#pragma alloc_text(INIT, DriverEntry)
#if EXT2_UNLOAD
#pragma alloc_text(PAGE, DriverUnload)
#endif
-BOOLEAN
-Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
+NTSTATUS NTAPI
+Ext2RegistryQueryCallback(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
{
- NTSTATUS Status;
- UNICODE_STRING ParameterPath;
- RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ ULONG i = 0;
+ BYTE *s, *t;
- ULONG WritingSupport = 0;
- ULONG CheckingBitmap = 0;
- ULONG Ext3ForceWriting = 0;
- ULONG AutoMount = 0;
+ if (NULL == ValueName || NULL == ValueData)
+ return STATUS_SUCCESS;
- UNICODE_STRING UniName;
- ANSI_STRING AnsiName;
+ if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(WRITING_SUPPORT) &&
+ _wcsnicmp(ValueName, WRITING_SUPPORT, wcslen(WRITING_SUPPORT)) == 0) {
- WCHAR UniBuffer[CODEPAGE_MAXLEN];
- USHORT Buffer[HIDINGPAT_LEN];
-
- ParameterPath.Length = 0;
+ if (ValueData && ValueLength == sizeof(DWORD)) {
+ if (*((PULONG)ValueData)) {
+ SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
+ } else {
+ ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
+ }
+ }
+ } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(CHECKING_BITMAP) &&
+ _wcsnicmp(ValueName, CHECKING_BITMAP, wcslen(CHECKING_BITMAP)) == 0) {
+
+ if (ValueData && ValueLength == sizeof(DWORD)) {
+ if (*((PULONG)ValueData)) {
+ SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
+ } else {
+ ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
+ }
+ }
+ } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(EXT3_FORCEWRITING) &&
+ _wcsnicmp(ValueName, EXT3_FORCEWRITING, wcslen(EXT3_FORCEWRITING)) == 0) {
+
+ if (ValueData && ValueLength == sizeof(DWORD)) {
+ if (*((PULONG)ValueData)) {
+ SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
+ SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
+ } else {
+ ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
+ }
+ }
+ } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(AUTO_MOUNT) &&
+ _wcsnicmp(ValueName, AUTO_MOUNT, wcslen(AUTO_MOUNT)) == 0) {
+
+ if (ValueData && ValueLength == sizeof(DWORD)) {
+ if (*((PULONG)ValueData)) {
+ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ } else {
+ ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ }
+ }
+ } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(CODEPAGE_NAME) &&
+ _wcsnicmp(ValueName, CODEPAGE_NAME, wcslen(CODEPAGE_NAME)) == 0) {
- ParameterPath.MaximumLength =
- RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR);
+ if (ValueData && ValueLength <= sizeof(WCHAR) * CODEPAGE_MAXLEN) {
+ RtlCopyMemory(&Ext2Global->Codepage.PageName[0],
+ ValueData, ValueLength);
+ }
+ } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_PREFIX) &&
+ _wcsnicmp(ValueName, HIDING_PREFIX, wcslen(HIDING_PREFIX)) == 0) {
- ParameterPath.Buffer =
- (PWSTR) Ext2AllocatePool(
- PagedPool,
- ParameterPath.MaximumLength,
- 'LG2E'
- );
+ if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) {
+ RtlCopyMemory(&Ext2Global->wHidingPrefix[0],
+ ValueData, ValueLength);
+ }
+ } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_SUFFIX) &&
+ _wcsnicmp(ValueName, HIDING_SUFFIX, wcslen(HIDING_SUFFIX)) == 0) {
- if (!ParameterPath.Buffer) {
- DbgBreak();
- DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n"));
- return FALSE;
+ if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) {
+ RtlCopyMemory(&Ext2Global->wHidingSuffix[0],
+ ValueData, ValueLength);
+ }
}
- RtlCopyUnicodeString(&ParameterPath, RegistryPath);
- RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY);
- /* querying value of WritingSupport */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
+ return STATUS_SUCCESS;
+}
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+NTSTATUS
+Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[8];
+ int i = 0;
+ NTSTATUS Status;
+
+ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 8);
+
+ /*
+ * 1 writing support
+ */
+ QueryTable[i].Flags = 0;
QueryTable[0].Name = WRITING_SUPPORT;
- QueryTable[0].EntryContext = &WritingSupport;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL );
+ /*
+ * 2 checking bitmap
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = CHECKING_BITMAP;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- DEBUG(DL_ERR, ( "Ext2QueryParameters: WritingSupport=%xh\n", WritingSupport));
+ /*
+ * 3 force writing
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = EXT3_FORCEWRITING;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- /* querying value of CheckingBitmap */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = CHECKING_BITMAP;
- QueryTable[0].EntryContext = &CheckingBitmap;
+ /*
+ * 4 automount
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = AUTO_MOUNT;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL );
+ /*
+ * 5 codepage
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = CODEPAGE_NAME;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- DEBUG(DL_ERR, ( "Ext2QueryParameters: CheckingBitmap=%xh\n", CheckingBitmap));
+ /*
+ * 6 hidden prefix
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = HIDING_PREFIX;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
- /* querying value of Ext3ForceWriting */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = EXT3_FORCEWRITING;
- QueryTable[0].EntryContext = &Ext3ForceWriting;
+
+ /*
+ * 7 hidden suffix
+ */
+ QueryTable[i].Flags = 0;
+ QueryTable[i].Name = HIDING_SUFFIX;
+ QueryTable[i].DefaultType = REG_NONE;
+ QueryTable[i].DefaultLength = 0;
+ QueryTable[i].DefaultData = NULL;
+ QueryTable[i].EntryContext = NULL;
+ QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
+ i++;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
+ RegistryPath->Buffer,
&QueryTable[0],
NULL,
- NULL );
+ NULL
+ );
- DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext3ForceWriting=%xh\n", Ext3ForceWriting));
+ return NT_SUCCESS(Status);
+}
- /* querying value of AutoMount */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
+BOOLEAN
+Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath)
+{
+ UNICODE_STRING ParameterPath;
+ UNICODE_STRING UniName;
+ ANSI_STRING AnsiName;
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = AUTO_MOUNT;
- QueryTable[0].EntryContext = &AutoMount;
+ ULONG WritingSupport = 0;
+ ULONG CheckingBitmap = 0;
+ ULONG Ext3ForceWriting = 0;
+ ULONG AutoMount = 0;
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL );
+ WCHAR UniBuffer[CODEPAGE_MAXLEN];
+ USHORT Buffer[HIDINGPAT_LEN];
- SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
- if (NT_SUCCESS(Status) && AutoMount == 0) {
- ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
+ NTSTATUS Status;
+
+ ParameterPath.Length = 0;
+ ParameterPath.MaximumLength =
+ RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR);
+ ParameterPath.Buffer =
+ (PWSTR) Ext2AllocatePool(
+ PagedPool,
+ ParameterPath.MaximumLength,
+ 'LG2E'
+ );
+ if (!ParameterPath.Buffer) {
+ DbgBreak();
+ DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n"));
+ return FALSE;
}
- DEBUG(DL_ERR, ( "Ext2QueryParameters: AutoMount=%xh\n", AutoMount));
+ RtlCopyUnicodeString(&ParameterPath, RegistryPath);
+ RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY);
- /* querying codepage */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = CODEPAGE_NAME;
- QueryTable[0].EntryContext = &(UniName);
- UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR);
- UniName.Length = 0;
- UniName.Buffer = (PWSTR)UniBuffer;
+ /* enable automount of ext2/3/4 volumes */
+ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL );
+ /* query parameter settings from registry */
+ Ext2QueryGlobalParameters(&ParameterPath);
- if (NT_SUCCESS(Status)) {
- DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext2CodePage=%wZ\n", &UniName));
+ /* set global codepage settings */
+ if (wcslen(&Ext2Global->Codepage.PageName[0])) {
+ UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->Codepage.PageName[0]);
+ UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR);
+ UniName.Buffer = &Ext2Global->Codepage.PageName[0];
AnsiName.MaximumLength = CODEPAGE_MAXLEN;
AnsiName.Length = 0;
- AnsiName.Buffer = &(Ext2Global->Codepage.AnsiName[0]);
-
+ AnsiName.Buffer = &Ext2Global->Codepage.AnsiName[0];
Status = RtlUnicodeStringToAnsiString(
&AnsiName,
&UniName,
FALSE);
-
if (!NT_SUCCESS(Status)) {
DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName));
RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8);
}
Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0;
- /* querying name hiding patterns: prefix*/
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = HIDING_PREFIX;
- QueryTable[0].EntryContext = &(UniName);
- UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
- UniName.Length = 0;
- UniName.Buffer = Buffer;
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL );
-
- if (NT_SUCCESS(Status)) {
- DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix=%wZ\n", &UniName));
- AnsiName.MaximumLength =HIDINGPAT_LEN;
+ /* set global hidden prefix pattern */
+ if (wcslen(&Ext2Global->wHidingPrefix[0])) {
+ UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingPrefix[0]);
+ UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
+ UniName.Buffer = &Ext2Global->wHidingPrefix[0];
+ AnsiName.MaximumLength = HIDINGPAT_LEN;
AnsiName.Length = 0;
AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]);
}
Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
- /* querying name hiding patterns: suffix */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = HIDING_SUFFIX;
- QueryTable[0].EntryContext = &(UniName);
- UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
- UniName.Length = 0;
- UniName.Buffer = Buffer;
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- ParameterPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL
- );
-
- if (NT_SUCCESS(Status)) {
-
- DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix=%wZ\n", &UniName));
+ /* set global hidden suffix pattern */
+ if (wcslen(&Ext2Global->wHidingSuffix[0])) {
+ UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingSuffix[0]);
+ UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
+ UniName.Buffer = &Ext2Global->wHidingSuffix[0];
AnsiName.MaximumLength = HIDINGPAT_LEN;
AnsiName.Length = 0;
AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]);
}
Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
- {
- if (WritingSupport) {
- SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
- } else {
- ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
- }
-
- if (CheckingBitmap) {
- SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
- } else {
- ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
- }
-
- if (Ext3ForceWriting) {
- DEBUG(DL_WRN, ("Ext2Fsd -- Warning: Ext3ForceWriting enabled !!!\n"));
-
- SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
- SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
- } else {
- ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
- }
- }
-
Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer;
Ext2Global->RegistryPath.Length = 0;
Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength;
)
#endif
+VOID
+Ext2EresourceAlignmentChecking()
+{
+ /* Verify ERESOURCE alignment in structures */
+ CL_ASSERT((FIELD_OFFSET(EXT2_GLOBAL, Resource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MainResource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, PagingIoResource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaInode) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaBlock) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, bd.bd_bh_lock) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_VCB, sbi.s_gd_lock) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, PagingIoResource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_FCB, MainResource) & 7) == 0);
+ CL_ASSERT((FIELD_OFFSET(EXT2_FCB, PagingIoResource) & 7) == 0);
+}
/*
* NAME: DriverEntry
PFAST_IO_DISPATCH FastIoDispatch;
PCACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
- LARGE_INTEGER Timeout;
NTSTATUS Status;
int rc = 0;
BOOLEAN linux_lib_inited = FALSE;
BOOLEAN journal_module_inited = FALSE;
- /* Verify ERESOURCE alignment in structures */
- ASSERT((FIELD_OFFSET(EXT2_GLOBAL, Resource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_VCB, MainResource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_VCB, PagingIoResource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_VCB, MetaLock) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_FCBVCB, PagingIoResource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_FCB, MainResource) & 7) == 0);
- ASSERT((FIELD_OFFSET(EXT2_FCB, PagingIoResource) & 7) == 0);
-
/* Verity super block ... */
ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024);
ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56);
InitializeListHead(&(Ext2Global->VcbList));
ExInitializeResourceLite(&(Ext2Global->Resource));
- /* Reaper thread engine event */
- KeInitializeEvent(&Ext2Global->Reaper.Engine,
- SynchronizationEvent, FALSE);
-
/* query registry settings */
- Ext2QueryGlobalParameters(RegistryPath);
+ Ext2QueryRegistrySettings(RegistryPath);
/* create Ext2Fsd cdrom fs deivce */
RtlInitUnicodeString(&DeviceName, CDROM_NAME);
}
/* start resource reaper thread */
- Status= Ext2StartReaperThread();
+ Status= Ext2StartReaper(
+ &Ext2Global->McbReaper,
+ Ext2McbReaperThread);
if (!NT_SUCCESS(Status)) {
goto errorout;
}
- /* make sure Reaperthread is started */
- Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
- Status = KeWaitForSingleObject(
- &(Ext2Global->Reaper.Engine),
- Executive,
- KernelMode,
- FALSE,
- &Timeout
- );
- if (Status != STATUS_SUCCESS) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ Status= Ext2StartReaper(
+ &Ext2Global->bhReaper,
+ Ext2bhReaperThread);
+ if (!NT_SUCCESS(Status)) {
+ Ext2StopReaper(&Ext2Global->McbReaper);
goto errorout;
}
FastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll;
FastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey;
FastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetworkOpenInfo;
+
+ FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite;
+ FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite;
FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite;
FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite;
FastIoDispatch->AcquireForCcFlush = Ext2AcquireFileForCcFlush;
FastIoDispatch->ReleaseForCcFlush = Ext2ReleaseFileForCcFlush;
FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection;
FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection;
+
DriverObject->FastIoDispatch = FastIoDispatch;
//
Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead = Ext2NoOpAcquire;
Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = Ext2NoOpRelease;
+
+#ifndef _WIN2K_TARGET_
+ //
+ // Initialize FS Filter callbacks
+ //
+
+ RtlZeroMemory(&Ext2Global->FilterCallbacks, sizeof(FS_FILTER_CALLBACKS));
+ Ext2Global->FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
+ Ext2Global->FilterCallbacks.PreAcquireForSectionSynchronization = Ext2PreAcquireForCreateSection;
+ FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &Ext2Global->FilterCallbacks );
+
+#endif
+
//
// Initialize the global data
//
struct buffer_head * bh = NULL;
bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS);
if (bh) {
+ atomic_inc(&g_jbh.bh_count);
+ atomic_inc(&g_jbh.bh_acount);
+
memset(bh, 0, sizeof(struct buffer_head));
+ InitializeListHead(&bh->b_link);
+ KeQuerySystemTime(&bh->b_ts_creat);
DEBUG(DL_BH, ("bh=%p allocated.\n", bh));
INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
}
+
return bh;
}
DEBUG(DL_BH, ("bh=%p mdl=%p (Flags:%xh VA:%p) released.\n", bh, bh->b_mdl,
bh->b_mdl->MdlFlags, bh->b_mdl->MappedSystemVa));
- if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_PAGES_LOCKED)) {
- /* MmUnlockPages will release it's VA */
- MmUnlockPages(bh->b_mdl);
- } else if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) {
+ if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) {
MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl);
}
-
Ext2DestroyMdl(bh->b_mdl);
}
if (bh->b_bcb) {
DEBUG(DL_BH, ("bh=%p freed.\n", bh));
DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
kmem_cache_free(g_jbh.bh_cache, bh);
+ atomic_dec(&g_jbh.bh_count);
}
}
PVOID bcb = NULL;
PVOID ptr = NULL;
- KIRQL irql = 0;
struct list_head *entry;
/* allocate buffer_head and initialize it */
}
/* search the bdev bh list */
- spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+ ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE);
tbh = buffer_head_search(bdev, block);
if (tbh) {
bh = tbh;
get_bh(bh);
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
goto errorout;
}
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head();
if (!bh) {
bh->b_blocknr = block;
bh->b_size = size;
bh->b_data = NULL;
- atomic_inc(&g_jbh.bh_count);
- atomic_inc(&g_jbh.bh_acount);
again:
set_buffer_uptodate(bh);
}
- bh->b_mdl = Ext2CreateMdl(ptr, TRUE, bh->b_size, IoModifyAccess);
+ bh->b_mdl = Ext2CreateMdl(ptr, bh->b_size, IoModifyAccess);
if (bh->b_mdl) {
/* muse map the PTE to NonCached zone. journal recovery will
access the PTE under spinlock: DISPATCH_LEVEL IRQL */
bh->b_data = MmMapLockedPagesSpecifyCache(
bh->b_mdl, KernelMode, MmNonCached,
NULL,FALSE, HighPagePriority);
+ /* bh->b_data = MmMapLockedPages(bh->b_mdl, KernelMode); */
}
if (!bh->b_mdl || !bh->b_data) {
free_buffer_head(bh);
DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p mdl=%p (Flags:%xh VA:%p)\n",
Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_data));
- spin_lock_irqsave(&bdev->bd_bh_lock, irql);
-
+ ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE);
/* do search again here */
tbh = buffer_head_search(bdev, block);
if (tbh) {
free_buffer_head(bh);
bh = tbh;
get_bh(bh);
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ RemoveEntryList(&bh->b_link);
+ InitializeListHead(&bh->b_link);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
goto errorout;
- } else
+ } else {
buffer_head_insert(bdev, bh);
-
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ }
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
/* we get it */
errorout:
}
struct buffer_head *
-get_block_bh(
+get_block_bh_pin(
struct block_device * bdev,
sector_t block,
unsigned long size,
PEXT2_VCB Vcb = bdev->bd_priv;
LARGE_INTEGER offset;
- KIRQL irql = 0;
struct list_head *entry;
/* allocate buffer_head and initialize it */
}
/* search the bdev bh list */
- spin_lock_irqsave(&bdev->bd_bh_lock, irql);
+ ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE);
tbh = buffer_head_search(bdev, block);
if (tbh) {
bh = tbh;
get_bh(bh);
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
goto errorout;
}
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head();
if (!bh) {
bh->b_blocknr = block;
bh->b_size = size;
bh->b_data = NULL;
- atomic_inc(&g_jbh.bh_count);
- atomic_inc(&g_jbh.bh_acount);
again:
&offset,
bh->b_size,
FALSE,
- PIN_WAIT | PIN_EXCLUSIVE,
+ PIN_WAIT,
&bh->b_bcb,
(PVOID *)&bh->b_data)) {
Ext2Sleep(100);
set_buffer_uptodate(bh);
}
+ if (bh->b_bcb)
+ CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
+
if (!bh->b_data) {
free_buffer_head(bh);
bh = NULL;
goto errorout;
}
-
get_bh(bh);
- CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n",
Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data));
- spin_lock_irqsave(&bdev->bd_bh_lock, irql);
-
+ ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE);
/* do search again here */
tbh = buffer_head_search(bdev, block);
if (tbh) {
get_bh(tbh);
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
free_buffer_head(bh);
bh = tbh;
+ RemoveEntryList(&bh->b_link);
+ InitializeListHead(&bh->b_link);
goto errorout;
} else {
buffer_head_insert(bdev, bh);
}
-
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
/* we get it */
errorout:
return bh;
}
-int submit_bh(int rw, struct buffer_head *bh)
+int submit_bh_pin(int rw, struct buffer_head *bh)
{
struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = bdev->bd_priv;
return 0;
}
+#if 0
+
+struct buffer_head *
+get_block_bh(
+ struct block_device * bdev,
+ sector_t block,
+ unsigned long size,
+ int zero
+)
+{
+ return get_block_bh_mdl(bdev, block, size, zero);
+}
+
+int submit_bh(int rw, struct buffer_head *bh)
+{
+ return submit_bh_mdl(rw, bh);
+}
+
+#else
+
+struct buffer_head *
+get_block_bh(
+ struct block_device * bdev,
+ sector_t block,
+ unsigned long size,
+ int zero
+)
+{
+ return get_block_bh_pin(bdev, block, size, zero);
+}
+
+int submit_bh(int rw, struct buffer_head *bh)
+{
+ return submit_bh_pin(rw, bh);
+}
+#endif
+
struct buffer_head *
__getblk(
struct block_device * bdev,
{
struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv;
- KIRQL irql = 0;
ASSERT(Vcb->Identifier.Type == EXT2VCB);
ll_rw_block(WRITE, 1, &bh);
}
- spin_lock_irqsave(&bdev->bd_bh_lock, irql);
- if (!atomic_dec_and_test(&bh->b_count)) {
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ if (1 == atomic_read(&bh->b_count)) {
+ } else if (atomic_dec_and_test(&bh->b_count)) {
+ atomic_inc(&bh->b_count);
+ } else {
+ return;
+ }
+
+ ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE);
+ if (atomic_dec_and_test(&bh->b_count)) {
+ ASSERT(0 == atomic_read(&bh->b_count));
+ } else {
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
return;
}
buffer_head_remove(bdev, bh);
- spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
+ KeQuerySystemTime(&bh->b_ts_drop);
+ InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link);
+ KeClearEvent(&Vcb->bd.bd_bh_notify);
+ ExReleaseResourceLite(&bdev->bd_bh_lock);
+ KeSetEvent(&Ext2Global->bhReaper.Wait, 0, FALSE);
DEBUG(DL_BH, ("brelse: cnt=%u size=%u blk=%10.10xh bh=%p ptr=%p\n",
atomic_read(&g_jbh.bh_count) - 1, bh->b_size,
bh->b_blocknr, bh, bh->b_data ));
-
- free_buffer_head(bh);
- atomic_dec(&g_jbh.bh_count);
}
int sync_blockdev(struct block_device *bdev)
{
PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv;
-
- if (0 == atomic_read(&g_jbh.bh_count)) {
- Ext2FlushVolume(NULL, Vcb, FALSE);
- }
+ Ext2FlushVolume(NULL, Vcb, FALSE);
return 0;
}
#pragma alloc_text(PAGE, Ext2DestroyVcb)
#pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
#pragma alloc_text(PAGE, Ext2ReaperThread)
-#pragma alloc_text(PAGE, Ext2StartReaperThread)
+#pragma alloc_text(PAGE, Ext2StartReaper)
+#pragma alloc_text(PAGE, Ext2StopReaper)
#endif
PEXT2_IRP_CONTEXT
/* need wake the reaper thread if there are many Mcb allocated */
if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
- KeSetEvent(&Ext2Global->Reaper.Wait, 0, FALSE);
+ KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE);
}
/* allocate Mcb from LookasideList */
#ifndef __REACTOS__
PEXT2_MCB Parent = Mcb->Parent;
#endif
+
ASSERT(Mcb != NULL);
ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
return FALSE;
}
+
RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
if (RtlCheckBit(&bitmap, dwBlk) == 0) {
VOID
Ext2ParseRegistryVolumeParams(
IN PUNICODE_STRING Params,
- OUT PEXT2_VOLUME_PROPERTY2 Property
+ OUT PEXT2_VOLUME_PROPERTY3 Property
)
{
WCHAR Codepage[CODEPAGE_MAXLEN];
WCHAR Suffix[HIDINGPAT_LEN];
USHORT MountPoint[4];
UCHAR DrvLetter[4];
+ WCHAR wUID[8], wGID[8], wEUID[8], wEGID[8];
+ CHAR sUID[8], sGID[8], sEUID[8], sEGID[8];
BOOLEAN bWriteSupport = FALSE,
bCheckBitmap = FALSE,
bCodeName = FALSE,
bMountPoint = FALSE;
+ BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
+
struct {
PWCHAR Name; /* parameters name */
PBOOLEAN bExist; /* is it contained in params */
{MOUNT_POINT, &bMountPoint, 4,
&MountPoint[0], &DrvLetter[0]},
+ {UID, &bUID, 8, &wUID[0], &sUID[0],},
+ {GID, &bGID, 8, &wGID[0], &sGID[0]},
+ {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
+ {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
+
/* end */
{NULL, NULL, 0, NULL}
};
RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
- RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY2));
+ RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
- Property->Command = APP_CMD_SET_PROPERTY2;
+ Property->Command = APP_CMD_SET_PROPERTY3;
for (i=0; ParamPattern[i].Name != NULL; i++) {
Property->DrvLetter = DrvLetter[0];
Property->DrvLetter |= 0x80;
}
+
+ if (bUID && bGID) {
+ SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
+ Property->uid = (USHORT)atoi(sUID);
+ Property->gid = (USHORT)atoi(sGID);
+ if (bEUID) {
+ Property->euid = (USHORT)atoi(sEUID);
+ Property->egid = (USHORT)atoi(sEGID);
+ Property->EIDS = TRUE;
+ } else {
+ Property->EIDS = FALSE;
+ }
+ } else {
+ ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ }
}
NTSTATUS
if (NT_SUCCESS(Status)) {
/* set Vcb settings from registery */
- EXT2_VOLUME_PROPERTY2 Property;
+ EXT2_VOLUME_PROPERTY3 Property;
Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
- if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) {
+ if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) {
RtlCopyMemory( Vcb->sHidingPrefix,
Ext2Global->sHidingPrefix,
HIDINGPAT_LEN);
HIDINGPAT_LEN);
}
- if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) {
+ if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
RtlCopyMemory( Vcb->sHidingSuffix,
Ext2Global->sHidingSuffix,
HIDINGPAT_LEN);
BOOLEAN NotifySyncInitialized = FALSE;
BOOLEAN ExtentsInitialized = FALSE;
BOOLEAN InodeLookasideInitialized = FALSE;
+ BOOLEAN GroupLoaded = FALSE;
_SEH2_TRY {
/* initialize eresources */
ExInitializeResourceLite(&Vcb->MainResource);
ExInitializeResourceLite(&Vcb->PagingIoResource);
- ExInitializeResourceLite(&Vcb->MetaLock);
+ ExInitializeResourceLite(&Vcb->MetaInode);
+ ExInitializeResourceLite(&Vcb->MetaBlock);
ExInitializeResourceLite(&Vcb->McbLock);
+ ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
#ifndef _WIN2K_TARGET_
ExInitializeFastMutex(&Vcb->Mutex);
FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
/* initialize UUID and serial number */
if (Ext2IsNullUuid(sb->s_uuid)) {
ExUuidCreate((UUID *)sb->s_uuid);
- } else {
- /* query parameters from registry */
- if (!NT_SUCCESS(Ext2PerformRegistryVolumeParams(Vcb))) {
- /* don't mount this volume */
- Status = STATUS_UNRECOGNIZED_VOLUME;
- _SEH2_LEAVE;
- }
}
-
Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
((ULONG*)sb->s_uuid)[1] +
((ULONG*)sb->s_uuid)[2] +
Vcb->bd.bd_volume = Vcb->Volume;
Vcb->bd.bd_priv = (void *) Vcb;
memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
- spin_lock_init(&Vcb->bd.bd_bh_lock);
+ InitializeListHead(&Vcb->bd.bd_bh_free);
+ ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
+ KeInitializeEvent(&Vcb->bd.bd_bh_notify,
+ NotificationEvent, TRUE);
Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
Vcb->BlockSize, 0, 0, NULL);
if (!Vcb->bd.bd_bh_cache) {
Status = STATUS_UNSUCCESSFUL;
_SEH2_LEAVE;
}
+ GroupLoaded = TRUE;
/* recovery journal since it's ext3 */
if (Vcb->IsExt3fs) {
/* get anything doen, then refer target device */
ObReferenceObject(Vcb->TargetDeviceObject);
+
+ /* query parameters from registry */
+ Ext2PerformRegistryVolumeParams(Vcb);
+
SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
} _SEH2_FINALLY {
}
if (ExtentsInitialized) {
- Ext2DropGroup(Vcb);
- if (Vcb->bd.bd_bh_cache)
+ if (Vcb->bd.bd_bh_cache) {
+ if (GroupLoaded)
+ Ext2PutGroup(Vcb);
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ }
FsRtlUninitializeLargeMcb(&(Vcb->Extents));
}
if (VcbResourceInitialized) {
ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->MainResource);
ExDeleteResourceLite(&Vcb->PagingIoResource);
}
if (Vcb->bd.bd_bh_cache)
kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
if (Vcb->SuperBlock) {
Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->PagingIoResource);
ExDeleteResourceLite(&Vcb->MainResource);
/* Reaper thread to release unused Mcb blocks */
VOID NTAPI
-Ext2ReaperThread(
+Ext2McbReaperThread(
PVOID Context
)
{
- BOOLEAN GlobalAcquired = FALSE;
-
- BOOLEAN DidNothing = TRUE;
- BOOLEAN LastState = TRUE;
- BOOLEAN WaitLock;
-
+ PEXT2_REAPER Reaper = Context;
PLIST_ENTRY List = NULL;
LARGE_INTEGER Timeout;
ULONG i, NumOfMcbs;
+ BOOLEAN GlobalAcquired = FALSE;
+
+ BOOLEAN DidNothing = TRUE;
+ BOOLEAN LastState = TRUE;
+ BOOLEAN WaitLock;
+
_SEH2_TRY {
/* wake up DirverEntry */
- KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE);
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
/* now process looping */
- while (TRUE) {
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
WaitLock = FALSE;
/* wait until it is waken or it times out */
KeWaitForSingleObject(
- &(Ext2Global->Reaper.Wait),
+ &Reaper->Wait,
Executive,
KernelMode,
FALSE,
&Timeout
);
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
DidNothing = TRUE;
/* acquire global exclusive lock */
if (GlobalAcquired) {
ExReleaseResourceLite(&Ext2Global->Resource);
}
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
} _SEH2_END;
PsTerminateSystemThread(STATUS_SUCCESS);
}
+/* get the first Mcb record in Vcb->McbList */
+
+BOOLEAN
+Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
+{
+ struct buffer_head *bh = NULL;
+ PLIST_ENTRY list = NULL;
+ LARGE_INTEGER now;
+ BOOLEAN wake = FALSE;
+
+ KeQuerySystemTime(&now);
+
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+ while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+ list = RemoveHeadList(&Vcb->bd.bd_bh_free);
+ bh = CONTAINING_RECORD(list, struct buffer_head, b_link);
+ if (atomic_read(&bh->b_count)) {
+ InitializeListHead(&bh->b_link);
+ continue;
+ }
+
+ if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
+ (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
+ (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
+ InsertTailList(head, &bh->b_link);
+ } else {
+ InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
+ break;
+ }
+ }
+ wake = IsListEmpty(&Vcb->bd.bd_bh_free);
+ ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+
+ if (wake)
+ KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
+
+ return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
+}
+
+
+/* Reaper thread to release unused buffer heads */
+VOID NTAPI
+Ext2bhReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PEXT2_VCB Vcb = NULL;
+ LIST_ENTRY List, *Link;
+ LARGE_INTEGER Timeout;
+
+ BOOLEAN GlobalAcquired = FALSE;
+ BOOLEAN DidNothing = FALSE;
+ BOOLEAN NonWait = FALSE;
+
+ _SEH2_TRY {
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ /* wait until it is waken or it times out */
+ if (NonWait) {
+ Timeout.QuadPart = (LONGLONG)-10*1000*10;
+ NonWait = FALSE;
+ } else if (DidNothing) {
+ Timeout.QuadPart = Timeout.QuadPart * 2;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
+ }
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ InitializeListHead(&List);
+
+ /* acquire global exclusive lock */
+ ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+ GlobalAcquired = TRUE;
+ /* search all Vcb to get unused resources freed to system */
+ for (Link = Ext2Global->VcbList.Flink;
+ Link != &(Ext2Global->VcbList);
+ Link = Link->Flink ) {
+
+ Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+ if (Ext2QueryUnusedBH(Vcb, &List))
+ NonWait = TRUE;
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+
+ DidNothing = IsListEmpty(&List);
+ while (!IsListEmpty(&List)) {
+ struct buffer_head *bh;
+ Link = RemoveHeadList(&List);
+ bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
+ ASSERT(0 == atomic_read(&bh->b_count));
+ free_buffer_head(bh);
+ }
+ }
+
+ } _SEH2_FINALLY {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ } _SEH2_END;
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
NTSTATUS
-Ext2StartReaperThread()
+Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
{
NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES oa;
HANDLE handle = 0;
+ LARGE_INTEGER timeout;
+
+ Reaper->Free = Free;
/* initialize wait event */
KeInitializeEvent(
- &Ext2Global->Reaper.Wait,
+ &Reaper->Wait,
+ SynchronizationEvent, FALSE
+ );
+
+ /* Reaper thread engine event */
+ KeInitializeEvent(
+ &Reaper->Engine,
SynchronizationEvent, FALSE
);
&oa,
NULL,
NULL,
- Ext2ReaperThread,
- NULL
+ Free,
+ (PVOID)Reaper
);
if (NT_SUCCESS(status)) {
ZwClose(handle);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ status = KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout
+ );
+ if (status != STATUS_SUCCESS) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
}
return status;
}
+
+
+VOID NTAPI
+Ext2StopReaper(PEXT2_REAPER Reaper)
+{
+ LARGE_INTEGER timeout;
+
+ Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
+ KeSetEvent(&Reaper->Wait, 0, FALSE);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout);
+}
} else {
- if (Nocache) {
+ if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject) {
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
}
MainResourceAcquired = TRUE;
- if (FileObject->SectionObjectPointer->DataSectionObject != NULL) {
- CcFlushCache( FileObject->SectionObjectPointer,
- &ByteOffset,
- Length,
- &Irp->IoStatus );
- if (!NT_SUCCESS(Irp->IoStatus.Status))
- _SEH2_LEAVE;
+ CcFlushCache(&Fcb->SectionObject,
+ &ByteOffset,
+ Length,
+ &Irp->IoStatus );
+ if (!NT_SUCCESS(Irp->IoStatus.Status))
+ _SEH2_LEAVE;
+ ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+
+ if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
+ ExReleaseResourceLite(&(Fcb->PagingIoResource));
}
+ CcPurgeCacheSection( &Fcb->SectionObject,
+ NULL,
+ 0,
+ FALSE );
+
+ ExConvertExclusiveToShared(&Fcb->MainResource);
} else {
} else {
+ if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) {
+ Status = STATUS_ACCESS_DENIED;
+ _SEH2_LEAVE;
+ }
+
if (IsDirectory(Fcb)) {
_SEH2_LEAVE;
}