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 bExt3Writable;
BOOLEAN bExt2; BOOLEAN bExt2;
BOOLEAN bExt3; BOOLEAN bExt3;
UCHAR Codepage[CODEPAGE_MAXLEN]; CHAR Codepage[CODEPAGE_MAXLEN];
} EXT2_VOLUME_PROPERTY; } EXT2_VOLUME_PROPERTY, *PEXT2_VOLUME_PROPERTY;
#ifdef __cplusplus #ifdef __cplusplus
typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY { typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY {
@ -196,14 +196,24 @@ typedef struct _EXT2_VOLUME_PROPERTY2 {
} EXT2_VOLUME_PROPERTY2, *PEXT2_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 { typedef struct _EXT2_VOLUME_PROPERTY3 {
EXT2_VOLUME_PROPERTY2 Prop2; EXT2_VOLUME_PROPERTY2 ;
unsigned __int64 Flags; #endif // __cplusplus
int AutoMount:1; unsigned __int64 Flags2;
int Reserved1:31; ULONG AutoMount:1;
int Reserved2[31]; ULONG EIDS:1;
ULONG Reserved1:30;
USHORT uid;
USHORT gid;
USHORT euid;
USHORT egid;
ULONG Reserved2[29];
} EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3; } EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3;
/* Ext2Fsd driver version and built time */ /* Ext2Fsd driver version and built time */

View file

@ -47,7 +47,7 @@
/* STRUCTS & CONSTS******************************************************/ /* STRUCTS & CONSTS******************************************************/
#define EXT2FSD_VERSION "0.63" #define EXT2FSD_VERSION "0.66"
/* WDK DEFINITIONS ******************************************************/ /* 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 CEILING_ALIGNED(T, A, B) (((A) + (B) - 1) & (~((T)(B) - 1)))
#define COCKLOFT_ALIGNED(T, A, B) (((A) + (B)) & (~((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 *************************************************/ /* File System Releated *************************************************/
#define DRIVER_NAME "Ext2Fsd" #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 HIDING_SUFFIX L"HidingSuffix"
#define AUTO_MOUNT L"AutoMount" #define AUTO_MOUNT L"AutoMount"
#define MOUNT_POINT L"MountPoint" #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" #define DOS_DEVICE_NAME L"\\DosDevices\\Ext2Fsd"
@ -464,6 +488,17 @@ typedef PVOID PBCB;
// Data that is not specific to a mounted volume // 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 { typedef struct _EXT2_GLOBAL {
/* Identifier for this structure */ /* Identifier for this structure */
@ -479,6 +514,9 @@ typedef struct _EXT2_GLOBAL {
/* Table of pointers to the fast I/O entry points */ /* Table of pointers to the fast I/O entry points */
FAST_IO_DISPATCH FastIoDispatch; FAST_IO_DISPATCH FastIoDispatch;
/* Filter callbacks */
FS_FILTER_CALLBACKS FilterCallbacks;
/* Table of pointers to the Cache Manager callbacks */ /* Table of pointers to the Cache Manager callbacks */
CACHE_MANAGER_CALLBACKS CacheManagerCallbacks; CACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks; CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks;
@ -496,10 +534,8 @@ typedef struct _EXT2_GLOBAL {
LIST_ENTRY VcbList; LIST_ENTRY VcbList;
/* Cleaning thread related: resource cleaner */ /* Cleaning thread related: resource cleaner */
struct { EXT2_REAPER McbReaper;
KEVENT Engine; EXT2_REAPER bhReaper;
KEVENT Wait;
} Reaper;
/* Look Aside table of IRP_CONTEXT, FCB, MCB, CCB */ /* Look Aside table of IRP_CONTEXT, FCB, MCB, CCB */
NPAGED_LOOKASIDE_LIST Ext2IrpContextLookasideList; NPAGED_LOOKASIDE_LIST Ext2IrpContextLookasideList;
@ -512,11 +548,14 @@ typedef struct _EXT2_GLOBAL {
/* User specified global codepage name */ /* User specified global codepage name */
struct { struct {
WCHAR PageName[CODEPAGE_MAXLEN];
UCHAR AnsiName[CODEPAGE_MAXLEN]; UCHAR AnsiName[CODEPAGE_MAXLEN];
struct nls_table * PageTable; struct nls_table * PageTable;
} Codepage; } Codepage;
/* global hiding patterns */ /* global hiding patterns */
WCHAR wHidingPrefix[HIDINGPAT_LEN];
WCHAR wHidingSuffix[HIDINGPAT_LEN];
BOOLEAN bHidingPrefix; BOOLEAN bHidingPrefix;
CHAR sHidingPrefix[HIDINGPAT_LEN]; CHAR sHidingPrefix[HIDINGPAT_LEN];
BOOLEAN bHidingSuffix; BOOLEAN bHidingSuffix;
@ -599,8 +638,11 @@ typedef struct _EXT2_VCB {
/* Common header */ /* Common header */
EXT2_FCBVCB; EXT2_FCBVCB;
// Resource for metadata (super block, tables) // Resource for metadata (inode)
ERESOURCE MetaLock; ERESOURCE MetaInode;
// Resource for metadata (block)
ERESOURCE MetaBlock;
// Resource for Mcb (Meta data control block) // Resource for Mcb (Meta data control block)
ERESOURCE McbLock; ERESOURCE McbLock;
@ -669,12 +711,6 @@ typedef struct _EXT2_VCB {
BOOLEAN IsExt3fs; BOOLEAN IsExt3fs;
PEXT2_SUPER_BLOCK SuperBlock; PEXT2_SUPER_BLOCK SuperBlock;
/*
// Bitmap Block per group
PRTL_BITMAP BlockBitMaps;
PRTL_BITMAP InodeBitMaps;
*/
// Block / Cluster size // Block / Cluster size
ULONG BlockSize; ULONG BlockSize;
@ -745,6 +781,7 @@ typedef struct _EXT2_VCB {
#define VCB_USER_IDS 0x00000040 /* uid/gid specified by user */ #define VCB_USER_IDS 0x00000040 /* uid/gid specified by user */
#define VCB_USER_EIDS 0x00000080 /* euid/egid 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_FORCE_WRITING 0x00004000
#define VCB_DEVICE_REMOVED 0x00008000 #define VCB_DEVICE_REMOVED 0x00008000
#define VCB_JOURNAL_RECOVER 0x00080000 #define VCB_JOURNAL_RECOVER 0x00080000
@ -1148,7 +1185,6 @@ int Ext2CheckFileAccess (PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt);
PMDL PMDL
Ext2CreateMdl ( Ext2CreateMdl (
IN PVOID Buffer, IN PVOID Buffer,
IN BOOLEAN bPaged,
IN ULONG Length, IN ULONG Length,
IN LOCK_OPERATION Operation IN LOCK_OPERATION Operation
); );
@ -1255,44 +1291,6 @@ Ext2NoOpAcquire (
VOID NTAPI VOID NTAPI
Ext2NoOpRelease (IN PVOID Fcb); 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 // Create.c
// //
@ -1482,21 +1480,21 @@ Ext2FreePool(
NTSTATUS NTSTATUS
Ext2ProcessGlobalProperty( Ext2ProcessGlobalProperty(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length IN ULONG Length
); );
NTSTATUS NTSTATUS
Ext2ProcessVolumeProperty( Ext2ProcessVolumeProperty(
IN PEXT2_VCB Vcb, IN PEXT2_VCB Vcb,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length IN ULONG Length
); );
NTSTATUS NTSTATUS
Ext2ProcessUserProperty( Ext2ProcessUserProperty(
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length IN ULONG Length
); );
@ -1911,6 +1909,13 @@ Ext2NewInode(
OUT PULONG Inode OUT PULONG Inode
); );
NTSTATUS
Ext2UpdateGroupDirStat(
IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb,
IN ULONG Group
);
NTSTATUS NTSTATUS
Ext2FreeInode( Ext2FreeInode(
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
@ -1934,7 +1939,8 @@ Ext2SetFileType (
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb, IN PEXT2_VCB Vcb,
IN PEXT2_FCB Dcb, IN PEXT2_FCB Dcb,
IN PEXT2_MCB Mcb IN PEXT2_MCB Mcb,
IN umode_t mode
); );
NTSTATUS NTSTATUS
@ -2110,6 +2116,56 @@ Ext2FastIoQueryNetworkOpenInfo (
OUT PIO_STATUS_BLOCK IoStatus, OUT PIO_STATUS_BLOCK IoStatus,
IN PDEVICE_OBJECT DeviceObject); 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 // FileInfo.c
@ -2402,8 +2458,10 @@ int ext3_is_dir_empty(struct ext2_icb *icb, struct inode *inode);
// Init.c // Init.c
// //
NTSTATUS
Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath);
BOOLEAN BOOLEAN
Ext2QueryGlobalParameters (IN PUNICODE_STRING RegistryPath); Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath);
VOID NTAPI VOID NTAPI
DriverUnload (IN PDRIVER_OBJECT DriverObject); DriverUnload (IN PDRIVER_OBJECT DriverObject);
@ -2465,6 +2523,19 @@ Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext);
// Memory.c // Memory.c
// //
VOID
NTAPI
Ext2McbReaperThread(
PVOID Context
);
VOID
NTAPI
Ext2bhReaperThread(
PVOID Context
);
PEXT2_IRP_CONTEXT PEXT2_IRP_CONTEXT
Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject, Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp ); IN PIRP Irp );
@ -2769,7 +2840,10 @@ Ext2ReaperThread(
); );
NTSTATUS NTSTATUS
Ext2StartReaperThread(); Ext2StartReaper(PEXT2_REAPER, EXT2_REAPER_RELEASE);
VOID
NTAPI
Ext2StopReaper(PEXT2_REAPER Reaper);
// //
// Misc.c // Misc.c
@ -2948,6 +3022,7 @@ Ext2WriteInode (
OUT PULONG dwReturn OUT PULONG dwReturn
); );
VOID VOID
Ext2StartFloppyFlushDpc ( Ext2StartFloppyFlushDpc (
PEXT2_VCB Vcb, PEXT2_VCB Vcb,

View file

@ -8,7 +8,7 @@
// //
typedef struct { typedef struct {
volatile int counter; volatile LONG counter;
} atomic_t; } atomic_t;
#define ATOMIC_INIT(i) (i) #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); 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 * 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 { 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_desc_size; /* size of group desc */
unsigned long s_gdb_count; /* Number of group descriptor blocks */ unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */ 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_addr_per_block_bits;
int s_desc_per_block_bits; int s_desc_per_block_bits;
ext3_fsblk_t *s_group_desc;
#if 0 #if 0
unsigned long s_frag_size; /* Size of a fragment in bytes */ 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 */ PFILE_OBJECT bd_volume; /* streaming object file */
LARGE_MCB bd_extents; /* dirty extents */ LARGE_MCB bd_extents; /* dirty extents */
spinlock_t bd_bh_lock; /**/ kmem_cache_t * bd_bh_cache;/* memory cache for buffer_head */
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 */ 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). * for backward compatibility reasons (e.g. submit_bh).
*/ */
struct buffer_head { struct buffer_head {
LIST_ENTRY b_link; /* to be added to reaper list */
unsigned long b_state; /* buffer state bitmap (see above) */ unsigned long b_state; /* buffer state bitmap (see above) */
struct page *b_page; /* the page this bh is mapped to */ struct page *b_page; /* the page this bh is mapped to */
PMDL b_mdl; /* MDL of the locked buffer */ 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 list_head b_assoc_buffers; /* associated with another mapping */
// struct address_space *b_assoc_map; /* mapping this buffer is associated with */ // struct address_space *b_assoc_map; /* mapping this buffer is associated with */
atomic_t b_count; /* users using this buffer_head */ 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 PMDL
Ext2CreateMdl ( Ext2CreateMdl (
IN PVOID Buffer, IN PVOID Buffer,
IN BOOLEAN bPaged,
IN ULONG Length, IN ULONG Length,
IN LOCK_OPERATION Operation IN LOCK_OPERATION op
) )
{ {
NTSTATUS Status; NTSTATUS Status;
@ -65,10 +64,10 @@ Ext2CreateMdl (
Status = STATUS_INSUFFICIENT_RESOURCES; Status = STATUS_INSUFFICIENT_RESOURCES;
} else { } else {
_SEH2_TRY { _SEH2_TRY {
if (bPaged) { if (MmIsNonPagedSystemAddressValid(Buffer)) {
MmProbeAndLockPages(Mdl, KernelMode, Operation); MmBuildMdlForNonPagedPool(Mdl);
} else { } else {
MmBuildMdlForNonPagedPool (Mdl); MmProbeAndLockPages(Mdl, KernelMode, op);
} }
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
@ -89,6 +88,7 @@ Ext2DestroyMdl (IN PMDL Mdl)
while (Mdl) { while (Mdl) {
PMDL Next; PMDL Next;
Next = Mdl->Next; Next = Mdl->Next;
Mdl->Next = NULL;
if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) { if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) {
MmUnlockPages (Mdl); MmUnlockPages (Mdl);
} }

View file

@ -33,6 +33,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN VcbResourceAcquired = FALSE;
BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbResourceAcquired = FALSE;
BOOLEAN FcbPagingIoResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE;
BOOLEAN SymLinkDelete = FALSE;
_SEH2_TRY { _SEH2_TRY {
@ -198,7 +199,11 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
} }
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { 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
//
// if (FcbResourceAcquired) {
// Ext2DeleteFile will acquire these lock inside ExReleaseResourceLite(&Fcb->MainResource);
// FcbResourceAcquired = FALSE;
}
if (FcbResourceAcquired) { //
ExReleaseResourceLite(&Fcb->MainResource); // this file is to be deleted ...
FcbResourceAcquired = FALSE; //
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 ... // re-acquire the main resource lock
// //
if (Ccb->SymLink) {
Mcb = Ccb->SymLink;
FileObject->DeletePending = FALSE;
}
Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); FcbResourceAcquired =
ExAcquireResourceExclusiveLite(
if (NT_SUCCESS(Status)) { &Fcb->MainResource,
if (IsMcbDirectory(Mcb)) { TRUE
Ext2NotifyReportChange( IrpContext, Vcb, Mcb, );
FILE_NOTIFY_CHANGE_DIR_NAME, if (!SymLinkDelete) {
FILE_ACTION_REMOVED ); SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
} 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);
if (CcIsFileCached(FileObject)) { if (CcIsFileCached(FileObject)) {
CcSetFileSizes(FileObject, CcSetFileSizes(FileObject,
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));

View file

@ -38,8 +38,7 @@ Ext2AcquireForLazyWrite (
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n", DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n",
Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb)); Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb));
#endif #endif
if (!ExAcquireResourceSharedLite( if (!ExAcquireResourceExclusiveLite(Fcb->Header.Resource, Wait)) {
&Fcb->PagingIoResource, Wait)) {
return FALSE; return FALSE;
} }
@ -47,7 +46,6 @@ Ext2AcquireForLazyWrite (
Fcb->LazyWriterThread = PsGetCurrentThread(); Fcb->LazyWriterThread = PsGetCurrentThread();
ASSERT(IoGetTopLevelIrp() == NULL); ASSERT(IoGetTopLevelIrp() == NULL);
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
return TRUE; return TRUE;
@ -59,9 +57,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context)
// //
// On a readonly filesystem this function still has to exist but it // On a readonly filesystem this function still has to exist but it
// doesn't need to do anything. // doesn't need to do anything.
PEXT2_FCB Fcb; PEXT2_FCB Fcb = (PEXT2_FCB) Context;
Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL); ASSERT(Fcb != NULL);
@ -74,7 +70,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context)
ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread()); ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread());
Fcb->LazyWriterThread = NULL; Fcb->LazyWriterThread = NULL;
ExReleaseResourceLite(&Fcb->PagingIoResource); ExReleaseResourceLite(Fcb->Header.Resource);
ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
IoSetTopLevelIrp( NULL ); IoSetTopLevelIrp( NULL );
@ -84,24 +80,18 @@ BOOLEAN NTAPI
Ext2AcquireForReadAhead (IN PVOID Context, Ext2AcquireForReadAhead (IN PVOID Context,
IN BOOLEAN Wait) IN BOOLEAN Wait)
{ {
PEXT2_FCB Fcb; PEXT2_FCB Fcb = (PEXT2_FCB) Context;
Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL); ASSERT(Fcb != NULL);
ASSERT((Fcb->Identifier.Type == EXT2FCB) && ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
(Fcb->Identifier.Size == sizeof(EXT2_FCB))); (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n", DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n",
Fcb->Mcb->Inode.i_ino, Fcb)); Fcb->Mcb->Inode.i_ino, Fcb));
if (!ExAcquireResourceSharedLite( if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait))
&Fcb->MainResource, Wait ))
return FALSE; return FALSE;
ASSERT(IoGetTopLevelIrp() == NULL); ASSERT(IoGetTopLevelIrp() == NULL);
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
return TRUE; return TRUE;
@ -110,9 +100,7 @@ Ext2AcquireForReadAhead (IN PVOID Context,
VOID NTAPI VOID NTAPI
Ext2ReleaseFromReadAhead (IN PVOID Context) Ext2ReleaseFromReadAhead (IN PVOID Context)
{ {
PEXT2_FCB Fcb; PEXT2_FCB Fcb = (PEXT2_FCB) Context;
Fcb = (PEXT2_FCB) Context;
ASSERT(Fcb != NULL); ASSERT(Fcb != NULL);
@ -122,9 +110,8 @@ Ext2ReleaseFromReadAhead (IN PVOID Context)
DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n", DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n",
Fcb->Mcb->Inode.i_ino, Fcb)); Fcb->Mcb->Inode.i_ino, Fcb));
IoSetTopLevelIrp( NULL ); IoSetTopLevelIrp(NULL);
ExReleaseResourceLite(Fcb->Header.Resource);
ExReleaseResourceLite(&Fcb->MainResource);
} }
BOOLEAN NTAPI BOOLEAN NTAPI
@ -149,120 +136,3 @@ Ext2NoOpRelease (
return; 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 */ /* 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.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]);
OemName.Length = (USHORT)Mcb->Inode.i_size; OemName.Length = (USHORT)Mcb->Inode.i_size;
@ -871,6 +871,7 @@ McbExisting:
#ifndef __REACTOS__ #ifndef __REACTOS__
LONG i = 0; LONG i = 0;
#endif #endif
PathName = FileName; PathName = FileName;
Mcb = NULL; Mcb = NULL;
@ -1388,6 +1389,7 @@ Openit:
// //
// check the oplock state of the file // check the oplock state of the file
// //
Status = FsRtlCheckOplock( &Fcb->Oplock, Status = FsRtlCheckOplock( &Fcb->Oplock,
IrpContext->Irp, IrpContext->Irp,
IrpContext, IrpContext,
@ -1895,8 +1897,13 @@ Ext2CreateInode(
Inode.i_ino = iNo; Inode.i_ino = iNo;
Inode.i_ctime = Inode.i_mtime = Inode.i_ctime = Inode.i_mtime =
Inode.i_atime = Ext2LinuxTime(SysTime); Inode.i_atime = Ext2LinuxTime(SysTime);
Inode.i_uid = Vcb->uid; if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) {
Inode.i_gid = Vcb->gid; 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_generation = Parent->Inode->i_generation;
Inode.i_mode = S_IPERMISSION_MASK & Inode.i_mode = S_IPERMISSION_MASK &
Parent->Inode->i_mode; Parent->Inode->i_mode;

View file

@ -231,13 +231,16 @@ extern CHAR gDate[];
NTSTATUS NTSTATUS
Ext2ProcessGlobalProperty( Ext2ProcessGlobalProperty(
IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_OBJECT DeviceObject,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property3,
IN ULONG Length IN ULONG Length
) )
{ {
PEXT2_VOLUME_PROPERTY3 Property2 = (PVOID)Property3;
PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3;
struct nls_table * PageTable = NULL;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN GlobalDataResourceAcquired = FALSE; BOOLEAN GlobalDataResourceAcquired = FALSE;
struct nls_table * PageTable = NULL;
_SEH2_TRY { _SEH2_TRY {
@ -289,51 +292,57 @@ Ext2ProcessGlobalProperty(
ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE); ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
GlobalDataResourceAcquired = 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); switch (Property->Command) {
if (PageTable) {
memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN);
Ext2Global->Codepage.PageTable = PageTable;
}
if (Property->Command == APP_CMD_SET_PROPERTY2 || case APP_CMD_SET_PROPERTY3:
Property->Command == APP_CMD_SET_PROPERTY3 ) {
RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN); if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) {
if ((Ext2Global->bHidingPrefix = Property->bHidingPrefix)) { if (Property3->AutoMount)
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)
SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
else else
ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); 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 { } _SEH2_FINALLY {
@ -350,13 +359,15 @@ Ext2ProcessGlobalProperty(
NTSTATUS NTSTATUS
Ext2ProcessVolumeProperty( Ext2ProcessVolumeProperty(
IN PEXT2_VCB Vcb, IN PEXT2_VCB Vcb,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property3,
IN ULONG Length IN ULONG Length
) )
{ {
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN VcbResourceAcquired = FALSE;
struct nls_table * PageTable = NULL; 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 { _SEH2_TRY {
@ -364,7 +375,7 @@ Ext2ProcessVolumeProperty(
VcbResourceAcquired = TRUE; VcbResourceAcquired = TRUE;
if (Property->Command == APP_CMD_SET_PROPERTY || 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)) { if (Length < sizeof(EXT2_VOLUME_PROPERTY)) {
Status = STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE; _SEH2_LEAVE;
@ -375,17 +386,67 @@ Ext2ProcessVolumeProperty(
Status = STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER;
_SEH2_LEAVE; _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) { 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: 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); RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN);
Ext2FlushVolume(NULL, Vcb, FALSE); 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); SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
} else { } else {
@ -418,30 +479,58 @@ Ext2ProcessVolumeProperty(
Ext2InitializeLabel(Vcb, Vcb->SuperBlock); 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; 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: 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->bExt2 = TRUE;
Property->bExt3 = Vcb->IsExt3fs; Property->bExt3 = Vcb->IsExt3fs;
Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY); Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY);
@ -457,32 +546,6 @@ Ext2ProcessVolumeProperty(
} else { } else {
strncpy(Property->Codepage, "default", CODEPAGE_MAXLEN); 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; break;
default: default:
@ -503,7 +566,7 @@ Ext2ProcessVolumeProperty(
NTSTATUS NTSTATUS
Ext2ProcessUserProperty( Ext2ProcessUserProperty(
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VOLUME_PROPERTY2 Property, IN PEXT2_VOLUME_PROPERTY3 Property,
IN ULONG Length IN ULONG Length
) )
{ {

View file

@ -127,6 +127,27 @@ Ext2RefreshSuper (
return TRUE; 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 BOOLEAN
Ext2LoadGroup(IN PEXT2_VCB Vcb) Ext2LoadGroup(IN PEXT2_VCB Vcb)
{ {
@ -134,34 +155,56 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb)
struct ext3_sb_info *sbi = &Vcb->sbi; struct ext3_sb_info *sbi = &Vcb->sbi;
ext3_fsblk_t sb_block = 1; ext3_fsblk_t sb_block = 1;
unsigned long i; unsigned long i;
BOOLEAN rc = FALSE;
if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) { _SEH2_TRY {
sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
}
if (NULL == sbi->s_group_desc) { ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
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;
}
for (i = 0; i < sbi->s_gdb_count; i++) { if (NULL == sbi->s_gd) {
sbi->s_group_desc[i] = descriptor_loc(sb, sb_block, i); sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
if (!sbi->s_group_desc[i]) { GFP_KERNEL);
DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i)); }
return FALSE; if (sbi->s_gd == NULL) {
DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
_SEH2_LEAVE;
} }
}
if (!ext4_check_descriptors(sb)) { if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n")); sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
return FALSE; }
}
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) Ext2DropGroup(IN PEXT2_VCB Vcb)
{ {
struct ext3_sb_info *sbi = &Vcb->sbi; struct ext3_sb_info *sbi = &Vcb->sbi;
LARGE_INTEGER timeout;
unsigned long i; unsigned long i;
if (NULL == sbi->s_group_desc) { /* do nothing if Vcb is not initialized yet */
if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
return; return;
}
kfree(sbi->s_group_desc); _SEH2_TRY {
sbi->s_group_desc = NULL; 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 BOOLEAN
@ -592,7 +647,7 @@ Ext2NewBlock(
*Block = 0; *Block = 0;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
/* validate the hint group and hint block */ /* validate the hint group and hint block */
if (GroupHint >= Vcb->sbi.s_groups_count) { if (GroupHint >= Vcb->sbi.s_groups_count) {
@ -762,7 +817,7 @@ Again:
errorout: errorout:
ExReleaseResourceLite(&Vcb->MetaLock); ExReleaseResourceLite(&Vcb->MetaBlock);
if (bh) if (bh)
fini_bh(&bh); fini_bh(&bh);
@ -799,7 +854,7 @@ Ext2FreeBlock(
NTSTATUS Status = STATUS_UNSUCCESSFUL; NTSTATUS Status = STATUS_UNSUCCESSFUL;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n", DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
Block, Block + Number)); Block, Block + Number));
@ -916,7 +971,7 @@ errorout:
if (gb) if (gb)
fini_bh(&gb); fini_bh(&gb);
ExReleaseResourceLite(&Vcb->MetaLock); ExReleaseResourceLite(&Vcb->MetaBlock);
return Status; return Status;
} }
@ -948,7 +1003,7 @@ Ext2NewInode(
*Inode = dwInode = 0XFFFFFFFF; *Inode = dwInode = 0XFFFFFFFF;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
if (GroupHint >= Vcb->sbi.s_groups_count) if (GroupHint >= Vcb->sbi.s_groups_count)
GroupHint = GroupHint % Vcb->sbi.s_groups_count; GroupHint = GroupHint % Vcb->sbi.s_groups_count;
@ -1088,7 +1143,7 @@ repeat:
break; break;
} }
fini_bh(&gb); fini_bh(&gb);
} }
} }
@ -1272,7 +1327,7 @@ repeat:
errorout: errorout:
ExReleaseResourceLite(&Vcb->MetaLock); ExReleaseResourceLite(&Vcb->MetaInode);
if (bh) if (bh)
fini_bh(&bh); fini_bh(&bh);
@ -1284,6 +1339,44 @@ errorout:
return Status; 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 NTSTATUS
Ext2FreeInode( Ext2FreeInode(
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
@ -1308,7 +1401,7 @@ Ext2FreeInode(
NTSTATUS Status = STATUS_UNSUCCESSFUL; NTSTATUS Status = STATUS_UNSUCCESSFUL;
ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
Group = (Inode - 1) / INODES_PER_GROUP; Group = (Inode - 1) / INODES_PER_GROUP;
dwIno = (Inode - 1) % INODES_PER_GROUP; dwIno = (Inode - 1) % INODES_PER_GROUP;
@ -1385,7 +1478,7 @@ Ext2FreeInode(
errorout: errorout:
ExReleaseResourceLite(&Vcb->MetaLock); ExReleaseResourceLite(&Vcb->MetaInode);
if (bh) if (bh)
fini_bh(&bh); fini_bh(&bh);
@ -1474,7 +1567,8 @@ Ext2SetFileType (
IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_IRP_CONTEXT IrpContext,
IN PEXT2_VCB Vcb, IN PEXT2_VCB Vcb,
IN PEXT2_FCB Dcb, IN PEXT2_FCB Dcb,
IN PEXT2_MCB Mcb IN PEXT2_MCB Mcb,
IN umode_t mode
) )
{ {
struct inode *dir = Dcb->Inode; struct inode *dir = Dcb->Inode;
@ -1507,15 +1601,21 @@ Ext2SetFileType (
if (le32_to_cpu(de->inode) != inode->i_ino) if (le32_to_cpu(de->inode) != inode->i_ino)
_SEH2_LEAVE; _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); 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); dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
ext3_mark_inode_dirty(IrpContext, dir); ext3_mark_inode_dirty(IrpContext, dir);
inode->i_mode = mode;
ext3_mark_inode_dirty(IrpContext, inode);
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} _SEH2_FINALLY { } _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, __le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
struct ext4_group_desc *gdp) 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 & /* old crc16 code */
cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { if (!(sbi->s_es->s_feature_ro_compat &
int offset = offsetof(struct ext4_group_desc, bg_checksum); cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
__le32 le_group = cpu_to_le32(block_group); return 0;
crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); offset = offsetof(struct ext4_group_desc, bg_checksum);
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); 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, 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) ext4_group_t block_group, struct buffer_head **bh)
{ {
struct ext4_group_desc *desc = NULL; struct ext4_group_desc *desc = NULL;
struct buffer_head *gb = NULL;
struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_sb_info *sbi = EXT3_SB(sb);
PEXT2_VCB vcb = sb->s_priv; PEXT2_VCB vcb = sb->s_priv;
ext4_group_t group;
unsigned int group; ext4_group_t offset;
unsigned int offset;
if (bh) if (bh)
*bh = NULL; *bh = NULL;
@ -2507,44 +2608,33 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
return NULL; return NULL;
} }
smp_rmb();
group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); _SEH2_TRY {
offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
if (!sbi->s_group_desc || !sbi->s_group_desc[group]) { group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
Ext2LoadGroup(vcb); offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
}
if (!sbi->s_group_desc[group]) { if (!sbi->s_gd || !sbi->s_gd[group].block ||
ext4_error(sb, "ext4_get_group_desc", !sbi->s_gd[group].bh) {
"Group descriptor not loaded - " if (!Ext2LoadGroup(vcb)) {
"block_group = %u, group = %u, desc = %u", _SEH2_LEAVE;
block_group, group, offset); }
goto errorout; }
}
gb = sb_getblk(sb, sbi->s_group_desc[group]); desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
if (!gb) { offset * EXT4_DESC_SIZE(sb));
ext4_error(sb, "ext4_get_group_desc", if (bh) {
"failed to load group - " atomic_inc(&sbi->s_gd[group].bh->b_count);
"block_group = %u, group = %u, desc = %u", *bh = sbi->s_gd[group].bh;
block_group, group, offset); }
goto errorout; } _SEH2_FINALLY {
} /* do cleanup */
} _SEH2_END;
desc = (struct ext4_group_desc *)(gb->b_data +
offset * EXT4_DESC_SIZE(sb));
if (bh)
*bh = gb;
else
fini_bh(&gb);
errorout:
return desc; return desc;
} }
/** /**
* ext4_count_free_blocks() -- count filesystem free blocks * ext4_count_free_blocks() -- count filesystem free blocks
* @sb: superblock * @sb: superblock
@ -2670,7 +2760,8 @@ int ext4_check_descriptors(struct super_block *sb)
printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
"Checksum for group %u failed (%u!=%u)\n", "Checksum for group %u failed (%u!=%u)\n",
i, le16_to_cpu(ext4_group_desc_csum(sbi, i, 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)) { if (!IsVcbReadOnly(Vcb)) {
__brelse(bh); __brelse(bh);
return 0; return 0;

View file

@ -23,6 +23,7 @@
#pragma warning(disable: 4244) #pragma warning(disable: 4244)
#endif #endif
/* /*
* used by extent splitting. * used by extent splitting.
*/ */
@ -1098,6 +1099,77 @@ out:
return err; 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: * ext4_ext_create_new_leaf:
* finds empty index and adds new leaf. * finds empty index and adds new leaf.
@ -1355,29 +1427,25 @@ found_extent:
* with leaves. * with leaves.
*/ */
ext4_lblk_t 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; if (at == 0 && !path->p_ext && !path->p_idx)
depth = path->p_depth;
if (depth == 0 && path->p_ext == NULL)
return EXT_MAX_BLOCKS; return EXT_MAX_BLOCKS;
while (depth >= 0) { while (at >= 0) {
if (depth == path->p_depth) { if (at == path->p_depth) {
/* leaf */ /* leaf */
if (path[depth].p_ext && if (path[at].p_ext &&
path[depth].p_ext != path[at].p_ext !=
EXT_LAST_EXTENT(path[depth].p_hdr)) EXT_LAST_EXTENT(path[at].p_hdr))
return le32_to_cpu(path[depth].p_ext[1].ee_block); return le32_to_cpu(path[at].p_ext[1].ee_block);
} else { } else {
/* index */ /* index */
if (path[depth].p_idx != if (path[at].p_idx !=
EXT_LAST_INDEX(path[depth].p_hdr)) EXT_LAST_INDEX(path[at].p_hdr))
return le32_to_cpu(path[depth].p_idx[1].ei_block); return le32_to_cpu(path[at].p_idx[1].ei_block);
} }
depth--; at--;
} }
return EXT_MAX_BLOCKS; 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: * 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. * 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, static int ext4_ext_correct_indexes(void *icb, handle_t *handle,
struct ext4_ext_path *path) struct inode *inode,
struct ext4_ext_path *path,
int at)
{ {
struct ext4_extent_header *eh; struct ext4_extent_header *eh;
int depth = ext_depth(inode); 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; __le32 border;
int k, err = 0; int k, err = 0;
eh = path[depth].p_hdr; assert(at >= 0);
ex = path[depth].p_ext; if (!at)
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 */
return 0; return 0;
}
if (ex != EXT_FIRST_EXTENT(eh)) { if (depth == at) {
/* we correct tree if first leaf got modified only */ eh = path[at].p_hdr;
return 0; ex = path[at].p_ext;
}
/* if (ex == NULL || eh == NULL)
* TODO: we need correction if border is smaller than current one return -EIO;
*/
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;
while (k--) { if (at == 0) {
/* change all left-side indexes */ /* there is no tree at all */
if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr)) return 0;
break; }
err = ext4_ext_get_access(icb, handle, inode, path + k);
if (err) if (ex != EXT_FIRST_EXTENT(eh)) {
break; /* 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; path[k].p_idx->ei_block = border;
err = ext4_ext_dirty(icb, handle, inode, path + k); err = ext4_ext_dirty(icb, handle, inode, path + k);
if (err) 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; 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; return err;
@ -1844,9 +1914,11 @@ merge:
if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO))
ext4_ext_try_to_merge(icb, handle, inode, path, nearex); ext4_ext_try_to_merge(icb, handle, inode, path, nearex);
depth = ext_depth(inode);
/* time to correct all indexes above */ /* 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) if (err)
goto cleanup; goto cleanup;
@ -1880,158 +1952,353 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
return ret; return ret;
} }
static int ext4_remove_blocks(void *icb, handle_t *handle, struct inode *inode, static void ext4_ext_remove_blocks(
struct ext4_extent *ex, void *icb,
unsigned long from, unsigned long to) handle_t *handle,
struct inode *inode, struct ext4_extent *ex,
ext4_lblk_t from, ext4_lblk_t to)
{ {
struct buffer_head *bh; int len = to - from + 1;
int i; ext4_lblk_t num;
ext4_fsblk_t start;
if (from >= le32_to_cpu(ex->ee_block) num = from - le32_to_cpu(ex->ee_block);
&& to == le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) { start = ext4_ext_pblock(ex) + num;
/* tail removal */ ext_debug("Freeing %lu at %I64u, %d\n", from, start, len);
unsigned long num, start; ext4_free_blocks(icb, handle, inode, NULL,
num = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - from; start, len, 0);
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;
} }
/* static int ext4_ext_remove_idx(void *icb,
* routine removes index from the index block handle_t *handle,
* it's used in truncate case only. thus all requests are for struct inode *inode,
* last index in the block only struct ext4_ext_path *path,
*/ int depth)
int ext4_ext_rm_idx(void *icb, handle_t *handle, struct inode *inode,
struct ext4_ext_path *path)
{ {
int err; int err, i = depth;
ext4_fsblk_t leaf; ext4_fsblk_t leaf;
/* free index block */ /* free index block */
path--; leaf = ext4_idx_pblock(path[i].p_idx);
leaf = ext4_idx_pblock(path->p_idx);
BUG_ON(path->p_hdr->eh_entries == 0); if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) {
if ((err = ext4_ext_get_access(icb, handle, inode, path))) 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; 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))) ext_debug("IDX: Freeing %lu at %I64u, %d\n",
return err; le32_to_cpu(path[i].p_idx->ei_block), leaf, 1);
ext4_free_blocks(icb, handle, inode, NULL, leaf, 1, 0); ext4_free_blocks(icb, handle, inode, NULL,
leaf, 1, 0);
return err; return err;
} }
static int static int ext4_ext_amalgamate(void *icb,
ext4_ext_rm_leaf(void *icb, handle_t *handle, struct inode *inode, handle_t *handle,
struct ext4_ext_path *path, unsigned long start) struct inode *inode,
struct ext4_ext_path *path,
int at)
{ {
int err = 0, correct_index = 0; int new_entries, right_entries;
int depth = ext_depth(inode), credits; int depth = ext_depth(inode);
struct ext4_extent_header *eh; struct ext4_ext_path *right_path = NULL;
unsigned a, b, block, num; ext4_lblk_t now;
unsigned long ex_ee_block; int ret = 0;
unsigned short ex_ee_len; if (!at)
struct ext4_extent *ex; return 0;
/* the header must be checked already in ext4_ext_remove_space() */ now = ext4_ext_next_allocated_block(path, at - 1);
if (!path[depth].p_hdr) if (now == EXT_MAX_BLOCKS)
path[depth].p_hdr = ext_block_hdr(path[depth].p_bh); goto out;
eh = path[depth].p_hdr;
BUG_ON(eh == NULL);
/* find where to start removing */ right_path = ext4_find_extent(inode, now, NULL, 0);
ex = EXT_LAST_EXTENT(eh); if (IS_ERR(right_path)) {
ret = PTR_ERR(right_path);
ex_ee_block = le32_to_cpu(ex->ee_block); right_path = NULL;
ex_ee_len = ext4_ext_get_actual_len(ex); goto out;
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);
} }
if (correct_index && eh->eh_entries) right_entries = le16_to_cpu(right_path[at].p_hdr->eh_entries);
err = ext4_ext_correct_indexes(icb, handle, inode, path); 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 */ * remove the empty node 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); 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: 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; 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. * ext4_split_extent_at() splits an extent at given block.
* *
@ -2171,138 +2438,6 @@ fix_extent_len:
return err; 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) int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode)
{ {
struct ext4_extent_header *eh; 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 /* find next allocated block so that we know how many
* blocks we can allocate without ovelapping next extent */ * 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); BUG_ON(next <= iblock);
allocated = next - iblock; allocated = next - iblock;
if (flags & EXT4_GET_BLOCKS_PRE_IO && max_blocks > EXT_UNWRITTEN_MAX_LEN) 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 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. */ /* Save modifications on i_blocks field of the inode. */
if (!ret) if (!ret)

View file

@ -17,6 +17,9 @@ extern PEXT2_GLOBAL Ext2Global;
/* DEFINITIONS *************************************************************/ /* DEFINITIONS *************************************************************/
#define FASTIO_DEBUG_LEVEL DL_NVR
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, Ext2FastIoRead) #pragma alloc_text(PAGE, Ext2FastIoRead)
@ -213,30 +216,34 @@ Ext2FastIoWrite (
_SEH2_LEAVE; _SEH2_LEAVE;
} }
if (ExAcquireResourceExclusiveLite(&Fcb->MainResource, Wait)) if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait)) {
Locked = TRUE;
else
_SEH2_LEAVE; _SEH2_LEAVE;
}
Locked = TRUE;
if (IsWritingToEof(*FileOffset) || if (IsWritingToEof(*FileOffset) ||
Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length ||
Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) { Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) {
Status = FALSE; Status = FALSE;
_SEH2_LEAVE; _SEH2_LEAVE;
} }
if (Locked) {
ExReleaseResourceLite(Fcb->Header.Resource);
Locked = FALSE;
}
Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait,
LockKey, Buffer, IoStatus, DeviceObject); LockKey, Buffer, IoStatus, DeviceObject);
if (Status) { if (Status) {
if (IoStatus) if (IoStatus)
Length = (ULONG)IoStatus->Information; Length = (ULONG)IoStatus->Information;
if (Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length)
Fcb->Header.ValidDataLength.QuadPart = FileOffset->QuadPart + Length;
} }
} _SEH2_FINALLY { } _SEH2_FINALLY {
if (Locked) { if (Locked) {
ExReleaseResourceLite(&Fcb->MainResource); ExReleaseResourceLite(Fcb->Header.Resource);
} }
FsRtlExitFileSystem(); FsRtlExitFileSystem();
@ -981,3 +988,137 @@ Ext2FastIoQueryNetworkOpenInfo (
return bResult; 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; VcbMainResourceAcquired = TRUE;
} }
if (IsVcbReadOnly(Vcb)) {
if (FileInformationClass != FilePositionInformation) {
Status = STATUS_MEDIA_WRITE_PROTECTED;
_SEH2_LEAVE;
}
}
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
Status = STATUS_ACCESS_DENIED; Status = STATUS_ACCESS_DENIED;
_SEH2_LEAVE; _SEH2_LEAVE;
@ -596,6 +589,17 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
Mcb = Fcb->Mcb; 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) && if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
((FileInformationClass == FileEndOfFileInformation) || ((FileInformationClass == FileEndOfFileInformation) ||
(FileInformationClass == FileValidDataLengthInformation) || (FileInformationClass == FileValidDataLengthInformation) ||
@ -1289,8 +1293,9 @@ Ext2SetDispositionInfo(
DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n", DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n",
&Mcb->FullName)); &Mcb->FullName));
/* always allow deleting on symlinks */ if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
if (Ccb->SymLink == NULL) { /* always allow deleting on symlinks */
} else {
status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb); status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb);
} }

