/*
* lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project.
*
- * Copyright (c) 2004 Anton Altaparmakov
+ * Copyright (c) 2004-2005 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
int ret = 0;
ntfs_debug("Entering.");
+ if (!rl)
+ return 0;
for (; rl->length; rl++) {
int err;
if (rl->lcn < 0)
continue;
err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length);
- if (unlikely(err && (!ret || ret == ENOMEM) && ret != err))
+ if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err))
ret = err;
}
ntfs_debug("Done.");
BUG_ON(zone < FIRST_ZONE);
BUG_ON(zone > LAST_ZONE);
- /* Return empty runlist if @count == 0 */
- // FIXME: Do we want to just return NULL instead? (AIA)
- if (!count) {
- rl = ntfs_malloc_nofs(PAGE_SIZE);
- if (!rl)
- return ERR_PTR(-ENOMEM);
- rl[0].vcn = start_vcn;
- rl[0].lcn = LCN_RL_NOT_MAPPED;
- rl[0].length = 0;
- return rl;
- }
+ /* Return NULL if @count is zero. */
+ if (!count)
+ return NULL;
/* Take the lcnbmp lock for writing. */
down_write(&vol->lcnbmp_lock);
/*
buf_size = i_size - last_read_pos;
buf_size <<= 3;
lcn = bmp_pos & 7;
- bmp_pos &= ~7;
+ bmp_pos &= ~(LCN)7;
ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, "
"bmp_pos 0x%llx, need_writeback %i.", buf_size,
(unsigned long long)lcn,
(unsigned int)*byte);
/* Skip full bytes. */
if (*byte == 0xff) {
- lcn = (lcn + 8) & ~7;
+ lcn = (lcn + 8) & ~(LCN)7;
ntfs_debug("Continuing while loop 1.");
continue;
}
if (zone == MFT_ZONE || mft_zone_size <= 0) {
ntfs_debug("No free clusters left, going to out.");
/* Really no more space left on device. */
- err = ENOSPC;
+ err = -ENOSPC;
goto out;
} /* zone == DATA_ZONE && mft_zone_size > 0 */
ntfs_debug("Shrinking mft zone.");
if (rl) {
int err2;
- if (err == ENOSPC)
+ if (err == -ENOSPC)
ntfs_debug("Not enough space to complete allocation, "
- "err ENOSPC, first free lcn 0x%llx, "
+ "err -ENOSPC, first free lcn 0x%llx, "
"could allocate up to 0x%llx "
"clusters.",
(unsigned long long)rl[0].lcn,
- (unsigned long long)count - clusters);
+ (unsigned long long)(count - clusters));
/* Deallocate all allocated clusters. */
ntfs_debug("Attempting rollback...");
err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);
}
/* Free the runlist. */
ntfs_free(rl);
- } else if (err == ENOSPC)
- ntfs_debug("No space left at all, err = ENOSPC, "
- "first free lcn = 0x%llx.",
- (unsigned long long)vol->data1_zone_pos);
+ } else if (err == -ENOSPC)
+ ntfs_debug("No space left at all, err = -ENOSPC, first free "
+ "lcn = 0x%llx.",
+ (long long)vol->data1_zone_pos);
up_write(&vol->lcnbmp_lock);
return ERR_PTR(err);
}
* @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
- * @is_rollback: if TRUE this is a rollback operation
+ * @write_locked: true if the runlist is locked for writing
+ * @is_rollback: true if this is a rollback operation
*
* Free @count clusters starting at the cluster @start_vcn in the runlist
* described by the vfs inode @vi.
* 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.
+ * Locking: - The runlist described by @vi must be locked on entry and is
+ * locked on return. Note if the runlist is locked for reading the
+ * lock may be dropped and reacquired. Note the runlist may be
+ * modified when needed runlist fragments need to be mapped.
* - 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.
*/
s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
- const BOOL is_rollback)
+ const BOOL write_locked, const BOOL is_rollback)
{
s64 delta, to_free, total_freed, real_freed;
ntfs_inode *ni;
total_freed = real_freed = 0;
- /* This returns with ni->runlist locked for reading on success. */
- rl = ntfs_find_vcn(ni, start_vcn, FALSE);
+ rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, write_locked);
if (IS_ERR(rl)) {
if (!is_rollback)
ntfs_error(vol->sb, "Failed to find first runlist "
ntfs_error(vol->sb, "First runlist element has "
"invalid lcn, aborting.");
err = -EIO;
- goto unl_err_out;
+ goto err_out;
}
/* Find the starting cluster inside the run that needs freeing. */
delta = start_vcn - rl->vcn;
if (!is_rollback)
ntfs_error(vol->sb, "Failed to clear first run "
"(error %i), aborting.", err);
- goto unl_err_out;
+ goto err_out;
}
/* We have freed @to_free real clusters. */
real_freed = to_free;
if (unlikely(rl->lcn < LCN_HOLE)) {
VCN vcn;
- /*
- * Attempt to map runlist, dropping runlist lock for
- * the duration.
- */
+ /* Attempt to map runlist. */
vcn = rl->vcn;
- up_read(&ni->runlist.lock);
- err = ntfs_map_runlist(ni, vcn);
- if (err) {
- if (!is_rollback)
- ntfs_error(vol->sb, "Failed to map "
- "runlist fragment.");
- if (err == -EINVAL || err == -ENOENT)
- err = -EIO;
- goto err_out;
- }
- /*
- * This returns with ni->runlist locked for reading on
- * success.
- */
- rl = ntfs_find_vcn(ni, vcn, FALSE);
+ rl = ntfs_attr_find_vcn_nolock(ni, vcn, write_locked);
if (IS_ERR(rl)) {
err = PTR_ERR(rl);
if (!is_rollback)
- ntfs_error(vol->sb, "Failed to find "
+ ntfs_error(vol->sb, "Failed to map "
+ "runlist fragment or "
+ "failed to find "
"subsequent runlist "
"element.");
goto err_out;
(unsigned long long)
rl->lcn);
err = -EIO;
- goto unl_err_out;
+ goto err_out;
}
}
/* The number of clusters in this run that need freeing. */
if (!is_rollback)
ntfs_error(vol->sb, "Failed to clear "
"subsequent run.");
- goto unl_err_out;
+ goto err_out;
}
/* We have freed @to_free real clusters. */
real_freed += to_free;
/* Update the total done clusters. */
total_freed += to_free;
}
- up_read(&ni->runlist.lock);
if (likely(!is_rollback))
up_write(&vol->lcnbmp_lock);
/* We are done. Return the number of actually freed clusters. */
ntfs_debug("Done.");
return real_freed;
-unl_err_out:
- up_read(&ni->runlist.lock);
err_out:
if (is_rollback)
return err;
* If rollback fails, set the volume errors flag, emit an error
* message, and return the error code.
*/
- delta = __ntfs_cluster_free(vi, start_vcn, total_freed, TRUE);
+ delta = __ntfs_cluster_free(vi, start_vcn, total_freed, write_locked,
+ TRUE);
if (delta < 0) {
ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving "
"inconsistent metadata! Unmount and run "