statfs optimization: O(1) free cluster calculation (David Fox, Szabolcs Szakacsits)
parent
fd9f27aae4
commit
a97c661efe
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue