Skip to content

Commit c380b52

Browse files
fs/ntfs3: Change new sparse cluster processing
Remove ntfs_sparse_cluster. Zero clusters in attr_allocate_clusters. Fixes xfstest generic/263 Signed-off-by: Konstantin Komarov <[email protected]>
1 parent 2f56a3f commit c380b52

File tree

6 files changed

+166
-181
lines changed

6 files changed

+166
-181
lines changed

fs/ntfs3/attrib.c

Lines changed: 122 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static int run_deallocate_ex(struct ntfs_sb_info *sbi, struct runs_tree *run,
149149
int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
150150
CLST vcn, CLST lcn, CLST len, CLST *pre_alloc,
151151
enum ALLOCATE_OPT opt, CLST *alen, const size_t fr,
152-
CLST *new_lcn)
152+
CLST *new_lcn, CLST *new_len)
153153
{
154154
int err;
155155
CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0;
@@ -169,20 +169,36 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
169169
if (err)
170170
goto out;
171171

172-
if (new_lcn && vcn == vcn0)
173-
*new_lcn = lcn;
172+
if (vcn == vcn0) {
173+
/* Return the first fragment. */
174+
if (new_lcn)
175+
*new_lcn = lcn;
176+
if (new_len)
177+
*new_len = flen;
178+
}
174179

175180
/* Add new fragment into run storage. */
176-
if (!run_add_entry(run, vcn, lcn, flen, opt == ALLOCATE_MFT)) {
181+
if (!run_add_entry(run, vcn, lcn, flen, opt & ALLOCATE_MFT)) {
177182
/* Undo last 'ntfs_look_for_free_space' */
178183
mark_as_free_ex(sbi, lcn, len, false);
179184
err = -ENOMEM;
180185
goto out;
181186
}
182187

188+
if (opt & ALLOCATE_ZERO) {
189+
u8 shift = sbi->cluster_bits - SECTOR_SHIFT;
190+
191+
err = blkdev_issue_zeroout(sbi->sb->s_bdev,
192+
(sector_t)lcn << shift,
193+
(sector_t)flen << shift,
194+
GFP_NOFS, 0);
195+
if (err)
196+
goto out;
197+
}
198+
183199
vcn += flen;
184200

185-
if (flen >= len || opt == ALLOCATE_MFT ||
201+
if (flen >= len || (opt & ALLOCATE_MFT) ||
186202
(fr && run->count - cnt >= fr)) {
187203
*alen = vcn - vcn0;
188204
return 0;
@@ -257,7 +273,8 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
257273
const char *data = resident_data(attr);
258274

259275
err = attr_allocate_clusters(sbi, run, 0, 0, len, NULL,
260-
ALLOCATE_DEF, &alen, 0, NULL);
276+
ALLOCATE_DEF, &alen, 0, NULL,
277+
NULL);
261278
if (err)
262279
goto out1;
263280

@@ -552,13 +569,13 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
552569
/* ~3 bytes per fragment. */
553570
err = attr_allocate_clusters(
554571
sbi, run, vcn, lcn, to_allocate, &pre_alloc,
555-
is_mft ? ALLOCATE_MFT : 0, &alen,
572+
is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen,
556573
is_mft ? 0
557574
: (sbi->record_size -
558575
le32_to_cpu(rec->used) + 8) /
559576
3 +
560577
1,
561-
NULL);
578+
NULL, NULL);
562579
if (err)
563580
goto out;
564581
}
@@ -855,8 +872,19 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
855872
return err;
856873
}
857874

