Upgrade the driver to release 0.66.

CORE-11295 #resolve #comment Committed in r71411

svn path=/trunk/; revision=71411
This commit is contained in:
Pierre Schweitzer 2016-05-26 17:10:02 +00:00
parent e6b12e4774
commit f0a44d618b
21 changed files with 1848 additions and 1071 deletions

View file

@ -167,8 +167,8 @@ typedef struct _EXT2_VOLUME_PROPERTY {
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 {
@ -196,14 +196,24 @@ typedef struct _EXT2_VOLUME_PROPERTY2 {
} 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 */

View file

@ -47,7 +47,7 @@
/* STRUCTS & CONSTS******************************************************/
#define EXT2FSD_VERSION "0.63"
#define EXT2FSD_VERSION "0.66"
/* WDK DEFINITIONS ******************************************************/
@ -110,6 +110,26 @@ typedef struct ext3_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2;
#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"
@ -130,6 +150,10 @@ typedef struct ext3_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2;
#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"
@ -464,6 +488,17 @@ typedef PVOID PBCB;
// 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 */
@ -479,6 +514,9 @@ typedef struct _EXT2_GLOBAL {
/* 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;
@ -496,10 +534,8 @@ typedef struct _EXT2_GLOBAL {
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;
@ -512,11 +548,14 @@ typedef struct _EXT2_GLOBAL {
/* 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;
@ -599,8 +638,11 @@ typedef struct _EXT2_VCB {
/* 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;
@ -669,12 +711,6 @@ typedef struct _EXT2_VCB {
BOOLEAN IsExt3fs;
PEXT2_SUPER_BLOCK SuperBlock;
/*
// Bitmap Block per group
PRTL_BITMAP BlockBitMaps;
PRTL_BITMAP InodeBitMaps;
*/
// Block / Cluster size
ULONG BlockSize;
@ -745,6 +781,7 @@ typedef struct _EXT2_VCB {
#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
@ -1148,7 +1185,6 @@ int Ext2CheckFileAccess (PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt);
PMDL
Ext2CreateMdl (
IN PVOID Buffer,
IN BOOLEAN bPaged,
IN ULONG Length,
IN LOCK_OPERATION Operation
);
@ -1255,44 +1291,6 @@ Ext2NoOpAcquire (
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
//
@ -1482,21 +1480,21 @@ Ext2FreePool(
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
);
@ -1911,6 +1909,13 @@ Ext2NewInode(
OUT PULONG Inode
);
NTSTATUS
Ext2UpdateGroupDirStat(
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
IN ULONG Group
);
NTSTATUS
Ext2FreeInode(
IN PEXT2_IRP_CONTEXT IrpContext,
@ -1934,7 +1939,8 @@ Ext2SetFileType (
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
@ -2110,6 +2116,56 @@ Ext2FastIoQueryNetworkOpenInfo (
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
@ -2402,8 +2458,10 @@ int ext3_is_dir_empty(struct ext2_icb *icb, struct inode *inode);
// 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);
@ -2465,6 +2523,19 @@ Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext);
// Memory.c
//
VOID
NTAPI
Ext2McbReaperThread(
PVOID Context
);
VOID
NTAPI
Ext2bhReaperThread(
PVOID Context
);
PEXT2_IRP_CONTEXT
Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp );
@ -2769,7 +2840,10 @@ Ext2ReaperThread(
);
NTSTATUS
Ext2StartReaperThread();
Ext2StartReaper(PEXT2_REAPER, EXT2_REAPER_RELEASE);
VOID
NTAPI
Ext2StopReaper(PEXT2_REAPER Reaper);
//
// Misc.c
@ -2948,6 +3022,7 @@ Ext2WriteInode (
OUT PULONG dwReturn
);
VOID
Ext2StartFloppyFlushDpc (
PEXT2_VCB Vcb,

View file

@ -8,7 +8,7 @@
//
typedef struct {
volatile int counter;
volatile LONG counter;
} atomic_t;
#define ATOMIC_INIT(i) (i)
@ -152,4 +152,4 @@ static inline int atomic_add_negative(int volatile i, atomic_t volatile *v)
return (InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i) + i);
}
#endif /* LINUX_ATOMIC_H */
#endif /* LINUX_ATOMIC_H */

View file

@ -22,8 +22,18 @@
/*
* 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 */
@ -36,7 +46,6 @@ struct ext3_sb_info {
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 */

View file

@ -546,9 +546,11 @@ struct block_device {
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 */
};
//
@ -709,6 +711,7 @@ typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
* 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 */
@ -725,7 +728,10 @@ struct buffer_head {
// 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) */
};

View file

@ -51,9 +51,8 @@ Ext2MediaEjectControlCompletion (
PMDL
Ext2CreateMdl (
IN PVOID Buffer,
IN BOOLEAN bPaged,
IN ULONG Length,
IN LOCK_OPERATION Operation
IN LOCK_OPERATION op
)
{
NTSTATUS Status;
@ -65,10 +64,10 @@ Ext2CreateMdl (
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) {
@ -89,6 +88,7 @@ Ext2DestroyMdl (IN PMDL Mdl)
while (Mdl) {
PMDL Next;
Next = Mdl->Next;
Mdl->Next = NULL;
if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) {
MmUnlockPages (Mdl);
}

View file

@ -33,6 +33,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN FcbResourceAcquired = FALSE;
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
BOOLEAN SymLinkDelete = FALSE;
_SEH2_TRY {
@ -198,7 +199,11 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
}
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);
}
}
//
@ -279,52 +284,52 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
}
}
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;
}
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 );
}
}
//
// this file is to be deleted ...
//
if (Ccb->SymLink) {
Mcb = Ccb->SymLink;
FileObject->DeletePending = FALSE;
}
//
// re-acquire the main resource lock
//
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
);
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)));