View file

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

View file

@ -1422,7 +1422,8 @@ Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
_SEH2_TRY { _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; Status = STATUS_NOT_A_REPARSE_POINT;
_SEH2_LEAVE; _SEH2_LEAVE;
} }
@ -1567,7 +1568,6 @@ out:
return Status; return Status;
} }
NTSTATUS NTSTATUS
Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) 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 */ /* overwrite inode mode as type SYMLINK */
Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT); SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer, Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
OemNameLength, &BytesWritten); OemNameLength, &BytesWritten);
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb); Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
S_IFLNK | S_IRWXUGO);
} }
} _SEH2_FINALLY { } _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; Status = STATUS_NOT_A_REPARSE_POINT;
_SEH2_LEAVE; _SEH2_LEAVE;
} }
@ -1825,15 +1842,9 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
_SEH2_LEAVE; _SEH2_LEAVE;
} }
if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL); /* inode is to be removed */
} SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
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);
}
} _SEH2_FINALLY { } _SEH2_FINALLY {
@ -2702,6 +2713,9 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb,
FlushBeforePurge = FALSE; FlushBeforePurge = FALSE;
} }
/* discard buffer_headers for group_desc */
Ext2DropGroup(Vcb);
FcbListEntry= NULL; FcbListEntry= NULL;
InitializeListHead(&FcbList); InitializeListHead(&FcbList);

View file

@ -33,6 +33,7 @@ DriverEntry(
#ifdef ALLOC_PRAGMA #ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, Ext2QueryGlobalParameters) #pragma alloc_text(INIT, Ext2QueryGlobalParameters)
#pragma alloc_text(INIT, Ext2QueryRegistrySettings)
#pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(INIT, DriverEntry)
#if EXT2_UNLOAD #if EXT2_UNLOAD
#pragma alloc_text(PAGE, DriverUnload) #pragma alloc_text(PAGE, DriverUnload)
@ -99,36 +100,222 @@ DriverUnload (IN PDRIVER_OBJECT DriverObject)
#endif #endif
BOOLEAN NTSTATUS NTAPI
Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) 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; 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; UNICODE_STRING ParameterPath;
RTL_QUERY_REGISTRY_TABLE QueryTable[2]; UNICODE_STRING UniName;
ANSI_STRING AnsiName;
ULONG WritingSupport = 0; ULONG WritingSupport = 0;
ULONG CheckingBitmap = 0; ULONG CheckingBitmap = 0;
ULONG Ext3ForceWriting = 0; ULONG Ext3ForceWriting = 0;
ULONG AutoMount = 0; ULONG AutoMount = 0;
UNICODE_STRING UniName;
ANSI_STRING AnsiName;
WCHAR UniBuffer[CODEPAGE_MAXLEN]; WCHAR UniBuffer[CODEPAGE_MAXLEN];
USHORT Buffer[HIDINGPAT_LEN]; USHORT Buffer[HIDINGPAT_LEN];
ParameterPath.Length = 0; NTSTATUS Status;
ParameterPath.Length = 0;
ParameterPath.MaximumLength = ParameterPath.MaximumLength =
RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR); RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR);
ParameterPath.Buffer = ParameterPath.Buffer =
(PWSTR) Ext2AllocatePool( (PWSTR) Ext2AllocatePool(
PagedPool, PagedPool,
ParameterPath.MaximumLength, ParameterPath.MaximumLength,
'LG2E' 'LG2E'
); );
if (!ParameterPath.Buffer) { if (!ParameterPath.Buffer) {
DbgBreak(); DbgBreak();
DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n")); DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n"));
@ -138,101 +325,24 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
RtlCopyUnicodeString(&ParameterPath, RegistryPath); RtlCopyUnicodeString(&ParameterPath, RegistryPath);
RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY); RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY);
/* querying value of WritingSupport */ /* enable automount of ext2/3/4 volumes */
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 );
SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); 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 */ /* set global codepage settings */
RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); if (wcslen(&Ext2Global->Codepage.PageName[0])) {
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->Codepage.PageName[0]);
QueryTable[0].Name = CODEPAGE_NAME; UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR);
QueryTable[0].EntryContext = &(UniName); UniName.Buffer = &Ext2Global->Codepage.PageName[0];
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));
AnsiName.MaximumLength = CODEPAGE_MAXLEN; AnsiName.MaximumLength = CODEPAGE_MAXLEN;
AnsiName.Length = 0; AnsiName.Length = 0;
AnsiName.Buffer = &(Ext2Global->Codepage.AnsiName[0]); AnsiName.Buffer = &Ext2Global->Codepage.AnsiName[0];
Status = RtlUnicodeStringToAnsiString( Status = RtlUnicodeStringToAnsiString(
&AnsiName, &AnsiName,
&UniName, &UniName,
FALSE); FALSE);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName)); DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName));
RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8);
@ -243,25 +353,13 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
} }
Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0; 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( /* set global hidden prefix pattern */
RTL_REGISTRY_ABSOLUTE, if (wcslen(&Ext2Global->wHidingPrefix[0])) {
ParameterPath.Buffer, UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingPrefix[0]);
&QueryTable[0], UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
NULL, UniName.Buffer = &Ext2Global->wHidingPrefix[0];
NULL ); AnsiName.MaximumLength = HIDINGPAT_LEN;
if (NT_SUCCESS(Status)) {
DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix=%wZ\n", &UniName));
AnsiName.MaximumLength =HIDINGPAT_LEN;
AnsiName.Length = 0; AnsiName.Length = 0;
AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]); AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]);
@ -279,26 +377,12 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
} }
Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
/* querying name hiding patterns: suffix */
RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].Name = HIDING_SUFFIX;
QueryTable[0].EntryContext = &(UniName);
UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
UniName.Length = 0;
UniName.Buffer = Buffer;
Status = RtlQueryRegistryValues( /* set global hidden suffix pattern */
RTL_REGISTRY_ABSOLUTE, if (wcslen(&Ext2Global->wHidingSuffix[0])) {
ParameterPath.Buffer, UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingSuffix[0]);
&QueryTable[0], UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
NULL, UniName.Buffer = &Ext2Global->wHidingSuffix[0];
NULL
);
if (NT_SUCCESS(Status)) {
DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix=%wZ\n", &UniName));
AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.MaximumLength = HIDINGPAT_LEN;
AnsiName.Length = 0; AnsiName.Length = 0;
AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]); AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]);
@ -317,29 +401,6 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
} }
Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
{
if (WritingSupport) {
SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
} else {
ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
}
if (CheckingBitmap) {
SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
} else {
ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
}
if (Ext3ForceWriting) {
DEBUG(DL_WRN, ("Ext2Fsd -- Warning: Ext3ForceWriting enabled !!!\n"));
SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
} else {
ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
}
}
Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer; Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer;
Ext2Global->RegistryPath.Length = 0; Ext2Global->RegistryPath.Length = 0;
Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength; Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength;
@ -360,6 +421,23 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath)
) )
#endif #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 * NAME: DriverEntry
@ -384,24 +462,12 @@ DriverEntry (
PFAST_IO_DISPATCH FastIoDispatch; PFAST_IO_DISPATCH FastIoDispatch;
PCACHE_MANAGER_CALLBACKS CacheManagerCallbacks; PCACHE_MANAGER_CALLBACKS CacheManagerCallbacks;
LARGE_INTEGER Timeout;
NTSTATUS Status; NTSTATUS Status;
int rc = 0; int rc = 0;
BOOLEAN linux_lib_inited = FALSE; BOOLEAN linux_lib_inited = FALSE;
BOOLEAN journal_module_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 ... */ /* Verity super block ... */
ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024); ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024);
ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56); ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56);
@ -454,12 +520,8 @@ DriverEntry (
InitializeListHead(&(Ext2Global->VcbList)); InitializeListHead(&(Ext2Global->VcbList));
ExInitializeResourceLite(&(Ext2Global->Resource)); ExInitializeResourceLite(&(Ext2Global->Resource));
/* Reaper thread engine event */
KeInitializeEvent(&Ext2Global->Reaper.Engine,
SynchronizationEvent, FALSE);
/* query registry settings */ /* query registry settings */
Ext2QueryGlobalParameters(RegistryPath); Ext2QueryRegistrySettings(RegistryPath);
/* create Ext2Fsd cdrom fs deivce */ /* create Ext2Fsd cdrom fs deivce */
RtlInitUnicodeString(&DeviceName, CDROM_NAME); RtlInitUnicodeString(&DeviceName, CDROM_NAME);
@ -494,21 +556,18 @@ DriverEntry (
} }
/* start resource reaper thread */ /* start resource reaper thread */
Status= Ext2StartReaperThread(); Status= Ext2StartReaper(
&Ext2Global->McbReaper,
Ext2McbReaperThread);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
goto errorout; goto errorout;
} }
/* make sure Reaperthread is started */
Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */ Status= Ext2StartReaper(
Status = KeWaitForSingleObject( &Ext2Global->bhReaper,
&(Ext2Global->Reaper.Engine), Ext2bhReaperThread);
Executive, if (!NT_SUCCESS(Status)) {
KernelMode, Ext2StopReaper(&Ext2Global->McbReaper);
FALSE,
&Timeout
);
if (Status != STATUS_SUCCESS) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto errorout; goto errorout;
} }
@ -564,12 +623,16 @@ DriverEntry (
FastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; FastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll;
FastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; FastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey;
FastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetworkOpenInfo; FastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetworkOpenInfo;
FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite;
FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite;
FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite; FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite;
FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite; FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite;
FastIoDispatch->AcquireForCcFlush = Ext2AcquireFileForCcFlush; FastIoDispatch->AcquireForCcFlush = Ext2AcquireFileForCcFlush;
FastIoDispatch->ReleaseForCcFlush = Ext2ReleaseFileForCcFlush; FastIoDispatch->ReleaseForCcFlush = Ext2ReleaseFileForCcFlush;
FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection; FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection;
FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection; FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection;
DriverObject->FastIoDispatch = FastIoDispatch; DriverObject->FastIoDispatch = FastIoDispatch;
// //
@ -633,6 +696,19 @@ DriverEntry (
Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead = Ext2NoOpAcquire; Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead = Ext2NoOpAcquire;
Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = Ext2NoOpRelease; 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 // Initialize the global data
// //

View file

@ -329,10 +329,16 @@ new_buffer_head()
struct buffer_head * bh = NULL; struct buffer_head * bh = NULL;
bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS); bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS);
if (bh) { if (bh) {
atomic_inc(&g_jbh.bh_count);
atomic_inc(&g_jbh.bh_acount);
memset(bh, 0, sizeof(struct buffer_head)); memset(bh, 0, sizeof(struct buffer_head));
InitializeListHead(&bh->b_link);
KeQuerySystemTime(&bh->b_ts_creat);
DEBUG(DL_BH, ("bh=%p allocated.\n", bh)); DEBUG(DL_BH, ("bh=%p allocated.\n", bh));
INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
} }
return bh; 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, 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)); bh->b_mdl->MdlFlags, bh->b_mdl->MappedSystemVa));
if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_PAGES_LOCKED)) { if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) {
/* MmUnlockPages will release it's VA */
MmUnlockPages(bh->b_mdl);
} else if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) {
MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl); MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl);
} }
Ext2DestroyMdl(bh->b_mdl); Ext2DestroyMdl(bh->b_mdl);
} }
if (bh->b_bcb) { if (bh->b_bcb) {
@ -360,6 +362,7 @@ free_buffer_head(struct buffer_head * bh)
DEBUG(DL_BH, ("bh=%p freed.\n", bh)); DEBUG(DL_BH, ("bh=%p freed.\n", bh));
DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head));
kmem_cache_free(g_jbh.bh_cache, bh); 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 bcb = NULL;
PVOID ptr = NULL; PVOID ptr = NULL;
KIRQL irql = 0;
struct list_head *entry; struct list_head *entry;
/* allocate buffer_head and initialize it */ /* allocate buffer_head and initialize it */
@ -449,15 +451,15 @@ get_block_bh_mdl(
} }
/* search the bdev bh list */ /* 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); tbh = buffer_head_search(bdev, block);
if (tbh) { if (tbh) {
bh = tbh; bh = tbh;
get_bh(bh); get_bh(bh);
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
goto errorout; goto errorout;
} }
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head(); bh = new_buffer_head();
if (!bh) { if (!bh) {
@ -467,8 +469,6 @@ get_block_bh_mdl(
bh->b_blocknr = block; bh->b_blocknr = block;
bh->b_size = size; bh->b_size = size;
bh->b_data = NULL; bh->b_data = NULL;
atomic_inc(&g_jbh.bh_count);
atomic_inc(&g_jbh.bh_acount);
again: again:
@ -499,13 +499,14 @@ again:
set_buffer_uptodate(bh); 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) { if (bh->b_mdl) {
/* muse map the PTE to NonCached zone. journal recovery will /* muse map the PTE to NonCached zone. journal recovery will
access the PTE under spinlock: DISPATCH_LEVEL IRQL */ access the PTE under spinlock: DISPATCH_LEVEL IRQL */
bh->b_data = MmMapLockedPagesSpecifyCache( bh->b_data = MmMapLockedPagesSpecifyCache(
bh->b_mdl, KernelMode, MmNonCached, bh->b_mdl, KernelMode, MmNonCached,
NULL,FALSE, HighPagePriority); NULL,FALSE, HighPagePriority);
/* bh->b_data = MmMapLockedPages(bh->b_mdl, KernelMode); */
} }
if (!bh->b_mdl || !bh->b_data) { if (!bh->b_mdl || !bh->b_data) {
free_buffer_head(bh); 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", 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)); 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 */ /* do search again here */
tbh = buffer_head_search(bdev, block); tbh = buffer_head_search(bdev, block);
if (tbh) { if (tbh) {
free_buffer_head(bh); free_buffer_head(bh);
bh = tbh; bh = tbh;
get_bh(bh); 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; goto errorout;
} else } else {
buffer_head_insert(bdev, bh); buffer_head_insert(bdev, bh);
}
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
/* we get it */ /* we get it */
errorout: errorout:
@ -602,7 +604,7 @@ errorout:
} }
struct buffer_head * struct buffer_head *
get_block_bh( get_block_bh_pin(
struct block_device * bdev, struct block_device * bdev,
sector_t block, sector_t block,
unsigned long size, unsigned long size,
@ -612,7 +614,6 @@ get_block_bh(
PEXT2_VCB Vcb = bdev->bd_priv; PEXT2_VCB Vcb = bdev->bd_priv;
LARGE_INTEGER offset; LARGE_INTEGER offset;
KIRQL irql = 0;
struct list_head *entry; struct list_head *entry;
/* allocate buffer_head and initialize it */ /* allocate buffer_head and initialize it */
@ -625,15 +626,15 @@ get_block_bh(
} }
/* search the bdev bh list */ /* 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); tbh = buffer_head_search(bdev, block);
if (tbh) { if (tbh) {
bh = tbh; bh = tbh;
get_bh(bh); get_bh(bh);
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
goto errorout; goto errorout;
} }
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
bh = new_buffer_head(); bh = new_buffer_head();
if (!bh) { if (!bh) {
@ -643,8 +644,6 @@ get_block_bh(
bh->b_blocknr = block; bh->b_blocknr = block;
bh->b_size = size; bh->b_size = size;
bh->b_data = NULL; bh->b_data = NULL;
atomic_inc(&g_jbh.bh_count);
atomic_inc(&g_jbh.bh_acount);
again: again:
@ -656,7 +655,7 @@ again:
&offset, &offset,
bh->b_size, bh->b_size,
FALSE, FALSE,
PIN_WAIT | PIN_EXCLUSIVE, PIN_WAIT,
&bh->b_bcb, &bh->b_bcb,
(PVOID *)&bh->b_data)) { (PVOID *)&bh->b_data)) {
Ext2Sleep(100); Ext2Sleep(100);
@ -675,33 +674,34 @@ again:
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
} }
if (bh->b_bcb)
CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3));
if (!bh->b_data) { if (!bh->b_data) {
free_buffer_head(bh); free_buffer_head(bh);
bh = NULL; bh = NULL;
goto errorout; goto errorout;
} }
get_bh(bh); 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", 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)); 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 */ /* do search again here */
tbh = buffer_head_search(bdev, block); tbh = buffer_head_search(bdev, block);
if (tbh) { if (tbh) {
get_bh(tbh); get_bh(tbh);
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); ExReleaseResourceLite(&bdev->bd_bh_lock);
free_buffer_head(bh); free_buffer_head(bh);
bh = tbh; bh = tbh;
RemoveEntryList(&bh->b_link);
InitializeListHead(&bh->b_link);
goto errorout; goto errorout;
} else { } else {
buffer_head_insert(bdev, bh); buffer_head_insert(bdev, bh);
} }
ExReleaseResourceLite(&bdev->bd_bh_lock);
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql);
/* we get it */ /* we get it */
errorout: errorout:
@ -709,7 +709,7 @@ errorout:
return bh; 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; struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = bdev->bd_priv; PEXT2_VCB Vcb = bdev->bd_priv;
@ -744,6 +744,43 @@ errorout:
return 0; 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 * struct buffer_head *
__getblk( __getblk(
struct block_device * bdev, struct block_device * bdev,
@ -758,7 +795,6 @@ void __brelse(struct buffer_head *bh)
{ {
struct block_device *bdev = bh->b_bdev; struct block_device *bdev = bh->b_bdev;
PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv; PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv;
KIRQL irql = 0;
ASSERT(Vcb->Identifier.Type == EXT2VCB); ASSERT(Vcb->Identifier.Type == EXT2VCB);
@ -767,20 +803,30 @@ void __brelse(struct buffer_head *bh)
ll_rw_block(WRITE, 1, &bh); ll_rw_block(WRITE, 1, &bh);
} }
spin_lock_irqsave(&bdev->bd_bh_lock, irql); if (1 == atomic_read(&bh->b_count)) {
if (!atomic_dec_and_test(&bh->b_count)) { } else if (atomic_dec_and_test(&bh->b_count)) {
spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); 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; return;
} }
buffer_head_remove(bdev, bh); 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", 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, atomic_read(&g_jbh.bh_count) - 1, bh->b_size,
bh->b_blocknr, bh, bh->b_data )); 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) int sync_blockdev(struct block_device *bdev)
{ {
PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv; PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv;
Ext2FlushVolume(NULL, Vcb, FALSE);
if (0 == atomic_read(&g_jbh.bh_count)) {
Ext2FlushVolume(NULL, Vcb, FALSE);
}
return 0; return 0;
} }