875+
/*
876+
* attr_data_get_block - Returns 'lcn' and 'len' for given 'vcn'.
877+
*
878+
* @new == NULL means just to get current mapping for 'vcn'
879+
* @new != NULL means allocate real cluster if 'vcn' maps to hole
880+
* @zero - zeroout new allocated clusters
881+
*
882+
* NOTE:
883+
* - @new != NULL is called only for sparsed or compressed attributes.
884+
* - new allocated clusters are zeroed via blkdev_issue_zeroout.
885+
*/
858886
int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
859-
CLST *len, bool *new)
887+
CLST *len, bool *new, bool zero)
860888
{
861889
int err = 0;
862890
struct runs_tree *run = &ni->file.run;
@@ -865,29 +893,27 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
865893
struct ATTRIB *attr = NULL, *attr_b;
866894
struct ATTR_LIST_ENTRY *le, *le_b;
867895
struct mft_inode *mi, *mi_b;
868-
CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end;
896+
CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0, alen;
897+
unsigned fr;
869898
u64 total_size;
870-
u32 clst_per_frame;
871-
bool ok;
872899

873900
if (new)
874901
*new = false;
875902

903+
/* Try to find in cache. */
876904
down_read(&ni->file.run_lock);
877-
ok = run_lookup_entry(run, vcn, lcn, len, NULL);
905+
if (!run_lookup_entry(run, vcn, lcn, len, NULL))
906+
*len = 0;
878907
up_read(&ni->file.run_lock);
879908

880-
if (ok && (*lcn != SPARSE_LCN || !new)) {
881-
/* Normal way. */
882-
return 0;
909+
if (*len) {
910+
if (*lcn != SPARSE_LCN || !new)
911+
return 0; /* Fast normal way without allocation. */
912+
else if (clen > *len)
913+
clen = *len;
883914
}
884915

885-
if (!clen)
886-
clen = 1;
887-
888-
if (ok && clen > *len)
889-
clen = *len;
890-
916+
/* No cluster in cache or we need to allocate cluster in hole. */
891917
sbi = ni->mi.sbi;
892918
cluster_bits = sbi->cluster_bits;
893919

@@ -913,12 +939,6 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
913939
goto out;
914940
}
915941

916-
clst_per_frame = 1u << attr_b->nres.c_unit;
917-
to_alloc = (clen + clst_per_frame - 1) & ~(clst_per_frame - 1);
918-
919-
if (vcn + to_alloc > asize)
920-
to_alloc = asize - vcn;
921-
922942
svcn = le64_to_cpu(attr_b->nres.svcn);
923943
evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
924944

@@ -937,36 +957,68 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
937957
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
938958
}
939959

960+
/* Load in cache actual information. */
940961
err = attr_load_runs(attr, ni, run, NULL);
941962
if (err)
942963
goto out;
943964