View file

@ -38,8 +38,7 @@ Ext2AcquireForLazyWrite (
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;
}
@ -47,7 +46,6 @@ Ext2AcquireForLazyWrite (
Fcb->LazyWriterThread = PsGetCurrentThread();
ASSERT(IoGetTopLevelIrp() == NULL);
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
return TRUE;
@ -59,9 +57,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context)
//
// 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);
@ -74,7 +70,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context)
ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread());
Fcb->LazyWriterThread = NULL;
ExReleaseResourceLite(&Fcb->PagingIoResource);
ExReleaseResourceLite(Fcb->Header.Resource);
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
IoSetTopLevelIrp( NULL );
@ -84,24 +80,18 @@ BOOLEAN NTAPI
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;
@ -110,9 +100,7 @@ Ext2AcquireForReadAhead (IN PVOID Context,
VOID NTAPI
Ext2ReleaseFromReadAhead (IN PVOID Context)
{
PEXT2_FCB Fcb;
Fcb = (PEXT2_FCB) Context;
PEXT2_FCB Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL);
@ -122,9 +110,8 @@ Ext2ReleaseFromReadAhead (IN PVOID Context)
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
@ -149,120 +136,3 @@ Ext2NoOpRelease (
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;
}

View file

@ -93,7 +93,7 @@ Ext2FollowLink (
}
/* 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;
@ -871,6 +871,7 @@ McbExisting:
#ifndef __REACTOS__
LONG i = 0;
#endif
PathName = FileName;
Mcb = NULL;
@ -1388,6 +1389,7 @@ Openit:
//
// check the oplock state of the file
//
Status = FsRtlCheckOplock( &Fcb->Oplock,
IrpContext->Irp,
IrpContext,
@ -1895,8 +1897,13 @@ Ext2CreateInode(
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;

View file

@ -231,13 +231,16 @@ extern CHAR gDate[];
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 {
@ -289,51 +292,57 @@ Ext2ProcessGlobalProperty(
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) {
if (Property->Command == APP_CMD_SET_PROPERTY2 ||
Property->Command == APP_CMD_SET_PROPERTY3 ) {
case APP_CMD_SET_PROPERTY3:
RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN);
if ((Ext2Global->bHidingPrefix = Property->bHidingPrefix)) {
RtlCopyMemory( Ext2Global->sHidingPrefix,
Property->sHidingPrefix,
HIDINGPAT_LEN - 1);
}
RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN);
if ((Ext2Global->bHidingSuffix = Property->bHidingSuffix)) {
RtlCopyMemory( Ext2Global->sHidingSuffix,
Property->sHidingSuffix,
HIDINGPAT_LEN - 1);
}
}
if (Property->Command == APP_CMD_SET_PROPERTY3) {
PEXT2_VOLUME_PROPERTY3 Prop3 = (PEXT2_VOLUME_PROPERTY3)Property;
if (Prop3->Flags & EXT2_VPROP3_AUTOMOUNT) {
if (Prop3->AutoMount)
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 = Property2->bHidingPrefix)) {
RtlCopyMemory( Ext2Global->sHidingPrefix,
Property2->sHidingPrefix,
HIDINGPAT_LEN - 1);
}
RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN);
if ((Ext2Global->bHidingSuffix = Property2->bHidingSuffix)) {
RtlCopyMemory( Ext2Global->sHidingSuffix,
Property2->sHidingSuffix,
HIDINGPAT_LEN - 1);
}
case APP_CMD_SET_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);
}
}
PageTable = load_nls(Property->Codepage);
if (PageTable) {
memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
Ext2Global->Codepage.PageTable = PageTable;
}
break;
default:
break;
}
} _SEH2_FINALLY {
@ -350,13 +359,15 @@ Ext2ProcessGlobalProperty(
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 {
@ -364,7 +375,7 @@ Ext2ProcessVolumeProperty(
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;
@ -375,17 +386,67 @@ Ext2ProcessVolumeProperty(
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);
}
Ext2FlushFiles(NULL, Vcb, FALSE);
Ext2FlushVolume(NULL, Vcb, FALSE);
RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
if (Vcb->bHidingSuffix == Property2->bHidingSuffix) {
RtlCopyMemory( Vcb->sHidingSuffix,
Property2->sHidingSuffix,
HIDINGPAT_LEN - 1);
}
Vcb->DrvLetter = Property2->DrvLetter;
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 {
@ -418,30 +479,58 @@ Ext2ProcessVolumeProperty(
Ext2InitializeLabel(Vcb, Vcb->SuperBlock);
}
if (Property->Command == APP_CMD_SET_PROPERTY2) {
RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN);
if ((Vcb->bHidingPrefix = Property->bHidingPrefix) != 0) {
RtlCopyMemory( Vcb->sHidingPrefix,
Property->sHidingPrefix,
HIDINGPAT_LEN - 1);
}
RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
if ((Vcb->bHidingSuffix = Property->bHidingSuffix) != 0) {
RtlCopyMemory( Vcb->sHidingSuffix,
Property->sHidingSuffix,
HIDINGPAT_LEN - 1);
}
Vcb->DrvLetter = Property->DrvLetter;
}
break;
case APP_CMD_QUERY_PROPERTY:
case APP_CMD_QUERY_PROPERTY3:
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;
}
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;
if (Property2->bHidingPrefix == Vcb->bHidingPrefix) {
RtlCopyMemory( Property2->sHidingPrefix,
Vcb->sHidingPrefix,
HIDINGPAT_LEN);
} else {
RtlZeroMemory( Property2->sHidingPrefix,
HIDINGPAT_LEN);
}
if (Property2->bHidingSuffix == Vcb->bHidingSuffix) {
RtlCopyMemory( Property2->sHidingSuffix,
Vcb->sHidingSuffix,
HIDINGPAT_LEN);
} else {
RtlZeroMemory( Property2->sHidingSuffix,
HIDINGPAT_LEN);
}
case APP_CMD_QUERY_PROPERTY:
Property->bExt2 = TRUE;
Property->bExt3 = Vcb->IsExt3fs;
Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY);
@ -457,32 +546,6 @@ Ext2ProcessVolumeProperty(
} 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:
@ -503,7 +566,7 @@ Ext2ProcessVolumeProperty(
NTSTATUS
Ext2ProcessUserProperty(
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VOLUME_PROPERTY2 Property,
IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length
)
{

View file

@ -127,6 +127,27 @@ Ext2RefreshSuper (
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)
{
@ -134,34 +155,56 @@ 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;
}
@ -169,14 +212,26 @@ VOID
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
@ -592,7 +647,7 @@ Ext2NewBlock(
*Block = 0;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
/* validate the hint group and hint block */
if (GroupHint >= Vcb->sbi.s_groups_count) {
@ -762,7 +817,7 @@ Again:
errorout:
ExReleaseResourceLite(&Vcb->MetaLock);
ExReleaseResourceLite(&Vcb->MetaBlock);
if (bh)
fini_bh(&bh);
@ -799,7 +854,7 @@ Ext2FreeBlock(
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));
@ -916,7 +971,7 @@ errorout:
if (gb)
fini_bh(&gb);
ExReleaseResourceLite(&Vcb->MetaLock);
ExReleaseResourceLite(&Vcb->MetaBlock);
return Status;
}
@ -948,7 +1003,7 @@ Ext2NewInode(
*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;
@ -1088,7 +1143,7 @@ repeat:
break;
}
fini_bh(&gb);
fini_bh(&gb);
}
}
@ -1272,7 +1327,7 @@ repeat:
errorout:
ExReleaseResourceLite(&Vcb->MetaLock);
ExReleaseResourceLite(&Vcb->MetaInode);
if (bh)
fini_bh(&bh);
@ -1284,6 +1339,44 @@ errorout:
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,
@ -1308,7 +1401,7 @@ Ext2FreeInode(
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE);
ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
Group = (Inode - 1) / INODES_PER_GROUP;
dwIno = (Inode - 1) % INODES_PER_GROUP;
@ -1385,7 +1478,7 @@ Ext2FreeInode(
errorout:
ExReleaseResourceLite(&Vcb->MetaLock);
ExReleaseResourceLite(&Vcb->MetaInode);
if (bh)
fini_bh(&bh);
@ -1474,7 +1567,8 @@ Ext2SetFileType (
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;
@ -1507,15 +1601,21 @@ Ext2SetFileType (
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 {
@ -2134,27 +2234,30 @@ __u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
__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);
return cpu_to_le16(crc);
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);
}
int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
@ -2489,12 +2592,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
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;
@ -2507,44 +2608,33 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
return NULL;
}
smp_rmb();
group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
_SEH2_TRY {
if (!sbi->s_group_desc || !sbi->s_group_desc[group]) {
Ext2LoadGroup(vcb);
}
group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
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;
}
if (!sbi->s_gd || !sbi->s_gd[group].block ||
!sbi->s_gd[group].bh) {
if (!Ext2LoadGroup(vcb)) {
_SEH2_LEAVE;
}
}
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);
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
@ -2670,7 +2760,8 @@ int ext4_check_descriptors(struct super_block *sb)
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;

