statfs optimization: O(1) free cluster calculation (David Fox, Szabolcs Szakacsits)

master
szaka 2007-09-12 20:51:06 +00:00
parent fd9f27aae4
commit a97c661efe
4 changed files with 69 additions and 49 deletions

View File

@ -212,6 +212,9 @@ struct _ntfs_volume {
s32 attrdef_len; /* Size of the attribute definition table in
bytes. */
s64 free_clusters; /* Track the number of free clusters which
greatly improves statfs() performance */
/* Temp: for directory handling */
void *private_data; /* ntfs_dir for . */
void *private_bmp1; /* ntfs_bmp for $MFT/$BITMAP */

View File

@ -305,6 +305,11 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
/* Allocate the bitmap bit. */
*byte |= bit;
writeback = 1;
if (vol->free_clusters <= 0)
ntfs_log_error("Non-positive free clusters "
"(%lld)!\n", vol->free_clusters);
else
vol->free_clusters--;
/*
* Coalesce with previous run if adjacent LCNs.
@ -490,6 +495,9 @@ err_ret:
*/
int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
{
s64 nr_freed = 0;
int ret = -1;
ntfs_log_trace("Entering.\n");
for (; rl->length; rl++) {
@ -497,15 +505,26 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
(long long)rl->lcn, (long long)rl->length);
if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na,
rl->lcn, rl->length)) {
int eo = errno;
ntfs_log_trace("Eeek! Deallocation of clusters failed.\n");
errno = eo;
return -1;
if (rl->lcn >= 0) {
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
rl->length)) {
ntfs_log_perror("Cluster deallocation failed "
"(%lld, %lld)", rl->lcn,
rl->length);
goto out;
}
nr_freed += rl->length ;
}
}
return 0;
ret = 0;
out:
vol->free_clusters += nr_freed;
if (vol->free_clusters > vol->nr_clusters)
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
(long long)vol->nr_clusters);
return ret;
}
/**
@ -527,7 +546,8 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
{
runlist *rl;
s64 nr_freed, delta, to_free;
s64 delta, to_free, nr_freed = 0;
int ret = -1;
if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 ||
(count < 0 && count != -1)) {
@ -543,12 +563,13 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if (!rl) {
if (errno == ENOENT)
return 0;
else
return -1;
return -1;
}
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
errno = EIO;
ntfs_log_perror("%s: Unexpected lcn (%lld)", __FUNCTION__,
(long long)rl->lcn);
return -1;
}
@ -563,14 +584,10 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if (rl->lcn != LCN_HOLE) {
/* Do the actual freeing of the clusters in this run. */
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta,
to_free))
to_free))
return -1;
/* We have freed @to_free real clusters. */
nr_freed = to_free;
} else {
/* No real clusters were freed. */
nr_freed = 0;
}
}
/* Go to the next run and adjust the number of clusters left to free. */
++rl;
@ -586,11 +603,10 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
// list support! (AIA)
if (rl->lcn < 0 && rl->lcn != LCN_HOLE) {
// FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! invalid lcn (= %lli). Should attempt "
"to map runlist! Leaving inconsistent "
"metadata!\n", (long long)rl->lcn);
errno = EIO;
return -1;
ntfs_log_perror("%s: Invalid lcn (%lli)",
__FUNCTION__, (long long)rl->lcn);
goto out;
}
/* The number of clusters in this run that need freeing. */
@ -599,18 +615,13 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
to_free = count;
if (rl->lcn != LCN_HOLE) {
/* Do the actual freeing of the clusters in the run. */
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn,
to_free)) {
int eo = errno;
// FIXME: Eeek! We need rollback! (AIA)
ntfs_log_trace("Eeek! bitmap clear run failed. "
"Leaving inconsistent metadata!\n");
errno = eo;
return -1;
ntfs_log_perror("%s: Clearing bitmap run failed",
__FUNCTION__);
goto out;
}
/* We have freed @to_free real clusters. */
nr_freed += to_free;
}
@ -620,12 +631,18 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
if (count != -1 && count != 0) {
// FIXME: Eeek! BUG()
ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving "
"inconsistent metadata!\n", (long long)count);
errno = EIO;
return -1;
ntfs_log_perror("%s: count still not zero (%lld)", __FUNCTION__,
(long long)count);
goto out;
}
/* Done. Return the number of actual clusters that were freed. */
return nr_freed;
ret = nr_freed;
out:
vol->free_clusters += nr_freed ;
if (vol->free_clusters > vol->nr_clusters)
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
(long long)vol->nr_clusters);
return ret;
}