944-
if (!ok) {
945-
ok = run_lookup_entry(run, vcn, lcn, len, NULL);
946-
if (ok && (*lcn != SPARSE_LCN || !new)) {
947-
/* Normal way. */
948-
err = 0;
949-
goto ok;
950-
}
965+
if (!*len) {
966+
if (run_lookup_entry(run, vcn, lcn, len, NULL)) {
967+
if (*lcn != SPARSE_LCN || !new)
968+
goto ok; /* Slow normal way without allocation. */
951969

952-
if (!ok && !new) {
953-
*len = 0;
954-
err = 0;
970+
if (clen > *len)
971+
clen = *len;
972+
} else if (!new) {
973+
/* Here we may return -ENOENT.
974+
* In any case caller gets zero length. */
955975
goto ok;
956976
}
957-
958-
if (ok && clen > *len) {
959-
clen = *len;
960-
to_alloc = (clen + clst_per_frame - 1) &
961-
~(clst_per_frame - 1);
962-
}
963977
}
964978

965979
if (!is_attr_ext(attr_b)) {
980+
/* The code below only for sparsed or compressed attributes. */
966981
err = -EINVAL;
967982
goto out;
968983
}
969984

985+
vcn0 = vcn;
986+
to_alloc = clen;
987+
fr = (sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1;
988+
/* Allocate frame aligned clusters.
989+
* ntfs.sys usually uses 16 clusters per frame for sparsed or compressed.
990+
* ntfs3 uses 1 cluster per frame for new created sparsed files. */
991+
if (attr_b->nres.c_unit) {
992+
CLST clst_per_frame = 1u << attr_b->nres.c_unit;
993+
CLST cmask = ~(clst_per_frame - 1);
994+
995+
/* Get frame aligned vcn and to_alloc. */
996+
vcn = vcn0 & cmask;
997+
to_alloc = ((vcn0 + clen + clst_per_frame - 1) & cmask) - vcn;
998+
if (fr < clst_per_frame)
999+
fr = clst_per_frame;
1000+
zero = true;
1001+
1002+
/* Check if 'vcn' and 'vcn0' in different attribute segments. */
1003+
if (vcn < svcn || evcn1 <= vcn) {
1004+
/* Load attribute for truncated vcn. */
1005+
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0,
1006+
&vcn, &mi);
1007+
if (!attr) {
1008+
err = -EINVAL;
1009+
goto out;
1010+
}
1011+
svcn = le64_to_cpu(attr->nres.svcn);
1012+
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
1013+
err = attr_load_runs(attr, ni, run, NULL);
1014+
if (err)
1015+
goto out;
1016+
}
1017+
}
1018+
1019+
if (vcn + to_alloc > asize)
1020+
to_alloc = asize - vcn;
1021+
9701022
/* Get the last LCN to allocate from. */
9711023
hint = 0;
9721024

@@ -980,18 +1032,33 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
9801032
hint = -1;
9811033
}
9821034

983-
err = attr_allocate_clusters(
984-
sbi, run, vcn, hint + 1, to_alloc, NULL, 0, len,
985-
(sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1,
986-
lcn);
1035+
/* Allocate and zeroout new clusters. */
1036+
err = attr_allocate_clusters(sbi, run, vcn, hint + 1, to_alloc, NULL,
1037+
zero ? ALLOCATE_ZERO : ALLOCATE_DEF, &alen,
1038+
fr, lcn, len);
9871039
if (err)
9881040
goto out;
9891041
*new = true;
9901042

991-
end = vcn + *len;
992-
1043+
end = vcn + alen;
9931044
total_size = le64_to_cpu(attr_b->nres.total_size) +
994-
((u64)*len << cluster_bits);
1045+
((u64)alen << cluster_bits);
1046+
1047+
if (vcn != vcn0) {
1048+
if (!run_lookup_entry(run, vcn0, lcn, len, NULL)) {
1049+
err = -EINVAL;
1050+
goto out;
1051+
}
1052+
if (*lcn == SPARSE_LCN) {
1053+
/* Internal error. Should not happened. */
1054+
WARN_ON(1);
1055+
err = -EINVAL;
1056+
goto out;
1057+
}
1058+
/* Check case when vcn0 + len overlaps new allocated clusters. */
1059+
if (vcn0 + *len > end)
1060+
*len = end - vcn0;
1061+
}
9951062

9961063
repack:
9971064
err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn);
@@ -1516,7 +1583,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
15161583
struct ATTRIB *attr = NULL, *attr_b;
15171584
struct ATTR_LIST_ENTRY *le, *le_b;
15181585
struct mft_inode *mi, *mi_b;
1519-
CLST svcn, evcn1, next_svcn, lcn, len;
1586+
CLST svcn, evcn1, next_svcn, len;
15201587
CLST vcn, end, clst_data;
15211588
u64 total_size, valid_size, data_size;
15221589

@@ -1592,8 +1659,9 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
15921659
}
15931660

15941661
err = attr_allocate_clusters(sbi, run, vcn + clst_data,
1595-
hint + 1, len - clst_data, NULL, 0,
1596-
&alen, 0, &lcn);
1662+
hint + 1, len - clst_data, NULL,
1663+
ALLOCATE_DEF, &alen, 0, NULL,
1664+
NULL);
15971665
if (err)
15981666
goto out;
15991667

0 commit comments

Comments
 (0)