Commit c935fcd5 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: Implement cluster (de-)allocation code (fs/ntfs/lcnalloc.[hc]).

Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
parent 4675d604
...@@ -28,6 +28,7 @@ ToDo/Notes: ...@@ -28,6 +28,7 @@ ToDo/Notes:
- Add fs/ntfs/attrib.[hc]::ntfs_find_vcn() which returns the locked - Add fs/ntfs/attrib.[hc]::ntfs_find_vcn() which returns the locked
runlist element containing a particular vcn. It also takes care of runlist element containing a particular vcn. It also takes care of
mapping any needed runlist fragments. mapping any needed runlist fragments.
- Implement cluster (de-)allocation code (fs/ntfs/lcnalloc.[hc]).
2.1.16 - Implement access time updates, file sync, async io, and read/writev. 2.1.16 - Implement access time updates, file sync, async io, and read/writev.
......
...@@ -15,5 +15,5 @@ endif ...@@ -15,5 +15,5 @@ endif
ifeq ($(CONFIG_NTFS_RW),y) ifeq ($(CONFIG_NTFS_RW),y)
EXTRA_CFLAGS += -DNTFS_RW EXTRA_CFLAGS += -DNTFS_RW
ntfs-objs += bitmap.o logfile.o quota.o ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o
endif endif
...@@ -56,8 +56,9 @@ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, ...@@ -56,8 +56,9 @@ int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
BUG_ON(!vi); BUG_ON(!vi);
ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, " ntfs_debug("Entering for i_ino 0x%lx, start_bit 0x%llx, count 0x%llx, "
"value %u.", vi->i_ino, (unsigned long long)start_bit, "value %u.%s", vi->i_ino, (unsigned long long)start_bit,
(unsigned long long)cnt, (unsigned int)value); (unsigned long long)cnt, (unsigned int)value,
is_rollback ? " (rollback)" : "");
BUG_ON(start_bit < 0); BUG_ON(start_bit < 0);
BUG_ON(cnt < 0); BUG_ON(cnt < 0);
BUG_ON(value > 1); BUG_ON(value > 1);
......
This diff is collapsed.
/*
* lcnalloc.h - Exports for NTFS kernel cluster (de)allocation. Part of the
* Linux-NTFS project.
*
* Copyright (c) 2004 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
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LINUX_NTFS_LCNALLOC_H
#define _LINUX_NTFS_LCNALLOC_H
#ifdef NTFS_RW
#include <linux/fs.h>
#include "types.h"
#include "volume.h"
typedef enum {
FIRST_ZONE = 0, /* For sanity checking. */
MFT_ZONE = 0, /* Allocate from $MFT zone. */
DATA_ZONE = 1, /* Allocate from $DATA zone. */
LAST_ZONE = 1, /* For sanity checking. */
} NTFS_CLUSTER_ALLOCATION_ZONES;
extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
const VCN start_vcn, const s64 count, const LCN start_lcn,
const NTFS_CLUSTER_ALLOCATION_ZONES zone);
extern s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
s64 count, const BOOL is_rollback);
/**
* ntfs_cluster_free - free clusters on an ntfs volume
* @vi: vfs inode whose runlist describes the clusters to free
* @start_vcn: vcn in the runlist of @vi at which to start freeing clusters
* @count: number of clusters to free or -1 for all clusters
*
* Free @count clusters starting at the cluster @start_vcn in the runlist
* described by the vfs inode @vi.
*
* If @count is -1, all clusters from @start_vcn to the end of the runlist are
* deallocated. Thus, to completely free all clusters in a runlist, use
* @start_vcn = 0 and @count = -1.
*
* Note, ntfs_cluster_free() does not modify the runlist at all, so the caller
* has to deal with it later.
*
* Return the number of deallocated clusters (not counting sparse ones) on
* success and -errno on error.
*
* Locking: - The runlist described by @vi must be unlocked on entry and is
* unlocked on return.
* - This function takes the runlist lock of @vi for reading and
* sometimes for writing and sometimes modifies the runlist.
* - The volume lcn bitmap must be unlocked on entry and is unlocked
* on return.
* - This function takes the volume lcn bitmap lock for writing and
* modifies the bitmap contents.
*/
static inline s64 ntfs_cluster_free(struct inode *vi, const VCN start_vcn,
s64 count)
{
return __ntfs_cluster_free(vi, start_vcn, count, FALSE);
}
#endif /* NTFS_RW */
#endif /* defined _LINUX_NTFS_LCNALLOC_H */
...@@ -818,37 +818,86 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b) ...@@ -818,37 +818,86 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
vol->serial_no = le64_to_cpu(b->volume_serial_number); vol->serial_no = le64_to_cpu(b->volume_serial_number);
ntfs_debug("vol->serial_no = 0x%llx", ntfs_debug("vol->serial_no = 0x%llx",
(unsigned long long)vol->serial_no); (unsigned long long)vol->serial_no);
/* return TRUE;
* Determine MFT zone size. This is not strictly the right place to do }
* this, but I am too lazy to create a function especially for it...
/**
* setup_lcn_allocator - initialize the cluster allocator
* @vol: volume structure for which to setup the lcn allocator
*
* Setup the cluster (lcn) allocator to the starting values.
*/ */
vol->mft_zone_end = vol->nr_clusters; static void setup_lcn_allocator(ntfs_volume *vol)
{
#ifdef NTFS_RW
LCN mft_zone_size, mft_lcn;
#endif /* NTFS_RW */
ntfs_debug("vol->mft_zone_multiplier = 0x%x",
vol->mft_zone_multiplier);
#ifdef NTFS_RW
/* Determine the size of the MFT zone. */
mft_zone_size = vol->nr_clusters;
switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */ switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */
case 4: case 4:
vol->mft_zone_end = vol->mft_zone_end >> 1; /* 50% */ mft_zone_size >>= 1; /* 50% */
break; break;
case 3: case 3:
vol->mft_zone_end = (vol->mft_zone_end + mft_zone_size = (mft_zone_size +
(vol->mft_zone_end >> 1)) >> 2; /* 37.5% */ (mft_zone_size >> 1)) >> 2; /* 37.5% */
break; break;
case 2: case 2:
vol->mft_zone_end = vol->mft_zone_end >> 2; /* 25% */ mft_zone_size >>= 2; /* 25% */
break; break;
/* case 1: */
default: default:
vol->mft_zone_multiplier = 1; mft_zone_size >>= 3; /* 12.5% */
/* Fall through into case 1. */
case 1:
vol->mft_zone_end = vol->mft_zone_end >> 3; /* 12.5% */
break; break;
} }
ntfs_debug("vol->mft_zone_multiplier = 0x%x", /* Setup the mft zone. */
vol->mft_zone_multiplier); vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;
vol->mft_zone_start = vol->mft_lcn; ntfs_debug("vol->mft_zone_pos = 0x%llx",
vol->mft_zone_end += vol->mft_lcn; (unsigned long long)vol->mft_zone_pos);
/*
* Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs
* source) and if the actual mft_lcn is in the expected place or even
* further to the front of the volume, extend the mft_zone to cover the
* beginning of the volume as well. This is in order to protect the
* area reserved for the mft bitmap as well within the mft_zone itself.
* On non-standard volumes we do not protect it as the overhead would
* be higher than the speed increase we would get by doing it.
*/
mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;
if (mft_lcn * vol->cluster_size < 16 * 1024)
mft_lcn = (16 * 1024 + vol->cluster_size - 1) /
vol->cluster_size;
if (vol->mft_zone_start <= mft_lcn)
vol->mft_zone_start = 0;
ntfs_debug("vol->mft_zone_start = 0x%llx", ntfs_debug("vol->mft_zone_start = 0x%llx",
(long long)vol->mft_zone_start); (unsigned long long)vol->mft_zone_start);
ntfs_debug("vol->mft_zone_end = 0x%llx", (long long)vol->mft_zone_end); /*
return TRUE; * Need to cap the mft zone on non-standard volumes so that it does
* not point outside the boundaries of the volume. We do this by
* halving the zone size until we are inside the volume.
*/
vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
while (vol->mft_zone_end >= vol->nr_clusters) {
mft_zone_size >>= 1;
vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
}
ntfs_debug("vol->mft_zone_end = 0x%llx",
(unsigned long long)vol->mft_zone_end);
/*
* Set the current position within each data zone to the start of the
* respective zone.
*/
vol->data1_zone_pos = vol->mft_zone_end;
ntfs_debug("vol->data1_zone_pos = 0x%llx",
(unsigned long long)vol->data1_zone_pos);
vol->data2_zone_pos = 0;
ntfs_debug("vol->data2_zone_pos = 0x%llx",
(unsigned long long)vol->data2_zone_pos);
#endif /* NTFS_RW */
} }
#ifdef NTFS_RW #ifdef NTFS_RW
...@@ -2196,6 +2245,9 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2196,6 +2245,9 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
*/ */
result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data); result = parse_ntfs_boot_sector(vol, (NTFS_BOOT_SECTOR*)bh->b_data);
/* Initialize the cluster allocator. */
setup_lcn_allocator(vol);
brelse(bh); brelse(bh);
if (!result) { if (!result) {
......
...@@ -73,8 +73,18 @@ typedef struct { ...@@ -73,8 +73,18 @@ typedef struct {
/* Mount specific NTFS information. */ /* Mount specific NTFS information. */
u32 upcase_len; /* Number of entries in upcase[]. */ u32 upcase_len; /* Number of entries in upcase[]. */
ntfschar *upcase; /* The upcase table. */ ntfschar *upcase; /* The upcase table. */
#ifdef NTFS_RW
/* Variables used by the cluster and mft allocators. */
LCN mft_zone_start; /* First cluster of the mft zone. */ LCN mft_zone_start; /* First cluster of the mft zone. */
LCN mft_zone_end; /* First cluster beyond the mft zone. */ LCN mft_zone_end; /* First cluster beyond the mft zone. */
LCN mft_zone_pos; /* Current position in the mft zone. */
LCN data1_zone_pos; /* Current position in the first data
zone. */
LCN data2_zone_pos; /* Current position in the second data
zone. */
#endif /* NTFS_RW */
struct inode *mft_ino; /* The VFS inode of $MFT. */ struct inode *mft_ino; /* The VFS inode of $MFT. */
struct inode *mftbmp_ino; /* Attribute inode for $MFT/$BITMAP. */ struct inode *mftbmp_ino; /* Attribute inode for $MFT/$BITMAP. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment