Skip to content

Commit 5569b3c

Browse files
fs/ntfs3: handle delayed allocation overlap in run lookup
Introduce run_lookup_entry_da() to look up data runs while taking delayed allocation into account. ntfs3 may have both committed extents and delayed allocation extents for the same VCN range. The new helper checks delayed allocation first and falls back to the real run, then corrects the returned range when a real run overlaps with a delayed allocation run. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
1 parent 4f165b1 commit 5569b3c

3 files changed

Lines changed: 69 additions & 12 deletions

File tree

fs/ntfs3/attrib.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -962,11 +962,8 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
962962

963963
/* Try to find in cache. */
964964
down_read(&ni->file.run_lock);
965-
if (!no_da && run_lookup_entry(&ni->file.run_da, vcn, lcn, len, NULL)) {
966-
/* The requested vcn is delay allocated. */
967-
*lcn = DELALLOC_LCN;
968-
} else if (run_lookup_entry(&ni->file.run, vcn, lcn, len, NULL)) {
969-
/* The requested vcn is known in current run. */
965+
if (run_lookup_entry_da(&ni->file.run, !no_da ? &ni->file.run_da : NULL,
966+
vcn, lcn, len)) {
970967
} else {
971968
*len = 0;
972969
}
@@ -1011,11 +1008,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
10111008
int step;
10121009

10131010
again:
1014-
if (da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) {
1015-
/* The requested vcn is delay allocated. */
1016-
*lcn = DELALLOC_LCN;
1017-
} else if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
1018-
/* The requested vcn is known in current run. */
1011+
if (run_lookup_entry_da(run, da ? &ni->file.run_da : NULL, vcn, lcn,
1012+
len)) {
10191013
} else {
10201014
*len = 0;
10211015
}
@@ -1100,7 +1094,8 @@ int attr_data_get_block_locked(struct ntfs_inode *ni, CLST vcn, CLST clen,
11001094
}
11011095

11021096
if (!*len) {
1103-
if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
1097+
if (run_lookup_entry_da(run, da ? run_da : NULL, vcn, lcn,
1098+
len)) {
11041099
if (*lcn != SPARSE_LCN || !new)
11051100
goto ok; /* Slow normal way without allocation. */
11061101

fs/ntfs3/ntfs_fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,9 @@ static inline void mi_get_ref(const struct mft_inode *mi, struct MFT_REF *ref)
858858
/* Globals from run.c */
859859
bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn,
860860
CLST *len, size_t *index);
861+
bool run_lookup_entry_da(const struct runs_tree *run,
862+
const struct runs_tree *run_da, CLST vcn, CLST *lcn,
863+
CLST *len);
861864
void run_truncate(struct runs_tree *run, CLST vcn);
862865
void run_truncate_head(struct runs_tree *run, CLST vcn);
863866
void run_truncate_around(struct runs_tree *run, CLST vcn);

fs/ntfs3/run.c

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,66 @@ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn,
223223
return true;
224224
}
225225

226+
/*
227+
* run_overlaps
228+
*
229+
* true if run overlaps with range [svcn, svcn + len)
230+
*/
231+
static bool run_overlaps(const struct runs_tree *run, CLST svcn, CLST len,
232+
CLST *vcn, CLST *clen)
233+
{
234+
size_t i;
235+
const struct ntfs_run *r = run->runs;
236+
CLST end = svcn + len;
237+
238+
for (i = 0; i < run->count; i++, r++) {
239+
/* Check if [r->vcn, r->vcn+r->len) overlaps [svcn, end). */
240+
if (r->vcn < end && svcn < r->vcn + r->len) {
241+
if (vcn)
242+
*vcn = r->vcn;
243+
if (clen)
244+
*clen = r->len;
245+
return true;
246+
}
247+
}
248+
249+
return false;
250+
}
251+
252+
/*
253+
* run_lookup_entry_da
254+
*
255+
* - lookup vcn in delalloc run
256+
* - lookup vcn in real run
257+
* - correct result if real run overlaps with delalloc
258+
*/
259+
bool run_lookup_entry_da(const struct runs_tree *run,
260+
const struct runs_tree *run_da, CLST vcn, CLST *lcn,
261+
CLST *len)
262+
{
263+
CLST vcn1, len1;
264+
265+
if (run_da && run_lookup_entry(run_da, vcn, lcn, len, NULL)) {
266+
*lcn = DELALLOC_LCN;
267+
return true;
268+
}
269+
270+
if (!run_lookup_entry(run, vcn, lcn, len, NULL))
271+
return false;
272+
273+
if (run_da && run_overlaps(run_da, vcn, *len, &vcn1, &len1)) {
274+
/* Correct return value. */
275+
if (vcn1 > vcn) {
276+
*len = vcn1 - vcn;
277+
} else {
278+
*lcn = DELALLOC_LCN;
279+
*len = len1;
280+
}
281+
}
282+
283+
return true;
284+
}
285+
226286
/*
227287
* run_truncate_head - Decommit the range before vcn.
228288
*/
@@ -1286,7 +1346,6 @@ bool run_remove_range(struct runs_tree *run, CLST vcn, CLST len, CLST *done)
12861346
return true;
12871347
}
12881348

1289-
12901349
e = run->runs + run->count;
12911350
r = run->runs + index;
12921351
end = vcn + len;

0 commit comments

Comments
 (0)