diff options
| -rw-r--r-- | fs/ntfs3/attrib.c | 17 | ||||
| -rw-r--r-- | fs/ntfs3/ntfs_fs.h | 3 | ||||
| -rw-r--r-- | fs/ntfs3/run.c | 61 |
3 files changed, 69 insertions, 12 deletions
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index e61c5bf7e27e..0caf2f8a8c1e 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -962,11 +962,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, /* Try to find in cache. */ down_read(&ni->file.run_lock); - if (!no_da && run_lookup_entry(&ni->file.run_da, vcn, lcn, len, NULL)) { - /* The requested vcn is delay allocated. */ - *lcn = DELALLOC_LCN; - } else if (run_lookup_entry(&ni->file.run, vcn, lcn, len, NULL)) { - /* The requested vcn is known in current run. */ + if (run_lookup_entry_da(&ni->file.run, !no_da ? &ni->file.run_da : NULL, + vcn, lcn, len)) { } else { *len = 0; } @@ -1011,11 +1008,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen, int step; again: - if (da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) { - /* The requested vcn is delay allocated. */ - *lcn = DELALLOC_LCN; - } else if (run_lookup_entry(run, vcn, lcn, len, NULL)) { - /* The requested vcn is known in current run. */ + if (run_lookup_entry_da(run, da ? &ni->file.run_da : NULL, vcn, lcn, + len)) { } else { *len = 0; } @@ -1100,7 +1094,8 @@ again: } if (!*len) { - if (run_lookup_entry(run, vcn, lcn, len, NULL)) { + if (run_lookup_entry_da(run, da ? run_da : NULL, vcn, lcn, + len)) { if (*lcn != SPARSE_LCN || !new) goto ok; /* Slow normal way without allocation. */ diff --git a/fs/ntfs3/ntfs_fs.h b/fs/ntfs3/ntfs_fs.h index 9939556dcdc1..d98d7e474476 100644 --- a/fs/ntfs3/ntfs_fs.h +++ b/fs/ntfs3/ntfs_fs.h @@ -858,6 +858,9 @@ static inline void mi_get_ref(const struct mft_inode *mi, struct MFT_REF *ref) /* Globals from run.c */ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn, CLST *len, size_t *index); +bool run_lookup_entry_da(const struct runs_tree *run, + const struct runs_tree *run_da, CLST vcn, CLST *lcn, + CLST *len); void run_truncate(struct runs_tree *run, CLST vcn); void run_truncate_head(struct runs_tree *run, CLST vcn); void run_truncate_around(struct runs_tree *run, CLST vcn); diff --git a/fs/ntfs3/run.c b/fs/ntfs3/run.c index ad7db67514ef..3ebf0154eda3 100644 --- a/fs/ntfs3/run.c +++ b/fs/ntfs3/run.c @@ -224,6 +224,66 @@ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn, } /* + * run_overlaps + * + * true if run overlaps with range [svcn, svcn + len) + */ +static bool run_overlaps(const struct runs_tree *run, CLST svcn, CLST len, + CLST *vcn, CLST *clen) +{ + size_t i; + const struct ntfs_run *r = run->runs; + CLST end = svcn + len; + + for (i = 0; i < run->count; i++, r++) { + /* Check if [r->vcn, r->vcn+r->len) overlaps [svcn, end). */ + if (r->vcn < end && svcn < r->vcn + r->len) { + if (vcn) + *vcn = r->vcn; + if (clen) + *clen = r->len; + return true; + } + } + + return false; +} + +/* + * run_lookup_entry_da + * + * - lookup vcn in delalloc run + * - lookup vcn in real run + * - correct result if real run overlaps with delalloc + */ +bool run_lookup_entry_da(const struct runs_tree *run, + const struct runs_tree *run_da, CLST vcn, CLST *lcn, + CLST *len) +{ + CLST vcn1, len1; + + if (run_da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) { + *lcn = DELALLOC_LCN; + return true; + } + + if (!run_lookup_entry(run, vcn, lcn, len, NULL)) + return false; + + if (run_da && run_overlaps(run_da, vcn, *len, &vcn1, &len1)) { + /* Correct return value. */ + if (vcn1 > vcn) { + *len = vcn1 - vcn; + } else { + *lcn = DELALLOC_LCN; + *len = len1; + } + } + + return true; +} + +/* * run_truncate_head - Decommit the range before vcn. */ void run_truncate_head(struct runs_tree *run, CLST vcn) @@ -1286,7 +1346,6 @@ bool run_remove_range(struct runs_tree *run, CLST vcn, CLST len, CLST *done) return true; } - e = run->runs + run->count; r = run->runs + index; end = vcn + len; |
