Skip to content

Commit 559e608

Browse files
committed
Pull ntfs3 updates from Konstantin Komarov: "New code: - support timestamps prior to epoch - do not overwrite uptodate pages - disable readahead for compressed files - setting of dummy blocksize to read boot_block when mounting - the run_lock initialization when loading $Extend - initialization of allocated memory before use - support for the NTFS3_IOC_SHUTDOWN ioctl - check for minimum alignment when performing direct I/O reads - check for shutdown in fsync Fixes: - mount failure for sparse runs in run_unpack() - use-after-free of sbi->options in cmp_fnames - KMSAN uninit bug after failed mi_read in mi_format_new - uninit error after buffer allocation by __getname() - KMSAN uninit-value in ni_create_attr_list - double free of sbi->options->nls and ownership of fc->fs_private - incorrect vcn adjustments in attr_collapse_range() - mode update when ACL can be reduced to mode - memory leaks in add sub record Changes: - refactor code, updated terminology, spelling - do not kmap pages in (de)compression code - after ntfs_look_free_mft(), code that fails must put mft_inode - default mount options for "acl" and "prealloc" Replaced: - use unsafe_memcpy() to avoid memcpy size warning - ntfs_bio_pages with page cache for compressed files" * tag 'ntfs3_for_6.19' of https://github.com/Paragon-Software-Group/linux-ntfs3: (26 commits) fs/ntfs3: check for shutdown in fsync fs/ntfs3: change the default mount options for "acl" and "prealloc" fs/ntfs3: Prevent memory leaks in add sub record fs/ntfs3: out1 also needs to put mi fs/ntfs3: Fix spelling mistake "recommened" -> "recommended" fs/ntfs3: update mode in xattr when ACL can be reduced to mode fs/ntfs3: check minimum alignment for direct I/O fs/ntfs3: implement NTFS3_IOC_SHUTDOWN ioctl fs/ntfs3: correct attr_collapse_range when file is too fragmented ntfs3: fix double free of sbi->options->nls and clarify ownership of fc->fs_private fs/ntfs3: Initialize allocated memory before use fs/ntfs3: remove ntfs_bio_pages and use page cache for compressed I/O ntfs3: avoid memcpy size warning fs/ntfs3: fix KMSAN uninit-value in ni_create_attr_list ntfs3: init run lock for extend inode ntfs: set dummy blocksize to read boot_block when mounting fs/ntfs3: disable readahead for compressed files ntfs3: Fix uninit buffer allocated by __getname() ntfs3: fix uninit memory after failed mi_read in mi_format_new ntfs3: fix use-after-free of sbi->options in cmp_fnames ...
2 parents fbeea4d + 1b2ae19 commit 559e608

13 files changed

Lines changed: 421 additions & 331 deletions

File tree

fs/ntfs3/attrib.c

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,6 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
14571457
pgoff_t index = vbo[i] >> PAGE_SHIFT;
14581458

14591459
if (index != folio->index) {
1460-
struct page *page = &folio->page;
14611460
u64 from = vbo[i] & ~(u64)(PAGE_SIZE - 1);
14621461
u64 to = min(from + PAGE_SIZE, wof_size);
14631462

@@ -1467,8 +1466,7 @@ int attr_wof_frame_info(struct ntfs_inode *ni, struct ATTRIB *attr,
14671466
if (err)
14681467
goto out1;
14691468

1470-
err = ntfs_bio_pages(sbi, run, &page, 1, from,
1471-
to - from, REQ_OP_READ);
1469+
err = ntfs_read_run(sbi, run, addr, from, to - from);
14721470
if (err) {
14731471
folio->index = -1;
14741472
goto out1;
@@ -1862,7 +1860,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
18621860
struct ATTRIB *attr = NULL, *attr_b;
18631861
struct ATTR_LIST_ENTRY *le, *le_b;
18641862
struct mft_inode *mi, *mi_b;
1865-
CLST svcn, evcn1, len, dealloc, alen;
1863+
CLST svcn, evcn1, len, dealloc, alen, done;
18661864
CLST vcn, end;
18671865
u64 valid_size, data_size, alloc_size, total_size;
18681866
u32 mask;
@@ -1925,6 +1923,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19251923
len = bytes >> sbi->cluster_bits;
19261924
end = vcn + len;
19271925
dealloc = 0;
1926+
done = 0;
19281927

19291928
svcn = le64_to_cpu(attr_b->nres.svcn);
19301929
evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
@@ -1933,23 +1932,28 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19331932
attr = attr_b;
19341933
le = le_b;
19351934
mi = mi_b;
1936-
} else if (!le_b) {
1935+
goto check_seg;
1936+
}
1937+
1938+
if (!le_b) {
19371939
err = -EINVAL;
19381940
goto out;
1939-
} else {
1940-
le = le_b;
1941-
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
1942-
&mi);
1943-
if (!attr) {
1944-
err = -EINVAL;
1945-
goto out;
1946-
}
1941+
}
19471942

1948-
svcn = le64_to_cpu(attr->nres.svcn);
1949-
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
1943+
le = le_b;
1944+
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn, &mi);
1945+
if (!attr) {
1946+
err = -EINVAL;
1947+
goto out;
19501948
}
19511949