View File

@ -568,7 +568,7 @@ static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol)
{
LCN lcn;
s64 ll = 0; /* silence compiler warning */
ntfs_attr *mftbmp_na, *lcnbmp_na;
ntfs_attr *mftbmp_na;
runlist_element *rl, *rl2 = NULL; /* silence compiler warning */
ntfs_attr_search_ctx *ctx;
MFT_RECORD *m = NULL; /* silence compiler warning */
@ -578,7 +578,6 @@ static int ntfs_mft_bitmap_extend_allocation(ntfs_volume *vol)
BOOL mp_rebuilt = FALSE;
mftbmp_na = vol->mftbmp_na;
lcnbmp_na = vol->lcnbmp_na;
/*
* Determine the last lcn of the mft bitmap. The allocated size of the
* mft bitmap cannot be zero so we are ok to do this.
@ -726,9 +725,11 @@ undo_alloc:
rl->lcn = rl[1].lcn;
rl->length = 0;
/* Deallocate the cluster. */
if (ntfs_bitmap_clear_bit(lcnbmp_na, lcn))
/* FIXME: use an ntfs_cluster_free_* function */
if (ntfs_bitmap_clear_bit(vol->lcnbmp_na, lcn))
ntfs_log_error("Failed to free cluster.%s\n", es);
else
vol->free_clusters++;
if (mp_rebuilt) {
if (ntfs_mapping_pairs_build(vol, (u8*)a +
le16_to_cpu(a->mapping_pairs_offset),

View File

@ -106,7 +106,6 @@ typedef enum {
typedef struct {
ntfs_volume *vol;
int state;
long free_clusters;
long free_mft;
unsigned int uid;
unsigned int gid;
@ -123,8 +122,6 @@ typedef struct {
} ntfs_fuse_context_t;
typedef enum {
NF_FreeClustersOutdate = (1 << 0), /* Information about amount of
free clusters is outdated. */
NF_FreeMFTOutdate = (1 << 1), /* Information about amount of
free MFT records is outdated. */
} ntfs_fuse_state_bits;
@ -167,8 +164,8 @@ static const char *usage_msg =
static __inline__ void ntfs_fuse_mark_free_space_outdated(void)
{
/* Mark information about free MFT record and clusters outdated. */
ctx->state |= (NF_FreeClustersOutdate | NF_FreeMFTOutdate);
/* Mark information about free MFT records outdated. */
ctx->state |= NF_FreeMFTOutdate;
}
/**
@ -221,14 +218,12 @@ static long ntfs_fuse_get_nr_free_mft_records(ntfs_volume *vol, s64 numof_inode)
return nr_free;
}
static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol)
static long ntfs_get_nr_free_clusters(ntfs_volume *vol)
{
u8 *buf;
long nr_free = 0;
s64 br, total = 0;
if (!(ctx->state & NF_FreeClustersOutdate))
return ctx->free_clusters;
buf = ntfs_malloc(vol->cluster_size);
if (!buf)
return -errno;
@ -248,8 +243,6 @@ static long ntfs_fuse_get_nr_free_clusters(ntfs_volume *vol)
free(buf);
if (!total || br < 0)
return -errno;
ctx->free_clusters = nr_free;
ctx->state &= ~(NF_FreeClustersOutdate);
return nr_free;
}
@ -292,7 +285,7 @@ static int ntfs_fuse_statfs(const char *path __attribute__((unused)),
sfs->f_blocks = vol->nr_clusters;
/* Free data blocks in file system in units of f_bsize. */
size = ntfs_fuse_get_nr_free_clusters(vol);
size = vol->free_clusters;
if (size < 0)
size = 0;
@ -1655,7 +1648,7 @@ static int ntfs_fuse_init(void)
return -1;
*ctx = (ntfs_fuse_context_t) {
.state = NF_FreeClustersOutdate | NF_FreeMFTOutdate,
.state = NF_FreeMFTOutdate,
.uid = getuid(),
.gid = getgid(),
.fmask = 0,
@ -2233,6 +2226,12 @@ int main(int argc, char *argv[])
if (!ntfs_open(opts.device, opts.mnt_point, use_blkdev))
goto err_out;
ctx->vol->free_clusters = ntfs_get_nr_free_clusters(ctx->vol);
if (ctx->vol->free_clusters < 0) {
ntfs_log_perror("Failed to read NTFS $Bitmap");
goto err_out;
}
if (use_blkdev) {
set_fuseblk_options(parsed_options);
set_user_mount_option(parsed_options, uid);