diff --git a/reactos/drivers/filesystems/ext2/inc/common.h b/reactos/drivers/filesystems/ext2/inc/common.h index 66ed586c9cb..78ec730aab0 100644 --- a/reactos/drivers/filesystems/ext2/inc/common.h +++ b/reactos/drivers/filesystems/ext2/inc/common.h @@ -167,8 +167,8 @@ typedef struct _EXT2_VOLUME_PROPERTY { BOOLEAN bExt3Writable; BOOLEAN bExt2; BOOLEAN bExt3; - UCHAR Codepage[CODEPAGE_MAXLEN]; -} EXT2_VOLUME_PROPERTY; + CHAR Codepage[CODEPAGE_MAXLEN]; +} EXT2_VOLUME_PROPERTY, *PEXT2_VOLUME_PROPERTY; #ifdef __cplusplus typedef struct _EXT2_VOLUME_PROPERTY2:EXT2_VOLUME_PROPERTY { @@ -196,14 +196,24 @@ typedef struct _EXT2_VOLUME_PROPERTY2 { } EXT2_VOLUME_PROPERTY2, *PEXT2_VOLUME_PROPERTY2; -#define EXT2_VPROP3_AUTOMOUNT 0x0000000000000001 +#define EXT2_VPROP3_AUTOMOUNT (1ULL << 0) +#define EXT2_VPROP3_USERIDS (1ULL << 1) +#ifdef __cplusplus +typedef struct _EXT2_VOLUME_PROPERTY3:EXT2_VOLUME_PROPERTY2 { +#else // __cplusplus typedef struct _EXT2_VOLUME_PROPERTY3 { - EXT2_VOLUME_PROPERTY2 Prop2; - unsigned __int64 Flags; - int AutoMount:1; - int Reserved1:31; - int Reserved2[31]; + EXT2_VOLUME_PROPERTY2 ; +#endif // __cplusplus + unsigned __int64 Flags2; + ULONG AutoMount:1; + ULONG EIDS:1; + ULONG Reserved1:30; + USHORT uid; + USHORT gid; + USHORT euid; + USHORT egid; + ULONG Reserved2[29]; } EXT2_VOLUME_PROPERTY3, *PEXT2_VOLUME_PROPERTY3; /* Ext2Fsd driver version and built time */ diff --git a/reactos/drivers/filesystems/ext2/inc/ext2fs.h b/reactos/drivers/filesystems/ext2/inc/ext2fs.h index eb806f3368c..f2388403569 100644 --- a/reactos/drivers/filesystems/ext2/inc/ext2fs.h +++ b/reactos/drivers/filesystems/ext2/inc/ext2fs.h @@ -47,7 +47,7 @@ /* STRUCTS & CONSTS******************************************************/ -#define EXT2FSD_VERSION "0.63" +#define EXT2FSD_VERSION "0.66" /* WDK DEFINITIONS ******************************************************/ @@ -110,6 +110,26 @@ typedef struct ext3_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2; #define CEILING_ALIGNED(T, A, B) (((A) + (B) - 1) & (~((T)(B) - 1))) #define COCKLOFT_ALIGNED(T, A, B) (((A) + (B)) & (~((T)(B) - 1))) + + +/* + * Compile-time assertion: (Lustre version) + * + * Check an invariant described by a constant expression at compile time by + * forcing a compiler error if it does not hold. \a cond must be a constant + * expression as defined by the ISO C Standard: + * + * 6.8.4.2 The switch statement + * .... + * [#3] The expression of each case label shall be an integer + * constant expression and no two of the case constant + * expressions in the same switch statement shall have the same + * value after conversion... + * + */ + +#define CL_ASSERT(cond) do {switch('x') {case (cond): case 0: break;}} while (0) + /* File System Releated *************************************************/ #define DRIVER_NAME "Ext2Fsd" @@ -130,6 +150,10 @@ typedef struct ext3_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2; #define HIDING_SUFFIX L"HidingSuffix" #define AUTO_MOUNT L"AutoMount" #define MOUNT_POINT L"MountPoint" +#define UID L"uid" +#define GID L"gid" +#define EUID L"euid" +#define EGID L"egid" #define DOS_DEVICE_NAME L"\\DosDevices\\Ext2Fsd" @@ -464,6 +488,17 @@ typedef PVOID PBCB; // Data that is not specific to a mounted volume // +typedef VOID (NTAPI *EXT2_REAPER_RELEASE)(PVOID); + +typedef struct _EXT2_REAPER { + KEVENT Engine; + KEVENT Wait; + EXT2_REAPER_RELEASE Free; + ULONG Flags; +} EXT2_REAPER, *PEXT2_REAPER; + +#define EXT2_REAPER_FLAG_STOP (1 << 0) + typedef struct _EXT2_GLOBAL { /* Identifier for this structure */ @@ -479,6 +514,9 @@ typedef struct _EXT2_GLOBAL { /* Table of pointers to the fast I/O entry points */ FAST_IO_DISPATCH FastIoDispatch; + /* Filter callbacks */ + FS_FILTER_CALLBACKS FilterCallbacks; + /* Table of pointers to the Cache Manager callbacks */ CACHE_MANAGER_CALLBACKS CacheManagerCallbacks; CACHE_MANAGER_CALLBACKS CacheManagerNoOpCallbacks; @@ -496,10 +534,8 @@ typedef struct _EXT2_GLOBAL { LIST_ENTRY VcbList; /* Cleaning thread related: resource cleaner */ - struct { - KEVENT Engine; - KEVENT Wait; - } Reaper; + EXT2_REAPER McbReaper; + EXT2_REAPER bhReaper; /* Look Aside table of IRP_CONTEXT, FCB, MCB, CCB */ NPAGED_LOOKASIDE_LIST Ext2IrpContextLookasideList; @@ -512,11 +548,14 @@ typedef struct _EXT2_GLOBAL { /* User specified global codepage name */ struct { + WCHAR PageName[CODEPAGE_MAXLEN]; UCHAR AnsiName[CODEPAGE_MAXLEN]; struct nls_table * PageTable; } Codepage; /* global hiding patterns */ + WCHAR wHidingPrefix[HIDINGPAT_LEN]; + WCHAR wHidingSuffix[HIDINGPAT_LEN]; BOOLEAN bHidingPrefix; CHAR sHidingPrefix[HIDINGPAT_LEN]; BOOLEAN bHidingSuffix; @@ -599,8 +638,11 @@ typedef struct _EXT2_VCB { /* Common header */ EXT2_FCBVCB; - // Resource for metadata (super block, tables) - ERESOURCE MetaLock; + // Resource for metadata (inode) + ERESOURCE MetaInode; + + // Resource for metadata (block) + ERESOURCE MetaBlock; // Resource for Mcb (Meta data control block) ERESOURCE McbLock; @@ -669,12 +711,6 @@ typedef struct _EXT2_VCB { BOOLEAN IsExt3fs; PEXT2_SUPER_BLOCK SuperBlock; - /* - // Bitmap Block per group - PRTL_BITMAP BlockBitMaps; - PRTL_BITMAP InodeBitMaps; - */ - // Block / Cluster size ULONG BlockSize; @@ -745,6 +781,7 @@ typedef struct _EXT2_VCB { #define VCB_USER_IDS 0x00000040 /* uid/gid specified by user */ #define VCB_USER_EIDS 0x00000080 /* euid/egid specified by user */ +#define VCB_BEING_DROPPED 0x00002000 #define VCB_FORCE_WRITING 0x00004000 #define VCB_DEVICE_REMOVED 0x00008000 #define VCB_JOURNAL_RECOVER 0x00080000 @@ -1148,7 +1185,6 @@ int Ext2CheckFileAccess (PEXT2_VCB Vcb, PEXT2_MCB Mcb, int attempt); PMDL Ext2CreateMdl ( IN PVOID Buffer, - IN BOOLEAN bPaged, IN ULONG Length, IN LOCK_OPERATION Operation ); @@ -1255,44 +1291,6 @@ Ext2NoOpAcquire ( VOID NTAPI Ext2NoOpRelease (IN PVOID Fcb); -VOID NTAPI -Ext2AcquireForCreateSection ( - IN PFILE_OBJECT FileObject -); - -VOID NTAPI -Ext2ReleaseForCreateSection ( - IN PFILE_OBJECT FileObject -); - -NTSTATUS NTAPI -Ext2AcquireFileForModWrite ( - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER EndingOffset, - OUT PERESOURCE *ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject -); - -NTSTATUS NTAPI -Ext2ReleaseFileForModWrite ( - IN PFILE_OBJECT FileObject, - IN PERESOURCE ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject -); - -NTSTATUS NTAPI -Ext2AcquireFileForCcFlush ( - IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject -); - -NTSTATUS NTAPI -Ext2ReleaseFileForCcFlush ( - IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject -); - - // // Create.c // @@ -1482,21 +1480,21 @@ Ext2FreePool( NTSTATUS Ext2ProcessGlobalProperty( IN PDEVICE_OBJECT DeviceObject, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property, IN ULONG Length ); NTSTATUS Ext2ProcessVolumeProperty( IN PEXT2_VCB Vcb, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property, IN ULONG Length ); NTSTATUS Ext2ProcessUserProperty( IN PEXT2_IRP_CONTEXT IrpContext, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property, IN ULONG Length ); @@ -1911,6 +1909,13 @@ Ext2NewInode( OUT PULONG Inode ); +NTSTATUS +Ext2UpdateGroupDirStat( + IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN ULONG Group +); + NTSTATUS Ext2FreeInode( IN PEXT2_IRP_CONTEXT IrpContext, @@ -1934,7 +1939,8 @@ Ext2SetFileType ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, - IN PEXT2_MCB Mcb + IN PEXT2_MCB Mcb, + IN umode_t mode ); NTSTATUS @@ -2110,6 +2116,56 @@ Ext2FastIoQueryNetworkOpenInfo ( OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject); +VOID +NTAPI +Ext2AcquireForCreateSection ( + IN PFILE_OBJECT FileObject +); + +VOID +NTAPI +Ext2ReleaseForCreateSection ( + IN PFILE_OBJECT FileObject +); + +NTSTATUS +NTAPI +Ext2AcquireFileForModWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE *ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject +); + +NTSTATUS +NTAPI +Ext2ReleaseFileForModWrite ( + IN PFILE_OBJECT FileObject, + IN PERESOURCE ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject +); + +NTSTATUS +NTAPI +Ext2AcquireFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject +); + +NTSTATUS +NTAPI +Ext2ReleaseFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject +); + + +NTSTATUS +NTAPI +Ext2PreAcquireForCreateSection( + IN PFS_FILTER_CALLBACK_DATA cd, + OUT PVOID *cc + ); // // FileInfo.c @@ -2402,8 +2458,10 @@ int ext3_is_dir_empty(struct ext2_icb *icb, struct inode *inode); // Init.c // +NTSTATUS +Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath); BOOLEAN -Ext2QueryGlobalParameters (IN PUNICODE_STRING RegistryPath); +Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath); VOID NTAPI DriverUnload (IN PDRIVER_OBJECT DriverObject); @@ -2465,6 +2523,19 @@ Ext2LockControl (IN PEXT2_IRP_CONTEXT IrpContext); // Memory.c // +VOID +NTAPI +Ext2McbReaperThread( + PVOID Context +); + +VOID +NTAPI +Ext2bhReaperThread( + PVOID Context +); + + PEXT2_IRP_CONTEXT Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ); @@ -2769,7 +2840,10 @@ Ext2ReaperThread( ); NTSTATUS -Ext2StartReaperThread(); +Ext2StartReaper(PEXT2_REAPER, EXT2_REAPER_RELEASE); +VOID +NTAPI +Ext2StopReaper(PEXT2_REAPER Reaper); // // Misc.c @@ -2948,6 +3022,7 @@ Ext2WriteInode ( OUT PULONG dwReturn ); + VOID Ext2StartFloppyFlushDpc ( PEXT2_VCB Vcb, diff --git a/reactos/drivers/filesystems/ext2/inc/linux/atomic.h b/reactos/drivers/filesystems/ext2/inc/linux/atomic.h index d3db770bc7d..543f9af0ab0 100644 --- a/reactos/drivers/filesystems/ext2/inc/linux/atomic.h +++ b/reactos/drivers/filesystems/ext2/inc/linux/atomic.h @@ -8,7 +8,7 @@ // typedef struct { - volatile int counter; + volatile LONG counter; } atomic_t; #define ATOMIC_INIT(i) (i) @@ -152,4 +152,4 @@ static inline int atomic_add_negative(int volatile i, atomic_t volatile *v) return (InterlockedExchangeAdd((PLONG)(&v->counter), (LONG) i) + i); } -#endif /* LINUX_ATOMIC_H */ \ No newline at end of file +#endif /* LINUX_ATOMIC_H */ diff --git a/reactos/drivers/filesystems/ext2/inc/linux/ext3_fs_sb.h b/reactos/drivers/filesystems/ext2/inc/linux/ext3_fs_sb.h index 8aaeace04b3..22eea41a6e7 100644 --- a/reactos/drivers/filesystems/ext2/inc/linux/ext3_fs_sb.h +++ b/reactos/drivers/filesystems/ext2/inc/linux/ext3_fs_sb.h @@ -22,8 +22,18 @@ /* * third extended-fs super-block data in memory */ + +struct ext3_gd { + ext3_fsblk_t block; + struct ext4_group_desc *gd; + struct buffer_head *bh; +}; + struct ext3_sb_info { + ERESOURCE s_gd_lock; + struct ext3_gd *s_gd; + unsigned long s_desc_size; /* size of group desc */ unsigned long s_gdb_count; /* Number of group descriptor blocks */ unsigned long s_desc_per_block; /* Number of group descriptors per block */ @@ -36,7 +46,6 @@ struct ext3_sb_info { int s_addr_per_block_bits; int s_desc_per_block_bits; - ext3_fsblk_t *s_group_desc; #if 0 unsigned long s_frag_size; /* Size of a fragment in bytes */ diff --git a/reactos/drivers/filesystems/ext2/inc/linux/module.h b/reactos/drivers/filesystems/ext2/inc/linux/module.h index ac35b5af5d8..141e8fd694b 100644 --- a/reactos/drivers/filesystems/ext2/inc/linux/module.h +++ b/reactos/drivers/filesystems/ext2/inc/linux/module.h @@ -546,9 +546,11 @@ struct block_device { PFILE_OBJECT bd_volume; /* streaming object file */ LARGE_MCB bd_extents; /* dirty extents */ - spinlock_t bd_bh_lock; /**/ - kmem_cache_t * bd_bh_cache; /* memory cache for buffer_head */ - struct rb_root bd_bh_root; /* buffer_head red-black tree root */ + kmem_cache_t * bd_bh_cache;/* memory cache for buffer_head */ + ERESOURCE bd_bh_lock; /* lock for bh tree and reaper list */ + struct rb_root bd_bh_root; /* buffer_head red-black tree root */ + LIST_ENTRY bd_bh_free; /* reaper list */ + KEVENT bd_bh_notify; /* notification event for cleanup */ }; // @@ -709,6 +711,7 @@ typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate); * for backward compatibility reasons (e.g. submit_bh). */ struct buffer_head { + LIST_ENTRY b_link; /* to be added to reaper list */ unsigned long b_state; /* buffer state bitmap (see above) */ struct page *b_page; /* the page this bh is mapped to */ PMDL b_mdl; /* MDL of the locked buffer */ @@ -725,7 +728,10 @@ struct buffer_head { // struct list_head b_assoc_buffers; /* associated with another mapping */ // struct address_space *b_assoc_map; /* mapping this buffer is associated with */ atomic_t b_count; /* users using this buffer_head */ - struct rb_node b_rb_node; /* Red-black tree node entry */ + struct rb_node b_rb_node; /* Red-black tree node entry */ + + LARGE_INTEGER b_ts_creat; /* creation time*/ + LARGE_INTEGER b_ts_drop; /* drop time (to be released) */ }; diff --git a/reactos/drivers/filesystems/ext2/src/block.c b/reactos/drivers/filesystems/ext2/src/block.c index 0ba96caf460..d06343737e5 100644 --- a/reactos/drivers/filesystems/ext2/src/block.c +++ b/reactos/drivers/filesystems/ext2/src/block.c @@ -51,9 +51,8 @@ Ext2MediaEjectControlCompletion ( PMDL Ext2CreateMdl ( IN PVOID Buffer, - IN BOOLEAN bPaged, IN ULONG Length, - IN LOCK_OPERATION Operation + IN LOCK_OPERATION op ) { NTSTATUS Status; @@ -65,10 +64,10 @@ Ext2CreateMdl ( Status = STATUS_INSUFFICIENT_RESOURCES; } else { _SEH2_TRY { - if (bPaged) { - MmProbeAndLockPages(Mdl, KernelMode, Operation); + if (MmIsNonPagedSystemAddressValid(Buffer)) { + MmBuildMdlForNonPagedPool(Mdl); } else { - MmBuildMdlForNonPagedPool (Mdl); + MmProbeAndLockPages(Mdl, KernelMode, op); } Status = STATUS_SUCCESS; } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { @@ -89,6 +88,7 @@ Ext2DestroyMdl (IN PMDL Mdl) while (Mdl) { PMDL Next; Next = Mdl->Next; + Mdl->Next = NULL; if (IsFlagOn(Mdl->MdlFlags, MDL_PAGES_LOCKED)) { MmUnlockPages (Mdl); } diff --git a/reactos/drivers/filesystems/ext2/src/cleanup.c b/reactos/drivers/filesystems/ext2/src/cleanup.c index bc20461ad59..005fcb6c279 100644 --- a/reactos/drivers/filesystems/ext2/src/cleanup.c +++ b/reactos/drivers/filesystems/ext2/src/cleanup.c @@ -33,6 +33,7 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) BOOLEAN VcbResourceAcquired = FALSE; BOOLEAN FcbResourceAcquired = FALSE; BOOLEAN FcbPagingIoResourceAcquired = FALSE; + BOOLEAN SymLinkDelete = FALSE; _SEH2_TRY { @@ -198,7 +199,11 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) } if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { - SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); + if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) { + SymLinkDelete = TRUE; + } else { + SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING); + } } // @@ -279,52 +284,52 @@ Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext) } } - if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { + if (SymLinkDelete || + (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) && + Fcb->OpenHandleCount == 0) ) { - if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) { + // + // Ext2DeleteFile will acquire these lock inside + // - // - // Ext2DeleteFile will acquire these lock inside - // + if (FcbResourceAcquired) { + ExReleaseResourceLite(&Fcb->MainResource); + FcbResourceAcquired = FALSE; + } - if (FcbResourceAcquired) { - ExReleaseResourceLite(&Fcb->MainResource); - FcbResourceAcquired = FALSE; + // + // this file is to be deleted ... + // + if (Ccb->SymLink) { + Mcb = Ccb->SymLink; + FileObject->DeletePending = FALSE; + } + + Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); + + if (NT_SUCCESS(Status)) { + if (IsMcbDirectory(Mcb)) { + Ext2NotifyReportChange( IrpContext, Vcb, Mcb, + FILE_NOTIFY_CHANGE_DIR_NAME, + FILE_ACTION_REMOVED ); + } else { + Ext2NotifyReportChange( IrpContext, Vcb, Mcb, + FILE_NOTIFY_CHANGE_FILE_NAME, + FILE_ACTION_REMOVED ); } + } - // - // this file is to be deleted ... - // - if (Ccb->SymLink) { - Mcb = Ccb->SymLink; - FileObject->DeletePending = FALSE; - } + // + // re-acquire the main resource lock + // - Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb); - - if (NT_SUCCESS(Status)) { - if (IsMcbDirectory(Mcb)) { - Ext2NotifyReportChange( IrpContext, Vcb, Mcb, - FILE_NOTIFY_CHANGE_DIR_NAME, - FILE_ACTION_REMOVED ); - } else { - Ext2NotifyReportChange( IrpContext, Vcb, Mcb, - FILE_NOTIFY_CHANGE_FILE_NAME, - FILE_ACTION_REMOVED ); - } - } - - // - // re-acquire the main resource lock - // - - FcbResourceAcquired = - ExAcquireResourceExclusiveLite( - &Fcb->MainResource, - TRUE - ); - - SetFlag(FileObject->Flags, FO_FILE_MODIFIED); + FcbResourceAcquired = + ExAcquireResourceExclusiveLite( + &Fcb->MainResource, + TRUE + ); + if (!SymLinkDelete) { + SetFlag(FileObject->Flags, FO_FILE_MODIFIED); if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize))); diff --git a/reactos/drivers/filesystems/ext2/src/cmcb.c b/reactos/drivers/filesystems/ext2/src/cmcb.c index deafda2b51f..2c0d1874049 100644 --- a/reactos/drivers/filesystems/ext2/src/cmcb.c +++ b/reactos/drivers/filesystems/ext2/src/cmcb.c @@ -38,8 +38,7 @@ Ext2AcquireForLazyWrite ( DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForLazyWrite: %s %s Fcb=%p\n", Ext2GetCurrentProcessName(), "ACQUIRE_FOR_LAZY_WRITE", Fcb)); #endif - if (!ExAcquireResourceSharedLite( - &Fcb->PagingIoResource, Wait)) { + if (!ExAcquireResourceExclusiveLite(Fcb->Header.Resource, Wait)) { return FALSE; } @@ -47,7 +46,6 @@ Ext2AcquireForLazyWrite ( Fcb->LazyWriterThread = PsGetCurrentThread(); ASSERT(IoGetTopLevelIrp() == NULL); - IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); return TRUE; @@ -59,9 +57,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context) // // On a readonly filesystem this function still has to exist but it // doesn't need to do anything. - PEXT2_FCB Fcb; - - Fcb = (PEXT2_FCB) Context; + PEXT2_FCB Fcb = (PEXT2_FCB) Context; ASSERT(Fcb != NULL); @@ -74,7 +70,7 @@ Ext2ReleaseFromLazyWrite (IN PVOID Context) ASSERT(Fcb->LazyWriterThread == PsGetCurrentThread()); Fcb->LazyWriterThread = NULL; - ExReleaseResourceLite(&Fcb->PagingIoResource); + ExReleaseResourceLite(Fcb->Header.Resource); ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); IoSetTopLevelIrp( NULL ); @@ -84,24 +80,18 @@ BOOLEAN NTAPI Ext2AcquireForReadAhead (IN PVOID Context, IN BOOLEAN Wait) { - PEXT2_FCB Fcb; - - Fcb = (PEXT2_FCB) Context; + PEXT2_FCB Fcb = (PEXT2_FCB) Context; ASSERT(Fcb != NULL); - ASSERT((Fcb->Identifier.Type == EXT2FCB) && (Fcb->Identifier.Size == sizeof(EXT2_FCB))); DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForReadAhead: i=%xh Fcb=%p\n", Fcb->Mcb->Inode.i_ino, Fcb)); - if (!ExAcquireResourceSharedLite( - &Fcb->MainResource, Wait )) + if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait)) return FALSE; - ASSERT(IoGetTopLevelIrp() == NULL); - IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); return TRUE; @@ -110,9 +100,7 @@ Ext2AcquireForReadAhead (IN PVOID Context, VOID NTAPI Ext2ReleaseFromReadAhead (IN PVOID Context) { - PEXT2_FCB Fcb; - - Fcb = (PEXT2_FCB) Context; + PEXT2_FCB Fcb = (PEXT2_FCB) Context; ASSERT(Fcb != NULL); @@ -122,9 +110,8 @@ Ext2ReleaseFromReadAhead (IN PVOID Context) DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFromReadAhead: i=%xh Fcb=%p\n", Fcb->Mcb->Inode.i_ino, Fcb)); - IoSetTopLevelIrp( NULL ); - - ExReleaseResourceLite(&Fcb->MainResource); + IoSetTopLevelIrp(NULL); + ExReleaseResourceLite(Fcb->Header.Resource); } BOOLEAN NTAPI @@ -149,120 +136,3 @@ Ext2NoOpRelease ( return; } - -VOID NTAPI -Ext2AcquireForCreateSection ( - IN PFILE_OBJECT FileObject -) - -{ - PEXT2_FCB Fcb = FileObject->FsContext; - - if (Fcb->Header.Resource != NULL) { - ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE); - } - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireForCreateSection: Fcb=%p\n", Fcb)); -} - -VOID NTAPI -Ext2ReleaseForCreateSection ( - IN PFILE_OBJECT FileObject -) - -{ - PEXT2_FCB Fcb = FileObject->FsContext; - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseForCreateSection: Fcb=%p\n", Fcb)); - - if (Fcb->Header.Resource != NULL) { - ExReleaseResourceLite(Fcb->Header.Resource); - } -} - - -NTSTATUS NTAPI -Ext2AcquireFileForModWrite ( - IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER EndingOffset, - OUT PERESOURCE *ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject -) - -{ - BOOLEAN ResourceAcquired = FALSE; - - PEXT2_FCB Fcb = FileObject->FsContext; - - if (Fcb->Header.PagingIoResource != NULL) { - *ResourceToRelease = Fcb->Header.PagingIoResource; - } else { - *ResourceToRelease = Fcb->Header.Resource; - } - - ResourceAcquired = ExAcquireResourceSharedLite(*ResourceToRelease, FALSE); - if (!ResourceAcquired) { - *ResourceToRelease = NULL; - } - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireFileForModWrite: Fcb=%p Acquired=%d\n", - Fcb, ResourceAcquired)); - - return (ResourceAcquired ? STATUS_SUCCESS : STATUS_CANT_WAIT); -} - -NTSTATUS NTAPI -Ext2ReleaseFileForModWrite ( - IN PFILE_OBJECT FileObject, - IN PERESOURCE ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject -) -{ - PEXT2_FCB Fcb = FileObject->FsContext; - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFileForModWrite: Fcb=%p\n", Fcb)); - - if (ResourceToRelease != NULL) { - ASSERT(ResourceToRelease == Fcb->Header.PagingIoResource || - ResourceToRelease == Fcb->Header.Resource); - ExReleaseResourceLite(ResourceToRelease); - } else { - DbgBreak(); - } - - return STATUS_SUCCESS; -} - -NTSTATUS NTAPI -Ext2AcquireFileForCcFlush ( - IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject -) -{ - PEXT2_FCB Fcb = FileObject->FsContext; - - if (Fcb->Header.PagingIoResource != NULL) { - ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, TRUE); - } - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2AcquireFileForCcFlush: Fcb=%p\n", Fcb)); - - return STATUS_SUCCESS; -} - -NTSTATUS NTAPI -Ext2ReleaseFileForCcFlush ( - IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject -) -{ - PEXT2_FCB Fcb = FileObject->FsContext; - - DEBUG(CMCB_DEBUG_LEVEL, ("Ext2ReleaseFileForCcFlush: Fcb=%p\n", Fcb)); - - if (Fcb->Header.PagingIoResource != NULL) { - ExReleaseResourceLite(Fcb->Header.PagingIoResource); - } - - return STATUS_SUCCESS; -} diff --git a/reactos/drivers/filesystems/ext2/src/create.c b/reactos/drivers/filesystems/ext2/src/create.c index 6ef28f7173c..a72da5a94fe 100644 --- a/reactos/drivers/filesystems/ext2/src/create.c +++ b/reactos/drivers/filesystems/ext2/src/create.c @@ -93,7 +93,7 @@ Ext2FollowLink ( } /* read the symlink target path */ - if (Mcb->Inode.i_size < EXT2_LINKLEN_IN_INODE) { + if (!Mcb->Inode.i_blocks) { OemName.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]); OemName.Length = (USHORT)Mcb->Inode.i_size; @@ -871,6 +871,7 @@ McbExisting: #ifndef __REACTOS__ LONG i = 0; #endif + PathName = FileName; Mcb = NULL; @@ -1388,6 +1389,7 @@ Openit: // // check the oplock state of the file // + Status = FsRtlCheckOplock( &Fcb->Oplock, IrpContext->Irp, IrpContext, @@ -1895,8 +1897,13 @@ Ext2CreateInode( Inode.i_ino = iNo; Inode.i_ctime = Inode.i_mtime = Inode.i_atime = Ext2LinuxTime(SysTime); - Inode.i_uid = Vcb->uid; - Inode.i_gid = Vcb->gid; + if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) { + Inode.i_uid = Vcb->uid; + Inode.i_gid = Vcb->gid; + } else { + Inode.i_uid = Parent->Mcb->Inode.i_uid; + Inode.i_gid = Parent->Mcb->Inode.i_gid; + } Inode.i_generation = Parent->Inode->i_generation; Inode.i_mode = S_IPERMISSION_MASK & Parent->Inode->i_mode; diff --git a/reactos/drivers/filesystems/ext2/src/devctl.c b/reactos/drivers/filesystems/ext2/src/devctl.c index 20eec7bb24d..1114989db02 100644 --- a/reactos/drivers/filesystems/ext2/src/devctl.c +++ b/reactos/drivers/filesystems/ext2/src/devctl.c @@ -231,13 +231,16 @@ extern CHAR gDate[]; NTSTATUS Ext2ProcessGlobalProperty( IN PDEVICE_OBJECT DeviceObject, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property3, IN ULONG Length ) { + PEXT2_VOLUME_PROPERTY3 Property2 = (PVOID)Property3; + PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3; + struct nls_table * PageTable = NULL; + NTSTATUS Status = STATUS_SUCCESS; BOOLEAN GlobalDataResourceAcquired = FALSE; - struct nls_table * PageTable = NULL; _SEH2_TRY { @@ -289,51 +292,57 @@ Ext2ProcessGlobalProperty( ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE); GlobalDataResourceAcquired = TRUE; - if (Property->bReadonly) { - ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); - ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); - } else { - SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); - if (Property->bExt3Writable) { - SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); - } else { - ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); - } - } - PageTable = load_nls(Property->Codepage); - if (PageTable) { - memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN); - Ext2Global->Codepage.PageTable = PageTable; - } + switch (Property->Command) { - if (Property->Command == APP_CMD_SET_PROPERTY2 || - Property->Command == APP_CMD_SET_PROPERTY3 ) { + case APP_CMD_SET_PROPERTY3: - RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN); - if ((Ext2Global->bHidingPrefix = Property->bHidingPrefix)) { - RtlCopyMemory( Ext2Global->sHidingPrefix, - Property->sHidingPrefix, - HIDINGPAT_LEN - 1); - } - RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN); - if ((Ext2Global->bHidingSuffix = Property->bHidingSuffix)) { - RtlCopyMemory( Ext2Global->sHidingSuffix, - Property->sHidingSuffix, - HIDINGPAT_LEN - 1); - } - } - - if (Property->Command == APP_CMD_SET_PROPERTY3) { - - PEXT2_VOLUME_PROPERTY3 Prop3 = (PEXT2_VOLUME_PROPERTY3)Property; - - if (Prop3->Flags & EXT2_VPROP3_AUTOMOUNT) { - if (Prop3->AutoMount) + if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) { + if (Property3->AutoMount) SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); else ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); } + + case APP_CMD_SET_PROPERTY2: + + RtlZeroMemory(Ext2Global->sHidingPrefix, HIDINGPAT_LEN); + if ((Ext2Global->bHidingPrefix = Property2->bHidingPrefix)) { + RtlCopyMemory( Ext2Global->sHidingPrefix, + Property2->sHidingPrefix, + HIDINGPAT_LEN - 1); + } + RtlZeroMemory(Ext2Global->sHidingSuffix, HIDINGPAT_LEN); + if ((Ext2Global->bHidingSuffix = Property2->bHidingSuffix)) { + RtlCopyMemory( Ext2Global->sHidingSuffix, + Property2->sHidingSuffix, + HIDINGPAT_LEN - 1); + } + + case APP_CMD_SET_PROPERTY: + + if (Property->bReadonly) { + ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); + ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); + } else { + SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); + if (Property->bExt3Writable) { + SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); + } else { + ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); + } + } + + PageTable = load_nls(Property->Codepage); + if (PageTable) { + memcpy(Ext2Global->Codepage.AnsiName, Property->Codepage, CODEPAGE_MAXLEN); + Ext2Global->Codepage.PageTable = PageTable; + } + + break; + + default: + break; } } _SEH2_FINALLY { @@ -350,13 +359,15 @@ Ext2ProcessGlobalProperty( NTSTATUS Ext2ProcessVolumeProperty( IN PEXT2_VCB Vcb, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property3, IN ULONG Length ) { - NTSTATUS Status = STATUS_SUCCESS; - BOOLEAN VcbResourceAcquired = FALSE; struct nls_table * PageTable = NULL; + PEXT2_VOLUME_PROPERTY2 Property2 = (PVOID)Property3; + PEXT2_VOLUME_PROPERTY Property = (PVOID)Property3; + NTSTATUS Status = STATUS_SUCCESS; + BOOLEAN VcbResourceAcquired = FALSE; _SEH2_TRY { @@ -364,7 +375,7 @@ Ext2ProcessVolumeProperty( VcbResourceAcquired = TRUE; if (Property->Command == APP_CMD_SET_PROPERTY || - Property->Command == APP_CMD_QUERY_PROPERTY) { + Property->Command == APP_CMD_QUERY_PROPERTY) { if (Length < sizeof(EXT2_VOLUME_PROPERTY)) { Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; @@ -375,17 +386,67 @@ Ext2ProcessVolumeProperty( Status = STATUS_INVALID_PARAMETER; _SEH2_LEAVE; } + } else if (Property->Command == APP_CMD_SET_PROPERTY3 || + Property->Command == APP_CMD_QUERY_PROPERTY3) { + if (Length < sizeof(EXT2_VOLUME_PROPERTY3)) { + Status = STATUS_INVALID_PARAMETER; + _SEH2_LEAVE; + } } switch (Property->Command) { - case APP_CMD_SET_PROPERTY: + case APP_CMD_SET_PROPERTY3: + + if (Property3->Flags2 & EXT2_VPROP3_AUTOMOUNT) { + if (Property3->AutoMount) + SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); + else + ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); + } + if (Property3->Flags2 & EXT2_VPROP3_USERIDS) { + SetFlag(Vcb->Flags, VCB_USER_IDS); + Vcb->uid = Property3->uid; + Vcb->gid = Property3->gid; + if (Property3->EIDS) { + Vcb->euid = Property3->euid; + Vcb->egid = Property3->egid; + SetFlag(Vcb->Flags, VCB_USER_EIDS); + } else { + Vcb->euid = Vcb->egid = 0; + ClearFlag(Vcb->Flags, VCB_USER_EIDS); + } + } else { + ClearFlag(Vcb->Flags, VCB_USER_IDS); + ClearFlag(Vcb->Flags, VCB_USER_EIDS); + Vcb->uid = Vcb->gid = 0; + Vcb->euid = Vcb->egid = 0; + } + case APP_CMD_SET_PROPERTY2: - if (Property->bReadonly) { + RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN); + if (Vcb->bHidingPrefix == Property2->bHidingPrefix) { + RtlCopyMemory( Vcb->sHidingPrefix, + Property2->sHidingPrefix, + HIDINGPAT_LEN - 1); + } - Ext2FlushFiles(NULL, Vcb, FALSE); - Ext2FlushVolume(NULL, Vcb, FALSE); + RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN); + if (Vcb->bHidingSuffix == Property2->bHidingSuffix) { + RtlCopyMemory( Vcb->sHidingSuffix, + Property2->sHidingSuffix, + HIDINGPAT_LEN - 1); + } + Vcb->DrvLetter = Property2->DrvLetter; + + case APP_CMD_SET_PROPERTY: + + if (Property->bReadonly) { + if (IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) { + Ext2FlushFiles(NULL, Vcb, FALSE); + Ext2FlushVolume(NULL, Vcb, FALSE); + } SetLongFlag(Vcb->Flags, VCB_READ_ONLY); } else { @@ -418,30 +479,58 @@ Ext2ProcessVolumeProperty( Ext2InitializeLabel(Vcb, Vcb->SuperBlock); } - if (Property->Command == APP_CMD_SET_PROPERTY2) { - - RtlZeroMemory(Vcb->sHidingPrefix, HIDINGPAT_LEN); - if ((Vcb->bHidingPrefix = Property->bHidingPrefix) != 0) { - RtlCopyMemory( Vcb->sHidingPrefix, - Property->sHidingPrefix, - HIDINGPAT_LEN - 1); - } - - RtlZeroMemory(Vcb->sHidingSuffix, HIDINGPAT_LEN); - if ((Vcb->bHidingSuffix = Property->bHidingSuffix) != 0) { - RtlCopyMemory( Vcb->sHidingSuffix, - Property->sHidingSuffix, - HIDINGPAT_LEN - 1); - } - - Vcb->DrvLetter = Property->DrvLetter; - } - break; - case APP_CMD_QUERY_PROPERTY: + case APP_CMD_QUERY_PROPERTY3: + + if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) { + SetFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT); + Property3->AutoMount = TRUE; + } else { + ClearFlag(Property3->Flags2, EXT2_VPROP3_AUTOMOUNT); + Property3->AutoMount = FALSE; + } + + if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) { + SetFlag(Property3->Flags2, EXT2_VPROP3_USERIDS); + Property3->uid = Vcb->uid; + Property3->gid = Vcb->gid; + if (IsFlagOn(Vcb->Flags, VCB_USER_EIDS)) { + Property3->EIDS = TRUE; + Property3->euid = Vcb->euid; + Property3->egid = Vcb->egid; + } else { + Property3->EIDS = FALSE; + } + } else { + ClearFlag(Property3->Flags2, EXT2_VPROP3_USERIDS); + } + case APP_CMD_QUERY_PROPERTY2: + RtlCopyMemory(Property2->UUID, Vcb->SuperBlock->s_uuid, 16); + Property2->DrvLetter = Vcb->DrvLetter; + + if (Property2->bHidingPrefix == Vcb->bHidingPrefix) { + RtlCopyMemory( Property2->sHidingPrefix, + Vcb->sHidingPrefix, + HIDINGPAT_LEN); + } else { + RtlZeroMemory( Property2->sHidingPrefix, + HIDINGPAT_LEN); + } + + if (Property2->bHidingSuffix == Vcb->bHidingSuffix) { + RtlCopyMemory( Property2->sHidingSuffix, + Vcb->sHidingSuffix, + HIDINGPAT_LEN); + } else { + RtlZeroMemory( Property2->sHidingSuffix, + HIDINGPAT_LEN); + } + + case APP_CMD_QUERY_PROPERTY: + Property->bExt2 = TRUE; Property->bExt3 = Vcb->IsExt3fs; Property->bReadonly = IsFlagOn(Vcb->Flags, VCB_READ_ONLY); @@ -457,32 +546,6 @@ Ext2ProcessVolumeProperty( } else { strncpy(Property->Codepage, "default", CODEPAGE_MAXLEN); } - - if (Property->Command == APP_CMD_QUERY_PROPERTY2) { - - RtlCopyMemory(Property->UUID, Vcb->SuperBlock->s_uuid, 16); - - Property->DrvLetter = Vcb->DrvLetter; - - if ((Property->bHidingPrefix = Vcb->bHidingPrefix) != 0) { - RtlCopyMemory( Property->sHidingPrefix, - Vcb->sHidingPrefix, - HIDINGPAT_LEN); - } else { - RtlZeroMemory( Property->sHidingPrefix, - HIDINGPAT_LEN); - } - - if ((Property->bHidingSuffix = Vcb->bHidingSuffix) != 0) { - RtlCopyMemory( Property->sHidingSuffix, - Vcb->sHidingSuffix, - HIDINGPAT_LEN); - } else { - RtlZeroMemory( Property->sHidingSuffix, - HIDINGPAT_LEN); - } - } - break; default: @@ -503,7 +566,7 @@ Ext2ProcessVolumeProperty( NTSTATUS Ext2ProcessUserProperty( IN PEXT2_IRP_CONTEXT IrpContext, - IN PEXT2_VOLUME_PROPERTY2 Property, + IN PEXT2_VOLUME_PROPERTY3 Property, IN ULONG Length ) { diff --git a/reactos/drivers/filesystems/ext2/src/ext3/generic.c b/reactos/drivers/filesystems/ext2/src/ext3/generic.c index 2ae5b0f5e0e..9bc27477fed 100644 --- a/reactos/drivers/filesystems/ext2/src/ext3/generic.c +++ b/reactos/drivers/filesystems/ext2/src/ext3/generic.c @@ -127,6 +127,27 @@ Ext2RefreshSuper ( return TRUE; } +VOID +Ext2PutGroup(IN PEXT2_VCB Vcb) +{ + struct ext3_sb_info *sbi = &Vcb->sbi; + unsigned long i; + + + if (NULL == Vcb->sbi.s_gd) { + return; + } + + for (i = 0; i < Vcb->sbi.s_gdb_count; i++) { + if (Vcb->sbi.s_gd[i].bh) + fini_bh(&sbi->s_gd[i].bh); + } + + kfree(Vcb->sbi.s_gd); + Vcb->sbi.s_gd = NULL; +} + + BOOLEAN Ext2LoadGroup(IN PEXT2_VCB Vcb) { @@ -134,34 +155,56 @@ Ext2LoadGroup(IN PEXT2_VCB Vcb) struct ext3_sb_info *sbi = &Vcb->sbi; ext3_fsblk_t sb_block = 1; unsigned long i; + BOOLEAN rc = FALSE; - if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) { - sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE; - } + _SEH2_TRY { - if (NULL == sbi->s_group_desc) { - sbi->s_group_desc = kzalloc(sbi->s_gdb_count * sizeof(ext3_fsblk_t), - GFP_KERNEL); - } - if (sbi->s_group_desc == NULL) { - DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n")); - return FALSE; - } + ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); - for (i = 0; i < sbi->s_gdb_count; i++) { - sbi->s_group_desc[i] = descriptor_loc(sb, sb_block, i); - if (!sbi->s_group_desc[i]) { - DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i)); - return FALSE; + if (NULL == sbi->s_gd) { + sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd), + GFP_KERNEL); + } + if (sbi->s_gd == NULL) { + DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n")); + _SEH2_LEAVE; } - } - if (!ext4_check_descriptors(sb)) { - DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n")); - return FALSE; - } + if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) { + sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE; + } - return TRUE; + for (i = 0; i < sbi->s_gdb_count; i++) { + sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i); + if (!sbi->s_gd[i].block) { + DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i)); + _SEH2_LEAVE; + } + sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block); + if (!sbi->s_gd[i].bh) { + DEBUG(DL_ERR, ("Ext2LoadGroup: can't read group descriptor %d\n", i)); + _SEH2_LEAVE; + } + sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data; + } + + if (!ext4_check_descriptors(sb)) { + DbgBreak(); + DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted!\n")); + _SEH2_LEAVE; + } + + rc = TRUE; + + } _SEH2_FINALLY { + + if (!rc) + Ext2PutGroup(Vcb); + + ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); + } _SEH2_END; + + return rc; } @@ -169,14 +212,26 @@ VOID Ext2DropGroup(IN PEXT2_VCB Vcb) { struct ext3_sb_info *sbi = &Vcb->sbi; + LARGE_INTEGER timeout; unsigned long i; - if (NULL == sbi->s_group_desc) { + /* do nothing if Vcb is not initialized yet */ + if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) return; - } - kfree(sbi->s_group_desc); - sbi->s_group_desc = NULL; + _SEH2_TRY { + SetFlag(Vcb->Flags, VCB_BEING_DROPPED); + ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); + Ext2PutGroup(Vcb); + } _SEH2_FINALLY { + ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); + } _SEH2_END; + + timeout.QuadPart = (LONGLONG)-10*1000*1000; + KeWaitForSingleObject(&Vcb->bd.bd_bh_notify, + Executive, KernelMode, + FALSE, &timeout); + ClearFlag(Vcb->Flags, VCB_BEING_DROPPED); } BOOLEAN @@ -592,7 +647,7 @@ Ext2NewBlock( *Block = 0; - ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); + ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE); /* validate the hint group and hint block */ if (GroupHint >= Vcb->sbi.s_groups_count) { @@ -762,7 +817,7 @@ Again: errorout: - ExReleaseResourceLite(&Vcb->MetaLock); + ExReleaseResourceLite(&Vcb->MetaBlock); if (bh) fini_bh(&bh); @@ -799,7 +854,7 @@ Ext2FreeBlock( NTSTATUS Status = STATUS_UNSUCCESSFUL; - ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); + ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE); DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n", Block, Block + Number)); @@ -916,7 +971,7 @@ errorout: if (gb) fini_bh(&gb); - ExReleaseResourceLite(&Vcb->MetaLock); + ExReleaseResourceLite(&Vcb->MetaBlock); return Status; } @@ -948,7 +1003,7 @@ Ext2NewInode( *Inode = dwInode = 0XFFFFFFFF; - ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); + ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE); if (GroupHint >= Vcb->sbi.s_groups_count) GroupHint = GroupHint % Vcb->sbi.s_groups_count; @@ -1088,7 +1143,7 @@ repeat: break; } - fini_bh(&gb); + fini_bh(&gb); } } @@ -1272,7 +1327,7 @@ repeat: errorout: - ExReleaseResourceLite(&Vcb->MetaLock); + ExReleaseResourceLite(&Vcb->MetaInode); if (bh) fini_bh(&bh); @@ -1284,6 +1339,44 @@ errorout: return Status; } +NTSTATUS +Ext2UpdateGroupDirStat( + IN PEXT2_IRP_CONTEXT IrpContext, + IN PEXT2_VCB Vcb, + IN ULONG group + ) +{ + struct super_block *sb = &Vcb->sb; + PEXT2_GROUP_DESC gd; + struct buffer_head *gb = NULL; + NTSTATUS status; + + ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE); + + /* get group desc */ + gd = ext4_get_group_desc(sb, group, &gb); + if (!gd) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto errorout; + } + + /* update group_desc and super_block */ + ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1); + Ext2SaveGroup(IrpContext, Vcb, group); + Ext2UpdateVcbStat(IrpContext, Vcb); + status = STATUS_SUCCESS; + +errorout: + + ExReleaseResourceLite(&Vcb->MetaInode); + + if (gb) + fini_bh(&gb); + + return status; +} + + NTSTATUS Ext2FreeInode( IN PEXT2_IRP_CONTEXT IrpContext, @@ -1308,7 +1401,7 @@ Ext2FreeInode( NTSTATUS Status = STATUS_UNSUCCESSFUL; - ExAcquireResourceExclusiveLite(&Vcb->MetaLock, TRUE); + ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE); Group = (Inode - 1) / INODES_PER_GROUP; dwIno = (Inode - 1) % INODES_PER_GROUP; @@ -1385,7 +1478,7 @@ Ext2FreeInode( errorout: - ExReleaseResourceLite(&Vcb->MetaLock); + ExReleaseResourceLite(&Vcb->MetaInode); if (bh) fini_bh(&bh); @@ -1474,7 +1567,8 @@ Ext2SetFileType ( IN PEXT2_IRP_CONTEXT IrpContext, IN PEXT2_VCB Vcb, IN PEXT2_FCB Dcb, - IN PEXT2_MCB Mcb + IN PEXT2_MCB Mcb, + IN umode_t mode ) { struct inode *dir = Dcb->Inode; @@ -1507,15 +1601,21 @@ Ext2SetFileType ( if (le32_to_cpu(de->inode) != inode->i_ino) _SEH2_LEAVE; - ext3_set_de_type(inode->i_sb, de, inode->i_mode); + ext3_set_de_type(inode->i_sb, de, mode); mark_buffer_dirty(bh); - - //if (!inode->i_nlink) - // ext3_orphan_add(handle, inode); + if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) { + } else if (S_ISDIR(inode->i_mode)) { + ext3_dec_count(dir); + } else if (S_ISDIR(mode)) { + ext3_inc_count(dir); + } dir->i_ctime = dir->i_mtime = ext3_current_time(dir); ext3_mark_inode_dirty(IrpContext, dir); + inode->i_mode = mode; + ext3_mark_inode_dirty(IrpContext, inode); + Status = STATUS_SUCCESS; } _SEH2_FINALLY { @@ -2134,27 +2234,30 @@ __u16 crc16(__u16 crc, __u8 const *buffer, size_t len) __le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group, struct ext4_group_desc *gdp) { - __u16 crc = 0; + int offset; + __u16 crc = 0; + __le32 le_group = cpu_to_le32(block_group); - if (sbi->s_es->s_feature_ro_compat & - cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { - int offset = offsetof(struct ext4_group_desc, bg_checksum); - __le32 le_group = cpu_to_le32(block_group); + /* old crc16 code */ + if (!(sbi->s_es->s_feature_ro_compat & + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM))) + return 0; - crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); - crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); - crc = crc16(crc, (__u8 *)gdp, offset); - offset += sizeof(gdp->bg_checksum); /* skip checksum */ - /* for checksum of struct ext4_group_desc do the rest...*/ - if ((sbi->s_es->s_feature_incompat & - cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && - offset < le16_to_cpu(sbi->s_es->s_desc_size)) - crc = crc16(crc, (__u8 *)gdp + offset, - le16_to_cpu(sbi->s_es->s_desc_size) - - offset); - } + offset = offsetof(struct ext4_group_desc, bg_checksum); - return cpu_to_le16(crc); + crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); + crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); + crc = crc16(crc, (__u8 *)gdp, offset); + offset += sizeof(gdp->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if ((sbi->s_es->s_feature_incompat & + cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && + offset < le16_to_cpu(sbi->s_es->s_desc_size)) + crc = crc16(crc, (__u8 *)gdp + offset, + le16_to_cpu(sbi->s_es->s_desc_size) - + offset); + + return cpu_to_le16(crc); } int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group, @@ -2489,12 +2592,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, ext4_group_t block_group, struct buffer_head **bh) { struct ext4_group_desc *desc = NULL; - struct buffer_head *gb = NULL; struct ext3_sb_info *sbi = EXT3_SB(sb); PEXT2_VCB vcb = sb->s_priv; - - unsigned int group; - unsigned int offset; + ext4_group_t group; + ext4_group_t offset; if (bh) *bh = NULL; @@ -2507,44 +2608,33 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, return NULL; } - smp_rmb(); - group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); - offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); + _SEH2_TRY { - if (!sbi->s_group_desc || !sbi->s_group_desc[group]) { - Ext2LoadGroup(vcb); - } + group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); + offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_group_desc[group]) { - ext4_error(sb, "ext4_get_group_desc", - "Group descriptor not loaded - " - "block_group = %u, group = %u, desc = %u", - block_group, group, offset); - goto errorout; - } + if (!sbi->s_gd || !sbi->s_gd[group].block || + !sbi->s_gd[group].bh) { + if (!Ext2LoadGroup(vcb)) { + _SEH2_LEAVE; + } + } - gb = sb_getblk(sb, sbi->s_group_desc[group]); - if (!gb) { - ext4_error(sb, "ext4_get_group_desc", - "failed to load group - " - "block_group = %u, group = %u, desc = %u", - block_group, group, offset); - goto errorout; - } - - desc = (struct ext4_group_desc *)(gb->b_data + - offset * EXT4_DESC_SIZE(sb)); - if (bh) - *bh = gb; - else - fini_bh(&gb); - -errorout: + desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd + + offset * EXT4_DESC_SIZE(sb)); + if (bh) { + atomic_inc(&sbi->s_gd[group].bh->b_count); + *bh = sbi->s_gd[group].bh; + } + } _SEH2_FINALLY { + /* do cleanup */ + } _SEH2_END; return desc; } + /** * ext4_count_free_blocks() -- count filesystem free blocks * @sb: superblock @@ -2670,7 +2760,8 @@ int ext4_check_descriptors(struct super_block *sb) printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " "Checksum for group %u failed (%u!=%u)\n", i, le16_to_cpu(ext4_group_desc_csum(sbi, i, - gdp)), le16_to_cpu(gdp->bg_checksum)); + gdp)), + le16_to_cpu(gdp->bg_checksum)); if (!IsVcbReadOnly(Vcb)) { __brelse(bh); return 0; diff --git a/reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c b/reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c index a135b4a48f5..3d47033ed98 100644 --- a/reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c +++ b/reactos/drivers/filesystems/ext2/src/ext4/ext4_extents.c @@ -23,6 +23,7 @@ #pragma warning(disable: 4244) #endif + /* * used by extent splitting. */ @@ -1098,6 +1099,77 @@ out: return err; } +static int ext4_ext_shrink_indepth(void *icb, + handle_t *handle, + struct inode *inode, + unsigned int flags, + int *shrinked) +{ + struct ext4_extent_header *eh, *neh; + struct ext4_extent_idx *ix; + struct buffer_head *bh = NULL; + ext4_fsblk_t block; + int err = 0, depth = ext_depth(inode); + int neh_entries; + *shrinked = 0; + + if (!depth) + return 0; + + eh = ext_inode_hdr(inode); + if (le16_to_cpu(eh->eh_entries) != 1) + return 0; + + ix = EXT_FIRST_INDEX(eh); + block = ext4_idx_pblock(ix); + bh = extents_bread(inode->i_sb, block); + if (!bh) + goto out; + + /* set size of new block */ + neh = ext_block_hdr(bh); + neh_entries = le16_to_cpu(neh->eh_entries); + if (!neh->eh_depth && + neh_entries > ext4_ext_space_root(inode, 0)) + goto out; + + if (neh->eh_depth && + neh_entries > ext4_ext_space_root_idx(inode, 0)) + goto out; + + /* old root could have indexes or leaves + * so calculate e_max right way */ + if (neh->eh_depth) + eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0)); + else + eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); + + eh->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC); + eh->eh_entries = neh_entries; + if (neh->eh_depth) { + memmove(EXT_FIRST_INDEX(eh), + EXT_FIRST_INDEX(neh), + sizeof(struct ext4_extent_idx) * neh_entries); + } else { + memmove(EXT_FIRST_EXTENT(eh), + EXT_FIRST_EXTENT(neh), + sizeof(struct ext4_extent) * neh_entries); + } + le16_add_cpu(&eh->eh_depth, -1); + + ext4_mark_inode_dirty(icb, handle, inode); + *shrinked = 1; +out: + if (bh) + extents_brelse(bh); + + if (*shrinked) + ext4_free_blocks(icb, handle, inode, NULL, + block, 1, flags); + + return err; +} + /* * ext4_ext_create_new_leaf: * finds empty index and adds new leaf. @@ -1355,29 +1427,25 @@ found_extent: * with leaves. */ ext4_lblk_t -ext4_ext_next_allocated_block(struct ext4_ext_path *path) +ext4_ext_next_allocated_block(struct ext4_ext_path *path, int at) { - int depth; - - depth = path->p_depth; - - if (depth == 0 && path->p_ext == NULL) + if (at == 0 && !path->p_ext && !path->p_idx) return EXT_MAX_BLOCKS; - while (depth >= 0) { - if (depth == path->p_depth) { + while (at >= 0) { + if (at == path->p_depth) { /* leaf */ - if (path[depth].p_ext && - path[depth].p_ext != - EXT_LAST_EXTENT(path[depth].p_hdr)) - return le32_to_cpu(path[depth].p_ext[1].ee_block); + if (path[at].p_ext && + path[at].p_ext != + EXT_LAST_EXTENT(path[at].p_hdr)) + return le32_to_cpu(path[at].p_ext[1].ee_block); } else { /* index */ - if (path[depth].p_idx != - EXT_LAST_INDEX(path[depth].p_hdr)) - return le32_to_cpu(path[depth].p_idx[1].ei_block); + if (path[at].p_idx != + EXT_LAST_INDEX(path[at].p_hdr)) + return le32_to_cpu(path[at].p_idx[1].ei_block); } - depth--; + at--; } return EXT_MAX_BLOCKS; @@ -1414,12 +1482,14 @@ static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path) /* * ext4_ext_correct_indexes: - * if leaf gets modified and modified extent is first in the leaf, + * if leaf/node gets modified and modified extent/index + * is first in the leaf/node, * then we have to correct all indexes above. - * TODO: do we need to correct tree in all cases? */ -static int ext4_ext_correct_indexes(void *icb, handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) +static int ext4_ext_correct_indexes(void *icb, handle_t *handle, + struct inode *inode, + struct ext4_ext_path *path, + int at) { struct ext4_extent_header *eh; int depth = ext_depth(inode); @@ -1427,49 +1497,49 @@ static int ext4_ext_correct_indexes(void *icb, handle_t *handle, struct inode *i __le32 border; int k, err = 0; - eh = path[depth].p_hdr; - ex = path[depth].p_ext; - - if (unlikely(ex == NULL || eh == NULL)) { - EXT4_ERROR_INODE(inode, - "ex %p == NULL or eh %p == NULL", ex, eh); - return -EIO; - } - - if (depth == 0) { - /* there is no tree at all */ + assert(at >= 0); + if (!at) return 0; - } - if (ex != EXT_FIRST_EXTENT(eh)) { - /* we correct tree if first leaf got modified only */ - return 0; - } + if (depth == at) { + eh = path[at].p_hdr; + ex = path[at].p_ext; - /* - * TODO: we need correction if border is smaller than current one - */ - k = depth - 1; - border = path[depth].p_ext->ee_block; - err = ext4_ext_get_access(icb, handle, inode, path + k); - if (err) - return err; - path[k].p_idx->ei_block = border; - err = ext4_ext_dirty(icb, handle, inode, path + k); - if (err) - return err; + if (ex == NULL || eh == NULL) + return -EIO; - while (k--) { - /* change all left-side indexes */ - if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr)) - break; - err = ext4_ext_get_access(icb, handle, inode, path + k); - if (err) - break; + if (at == 0) { + /* there is no tree at all */ + return 0; + } + + if (ex != EXT_FIRST_EXTENT(eh)) { + /* we correct tree if first leaf got modified only */ + return 0; + } + + k = at - 1; + border = path[at].p_ext->ee_block; path[k].p_idx->ei_block = border; err = ext4_ext_dirty(icb, handle, inode, path + k); if (err) + return err; + + } else { + border = path[at].p_idx->ei_block; + k = at; + } + + while (k) { + /* change all left-side indexes */ + if (path[k].p_idx != EXT_FIRST_INDEX(path[k].p_hdr)) break; + path[k-1].p_idx->ei_block = border; + err = ext4_ext_dirty(icb, handle, inode, path + k-1); + if (err) + break; + + k--; } return err; @@ -1844,9 +1914,11 @@ merge: if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) ext4_ext_try_to_merge(icb, handle, inode, path, nearex); + depth = ext_depth(inode); /* time to correct all indexes above */ - err = ext4_ext_correct_indexes(icb, handle, inode, path); + err = ext4_ext_correct_indexes(icb, handle, + inode, path, depth); if (err) goto cleanup; @@ -1880,158 +1952,353 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) return ret; } -static int ext4_remove_blocks(void *icb, handle_t *handle, struct inode *inode, - struct ext4_extent *ex, - unsigned long from, unsigned long to) +static void ext4_ext_remove_blocks( + void *icb, + handle_t *handle, + struct inode *inode, struct ext4_extent *ex, + ext4_lblk_t from, ext4_lblk_t to) { - struct buffer_head *bh; - int i; - - if (from >= le32_to_cpu(ex->ee_block) - && to == le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) { - /* tail removal */ - unsigned long num, start; - num = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - from; - start = ext4_ext_pblock(ex) + ext4_ext_get_actual_len(ex) - num; - ext4_free_blocks(icb, handle, inode, NULL, start, num, 0); - } else if (from == le32_to_cpu(ex->ee_block) - && to <= le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1) { - } else { - } - return 0; + int len = to - from + 1; + ext4_lblk_t num; + ext4_fsblk_t start; + num = from - le32_to_cpu(ex->ee_block); + start = ext4_ext_pblock(ex) + num; + ext_debug("Freeing %lu at %I64u, %d\n", from, start, len); + ext4_free_blocks(icb, handle, inode, NULL, + start, len, 0); } -/* - * routine removes index from the index block - * it's used in truncate case only. thus all requests are for - * last index in the block only - */ -int ext4_ext_rm_idx(void *icb, handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) +static int ext4_ext_remove_idx(void *icb, + handle_t *handle, + struct inode *inode, + struct ext4_ext_path *path, + int depth) { - int err; + int err, i = depth; ext4_fsblk_t leaf; /* free index block */ - path--; - leaf = ext4_idx_pblock(path->p_idx); - BUG_ON(path->p_hdr->eh_entries == 0); - if ((err = ext4_ext_get_access(icb, handle, inode, path))) + leaf = ext4_idx_pblock(path[i].p_idx); + + if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) { + int len = EXT_LAST_INDEX(path[i].p_hdr) - path[i].p_idx; + memmove(path[i].p_idx, path[i].p_idx + 1, + len * sizeof(struct ext4_extent_idx)); + } + + le16_add_cpu(&path[i].p_hdr->eh_entries, -1); + err = ext4_ext_dirty(icb, handle, inode, path + i); + if (err) return err; - path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1); - if ((err = ext4_ext_dirty(icb, handle, inode, path))) - return err; - ext4_free_blocks(icb, handle, inode, NULL, leaf, 1, 0); + + ext_debug("IDX: Freeing %lu at %I64u, %d\n", + le32_to_cpu(path[i].p_idx->ei_block), leaf, 1); + ext4_free_blocks(icb, handle, inode, NULL, + leaf, 1, 0); return err; } -static int -ext4_ext_rm_leaf(void *icb, handle_t *handle, struct inode *inode, - struct ext4_ext_path *path, unsigned long start) +static int ext4_ext_amalgamate(void *icb, + handle_t *handle, + struct inode *inode, + struct ext4_ext_path *path, + int at) { - int err = 0, correct_index = 0; - int depth = ext_depth(inode), credits; - struct ext4_extent_header *eh; - unsigned a, b, block, num; - unsigned long ex_ee_block; - unsigned short ex_ee_len; - struct ext4_extent *ex; + int new_entries, right_entries; + int depth = ext_depth(inode); + struct ext4_ext_path *right_path = NULL; + ext4_lblk_t now; + int ret = 0; + if (!at) + return 0; - /* the header must be checked already in ext4_ext_remove_space() */ - if (!path[depth].p_hdr) - path[depth].p_hdr = ext_block_hdr(path[depth].p_bh); - eh = path[depth].p_hdr; - BUG_ON(eh == NULL); + now = ext4_ext_next_allocated_block(path, at - 1); + if (now == EXT_MAX_BLOCKS) + goto out; - /* find where to start removing */ - ex = EXT_LAST_EXTENT(eh); - - ex_ee_block = le32_to_cpu(ex->ee_block); - ex_ee_len = ext4_ext_get_actual_len(ex); - - while (ex >= EXT_FIRST_EXTENT(eh) && - ex_ee_block + ex_ee_len > start) { - path[depth].p_ext = ex; - - a = ex_ee_block > start ? ex_ee_block : start; - b = (unsigned long long)ex_ee_block + ex_ee_len - 1 < - EXT_MAX_BLOCKS ? ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCKS; - - - if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) { - block = 0; - num = 0; - BUG(); - } else if (a != ex_ee_block) { - /* remove tail of the extent */ - block = ex_ee_block; - num = a - block; - } else if (b != ex_ee_block + ex_ee_len - 1) { - /* remove head of the extent */ - block = a; - num = b - a; - /* there is no "make a hole" API yet */ - BUG(); - } else { - /* remove whole extent: excellent! */ - block = ex_ee_block; - num = 0; - BUG_ON(a != ex_ee_block); - BUG_ON(b != ex_ee_block + ex_ee_len - 1); - } - - /* at present, extent can't cross block group */ - /* leaf + bitmap + group desc + sb + inode */ - credits = 5; - if (ex == EXT_FIRST_EXTENT(eh)) { - correct_index = 1; - credits += (ext_depth(inode)) + 1; - } - - /*handle = ext4_ext_journal_restart(icb, handle, credits);*/ - /*if (IS_ERR(icb, handle)) {*/ - /*err = PTR_ERR(icb, handle);*/ - /*goto out;*/ - /*}*/ - - err = ext4_ext_get_access(icb, handle, inode, path + depth); - if (err) - goto out; - - err = ext4_remove_blocks(icb, handle, inode, ex, a, b); - if (err) - goto out; - - if (num == 0) { - /* this extent is removed entirely mark slot unused */ - ext4_ext_store_pblock(ex, 0); - eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1); - } - - ex->ee_block = cpu_to_le32(block); - ex->ee_len = cpu_to_le16(num); - - err = ext4_ext_dirty(icb, handle, inode, path + depth); - if (err) - goto out; - - ex--; - ex_ee_block = le32_to_cpu(ex->ee_block); - ex_ee_len = ext4_ext_get_actual_len(ex); + right_path = ext4_find_extent(inode, now, NULL, 0); + if (IS_ERR(right_path)) { + ret = PTR_ERR(right_path); + right_path = NULL; + goto out; } - if (correct_index && eh->eh_entries) - err = ext4_ext_correct_indexes(icb, handle, inode, path); + right_entries = le16_to_cpu(right_path[at].p_hdr->eh_entries); + new_entries = le16_to_cpu(path[at].p_hdr->eh_entries) + + right_entries; + if (new_entries > path[at].p_hdr->eh_max) { + ret = 0; + goto out; + } + if (at == depth) { + struct ext4_extent *last_ex = EXT_LAST_EXTENT(path[at].p_hdr); + memmove(last_ex + 1, + EXT_FIRST_EXTENT(right_path[at].p_hdr), + right_entries * sizeof(struct ext4_extent)); + } else { + struct ext4_extent_idx *last_ix = EXT_LAST_INDEX(path[at].p_hdr); + memmove(last_ix + 1, + EXT_FIRST_INDEX(right_path[at].p_hdr), + right_entries * sizeof(struct ext4_extent_idx)); + } + path[at].p_hdr->eh_entries = cpu_to_le16(new_entries); + right_path[at].p_hdr->eh_entries = 0; + ext4_ext_dirty(icb, handle, inode, path + at); - /* if this leaf is free, then we should - * remove it from index block above */ - if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) - err = ext4_ext_rm_idx(icb, handle, inode, path + depth); + /* + * remove the empty node from index block above. + */ + depth = at; + while (depth > 0) { + struct ext4_extent_header *eh = right_path[depth].p_hdr; + if (eh->eh_entries == 0 && right_path[depth].p_bh != NULL) { + ext4_ext_drop_refs(right_path + depth); + ret = ext4_ext_remove_idx(icb, handle, inode, right_path, depth - 1); + if (ret) + goto out; + + } else + break; + + depth--; + } + ret = ext4_ext_correct_indexes(icb, handle, + inode, right_path, depth); +out: + if (right_path) { + ext4_ext_drop_refs(right_path); + kfree(right_path); + } + + return ret; +} + +static int ext4_ext_balance(void *icb, + handle_t *handle, + struct inode *inode, + struct ext4_ext_path **path, + int at) +{ + int ret, shrinked = 0; + int depth = at; + + while (depth > 0) { + ret = ext4_ext_amalgamate(icb, handle, + inode, *path, depth); + if (ret) + goto out; + + depth--; + } + do { + ret = ext4_ext_shrink_indepth(icb, handle, + inode, 0, &shrinked); + } while (!ret && shrinked); out: + return ret; +} + +/* + * NOTE: After removal, path should not be reused. + */ +int ext4_ext_remove_extent(void *icb, + handle_t *handle, + struct inode *inode, struct ext4_ext_path **path) +{ + int len; + int err = 0; + ext4_lblk_t start; + uint16_t new_entries; + int depth = ext_depth(inode); + struct ext4_extent *ex = (*path)[depth].p_ext, + *ex2 = ex + 1; + struct ext4_extent_header *eh = (*path)[depth].p_hdr; + if (!ex) + return -EINVAL; + + start = le32_to_cpu(ex->ee_block); + len = ext4_ext_get_actual_len(ex); + new_entries = le16_to_cpu(eh->eh_entries) - 1; + + ext4_ext_remove_blocks(icb, handle, + inode, ex, start, start + len - 1); + if (ex2 <= EXT_LAST_EXTENT(eh)) + memmove(ex, ex2, + (EXT_LAST_EXTENT(eh) - ex2 + 1) * sizeof(struct ext4_extent)); + eh->eh_entries = cpu_to_le16(new_entries); + + ext4_ext_dirty(icb, handle, inode, (*path) + depth); + + /* + * If the node is free, then we should + * remove it from index block above. + */ + while (depth > 0) { + eh = (*path)[depth].p_hdr; + if (eh->eh_entries == 0 && (*path)[depth].p_bh != NULL) { + ext4_ext_drop_refs((*path) + depth); + err = ext4_ext_remove_idx(icb, handle, + inode, *path, depth - 1); + if (err) + break; + + } else + break; + + depth--; + } + err = ext4_ext_correct_indexes(icb, handle, + inode, *path, depth); + + if ((*path)->p_hdr->eh_entries == 0) { + /* + * truncate to zero freed all the tree, + * so we need to correct eh_depth + */ + ext_inode_hdr(inode)->eh_depth = 0; + ext_inode_hdr(inode)->eh_max = + cpu_to_le16(ext4_ext_space_root(inode, 0)); + err = ext4_ext_dirty(icb, handle, inode, *path); + } + err = ext4_ext_balance(icb, handle, inode, path, depth); + return err; } +int __ext4_ext_truncate(void *icb, + handle_t *handle, + struct inode *inode, + ext4_lblk_t from, ext4_lblk_t to) +{ + int depth = ext_depth(inode), ret = -EIO; + struct ext4_extent *ex; + struct ext4_ext_path *path = NULL, *npath; + ext4_lblk_t now = from; + + if (to < from) + return -EINVAL; + + npath = ext4_find_extent(inode, from, &path, 0); + if (IS_ERR(npath)) + goto out; + + path = npath; + ex = path[depth].p_ext; + if (!ex) + goto out; + + if (from < le32_to_cpu(ex->ee_block) && + to < le32_to_cpu(ex->ee_block)) { + ret = 0; + goto out; + } + /* If we do remove_space inside the range of an extent */ + if ((le32_to_cpu(ex->ee_block) < from) && + (to < le32_to_cpu(ex->ee_block) + + ext4_ext_get_actual_len(ex) - 1)) { + + struct ext4_extent newex; + int unwritten = ext4_ext_is_unwritten(ex); + ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block); + int len = ext4_ext_get_actual_len(ex); + ext4_fsblk_t newblock = + to + 1 - ee_block + ext4_ext_pblock(ex); + + ex->ee_len = cpu_to_le16(from - ee_block); + if (unwritten) + ext4_ext_mark_unwritten(ex); + + ext4_ext_dirty(icb, handle, inode, path + depth); + + ext4_ext_remove_blocks(icb, handle, + inode, + ex, from, to); + + newex.ee_block = cpu_to_le32(to + 1); + newex.ee_len = cpu_to_le16(ee_block + len - 1 - to); + ext4_ext_store_pblock(&newex, newblock); + if (unwritten) + ext4_ext_mark_unwritten(&newex); + + ret = ext4_ext_insert_extent(icb, handle, + inode, &path, &newex, 0); + goto out; + } + if (le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 < from) { + now = ext4_ext_next_allocated_block(path, depth); + npath = ext4_find_extent(inode, now, &path, 0); + if (IS_ERR(npath)) + goto out; + + path = npath; + ex = path[depth].p_ext; + } + while (ex && + le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex) - 1 >= now && + le32_to_cpu(ex->ee_block) <= to) { + int len, new_len = 0; + int unwritten; + ext4_lblk_t start, new_start; + ext4_fsblk_t newblock; + + new_start = start = le32_to_cpu(ex->ee_block); + len = ext4_ext_get_actual_len(ex); + newblock = ext4_ext_pblock(ex); + if (start < from) { + len -= from - start; + new_len = from - start; + start = from; + } else { + if (start + len - 1 > to) { + new_len = start + len - 1 - to; + len -= new_len; + new_start = to + 1; + newblock += to + 1 - start; + } + } + + now = ext4_ext_next_allocated_block(path, depth); + if (!new_len) { + ret = ext4_ext_remove_extent(icb, handle, + inode, &path); + if (ret) + goto out; + + } else { + ext4_ext_remove_blocks(icb, handle, + inode, + ex, start, start + len - 1); + ex->ee_block = cpu_to_le32(new_start); + unwritten = ext4_ext_is_unwritten(ex); + ex->ee_len = cpu_to_le16(new_len); + ext4_ext_store_pblock(ex, newblock); + if (unwritten) + ext4_ext_mark_unwritten(ex); + + ext4_ext_dirty(icb, handle, + inode, path + depth); + } + npath = ext4_find_extent(inode, now, &path, 0); + if (IS_ERR(npath)) + goto out; + + path = npath; + depth = ext_depth(inode); + ex = path[depth].p_ext; + } +out: + if (path) { + ext4_ext_drop_refs(path); + kfree(path); + } + + if (IS_ERR(npath)) + ret = PTR_ERR(npath); + + return ret; +} + /* * ext4_split_extent_at() splits an extent at given block. * @@ -2171,138 +2438,6 @@ fix_extent_len: return err; } -/* - * returns 1 if current index have to be freed (even partial) - */ -static inline int -ext4_ext_more_to_rm(struct ext4_ext_path *path) -{ - BUG_ON(path->p_idx == NULL); - - if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr)) - return 0; - - /* - * if truncate on deeper level happened it it wasn't partial - * so we have to consider current index for truncation - */ - if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block) - return 0; - return 1; -} - -int ext4_ext_remove_space(void *icb, struct inode *inode, unsigned long start) -{ -#ifndef __REACTOS__ - struct super_block *sb = inode->i_sb; -#endif - int depth = ext_depth(inode); - struct ext4_ext_path *path; - handle_t *handle = NULL; - int i = 0, err = 0; - - /* probably first extent we're gonna free will be last in block */ - /*handle = ext4_journal_start(inode, depth + 1);*/ - /*if (IS_ERR(icb, handle))*/ - /*return PTR_ERR(icb, handle);*/ - - /* - * we start scanning from right side freeing all the blocks - * after i_size and walking into the deep - */ - path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL); - if (path == NULL) { - ext4_journal_stop(icb, handle); - return -ENOMEM; - } - memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1)); - path[0].p_hdr = ext_inode_hdr(inode); - if (ext4_ext_check_inode(inode)) { - err = -EIO; - goto out; - } - path[0].p_depth = depth; - - while (i >= 0 && err == 0) { - if (i == depth) { - /* this is leaf block */ - err = ext4_ext_rm_leaf(icb, handle, inode, path, start); - /* root level have p_bh == NULL, extents_brelse() eats this */ - extents_brelse(path[i].p_bh); - path[i].p_bh = NULL; - i--; - continue; - } - - /* this is index block */ - if (!path[i].p_hdr) { - path[i].p_hdr = ext_block_hdr(path[i].p_bh); - } - - if (!path[i].p_idx) { - /* this level hasn't touched yet */ - path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr); - path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1; - } else { - /* we've already was here, see at next index */ - path[i].p_idx--; - } - - if (ext4_ext_more_to_rm(path + i)) { - struct buffer_head *bh; - /* go to the next level */ - memset(path + i + 1, 0, sizeof(*path)); - bh = read_extent_tree_block(inode, ext4_idx_pblock(path[i].p_idx), path[0].p_depth - (i + 1), 0); - if (IS_ERR(bh)) { - /* should we reset i_size? */ - err = -EIO; - break; - } - path[i+1].p_bh = bh; - - /* put actual number of indexes to know is this - * number got changed at the next iteration */ - path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries); - i++; - } else { - /* we finish processing this index, go up */ - if (path[i].p_hdr->eh_entries == 0 && i > 0) { - /* index is empty, remove it - * handle must be already prepared by the - * truncatei_leaf() */ - err = ext4_ext_rm_idx(icb, handle, inode, path + i); - } - /* root level have p_bh == NULL, extents_brelse() eats this */ - extents_brelse(path[i].p_bh); - path[i].p_bh = NULL; - i--; - } - } - - /* TODO: flexible tree reduction should be here */ - if (path->p_hdr->eh_entries == 0) { - /* - * truncate to zero freed all the tree - * so, we need to correct eh_depth - */ - err = ext4_ext_get_access(icb, handle, inode, path); - if (err == 0) { - ext_inode_hdr(inode)->eh_depth = 0; - ext_inode_hdr(inode)->eh_max = - cpu_to_le16(ext4_ext_space_root(inode, 0)); - err = ext4_ext_dirty(icb, handle, inode, path); - } - } -out: - if (path) { - ext4_ext_drop_refs(path); - kfree(path); - } - ext4_journal_stop(icb, handle); - - return err; -} - int ext4_ext_tree_init(void *icb, handle_t *handle, struct inode *inode) { struct ext4_extent_header *eh; @@ -2441,7 +2576,7 @@ int ext4_ext_get_blocks(void *icb, handle_t *handle, struct inode *inode, ext4_f /* find next allocated block so that we know how many * blocks we can allocate without ovelapping next extent */ - next = ext4_ext_next_allocated_block(path); + next = ext4_ext_next_allocated_block(path, depth); BUG_ON(next <= iblock); allocated = next - iblock; if (flags & EXT4_GET_BLOCKS_PRE_IO && max_blocks > EXT_UNWRITTEN_MAX_LEN) @@ -2504,7 +2639,8 @@ out2: int ext4_ext_truncate(void *icb, struct inode *inode, unsigned long start) { - int ret = ext4_ext_remove_space(icb, inode, start); + int ret = __ext4_ext_truncate(icb, NULL, inode, + start, EXT_MAX_BLOCKS); /* Save modifications on i_blocks field of the inode. */ if (!ret) diff --git a/reactos/drivers/filesystems/ext2/src/fastio.c b/reactos/drivers/filesystems/ext2/src/fastio.c index 56e7ae641f6..70dc2be09b1 100644 --- a/reactos/drivers/filesystems/ext2/src/fastio.c +++ b/reactos/drivers/filesystems/ext2/src/fastio.c @@ -17,6 +17,9 @@ extern PEXT2_GLOBAL Ext2Global; /* DEFINITIONS *************************************************************/ +#define FASTIO_DEBUG_LEVEL DL_NVR + + #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, Ext2FastIoRead) @@ -213,30 +216,34 @@ Ext2FastIoWrite ( _SEH2_LEAVE; } - if (ExAcquireResourceExclusiveLite(&Fcb->MainResource, Wait)) - Locked = TRUE; - else + if (!ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait)) { _SEH2_LEAVE; + } + Locked = TRUE; if (IsWritingToEof(*FileOffset) || + Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length || Fcb->Header.FileSize.QuadPart < FileOffset->QuadPart + Length ) { Status = FALSE; _SEH2_LEAVE; } + if (Locked) { + ExReleaseResourceLite(Fcb->Header.Resource); + Locked = FALSE; + } + Status = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject); if (Status) { if (IoStatus) Length = (ULONG)IoStatus->Information; - if (Fcb->Header.ValidDataLength.QuadPart < FileOffset->QuadPart + Length) - Fcb->Header.ValidDataLength.QuadPart = FileOffset->QuadPart + Length; } } _SEH2_FINALLY { if (Locked) { - ExReleaseResourceLite(&Fcb->MainResource); + ExReleaseResourceLite(Fcb->Header.Resource); } FsRtlExitFileSystem(); @@ -981,3 +988,137 @@ Ext2FastIoQueryNetworkOpenInfo ( return bResult; } + + +VOID NTAPI +Ext2AcquireForCreateSection ( + IN PFILE_OBJECT FileObject +) + +{ + PEXT2_FCB Fcb = FileObject->FsContext; + + if (Fcb->Header.Resource != NULL) { + ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE); + } + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireForCreateSection: Fcb=%p\n", Fcb)); +} + +VOID NTAPI +Ext2ReleaseForCreateSection ( + IN PFILE_OBJECT FileObject +) +{ + PEXT2_FCB Fcb = FileObject->FsContext; + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseForCreateSection: Fcb=%p\n", Fcb)); + + if (Fcb->Header.Resource != NULL) { + ExReleaseResourceLite(Fcb->Header.Resource); + } +} + + +NTSTATUS NTAPI +Ext2AcquireFileForModWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE *ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject +) + +{ + BOOLEAN ResourceAcquired = FALSE; + + PEXT2_FCB Fcb = FileObject->FsContext; + + *ResourceToRelease = Fcb->Header.Resource; + ResourceAcquired = ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE); + if (!ResourceAcquired) { + *ResourceToRelease = NULL; + } + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForModWrite: Fcb=%p Acquired=%d\n", + Fcb, ResourceAcquired)); + + return (ResourceAcquired ? STATUS_SUCCESS : STATUS_CANT_WAIT); +} + +NTSTATUS NTAPI +Ext2ReleaseFileForModWrite ( + IN PFILE_OBJECT FileObject, + IN PERESOURCE ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject +) +{ + PEXT2_FCB Fcb = FileObject->FsContext; + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForModWrite: Fcb=%p\n", Fcb)); + + if (ResourceToRelease != NULL) { + ASSERT(ResourceToRelease == Fcb->Header.Resource); + ExReleaseResourceLite(ResourceToRelease); + } else { + DbgBreak(); + } + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +Ext2AcquireFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject +) +{ + PEXT2_FCB Fcb = FileObject->FsContext; + + if (Fcb->Header.Resource != NULL) { + ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE); + } + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2AcquireFileForCcFlush: Fcb=%p\n", Fcb)); + + return STATUS_SUCCESS; +} + +NTSTATUS NTAPI +Ext2ReleaseFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject +) +{ + PEXT2_FCB Fcb = FileObject->FsContext; + + DEBUG(FASTIO_DEBUG_LEVEL, ("Ext2ReleaseFileForCcFlush: Fcb=%p\n", Fcb)); + + if (Fcb->Header.Resource != NULL) { + ExReleaseResourceLite(Fcb->Header.Resource); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS NTAPI +Ext2PreAcquireForCreateSection( + IN PFS_FILTER_CALLBACK_DATA cd, + OUT PVOID *cc + ) +{ + PEXT2_FCB Fcb = (PEXT2_FCB)cd->FileObject->FsContext; + NTSTATUS status; + + ASSERT(cd->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION); + ExAcquireResourceExclusiveLite(Fcb->Header.Resource, TRUE); + if (cd->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) { + status = STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY; + } else if (Fcb->ShareAccess.Writers == 0) { + status = STATUS_FILE_LOCKED_WITH_ONLY_READERS; + } else { + status = STATUS_FILE_LOCKED_WITH_WRITERS; + } + + return status; +} diff --git a/reactos/drivers/filesystems/ext2/src/fileinfo.c b/reactos/drivers/filesystems/ext2/src/fileinfo.c index f00035d4d25..dff7195d921 100644 --- a/reactos/drivers/filesystems/ext2/src/fileinfo.c +++ b/reactos/drivers/filesystems/ext2/src/fileinfo.c @@ -554,13 +554,6 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) VcbMainResourceAcquired = TRUE; } - if (IsVcbReadOnly(Vcb)) { - if (FileInformationClass != FilePositionInformation) { - Status = STATUS_MEDIA_WRITE_PROTECTED; - _SEH2_LEAVE; - } - } - if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { Status = STATUS_ACCESS_DENIED; _SEH2_LEAVE; @@ -596,6 +589,17 @@ Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext) Mcb = Fcb->Mcb; } + if (FileInformationClass != FilePositionInformation) { + if (IsVcbReadOnly(Vcb)) { + Status = STATUS_MEDIA_WRITE_PROTECTED; + _SEH2_LEAVE; + } + if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) { + Status = STATUS_ACCESS_DENIED; + _SEH2_LEAVE; + } + } + if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) && ((FileInformationClass == FileEndOfFileInformation) || (FileInformationClass == FileValidDataLengthInformation) || @@ -1289,8 +1293,9 @@ Ext2SetDispositionInfo( DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n", &Mcb->FullName)); - /* always allow deleting on symlinks */ - if (Ccb->SymLink == NULL) { + if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) { + /* always allow deleting on symlinks */ + } else { status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb); } diff --git a/reactos/drivers/filesystems/ext2/src/flush.c b/reactos/drivers/filesystems/ext2/src/flush.c index dba95f55f35..3359a117eec 100644 --- a/reactos/drivers/filesystems/ext2/src/flush.c +++ b/reactos/drivers/filesystems/ext2/src/flush.c @@ -81,6 +81,9 @@ Ext2FlushVolume ( DEBUG(DL_INF, ( "Ext2FlushVolume: Flushing Vcb ...\n")); + /* discard buffer_headers for group_desc */ + Ext2DropGroup(Vcb); + ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); ExReleaseResourceLite(&Vcb->PagingIoResource); diff --git a/reactos/drivers/filesystems/ext2/src/fsctl.c b/reactos/drivers/filesystems/ext2/src/fsctl.c index 5ff4264e2ba..a7c56774d41 100644 --- a/reactos/drivers/filesystems/ext2/src/fsctl.c +++ b/reactos/drivers/filesystems/ext2/src/fsctl.c @@ -1422,7 +1422,8 @@ Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) _SEH2_TRY { - if (!Mcb || !IsInodeSymLink(&Mcb->Inode)) { + if (!Mcb || !IsInodeSymLink(&Mcb->Inode) || + !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) { Status = STATUS_NOT_A_REPARSE_POINT; _SEH2_LEAVE; } @@ -1567,7 +1568,6 @@ out: return Status; } - NTSTATUS Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) { @@ -1673,15 +1673,31 @@ Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) } } + /* free all data blocks of the inode (to be set as symlink) */ + { + LARGE_INTEGER zero = {0}; + Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero); + } + + /* decrease dir count of group desc and vcb stat */ + if (S_ISDIR(Mcb->Inode.i_mode)) { + + ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP; + Ext2UpdateGroupDirStat(IrpContext, Vcb, group); + + /* drop extra reference for dir inode */ + ext3_dec_count(&Mcb->Inode); + } + /* overwrite inode mode as type SYMLINK */ - Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO; Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT); Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer, OemNameLength, &BytesWritten); if (NT_SUCCESS(Status)) { - Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb); + Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb, + S_IFLNK | S_IRWXUGO); } } _SEH2_FINALLY { @@ -1799,7 +1815,8 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) } } - if (!Mcb) { + if (!Mcb || !IsInodeSymLink(&Mcb->Inode) || + !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) { Status = STATUS_NOT_A_REPARSE_POINT; _SEH2_LEAVE; } @@ -1825,15 +1842,9 @@ Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) if (!NT_SUCCESS(Status)) { _SEH2_LEAVE; } - if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) { - SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL); - } - ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT); - ClearFlag(Mcb->Inode.i_flags, S_IFLNK); - Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); - if (NT_SUCCESS(Status)) { - Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb); - } + + /* inode is to be removed */ + SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE); } _SEH2_FINALLY { @@ -2702,6 +2713,9 @@ Ext2PurgeVolume (IN PEXT2_VCB Vcb, FlushBeforePurge = FALSE; } + /* discard buffer_headers for group_desc */ + Ext2DropGroup(Vcb); + FcbListEntry= NULL; InitializeListHead(&FcbList); diff --git a/reactos/drivers/filesystems/ext2/src/init.c b/reactos/drivers/filesystems/ext2/src/init.c index 470811a273b..f9a80235ef5 100644 --- a/reactos/drivers/filesystems/ext2/src/init.c +++ b/reactos/drivers/filesystems/ext2/src/init.c @@ -33,6 +33,7 @@ DriverEntry( #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, Ext2QueryGlobalParameters) +#pragma alloc_text(INIT, Ext2QueryRegistrySettings) #pragma alloc_text(INIT, DriverEntry) #if EXT2_UNLOAD #pragma alloc_text(PAGE, DriverUnload) @@ -99,36 +100,222 @@ DriverUnload (IN PDRIVER_OBJECT DriverObject) #endif -BOOLEAN -Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) +NTSTATUS NTAPI +Ext2RegistryQueryCallback( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) { + ULONG i = 0; + BYTE *s, *t; + + if (NULL == ValueName || NULL == ValueData) + return STATUS_SUCCESS; + + if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(WRITING_SUPPORT) && + _wcsnicmp(ValueName, WRITING_SUPPORT, wcslen(WRITING_SUPPORT)) == 0) { + + if (ValueData && ValueLength == sizeof(DWORD)) { + if (*((PULONG)ValueData)) { + SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); + } else { + ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); + } + } + } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(CHECKING_BITMAP) && + _wcsnicmp(ValueName, CHECKING_BITMAP, wcslen(CHECKING_BITMAP)) == 0) { + + if (ValueData && ValueLength == sizeof(DWORD)) { + if (*((PULONG)ValueData)) { + SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); + } else { + ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); + } + } + } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(EXT3_FORCEWRITING) && + _wcsnicmp(ValueName, EXT3_FORCEWRITING, wcslen(EXT3_FORCEWRITING)) == 0) { + + if (ValueData && ValueLength == sizeof(DWORD)) { + if (*((PULONG)ValueData)) { + SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); + SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); + } else { + ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); + } + } + } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(AUTO_MOUNT) && + _wcsnicmp(ValueName, AUTO_MOUNT, wcslen(AUTO_MOUNT)) == 0) { + + if (ValueData && ValueLength == sizeof(DWORD)) { + if (*((PULONG)ValueData)) { + SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); + } else { + ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); + } + } + } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(CODEPAGE_NAME) && + _wcsnicmp(ValueName, CODEPAGE_NAME, wcslen(CODEPAGE_NAME)) == 0) { + + if (ValueData && ValueLength <= sizeof(WCHAR) * CODEPAGE_MAXLEN) { + RtlCopyMemory(&Ext2Global->Codepage.PageName[0], + ValueData, ValueLength); + } + } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_PREFIX) && + _wcsnicmp(ValueName, HIDING_PREFIX, wcslen(HIDING_PREFIX)) == 0) { + + if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) { + RtlCopyMemory(&Ext2Global->wHidingPrefix[0], + ValueData, ValueLength); + } + } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_SUFFIX) && + _wcsnicmp(ValueName, HIDING_SUFFIX, wcslen(HIDING_SUFFIX)) == 0) { + + if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) { + RtlCopyMemory(&Ext2Global->wHidingSuffix[0], + ValueData, ValueLength); + } + } + + + return STATUS_SUCCESS; +} + +NTSTATUS +Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath) +{ + RTL_QUERY_REGISTRY_TABLE QueryTable[8]; + int i = 0; NTSTATUS Status; + + RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 8); + + /* + * 1 writing support + */ + QueryTable[i].Flags = 0; + QueryTable[0].Name = WRITING_SUPPORT; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + /* + * 2 checking bitmap + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = CHECKING_BITMAP; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + /* + * 3 force writing + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = EXT3_FORCEWRITING; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + /* + * 4 automount + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = AUTO_MOUNT; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + /* + * 5 codepage + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = CODEPAGE_NAME; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + /* + * 6 hidden prefix + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = HIDING_PREFIX; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + + /* + * 7 hidden suffix + */ + QueryTable[i].Flags = 0; + QueryTable[i].Name = HIDING_SUFFIX; + QueryTable[i].DefaultType = REG_NONE; + QueryTable[i].DefaultLength = 0; + QueryTable[i].DefaultData = NULL; + QueryTable[i].EntryContext = NULL; + QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback; + i++; + + Status = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE, + RegistryPath->Buffer, + &QueryTable[0], + NULL, + NULL + ); + + return NT_SUCCESS(Status); +} + + +BOOLEAN +Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath) +{ UNICODE_STRING ParameterPath; - RTL_QUERY_REGISTRY_TABLE QueryTable[2]; + UNICODE_STRING UniName; + ANSI_STRING AnsiName; ULONG WritingSupport = 0; ULONG CheckingBitmap = 0; ULONG Ext3ForceWriting = 0; ULONG AutoMount = 0; - UNICODE_STRING UniName; - ANSI_STRING AnsiName; - WCHAR UniBuffer[CODEPAGE_MAXLEN]; USHORT Buffer[HIDINGPAT_LEN]; - ParameterPath.Length = 0; + NTSTATUS Status; + ParameterPath.Length = 0; ParameterPath.MaximumLength = RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR); - ParameterPath.Buffer = (PWSTR) Ext2AllocatePool( PagedPool, ParameterPath.MaximumLength, 'LG2E' ); - if (!ParameterPath.Buffer) { DbgBreak(); DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n")); @@ -138,101 +325,24 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) RtlCopyUnicodeString(&ParameterPath, RegistryPath); RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY); - /* querying value of WritingSupport */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = WRITING_SUPPORT; - QueryTable[0].EntryContext = &WritingSupport; - - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - - DEBUG(DL_ERR, ( "Ext2QueryParameters: WritingSupport=%xh\n", WritingSupport)); - - /* querying value of CheckingBitmap */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = CHECKING_BITMAP; - QueryTable[0].EntryContext = &CheckingBitmap; - - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - - DEBUG(DL_ERR, ( "Ext2QueryParameters: CheckingBitmap=%xh\n", CheckingBitmap)); - - /* querying value of Ext3ForceWriting */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = EXT3_FORCEWRITING; - QueryTable[0].EntryContext = &Ext3ForceWriting; - - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - - DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext3ForceWriting=%xh\n", Ext3ForceWriting)); - - - /* querying value of AutoMount */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = AUTO_MOUNT; - QueryTable[0].EntryContext = &AutoMount; - - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - + /* enable automount of ext2/3/4 volumes */ SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); - if (NT_SUCCESS(Status) && AutoMount == 0) { - ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT); - } - DEBUG(DL_ERR, ( "Ext2QueryParameters: AutoMount=%xh\n", AutoMount)); + /* query parameter settings from registry */ + Ext2QueryGlobalParameters(&ParameterPath); - /* querying codepage */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = CODEPAGE_NAME; - QueryTable[0].EntryContext = &(UniName); - UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR); - UniName.Length = 0; - UniName.Buffer = (PWSTR)UniBuffer; - - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - - if (NT_SUCCESS(Status)) { - DEBUG(DL_ERR, ( "Ext2QueryParameters: Ext2CodePage=%wZ\n", &UniName)); + /* set global codepage settings */ + if (wcslen(&Ext2Global->Codepage.PageName[0])) { + UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->Codepage.PageName[0]); + UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR); + UniName.Buffer = &Ext2Global->Codepage.PageName[0]; AnsiName.MaximumLength = CODEPAGE_MAXLEN; AnsiName.Length = 0; - AnsiName.Buffer = &(Ext2Global->Codepage.AnsiName[0]); - + AnsiName.Buffer = &Ext2Global->Codepage.AnsiName[0]; Status = RtlUnicodeStringToAnsiString( &AnsiName, &UniName, FALSE); - if (!NT_SUCCESS(Status)) { DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName)); RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8); @@ -243,25 +353,13 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) } Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0; - /* querying name hiding patterns: prefix*/ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = HIDING_PREFIX; - QueryTable[0].EntryContext = &(UniName); - UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); - UniName.Length = 0; - UniName.Buffer = Buffer; - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL ); - - if (NT_SUCCESS(Status)) { - DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix=%wZ\n", &UniName)); - AnsiName.MaximumLength =HIDINGPAT_LEN; + /* set global hidden prefix pattern */ + if (wcslen(&Ext2Global->wHidingPrefix[0])) { + UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingPrefix[0]); + UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); + UniName.Buffer = &Ext2Global->wHidingPrefix[0]; + AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]); @@ -279,26 +377,12 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; - /* querying name hiding patterns: suffix */ - RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2); - QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; - QueryTable[0].Name = HIDING_SUFFIX; - QueryTable[0].EntryContext = &(UniName); - UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); - UniName.Length = 0; - UniName.Buffer = Buffer; - Status = RtlQueryRegistryValues( - RTL_REGISTRY_ABSOLUTE, - ParameterPath.Buffer, - &QueryTable[0], - NULL, - NULL - ); - - if (NT_SUCCESS(Status)) { - - DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix=%wZ\n", &UniName)); + /* set global hidden suffix pattern */ + if (wcslen(&Ext2Global->wHidingSuffix[0])) { + UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingSuffix[0]); + UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR); + UniName.Buffer = &Ext2Global->wHidingSuffix[0]; AnsiName.MaximumLength = HIDINGPAT_LEN; AnsiName.Length = 0; AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]); @@ -317,29 +401,6 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) } Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0; - { - if (WritingSupport) { - SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); - } else { - ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); - } - - if (CheckingBitmap) { - SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); - } else { - ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP); - } - - if (Ext3ForceWriting) { - DEBUG(DL_WRN, ("Ext2Fsd -- Warning: Ext3ForceWriting enabled !!!\n")); - - SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); - SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING); - } else { - ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING); - } - } - Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer; Ext2Global->RegistryPath.Length = 0; Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength; @@ -360,6 +421,23 @@ Ext2QueryGlobalParameters( IN PUNICODE_STRING RegistryPath) ) #endif +VOID +Ext2EresourceAlignmentChecking() +{ + /* Verify ERESOURCE alignment in structures */ + CL_ASSERT((FIELD_OFFSET(EXT2_GLOBAL, Resource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MainResource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, PagingIoResource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaInode) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaBlock) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, bd.bd_bh_lock) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_VCB, sbi.s_gd_lock) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, PagingIoResource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_FCB, MainResource) & 7) == 0); + CL_ASSERT((FIELD_OFFSET(EXT2_FCB, PagingIoResource) & 7) == 0); +} /* * NAME: DriverEntry @@ -384,24 +462,12 @@ DriverEntry ( PFAST_IO_DISPATCH FastIoDispatch; PCACHE_MANAGER_CALLBACKS CacheManagerCallbacks; - LARGE_INTEGER Timeout; NTSTATUS Status; int rc = 0; BOOLEAN linux_lib_inited = FALSE; BOOLEAN journal_module_inited = FALSE; - /* Verify ERESOURCE alignment in structures */ - ASSERT((FIELD_OFFSET(EXT2_GLOBAL, Resource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_VCB, MainResource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_VCB, PagingIoResource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_VCB, MetaLock) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_FCBVCB, PagingIoResource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_FCB, MainResource) & 7) == 0); - ASSERT((FIELD_OFFSET(EXT2_FCB, PagingIoResource) & 7) == 0); - /* Verity super block ... */ ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024); ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56); @@ -454,12 +520,8 @@ DriverEntry ( InitializeListHead(&(Ext2Global->VcbList)); ExInitializeResourceLite(&(Ext2Global->Resource)); - /* Reaper thread engine event */ - KeInitializeEvent(&Ext2Global->Reaper.Engine, - SynchronizationEvent, FALSE); - /* query registry settings */ - Ext2QueryGlobalParameters(RegistryPath); + Ext2QueryRegistrySettings(RegistryPath); /* create Ext2Fsd cdrom fs deivce */ RtlInitUnicodeString(&DeviceName, CDROM_NAME); @@ -494,21 +556,18 @@ DriverEntry ( } /* start resource reaper thread */ - Status= Ext2StartReaperThread(); + Status= Ext2StartReaper( + &Ext2Global->McbReaper, + Ext2McbReaperThread); if (!NT_SUCCESS(Status)) { goto errorout; } - /* make sure Reaperthread is started */ - Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */ - Status = KeWaitForSingleObject( - &(Ext2Global->Reaper.Engine), - Executive, - KernelMode, - FALSE, - &Timeout - ); - if (Status != STATUS_SUCCESS) { - Status = STATUS_INSUFFICIENT_RESOURCES; + + Status= Ext2StartReaper( + &Ext2Global->bhReaper, + Ext2bhReaperThread); + if (!NT_SUCCESS(Status)) { + Ext2StopReaper(&Ext2Global->McbReaper); goto errorout; } @@ -564,12 +623,16 @@ DriverEntry ( FastIoDispatch->FastIoUnlockAll = Ext2FastIoUnlockAll; FastIoDispatch->FastIoUnlockAllByKey = Ext2FastIoUnlockAllByKey; FastIoDispatch->FastIoQueryNetworkOpenInfo = Ext2FastIoQueryNetworkOpenInfo; + + FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite; + FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite; FastIoDispatch->AcquireForModWrite = Ext2AcquireFileForModWrite; FastIoDispatch->ReleaseForModWrite = Ext2ReleaseFileForModWrite; FastIoDispatch->AcquireForCcFlush = Ext2AcquireFileForCcFlush; FastIoDispatch->ReleaseForCcFlush = Ext2ReleaseFileForCcFlush; FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection; FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection; + DriverObject->FastIoDispatch = FastIoDispatch; // @@ -633,6 +696,19 @@ DriverEntry ( Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead = Ext2NoOpAcquire; Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = Ext2NoOpRelease; + +#ifndef _WIN2K_TARGET_ + // + // Initialize FS Filter callbacks + // + + RtlZeroMemory(&Ext2Global->FilterCallbacks, sizeof(FS_FILTER_CALLBACKS)); + Ext2Global->FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS); + Ext2Global->FilterCallbacks.PreAcquireForSectionSynchronization = Ext2PreAcquireForCreateSection; + FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &Ext2Global->FilterCallbacks ); + +#endif + // // Initialize the global data // diff --git a/reactos/drivers/filesystems/ext2/src/linux.c b/reactos/drivers/filesystems/ext2/src/linux.c index 289c0c7bfb1..f65e0b5e8be 100644 --- a/reactos/drivers/filesystems/ext2/src/linux.c +++ b/reactos/drivers/filesystems/ext2/src/linux.c @@ -329,10 +329,16 @@ new_buffer_head() struct buffer_head * bh = NULL; bh = kmem_cache_alloc(g_jbh.bh_cache, GFP_NOFS); if (bh) { + atomic_inc(&g_jbh.bh_count); + atomic_inc(&g_jbh.bh_acount); + memset(bh, 0, sizeof(struct buffer_head)); + InitializeListHead(&bh->b_link); + KeQuerySystemTime(&bh->b_ts_creat); DEBUG(DL_BH, ("bh=%p allocated.\n", bh)); INC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); } + return bh; } @@ -344,13 +350,9 @@ free_buffer_head(struct buffer_head * bh) DEBUG(DL_BH, ("bh=%p mdl=%p (Flags:%xh VA:%p) released.\n", bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_mdl->MappedSystemVa)); - if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_PAGES_LOCKED)) { - /* MmUnlockPages will release it's VA */ - MmUnlockPages(bh->b_mdl); - } else if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) { + if (IsFlagOn(bh->b_mdl->MdlFlags, MDL_MAPPED_TO_SYSTEM_VA)) { MmUnmapLockedPages(bh->b_mdl->MappedSystemVa, bh->b_mdl); } - Ext2DestroyMdl(bh->b_mdl); } if (bh->b_bcb) { @@ -360,6 +362,7 @@ free_buffer_head(struct buffer_head * bh) DEBUG(DL_BH, ("bh=%p freed.\n", bh)); DEC_MEM_COUNT(PS_BUFF_HEAD, bh, sizeof(struct buffer_head)); kmem_cache_free(g_jbh.bh_cache, bh); + atomic_dec(&g_jbh.bh_count); } } @@ -436,7 +439,6 @@ get_block_bh_mdl( PVOID bcb = NULL; PVOID ptr = NULL; - KIRQL irql = 0; struct list_head *entry; /* allocate buffer_head and initialize it */ @@ -449,15 +451,15 @@ get_block_bh_mdl( } /* search the bdev bh list */ - spin_lock_irqsave(&bdev->bd_bh_lock, irql); + ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); tbh = buffer_head_search(bdev, block); if (tbh) { bh = tbh; get_bh(bh); - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); bh = new_buffer_head(); if (!bh) { @@ -467,8 +469,6 @@ get_block_bh_mdl( bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL; - atomic_inc(&g_jbh.bh_count); - atomic_inc(&g_jbh.bh_acount); again: @@ -499,13 +499,14 @@ again: set_buffer_uptodate(bh); } - bh->b_mdl = Ext2CreateMdl(ptr, TRUE, bh->b_size, IoModifyAccess); + bh->b_mdl = Ext2CreateMdl(ptr, bh->b_size, IoModifyAccess); if (bh->b_mdl) { /* muse map the PTE to NonCached zone. journal recovery will access the PTE under spinlock: DISPATCH_LEVEL IRQL */ bh->b_data = MmMapLockedPagesSpecifyCache( bh->b_mdl, KernelMode, MmNonCached, NULL,FALSE, HighPagePriority); + /* bh->b_data = MmMapLockedPages(bh->b_mdl, KernelMode); */ } if (!bh->b_mdl || !bh->b_data) { free_buffer_head(bh); @@ -518,20 +519,21 @@ again: DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p mdl=%p (Flags:%xh VA:%p)\n", Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_mdl, bh->b_mdl->MdlFlags, bh->b_data)); - spin_lock_irqsave(&bdev->bd_bh_lock, irql); - + ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); /* do search again here */ tbh = buffer_head_search(bdev, block); if (tbh) { free_buffer_head(bh); bh = tbh; get_bh(bh); - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + RemoveEntryList(&bh->b_link); + InitializeListHead(&bh->b_link); + ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; - } else + } else { buffer_head_insert(bdev, bh); - - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + } + ExReleaseResourceLite(&bdev->bd_bh_lock); /* we get it */ errorout: @@ -602,7 +604,7 @@ errorout: } struct buffer_head * -get_block_bh( +get_block_bh_pin( struct block_device * bdev, sector_t block, unsigned long size, @@ -612,7 +614,6 @@ get_block_bh( PEXT2_VCB Vcb = bdev->bd_priv; LARGE_INTEGER offset; - KIRQL irql = 0; struct list_head *entry; /* allocate buffer_head and initialize it */ @@ -625,15 +626,15 @@ get_block_bh( } /* search the bdev bh list */ - spin_lock_irqsave(&bdev->bd_bh_lock, irql); + ExAcquireSharedStarveExclusive(&bdev->bd_bh_lock, TRUE); tbh = buffer_head_search(bdev, block); if (tbh) { bh = tbh; get_bh(bh); - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); goto errorout; } - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); bh = new_buffer_head(); if (!bh) { @@ -643,8 +644,6 @@ get_block_bh( bh->b_blocknr = block; bh->b_size = size; bh->b_data = NULL; - atomic_inc(&g_jbh.bh_count); - atomic_inc(&g_jbh.bh_acount); again: @@ -656,7 +655,7 @@ again: &offset, bh->b_size, FALSE, - PIN_WAIT | PIN_EXCLUSIVE, + PIN_WAIT, &bh->b_bcb, (PVOID *)&bh->b_data)) { Ext2Sleep(100); @@ -675,33 +674,34 @@ again: set_buffer_uptodate(bh); } + if (bh->b_bcb) + CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3)); + if (!bh->b_data) { free_buffer_head(bh); bh = NULL; goto errorout; } - get_bh(bh); - CcSetBcbOwnerPointer(bh->b_bcb, (PVOID)((ERESOURCE_THREAD)bh | 0x3)); DEBUG(DL_BH, ("getblk: Vcb=%p bhcount=%u block=%u bh=%p ptr=%p.\n", Vcb, atomic_read(&g_jbh.bh_count), block, bh, bh->b_data)); - spin_lock_irqsave(&bdev->bd_bh_lock, irql); - + ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); /* do search again here */ tbh = buffer_head_search(bdev, block); if (tbh) { get_bh(tbh); - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); free_buffer_head(bh); bh = tbh; + RemoveEntryList(&bh->b_link); + InitializeListHead(&bh->b_link); goto errorout; } else { buffer_head_insert(bdev, bh); } - - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + ExReleaseResourceLite(&bdev->bd_bh_lock); /* we get it */ errorout: @@ -709,7 +709,7 @@ errorout: return bh; } -int submit_bh(int rw, struct buffer_head *bh) +int submit_bh_pin(int rw, struct buffer_head *bh) { struct block_device *bdev = bh->b_bdev; PEXT2_VCB Vcb = bdev->bd_priv; @@ -744,6 +744,43 @@ errorout: return 0; } +#if 0 + +struct buffer_head * +get_block_bh( + struct block_device * bdev, + sector_t block, + unsigned long size, + int zero +) +{ + return get_block_bh_mdl(bdev, block, size, zero); +} + +int submit_bh(int rw, struct buffer_head *bh) +{ + return submit_bh_mdl(rw, bh); +} + +#else + +struct buffer_head * +get_block_bh( + struct block_device * bdev, + sector_t block, + unsigned long size, + int zero +) +{ + return get_block_bh_pin(bdev, block, size, zero); +} + +int submit_bh(int rw, struct buffer_head *bh) +{ + return submit_bh_pin(rw, bh); +} +#endif + struct buffer_head * __getblk( struct block_device * bdev, @@ -758,7 +795,6 @@ void __brelse(struct buffer_head *bh) { struct block_device *bdev = bh->b_bdev; PEXT2_VCB Vcb = (PEXT2_VCB)bdev->bd_priv; - KIRQL irql = 0; ASSERT(Vcb->Identifier.Type == EXT2VCB); @@ -767,20 +803,30 @@ void __brelse(struct buffer_head *bh) ll_rw_block(WRITE, 1, &bh); } - spin_lock_irqsave(&bdev->bd_bh_lock, irql); - if (!atomic_dec_and_test(&bh->b_count)) { - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + if (1 == atomic_read(&bh->b_count)) { + } else if (atomic_dec_and_test(&bh->b_count)) { + atomic_inc(&bh->b_count); + } else { + return; + } + + ExAcquireResourceExclusiveLite(&bdev->bd_bh_lock, TRUE); + if (atomic_dec_and_test(&bh->b_count)) { + ASSERT(0 == atomic_read(&bh->b_count)); + } else { + ExReleaseResourceLite(&bdev->bd_bh_lock); return; } buffer_head_remove(bdev, bh); - spin_unlock_irqrestore(&bdev->bd_bh_lock, irql); + KeQuerySystemTime(&bh->b_ts_drop); + InsertTailList(&Vcb->bd.bd_bh_free, &bh->b_link); + KeClearEvent(&Vcb->bd.bd_bh_notify); + ExReleaseResourceLite(&bdev->bd_bh_lock); + KeSetEvent(&Ext2Global->bhReaper.Wait, 0, FALSE); DEBUG(DL_BH, ("brelse: cnt=%u size=%u blk=%10.10xh bh=%p ptr=%p\n", atomic_read(&g_jbh.bh_count) - 1, bh->b_size, bh->b_blocknr, bh, bh->b_data )); - - free_buffer_head(bh); - atomic_dec(&g_jbh.bh_count); } @@ -863,10 +909,7 @@ void mark_buffer_dirty(struct buffer_head *bh) int sync_blockdev(struct block_device *bdev) { PEXT2_VCB Vcb = (PEXT2_VCB) bdev->bd_priv; - - if (0 == atomic_read(&g_jbh.bh_count)) { - Ext2FlushVolume(NULL, Vcb, FALSE); - } + Ext2FlushVolume(NULL, Vcb, FALSE); return 0; } diff --git a/reactos/drivers/filesystems/ext2/src/memory.c b/reactos/drivers/filesystems/ext2/src/memory.c index da91dc12a88..60055a6e7bf 100644 --- a/reactos/drivers/filesystems/ext2/src/memory.c +++ b/reactos/drivers/filesystems/ext2/src/memory.c @@ -31,7 +31,8 @@ extern PEXT2_GLOBAL Ext2Global; #pragma alloc_text(PAGE, Ext2DestroyVcb) #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap) #pragma alloc_text(PAGE, Ext2ReaperThread) -#pragma alloc_text(PAGE, Ext2StartReaperThread) +#pragma alloc_text(PAGE, Ext2StartReaper) +#pragma alloc_text(PAGE, Ext2StopReaper) #endif PEXT2_IRP_CONTEXT @@ -1404,7 +1405,7 @@ Ext2AllocateMcb ( /* need wake the reaper thread if there are many Mcb allocated */ if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) { - KeSetEvent(&Ext2Global->Reaper.Wait, 0, FALSE); + KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE); } /* allocate Mcb from LookasideList */ @@ -1505,6 +1506,7 @@ Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb) #ifndef __REACTOS__ PEXT2_MCB Parent = Mcb->Parent; #endif + ASSERT(Mcb != NULL); ASSERT((Mcb->Identifier.Type == EXT2MCB) && @@ -1839,6 +1841,7 @@ Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block) return FALSE; } + RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length); if (RtlCheckBit(&bitmap, dwBlk) == 0) { @@ -1982,7 +1985,7 @@ errorout: VOID Ext2ParseRegistryVolumeParams( IN PUNICODE_STRING Params, - OUT PEXT2_VOLUME_PROPERTY2 Property + OUT PEXT2_VOLUME_PROPERTY3 Property ) { WCHAR Codepage[CODEPAGE_MAXLEN]; @@ -1990,11 +1993,15 @@ Ext2ParseRegistryVolumeParams( WCHAR Suffix[HIDINGPAT_LEN]; USHORT MountPoint[4]; UCHAR DrvLetter[4]; + WCHAR wUID[8], wGID[8], wEUID[8], wEGID[8]; + CHAR sUID[8], sGID[8], sEUID[8], sEGID[8]; BOOLEAN bWriteSupport = FALSE, bCheckBitmap = FALSE, bCodeName = FALSE, bMountPoint = FALSE; + BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0; + struct { PWCHAR Name; /* parameters name */ PBOOLEAN bExist; /* is it contained in params */ @@ -2020,6 +2027,11 @@ Ext2ParseRegistryVolumeParams( {MOUNT_POINT, &bMountPoint, 4, &MountPoint[0], &DrvLetter[0]}, + {UID, &bUID, 8, &wUID[0], &sUID[0],}, + {GID, &bGID, 8, &wGID[0], &sGID[0]}, + {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]}, + {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]}, + /* end */ {NULL, NULL, 0, NULL} }; @@ -2032,9 +2044,9 @@ Ext2ParseRegistryVolumeParams( RtlZeroMemory(MountPoint, sizeof(USHORT) * 4); RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4); - RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY2)); + RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3)); Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC; - Property->Command = APP_CMD_SET_PROPERTY2; + Property->Command = APP_CMD_SET_PROPERTY3; for (i=0; ParamPattern[i].Name != NULL; i++) { @@ -2095,6 +2107,22 @@ Ext2ParseRegistryVolumeParams( Property->DrvLetter = DrvLetter[0]; Property->DrvLetter |= 0x80; } + + if (bUID && bGID) { + SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS); + sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0; + Property->uid = (USHORT)atoi(sUID); + Property->gid = (USHORT)atoi(sGID); + if (bEUID) { + Property->euid = (USHORT)atoi(sEUID); + Property->egid = (USHORT)atoi(sEGID); + Property->EIDS = TRUE; + } else { + Property->EIDS = FALSE; + } + } else { + ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS); + } } NTSTATUS @@ -2107,7 +2135,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb) if (NT_SUCCESS(Status)) { /* set Vcb settings from registery */ - EXT2_VOLUME_PROPERTY2 Property; + EXT2_VOLUME_PROPERTY3 Property; Ext2ParseRegistryVolumeParams(&VolumeParams, &Property); Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property)); @@ -2141,7 +2169,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb) memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN); Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable; - if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) { + if (Vcb->bHidingPrefix == Ext2Global->bHidingPrefix) { RtlCopyMemory( Vcb->sHidingPrefix, Ext2Global->sHidingPrefix, HIDINGPAT_LEN); @@ -2150,7 +2178,7 @@ Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb) HIDINGPAT_LEN); } - if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) { + if (Vcb->bHidingSuffix == Ext2Global->bHidingSuffix) { RtlCopyMemory( Vcb->sHidingSuffix, Ext2Global->sHidingSuffix, HIDINGPAT_LEN); @@ -2247,6 +2275,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, BOOLEAN NotifySyncInitialized = FALSE; BOOLEAN ExtentsInitialized = FALSE; BOOLEAN InodeLookasideInitialized = FALSE; + BOOLEAN GroupLoaded = FALSE; _SEH2_TRY { @@ -2293,8 +2322,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, /* initialize eresources */ ExInitializeResourceLite(&Vcb->MainResource); ExInitializeResourceLite(&Vcb->PagingIoResource); - ExInitializeResourceLite(&Vcb->MetaLock); + ExInitializeResourceLite(&Vcb->MetaInode); + ExInitializeResourceLite(&Vcb->MetaBlock); ExInitializeResourceLite(&Vcb->McbLock); + ExInitializeResourceLite(&Vcb->sbi.s_gd_lock); #ifndef _WIN2K_TARGET_ ExInitializeFastMutex(&Vcb->Mutex); FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex); @@ -2367,15 +2398,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, /* initialize UUID and serial number */ if (Ext2IsNullUuid(sb->s_uuid)) { ExUuidCreate((UUID *)sb->s_uuid); - } else { - /* query parameters from registry */ - if (!NT_SUCCESS(Ext2PerformRegistryVolumeParams(Vcb))) { - /* don't mount this volume */ - Status = STATUS_UNRECOGNIZED_VOLUME; - _SEH2_LEAVE; - } } - Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] + ((ULONG*)sb->s_uuid)[1] + ((ULONG*)sb->s_uuid)[2] + @@ -2471,7 +2494,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, Vcb->bd.bd_volume = Vcb->Volume; Vcb->bd.bd_priv = (void *) Vcb; memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root)); - spin_lock_init(&Vcb->bd.bd_bh_lock); + InitializeListHead(&Vcb->bd.bd_bh_free); + ExInitializeResourceLite(&Vcb->bd.bd_bh_lock); + KeInitializeEvent(&Vcb->bd.bd_bh_notify, + NotificationEvent, TRUE); Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer", Vcb->BlockSize, 0, 0, NULL); if (!Vcb->bd.bd_bh_cache) { @@ -2600,6 +2626,7 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, Status = STATUS_UNSUCCESSFUL; _SEH2_LEAVE; } + GroupLoaded = TRUE; /* recovery journal since it's ext3 */ if (Vcb->IsExt3fs) { @@ -2656,6 +2683,10 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, /* get anything doen, then refer target device */ ObReferenceObject(Vcb->TargetDeviceObject); + + /* query parameters from registry */ + Ext2PerformRegistryVolumeParams(Vcb); + SetLongFlag(Vcb->Flags, VCB_INITIALIZED); } _SEH2_FINALLY { @@ -2671,9 +2702,11 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, } if (ExtentsInitialized) { - Ext2DropGroup(Vcb); - if (Vcb->bd.bd_bh_cache) + if (Vcb->bd.bd_bh_cache) { + if (GroupLoaded) + Ext2PutGroup(Vcb); kmem_cache_destroy(Vcb->bd.bd_bh_cache); + } FsRtlUninitializeLargeMcb(&(Vcb->Extents)); } @@ -2690,7 +2723,9 @@ Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext, if (VcbResourceInitialized) { ExDeleteResourceLite(&Vcb->McbLock); - ExDeleteResourceLite(&Vcb->MetaLock); + ExDeleteResourceLite(&Vcb->MetaInode); + ExDeleteResourceLite(&Vcb->MetaBlock); + ExDeleteResourceLite(&Vcb->sbi.s_gd_lock); ExDeleteResourceLite(&Vcb->MainResource); ExDeleteResourceLite(&Vcb->PagingIoResource); } @@ -2752,6 +2787,7 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb) if (Vcb->bd.bd_bh_cache) kmem_cache_destroy(Vcb->bd.bd_bh_cache); + ExDeleteResourceLite(&Vcb->bd.bd_bh_lock); if (Vcb->SuperBlock) { Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC); @@ -2770,7 +2806,9 @@ Ext2DestroyVcb (IN PEXT2_VCB Vcb) ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList)); ExDeleteResourceLite(&Vcb->McbLock); - ExDeleteResourceLite(&Vcb->MetaLock); + ExDeleteResourceLite(&Vcb->MetaInode); + ExDeleteResourceLite(&Vcb->MetaBlock); + ExDeleteResourceLite(&Vcb->sbi.s_gd_lock); ExDeleteResourceLite(&Vcb->PagingIoResource); ExDeleteResourceLite(&Vcb->MainResource); @@ -2935,16 +2973,11 @@ Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number) /* Reaper thread to release unused Mcb blocks */ VOID NTAPI -Ext2ReaperThread( +Ext2McbReaperThread( PVOID Context ) { - BOOLEAN GlobalAcquired = FALSE; - - BOOLEAN DidNothing = TRUE; - BOOLEAN LastState = TRUE; - BOOLEAN WaitLock; - + PEXT2_REAPER Reaper = Context; PLIST_ENTRY List = NULL; LARGE_INTEGER Timeout; @@ -2953,13 +2986,19 @@ Ext2ReaperThread( ULONG i, NumOfMcbs; + BOOLEAN GlobalAcquired = FALSE; + + BOOLEAN DidNothing = TRUE; + BOOLEAN LastState = TRUE; + BOOLEAN WaitLock; + _SEH2_TRY { /* wake up DirverEntry */ - KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE); + KeSetEvent(&Reaper->Engine, 0, FALSE); /* now process looping */ - while (TRUE) { + while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) { WaitLock = FALSE; @@ -3002,13 +3041,16 @@ Ext2ReaperThread( /* wait until it is waken or it times out */ KeWaitForSingleObject( - &(Ext2Global->Reaper.Wait), + &Reaper->Wait, Executive, KernelMode, FALSE, &Timeout ); + if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) + break; + DidNothing = TRUE; /* acquire global exclusive lock */ @@ -3047,22 +3089,157 @@ Ext2ReaperThread( if (GlobalAcquired) { ExReleaseResourceLite(&Ext2Global->Resource); } + + KeSetEvent(&Reaper->Engine, 0, FALSE); } _SEH2_END; PsTerminateSystemThread(STATUS_SUCCESS); } +/* get the first Mcb record in Vcb->McbList */ + +BOOLEAN +Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head) +{ + struct buffer_head *bh = NULL; + PLIST_ENTRY list = NULL; + LARGE_INTEGER now; + BOOLEAN wake = FALSE; + + KeQuerySystemTime(&now); + + ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE); + while (!IsListEmpty(&Vcb->bd.bd_bh_free)) { + list = RemoveHeadList(&Vcb->bd.bd_bh_free); + bh = CONTAINING_RECORD(list, struct buffer_head, b_link); + if (atomic_read(&bh->b_count)) { + InitializeListHead(&bh->b_link); + continue; + } + + if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) || + (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart || + (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) { + InsertTailList(head, &bh->b_link); + } else { + InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link); + break; + } + } + wake = IsListEmpty(&Vcb->bd.bd_bh_free); + ExReleaseResourceLite(&Vcb->bd.bd_bh_lock); + + if (wake) + KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE); + + return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED); +} + + +/* Reaper thread to release unused buffer heads */ +VOID NTAPI +Ext2bhReaperThread( + PVOID Context +) +{ + PEXT2_REAPER Reaper = Context; + PEXT2_VCB Vcb = NULL; + LIST_ENTRY List, *Link; + LARGE_INTEGER Timeout; + + BOOLEAN GlobalAcquired = FALSE; + BOOLEAN DidNothing = FALSE; + BOOLEAN NonWait = FALSE; + + _SEH2_TRY { + + /* wake up DirverEntry */ + KeSetEvent(&Reaper->Engine, 0, FALSE); + + /* now process looping */ + while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) { + + /* wait until it is waken or it times out */ + if (NonWait) { + Timeout.QuadPart = (LONGLONG)-10*1000*10; + NonWait = FALSE; + } else if (DidNothing) { + Timeout.QuadPart = Timeout.QuadPart * 2; + } else { + Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */ + } + KeWaitForSingleObject( + &Reaper->Wait, + Executive, + KernelMode, + FALSE, + &Timeout + ); + + if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) + break; + + InitializeListHead(&List); + + /* acquire global exclusive lock */ + ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE); + GlobalAcquired = TRUE; + /* search all Vcb to get unused resources freed to system */ + for (Link = Ext2Global->VcbList.Flink; + Link != &(Ext2Global->VcbList); + Link = Link->Flink ) { + + Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next); + if (Ext2QueryUnusedBH(Vcb, &List)) + NonWait = TRUE; + } + if (GlobalAcquired) { + ExReleaseResourceLite(&Ext2Global->Resource); + GlobalAcquired = FALSE; + } + + DidNothing = IsListEmpty(&List); + while (!IsListEmpty(&List)) { + struct buffer_head *bh; + Link = RemoveHeadList(&List); + bh = CONTAINING_RECORD(Link, struct buffer_head, b_link); + ASSERT(0 == atomic_read(&bh->b_count)); + free_buffer_head(bh); + } + } + + } _SEH2_FINALLY { + + if (GlobalAcquired) { + ExReleaseResourceLite(&Ext2Global->Resource); + } + + KeSetEvent(&Reaper->Engine, 0, FALSE); + } _SEH2_END; + + PsTerminateSystemThread(STATUS_SUCCESS); +} + NTSTATUS -Ext2StartReaperThread() +Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free) { NTSTATUS status = STATUS_SUCCESS; OBJECT_ATTRIBUTES oa; HANDLE handle = 0; + LARGE_INTEGER timeout; + + Reaper->Free = Free; /* initialize wait event */ KeInitializeEvent( - &Ext2Global->Reaper.Wait, + &Reaper->Wait, + SynchronizationEvent, FALSE + ); + + /* Reaper thread engine event */ + KeInitializeEvent( + &Reaper->Engine, SynchronizationEvent, FALSE ); @@ -3083,13 +3260,45 @@ Ext2StartReaperThread() &oa, NULL, NULL, - Ext2ReaperThread, - NULL + Free, + (PVOID)Reaper ); if (NT_SUCCESS(status)) { ZwClose(handle); + + /* make sure Reaperthread is started */ + timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */ + status = KeWaitForSingleObject( + &Reaper->Engine, + Executive, + KernelMode, + FALSE, + &timeout + ); + if (status != STATUS_SUCCESS) { + status = STATUS_INSUFFICIENT_RESOURCES; + } } return status; } + + +VOID NTAPI +Ext2StopReaper(PEXT2_REAPER Reaper) +{ + LARGE_INTEGER timeout; + + Reaper->Flags |= EXT2_REAPER_FLAG_STOP; + KeSetEvent(&Reaper->Wait, 0, FALSE); + + /* make sure Reaperthread is started */ + timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */ + KeWaitForSingleObject( + &Reaper->Engine, + Executive, + KernelMode, + FALSE, + &timeout); +} diff --git a/reactos/drivers/filesystems/ext2/src/read.c b/reactos/drivers/filesystems/ext2/src/read.c index 660fd5d72f9..b01e97e1c35 100644 --- a/reactos/drivers/filesystems/ext2/src/read.c +++ b/reactos/drivers/filesystems/ext2/src/read.c @@ -582,7 +582,7 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) } else { - if (Nocache) { + if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject) { if (!ExAcquireResourceExclusiveLite( &Fcb->MainResource, @@ -592,14 +592,23 @@ Ext2ReadFile(IN PEXT2_IRP_CONTEXT IrpContext) } MainResourceAcquired = TRUE; - if (FileObject->SectionObjectPointer->DataSectionObject != NULL) { - CcFlushCache( FileObject->SectionObjectPointer, - &ByteOffset, - Length, - &Irp->IoStatus ); - if (!NT_SUCCESS(Irp->IoStatus.Status)) - _SEH2_LEAVE; + CcFlushCache(&Fcb->SectionObject, + &ByteOffset, + Length, + &Irp->IoStatus ); + if (!NT_SUCCESS(Irp->IoStatus.Status)) + _SEH2_LEAVE; + ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED); + + if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) { + ExReleaseResourceLite(&(Fcb->PagingIoResource)); } + CcPurgeCacheSection( &Fcb->SectionObject, + NULL, + 0, + FALSE ); + + ExConvertExclusiveToShared(&Fcb->MainResource); } else { diff --git a/reactos/drivers/filesystems/ext2/src/write.c b/reactos/drivers/filesystems/ext2/src/write.c index a3ddcbc5771..110014040a0 100644 --- a/reactos/drivers/filesystems/ext2/src/write.c +++ b/reactos/drivers/filesystems/ext2/src/write.c @@ -936,6 +936,11 @@ Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext) } else { + if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) { + Status = STATUS_ACCESS_DENIED; + _SEH2_LEAVE; + } + if (IsDirectory(Fcb)) { _SEH2_LEAVE; }