View file

@ -23,6 +23,7 @@
#pragma warning(disable: 4244)
#endif
/*
* used by extent splitting.
*/
@ -1098,6 +1099,77 @@ out:
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.
@ -1355,29 +1427,25 @@ found_extent:
* 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;
@ -1414,12 +1482,14 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path)
/*
* 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);
@ -1427,49 +1497,49 @@ static int ext4_ext_correct_indexes(void *icb, handle_t *handle, struct inode *i
__le32 border;
int k, err = 0;
eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (unlikely(ex == NULL || eh == NULL)) {
EXT4_ERROR_INODE(inode,
"ex %p == NULL or eh %p == NULL", ex, eh);
return -EIO;
}
if (depth == 0) {
/* there is no tree at all */
assert(at >= 0);
if (!at)
return 0;
}
if (ex != EXT_FIRST_EXTENT(eh)) {
/* we correct tree if first leaf got modified only */
return 0;
}
if (depth == at) {
eh = path[at].p_hdr;
ex = path[at].p_ext;
/*
* 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 == NULL || eh == NULL)
return -EIO;
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;
if (at == 0) {
/* there is no tree at all */
return 0;
}
if (ex != EXT_FIRST_EXTENT(eh)) {
/* we correct tree if first leaf got modified only */
return 0;
}
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;
@ -1844,9 +1914,11 @@ merge:
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;
@ -1880,158 +1952,353 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
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;
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) {
} else {
}
return 0;
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);
}
/*
* 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
*/
int ext4_ext_rm_idx(void *icb, handle_t *handle, struct inode *inode,
struct ext4_ext_path *path)
static int ext4_ext_remove_idx(void *icb,
handle_t *handle,
struct inode *inode,
struct ext4_ext_path *path,
int depth)
{
int err;
int err, i = depth;
ext4_fsblk_t leaf;
/* 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)))
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;
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);
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_rm_leaf(void *icb, handle_t *handle, struct inode *inode,
struct ext4_ext_path *path, unsigned long start)
static int ext4_ext_amalgamate(void *icb,
handle_t *handle,
struct inode *inode,
struct ext4_ext_path *path,
int at)
{
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;
struct ext4_extent *ex;
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;
/* 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);
now = ext4_ext_next_allocated_block(path, at - 1);
if (now == EXT_MAX_BLOCKS)
goto out;
/* 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);
}
/* 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;
}
/*handle = ext4_ext_journal_restart(icb, handle, credits);*/
/*if (IS_ERR(icb, handle)) {*/
/*err = PTR_ERR(icb, handle);*/
/*goto out;*/
/*}*/
err = ext4_ext_get_access(icb, handle, inode, path + depth);
if (err)
goto out;
err = ext4_remove_blocks(icb, handle, inode, ex, a, b);
if (err)
goto out;
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_block = cpu_to_le32(block);
ex->ee_len = cpu_to_le16(num);
err = ext4_ext_dirty(icb, handle, inode, path + depth);
if (err)
goto out;
ex--;
ex_ee_block = le32_to_cpu(ex->ee_block);
ex_ee_len = ext4_ext_get_actual_len(ex);
right_path = ext4_find_extent(inode, now, NULL, 0);
if (IS_ERR(right_path)) {
ret = PTR_ERR(right_path);
right_path = NULL;
goto out;
}
if (correct_index && eh->eh_entries)
err = ext4_ext_correct_indexes(icb, handle, inode, path);
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));
}
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);
/* 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);
/*
* 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;
}
/*
* NOTE: After removal, path should not be reused.
*/
int ext4_ext_remove_extent(void *icb,
handle_t *handle,
struct inode *inode, struct ext4_ext_path **path)
{
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);
return err;
}
int __ext4_ext_truncate(void *icb,
handle_t *handle,
struct inode *inode,
ext4_lblk_t from, ext4_lblk_t to)
{
int depth = ext_depth(inode), ret = -EIO;
struct ext4_extent *ex;
struct ext4_ext_path *path = NULL, *npath;
ext4_lblk_t now = from;
if (to < from)
return -EINVAL;
npath = ext4_find_extent(inode, from, &path, 0);
if (IS_ERR(npath))
goto out;
path = npath;
ex = path[depth].p_ext;
if (!ex)
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)) {
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);
ex->ee_len = cpu_to_le16(from - ee_block);
if (unwritten)
ext4_ext_mark_unwritten(ex);
ext4_ext_dirty(icb, handle, inode, path + depth);
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;
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;
}
}
now = ext4_ext_next_allocated_block(path, depth);
if (!new_len) {
ret = ext4_ext_remove_extent(icb, handle,
inode, &path);
if (ret)
goto out;
} 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:
if (path) {
ext4_ext_drop_refs(path);
kfree(path);
}
if (IS_ERR(npath))
ret = PTR_ERR(npath);
return ret;
}
/*
* ext4_split_extent_at() splits an extent at given block.
*
@ -2171,138 +2438,6 @@ fix_extent_len:
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;
@ -2441,7 +2576,7 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f
/* 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)
@ -2504,7 +2639,8 @@ out2:
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)

View file

@ -17,6 +17,9 @@ extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/
#define FASTIO_DEBUG_LEVEL DL_NVR
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Ext2FastIoRead)
@ -213,30 +216,34 @@ Ext2FastIoWrite (
_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();
@ -981,3 +988,137 @@ Ext2FastIoQueryNetworkOpenInfo (
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;
}

View file

@ -554,13 +554,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
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;
@ -596,6 +589,17 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
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) ||
@ -1289,8 +1293,9 @@ Ext2SetDispositionInfo(
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);
}

View file

@ -81,6 +81,9 @@ Ext2FlushVolume (
DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n"));
/* discard buffer_headers for group_desc */
Ext2DropGroup(Vcb);
ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
ExReleaseResourceLite(&Vcb->PagingIoResource);

