diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-21 10:18:17 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-21 10:18:17 -0800 |
| commit | 6022ec6ee2c3a16b26f218d7abb538afb839bd6d (patch) | |
| tree | 3d76c77e65091076aec7d82c5b2eea6819bc7cea /fs | |
| parent | 04065c12072b6124475c7c4f6ad7484475a2f66e (diff) | |
| parent | 36963cf225f890f97fd84af0a82d323043edd0f1 (diff) | |
| download | linux-6022ec6ee2c3a16b26f218d7abb538afb839bd6d.tar.gz linux-6022ec6ee2c3a16b26f218d7abb538afb839bd6d.tar.bz2 linux-6022ec6ee2c3a16b26f218d7abb538afb839bd6d.zip | |
Merge tag 'ntfs3_for_6.2' of https://github.com/Paragon-Software-Group/linux-ntfs3
Pull ntfs3 updates from Konstantin Komarov:
- added mount options 'hidedotfiles', 'nocase' and 'windows_names'
- fixed xfstests (tested on x86_64): generic/083 generic/263
generic/307 generic/465
- fix some logic errors
- code refactoring and dead code removal
* tag 'ntfs3_for_6.2' of https://github.com/Paragon-Software-Group/linux-ntfs3: (61 commits)
fs/ntfs3: Make if more readable
fs/ntfs3: Improve checking of bad clusters
fs/ntfs3: Fix wrong if in hdr_first_de
fs/ntfs3: Use ALIGN kernel macro
fs/ntfs3: Fix incorrect if in ntfs_set_acl_ex
fs/ntfs3: Check fields while reading
fs/ntfs3: Correct ntfs_check_for_free_space
fs/ntfs3: Restore correct state after ENOSPC in attr_data_get_block
fs/ntfs3: Changing locking in ntfs_rename
fs/ntfs3: Fixing wrong logic in attr_set_size and ntfs_fallocate
fs/ntfs3: atomic_open implementation
fs/ntfs3: Fix wrong indentations
fs/ntfs3: Change new sparse cluster processing
fs/ntfs3: Fixing work with sparse clusters
fs/ntfs3: Simplify ntfs_update_mftmirr function
fs/ntfs3: Remove unused functions
fs/ntfs3: Fix sparse problems
fs/ntfs3: Add ntfs_bitmap_weight_le function and refactoring
fs/ntfs3: Use _le variants of bitops functions
fs/ntfs3: Add functions to modify LE bitmaps
...
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/ntfs3/attrib.c | 392 | ||||
| -rw-r--r-- | fs/ntfs3/attrlist.c | 5 | ||||
| -rw-r--r-- | fs/ntfs3/bitfunc.c | 4 | ||||
| -rw-r--r-- | fs/ntfs3/bitmap.c | 168 | ||||
| -rw-r--r-- | fs/ntfs3/dir.c | 4 | ||||
| -rw-r--r-- | fs/ntfs3/file.c | 203 | ||||
| -rw-r--r-- | fs/ntfs3/frecord.c | 40 | ||||
| -rw-r--r-- | fs/ntfs3/fslog.c | 62 | ||||
| -rw-r--r-- | fs/ntfs3/fsntfs.c | 190 | ||||
| -rw-r--r-- | fs/ntfs3/index.c | 127 | ||||
| -rw-r--r-- | fs/ntfs3/inode.c | 203 | ||||
| -rw-r--r-- | fs/ntfs3/namei.c | 238 | ||||
| -rw-r--r-- | fs/ntfs3/ntfs.h | 6 | ||||
| -rw-r--r-- | fs/ntfs3/ntfs_fs.h | 41 | ||||
| -rw-r--r-- | fs/ntfs3/record.c | 13 | ||||
| -rw-r--r-- | fs/ntfs3/run.c | 28 | ||||
| -rw-r--r-- | fs/ntfs3/super.c | 143 | ||||
| -rw-r--r-- | fs/ntfs3/upcase.c | 12 | ||||
| -rw-r--r-- | fs/ntfs3/xattr.c | 158 |
19 files changed, 1411 insertions, 626 deletions
diff --git a/fs/ntfs3/attrib.c b/fs/ntfs3/attrib.c index 71f870d497ae..5e6bafb10f42 100644 --- a/fs/ntfs3/attrib.c +++ b/fs/ntfs3/attrib.c @@ -55,33 +55,6 @@ static inline u64 get_pre_allocated(u64 size) } /* - * attr_must_be_resident - * - * Return: True if attribute must be resident. - */ -static inline bool attr_must_be_resident(struct ntfs_sb_info *sbi, - enum ATTR_TYPE type) -{ - const struct ATTR_DEF_ENTRY *de; - - switch (type) { - case ATTR_STD: - case ATTR_NAME: - case ATTR_ID: - case ATTR_LABEL: - case ATTR_VOL_INFO: - case ATTR_ROOT: - case ATTR_EA_INFO: - return true; - default: - de = ntfs_query_def(sbi, type); - if (de && (de->flags & NTFS_ATTR_MUST_BE_RESIDENT)) - return true; - return false; - } -} - -/* * attr_load_runs - Load all runs stored in @attr. */ static int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni, @@ -101,6 +74,10 @@ static int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni, asize = le32_to_cpu(attr->size); run_off = le16_to_cpu(attr->nres.run_off); + + if (run_off > asize) + return -EINVAL; + err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn, vcn ? *vcn : svcn, Add2Ptr(attr, run_off), asize - run_off); @@ -172,7 +149,7 @@ out: int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run, CLST vcn, CLST lcn, CLST len, CLST *pre_alloc, enum ALLOCATE_OPT opt, CLST *alen, const size_t fr, - CLST *new_lcn) + CLST *new_lcn, CLST *new_len) { int err; CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0; @@ -192,20 +169,36 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run, if (err) goto out; - if (new_lcn && vcn == vcn0) - *new_lcn = lcn; + if (vcn == vcn0) { + /* Return the first fragment. */ + if (new_lcn) + *new_lcn = lcn; + if (new_len) + *new_len = flen; + } /* Add new fragment into run storage. */ - if (!run_add_entry(run, vcn, lcn, flen, opt == ALLOCATE_MFT)) { + if (!run_add_entry(run, vcn, lcn, flen, opt & ALLOCATE_MFT)) { /* Undo last 'ntfs_look_for_free_space' */ mark_as_free_ex(sbi, lcn, len, false); err = -ENOMEM; goto out; } + if (opt & ALLOCATE_ZERO) { + u8 shift = sbi->cluster_bits - SECTOR_SHIFT; + + err = blkdev_issue_zeroout(sbi->sb->s_bdev, + (sector_t)lcn << shift, + (sector_t)flen << shift, + GFP_NOFS, 0); + if (err) + goto out; + } + vcn += flen; - if (flen >= len || opt == ALLOCATE_MFT || + if (flen >= len || (opt & ALLOCATE_MFT) || (fr && run->count - cnt >= fr)) { *alen = vcn - vcn0; return 0; @@ -280,7 +273,8 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr, const char *data = resident_data(attr); err = attr_allocate_clusters(sbi, run, 0, 0, len, NULL, - ALLOCATE_DEF, &alen, 0, NULL); + ALLOCATE_DEF, &alen, 0, NULL, + NULL); if (err) goto out1; @@ -420,6 +414,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn; CLST next_svcn, pre_alloc = -1, done = 0; bool is_ext, is_bad = false; + bool dirty = false; u32 align; struct MFT_REC *rec; @@ -440,8 +435,10 @@ again: return err; /* Return if file is still resident. */ - if (!attr_b->non_res) + if (!attr_b->non_res) { + dirty = true; goto ok1; + } /* Layout of records may be changed, so do a full search. */ goto again; @@ -464,7 +461,7 @@ again_1: if (keep_prealloc && new_size < old_size) { attr_b->nres.data_size = cpu_to_le64(new_size); - mi_b->dirty = true; + mi_b->dirty = dirty = true; goto ok; } @@ -510,7 +507,7 @@ next_le: if (new_alloc <= old_alloc) { attr_b->nres.data_size = cpu_to_le64(new_size); - mi_b->dirty = true; + mi_b->dirty = dirty = true; goto ok; } @@ -575,13 +572,13 @@ add_alloc_in_same_attr_seg: /* ~3 bytes per fragment. */ err = attr_allocate_clusters( sbi, run, vcn, lcn, to_allocate, &pre_alloc, - is_mft ? ALLOCATE_MFT : 0, &alen, + is_mft ? ALLOCATE_MFT : ALLOCATE_DEF, &alen, is_mft ? 0 : (sbi->record_size - le32_to_cpu(rec->used) + 8) / 3 + 1, - NULL); + NULL, NULL); if (err) goto out; } @@ -601,7 +598,7 @@ pack_runs: next_svcn = le64_to_cpu(attr->nres.evcn) + 1; new_alloc_tmp = (u64)next_svcn << cluster_bits; attr_b->nres.alloc_size = cpu_to_le64(new_alloc_tmp); - mi_b->dirty = true; + mi_b->dirty = dirty = true; if (next_svcn >= vcn && !to_allocate) { /* Normal way. Update attribute and exit. */ @@ -687,7 +684,7 @@ pack_runs: old_valid = old_size = old_alloc = (u64)vcn << cluster_bits; attr_b->nres.valid_size = attr_b->nres.data_size = attr_b->nres.alloc_size = cpu_to_le64(old_size); - mi_b->dirty = true; + mi_b->dirty = dirty = true; goto again_1; } @@ -749,7 +746,7 @@ pack_runs: attr_b->nres.valid_size = attr_b->nres.alloc_size; } - mi_b->dirty = true; + mi_b->dirty = dirty = true; err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen, true); @@ -810,16 +807,9 @@ ok1: if (ret) *ret = attr_b; - /* Update inode_set_bytes. */ if (((type == ATTR_DATA && !name_len) || (type == ATTR_ALLOC && name == I30_NAME))) { - bool dirty = false; - - if (ni->vfs_inode.i_size != new_size) { - ni->vfs_inode.i_size = new_size; - dirty = true; - } - + /* Update inode_set_bytes. */ if (attr_b->non_res) { new_alloc = le64_to_cpu(attr_b->nres.alloc_size); if (inode_get_bytes(&ni->vfs_inode) != new_alloc) { @@ -828,6 +818,7 @@ ok1: } } + /* Don't forget to update duplicate information in parent. */ if (dirty) { ni->ni_flags |= NI_FLAG_UPDATE_PARENT; mark_inode_dirty(&ni->vfs_inode); @@ -878,8 +869,19 @@ bad_inode: return err; } +/* + * attr_data_get_block - Returns 'lcn' and 'len' for given 'vcn'. + * + * @new == NULL means just to get current mapping for 'vcn' + * @new != NULL means allocate real cluster if 'vcn' maps to hole + * @zero - zeroout new allocated clusters + * + * NOTE: + * - @new != NULL is called only for sparsed or compressed attributes. + * - new allocated clusters are zeroed via blkdev_issue_zeroout. + */ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, - CLST *len, bool *new) + CLST *len, bool *new, bool zero) { int err = 0; struct runs_tree *run = &ni->file.run; @@ -888,29 +890,29 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, struct ATTRIB *attr = NULL, *attr_b; struct ATTR_LIST_ENTRY *le, *le_b; struct mft_inode *mi, *mi_b; - CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end; - u64 total_size; - u32 clst_per_frame; - bool ok; + CLST hint, svcn, to_alloc, evcn1, next_svcn, asize, end, vcn0, alen; + CLST alloc, evcn; + unsigned fr; + u64 total_size, total_size0; + int step = 0; if (new) *new = false; + /* Try to find in cache. */ down_read(&ni->file.run_lock); - ok = run_lookup_entry(run, vcn, lcn, len, NULL); + if (!run_lookup_entry(run, vcn, lcn, len, NULL)) + *len = 0; up_read(&ni->file.run_lock); - if (ok && (*lcn != SPARSE_LCN || !new)) { - /* Normal way. */ - return 0; + if (*len) { + if (*lcn != SPARSE_LCN || !new) + return 0; /* Fast normal way without allocation. */ + else if (clen > *len) + clen = *len; } - if (!clen) - clen = 1; - - if (ok && clen > *len) - clen = *len; - + /* No cluster in cache or we need to allocate cluster in hole. */ sbi = ni->mi.sbi; cluster_bits = sbi->cluster_bits; @@ -932,16 +934,15 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, asize = le64_to_cpu(attr_b->nres.alloc_size) >> cluster_bits; if (vcn >= asize) { - err = -EINVAL; + if (new) { + err = -EINVAL; + } else { + *len = 1; + *lcn = SPARSE_LCN; + } goto out; } - clst_per_frame = 1u << attr_b->nres.c_unit; - to_alloc = (clen + clst_per_frame - 1) & ~(clst_per_frame - 1); - - if (vcn + to_alloc > asize) - to_alloc = asize - vcn; - svcn = le64_to_cpu(attr_b->nres.svcn); evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1; @@ -960,36 +961,68 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, evcn1 = le64_to_cpu(attr->nres.evcn) + 1; } + /* Load in cache actual information. */ err = attr_load_runs(attr, ni, run, NULL); if (err) goto out; - if (!ok) { - ok = run_lookup_entry(run, vcn, lcn, len, NULL); - if (ok && (*lcn != SPARSE_LCN || !new)) { - /* Normal way. */ - err = 0; - goto ok; - } + if (!*len) { + if (run_lookup_entry(run, vcn, lcn, len, NULL)) { + if (*lcn != SPARSE_LCN || !new) + goto ok; /* Slow normal way without allocation. */ - if (!ok && !new) { - *len = 0; - err = 0; + if (clen > *len) + clen = *len; + } else if (!new) { + /* Here we may return -ENOENT. + * In any case caller gets zero length. */ goto ok; } - - if (ok && clen > *len) { - clen = *len; - to_alloc = (clen + clst_per_frame - 1) & - ~(clst_per_frame - 1); - } } if (!is_attr_ext(attr_b)) { + /* The code below only for sparsed or compressed attributes. */ err = -EINVAL; goto out; } + vcn0 = vcn; + to_alloc = clen; + fr = (sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1; + /* Allocate frame aligned clusters. + * ntfs.sys usually uses 16 clusters per frame for sparsed or compressed. + * ntfs3 uses 1 cluster per frame for new created sparsed files. */ + if (attr_b->nres.c_unit) { + CLST clst_per_frame = 1u << attr_b->nres.c_unit; + CLST cmask = ~(clst_per_frame - 1); + + /* Get frame aligned vcn and to_alloc. */ + vcn = vcn0 & cmask; + to_alloc = ((vcn0 + clen + clst_per_frame - 1) & cmask) - vcn; + if (fr < clst_per_frame) + fr = clst_per_frame; + zero = true; + + /* Check if 'vcn' and 'vcn0' in different attribute segments. */ + if (vcn < svcn || evcn1 <= vcn) { + /* Load attribute for truncated vcn. */ + attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, + &vcn, &mi); + if (!attr) { + err = -EINVAL; + goto out; + } + svcn = le64_to_cpu(attr->nres.svcn); + evcn1 = le64_to_cpu(attr->nres.evcn) + 1; + err = attr_load_runs(attr, ni, run, NULL); + if (err) + goto out; + } + } + + if (vcn + to_alloc > asize) + to_alloc = asize - vcn; + /* Get the last LCN to allocate from. */ hint = 0; @@ -1003,18 +1036,35 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, hint = -1; } - err = attr_allocate_clusters( - sbi, run, vcn, hint + 1, to_alloc, NULL, 0, len, - (sbi->record_size - le32_to_cpu(mi->mrec->used) + 8) / 3 + 1, - lcn); + /* Allocate and zeroout new clusters. */ + err = attr_allocate_clusters(sbi, run, vcn, hint + 1, to_alloc, NULL, + zero ? ALLOCATE_ZERO : ALLOCATE_DEF, &alen, + fr, lcn, len); if (err) goto out; *new = true; + step = 1; - end = vcn + *len; + end = vcn + alen; + /* Save 'total_size0' to restore if error. */ + total_size0 = le64_to_cpu(attr_b->nres.total_size); + total_size = total_size0 + ((u64)alen << cluster_bits); - total_size = le64_to_cpu(attr_b->nres.total_size) + - ((u64)*len << cluster_bits); + if (vcn != vcn0) { + if (!run_lookup_entry(run, vcn0, lcn, len, NULL)) { + err = -EINVAL; + goto out; + } + if (*lcn == SPARSE_LCN) { + /* Internal error. Should not happened. */ + WARN_ON(1); + err = -EINVAL; + goto out; + } + /* Check case when vcn0 + len overlaps new allocated clusters. */ + if (vcn0 + *len > end) + *len = end - vcn0; + } repack: err = mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn); @@ -1040,7 +1090,7 @@ repack: if (!ni->attr_list.size) { err = ni_create_attr_list(ni); if (err) - goto out; + goto undo1; /* Layout of records is changed. */ le_b = NULL; attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, @@ -1057,67 +1107,83 @@ repack: } } + /* + * The code below may require additional cluster (to extend attribute list) + * and / or one MFT record + * It is too complex to undo operations if -ENOSPC occurs deep inside + * in 'ni_insert_nonresident'. + * Return in advance -ENOSPC here if there are no free cluster and no free MFT. + */ + if (!ntfs_check_for_free_space(sbi, 1, 1)) { + /* Undo step 1. */ + err = -ENOSPC; + goto undo1; + } + + step = 2; svcn = evcn1; /* Estimate next attribute. */ attr = ni_find_attr(ni, attr, &le, ATTR_DATA, NULL, 0, &svcn, &mi); - if (attr) { - CLST alloc = bytes_to_cluster( - sbi, le64_to_cpu(attr_b->nres.alloc_size)); - CLST evcn = le64_to_cpu(attr->nres.evcn); - - if (end < next_svcn) - end = next_svcn; - while (end > evcn) { - /* Remove segment [svcn : evcn). */ - mi_remove_attr(NULL, mi, attr); - - if (!al_remove_le(ni, le)) { - err = -EINVAL; - goto out; - } + if (!attr) { + /* Insert new attribute segment. */ + goto ins_ext; + } - if (evcn + 1 >= alloc) { - /* Last attribute segment. */ - evcn1 = evcn + 1; - goto ins_ext; - } + /* Try to update existed attribute segment. */ + alloc = bytes_to_cluster(sbi, le64_to_cpu(attr_b->nres.alloc_size)); + evcn = le64_to_cpu(attr->nres.evcn); - if (ni_load_mi(ni, le, &mi)) { - attr = NULL; - goto out; - } + if (end < next_svcn) + end = next_svcn; + while (end > evcn) { + /* Remove segment [svcn : evcn). */ + mi_remove_attr(NULL, mi, attr); - attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, - &le->id); - if (!attr) { - err = -EINVAL; - goto out; - } - svcn = le64_to_cpu(attr->nres.svcn); - evcn = le64_to_cpu(attr->nres.evcn); + if (!al_remove_le(ni, le)) { + err = -EINVAL; + goto out; } - if (end < svcn) - end = svcn; + if (evcn + 1 >= alloc) { + /* Last attribute segment. */ + evcn1 = evcn + 1; + goto ins_ext; + } - err = attr_load_runs(attr, ni, run, &end); - if (err) + if (ni_load_mi(ni, le, &mi)) { + attr = NULL; goto out; + } - evcn1 = evcn + 1; - attr->nres.svcn = cpu_to_le64(next_svcn); - err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn); - if (err) + attr = mi_find_attr(mi, NULL, ATTR_DATA, NULL, 0, &le->id); + if (!attr) { + err = -EINVAL; goto out; + } + svcn = le64_to_cpu(attr->nres.svcn); + evcn = le64_to_cpu(attr->nres.evcn); + } - le->vcn = cpu_to_le64(next_svcn); - ni->attr_list.dirty = true; - mi->dirty = true; + if (end < svcn) + end = svcn; + + err = attr_load_runs(attr, ni, run, &end); + if (err) + goto out; + + evcn1 = evcn + 1; + attr->nres.svcn = cpu_to_le64(next_svcn); + err = mi_pack_runs(mi, attr, run, evcn1 - next_svcn); + if (err) + goto out; + + le->vcn = cpu_to_le64(next_svcn); + ni->attr_list.dirty = true; + mi->dirty = true; + next_svcn = le64_to_cpu(attr->nres.evcn) + 1; - next_svcn = le64_to_cpu(attr->nres.evcn) + 1; - } ins_ext: if (evcn1 > next_svcn) { err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run, @@ -1129,10 +1195,26 @@ ins_ext: ok: run_truncate_around(run, vcn); out: + if (err && step > 1) { + /* Too complex to restore. */ + _ntfs_bad_inode(&ni->vfs_inode); + } up_write(&ni->file.run_lock); ni_unlock(ni); return err; + +undo1: + /* Undo step1. */ + attr_b->nres.total_size = cpu_to_le64(total_size0); + inode_set_bytes(&ni->vfs_inode, total_size0); + + if (run_deallocate_ex(sbi, run, vcn, alen, NULL, false) || + !run_add_entry(run, vcn, SPARSE_LCN, alen, false) || + mi_pack_runs(mi, attr, run, max(end, evcn1) - svcn)) { + _ntfs_bad_inode(&ni->vfs_inode); + } + goto out; } int attr_data_read_resident(struct ntfs_inode *ni, struct page *page) @@ -1217,6 +1299,11 @@ int attr_load_runs_vcn(struct ntfs_inode *ni, enum ATTR_TYPE type, CLST svcn, evcn; u16 ro; + if (!ni) { + /* Is record corrupted? */ + return -ENOENT; + } + attr = ni_find_attr(ni, NULL, NULL, type, name, name_len, &vcn, NULL); if (!attr) { /* Is record corrupted? */ @@ -1232,6 +1319,10 @@ int attr_load_runs_vcn(struct ntfs_inode *ni, enum ATTR_TYPE type, } ro = le16_to_cpu(attr->nres.run_off); + + if (ro > le32_to_cpu(attr->size)) + return -EINVAL; + err = run_unpack_ex(run, ni->mi.sbi, ni->mi.rno, svcn, evcn, svcn, Add2Ptr(attr, ro), le32_to_cpu(attr->size) - ro); if (err < 0) @@ -1530,7 +1621,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, struct ATTRIB *attr = NULL, *attr_b; struct ATTR_LIST_ENTRY *le, *le_b; struct mft_inode *mi, *mi_b; - CLST svcn, evcn1, next_svcn, lcn, len; + CLST svcn, evcn1, next_svcn, len; CLST vcn, end, clst_data; u64 total_size, valid_size, data_size; @@ -1606,8 +1697,9 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, } err = attr_allocate_clusters(sbi, run, vcn + clst_data, - hint + 1, len - clst_data, NULL, 0, - &alen, 0, &lcn); + hint + 1, len - clst_data, NULL, + ALLOCATE_DEF, &alen, 0, NULL, + NULL); if (err) goto out; @@ -1901,6 +1993,11 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) u16 le_sz; u16 roff = le16_to_cpu(attr->nres.run_off); + if (roff > le32_to_cpu(attr->size)) { + err = -EINVAL; + goto out; + } + run_unpack_ex(RUN_DEALLOCATE, sbi, ni->mi.rno, svcn, evcn1 - 1, svcn, Add2Ptr(attr, roff), le32_to_cpu(attr->size) - roff); @@ -2020,7 +2117,7 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) return -ENOENT; if (!attr_b->non_res) { - u32 data_size = le32_to_cpu(attr->res.data_size); + u32 data_size = le32_to_cpu(attr_b->res.data_size); u32 from, to; if (vbo > data_size) @@ -2290,7 +2387,8 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) if (!attr_b->non_res) { /* Still resident. */ - char *data = Add2Ptr(attr_b, attr_b->res.data_off); + char *data = Add2Ptr(attr_b, + le16_to_cpu(attr_b->res.data_off)); memmove(data + bytes, data, bytes); memset(data, 0, bytes); @@ -2382,8 +2480,8 @@ int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) if (vbo <= ni->i_valid) ni->i_valid += bytes; - attr_b->nres.data_size = le64_to_cpu(data_size + bytes); - attr_b->nres.alloc_size = le64_to_cpu(alloc_size + bytes); + attr_b->nres.data_size = cpu_to_le64(data_size + bytes); + attr_b->nres.alloc_size = cpu_to_le64(alloc_size + bytes); /* ni->valid may be not equal valid_size (temporary). */ if (ni->i_valid > data_size + bytes) diff --git a/fs/ntfs3/attrlist.c b/fs/ntfs3/attrlist.c index bad6d8a849a2..c0c6bcbc8c05 100644 --- a/fs/ntfs3/attrlist.c +++ b/fs/ntfs3/attrlist.c @@ -68,6 +68,11 @@ int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr) run_init(&ni->attr_list.run); + if (run_off > le32_to_cpu(attr->size)) { + err = -EINVAL; + goto out; + } + err = run_unpack_ex(&ni->attr_list.run, ni->mi.sbi, ni->mi.rno, 0, le64_to_cpu(attr->nres.evcn), 0, Add2Ptr(attr, run_off), diff --git a/fs/ntfs3/bitfunc.c b/fs/ntfs3/bitfunc.c index 50d838093790..25a4d4896aa9 100644 --- a/fs/ntfs3/bitfunc.c +++ b/fs/ntfs3/bitfunc.c @@ -30,7 +30,7 @@ static const u8 zero_mask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, * * Return: True if all bits [bit, bit+nbits) are zeros "0". */ -bool are_bits_clear(const ulong *lmap, size_t bit, size_t nbits) +bool are_bits_clear(const void *lmap, size_t bit, size_t nbits) { size_t pos = bit & 7; const u8 *map = (u8 *)lmap + (bit >> 3); @@ -78,7 +78,7 @@ bool are_bits_clear(const ulong *lmap, size_t bit, size_t nbits) * * Return: True if all bits [bit, bit+nbits) are ones "1". */ -bool are_bits_set(const ulong *lmap, size_t bit, size_t nbits) +bool are_bits_set(const void *lmap, size_t bit, size_t nbits) { u8 mask; size_t pos = bit & 7; diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c index e92bbd754365..723fb64e6531 100644 --- a/fs/ntfs3/bitmap.c +++ b/fs/ntfs3/bitmap.c @@ -59,14 +59,14 @@ void ntfs3_exit_bitmap(void) * * Return: -1 if not found. */ -static size_t wnd_scan(const ulong *buf, size_t wbit, u32 wpos, u32 wend, +static size_t wnd_scan(const void *buf, size_t wbit, u32 wpos, u32 wend, size_t to_alloc, size_t *prev_tail, size_t *b_pos, size_t *b_len) { while (wpos < wend) { size_t free_len; u32 free_bits, end; - u32 used = find_next_zero_bit(buf, wend, wpos); + u32 used = find_next_zero_bit_le(buf, wend, wpos); if (used >= wend) { if (*b_len < *prev_tail) { @@ -92,7 +92,7 @@ static size_t wnd_scan(const ulong *buf, size_t wbit, u32 wpos, u32 wend, * Now we have a fragment [wpos, wend) staring with 0. */ end = wpos + to_alloc - *prev_tail; - free_bits = find_next_bit(buf, min(end, wend), wpos); + free_bits = find_next_bit_le(buf, min(end, wend), wpos); free_len = *prev_tail + free_bits - wpos; @@ -504,7 +504,6 @@ static int wnd_rescan(struct wnd_bitmap *wnd) u8 cluster_bits = sbi->cluster_bits; u32 wbits = 8 * sb->s_blocksize; u32 used, frb; - const ulong *buf; size_t wpos, wbit, iw, vbo; struct buffer_head *bh = NULL; CLST lcn, clen; @@ -558,9 +557,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd) goto out; } - buf = (ulong *)bh->b_data; - - used = bitmap_weight(buf, wbits); + used = ntfs_bitmap_weight_le(bh->b_data, wbits); if (used < wbits) { frb = wbits - used; wnd->free_bits[iw] = frb; @@ -574,7 +571,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd) wbits = wnd->nbits - wbit; do { - used = find_next_zero_bit(buf, wbits, wpos); + used = find_next_zero_bit_le(bh->b_data, wbits, wpos); if (used > wpos && prev_tail) { wnd_add_free_ext(wnd, wbit + wpos - prev_tail, @@ -590,7 +587,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd) break; } - frb = find_next_bit(buf, wbits, wpos); + frb = find_next_bit_le(bh->b_data, wbits, wpos); if (frb >= wbits) { /* Keep last free block. */ prev_tail += frb - wpos; @@ -661,7 +658,7 @@ int wnd_init(struct wnd_bitmap *wnd, struct super_block *sb, size_t nbits) if (!wnd->bits_last) wnd->bits_last = wbits; - wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS); + wnd->free_bits = kcalloc(wnd->nwnd, sizeof(u16), GFP_NOFS | __GFP_NOWARN); if (!wnd->free_bits) return -ENOMEM; @@ -718,7 +715,6 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits) while (iw < wnd->nwnd && bits) { u32 tail, op; - ulong *buf; if (iw + 1 == wnd->nwnd) wbits = wnd->bits_last; @@ -732,11 +728,9 @@ int wnd_set_free(struct wnd_bitmap *wnd, size_t bit, size_t bits) break; } - buf = (ulong *)bh->b_data; - lock_buffer(bh); - __bitmap_clear(buf, wbit, op); + ntfs_bitmap_clear_le(bh->b_data, wbit, op); wnd->free_bits[iw] += op; @@ -771,7 +765,6 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits) while (iw < wnd->nwnd && bits) { u32 tail, op; - ulong *buf; if (unlikely(iw + 1 == wnd->nwnd)) wbits = wnd->bits_last; @@ -784,11 +777,10 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits) err = PTR_ERR(bh); break; } - buf = (ulong *)bh->b_data; lock_buffer(bh); - __bitmap_set(buf, wbit, op); + ntfs_bitmap_set_le(bh->b_data, wbit, op); wnd->free_bits[iw] -= op; set_buffer_uptodate(bh); @@ -809,6 +801,44 @@ int wnd_set_used(struct wnd_bitmap *wnd, size_t bit, size_t bits) } /* + * wnd_set_used_safe - Mark the bits range from bit to bit + bits as used. + * + * Unlikely wnd_set_used/wnd_set_free this function is not full trusted. + * It scans every bit in bitmap and marks free bit as used. + * @done - how many bits were marked as used. + * + * NOTE: normally *done should be 0. + */ +int wnd_set_used_safe(struct wnd_bitmap *wnd, size_t bit, size_t bits, + size_t *done) +{ + size_t i, from = 0, len = 0; + int err = 0; + + *done = 0; + for (i = 0; i < bits; i++) { + if (wnd_is_free(wnd, bit + i, 1)) { + if (!len) + from = bit + i; + len += 1; + } else if (len) { + err = wnd_set_used(wnd, from, len); + *done += len; + len = 0; + if (err) + break; + } + } + + if (len) { + /* last fragment. */ + err = wnd_set_used(wnd, from, len); + *done += len; + } + return err; +} + +/* * wnd_is_free_hlp * * Return: True if all clusters [bit, bit+bits) are free (bitmap only). @@ -836,7 +866,7 @@ static bool wnd_is_free_hlp(struct wnd_bitmap *wnd, size_t bit, size_t bits) if (IS_ERR(bh)) return false; - ret = are_bits_clear((ulong *)bh->b_data, wbit, op); + ret = are_bits_clear(bh->b_data, wbit, op); put_bh(bh); if (!ret) @@ -928,7 +958,7 @@ use_wnd: if (IS_ERR(bh)) goto out; - ret = are_bits_set((ulong *)bh->b_data, wbit, op); + ret = are_bits_set(bh->b_data, wbit, op); put_bh(bh); if (!ret) goto out; @@ -959,7 +989,6 @@ size_t wnd_find(struct wnd_bitmap *wnd, size_t to_alloc, size_t hint, size_t fnd, max_alloc, b_len, b_pos; size_t iw, prev_tail, nwnd, wbit, ebit, zbit, zend; size_t to_alloc0 = to_alloc; - const ulong *buf; const struct e_node *e; const struct rb_node *pr, *cr; u8 log2_bits; @@ -1185,14 +1214,13 @@ Again: continue; } - buf = (ulong *)bh->b_data; - /* Scan range [wbit, zbit). */ if (wpos < wzbit) { /* Scan range [wpos, zbit). */ - fnd = wnd_scan(buf, wbit, wpos, wzbit, - to_alloc, &prev_tail, - &b_pos, &b_len); + fnd = wnd_scan(bh->b_data, wbit, wpos, + wzbit, to_alloc, + &prev_tail, &b_pos, + &b_len); if (fnd != MINUS_ONE_T) { put_bh(bh); goto found; @@ -1203,7 +1231,7 @@ Again: /* Scan range [zend, ebit). */ if (wzend < wbits) { - fnd = wnd_scan(buf, wbit, + fnd = wnd_scan(bh->b_data, wbit, max(wzend, wpos), wbits, to_alloc, &prev_tail, &b_pos, &b_len); @@ -1242,11 +1270,9 @@ Again: continue; } - buf = (ulong *)bh->b_data; - /* Scan range [wpos, eBits). */ - fnd = wnd_scan(buf, wbit, wpos, wbits, to_alloc, &prev_tail, - &b_pos, &b_len); + fnd = wnd_scan(bh->b_data, wbit, wpos, wbits, to_alloc, + &prev_tail, &b_pos, &b_ |