View file

@ -31,7 +31,8 @@ extern PEXT2_GLOBAL Ext2Global;
#pragma alloc_text(PAGE, Ext2DestroyVcb) #pragma alloc_text(PAGE, Ext2DestroyVcb)
#pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap) #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
#pragma alloc_text(PAGE, Ext2ReaperThread) #pragma alloc_text(PAGE, Ext2ReaperThread)
#pragma alloc_text(PAGE, Ext2StartReaperThread) #pragma alloc_text(PAGE, Ext2StartReaper)
#pragma alloc_text(PAGE, Ext2StopReaper)
#endif #endif
PEXT2_IRP_CONTEXT PEXT2_IRP_CONTEXT
@ -1404,7 +1405,7 @@ Ext2AllocateMcb (
/* need wake the reaper thread if there are many Mcb allocated */ /* need wake the reaper thread if there are many Mcb allocated */
if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) { 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 */ /* allocate Mcb from LookasideList */
@ -1505,6 +1506,7 @@ Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
#ifndef __REACTOS__ #ifndef __REACTOS__
PEXT2_MCB Parent = Mcb->Parent; PEXT2_MCB Parent = Mcb->Parent;
#endif #endif
ASSERT(Mcb != NULL); ASSERT(Mcb != NULL);
ASSERT((Mcb->Identifier.Type == EXT2MCB) && ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
@ -1839,6 +1841,7 @@ Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
return FALSE; return FALSE;
} }
RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length); RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
if (RtlCheckBit(&bitmap, dwBlk) == 0) { if (RtlCheckBit(&bitmap, dwBlk) == 0) {
@ -1982,7 +1985,7 @@ errorout:
VOID VOID
Ext2ParseRegistryVolumeParams( Ext2ParseRegistryVolumeParams(
IN PUNICODE_STRING Params, IN PUNICODE_STRING Params,
OUT PEXT2_VOLUME_PROPERTY2 Property OUT PEXT2_VOLUME_PROPERTY3 Property
) )
{ {
WCHAR Codepage[CODEPAGE_MAXLEN]; WCHAR Codepage[CODEPAGE_MAXLEN];
@ -1990,11 +1993,15 @@ Ext2ParseRegistryVolumeParams(
WCHAR Suffix[HIDINGPAT_LEN]; WCHAR Suffix[HIDINGPAT_LEN];
USHORT MountPoint[4]; USHORT MountPoint[4];
UCHAR DrvLetter[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, BOOLEAN bWriteSupport = FALSE,
bCheckBitmap = FALSE, bCheckBitmap = FALSE,
bCodeName = FALSE, bCodeName = FALSE,
bMountPoint = FALSE; bMountPoint = FALSE;
BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
struct { struct {
PWCHAR Name; /* parameters name */ PWCHAR Name; /* parameters name */
PBOOLEAN bExist; /* is it contained in params */ PBOOLEAN bExist; /* is it contained in params */
@ -2020,6 +2027,11 @@ Ext2ParseRegistryVolumeParams(
{MOUNT_POINT, &bMountPoint, 4, {MOUNT_POINT, &bMountPoint, 4,
&MountPoint[0], &DrvLetter[0]}, &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 */ /* end */
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
@ -2032,9 +2044,9 @@ Ext2ParseRegistryVolumeParams(
RtlZeroMemory(MountPoint, sizeof(USHORT) * 4); RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
RtlZeroMemory(DrvLetter, sizeof(CHAR) * 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->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++) { for (i=0; ParamPattern[i].Name != NULL; i++) {
@ -2095,6 +2107,22 @@ Ext2ParseRegistryVolumeParams(
Property->DrvLetter = DrvLetter[0]; Property->DrvLetter = DrvLetter[0];
Property->DrvLetter |= 0x80; 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 NTSTATUS
@ -2107,7 +2135,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
/* set Vcb settings from registery */ /* set Vcb settings from registery */
EXT2_VOLUME_PROPERTY2 Property; EXT2_VOLUME_PROPERTY3 Property;
Ext2ParseRegistryVolumeParams(&VolumeParams, &Property); Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property)); Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
@ -2141,7 +2169,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN); memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable; Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) { if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) {
RtlCopyMemory( Vcb->sHidingPrefix, RtlCopyMemory( Vcb->sHidingPrefix,
Ext2Global->sHidingPrefix, Ext2Global->sHidingPrefix,
HIDINGPAT_LEN); HIDINGPAT_LEN);
@ -2150,7 +2178,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
HIDINGPAT_LEN); HIDINGPAT_LEN);
} }
if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) { if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) {
RtlCopyMemory( Vcb->sHidingSuffix, RtlCopyMemory( Vcb->sHidingSuffix,
Ext2Global->sHidingSuffix, Ext2Global->sHidingSuffix,
HIDINGPAT_LEN); HIDINGPAT_LEN);
@ -2247,6 +2275,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
BOOLEAN NotifySyncInitialized = FALSE; BOOLEAN NotifySyncInitialized = FALSE;
BOOLEAN ExtentsInitialized = FALSE; BOOLEAN ExtentsInitialized = FALSE;
BOOLEAN InodeLookasideInitialized = FALSE; BOOLEAN InodeLookasideInitialized = FALSE;
BOOLEAN GroupLoaded = FALSE;
_SEH2_TRY { _SEH2_TRY {
@ -2293,8 +2322,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* initialize eresources */ /* initialize eresources */
ExInitializeResourceLite(&Vcb->MainResource); ExInitializeResourceLite(&Vcb->MainResource);
ExInitializeResourceLite(&Vcb->PagingIoResource); ExInitializeResourceLite(&Vcb->PagingIoResource);
ExInitializeResourceLite(&Vcb->MetaLock); ExInitializeResourceLite(&Vcb->MetaInode);
ExInitializeResourceLite(&Vcb->MetaBlock);
ExInitializeResourceLite(&Vcb->McbLock); ExInitializeResourceLite(&Vcb->McbLock);
ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
#ifndef _WIN2K_TARGET_ #ifndef _WIN2K_TARGET_
ExInitializeFastMutex(&Vcb->Mutex); ExInitializeFastMutex(&Vcb->Mutex);
FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex); FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
@ -2367,15 +2398,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* initialize UUID and serial number */ /* initialize UUID and serial number */
if (Ext2IsNullUuid(sb->s_uuid)) { if (Ext2IsNullUuid(sb->s_uuid)) {
ExUuidCreate((UUID *)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] + Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
((ULONG*)sb->s_uuid)[1] + ((ULONG*)sb->s_uuid)[1] +
((ULONG*)sb->s_uuid)[2] + ((ULONG*)sb->s_uuid)[2] +
@ -2471,7 +2494,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
Vcb->bd.bd_volume = Vcb->Volume; Vcb->bd.bd_volume = Vcb->Volume;
Vcb->bd.bd_priv = (void *) Vcb; Vcb->bd.bd_priv = (void *) Vcb;
memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root)); 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->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
Vcb->BlockSize, 0, 0, NULL); Vcb->BlockSize, 0, 0, NULL);
if (!Vcb->bd.bd_bh_cache) { if (!Vcb->bd.bd_bh_cache) {
@ -2600,6 +2626,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
Status = STATUS_UNSUCCESSFUL; Status = STATUS_UNSUCCESSFUL;
_SEH2_LEAVE; _SEH2_LEAVE;
} }
GroupLoaded = TRUE;
/* recovery journal since it's ext3 */ /* recovery journal since it's ext3 */
if (Vcb->IsExt3fs) { if (Vcb->IsExt3fs) {
@ -2656,6 +2683,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
/* get anything doen, then refer target device */ /* get anything doen, then refer target device */
ObReferenceObject(Vcb->TargetDeviceObject); ObReferenceObject(Vcb->TargetDeviceObject);
/* query parameters from registry */
Ext2PerformRegistryVolumeParams(Vcb);
SetLongFlag(Vcb->Flags, VCB_INITIALIZED); SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
} _SEH2_FINALLY { } _SEH2_FINALLY {
@ -2671,9 +2702,11 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
} }
if (ExtentsInitialized) { 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); kmem_cache_destroy(Vcb->bd.bd_bh_cache);
}
FsRtlUninitializeLargeMcb(&(Vcb->Extents)); FsRtlUninitializeLargeMcb(&(Vcb->Extents));
} }
@ -2690,7 +2723,9 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
if (VcbResourceInitialized) { if (VcbResourceInitialized) {
ExDeleteResourceLite(&Vcb->McbLock); ExDeleteResourceLite(&Vcb->McbLock);
ExDeleteResourceLite(&Vcb->MetaLock); ExDeleteResourceLite(&Vcb->MetaInode);
ExDeleteResourceLite(&Vcb->MetaBlock);
ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->MainResource); ExDeleteResourceLite(&Vcb->MainResource);
ExDeleteResourceLite(&Vcb->PagingIoResource); ExDeleteResourceLite(&Vcb->PagingIoResource);
} }
@ -2752,6 +2787,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
if (Vcb->bd.bd_bh_cache) if (Vcb->bd.bd_bh_cache)
kmem_cache_destroy(Vcb->bd.bd_bh_cache); kmem_cache_destroy(Vcb->bd.bd_bh_cache);
ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
if (Vcb->SuperBlock) { if (Vcb->SuperBlock) {
Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC); Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
@ -2770,7 +2806,9 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb)
ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList)); ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
ExDeleteResourceLite(&Vcb->McbLock); ExDeleteResourceLite(&Vcb->McbLock);
ExDeleteResourceLite(&Vcb->MetaLock); ExDeleteResourceLite(&Vcb->MetaInode);
ExDeleteResourceLite(&Vcb->MetaBlock);
ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
ExDeleteResourceLite(&Vcb->PagingIoResource); ExDeleteResourceLite(&Vcb->PagingIoResource);
ExDeleteResourceLite(&Vcb->MainResource); ExDeleteResourceLite(&Vcb->MainResource);
@ -2935,16 +2973,11 @@ Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
/* Reaper thread to release unused Mcb blocks */ /* Reaper thread to release unused Mcb blocks */
VOID NTAPI VOID NTAPI
Ext2ReaperThread( Ext2McbReaperThread(
PVOID Context PVOID Context
) )
{ {
BOOLEAN GlobalAcquired = FALSE; PEXT2_REAPER Reaper = Context;
BOOLEAN DidNothing = TRUE;
BOOLEAN LastState = TRUE;
BOOLEAN WaitLock;
PLIST_ENTRY List = NULL; PLIST_ENTRY List = NULL;
LARGE_INTEGER Timeout; LARGE_INTEGER Timeout;
@ -2953,13 +2986,19 @@ Ext2ReaperThread(
ULONG i, NumOfMcbs; ULONG i, NumOfMcbs;
BOOLEAN GlobalAcquired = FALSE;
BOOLEAN DidNothing = TRUE;
BOOLEAN LastState = TRUE;
BOOLEAN WaitLock;
_SEH2_TRY { _SEH2_TRY {
/* wake up DirverEntry */ /* wake up DirverEntry */
KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE); KeSetEvent(&Reaper->Engine, 0, FALSE);
/* now process looping */ /* now process looping */
while (TRUE) { while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
WaitLock = FALSE; WaitLock = FALSE;
@ -3002,13 +3041,16 @@ Ext2ReaperThread(
/* wait until it is waken or it times out */ /* wait until it is waken or it times out */
KeWaitForSingleObject( KeWaitForSingleObject(
&(Ext2Global->Reaper.Wait), &Reaper->Wait,
Executive, Executive,
KernelMode, KernelMode,
FALSE, FALSE,
&Timeout &Timeout
); );
if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
break;
DidNothing = TRUE; DidNothing = TRUE;
/* acquire global exclusive lock */ /* acquire global exclusive lock */
@ -3047,22 +3089,157 @@ Ext2ReaperThread(
if (GlobalAcquired) { if (GlobalAcquired) {
ExReleaseResourceLite(&Ext2Global->Resource); ExReleaseResourceLite(&Ext2Global->Resource);
} }
KeSetEvent(&Reaper->Engine, 0, FALSE);
} _SEH2_END; } _SEH2_END;
PsTerminateSystemThread(STATUS_SUCCESS); 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 NTSTATUS
Ext2StartReaperThread() Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
{ {
NTSTATUS status = STATUS_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES oa; OBJECT_ATTRIBUTES oa;
HANDLE handle = 0; HANDLE handle = 0;
LARGE_INTEGER timeout;
Reaper->Free = Free;
/* initialize wait event */ /* initialize wait event */
KeInitializeEvent( KeInitializeEvent(
&Ext2Global->Reaper.Wait, &Reaper->Wait,
SynchronizationEvent, FALSE
);
/* Reaper thread engine event */
KeInitializeEvent(
&Reaper->Engine,
SynchronizationEvent, FALSE SynchronizationEvent, FALSE
); );
@ -3083,13 +3260,45 @@ Ext2StartReaperThread()
&oa, &oa,
NULL, NULL,
NULL, NULL,
Ext2ReaperThread, Free,
NULL (PVOID)Reaper
); );
if (NT_SUCCESS(status)) { if (NT_SUCCESS(status)) {
ZwClose(handle); 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; 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 { } else {
if (Nocache) { if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject) {
if (!ExAcquireResourceExclusiveLite( if (!ExAcquireResourceExclusiveLite(
&Fcb->MainResource, &Fcb->MainResource,
@ -592,14 +592,23 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext)
} }
MainResourceAcquired = TRUE; MainResourceAcquired = TRUE;
if (FileObject->SectionObjectPointer->DataSectionObject != NULL) { CcFlushCache(&Fcb->SectionObject,
CcFlushCache( FileObject->SectionObjectPointer, &ByteOffset,
&ByteOffset, Length,
Length, &Irp->IoStatus );
&Irp->IoStatus ); if (!NT_SUCCESS(Irp->IoStatus.Status))
if (!NT_SUCCESS(Irp->IoStatus.Status)) _SEH2_LEAVE;
_SEH2_LEAVE; ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
ExReleaseResourceLite(&(Fcb->PagingIoResource));
} }
CcPurgeCacheSection( &Fcb->SectionObject,
NULL,
0,
FALSE );
ExConvertExclusiveToShared(&Fcb->MainResource);
} else { } else {

View file

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