summaryrefslogtreecommitdiff
path: root/fs/ntfs/runlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ntfs/runlist.c')
-rw-r--r--fs/ntfs/runlist.c111
1 files changed, 81 insertions, 30 deletions
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
index 8438fb1da219..396d767c2cab 100644
--- a/fs/ntfs/runlist.c
+++ b/fs/ntfs/runlist.c
@@ -1,7 +1,7 @@
/**
* runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project.
*
- * Copyright (c) 2001-2004 Anton Altaparmakov
+ * Copyright (c) 2001-2005 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
@@ -59,7 +59,7 @@ static inline void ntfs_rl_mc(runlist_element *dstbase, int dst,
*
* As the runlists grow, more memory will be required. To prevent the
* kernel having to allocate and reallocate large numbers of small bits of
- * memory, this function returns and entire page of memory.
+ * memory, this function returns an entire page of memory.
*
* It is up to the caller to serialize access to the runlist @rl.
*
@@ -113,8 +113,11 @@ static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,
BUG_ON(!dst);
BUG_ON(!src);
- if ((dst->lcn < 0) || (src->lcn < 0)) /* Are we merging holes? */
+ if ((dst->lcn < 0) || (src->lcn < 0)) { /* Are we merging holes? */
+ if (dst->lcn == LCN_HOLE && src->lcn == LCN_HOLE)
+ return TRUE;
return FALSE;
+ }
if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */
return FALSE;
if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */
@@ -855,30 +858,42 @@ mpa_err:
if (!attr->data.non_resident.lowest_vcn) {
VCN max_cluster;
- max_cluster = (sle64_to_cpu(
+ max_cluster = ((sle64_to_cpu(
attr->data.non_resident.allocated_size) +
vol->cluster_size - 1) >>
- vol->cluster_size_bits;
+ vol->cluster_size_bits) - 1;
/*
- * If there is a difference between the highest_vcn and the
- * highest cluster, the runlist is either corrupt or, more
- * likely, there are more extents following this one.
+ * A highest_vcn of zero means this is a single extent
+ * attribute so simply terminate the runlist with LCN_ENOENT).
*/
- if (deltaxcn < --max_cluster) {
- ntfs_debug("More extents to follow; deltaxcn = 0x%llx, "
- "max_cluster = 0x%llx",
- (unsigned long long)deltaxcn,
- (unsigned long long)max_cluster);
- rl[rlpos].vcn = vcn;
- vcn += rl[rlpos].length = max_cluster - deltaxcn;
- rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
- rlpos++;
- } else if (unlikely(deltaxcn > max_cluster)) {
- ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "
- "0x%llx, max_cluster = 0x%llx",
- (unsigned long long)deltaxcn,
- (unsigned long long)max_cluster);
- goto mpa_err;
+ if (deltaxcn) {
+ /*
+ * If there is a difference between the highest_vcn and
+ * the highest cluster, the runlist is either corrupt
+ * or, more likely, there are more extents following
+ * this one.
+ */
+ if (deltaxcn < max_cluster) {
+ ntfs_debug("More extents to follow; deltaxcn "
+ "= 0x%llx, max_cluster = "
+ "0x%llx",
+ (unsigned long long)deltaxcn,
+ (unsigned long long)
+ max_cluster);
+ rl[rlpos].vcn = vcn;
+ vcn += rl[rlpos].length = max_cluster -
+ deltaxcn;
+ rl[rlpos].lcn = LCN_RL_NOT_MAPPED;
+ rlpos++;
+ } else if (unlikely(deltaxcn > max_cluster)) {
+ ntfs_error(vol->sb, "Corrupt attribute. "
+ "deltaxcn = 0x%llx, "
+ "max_cluster = 0x%llx",
+ (unsigned long long)deltaxcn,
+ (unsigned long long)
+ max_cluster);
+ goto mpa_err;
+ }
}
rl[rlpos].lcn = LCN_ENOENT;
} else /* Not the base extent. There may be more extents to follow. */
@@ -918,17 +933,18 @@ err_out:
*
* It is up to the caller to serialize access to the runlist @rl.
*
- * Since lcns must be >= 0, we use negative return values with special meaning:
+ * Since lcns must be >= 0, we use negative return codes with special meaning:
*
- * Return value Meaning / Description
+ * Return code Meaning / Description
* ==================================================
- * -1 = LCN_HOLE Hole / not allocated on disk.
- * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been
- * inserted into the runlist yet.
- * -3 = LCN_ENOENT There is no such vcn in the attribute.
+ * LCN_HOLE Hole / not allocated on disk.
+ * LCN_RL_NOT_MAPPED This is part of the runlist which has not been
+ * inserted into the runlist yet.
+ * LCN_ENOENT There is no such vcn in the attribute.
*
* Locking: - The caller must have locked the runlist (for reading or writing).
- * - This function does not touch the lock.
+ * - This function does not touch the lock, nor does it modify the
+ * runlist.
*/
LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
{
@@ -964,6 +980,39 @@ LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn)
return LCN_ENOENT;
}
+#ifdef NTFS_RW
+
+/**
+ * ntfs_rl_find_vcn_nolock - find a vcn in a runlist
+ * @rl: runlist to search
+ * @vcn: vcn to find
+ *
+ * Find the virtual cluster number @vcn in the runlist @rl and return the
+ * address of the runlist element containing the @vcn on success.
+ *
+ * Return NULL if @rl is NULL or @vcn is in an unmapped part/out of bounds of
+ * the runlist.
+ *
+ * Locking: The runlist must be locked on entry.
+ */
+runlist_element *ntfs_rl_find_vcn_nolock(runlist_element *rl, const VCN vcn)
+{
+ BUG_ON(vcn < 0);
+ if (unlikely(!rl || vcn < rl[0].vcn))
+ return NULL;
+ while (likely(rl->length)) {
+ if (unlikely(vcn < rl[1].vcn)) {
+ if (likely(rl->lcn >= LCN_HOLE))
+ return rl;
+ return NULL;
+ }
+ rl++;
+ }
+ if (likely(rl->lcn == LCN_ENOENT))
+ return rl;
+ return NULL;
+}
+
/**
* ntfs_get_nr_significant_bytes - get number of bytes needed to store a number
* @n: number for which to get the number of bytes for
@@ -1436,3 +1485,5 @@ int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist,
ntfs_debug("Done.");
return 0;
}
+
+#endif /* NTFS_RW */