19521950
for (;;) {
1951+
CLST vcn1, eat, next_svcn;
1952+
1953+
svcn = le64_to_cpu(attr->nres.svcn);
1954+
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
1955+
1956+
check_seg:
19531957
if (svcn >= end) {
19541958
/* Shift VCN- */
19551959
attr->nres.svcn = cpu_to_le64(svcn - len);
@@ -1959,30 +1963,33 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19591963
ni->attr_list.dirty = true;
19601964
}
19611965
mi->dirty = true;
1962-
} else if (svcn < vcn || end < evcn1) {
1963-
CLST vcn1, eat, next_svcn;
1966+
goto next_attr;
1967+
}
19641968

1965-
/* Collapse a part of this attribute segment. */
1966-
err = attr_load_runs(attr, ni, run, &svcn);
1967-
if (err)
1968-
goto out;
1969-
vcn1 = max(vcn, svcn);
1970-
eat = min(end, evcn1) - vcn1;
1969+
run_truncate(run, 0);
1970+
err = attr_load_runs(attr, ni, run, &svcn);
1971+
if (err)
1972+
goto out;
19711973

1972-
err = run_deallocate_ex(sbi, run, vcn1, eat, &dealloc,
1973-
true);
1974-
if (err)
1975-
goto out;
1974+
vcn1 = vcn + done; /* original vcn in attr/run. */
1975+
eat = min(end, evcn1) - vcn1;
1976+
1977+
err = run_deallocate_ex(sbi, run, vcn1, eat, &dealloc, true);
1978+
if (err)
1979+
goto out;
19761980

1977-
if (!run_collapse_range(run, vcn1, eat)) {
1981+
if (svcn + eat < evcn1) {
1982+
/* Collapse a part of this attribute segment. */
1983+
1984+
if (!run_collapse_range(run, vcn1, eat, done)) {
19781985
err = -ENOMEM;
19791986
goto out;
19801987
}
19811988

19821989
if (svcn >= vcn) {
19831990
/* Shift VCN */
19841991
attr->nres.svcn = cpu_to_le64(vcn);
1985-
if (le) {
1992+
if (le && attr->nres.svcn != le->vcn) {
19861993
le->vcn = attr->nres.svcn;
19871994
ni->attr_list.dirty = true;
19881995
}
@@ -1993,7 +2000,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
19932000
goto out;
19942001

19952002
next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
1996-
if (next_svcn + eat < evcn1) {
2003+
if (next_svcn + eat + done < evcn1) {
19972004
err = ni_insert_nonresident(
19982005
ni, ATTR_DATA, NULL, 0, run, next_svcn,
19992006
evcn1 - eat - next_svcn, a_flags, &attr,
@@ -2007,18 +2014,9 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20072014

20082015
/* Free all allocated memory. */
20092016
run_truncate(run, 0);
2017+
done += eat;
20102018
} else {
20112019
u16 le_sz;
2012-
u16 roff = le16_to_cpu(attr->nres.run_off);
2013-
2014-
if (roff > le32_to_cpu(attr->size)) {
2015-
err = -EINVAL;
2016-
goto out;
2017-
}
2018-
2019-
run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn,
2020-
evcn1 - 1, svcn, Add2Ptr(attr, roff),
2021-
le32_to_cpu(attr->size) - roff);
20222020

20232021
/* Delete this attribute segment. */
20242022
mi_remove_attr(NULL, mi, attr);
@@ -2031,6 +2029,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20312029
goto out;
20322030
}
20332031

2032+
done += evcn1 - svcn;
20342033
if (evcn1 >= alen)
20352034
break;
20362035

@@ -2048,11 +2047,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20482047
err = -EINVAL;
20492048
goto out;
20502049
}
2051-
goto next_attr;
2050+
continue;
20522051
}
20532052
le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
20542053
}
20552054

2055+
next_attr:
20562056
if (evcn1 >= alen)
20572057
break;
20582058

@@ -2061,10 +2061,6 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
20612061
err = -EINVAL;
20622062
goto out;
20632063
}
2064-
2065-
next_attr:
2066-
svcn = le64_to_cpu(attr->nres.svcn);
2067-
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
20682064
}
20692065

20702066
if (!attr_b) {
@@ -2554,7 +2550,7 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
25542550
if (attr_load_runs(attr, ni, run, NULL))
25552551
goto bad_inode;
25562552

2557-
if (!run_collapse_range(run, vcn, len))
2553+
if (!run_collapse_range(run, vcn, len, 0))
25582554
goto bad_inode;
25592555

25602556
if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))

fs/ntfs3/dir.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,7 @@ static inline bool ntfs_dir_emit(struct ntfs_sb_info *sbi,
332332
* It does additional locks/reads just to get the type of name.
333333
* Should we use additional mount option to enable branch below?
334334
*/
335-
if (fname->dup.extend_data &&
336-
ino != ni->mi.rno) {
335+
if (fname->dup.extend_data && ino != ni->mi.rno) {
337336
struct inode *inode = ntfs_iget5(sbi->sb, &e->ref, NULL);
338337
if (!IS_ERR_OR_NULL(inode)) {
339338
dt_type = fs_umode_to_dtype(inode->i_mode);

0 commit comments

Comments
 (0)