From 3c6af7fa787f21f8873a050568ed892312899eb5 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Thu, 24 Nov 2005 13:41:33 +0000 Subject: NTFS: Fix a potential overflow by casting (index + 1) to s64 before doing a left shift using PAGE_CACHE_SHIFT in fs/ntfs/file.c. Thanks to Andrew Morton pointing this out to. Signed-off-by: Anton Altaparmakov --- fs/ntfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ntfs') diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 72753389181..c73c8864cba 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -248,7 +248,7 @@ do_non_resident_extend: * enough to make ntfs_writepage() work. */ write_lock_irqsave(&ni->size_lock, flags); - ni->initialized_size = (index + 1) << PAGE_CACHE_SHIFT; + ni->initialized_size = (s64)(index + 1) << PAGE_CACHE_SHIFT; if (ni->initialized_size > new_init_size) ni->initialized_size = new_init_size; write_unlock_irqrestore(&ni->size_lock, flags); -- cgit v1.2.3 From 64419d93a5906600af5817ad0cae3c6ecf7fb389 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Sun, 5 Feb 2006 21:43:57 +0000 Subject: NTFS: We have struct kmem_cache now so use it instead of the typedef. Signed-off-by: Pekka Enberg Signed-off-by: Anton Altaparmakov --- fs/ntfs/ntfs.h | 10 +++++----- fs/ntfs/super.c | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'fs/ntfs') diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h index 446b5014115..653d2a5c489 100644 --- a/fs/ntfs/ntfs.h +++ b/fs/ntfs/ntfs.h @@ -50,11 +50,11 @@ typedef enum { /* Global variables. */ /* Slab caches (from super.c). */ -extern kmem_cache_t *ntfs_name_cache; -extern kmem_cache_t *ntfs_inode_cache; -extern kmem_cache_t *ntfs_big_inode_cache; -extern kmem_cache_t *ntfs_attr_ctx_cache; -extern kmem_cache_t *ntfs_index_ctx_cache; +extern struct kmem_cache *ntfs_name_cache; +extern struct kmem_cache *ntfs_inode_cache; +extern struct kmem_cache *ntfs_big_inode_cache; +extern struct kmem_cache *ntfs_attr_ctx_cache; +extern struct kmem_cache *ntfs_index_ctx_cache; /* The various operations structs defined throughout the driver files. */ extern struct address_space_operations ntfs_aops; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index c3a3f1a8310..e9c0d80dfab 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2987,14 +2987,14 @@ err_out_now: * strings of the maximum length allowed by NTFS, which is NTFS_MAX_NAME_LEN * (255) Unicode characters + a terminating NULL Unicode character. */ -kmem_cache_t *ntfs_name_cache; +struct kmem_cache *ntfs_name_cache; /* Slab caches for efficient allocation/deallocation of inodes. */ -kmem_cache_t *ntfs_inode_cache; -kmem_cache_t *ntfs_big_inode_cache; +struct kmem_cache *ntfs_inode_cache; +struct kmem_cache *ntfs_big_inode_cache; /* Init once constructor for the inode slab cache. */ -static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep, +static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep, unsigned long flags) { ntfs_inode *ni = (ntfs_inode *)foo; @@ -3008,8 +3008,8 @@ static void ntfs_big_inode_init_once(void *foo, kmem_cache_t *cachep, * Slab caches to optimize allocations and deallocations of attribute search * contexts and index contexts, respectively. */ -kmem_cache_t *ntfs_attr_ctx_cache; -kmem_cache_t *ntfs_index_ctx_cache; +struct kmem_cache *ntfs_attr_ctx_cache; +struct kmem_cache *ntfs_index_ctx_cache; /* Driver wide semaphore. */ DECLARE_MUTEX(ntfs_lock); -- cgit v1.2.3 From 3672b638ec1d5b1020ea27986060b830f09c96c1 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 24 Feb 2006 09:55:07 +0000 Subject: NTFS: - Cope with attribute list attribute having invalid flags. Windows copes with this and even chkdsk does not detect or fix this so we have to cope with it, too. Thanks to Pawel Kot for reporting the problem. - Miscellaneous updates to layout.h. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 28 +++++++++++++++++++--------- fs/ntfs/inode.c | 49 +++++++++++++++++++++++++++++++++++++++---------- fs/ntfs/layout.h | 25 ++++++++++++++++++------- 3 files changed, 76 insertions(+), 26 deletions(-) (limited to 'fs/ntfs') diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 02f44094bda..4a62201e844 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -1,9 +1,9 @@ ToDo/Notes: - Find and fix bugs. - The only places in the kernel where a file is resized are - ntfs_file_write*() and ntfs_truncate() for both of which i_sem is + ntfs_file_write*() and ntfs_truncate() for both of which i_mutex is held. Just have to be careful in read-/writepage and other helpers - not running under i_sem that we play nice... Also need to be careful + not running under i_mutex that we play nice. Also need to be careful with initialized_size extension in ntfs_file_write*() and writepage. UPDATE: The only things that need to be checked are the compressed write and the other attribute resize/write cases like index @@ -19,6 +19,16 @@ ToDo/Notes: - Enable the code for setting the NT4 compatibility flag when we start making NTFS 1.2 specific modifications. +2.1.26 - Minor bug fixes and updates. + + - We have struct kmem_cache now so use it instead of the typedef + kmem_cache_t. (Pekka Enberg) + - Miscellaneous updates to layout.h. + - Cope with attribute list attribute having invalid flags. Windows + copes with this and even chkdsk does not detect or fix this so we + have to cope with it, too. Thanks to Pawel Kot for reporting the + problem. + 2.1.25 - (Almost) fully implement write(2) and truncate(2). - Change ntfs_map_runlist_nolock(), ntfs_attr_find_vcn_nolock() and @@ -373,7 +383,7 @@ ToDo/Notes: single one of them had an mst error. (Thanks to Ken MacFerrin for the bug report.) - Fix error handling in fs/ntfs/quota.c::ntfs_mark_quotas_out_of_date() - where we failed to release i_sem on the $Quota/$Q attribute inode. + where we failed to release i_mutex on the $Quota/$Q attribute inode. - Fix bug in handling of bad inodes in fs/ntfs/namei.c::ntfs_lookup(). - Add mapping of unmapped buffers to all remaining code paths, i.e. fs/ntfs/aops.c::ntfs_write_mst_block(), mft.c::ntfs_sync_mft_mirror(), @@ -874,7 +884,7 @@ ToDo/Notes: clusters. (Philipp Thomas) - attrib.c::load_attribute_list(): Fix bug when initialized_size is a multiple of the block_size but not the cluster size. (Szabolcs - Szakacsits ) + Szakacsits) 2.1.2 - Important bug fixes aleviating the hangs in statfs. @@ -884,7 +894,7 @@ ToDo/Notes: - Add handling for initialized_size != data_size in compressed files. - Reduce function local stack usage from 0x3d4 bytes to just noise in - fs/ntfs/upcase.c. (Randy Dunlap ) + fs/ntfs/upcase.c. (Randy Dunlap) - Remove compiler warnings for newer gcc. - Pages are no longer kmapped by mm/filemap.c::generic_file_write() around calls to ->{prepare,commit}_write. Adapt NTFS appropriately @@ -1201,11 +1211,11 @@ ToDo/Notes: the kernel. We probably want a kernel generic init_address_space() function... - Drop BKL from ntfs_readdir() after consultation with Al Viro. The - only caller of ->readdir() is vfs_readdir() which holds i_sem during - the call, and i_sem is sufficient protection against changes in the - directory inode (including ->i_size). + only caller of ->readdir() is vfs_readdir() which holds i_mutex + during the call, and i_mutex is sufficient protection against changes + in the directory inode (including ->i_size). - Use generic_file_llseek() for directories (as opposed to - default_llseek()) as this downs i_sem instead of the BKL which is + default_llseek()) as this downs i_mutex instead of the BKL which is what we now need for exclusion against ->f_pos changes considering we no longer take the BKL in ntfs_readdir(). diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index ea1bd3feea1..55263b7de9c 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -677,13 +677,28 @@ static int ntfs_read_locked_inode(struct inode *vi) ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); NInoSetAttrList(ni); a = ctx->attr; - if (a->flags & ATTR_IS_ENCRYPTED || - a->flags & ATTR_COMPRESSION_MASK || - a->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(vi->i_sb, "Attribute list attribute is " - "compressed/encrypted/sparse."); + "compressed."); goto unm_err_out; } + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_IS_SPARSE) { + if (a->non_resident) { + ntfs_error(vi->i_sb, "Non-resident attribute " + "list attribute is encrypted/" + "sparse."); + goto unm_err_out; + } + ntfs_warning(vi->i_sb, "Resident attribute list " + "attribute in inode 0x%lx is marked " + "encrypted/sparse which is not true. " + "However, Windows allows this and " + "chkdsk does not detect or correct it " + "so we will just ignore the invalid " + "flags and pretend they are not set.", + vi->i_ino); + } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); @@ -1809,19 +1824,33 @@ int ntfs_read_inode_mount(struct inode *vi) } else /* if (!err) */ { ATTR_LIST_ENTRY *al_entry, *next_al_entry; u8 *al_end; + static const char *es = " Not allowed. $MFT is corrupt. " + "You should run chkdsk."; ntfs_debug("Attribute list attribute found in $MFT."); NInoSetAttrList(ni); a = ctx->attr; - if (a->flags & ATTR_IS_ENCRYPTED || - a->flags & ATTR_COMPRESSION_MASK || - a->flags & ATTR_IS_SPARSE) { + if (a->flags & ATTR_COMPRESSION_MASK) { ntfs_error(sb, "Attribute list attribute is " - "compressed/encrypted/sparse. Not " - "allowed. $MFT is corrupt. You should " - "run chkdsk."); + "compressed.%s", es); goto put_err_out; } + if (a->flags & ATTR_IS_ENCRYPTED || + a->flags & ATTR_IS_SPARSE) { + if (a->non_resident) { + ntfs_error(sb, "Non-resident attribute list " + "attribute is encrypted/" + "sparse.%s", es); + goto put_err_out; + } + ntfs_warning(sb, "Resident attribute list attribute " + "in $MFT system file is marked " + "encrypted/sparse which is not true. " + "However, Windows allows this and " + "chkdsk does not detect or correct it " + "so we will just ignore the invalid " + "flags and pretend they are not set."); + } /* Now allocate memory for the attribute list. */ ni->attr_list_size = (u32)ntfs_attr_size(a); ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index f5678d5d791..bb408d4dcbb 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h @@ -838,15 +838,19 @@ enum { F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask is used to to obtain all flags that are valid for setting. */ - /* - * The following flags are only present in the FILE_NAME attribute (in + * The following flag is only present in the FILE_NAME attribute (in * the field file_attributes). */ FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = const_cpu_to_le32(0x10000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this is a directory or not, i.e. whether it has an index root attribute or not. */ + /* + * The following flag is present both in the STANDARD_INFORMATION + * attribute and in the FILE_NAME attribute (in the field + * file_attributes). + */ FILE_ATTR_DUP_VIEW_INDEX_PRESENT = const_cpu_to_le32(0x20000000), /* Note, this is a copy of the corresponding bit from the mft record, telling us whether this file has a view index present (eg. object id @@ -1071,9 +1075,15 @@ typedef struct { modified. */ /* 20*/ sle64 last_access_time; /* Time this mft record was last accessed. */ -/* 28*/ sle64 allocated_size; /* Byte size of allocated space for the - data attribute. NOTE: Is a multiple - of the cluster size. */ +/* 28*/ sle64 allocated_size; /* Byte size of on-disk allocated space + for the data attribute. So for + normal $DATA, this is the + allocated_size from the unnamed + $DATA attribute and for compressed + and/or sparse $DATA, this is the + compressed_size from the unnamed + $DATA attribute. NOTE: This is a + multiple of the cluster size. */ /* 30*/ sle64 data_size; /* Byte size of actual data in data attribute. */ /* 38*/ FILE_ATTR_FLAGS file_attributes; /* Flags describing the file. */ @@ -1904,12 +1914,13 @@ enum { VOLUME_DELETE_USN_UNDERWAY = const_cpu_to_le16(0x0010), VOLUME_REPAIR_OBJECT_ID = const_cpu_to_le16(0x0020), + VOLUME_CHKDSK_UNDERWAY = const_cpu_to_le16(0x4000), VOLUME_MODIFIED_BY_CHKDSK = const_cpu_to_le16(0x8000), - VOLUME_FLAGS_MASK = const_cpu_to_le16(0x803f), + VOLUME_FLAGS_MASK = const_cpu_to_le16(0xc03f), /* To make our life easier when checking if we must mount read-only. */ - VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8027), + VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0xc027), } __attribute__ ((__packed__)); typedef le16 VOLUME_FLAGS; -- cgit v1.2.3 From 78af34f03d33d2ba179c9d35685860170b94a285 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 24 Feb 2006 10:32:33 +0000 Subject: NTFS: Implement support for sector sizes above 512 bytes (up to the maximum supported by NTFS which is 4096 bytes). --- fs/ntfs/ChangeLog | 6 +++ fs/ntfs/aops.c | 18 +++---- fs/ntfs/file.c | 8 +-- fs/ntfs/mft.c | 8 +-- fs/ntfs/super.c | 151 +++++++++++++++++++++++++++++++++++------------------- 5 files changed, 121 insertions(+), 70 deletions(-) (limited to 'fs/ntfs') diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 4a62201e844..e66b4ac2fad 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -21,8 +21,14 @@ ToDo/Notes: 2.1.26 - Minor bug fixes and updates. + - Fix a potential overflow in file.c where a cast to s64 was missing in + a left shift of a page index. + - The struct inode has had its i_sem semaphore changed to a mutex named + i_mutex. - We have struct kmem_cache now so use it instead of the typedef kmem_cache_t. (Pekka Enberg) + - Implement support for sector sizes above 512 bytes (up to the maximum + supported by NTFS which is 4096 bytes). - Miscellaneous updates to layout.h. - Cope with attribute list attribute having invalid flags. Windows copes with this and even chkdsk does not detect or fix this so we diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 1c0a4315876..7e361da770b 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -2,7 +2,7 @@ * aops.c - NTFS kernel address space operations and page cache handling. * Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -200,8 +200,8 @@ static int ntfs_read_block(struct page *page) /* $MFT/$DATA must have its complete runlist in memory at all times. */ BUG_ON(!ni->runlist.rl && !ni->mft_no && !NInoAttr(ni)); - blocksize_bits = VFS_I(ni)->i_blkbits; - blocksize = 1 << blocksize_bits; + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; if (!page_has_buffers(page)) { create_empty_buffers(page, blocksize, 0); @@ -569,10 +569,8 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc) BUG_ON(!NInoNonResident(ni)); BUG_ON(NInoMstProtected(ni)); - - blocksize_bits = vi->i_blkbits; - blocksize = 1 << blocksize_bits; - + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; if (!page_has_buffers(page)) { BUG_ON(!PageUptodate(page)); create_empty_buffers(page, blocksize, @@ -949,8 +947,8 @@ static int ntfs_write_mst_block(struct page *page, */ BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) || (NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION))); - bh_size_bits = vi->i_blkbits; - bh_size = 1 << bh_size_bits; + bh_size = vol->sb->s_blocksize; + bh_size_bits = vol->sb->s_blocksize_bits; max_bhs = PAGE_CACHE_SIZE / bh_size; BUG_ON(!max_bhs); BUG_ON(max_bhs > MAX_BUF_PER_PAGE); @@ -1596,7 +1594,7 @@ void mark_ntfs_record_dirty(struct page *page, const unsigned int ofs) { BUG_ON(!PageUptodate(page)); end = ofs + ni->itype.index.block_size; - bh_size = 1 << VFS_I(ni)->i_blkbits; + bh_size = VFS_I(ni)->i_sb->s_blocksize; spin_lock(&mapping->private_lock); if (unlikely(!page_has_buffers(page))) { spin_unlock(&mapping->private_lock); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 3a119a87686..5027d3d1b3f 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1,7 +1,7 @@ /* * file.c - NTFS kernel file operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -529,8 +529,8 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages, "index 0x%lx, nr_pages 0x%x, pos 0x%llx, bytes 0x%zx.", vi->i_ino, ni->type, pages[0]->index, nr_pages, (long long)pos, bytes); - blocksize_bits = vi->i_blkbits; - blocksize = 1 << blocksize_bits; + blocksize = vol->sb->s_blocksize; + blocksize_bits = vol->sb->s_blocksize_bits; u = 0; do { struct page *page = pages[u]; @@ -1525,7 +1525,7 @@ static inline int ntfs_commit_pages_after_non_resident_write( vi = pages[0]->mapping->host; ni = NTFS_I(vi); - blocksize = 1 << vi->i_blkbits; + blocksize = vi->i_sb->s_blocksize; end = pos + bytes; u = 0; do { diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 0c65cbb8c5c..6499aafc225 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -1,7 +1,7 @@ /** * mft.c - NTFS kernel mft record operations. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -473,7 +473,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, runlist_element *rl; unsigned int block_start, block_end, m_start, m_end, page_ofs; int i_bhs, nr_bhs, err = 0; - unsigned char blocksize_bits = vol->mftmirr_ino->i_blkbits; + unsigned char blocksize_bits = vol->sb->s_blocksize_bits; ntfs_debug("Entering for inode 0x%lx.", mft_no); BUG_ON(!max_bhs); @@ -672,8 +672,8 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) { ntfs_volume *vol = ni->vol; struct page *page = ni->page; - unsigned char blocksize_bits = vol->mft_ino->i_blkbits; - unsigned int blocksize = 1 << blocksize_bits; + unsigned int blocksize = vol->sb->s_blocksize; + unsigned char blocksize_bits = vol->sb->s_blocksize_bits; int max_bhs = vol->mft_record_size / blocksize; struct buffer_head *bhs[max_bhs]; struct buffer_head *bh, *head; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index e9c0d80dfab..489f7049146 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -1,7 +1,7 @@ /* * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2001,2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -22,6 +22,7 @@ #include #include +#include #include #include #include /* For bdev_hardsect_size(). */ @@ -641,7 +642,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb, { const char *read_err_str = "Unable to read %s boot sector."; struct buffer_head *bh_primary, *bh_backup; - long nr_blocks = NTFS_SB(sb)->nr_blocks; + sector_t nr_blocks = NTFS_SB(sb)->nr_blocks; /* Try to read primary boot sector. */ if ((bh_primary = sb_bread(sb, 0))) { @@ -688,13 +689,18 @@ hotfix_primary_boot_sector: /* * If we managed to read sector zero and the volume is not * read-only, copy the found, valid backup boot sector to the - * primary boot sector. + * primary boot sector. Note we only copy the actual boot + * sector structure, not the actual whole device sector as that + * may be bigger and would potentially damage the $Boot system + * file (FIXME: Would be nice to know if the backup boot sector + * on a large sector device contains the whole boot loader or + * just the first 512 bytes). */ if (!(sb->s_flags & MS_RDONLY)) { ntfs_warning(sb, "Hot-fix: Recovering invalid primary " "boot sector from backup copy."); memcpy(bh_primary->b_data, bh_backup->b_data, - sb->s_blocksize); + NTFS_BLOCK_SIZE); mark_buffer_dirty(bh_primary); sync_dirty_buffer(bh_primary); if (buffer_uptodate(bh_primary)) { @@ -733,9 +739,13 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) vol->sector_size); ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits, vol->sector_size_bits); - if (vol->sector_size != vol->sb->s_blocksize) - ntfs_warning(vol->sb, "The boot sector indicates a sector size " - "different from the device sector size."); + if (vol->sector_size < vol->sb->s_blocksize) { + ntfs_error(vol->sb, "Sector size (%i) is smaller than the " + "device block size (%lu). This is not " + "supported. Sorry.", vol->sector_size, + vol->sb->s_blocksize); + return FALSE; + } ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster); sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1; ntfs_debug("sectors_per_cluster_bits = 0x%x", @@ -748,16 +758,11 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size, vol->cluster_size); ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask); - ntfs_debug("vol->cluster_size_bits = %i (0x%x)", - vol->cluster_size_bits, vol->cluster_size_bits); - if (vol->sector_size > vol->cluster_size) { - ntfs_error(vol->sb, "Sector sizes above the cluster size are " - "not supported. Sorry."); - return FALSE; - } - if (vol->sb->s_blocksize > vol->cluster_size) { - ntfs_error(vol->sb, "Cluster sizes smaller than the device " - "sector size are not supported. Sorry."); + ntfs_debug("vol->cluster_size_bits = %i", vol->cluster_size_bits); + if (vol->cluster_size < vol->sector_size) { + ntfs_error(vol->sb, "Cluster size (%i) is smaller than the " + "sector size (%i). This is not supported. " + "Sorry.", vol->cluster_size, vol->sector_size); return FALSE; } clusters_per_mft_record = b->clusters_per_mft_record; @@ -786,11 +791,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) * we store $MFT/$DATA, the table of mft records in the page cache. */ if (vol->mft_record_size > PAGE_CACHE_SIZE) { - ntfs_error(vol->sb, "Mft record size %i (0x%x) exceeds the " - "page cache size on your system %lu (0x%lx). " + ntfs_error(vol->sb, "Mft record size (%i) exceeds the " + "PAGE_CACHE_SIZE on your system (%lu). " "This is not supported. Sorry.", - vol->mft_record_size, vol->mft_record_size, - PAGE_CACHE_SIZE, PAGE_CACHE_SIZE); + vol->mft_record_size, PAGE_CACHE_SIZE); + return FALSE; + } + /* We cannot support mft record sizes below the sector size. */ + if (vol->mft_record_size < vol->sector_size) { + ntfs_error(vol->sb, "Mft record size (%i) is smaller than the " + "sector size (%i). This is not supported. " + "Sorry.", vol->mft_record_size, + vol->sector_size); return FALSE; } clusters_per_index_record = b->clusters_per_index_record; @@ -816,6 +828,14 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ntfs_debug("vol->index_record_size_bits = %i (0x%x)", vol->index_record_size_bits, vol->index_record_size_bits); + /* We cannot support index record sizes below the sector size. */ + if (vol->index_record_size < vol->sector_size) { + ntfs_error(vol->sb, "Index record size (%i) is smaller than " + "the sector size (%i). This is not " + "supported. Sorry.", vol->index_record_size, + vol->sector_size); + return FALSE; + } /* * Get the size of the volume in clusters and check for 64-bit-ness. * Windows currently only uses 32 bits to save the clusters so we do @@ -845,15 +865,18 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) } ll = sle64_to_cpu(b->mft_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird."); + ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of " + "volume. Weird.", (unsigned long long)ll, + (unsigned long long)ll); return FALSE; } vol->mft_lcn = ll; ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); ll = sle64_to_cpu(b->mftmirr_lcn); if (ll >= vol->nr_clusters) { - ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. " - "Weird."); + ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end " + "of volume. Weird.", (unsigned long long)ll, + (unsigned long long)ll); return FALSE; } vol->mftmirr_lcn = ll; @@ -2685,7 +2708,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ntfs_volume *vol; struct buffer_head *bh; struct inode *tmp_ino; - int result; + int blocksize, result; ntfs_debug("Entering."); #ifndef NTFS_RW @@ -2724,60 +2747,85 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) if (!parse_options(vol, (char*)opt)) goto err_out_now; + /* We support sector sizes up to the PAGE_CACHE_SIZE. */ + if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) { + if (!silent) + ntfs_error(sb, "Device has unsupported sector size " + "(%i). The maximum supported sector " + "size on this architecture is %lu " + "bytes.", + bdev_hardsect_size(sb->s_bdev), + PAGE_CACHE_SIZE); + goto err_out_now; + } /* - * TODO: Fail safety check. In the future we should really be able to - * cope with this being the case, but for now just bail out. + * Setup the device access block size to NTFS_BLOCK_SIZE or the hard + * sector size, whichever is bigger. */ - if (bdev_hardsect_size(sb->s_bdev) > NTFS_BLOCK_SIZE) { + blocksize = sb_min_blocksize(sb, NTFS_BLOCK_SIZE); + if (blocksize < NTFS_BLOCK_SIZE) { if (!silent) - ntfs_error(sb, "Device has unsupported hardsect_size."); + ntfs_error(sb, "Unable to set device block size."); goto err_out_now; } - - /* Setup the device access block size to NTFS_BLOCK_SIZE. */ - if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) { + BUG_ON(blocksize != sb->s_blocksize); + ntfs_debug("Set device block size to %i bytes (block size bits %i).", + blocksize, sb->s_blocksize_bits); + /* Determine the size of the device in units of block_size bytes. */ + if (!i_size_read(sb->s_bdev->bd_inode)) { if (!silent) - ntfs_error(sb, "Unable to set block size."); + ntfs_error(sb, "Unable to determine device size."); goto err_out_now; } - - /* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */ vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> - NTFS_BLOCK_SIZE_BITS; - + sb->s_blocksize_bits; /* Read the boot sector and return unlocked buffer head to it. */ if (!(bh = read_ntfs_boot_sector(sb, silent))) { if (!silent) ntfs_error(sb, "Not an NTFS volume."); goto err_out_now; } - /* - * Extract the data from the boot sector and setup the ntfs super block + * Extract the data from the boot sector and setup the ntfs volume * using it. */ result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); - - /* Initialize the cluster and mft allocators. */ - ntfs_setup_allocators(vol); - brelse(bh); - if (!result) { if (!silent) ntfs_error(sb, "Unsupported NTFS filesystem."); goto err_out_now; } - /* - * TODO: When we start coping with sector sizes different from - * NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the - * device (probably to NTFS_BLOCK_SIZE). + * If the boot sector indicates a sector size bigger than the current + * device block size, switch the device block size to the sector size. + * TODO: It may be possible to support this case even when the set + * below fails, we would just be breaking up the i/o for each sector + * into multiple blocks for i/o purposes but otherwise it should just + * work. However it is safer to leave disabled until someone hits this + * error message and then we can get them to try it without the setting + * so we know for sure that it works. */ - + if (vol->sector_size > blocksize) { + blocksize = sb_set_blocksize(sb, vol->sector_size); + if (blocksize != vol->sector_size) { + if (!silent) + ntfs_error(sb, "Unable to set device block " + "size to sector size (%i).", + vol->sector_size); + goto err_out_now; + } + BUG_ON(blocksize != sb->s_blocksize); + vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> + sb->s_blocksize_bits; + ntfs_debug("Changed device block size to %i bytes (block size " + "bits %i) to match volume sector size.", + blocksize, sb->s_blocksize_bits); + } + /* Initialize the cluster and mft allocators. */ + ntfs_setup_allocators(vol); /* Setup remaining fields in the super block. */ sb->s_magic = NTFS_SB_MAGIC; - /* * Ntfs allows 63 bits for the file size, i.e. correct would be: * sb->s_maxbytes = ~0ULL >> 1; @@ -2787,9 +2835,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) * without overflowing the index or to 2^63 - 1, whichever is smaller. */ sb->s_maxbytes = MAX_LFS_FILESIZE; - + /* Ntfs measures time in 100ns intervals. */ sb->s_time_gran = 100; - /* * Now load the metadata required for the page cache and our address * space operations to function. We do this by setting up a specialised -- cgit v1.2.3 From 1cf3109ffb26a6ea572fd02436bd10458b4b2187 Mon Sep 17 00:00:00 2001 From: Anton Altaparmakov Date: Fri, 24 Feb 2006 10:48:14 +0000 Subject: NTFS: Do more detailed reporting of why we cannot mount read-write by special casing the VOLUME_MODIFIED_BY_CHKDSK flag. Signed-off-by: Anton Altaparmakov --- fs/ntfs/ChangeLog | 2 ++ fs/ntfs/Makefile | 2 +- fs/ntfs/super.c | 34 +++++++++++++++++++++++++++------- fs/ntfs/upcase.c | 10 ++++------ fs/ntfs/volume.h | 28 +++++++++++++--------------- 5 files changed, 47 insertions(+), 29 deletions(-) (limited to 'fs/ntfs') diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index e66b4ac2fad..9d8ffa89e2c 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -29,6 +29,8 @@ ToDo/Notes: kmem_cache_t. (Pekka Enberg) - Implement support for sector sizes above 512 bytes (up to the maximum supported by NTFS which is 4096 bytes). + - Do more detailed reporting of why we cannot mount read-write by + special casing the VOLUME_MODIFIED_BY_CHKDSK flag. - Miscellaneous updates to layout.h. - Cope with attribute list attribute having invalid flags. Windows copes with this and even chkdsk does not detect or fix this so we diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile index d0d45d1c853..d95fac7fdeb 100644 --- a/fs/ntfs/Makefile +++ b/fs/ntfs/Makefile @@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \ index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \ unistr.o upcase.o -EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.25\" +EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.26\" ifeq ($(CONFIG_NTFS_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 489f7049146..368a8ec1066 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -472,9 +472,16 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) ntfs_error(sb, "Volume is dirty and read-only%s", es); return -EROFS; } + if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { + ntfs_error(sb, "Volume has been modified by chkdsk " + "and is read-only%s", es); + return -EROFS; + } if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { - ntfs_error(sb, "Volume has unsupported flags set and " - "is read-only%s", es); + ntfs_error(sb, "Volume has unsupported flags set " + "(0x%x) and is read-only%s", + (unsigned)le16_to_cpu(vol->vol_flags), + es); return -EROFS; } if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { @@ -1845,11 +1852,24 @@ get_ctx_vol_failed: /* Make sure that no unsupported volume flags are set. */ if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { static const char *es1a = "Volume is dirty"; - static const char *es1b = "Volume has unsupported flags set"; - static const char *es2 = ". Run chkdsk and mount in Windows."; - const char *es1; - - es1 = vol->vol_flags & VOLUME_IS_DIRTY ? es1a : es1b; + static const char *es1b = "Volume has been modified by chkdsk"; + static const char *es1c = "Volume has unsupported flags set"; + static const char *es2a = ". Run chkdsk and mount in Windows."; + static const char *es2b = ". Mount in Windows."; + const char *es1, *es2; + + es2 = es2a; + if (vol->vol_flags & VOLUME_IS_DIRTY) + es1 = es1a; + else if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { + es1 = es1b; + es2 = es2b; + } else { + es1 = es1c; + ntfs_warning(sb, "Unsupported volume flags 0x%x " + "encountered.", + (unsigned)le16_to_cpu(vol->vol_flags)); + } /* If a read-write mount, convert it to a read-only mount. */ if (!(sb->s_flags & MS_RDONLY)) { if (!(vol->on_errors & (ON_ERRORS_REMOUNT_RO | diff --git a/fs/ntfs/upcase.c b/fs/ntfs/upcase.c index 879cdf1d5bd..9101807dc81 100644 --- a/fs/ntfs/upcase.c +++ b/fs/ntfs/upcase.c @@ -3,10 +3,7 @@ * Part of the Linux-NTFS project. * * Copyright (c) 2001 Richard Russon - * Copyright (c) 2001-2004 Anton Altaparmakov - * - * Modified for mkntfs inclusion 9 June 2001 by Anton Altaparmakov. - * Modified for kernel inclusion 10 September 2001 by Anton Altparmakov. + * Copyright (c) 2001-2006 Anton Altaparmakov * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -75,12 +72,13 @@ ntfschar *generate_default_upcase(void) if (!uc) return uc; memset(uc, 0, default_upcase_len * sizeof(ntfschar)); + /* Generate the little endian Unicode upcase table used by ntfs. */ for (i = 0; i < default_upcase_len; i++) uc[i] = cpu_to_le16(i); for (r = 0; uc_run_table[r][0]; r++) for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++) - uc[i] = cpu_to_le16((le16_to_cpu(uc[i]) + - uc_run_table[r][2])); + uc[i] = cpu_to_le16(le16_to_cpu(uc[i]) + + uc_run_table[r][2]); for (r = 0; uc_dup_table[r][0]; r++) for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2) uc[i + 1] = cpu_to_le16(le16_to_cpu(uc[i + 1]) - 1); diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h index 375cd20a9f6..406ab55dfb3 100644 --- a/fs/ntfs/volume.h +++ b/fs/ntfs/volume.h @@ -2,7 +2,7 @@ * volume.h - Defines for volume structures in NTFS Linux kernel driver. Part * of the Linux-NTFS project. * - * Copyright (c) 2001-2005 Anton Altaparmakov + * Copyright (c) 2001-2006 Anton Altaparmakov * Copyright (c) 2002 Richard Russon * * This program/include file is free software; you can redistribute it and/or @@ -41,10 +41,8 @@ typedef struct { * structure has stabilized... (AIA) */ /* Device specifics. */ - struct super_block *sb; /* Pointer back to the super_block, - so we don't have to get the offset - every time. */ - LCN nr_blocks; /* Number of NTFS_BLOCK_SIZE bytes + struct super_block *sb; /* Pointer back to the super_block. */ + LCN nr_blocks; /* Number of sb->s_blocksize bytes sized blocks on the device. */ /* Configuration provided by user at mount time. */ unsigned long flags; /* Miscellaneous flags, see below. */ @@ -141,8 +139,8 @@ typedef enum { NV_ShowSystemFiles, /* 1: Return system files in ntfs_readdir(). */ NV_CaseSensitive, /* 1: Treat file names as case sensitive and create filenames in the POSIX namespace. - Otherwise be case insensitive and create - file names in WIN32 namespace. */ + Otherwise be case insensitive but still + create file names in POSIX namespace. */ NV_LogFileEmpty, /* 1: $LogFile journal is empty. */ NV_QuotaOutOfDate, /* 1: $Quota is out of date. */ NV_UsnJrnlStamped, /* 1: $UsnJrnl has been stamped. */ @@ -153,7 +151,7 @@ typedef enum { * Macro tricks to expand the NVolFoo(), NVolSetFoo(), and NVolClearFoo() * functions. */ -#define NVOL_FNS(flag) \ +#define DEFINE_NVOL_BIT_OPS(flag) \ static inline int NVol##flag(ntfs_volume *vol) \ { \ return test_bit(NV_##flag, &(vol)->flags); \ @@ -168,12 +166,12 @@ static inline void NVolClear##flag(ntfs_volume *vol) \ } /* Emit the ntfs volume bitops functions. */ -NVOL_FNS(Errors) -NVOL_FNS(ShowSystemFiles) -NVOL_FNS(CaseSensitive) -NVOL_FNS(LogFileEmpty) -NVOL_FNS(QuotaOutOfDate) -NVOL_FNS(UsnJrnlStamped) -NVOL_FNS(SparseEnabled) +DEFINE_NVOL_BIT_OPS(Errors) +DEFINE_NVOL_BIT_OPS(ShowSystemFiles) +DEFINE_NVOL_BIT_OPS(CaseSensitive) +DEFINE_NVOL_BIT_OPS(LogFileEmpty) +DEFINE_NVOL_BIT_OPS(QuotaOutOfDate) +DEFINE_NVOL_BIT_OPS(UsnJrnlStamped) +DEFINE_NVOL_BIT_OPS(SparseEnabled) #endif /* _LINUX_NTFS_VOLUME_H */ -- cgit v1.2.3