diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2006-02-24 05:32:33 -0500 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2006-02-24 05:32:33 -0500 |
commit | 78af34f03d33d2ba179c9d35685860170b94a285 (patch) | |
tree | dc41d99f07193a581e7dd3734671c3854aa185eb /fs/ntfs/super.c | |
parent | 7b875affd49fbc8978a1a898a0a80ebfff11f8c6 (diff) |
NTFS: Implement support for sector sizes above 512 bytes (up to the maximum
supported by NTFS which is 4096 bytes).
Diffstat (limited to 'fs/ntfs/super.c')
-rw-r--r-- | fs/ntfs/super.c | 151 |
1 files changed, 99 insertions, 52 deletions
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index e9c0d80dfab1..489f7049146b 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. | 2 | * super.c - NTFS kernel super block handling. Part of the Linux-NTFS project. |
3 | * | 3 | * |
4 | * Copyright (c) 2001-2005 Anton Altaparmakov | 4 | * Copyright (c) 2001-2006 Anton Altaparmakov |
5 | * Copyright (c) 2001,2002 Richard Russon | 5 | * Copyright (c) 2001,2002 Richard Russon |
6 | * | 6 | * |
7 | * This program/include file is free software; you can redistribute it and/or | 7 | * This program/include file is free software; you can redistribute it and/or |
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <linux/stddef.h> | 23 | #include <linux/stddef.h> |
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/slab.h> | ||
25 | #include <linux/string.h> | 26 | #include <linux/string.h> |
26 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
27 | #include <linux/blkdev.h> /* For bdev_hardsect_size(). */ | 28 | #include <linux/blkdev.h> /* For bdev_hardsect_size(). */ |
@@ -641,7 +642,7 @@ static struct buffer_head *read_ntfs_boot_sector(struct super_block *sb, | |||
641 | { | 642 | { |
642 | const char *read_err_str = "Unable to read %s boot sector."; | 643 | const char *read_err_str = "Unable to read %s boot sector."; |
643 | struct buffer_head *bh_primary, *bh_backup; | 644 | struct buffer_head *bh_primary, *bh_backup; |
644 | long nr_blocks = NTFS_SB(sb)->nr_blocks; | 645 | sector_t nr_blocks = NTFS_SB(sb)->nr_blocks; |
645 | 646 | ||
646 | /* Try to read primary boot sector. */ | 647 | /* Try to read primary boot sector. */ |
647 | if ((bh_primary = sb_bread(sb, 0))) { | 648 | if ((bh_primary = sb_bread(sb, 0))) { |
@@ -688,13 +689,18 @@ hotfix_primary_boot_sector: | |||
688 | /* | 689 | /* |
689 | * If we managed to read sector zero and the volume is not | 690 | * If we managed to read sector zero and the volume is not |
690 | * read-only, copy the found, valid backup boot sector to the | 691 | * read-only, copy the found, valid backup boot sector to the |
691 | * primary boot sector. | 692 | * primary boot sector. Note we only copy the actual boot |
693 | * sector structure, not the actual whole device sector as that | ||
694 | * may be bigger and would potentially damage the $Boot system | ||
695 | * file (FIXME: Would be nice to know if the backup boot sector | ||
696 | * on a large sector device contains the whole boot loader or | ||
697 | * just the first 512 bytes). | ||
692 | */ | 698 | */ |
693 | if (!(sb->s_flags & MS_RDONLY)) { | 699 | if (!(sb->s_flags & MS_RDONLY)) { |
694 | ntfs_warning(sb, "Hot-fix: Recovering invalid primary " | 700 | ntfs_warning(sb, "Hot-fix: Recovering invalid primary " |
695 | "boot sector from backup copy."); | 701 | "boot sector from backup copy."); |
696 | memcpy(bh_primary->b_data, bh_backup->b_data, | 702 | memcpy(bh_primary->b_data, bh_backup->b_data, |
697 | sb->s_blocksize); | 703 | NTFS_BLOCK_SIZE); |
698 | mark_buffer_dirty(bh_primary); | 704 | mark_buffer_dirty(bh_primary); |
699 | sync_dirty_buffer(bh_primary); | 705 | sync_dirty_buffer(bh_primary); |
700 | if (buffer_uptodate(bh_primary)) { | 706 | if (buffer_uptodate(bh_primary)) { |
@@ -733,9 +739,13 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) | |||
733 | vol->sector_size); | 739 | vol->sector_size); |
734 | ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits, | 740 | ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits, |
735 | vol->sector_size_bits); | 741 | vol->sector_size_bits); |
736 | if (vol->sector_size != vol->sb->s_blocksize) | 742 | if (vol->sector_size < vol->sb->s_blocksize) { |
737 | ntfs_warning(vol->sb, "The boot sector indicates a sector size " | 743 | ntfs_error(vol->sb, "Sector size (%i) is smaller than the " |
738 | "different from the device sector size."); | 744 | "device block size (%lu). This is not " |
745 | "supported. Sorry.", vol->sector_size, | ||
746 | vol->sb->s_blocksize); | ||
747 | return FALSE; | ||
748 | } | ||
739 | ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster); | 749 | ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster); |
740 | sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1; | 750 | sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1; |
741 | ntfs_debug("sectors_per_cluster_bits = 0x%x", | 751 | 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) | |||
748 | ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size, | 758 | ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size, |
749 | vol->cluster_size); | 759 | vol->cluster_size); |
750 | ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask); | 760 | ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask); |
751 | ntfs_debug("vol->cluster_size_bits = %i (0x%x)", | 761 | ntfs_debug("vol->cluster_size_bits = %i", vol->cluster_size_bits); |
752 | vol->cluster_size_bits, vol->cluster_size_bits); | 762 | if (vol->cluster_size < vol->sector_size) { |
753 | if (vol->sector_size > vol->cluster_size) { | 763 | ntfs_error(vol->sb, "Cluster size (%i) is smaller than the " |
754 | ntfs_error(vol->sb, "Sector sizes above the cluster size are " | 764 | "sector size (%i). This is not supported. " |
755 | "not supported. Sorry."); | 765 | "Sorry.", vol->cluster_size, vol->sector_size); |
756 | return FALSE; | ||
757 | } | ||
758 | if (vol->sb->s_blocksize > vol->cluster_size) { | ||
759 | ntfs_error(vol->sb, "Cluster sizes smaller than the device " | ||
760 | "sector size are not supported. Sorry."); | ||
761 | return FALSE; | 766 | return FALSE; |
762 | } | 767 | } |
763 | clusters_per_mft_record = b->clusters_per_mft_record; | 768 | 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) | |||
786 | * we store $MFT/$DATA, the table of mft records in the page cache. | 791 | * we store $MFT/$DATA, the table of mft records in the page cache. |
787 | */ | 792 | */ |
788 | if (vol->mft_record_size > PAGE_CACHE_SIZE) { | 793 | if (vol->mft_record_size > PAGE_CACHE_SIZE) { |
789 | ntfs_error(vol->sb, "Mft record size %i (0x%x) exceeds the " | 794 | ntfs_error(vol->sb, "Mft record size (%i) exceeds the " |
790 | "page cache size on your system %lu (0x%lx). " | 795 | "PAGE_CACHE_SIZE on your system (%lu). " |
791 | "This is not supported. Sorry.", | 796 | "This is not supported. Sorry.", |
792 | vol->mft_record_size, vol->mft_record_size, | 797 | vol->mft_record_size, PAGE_CACHE_SIZE); |
793 | PAGE_CACHE_SIZE, PAGE_CACHE_SIZE); | 798 | return FALSE; |
799 | } | ||
800 | /* We cannot support mft record sizes below the sector size. */ | ||
801 | if (vol->mft_record_size < vol->sector_size) { | ||
802 | ntfs_error(vol->sb, "Mft record size (%i) is smaller than the " | ||
803 | "sector size (%i). This is not supported. " | ||
804 | "Sorry.", vol->mft_record_size, | ||
805 | vol->sector_size); | ||
794 | return FALSE; | 806 | return FALSE; |
795 | } | 807 | } |
796 | clusters_per_index_record = b->clusters_per_index_record; | 808 | 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) | |||
816 | ntfs_debug("vol->index_record_size_bits = %i (0x%x)", | 828 | ntfs_debug("vol->index_record_size_bits = %i (0x%x)", |
817 | vol->index_record_size_bits, | 829 | vol->index_record_size_bits, |
818 | vol->index_record_size_bits); | 830 | vol->index_record_size_bits); |
831 | /* We cannot support index record sizes below the sector size. */ | ||
832 | if (vol->index_record_size < vol->sector_size) { | ||
833 | ntfs_error(vol->sb, "Index record size (%i) is smaller than " | ||
834 | "the sector size (%i). This is not " | ||
835 | "supported. Sorry.", vol->index_record_size, | ||
836 | vol->sector_size); | ||
837 | return FALSE; | ||
838 | } | ||
819 | /* | 839 | /* |
820 | * Get the size of the volume in clusters and check for 64-bit-ness. | 840 | * Get the size of the volume in clusters and check for 64-bit-ness. |
821 | * Windows currently only uses 32 bits to save the clusters so we do | 841 | * 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) | |||
845 | } | 865 | } |
846 | ll = sle64_to_cpu(b->mft_lcn); | 866 | ll = sle64_to_cpu(b->mft_lcn); |
847 | if (ll >= vol->nr_clusters) { | 867 | if (ll >= vol->nr_clusters) { |
848 | ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird."); | 868 | ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of " |
869 | "volume. Weird.", (unsigned long long)ll, | ||
870 | (unsigned long long)ll); | ||
849 | return FALSE; | 871 | return FALSE; |
850 | } | 872 | } |
851 | vol->mft_lcn = ll; | 873 | vol->mft_lcn = ll; |
852 | ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); | 874 | ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); |
853 | ll = sle64_to_cpu(b->mftmirr_lcn); | 875 | ll = sle64_to_cpu(b->mftmirr_lcn); |
854 | if (ll >= vol->nr_clusters) { | 876 | if (ll >= vol->nr_clusters) { |
855 | ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. " | 877 | ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end " |
856 | "Weird."); | 878 | "of volume. Weird.", (unsigned long long)ll, |
879 | (unsigned long long)ll); | ||
857 | return FALSE; | 880 | return FALSE; |
858 | } | 881 | } |
859 | vol->mftmirr_lcn = ll; | 882 | vol->mftmirr_lcn = ll; |
@@ -2685,7 +2708,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) | |||
2685 | ntfs_volume *vol; | 2708 | ntfs_volume *vol; |
2686 | struct buffer_head *bh; | 2709 | struct buffer_head *bh; |
2687 | struct inode *tmp_ino; | 2710 | struct inode *tmp_ino; |
2688 | int result; | 2711 | int blocksize, result; |
2689 | 2712 | ||
2690 | ntfs_debug("Entering."); | 2713 | ntfs_debug("Entering."); |
2691 | #ifndef NTFS_RW | 2714 | #ifndef NTFS_RW |
@@ -2724,60 +2747,85 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) | |||
2724 | if (!parse_options(vol, (char*)opt)) | 2747 | if (!parse_options(vol, (char*)opt)) |
2725 | goto err_out_now; | 2748 | goto err_out_now; |
2726 | 2749 | ||
2750 | /* We support sector sizes up to the PAGE_CACHE_SIZE. */ | ||
2751 | if (bdev_hardsect_size(sb->s_bdev) > PAGE_CACHE_SIZE) { | ||
2752 | if (!silent) | ||
2753 | ntfs_error(sb, "Device has unsupported sector size " | ||
2754 | "(%i). The maximum supported sector " | ||
2755 | "size on this architecture is %lu " | ||
2756 | "bytes.", | ||
2757 | bdev_hardsect_size(sb->s_bdev), | ||
2758 | PAGE_CACHE_SIZE); | ||
2759 | goto err_out_now; | ||
2760 | } | ||
2727 | /* | 2761 | /* |
2728 | * TODO: Fail safety check. In the future we should really be able to | 2762 | * Setup the device access block size to NTFS_BLOCK_SIZE or the hard |
2729 | * cope with this being the case, but for now just bail out. | 2763 | * sector size, whichever is bigger. |
2730 | */ | 2764 | */ |
2731 | if (bdev_hardsect_size(sb->s_bdev) > NTFS_BLOCK_SIZE) { | 2765 | blocksize = sb_min_blocksize(sb, NTFS_BLOCK_SIZE); |
2766 | if (blocksize < NTFS_BLOCK_SIZE) { | ||
2732 | if (!silent) | 2767 | if (!silent) |
2733 | ntfs_error(sb, "Device has unsupported hardsect_size."); | 2768 | ntfs_error(sb, "Unable to set device block size."); |
2734 | goto err_out_now; | 2769 | goto err_out_now; |
2735 | } | 2770 | } |
2736 | 2771 | BUG_ON(blocksize != sb->s_blocksize); | |
2737 | /* Setup the device access block size to NTFS_BLOCK_SIZE. */ | 2772 | ntfs_debug("Set device block size to %i bytes (block size bits %i).", |
2738 | if (sb_set_blocksize(sb, NTFS_BLOCK_SIZE) != NTFS_BLOCK_SIZE) { | 2773 | blocksize, sb->s_blocksize_bits); |
2774 | /* Determine the size of the device in units of block_size bytes. */ | ||
2775 | if (!i_size_read(sb->s_bdev->bd_inode)) { | ||
2739 | if (!silent) | 2776 | if (!silent) |
2740 | ntfs_error(sb, "Unable to set block size."); | 2777 | ntfs_error(sb, "Unable to determine device size."); |
2741 | goto err_out_now; | 2778 | goto err_out_now; |
2742 | } | 2779 | } |
2743 | |||
2744 | /* Get the size of the device in units of NTFS_BLOCK_SIZE bytes. */ | ||
2745 | vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> | 2780 | vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> |
2746 | NTFS_BLOCK_SIZE_BITS; | 2781 | sb->s_blocksize_bits; |
2747 | |||
2748 | /* Read the boot sector and return unlocked buffer head to it. */ | 2782 | /* Read the boot sector and return unlocked buffer head to it. */ |
2749 | if (!(bh = read_ntfs_boot_sector(sb, silent))) { | 2783 | if (!(bh = read_ntfs_boot_sector(sb, silent))) { |
2750 | if (!silent) | 2784 | if (!silent) |
2751 | ntfs_error(sb, "Not an NTFS volume."); | 2785 | ntfs_error(sb, "Not an NTFS volume."); |
2752 | goto err_out_now; | 2786 | goto err_out_now; |
2753 | } | 2787 | } |
2754 | |||
2755 | /* | 2788 | /* |
2756 | * Extract the data from the boot sector and setup the ntfs super block | 2789 | * Extract the data from the boot sector and setup the ntfs volume |
2757 | * using it. | 2790 | * using it. |
2758 | */ | 2791 | */ |
2759 | result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); | 2792 | result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); |
2760 | |||
2761 | /* Initialize the cluster and mft allocators. */ | ||
2762 | ntfs_setup_allocators(vol); | ||
2763 | |||
2764 | brelse(bh); | 2793 | brelse(bh); |
2765 | |||
2766 | if (!result) { | 2794 | if (!result) { |
2767 | if (!silent) | 2795 | if (!silent) |
2768 | ntfs_error(sb, "Unsupported NTFS filesystem."); | 2796 | ntfs_error(sb, "Unsupported NTFS filesystem."); |
2769 | goto err_out_now; | 2797 | goto err_out_now; |
2770 | } | 2798 | } |
2771 | |||
2772 | /* | 2799 | /* |
2773 | * TODO: When we start coping with sector sizes different from | 2800 | * If the boot sector indicates a sector size bigger than the current |
2774 | * NTFS_BLOCK_SIZE, we now probably need to set the blocksize of the | 2801 | * device block size, switch the device block size to the sector size. |
2775 | * device (probably to NTFS_BLOCK_SIZE). | 2802 | * TODO: It may be possible to support this case even when the set |
2803 | * below fails, we would just be breaking up the i/o for each sector | ||
2804 | * into multiple blocks for i/o purposes but otherwise it should just | ||
2805 | * work. However it is safer to leave disabled until someone hits this | ||
2806 | * error message and then we can get them to try it without the setting | ||
2807 | * so we know for sure that it works. | ||
2776 | */ | 2808 | */ |
2777 | 2809 | if (vol->sector_size > blocksize) { | |
2810 | blocksize = sb_set_blocksize(sb, vol->sector_size); | ||
2811 | if (blocksize != vol->sector_size) { | ||
2812 | if (!silent) | ||
2813 | ntfs_error(sb, "Unable to set device block " | ||
2814 | "size to sector size (%i).", | ||
2815 | vol->sector_size); | ||
2816 | goto err_out_now; | ||
2817 | } | ||
2818 | BUG_ON(blocksize != sb->s_blocksize); | ||
2819 | vol->nr_blocks = i_size_read(sb->s_bdev->bd_inode) >> | ||
2820 | sb->s_blocksize_bits; | ||
2821 | ntfs_debug("Changed device block size to %i bytes (block size " | ||
2822 | "bits %i) to match volume sector size.", | ||
2823 | blocksize, sb->s_blocksize_bits); | ||
2824 | } | ||
2825 | /* Initialize the cluster and mft allocators. */ | ||
2826 | ntfs_setup_allocators(vol); | ||
2778 | /* Setup remaining fields in the super block. */ | 2827 | /* Setup remaining fields in the super block. */ |
2779 | sb->s_magic = NTFS_SB_MAGIC; | 2828 | sb->s_magic = NTFS_SB_MAGIC; |
2780 | |||
2781 | /* | 2829 | /* |
2782 | * Ntfs allows 63 bits for the file size, i.e. correct would be: | 2830 | * Ntfs allows 63 bits for the file size, i.e. correct would be: |
2783 | * sb->s_maxbytes = ~0ULL >> 1; | 2831 | * sb->s_maxbytes = ~0ULL >> 1; |
@@ -2787,9 +2835,8 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) | |||
2787 | * without overflowing the index or to 2^63 - 1, whichever is smaller. | 2835 | * without overflowing the index or to 2^63 - 1, whichever is smaller. |
2788 | */ | 2836 | */ |
2789 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 2837 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
2790 | 2838 | /* Ntfs measures time in 100ns intervals. */ | |
2791 | sb->s_time_gran = 100; | 2839 | sb->s_time_gran = 100; |
2792 | |||
2793 | /* | 2840 | /* |
2794 | * Now load the metadata required for the page cache and our address | 2841 | * Now load the metadata required for the page cache and our address |
2795 | * space operations to function. We do this by setting up a specialised | 2842 | * space operations to function. We do this by setting up a specialised |