View file

@ -1422,7 +1422,8 @@ Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
_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;
}
@ -1567,7 +1568,6 @@ out:
return Status;
}
NTSTATUS
Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
{
@ -1673,15 +1673,31 @@ 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 {
@ -1799,7 +1815,8 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
}
}
if (!Mcb) {
if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
!IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
Status = STATUS_NOT_A_REPARSE_POINT;
_SEH2_LEAVE;
}
@ -1825,15 +1842,9 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
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 {
@ -2702,6 +2713,9 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
FlushBeforePurge = FALSE;
}
/* discard buffer_headers for group_desc */
Ext2DropGroup(Vcb);
FcbListEntry= NULL;
InitializeListHead(&FcbList);

View file

@ -33,6 +33,7 @@ DriverEntry(
#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)
@ -99,36 +100,222 @@ DriverUnload (IN PDRIVER_OBJECT DriverObject)
#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
)
{
ULONG i = 0;
BYTE *s, *t;
if (NULL == ValueName || NULL == ValueData)
return STATUS_SUCCESS;
if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(WRITING_SUPPORT) &&
_wcsnicmp(ValueName, WRITING_SUPPORT, wcslen(WRITING_SUPPORT)) == 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) {
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) {
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 (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) {
RtlCopyMemory(&Ext2Global->wHidingSuffix[0],
ValueData, ValueLength);
}
}
return STATUS_SUCCESS;
}
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[i].DefaultType = REG_NONE;
QueryTable[i].DefaultLength = 0;
QueryTable[i].DefaultData = NULL;
QueryTable[i].EntryContext = NULL;
QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
i++;
/*
* 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++;
/*
* 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++;
/*
* 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++;
/*
* 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++;
/*
* 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++;
/*
* 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,
RegistryPath->Buffer,
&QueryTable[0],
NULL,
NULL
);
return NT_SUCCESS(Status);
}
BOOLEAN
Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING ParameterPath;
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
UNICODE_STRING UniName;
ANSI_STRING AnsiName;
ULONG WritingSupport = 0;
ULONG CheckingBitmap = 0;
ULONG Ext3ForceWriting = 0;
ULONG AutoMount = 0;
UNICODE_STRING UniName;
ANSI_STRING AnsiName;
WCHAR UniBuffer[CODEPAGE_MAXLEN];
USHORT Buffer[HIDINGPAT_LEN];
ParameterPath.Length = 0;
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"));
@ -138,101 +325,24 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
RtlCopyUnicodeString(&ParameterPath, RegistryPath);
RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY);
/* querying value of WritingSupport */
RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = WRITING_SUPPORT;
QueryTable[0].EntryContext = &WritingSupport;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParameterPath.Buffer,
&QueryTable[0],
NULL,
NULL );
DEBUG(DL_ERR, ( "Ext2QueryParameters: WritingSupport=%xh\n", WritingSupport));
/* 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;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParameterPath.Buffer,
&QueryTable[0],
NULL,
NULL );
DEBUG(DL_ERR, ( "Ext2QueryParameters: CheckingBitmap=%xh\n", CheckingBitmap));
/* 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;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParameterPath.Buffer,
&QueryTable[0],
NULL,
NULL );
DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext3ForceWriting=%xh\n", Ext3ForceWriting));
/* querying value of AutoMount */
RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = AUTO_MOUNT;
QueryTable[0].EntryContext = &AutoMount;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParameterPath.Buffer,
&QueryTable[0],
NULL,
NULL );
/* enable automount of ext2/3/4 volumes */
SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
if (NT_SUCCESS(Status) && AutoMount == 0) {
ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
}
DEBUG(DL_ERR, ( "Ext2QueryParameters: AutoMount=%xh\n", AutoMount));
/* query parameter settings from registry */
Ext2QueryGlobalParameters(&ParameterPath);
/* 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;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
ParameterPath.Buffer,
&QueryTable[0],
NULL,
NULL );
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);
@ -243,25 +353,13 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
}
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]);
@ -279,26 +377,12 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
}
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]);
@ -317,29 +401,6 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
}
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;
@ -360,6 +421,23 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
)
#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
@ -384,24 +462,12 @@ 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);
@ -454,12 +520,8 @@ DriverEntry (
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);
@ -494,21 +556,18 @@ DriverEntry (
}
/* 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;
}
@ -564,12 +623,16 @@ DriverEntry (
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;
//
@ -633,6 +696,19 @@ DriverEntry (
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
//

View file

@ -329,10 +329,16 @@ new_buffer_head()
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;
}
@ -344,13 +350,9 @@ free_buffer_head(struct buffer_head * 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) {
@ -360,6 +362,7 @@ free_buffer_head(struct buffer_head * bh)
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);
}
}
@ -436,7 +439,6 @@ get_block_bh_mdl(
PVOID bcb = NULL;
PVOID ptr = NULL;
KIRQL irql = 0;
struct list_head *entry;
/* allocate buffer_head and initialize it */
@ -449,15 +451,15 @@ get_block_bh_mdl(
}
/* 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) {
@ -467,8 +469,6 @@ get_block_bh_mdl(
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:
@ -499,13 +499,14 @@ 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);
@ -518,20 +519,21 @@ again:
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:
@ -602,7 +604,7 @@ errorout:
}
struct buffer_head *
get_block_bh(
get_block_bh_pin(
struct block_device * bdev,
sector_t block,
unsigned long size,
@ -612,7 +614,6 @@ get_block_bh(
PEXT2_VCB Vcb = bdev->bd_priv;
LARGE_INTEGER offset;
KIRQL irql = 0;
struct list_head *entry;
/* allocate buffer_head and initialize it */
@ -625,15 +626,15 @@ get_block_bh(
}
/* 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) {
@ -643,8 +644,6 @@ get_block_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:
@ -656,7 +655,7 @@ again:
&offset,
bh->b_size,
FALSE,
PIN_WAIT | PIN_EXCLUSIVE,
PIN_WAIT,
&bh->b_bcb,
(PVOID *)&bh->b_data)) {
Ext2Sleep(100);
@ -675,33 +674,34 @@ again:
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:
@ -709,7 +709,7 @@ 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;
@ -744,6 +744,43 @@ errorout:
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,
@ -758,7 +795,6 @@ void __brelse(struct buffer_head *bh)
{
struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv;
KIRQL irql = 0;
ASSERT(Vcb->Identifier.Type == EXT2VCB);
@ -767,20 +803,30 @@ void __brelse(struct buffer_head *bh)
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);
}
@ -863,10 +909,7 @@ void mark_buffer_dirty(struct buffer_head *bh)
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;
}

View file

@ -31,7 +31,8 @@ extern PEXT2_GLOBAL Ext2Global;
#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
@ -1404,7 +1405,7 @@ Ext2AllocateMcb (
/* 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 */
@ -1505,6 +1506,7 @@ Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
#ifndef __REACTOS__
PEXT2_MCB Parent = Mcb->Parent;
#endif
ASSERT(Mcb != NULL);
ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
@ -1839,6 +1841,7 @@ Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
return FALSE;
}
RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
if (RtlCheckBit(&bitmap, dwBlk) == 0) {
@ -1982,7 +1985,7 @@ errorout:
VOID
Ext2ParseRegistryVolumeParams(
IN PUNICODE_STRING Params,
OUT PEXT2_VOLUME_PROPERTY2 Property
OUT PEXT2_VOLUME_PROPERTY3 Property
)
{
WCHAR Codepage[CODEPAGE_MAXLEN];
@ -1990,11 +1993,15 @@ Ext2ParseRegistryVolumeParams(
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 */
@ -2020,6 +2027,11 @@ Ext2ParseRegistryVolumeParams(
{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}
};
@ -2032,9 +2044,9 @@ Ext2ParseRegistryVolumeParams(
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++) {
@ -2095,6 +2107,22 @@ Ext2ParseRegistryVolumeParams(
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
@ -2107,7 +2135,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
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));
@ -2141,7 +2169,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
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);
@ -2150,7 +2178,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
HIDINGPAT_LEN);
}
if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) {
if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
RtlCopyMemory( Vcb->sHidingSuffix,
Ext2Global->sHidingSuffix,
HIDINGPAT_LEN);
@ -2247,6 +2275,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
BOOLEAN NotifySyncInitialized = FALSE;
BOOLEAN ExtentsInitialized = FALSE;
BOOLEAN InodeLookasideInitialized = FALSE;
BOOLEAN GroupLoaded = FALSE;
_SEH2_TRY {
@ -2293,8 +2322,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* 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);
@ -2367,15 +2398,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* 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] +
@ -2471,7 +2494,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
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) {
@ -2600,6 +2626,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
Status = STATUS_UNSUCCESSFUL;
_SEH2_LEAVE;
}
GroupLoaded = TRUE;
/* recovery journal since it's ext3 */
if (Vcb->IsExt3fs) {
@ -2656,6 +2683,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* get anything doen, then refer target device */
ObReferenceObject(Vcb->TargetDeviceObject);
/* query parameters from registry */
Ext2PerformRegistryVolumeParams(Vcb);
SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
} _SEH2_FINALLY {
@ -2671,9 +2702,11 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
}
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));
}
@ -2690,7 +2723,9 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
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);
}
@ -2752,6 +2787,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
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);
@ -2770,7 +2806,9 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
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);
@ -2935,16 +2973,11 @@ Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
/* 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;
@ -2953,13 +2986,19 @@ Ext2ReaperThread(
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;
@ -3002,13 +3041,16 @@ Ext2ReaperThread(
/* 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 */
@ -3047,22 +3089,157 @@ Ext2ReaperThread(
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
);
@ -3083,13 +3260,45 @@ Ext2StartReaperThread()
&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);
}

View file

@ -582,7 +582,7 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
} else {
if (Nocache) {
if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject) {
if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource,
@ -592,14 +592,23 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
}
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 {

View file

@ -936,6 +936,11 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
} else {
if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) {
Status = STATUS_ACCESS_DENIED;
_SEH2_LEAVE;
}
if (IsDirectory(Fcb)) {
_SEH2_LEAVE;
}