Commit 3b06a275 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ntfs3_for_6.0' of https://github.com/Paragon-Software-Group/linux-ntfs3

Pull ntfs3 updates from Konstantin Komarov:

 - implement FALLOC_FL_INSERT_RANGE

 - fix some logic errors

 - fixed xfstests (tested on x86_64): generic/064 generic/213
   generic/300 generic/361 generic/449 generic/485

 - some dead code removed or refactored

* tag 'ntfs3_for_6.0' of https://github.com/Paragon-Software-Group/linux-ntfs3: (39 commits)
  fs/ntfs3: uninitialized variable in ntfs_set_acl_ex()
  fs/ntfs3: Remove unused function wnd_bits
  fs/ntfs3: Make ni_ins_new_attr return error
  fs/ntfs3: Create MFT zone only if length is large enough
  fs/ntfs3: Refactoring attr_insert_range to restore after errors
  fs/ntfs3: Refactoring attr_punch_hole to restore after errors
  fs/ntfs3: Refactoring attr_set_size to restore after errors
  fs/ntfs3: New function ntfs_bad_inode
  fs/ntfs3: Make MFT zone less fragmented
  fs/ntfs3: Check possible errors in run_pack in advance
  fs/ntfs3: Added comments to frecord functions
  fs/ntfs3: Fill duplicate info in ni_add_name
  fs/ntfs3: Make static function attr_load_runs
  fs/ntfs3: Add new argument is_mft to ntfs_mark_rec_free
  fs/ntfs3: Remove unused mi_mark_free
  fs/ntfs3: Fix very fragmented case in attr_punch_hole
  fs/ntfs3: Fix work with fragmented xattr
  fs/ntfs3: Make ntfs_fallocate return -ENOSPC instead of -EFBIG
  fs/ntfs3: extend ni_insert_nonresident to return inserted ATTR_LIST_ENTRY
  fs/ntfs3: Check reserved size for maximum allowed
  ...
parents ae2a8236 d4073595
...@@ -84,7 +84,7 @@ static inline bool attr_must_be_resident(struct ntfs_sb_info *sbi, ...@@ -84,7 +84,7 @@ static inline bool attr_must_be_resident(struct ntfs_sb_info *sbi,
/* /*
* attr_load_runs - Load all runs stored in @attr. * attr_load_runs - Load all runs stored in @attr.
*/ */
int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni, static int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
struct runs_tree *run, const CLST *vcn) struct runs_tree *run, const CLST *vcn)
{ {
int err; int err;
...@@ -140,7 +140,10 @@ static int run_deallocate_ex(struct ntfs_sb_info *sbi, struct runs_tree *run, ...@@ -140,7 +140,10 @@ static int run_deallocate_ex(struct ntfs_sb_info *sbi, struct runs_tree *run,
} }
if (lcn != SPARSE_LCN) { if (lcn != SPARSE_LCN) {
if (sbi) {
/* mark bitmap range [lcn + clen) as free and trim clusters. */
mark_as_free_ex(sbi, lcn, clen, trim); mark_as_free_ex(sbi, lcn, clen, trim);
}
dn += clen; dn += clen;
} }
...@@ -173,7 +176,6 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run, ...@@ -173,7 +176,6 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
{ {
int err; int err;
CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0; CLST flen, vcn0 = vcn, pre = pre_alloc ? *pre_alloc : 0;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
size_t cnt = run->count; size_t cnt = run->count;
for (;;) { for (;;) {
...@@ -196,9 +198,7 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run, ...@@ -196,9 +198,7 @@ int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
/* Add new fragment into run storage. */ /* 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' */ /* Undo last 'ntfs_look_for_free_space' */
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS); mark_as_free_ex(sbi, lcn, len, false);
wnd_set_free(wnd, lcn, flen);
up_write(&wnd->rw_lock);
err = -ENOMEM; err = -ENOMEM;
goto out; goto out;
} }
...@@ -320,7 +320,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr, ...@@ -320,7 +320,7 @@ int attr_make_nonresident(struct ntfs_inode *ni, struct ATTRIB *attr,
err = ni_insert_nonresident(ni, attr_s->type, attr_name(attr_s), err = ni_insert_nonresident(ni, attr_s->type, attr_name(attr_s),
attr_s->name_len, run, 0, alen, attr_s->name_len, run, 0, alen,
attr_s->flags, &attr, NULL); attr_s->flags, &attr, NULL, NULL);
if (err) if (err)
goto out3; goto out3;
...@@ -419,40 +419,44 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -419,40 +419,44 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
struct mft_inode *mi, *mi_b; struct mft_inode *mi, *mi_b;
CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn; CLST alen, vcn, lcn, new_alen, old_alen, svcn, evcn;
CLST next_svcn, pre_alloc = -1, done = 0; CLST next_svcn, pre_alloc = -1, done = 0;
bool is_ext; bool is_ext, is_bad = false;
u32 align; u32 align;
struct MFT_REC *rec; struct MFT_REC *rec;
again: again:
alen = 0;
le_b = NULL; le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, NULL, attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, NULL,
&mi_b); &mi_b);
if (!attr_b) { if (!attr_b) {
err = -ENOENT; err = -ENOENT;
goto out; goto bad_inode;
} }
if (!attr_b->non_res) { if (!attr_b->non_res) {
err = attr_set_size_res(ni, attr_b, le_b, mi_b, new_size, run, err = attr_set_size_res(ni, attr_b, le_b, mi_b, new_size, run,
&attr_b); &attr_b);
if (err || !attr_b->non_res) if (err)
goto out; return err;
/* Return if file is still resident. */
if (!attr_b->non_res)
goto ok1;
/* Layout of records may be changed, so do a full search. */ /* Layout of records may be changed, so do a full search. */
goto again; goto again;
} }
is_ext = is_attr_ext(attr_b); is_ext = is_attr_ext(attr_b);
again_1:
align = sbi->cluster_size; align = sbi->cluster_size;
if (is_ext) if (is_ext)
align <<= attr_b->nres.c_unit; align <<= attr_b->nres.c_unit;
old_valid = le64_to_cpu(attr_b->nres.valid_size); old_valid = le64_to_cpu(attr_b->nres.valid_size);
old_size = le64_to_cpu(attr_b->nres.data_size); old_size = le64_to_cpu(attr_b->nres.data_size);
old_alloc = le64_to_cpu(attr_b->nres.alloc_size); old_alloc = le64_to_cpu(attr_b->nres.alloc_size);
again_1:
old_alen = old_alloc >> cluster_bits; old_alen = old_alloc >> cluster_bits;
new_alloc = (new_size + align - 1) & ~(u64)(align - 1); new_alloc = (new_size + align - 1) & ~(u64)(align - 1);
...@@ -475,24 +479,27 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -475,24 +479,27 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
mi = mi_b; mi = mi_b;
} else if (!le_b) { } else if (!le_b) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} else { } else {
le = le_b; le = le_b;
attr = ni_find_attr(ni, attr_b, &le, type, name, name_len, &vcn, attr = ni_find_attr(ni, attr_b, &le, type, name, name_len, &vcn,
&mi); &mi);
if (!attr) { if (!attr) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
next_le_1: next_le_1:
svcn = le64_to_cpu(attr->nres.svcn); svcn = le64_to_cpu(attr->nres.svcn);
evcn = le64_to_cpu(attr->nres.evcn); evcn = le64_to_cpu(attr->nres.evcn);
} }
/*
* Here we have:
* attr,mi,le - last attribute segment (containing 'vcn').
* attr_b,mi_b,le_b - base (primary) attribute segment.
*/
next_le: next_le:
rec = mi->mrec; rec = mi->mrec;
err = attr_load_runs(attr, ni, run, NULL); err = attr_load_runs(attr, ni, run, NULL);
if (err) if (err)
goto out; goto out;
...@@ -507,6 +514,13 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -507,6 +514,13 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
goto ok; goto ok;
} }
/*
* Add clusters. In simple case we have to:
* - allocate space (vcn, lcn, len)
* - update packed run in 'mi'
* - update attr->nres.evcn
* - update attr_b->nres.data_size/attr_b->nres.alloc_size
*/
to_allocate = new_alen - old_alen; to_allocate = new_alen - old_alen;
add_alloc_in_same_attr_seg: add_alloc_in_same_attr_seg:
lcn = 0; lcn = 0;
...@@ -520,9 +534,11 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -520,9 +534,11 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
pre_alloc = 0; pre_alloc = 0;
if (type == ATTR_DATA && !name_len && if (type == ATTR_DATA && !name_len &&
sbi->options->prealloc) { sbi->options->prealloc) {
CLST new_alen2 = bytes_to_cluster( pre_alloc =
sbi, get_pre_allocated(new_size)); bytes_to_cluster(
pre_alloc = new_alen2 - new_alen; sbi,
get_pre_allocated(new_size)) -
new_alen;
} }
/* Get the last LCN to allocate from. */ /* Get the last LCN to allocate from. */
...@@ -580,7 +596,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -580,7 +596,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
pack_runs: pack_runs:
err = mi_pack_runs(mi, attr, run, vcn - svcn); err = mi_pack_runs(mi, attr, run, vcn - svcn);
if (err) if (err)
goto out; goto undo_1;
next_svcn = le64_to_cpu(attr->nres.evcn) + 1; next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
new_alloc_tmp = (u64)next_svcn << cluster_bits; new_alloc_tmp = (u64)next_svcn << cluster_bits;
...@@ -614,7 +630,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -614,7 +630,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (type == ATTR_LIST) { if (type == ATTR_LIST) {
err = ni_expand_list(ni); err = ni_expand_list(ni);
if (err) if (err)
goto out; goto undo_2;
if (next_svcn < vcn) if (next_svcn < vcn)
goto pack_runs; goto pack_runs;
...@@ -624,8 +640,9 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -624,8 +640,9 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (!ni->attr_list.size) { if (!ni->attr_list.size) {
err = ni_create_attr_list(ni); err = ni_create_attr_list(ni);
/* In case of error layout of records is not changed. */
if (err) if (err)
goto out; goto undo_2;
/* Layout of records is changed. */ /* Layout of records is changed. */
} }
...@@ -637,48 +654,57 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -637,48 +654,57 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
/* Insert new attribute segment. */ /* Insert new attribute segment. */
err = ni_insert_nonresident(ni, type, name, name_len, run, err = ni_insert_nonresident(ni, type, name, name_len, run,
next_svcn, vcn - next_svcn, next_svcn, vcn - next_svcn,
attr_b->flags, &attr, &mi); attr_b->flags, &attr, &mi, NULL);
if (err)
goto out;
if (!is_mft)
run_truncate_head(run, evcn + 1);
svcn = le64_to_cpu(attr->nres.svcn);
evcn = le64_to_cpu(attr->nres.evcn);
le_b = NULL;
/* /*
* Layout of records maybe changed. * Layout of records maybe changed.
* Find base attribute to update. * Find base attribute to update.
*/ */
le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len, attr_b = ni_find_attr(ni, NULL, &le_b, type, name, name_len,
NULL, &mi_b); NULL, &mi_b);
if (!attr_b) { if (!attr_b) {
err = -ENOENT; err = -EINVAL;
goto out; goto bad_inode;
} }
attr_b->nres.alloc_size = cpu_to_le64((u64)vcn << cluster_bits); if (err) {
attr_b->nres.data_size = attr_b->nres.alloc_size; /* ni_insert_nonresident failed. */
attr_b->nres.valid_size = attr_b->nres.alloc_size; attr = NULL;
goto undo_2;
}
if (!is_mft)
run_truncate_head(run, evcn + 1);
svcn = le64_to_cpu(attr->nres.svcn);
evcn = le64_to_cpu(attr->nres.evcn);
/*
* Attribute is in consistency state.
* Save this point to restore to if next steps fail.
*/
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 = true;
goto again_1; goto again_1;
} }
if (new_size != old_size || if (new_size != old_size ||
(new_alloc != old_alloc && !keep_prealloc)) { (new_alloc != old_alloc && !keep_prealloc)) {
/*
* Truncate clusters. In simple case we have to:
* - update packed run in 'mi'
* - update attr->nres.evcn
* - update attr_b->nres.data_size/attr_b->nres.alloc_size
* - mark and trim clusters as free (vcn, lcn, len)
*/
CLST dlen = 0;
vcn = max(svcn, new_alen); vcn = max(svcn, new_alen);
new_alloc_tmp = (u64)vcn << cluster_bits; new_alloc_tmp = (u64)vcn << cluster_bits;
alen = 0;
err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &alen,
true);
if (err)
goto out;
run_truncate(run, vcn);
if (vcn > svcn) { if (vcn > svcn) {
err = mi_pack_runs(mi, attr, run, vcn - svcn); err = mi_pack_runs(mi, attr, run, vcn - svcn);
if (err) if (err)
...@@ -697,7 +723,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -697,7 +723,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (!al_remove_le(ni, le)) { if (!al_remove_le(ni, le)) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz); le = (struct ATTR_LIST_ENTRY *)((u8 *)le - le_sz);
...@@ -723,12 +749,20 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -723,12 +749,20 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
attr_b->nres.valid_size = attr_b->nres.valid_size =
attr_b->nres.alloc_size; attr_b->nres.alloc_size;
} }
mi_b->dirty = true;
if (is_ext) err = run_deallocate_ex(sbi, run, vcn, evcn - vcn + 1, &dlen,
true);
if (err)
goto out;
if (is_ext) {
/* dlen - really deallocated clusters. */
le64_sub_cpu(&attr_b->nres.total_size, le64_sub_cpu(&attr_b->nres.total_size,
((u64)alen << cluster_bits)); ((u64)dlen << cluster_bits));
}
mi_b->dirty = true; run_truncate(run, vcn);
if (new_alloc_tmp <= new_alloc) if (new_alloc_tmp <= new_alloc)
goto ok; goto ok;
...@@ -747,7 +781,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -747,7 +781,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (le->type != type || le->name_len != name_len || if (le->type != type || le->name_len != name_len ||
memcmp(le_name(le), name, name_len * sizeof(short))) { memcmp(le_name(le), name, name_len * sizeof(short))) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
err = ni_load_mi(ni, le, &mi); err = ni_load_mi(ni, le, &mi);
...@@ -757,7 +791,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -757,7 +791,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id); attr = mi_find_attr(mi, NULL, type, name, name_len, &le->id);
if (!attr) { if (!attr) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
goto next_le_1; goto next_le_1;
} }
...@@ -772,12 +806,12 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -772,12 +806,12 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
} }
} }
out: ok1:
if (!err && attr_b && ret) if (ret)
*ret = attr_b; *ret = attr_b;
/* Update inode_set_bytes. */ /* Update inode_set_bytes. */
if (!err && ((type == ATTR_DATA && !name_len) || if (((type == ATTR_DATA && !name_len) ||
(type == ATTR_ALLOC && name == I30_NAME))) { (type == ATTR_ALLOC && name == I30_NAME))) {
bool dirty = false; bool dirty = false;
...@@ -786,7 +820,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -786,7 +820,7 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
dirty = true; dirty = true;
} }
if (attr_b && attr_b->non_res) { if (attr_b->non_res) {
new_alloc = le64_to_cpu(attr_b->nres.alloc_size); new_alloc = le64_to_cpu(attr_b->nres.alloc_size);
if (inode_get_bytes(&ni->vfs_inode) != new_alloc) { if (inode_get_bytes(&ni->vfs_inode) != new_alloc) {
inode_set_bytes(&ni->vfs_inode, new_alloc); inode_set_bytes(&ni->vfs_inode, new_alloc);
...@@ -800,6 +834,47 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -800,6 +834,47 @@ int attr_set_size(struct ntfs_inode *ni, enum ATTR_TYPE type,
} }
} }
return 0;
undo_2:
vcn -= alen;
attr_b->nres.data_size = cpu_to_le64(old_size);
attr_b->nres.valid_size = cpu_to_le64(old_valid);
attr_b->nres.alloc_size = cpu_to_le64(old_alloc);
/* Restore 'attr' and 'mi'. */
if (attr)
goto restore_run;
if (le64_to_cpu(attr_b->nres.svcn) <= svcn &&
svcn <= le64_to_cpu(attr_b->nres.evcn)) {
attr = attr_b;
le = le_b;
mi = mi_b;
} else if (!le_b) {
err = -EINVAL;
goto bad_inode;
} else {
le = le_b;
attr = ni_find_attr(ni, attr_b, &le, type, name, name_len,
&svcn, &mi);
if (!attr)
goto bad_inode;
}
restore_run:
if (mi_pack_runs(mi, attr, run, evcn - svcn + 1))
is_bad = true;
undo_1:
run_deallocate_ex(sbi, run, vcn, alen, NULL, false);
run_truncate(run, vcn);
out:
if (is_bad) {
bad_inode:
_ntfs_bad_inode(&ni->vfs_inode);
}
return err; return err;
} }
...@@ -855,7 +930,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, ...@@ -855,7 +930,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
goto out; goto out;
} }
asize = le64_to_cpu(attr_b->nres.alloc_size) >> sbi->cluster_bits; asize = le64_to_cpu(attr_b->nres.alloc_size) >> cluster_bits;
if (vcn >= asize) { if (vcn >= asize) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
...@@ -1047,7 +1122,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn, ...@@ -1047,7 +1122,7 @@ int attr_data_get_block(struct ntfs_inode *ni, CLST vcn, CLST clen, CLST *lcn,
if (evcn1 > next_svcn) { if (evcn1 > next_svcn) {
err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run, err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
next_svcn, evcn1 - next_svcn, next_svcn, evcn1 - next_svcn,
attr_b->flags, &attr, &mi); attr_b->flags, &attr, &mi, NULL);
if (err) if (err)
goto out; goto out;
} }
...@@ -1173,7 +1248,7 @@ int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1173,7 +1248,7 @@ int attr_load_runs_range(struct ntfs_inode *ni, enum ATTR_TYPE type,
{ {
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
u8 cluster_bits = sbi->cluster_bits; u8 cluster_bits = sbi->cluster_bits;
CLST vcn = from >> cluster_bits; CLST vcn;
CLST vcn_last = (to - 1) >> cluster_bits; CLST vcn_last = (to - 1) >> cluster_bits;
CLST lcn, clen; CLST lcn, clen;
int err; int err;
...@@ -1647,7 +1722,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, ...@@ -1647,7 +1722,7 @@ int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
if (evcn1 > next_svcn) { if (evcn1 > next_svcn) {
err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run, err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
next_svcn, evcn1 - next_svcn, next_svcn, evcn1 - next_svcn,
attr_b->flags, &attr, &mi); attr_b->flags, &attr, &mi, NULL);
if (err) if (err)
goto out; goto out;
} }
...@@ -1812,18 +1887,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) ...@@ -1812,18 +1887,12 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
err = ni_insert_nonresident( err = ni_insert_nonresident(
ni, ATTR_DATA, NULL, 0, run, next_svcn, ni, ATTR_DATA, NULL, 0, run, next_svcn,
evcn1 - eat - next_svcn, a_flags, &attr, evcn1 - eat - next_svcn, a_flags, &attr,
&mi); &mi, &le);
if (err) if (err)
goto out; goto out;
/* Layout of records maybe changed. */ /* Layout of records maybe changed. */
attr_b = NULL; attr_b = NULL;
le = al_find_ex(ni, NULL, ATTR_DATA, NULL, 0,
&next_svcn);
if (!le) {
err = -EINVAL;
goto out;
}
} }
/* Free all allocated memory. */ /* Free all allocated memory. */
...@@ -1918,7 +1987,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes) ...@@ -1918,7 +1987,7 @@ int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
out: out:
up_write(&ni->file.run_lock); up_write(&ni->file.run_lock);
if (err) if (err)
make_bad_inode(&ni->vfs_inode); _ntfs_bad_inode(&ni->vfs_inode);
return err; return err;
} }
...@@ -1936,9 +2005,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -1936,9 +2005,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
struct ATTRIB *attr = NULL, *attr_b; struct ATTRIB *attr = NULL, *attr_b;
struct ATTR_LIST_ENTRY *le, *le_b; struct ATTR_LIST_ENTRY *le, *le_b;
struct mft_inode *mi, *mi_b; struct mft_inode *mi, *mi_b;
CLST svcn, evcn1, vcn, len, end, alen, dealloc; CLST svcn, evcn1, vcn, len, end, alen, hole, next_svcn;
u64 total_size, alloc_size; u64 total_size, alloc_size;
u32 mask; u32 mask;
__le16 a_flags;
struct runs_tree run2;
if (!bytes) if (!bytes)
return 0; return 0;
...@@ -1990,6 +2061,9 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -1990,6 +2061,9 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
} }
down_write(&ni->file.run_lock); down_write(&ni->file.run_lock);
run_init(&run2);
run_truncate(run, 0);
/* /*
* Enumerate all attribute segments and punch hole where necessary. * Enumerate all attribute segments and punch hole where necessary.
*/ */
...@@ -1997,10 +2071,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -1997,10 +2071,11 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
vcn = vbo >> sbi->cluster_bits; vcn = vbo >> sbi->cluster_bits;
len = bytes >> sbi->cluster_bits; len = bytes >> sbi->cluster_bits;
end = vcn + len; end = vcn + len;
dealloc = 0; hole = 0;
svcn = le64_to_cpu(attr_b->nres.svcn); svcn = le64_to_cpu(attr_b->nres.svcn);
evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1; evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
a_flags = attr_b->flags;
if (svcn <= vcn && vcn < evcn1) { if (svcn <= vcn && vcn < evcn1) {
attr = attr_b; attr = attr_b;
...@@ -2008,14 +2083,14 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -2008,14 +2083,14 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
mi = mi_b; mi = mi_b;
} else if (!le_b) { } else if (!le_b) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} else { } else {
le = le_b; le = le_b;
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn, attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
&mi); &mi);
if (!attr) { if (!attr) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
svcn = le64_to_cpu(attr->nres.svcn); svcn = le64_to_cpu(attr->nres.svcn);
...@@ -2023,49 +2098,91 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -2023,49 +2098,91 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
} }
while (svcn < end) { while (svcn < end) {
CLST vcn1, zero, dealloc2; CLST vcn1, zero, hole2 = hole;
err = attr_load_runs(attr, ni, run, &svcn); err = attr_load_runs(attr, ni, run, &svcn);
if (err) if (err)
goto out; goto done;
vcn1 = max(vcn, svcn); vcn1 = max(vcn, svcn);
zero = min(end, evcn1) - vcn1; zero = min(end, evcn1) - vcn1;
dealloc2 = dealloc; /*
err = run_deallocate_ex(sbi, run, vcn1, zero, &dealloc, true); * Check range [vcn1 + zero).
* Calculate how many clusters there are.
* Don't do any destructive actions.
*/
err = run_deallocate_ex(NULL, run, vcn1, zero, &hole2, false);
if (err) if (err)
goto out; goto done;
if (dealloc2 == dealloc) { /* Check if required range is already hole. */
/* Looks like the required range is already sparsed. */ if (hole2 == hole)
} else { goto next_attr;
if (!run_add_entry(run, vcn1, SPARSE_LCN, zero,
false)) { /* Make a clone of run to undo. */
err = run_clone(run, &run2);
if (err)
goto done;
/* Make a hole range (sparse) [vcn1 + zero). */
if (!run_add_entry(run, vcn1, SPARSE_LCN, zero, false)) {
err = -ENOMEM; err = -ENOMEM;
goto out; goto done;
} }
/* Update run in attribute segment. */
err = mi_pack_runs(mi, attr, run, evcn1 - svcn); err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
if (err) if (err)
goto out; goto done;
next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
if (next_svcn < evcn1) {
/* Insert new attribute segment. */
err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
next_svcn,
evcn1 - next_svcn, a_flags,
&attr, &mi, &le);
if (err)
goto undo_punch;
/* Layout of records maybe changed. */
attr_b = NULL;
} }
/* Real deallocate. Should not fail. */
run_deallocate_ex(sbi, &run2, vcn1, zero, &hole, true);
next_attr:
/* Free all allocated memory. */ /* Free all allocated memory. */
run_truncate(run, 0); run_truncate(run, 0);
if (evcn1 >= alen) if (evcn1 >= alen)
break; break;
/* Get next attribute segment. */
attr = ni_enum_attr_ex(ni, attr, &le, &mi); attr = ni_enum_attr_ex(ni, attr, &le, &mi);
if (!attr) { if (!attr) {
err = -EINVAL; err = -EINVAL;
goto out; goto bad_inode;
} }
svcn = le64_to_cpu(attr->nres.svcn); svcn = le64_to_cpu(attr->nres.svcn);
evcn1 = le64_to_cpu(attr->nres.evcn) + 1; evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
} }
total_size -= (u64)dealloc << sbi->cluster_bits; done:
if (!hole)
goto out;
if (!attr_b) {
attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
&mi_b);
if (!attr_b) {
err = -EINVAL;
goto bad_inode;
}
}
total_size -= (u64)hole << sbi->cluster_bits;
attr_b->nres.total_size = cpu_to_le64(total_size); attr_b->nres.total_size = cpu_to_le64(total_size);
mi_b->dirty = true; mi_b->dirty = true;
...@@ -2075,9 +2192,263 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size) ...@@ -2075,9 +2192,263 @@ int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size)
mark_inode_dirty(&ni->vfs_inode); mark_inode_dirty(&ni->vfs_inode);
out: out:
run_close(&run2);
up_write(&ni->file.run_lock); up_write(&ni->file.run_lock);
return err;
bad_inode:
_ntfs_bad_inode(&ni->vfs_inode);
goto out;
undo_punch:
/*
* Restore packed runs.
* 'mi_pack_runs' should not fail, cause we restore original.
*/
if (mi_pack_runs(mi, attr, &run2, evcn1 - svcn))
goto bad_inode;
goto done;
}
/*
* attr_insert_range - Insert range (hole) in file.
* Not for normal files.
*/
int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes)
{
int err = 0;
struct runs_tree *run = &ni->file.run;
struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTRIB *attr = NULL, *attr_b;
struct ATTR_LIST_ENTRY *le, *le_b;
struct mft_inode *mi, *mi_b;
CLST vcn, svcn, evcn1, len, next_svcn;
u64 data_size, alloc_size;
u32 mask;
__le16 a_flags;
if (!bytes)
return 0;
le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL, &mi_b);
if (!attr_b)
return -ENOENT;
if (!is_attr_ext(attr_b)) {
/* It was checked above. See fallocate. */
return -EOPNOTSUPP;
}
if (!attr_b->non_res) {
data_size = le32_to_cpu(attr_b->res.data_size);
alloc_size = data_size;
mask = sbi->cluster_mask; /* cluster_size - 1 */
} else {
data_size = le64_to_cpu(attr_b->nres.data_size);
alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
mask = (sbi->cluster_size << attr_b->nres.c_unit) - 1;
}
if (vbo > data_size) {
/* Insert range after the file size is not allowed. */
return -EINVAL;
}
if ((vbo & mask) || (bytes & mask)) {
/* Allow to insert only frame aligned ranges. */
return -EINVAL;
}
/*
* valid_size <= data_size <= alloc_size
* Check alloc_size for maximum possible.
*/
if (bytes > sbi->maxbytes_sparse - alloc_size)
return -EFBIG;
vcn = vbo >> sbi->cluster_bits;
len = bytes >> sbi->cluster_bits;
down_write(&ni->file.run_lock);
if (!attr_b->non_res) {
err = attr_set_size(ni, ATTR_DATA, NULL, 0, run,
data_size + bytes, NULL, false, NULL);
le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
&mi_b);
if (!attr_b) {
err = -EINVAL;
goto bad_inode;
}
if (err) if (err)
make_bad_inode(&ni->vfs_inode); goto out;
if (!attr_b->non_res) {
/* Still resident. */
char *data = Add2Ptr(attr_b, attr_b->res.data_off);
memmove(data + bytes, data, bytes);
memset(data, 0, bytes);
goto done;
}
/* Resident files becomes nonresident. */
data_size = le64_to_cpu(attr_b->nres.data_size);
alloc_size = le64_to_cpu(attr_b->nres.alloc_size);
}
/*
* Enumerate all attribute segments and shift start vcn.
*/
a_flags = attr_b->flags;
svcn = le64_to_cpu(attr_b->nres.svcn);
evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
if (svcn <= vcn && vcn < evcn1) {
attr = attr_b;
le = le_b;
mi = mi_b;
} else if (!le_b) {
err = -EINVAL;
goto bad_inode;
} else {
le = le_b;
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
&mi);
if (!attr) {
err = -EINVAL;
goto bad_inode;
}
svcn = le64_to_cpu(attr->nres.svcn);
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
}
run_truncate(run, 0); /* clear cached values. */
err = attr_load_runs(attr, ni, run, NULL);
if (err)
goto out;
if (!run_insert_range(run, vcn, len)) {
err = -ENOMEM;
goto out;
}
/* Try to pack in current record as much as possible. */
err = mi_pack_runs(mi, attr, run, evcn1 + len - svcn);
if (err)
goto out;
next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
attr->type == ATTR_DATA && !attr->name_len) {
le64_add_cpu(&attr->nres.svcn, len);
le64_add_cpu(&attr->nres.evcn, len);
if (le) {
le->vcn = attr->nres.svcn;
ni->attr_list.dirty = true;
}
mi->dirty = true;
}
if (next_svcn < evcn1 + len) {
err = ni_insert_nonresident(ni, ATTR_DATA, NULL, 0, run,
next_svcn, evcn1 + len - next_svcn,
a_flags, NULL, NULL, NULL);
le_b = NULL;
attr_b = ni_find_attr(ni, NULL, &le_b, ATTR_DATA, NULL, 0, NULL,
&mi_b);
if (!attr_b) {
err = -EINVAL;
goto bad_inode;
}
if (err) {
/* ni_insert_nonresident failed. Try to undo. */
goto undo_insert_range;
}
}
/*
* Update primary attribute segment.
*/
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);
/* ni->valid may be not equal valid_size (temporary). */
if (ni->i_valid > data_size + bytes)
attr_b->nres.valid_size = attr_b->nres.data_size;
else
attr_b->nres.valid_size = cpu_to_le64(ni->i_valid);
mi_b->dirty = true;
done:
ni->vfs_inode.i_size += bytes;
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
mark_inode_dirty(&ni->vfs_inode);
out:
run_truncate(run, 0); /* clear cached values. */
up_write(&ni->file.run_lock);
return err; return err;
bad_inode:
_ntfs_bad_inode(&ni->vfs_inode);
goto out;
undo_insert_range:
svcn = le64_to_cpu(attr_b->nres.svcn);
evcn1 = le64_to_cpu(attr_b->nres.evcn) + 1;
if (svcn <= vcn && vcn < evcn1) {
attr = attr_b;
le = le_b;
mi = mi_b;
} else if (!le_b) {
goto bad_inode;
} else {
le = le_b;
attr = ni_find_attr(ni, attr_b, &le, ATTR_DATA, NULL, 0, &vcn,
&mi);
if (!attr) {
goto bad_inode;
}
svcn = le64_to_cpu(attr->nres.svcn);
evcn1 = le64_to_cpu(attr->nres.evcn) + 1;
}
if (attr_load_runs(attr, ni, run, NULL))
goto bad_inode;
if (!run_collapse_range(run, vcn, len))
goto bad_inode;
if (mi_pack_runs(mi, attr, run, evcn1 + len - svcn))
goto bad_inode;
while ((attr = ni_enum_attr_ex(ni, attr, &le, &mi)) &&
attr->type == ATTR_DATA && !attr->name_len) {
le64_sub_cpu(&attr->nres.svcn, len);
le64_sub_cpu(&attr->nres.evcn, len);
if (le) {
le->vcn = attr->nres.svcn;
ni->attr_list.dirty = true;
}
mi->dirty = true;
}
goto out;
} }
...@@ -51,11 +51,6 @@ void ntfs3_exit_bitmap(void) ...@@ -51,11 +51,6 @@ void ntfs3_exit_bitmap(void)
kmem_cache_destroy(ntfs_enode_cachep); kmem_cache_destroy(ntfs_enode_cachep);
} }
static inline u32 wnd_bits(const struct wnd_bitmap *wnd, size_t i)
{
return i + 1 == wnd->nwnd ? wnd->bits_last : wnd->sb->s_blocksize * 8;
}
/* /*
* wnd_scan * wnd_scan
* *
...@@ -1333,9 +1328,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits) ...@@ -1333,9 +1328,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
if (!new_free) if (!new_free)
return -ENOMEM; return -ENOMEM;
if (new_free != wnd->free_bits) memcpy(new_free, wnd->free_bits, wnd->nwnd * sizeof(short));
memcpy(new_free, wnd->free_bits,
wnd->nwnd * sizeof(short));
memset(new_free + wnd->nwnd, 0, memset(new_free + wnd->nwnd, 0,
(new_wnd - wnd->nwnd) * sizeof(short)); (new_wnd - wnd->nwnd) * sizeof(short));
kfree(wnd->free_bits); kfree(wnd->free_bits);
...@@ -1395,9 +1388,8 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits) ...@@ -1395,9 +1388,8 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
void wnd_zone_set(struct wnd_bitmap *wnd, size_t lcn, size_t len) void wnd_zone_set(struct wnd_bitmap *wnd, size_t lcn, size_t len)
{ {
size_t zlen; size_t zlen = wnd->zone_end - wnd->zone_bit;
zlen = wnd->zone_end - wnd->zone_bit;
if (zlen) if (zlen)
wnd_add_free_ext(wnd, wnd->zone_bit, zlen, false); wnd_add_free_ext(wnd, wnd->zone_bit, zlen, false);
......
...@@ -530,21 +530,35 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size) ...@@ -530,21 +530,35 @@ static int ntfs_truncate(struct inode *inode, loff_t new_size)
static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
{ {
struct inode *inode = file->f_mapping->host; struct inode *inode = file->f_mapping->host;
struct address_space *mapping = inode->i_mapping;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info; struct ntfs_sb_info *sbi = sb->s_fs_info;
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
loff_t end = vbo + len; loff_t end = vbo + len;
loff_t vbo_down = round_down(vbo, PAGE_SIZE); loff_t vbo_down = round_down(vbo, PAGE_SIZE);
loff_t i_size; bool is_supported_holes = is_sparsed(ni) || is_compressed(ni);
loff_t i_size, new_size;
bool map_locked;
int err; int err;
/* No support for dir. */ /* No support for dir. */
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
/* Return error if mode is not supported. */ /*
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | * vfs_fallocate checks all possible combinations of mode.
FALLOC_FL_COLLAPSE_RANGE)) { * Do additional checks here before ntfs_set_state(dirty).
*/
if (mode & FALLOC_FL_PUNCH_HOLE) {
if (!is_supported_holes)
return -EOPNOTSUPP;
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
} else if (mode & FALLOC_FL_INSERT_RANGE) {
if (!is_supported_holes)
return -EOPNOTSUPP;
} else if (mode &
~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)) {
ntfs_inode_warn(inode, "fallocate(0x%x) is not supported", ntfs_inode_warn(inode, "fallocate(0x%x) is not supported",
mode); mode);
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -554,6 +568,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -554,6 +568,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
inode_lock(inode); inode_lock(inode);
i_size = inode->i_size; i_size = inode->i_size;
new_size = max(end, i_size);
map_locked = false;
if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) { if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
/* Should never be here, see ntfs_file_open. */ /* Should never be here, see ntfs_file_open. */
...@@ -561,38 +577,27 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -561,38 +577,27 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
goto out; goto out;
} }
if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
FALLOC_FL_INSERT_RANGE)) {
inode_dio_wait(inode);
filemap_invalidate_lock(mapping);
map_locked = true;
}
if (mode & FALLOC_FL_PUNCH_HOLE) { if (mode & FALLOC_FL_PUNCH_HOLE) {
u32 frame_size; u32 frame_size;
loff_t mask, vbo_a, end_a, tmp; loff_t mask, vbo_a, end_a, tmp;
if (!(mode & FALLOC_FL_KEEP_SIZE)) { err = filemap_write_and_wait_range(mapping, vbo, end - 1);
err = -EINVAL;
goto out;
}
err = filemap_write_and_wait_range(inode->i_mapping, vbo,
end - 1);
if (err) if (err)
goto out; goto out;
err = filemap_write_and_wait_range(inode->i_mapping, end, err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
LLONG_MAX);
if (err) if (err)
goto out; goto out;
inode_dio_wait(inode);
truncate_pagecache(inode, vbo_down); truncate_pagecache(inode, vbo_down);
if (!is_sparsed(ni) && !is_compressed(ni)) {
/*
* Normal file, can't make hole.
* TODO: Try to find way to save info about hole.
*/
err = -EOPNOTSUPP;
goto out;
}
ni_lock(ni); ni_lock(ni);
err = attr_punch_hole(ni, vbo, len, &frame_size); err = attr_punch_hole(ni, vbo, len, &frame_size);
ni_unlock(ni); ni_unlock(ni);
...@@ -624,17 +629,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -624,17 +629,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
ni_unlock(ni); ni_unlock(ni);
} }
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) { } else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
if (mode & ~FALLOC_FL_COLLAPSE_RANGE) {
err = -EINVAL;
goto out;
}
/* /*
* Write tail of the last page before removed range since * Write tail of the last page before removed range since
* it will get removed from the page cache below. * it will get removed from the page cache below.
*/ */
err = filemap_write_and_wait_range(inode->i_mapping, vbo_down, err = filemap_write_and_wait_range(mapping, vbo_down, vbo);
vbo);
if (err) if (err)
goto out; goto out;
...@@ -642,34 +641,58 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -642,34 +641,58 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
* Write data that will be shifted to preserve them * Write data that will be shifted to preserve them
* when discarding page cache below. * when discarding page cache below.
*/ */
err = filemap_write_and_wait_range(inode->i_mapping, end, err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
LLONG_MAX);
if (err) if (err)
goto out; goto out;
/* Wait for existing dio to complete. */
inode_dio_wait(inode);
truncate_pagecache(inode, vbo_down); truncate_pagecache(inode, vbo_down);
ni_lock(ni); ni_lock(ni);
err = attr_collapse_range(ni, vbo, len); err = attr_collapse_range(ni, vbo, len);
ni_unlock(ni); ni_unlock(ni);
} else if (mode & FALLOC_FL_INSERT_RANGE) {
/* Check new size. */
err = inode_newsize_ok(inode, new_size);
if (err)
goto out;
/* Write out all dirty pages. */
err = filemap_write_and_wait_range(mapping, vbo_down,
LLONG_MAX);
if (err)
goto out;
truncate_pagecache(inode, vbo_down);
ni_lock(ni);
err = attr_insert_range(ni, vbo, len);
ni_unlock(ni);
} else { } else {
/* /* Check new size. */
* Normal file: Allocate clusters, do not change 'valid' size.
*/ /* generic/213: expected -ENOSPC instead of -EFBIG. */
loff_t new_size = max(end, i_size); if (!is_supported_holes) {
loff_t to_alloc = new_size - inode_get_bytes(inode);
if (to_alloc > 0 &&
(to_alloc >> sbi->cluster_bits) >
wnd_zeroes(&sbi->used.bitmap)) {
err = -ENOSPC;
goto out;
}
}
err = inode_newsize_ok(inode, new_size); err = inode_newsize_ok(inode, new_size);
if (err) if (err)
goto out; goto out;
/*
* Allocate clusters, do not change 'valid' size.
*/
err = ntfs_set_size(inode, new_size); err = ntfs_set_size(inode, new_size);
if (err) if (err)
goto out; goto out;
if (is_sparsed(ni) || is_compressed(ni)) { if (is_supported_holes) {
CLST vcn_v = ni->i_valid >> sbi->cluster_bits; CLST vcn_v = ni->i_valid >> sbi->cluster_bits;
CLST vcn = vbo >> sbi->cluster_bits; CLST vcn = vbo >> sbi->cluster_bits;
CLST cend = bytes_to_cluster(sbi, end); CLST cend = bytes_to_cluster(sbi, end);
...@@ -717,8 +740,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len) ...@@ -717,8 +740,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
} }
out: out:
if (err == -EFBIG) if (map_locked)
err = -ENOSPC; filemap_invalidate_unlock(mapping);
if (!err) { if (!err) {
inode->i_ctime = inode->i_mtime = current_time(inode); inode->i_ctime = inode->i_mtime = current_time(inode);
...@@ -989,7 +1012,6 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from) ...@@ -989,7 +1012,6 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from)
if (bytes > count) if (bytes > count)
bytes = count; bytes = count;
frame = pos >> frame_bits;
frame_vbo = pos & ~(frame_size - 1); frame_vbo = pos & ~(frame_size - 1);
index = frame_vbo >> PAGE_SHIFT; index = frame_vbo >> PAGE_SHIFT;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/fiemap.h> #include <linux/fiemap.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/minmax.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include "debug.h" #include "debug.h"
...@@ -468,7 +469,7 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi, ...@@ -468,7 +469,7 @@ ni_ins_new_attr(struct ntfs_inode *ni, struct mft_inode *mi,
&ref, &le); &ref, &le);
if (err) { if (err) {
/* No memory or no space. */ /* No memory or no space. */
return NULL; return ERR_PTR(err);
} }
le_added = true; le_added = true;
...@@ -649,6 +650,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -649,6 +650,7 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
struct mft_inode *mi; struct mft_inode *mi;
u32 asize, free; u32 asize, free;
struct MFT_REF ref; struct MFT_REF ref;
struct MFT_REC *mrec;
__le16 id; __le16 id;
if (!ni->attr_list.dirty) if (!ni->attr_list.dirty)
...@@ -692,11 +694,17 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -692,11 +694,17 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
free -= asize; free -= asize;
} }
/* Make a copy of primary record to restore if error. */
mrec = kmemdup(ni->mi.mrec, sbi->record_size, GFP_NOFS);
if (!mrec)
return 0; /* Not critical. */
/* It seems that attribute list can be removed from primary record. */ /* It seems that attribute list can be removed from primary record. */
mi_remove_attr(NULL, &ni->mi, attr_list); mi_remove_attr(NULL, &ni->mi, attr_list);
/* /*
* Repeat the cycle above and move all attributes to primary record. * Repeat the cycle above and copy all attributes to primary record.
* Do not remove original attributes from subrecords!
* It should be success! * It should be success!
*/ */
le = NULL; le = NULL;
...@@ -707,14 +715,14 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -707,14 +715,14 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
mi = ni_find_mi(ni, ino_get(&le->ref)); mi = ni_find_mi(ni, ino_get(&le->ref));
if (!mi) { if (!mi) {
/* Should never happened, 'cause already checked. */ /* Should never happened, 'cause already checked. */
goto bad; goto out;
} }
attr = mi_find_attr(mi, NULL, le->type, le_name(le), attr = mi_find_attr(mi, NULL, le->type, le_name(le),
le->name_len, &le->id); le->name_len, &le->id);
if (!attr) { if (!attr) {
/* Should never happened, 'cause already checked. */ /* Should never happened, 'cause already checked. */
goto bad; goto out;
} }
asize = le32_to_cpu(attr->size); asize = le32_to_cpu(attr->size);
...@@ -724,18 +732,33 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -724,18 +732,33 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
le16_to_cpu(attr->name_off)); le16_to_cpu(attr->name_off));
if (!attr_ins) { if (!attr_ins) {
/* /*
* Internal error. * No space in primary record (already checked).
* Either no space in primary record (already checked).
* Either tried to insert another
* non indexed attribute (logic error).
*/ */
goto bad; goto out;
} }
/* Copy all except id. */ /* Copy all except id. */
id = attr_ins->id; id = attr_ins->id;
memcpy(attr_ins, attr, asize); memcpy(attr_ins, attr, asize);
attr_ins->id = id; attr_ins->id = id;
}
/*
* Repeat the cycle above and remove all attributes from subrecords.
*/
le = NULL;
while ((le = al_enumerate(ni, le))) {
if (!memcmp(&le->ref, &ref, sizeof(ref)))
continue;
mi = ni_find_mi(ni, ino_get(&le->ref));
if (!mi)
continue;
attr = mi_find_attr(mi, NULL, le->type, le_name(le),
le->name_len, &le->id);
if (!attr)
continue;
/* Remove from original record. */ /* Remove from original record. */
mi_remove_attr(NULL, mi, attr); mi_remove_attr(NULL, mi, attr);
...@@ -748,11 +771,13 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni) ...@@ -748,11 +771,13 @@ static int ni_try_remove_attr_list(struct ntfs_inode *ni)
ni->attr_list.le = NULL; ni->attr_list.le = NULL;
ni->attr_list.dirty = false; ni->attr_list.dirty = false;
kfree(mrec);
return 0;
out:
/* Restore primary record. */
swap(mrec, ni->mi.mrec);
kfree(mrec);
return 0; return 0;
bad:
ntfs_inode_err(&ni->vfs_inode, "Internal error");
make_bad_inode(&ni->vfs_inode);
return -EINVAL;
} }
/* /*
...@@ -986,6 +1011,8 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, ...@@ -986,6 +1011,8 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
name_off, svcn, ins_le); name_off, svcn, ins_le);
if (!attr) if (!attr)
continue; continue;
if (IS_ERR(attr))
return PTR_ERR(attr);
if (ins_attr) if (ins_attr)
*ins_attr = attr; *ins_attr = attr;
...@@ -1007,8 +1034,15 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, ...@@ -1007,8 +1034,15 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize, attr = ni_ins_new_attr(ni, mi, le, type, name, name_len, asize,
name_off, svcn, ins_le); name_off, svcn, ins_le);
if (!attr) if (!attr) {
err = -EINVAL;
goto out2; goto out2;
}
if (IS_ERR(attr)) {
err = PTR_ERR(attr);
goto out2;
}
if (ins_attr) if (ins_attr)
*ins_attr = attr; *ins_attr = attr;
...@@ -1020,10 +1054,9 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le, ...@@ -1020,10 +1054,9 @@ static int ni_ins_attr_ext(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le,
out2: out2:
ni_remove_mi(ni, mi); ni_remove_mi(ni, mi);
mi_put(mi); mi_put(mi);
err = -EINVAL;
out1: out1:
ntfs_mark_rec_free(sbi, rno); ntfs_mark_rec_free(sbi, rno, is_mft);
out: out:
return err; return err;
...@@ -1076,6 +1109,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1076,6 +1109,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
if (asize <= free) { if (asize <= free) {
attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len, attr = ni_ins_new_attr(ni, &ni->mi, NULL, type, name, name_len,
asize, name_off, svcn, ins_le); asize, name_off, svcn, ins_le);
if (IS_ERR(attr)) {
err = PTR_ERR(attr);
goto out;
}
if (attr) { if (attr) {
if (ins_attr) if (ins_attr)
*ins_attr = attr; *ins_attr = attr;
...@@ -1173,6 +1211,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1173,6 +1211,11 @@ static int ni_insert_attr(struct ntfs_inode *ni, enum ATTR_TYPE type,
goto out; goto out;
} }
if (IS_ERR(attr)) {
err = PTR_ERR(attr);
goto out;
}
if (ins_attr) if (ins_attr)
*ins_attr = attr; *ins_attr = attr;
if (ins_mi) if (ins_mi)
...@@ -1218,7 +1261,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni) ...@@ -1218,7 +1261,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
mft_min = mft_new; mft_min = mft_new;
mi_min = mi_new; mi_min = mi_new;
} else { } else {
ntfs_mark_rec_free(sbi, mft_new); ntfs_mark_rec_free(sbi, mft_new, true);
mft_new = 0; mft_new = 0;
ni_remove_mi(ni, mi_new); ni_remove_mi(ni, mi_new);
} }
...@@ -1262,7 +1305,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni) ...@@ -1262,7 +1305,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
done = asize - run_size - SIZEOF_NONRESIDENT; done = asize - run_size - SIZEOF_NONRESIDENT;
le32_sub_cpu(&ni->mi.mrec->used, done); le32_sub_cpu(&ni->mi.mrec->used, done);
/* Estimate the size of second part: run_buf=NULL. */ /* Estimate packed size (run_buf=NULL). */
err = run_pack(run, svcn, evcn + 1 - svcn, NULL, sbi->record_size, err = run_pack(run, svcn, evcn + 1 - svcn, NULL, sbi->record_size,
&plen); &plen);
if (err < 0) if (err < 0)
...@@ -1288,10 +1331,16 @@ static int ni_expand_mft_list(struct ntfs_inode *ni) ...@@ -1288,10 +1331,16 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
goto out; goto out;
} }
if (IS_ERR(attr)) {
err = PTR_ERR(attr);
goto out;
}
attr->non_res = 1; attr->non_res = 1;
attr->name_off = SIZEOF_NONRESIDENT_LE; attr->name_off = SIZEOF_NONRESIDENT_LE;
attr->flags = 0; attr->flags = 0;
/* This function can't fail - cause already checked above. */
run_pack(run, svcn, evcn + 1 - svcn, Add2Ptr(attr, SIZEOF_NONRESIDENT), run_pack(run, svcn, evcn + 1 - svcn, Add2Ptr(attr, SIZEOF_NONRESIDENT),
run_size, &plen); run_size, &plen);
...@@ -1301,7 +1350,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni) ...@@ -1301,7 +1350,7 @@ static int ni_expand_mft_list(struct ntfs_inode *ni)
out: out:
if (mft_new) { if (mft_new) {
ntfs_mark_rec_free(sbi, mft_new); ntfs_mark_rec_free(sbi, mft_new, true);
ni_remove_mi(ni, mi_new); ni_remove_mi(ni, mi_new);
} }
...@@ -1367,8 +1416,6 @@ int ni_expand_list(struct ntfs_inode *ni) ...@@ -1367,8 +1416,6 @@ int ni_expand_list(struct ntfs_inode *ni)
/* Split MFT data as much as possible. */ /* Split MFT data as much as possible. */
err = ni_expand_mft_list(ni); err = ni_expand_mft_list(ni);
if (err)
goto out;
out: out:
return !err && !done ? -EOPNOTSUPP : err; return !err && !done ? -EOPNOTSUPP : err;
...@@ -1381,7 +1428,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1381,7 +1428,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, const __le16 *name, u8 name_len,
const struct runs_tree *run, CLST svcn, CLST len, const struct runs_tree *run, CLST svcn, CLST len,
__le16 flags, struct ATTRIB **new_attr, __le16 flags, struct ATTRIB **new_attr,
struct mft_inode **mi) struct mft_inode **mi, struct ATTR_LIST_ENTRY **le)
{ {
int err; int err;
CLST plen; CLST plen;
...@@ -1394,6 +1441,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1394,6 +1441,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
u32 run_size, asize; u32 run_size, asize;
struct ntfs_sb_info *sbi = ni->mi.sbi; struct ntfs_sb_info *sbi = ni->mi.sbi;
/* Estimate packed size (run_buf=NULL). */
err = run_pack(run, svcn, len, NULL, sbi->max_bytes_per_attr - run_off, err = run_pack(run, svcn, len, NULL, sbi->max_bytes_per_attr - run_off,
&plen); &plen);
if (err < 0) if (err < 0)
...@@ -1414,7 +1462,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1414,7 +1462,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
} }
err = ni_insert_attr(ni, type, name, name_len, asize, name_off, svcn, err = ni_insert_attr(ni, type, name, name_len, asize, name_off, svcn,
&attr, mi, NULL); &attr, mi, le);
if (err) if (err)
goto out; goto out;
...@@ -1423,12 +1471,12 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -1423,12 +1471,12 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
attr->name_off = cpu_to_le16(name_off); attr->name_off = cpu_to_le16(name_off);
attr->flags = flags; attr->flags = flags;
/* This function can't fail - cause already checked above. */
run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size, &plen); run_pack(run, svcn, len, Add2Ptr(attr, run_off), run_size, &plen);
attr->nres.svcn = cpu_to_le64(svcn); attr->nres.svcn = cpu_to_le64(svcn);
attr->nres.evcn = cpu_to_le64((u64)svcn + len - 1); attr->nres.evcn = cpu_to_le64((u64)svcn + len - 1);
err = 0;
if (new_attr) if (new_attr)
*new_attr = attr; *new_attr = attr;
...@@ -1560,7 +1608,7 @@ int ni_delete_all(struct ntfs_inode *ni) ...@@ -1560,7 +1608,7 @@ int ni_delete_all(struct ntfs_inode *ni)
mi->dirty = true; mi->dirty = true;
mi_write(mi, 0); mi_write(mi, 0);
ntfs_mark_rec_free(sbi, mi->rno); ntfs_mark_rec_free(sbi, mi->rno, false);
ni_remove_mi(ni, mi); ni_remove_mi(ni, mi);
mi_put(mi); mi_put(mi);
node = next; node = next;
...@@ -1571,7 +1619,7 @@ int ni_delete_all(struct ntfs_inode *ni) ...@@ -1571,7 +1619,7 @@ int ni_delete_all(struct ntfs_inode *ni)
ni->mi.dirty = true; ni->mi.dirty = true;
err = mi_write(&ni->mi, 0); err = mi_write(&ni->mi, 0);
ntfs_mark_rec_free(sbi, ni->mi.rno); ntfs_mark_rec_free(sbi, ni->mi.rno, false);
return err; return err;
} }
...@@ -1589,6 +1637,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, ...@@ -1589,6 +1637,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
struct ATTRIB *attr = NULL; struct ATTRIB *attr = NULL;
struct ATTR_FILE_NAME *fname; struct ATTR_FILE_NAME *fname;
if (le)
*le = NULL; *le = NULL;
/* Enumerate all names. */ /* Enumerate all names. */
...@@ -1605,7 +1654,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni, ...@@ -1605,7 +1654,7 @@ struct ATTR_FILE_NAME *ni_fname_name(struct ntfs_inode *ni,
goto next; goto next;
if (!uni) if (!uni)
goto next; return fname;
if (uni->len != fname->name_len) if (uni->len != fname->name_len)
goto next; goto next;
...@@ -2302,10 +2351,8 @@ int ni_decompress_file(struct ntfs_inode *ni) ...@@ -2302,10 +2351,8 @@ int ni_decompress_file(struct ntfs_inode *ni)
out: out:
kfree(pages); kfree(pages);
if (err) { if (err)
make_bad_inode(inode); _ntfs_bad_inode(inode);
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
}
return err; return err;
} }
...@@ -2944,7 +2991,7 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2944,7 +2991,7 @@ bool ni_remove_name_undo(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
} }
/* /*
* ni_add_name - Add new name in MFT and in directory. * ni_add_name - Add new name into MFT and into directory.
*/ */
int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
struct NTFS_DE *de) struct NTFS_DE *de)
...@@ -2953,13 +3000,20 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2953,13 +3000,20 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
struct ATTRIB *attr; struct ATTRIB *attr;
struct ATTR_LIST_ENTRY *le; struct ATTR_LIST_ENTRY *le;
struct mft_inode *mi; struct mft_inode *mi;
struct ATTR_FILE_NAME *fname;
struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1); struct ATTR_FILE_NAME *de_name = (struct ATTR_FILE_NAME *)(de + 1);
u16 de_key_size = le16_to_cpu(de->key_size); u16 de_key_size = le16_to_cpu(de->key_size);
mi_get_ref(&ni->mi, &de->ref); mi_get_ref(&ni->mi, &de->ref);
mi_get_ref(&dir_ni->mi, &de_name->home); mi_get_ref(&dir_ni->mi, &de_name->home);
/* Insert new name in MFT. */ /* Fill duplicate from any ATTR_NAME. */
fname = ni_fname_name(ni, NULL, NULL, NULL, NULL);
if (fname)
memcpy(&de_name->dup, &fname->dup, sizeof(fname->dup));
de_name->dup.fa = ni->std_fa;
/* Insert new name into MFT. */
err = ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, &attr, err = ni_insert_resident(ni, de_key_size, ATTR_NAME, NULL, 0, &attr,
&mi, &le); &mi, &le);
if (err) if (err)
...@@ -2967,7 +3021,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni, ...@@ -2967,7 +3021,7 @@ int ni_add_name(struct ntfs_inode *dir_ni, struct ntfs_inode *ni,
memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de_name, de_key_size); memcpy(Add2Ptr(attr, SIZEOF_RESIDENT), de_name, de_key_size);
/* Insert new name in directory. */ /* Insert new name into directory. */
err = indx_insert_entry(&dir_ni->dir, dir_ni, de, ni->mi.sbi, NULL, 0); err = indx_insert_entry(&dir_ni->dir, dir_ni, de, ni->mi.sbi, NULL, 0);
if (err) if (err)
ni_remove_attr_le(ni, attr, mi, le); ni_remove_attr_le(ni, attr, mi, le);
...@@ -2991,7 +3045,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni, ...@@ -2991,7 +3045,7 @@ int ni_rename(struct ntfs_inode *dir_ni, struct ntfs_inode *new_dir_ni,
* 1) Add new name and remove old name. * 1) Add new name and remove old name.
* 2) Remove old name and add new name. * 2) Remove old name and add new name.
* *
* In most cases (not all!) adding new name in MFT and in directory can * In most cases (not all!) adding new name into MFT and into directory can
* allocate additional cluster(s). * allocate additional cluster(s).
* Second way may result to bad inode if we can't add new name * Second way may result to bad inode if we can't add new name
* and then can't restore (add) old name. * and then can't restore (add) old name.
...@@ -3261,7 +3315,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint) ...@@ -3261,7 +3315,7 @@ int ni_write_inode(struct inode *inode, int sync, const char *hint)
err = err2; err = err2;
if (is_empty) { if (is_empty) {
ntfs_mark_rec_free(sbi, mi->rno); ntfs_mark_rec_free(sbi, mi->rno, false);
rb_erase(node, &ni->mi_tree); rb_erase(node, &ni->mi_tree);
mi_put(mi); mi_put(mi);
} }
......
...@@ -3843,6 +3843,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -3843,6 +3843,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
memset(&rst_info2, 0, sizeof(struct restart_info)); memset(&rst_info2, 0, sizeof(struct restart_info));
err = log_read_rst(log, l_size, false, &rst_info2); err = log_read_rst(log, l_size, false, &rst_info2);
if (err)
goto out;
/* Determine which restart area to use. */ /* Determine which restart area to use. */
if (!rst_info2.restart || rst_info2.last_lsn <= rst_info.last_lsn) if (!rst_info2.restart || rst_info2.last_lsn <= rst_info.last_lsn)
...@@ -5057,7 +5059,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) ...@@ -5057,7 +5059,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
goto add_allocated_vcns; goto add_allocated_vcns;
vcn = le64_to_cpu(lrh->target_vcn); vcn = le64_to_cpu(lrh->target_vcn);
vcn &= ~(log->clst_per_page - 1); vcn &= ~(u64)(log->clst_per_page - 1);
add_allocated_vcns: add_allocated_vcns:
for (i = 0, vcn = le64_to_cpu(lrh->target_vcn), for (i = 0, vcn = le64_to_cpu(lrh->target_vcn),
......
...@@ -703,11 +703,13 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft, ...@@ -703,11 +703,13 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
/* /*
* ntfs_mark_rec_free - Mark record as free. * ntfs_mark_rec_free - Mark record as free.
* is_mft - true if we are changing MFT
*/ */
void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno) void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft)
{ {
struct wnd_bitmap *wnd = &sbi->mft.bitmap; struct wnd_bitmap *wnd = &sbi->mft.bitmap;
if (!is_mft)
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT); down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
if (rno >= wnd->nbits) if (rno >= wnd->nbits)
goto out; goto out;
...@@ -727,6 +729,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno) ...@@ -727,6 +729,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno)
sbi->mft.next_free = rno; sbi->mft.next_free = rno;
out: out:
if (!is_mft)
up_write(&wnd->rw_lock); up_write(&wnd->rw_lock);
} }
...@@ -780,7 +783,7 @@ int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to) ...@@ -780,7 +783,7 @@ int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to)
*/ */
int ntfs_refresh_zone(struct ntfs_sb_info *sbi) int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
{ {
CLST zone_limit, zone_max, lcn, vcn, len; CLST lcn, vcn, len;
size_t lcn_s, zlen; size_t lcn_s, zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap; struct wnd_bitmap *wnd = &sbi->used.bitmap;
struct ntfs_inode *ni = sbi->mft.ni; struct ntfs_inode *ni = sbi->mft.ni;
...@@ -789,16 +792,6 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi) ...@@ -789,16 +792,6 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
if (wnd_zone_len(wnd)) if (wnd_zone_len(wnd))
return 0; return 0;
/*
* Compute the MFT zone at two steps.
* It would be nice if we are able to allocate 1/8 of
* total clusters for MFT but not more then 512 MB.
*/
zone_limit = (512 * 1024 * 1024) >> sbi->cluster_bits;
zone_max = wnd->nbits >> 3;
if (zone_max > zone_limit)
zone_max = zone_limit;
vcn = bytes_to_cluster(sbi, vcn = bytes_to_cluster(sbi,
(u64)sbi->mft.bitmap.nbits << sbi->record_bits); (u64)sbi->mft.bitmap.nbits << sbi->record_bits);
...@@ -812,13 +805,7 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi) ...@@ -812,13 +805,7 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
lcn_s = lcn + 1; lcn_s = lcn + 1;
/* Try to allocate clusters after last MFT run. */ /* Try to allocate clusters after last MFT run. */
zlen = wnd_find(wnd, zone_max, lcn_s, 0, &lcn_s); zlen = wnd_find(wnd, sbi->zone_max, lcn_s, 0, &lcn_s);
if (!zlen) {
ntfs_notice(sbi->sb, "MftZone: unavailable");
return 0;
}
/* Truncate too large zone. */
wnd_zone_set(wnd, lcn_s, zlen); wnd_zone_set(wnd, lcn_s, zlen);
return 0; return 0;
...@@ -827,16 +814,21 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi) ...@@ -827,16 +814,21 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
/* /*
* ntfs_update_mftmirr - Update $MFTMirr data. * ntfs_update_mftmirr - Update $MFTMirr data.
*/ */
int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
{ {
int err; int err;
struct super_block *sb = sbi->sb; struct super_block *sb = sbi->sb;
u32 blocksize = sb->s_blocksize; u32 blocksize;
sector_t block1, block2; sector_t block1, block2;
u32 bytes; u32 bytes;
if (!sb)
return;
blocksize = sb->s_blocksize;
if (!(sbi->flags & NTFS_FLAGS_MFTMIRR)) if (!(sbi->flags & NTFS_FLAGS_MFTMIRR))
return 0; return;
err = 0; err = 0;
bytes = sbi->mft.recs_mirr << sbi->record_bits; bytes = sbi->mft.recs_mirr << sbi->record_bits;
...@@ -847,16 +839,13 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) ...@@ -847,16 +839,13 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
struct buffer_head *bh1, *bh2; struct buffer_head *bh1, *bh2;
bh1 = sb_bread(sb, block1++); bh1 = sb_bread(sb, block1++);
if (!bh1) { if (!bh1)
err = -EIO; return;
goto out;
}
bh2 = sb_getblk(sb, block2++); bh2 = sb_getblk(sb, block2++);
if (!bh2) { if (!bh2) {
put_bh(bh1); put_bh(bh1);
err = -EIO; return;
goto out;
} }
if (buffer_locked(bh2)) if (buffer_locked(bh2))
...@@ -876,13 +865,24 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait) ...@@ -876,13 +865,24 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
put_bh(bh2); put_bh(bh2);
if (err) if (err)
goto out; return;
} }
sbi->flags &= ~NTFS_FLAGS_MFTMIRR; sbi->flags &= ~NTFS_FLAGS_MFTMIRR;
}
out: /*
return err; * ntfs_bad_inode
*
* Marks inode as bad and marks fs as 'dirty'
*/
void ntfs_bad_inode(struct inode *inode, const char *hint)
{
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
ntfs_inode_err(inode, "%s", hint);
make_bad_inode(inode);
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
} }
/* /*
...@@ -1395,7 +1395,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr, ...@@ -1395,7 +1395,7 @@ int ntfs_write_bh(struct ntfs_sb_info *sbi, struct NTFS_RECORD_HEADER *rhdr,
if (buffer_locked(bh)) if (buffer_locked(bh))
__wait_on_buffer(bh); __wait_on_buffer(bh);
lock_buffer(nb->bh[idx]); lock_buffer(bh);
bh_data = bh->b_data + off; bh_data = bh->b_data + off;
end_data = Add2Ptr(bh_data, op); end_data = Add2Ptr(bh_data, op);
...@@ -2424,7 +2424,7 @@ static inline void ntfs_unmap_and_discard(struct ntfs_sb_info *sbi, CLST lcn, ...@@ -2424,7 +2424,7 @@ static inline void ntfs_unmap_and_discard(struct ntfs_sb_info *sbi, CLST lcn,
void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim) void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
{ {
CLST end, i; CLST end, i, zone_len, zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap; struct wnd_bitmap *wnd = &sbi->used.bitmap;
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS); down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_CLUSTERS);
...@@ -2459,6 +2459,28 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim) ...@@ -2459,6 +2459,28 @@ void mark_as_free_ex(struct ntfs_sb_info *sbi, CLST lcn, CLST len, bool trim)
ntfs_unmap_and_discard(sbi, lcn, len); ntfs_unmap_and_discard(sbi, lcn, len);
wnd_set_free(wnd, lcn, len); wnd_set_free(wnd, lcn, len);
/* append to MFT zone, if possible. */
zone_len = wnd_zone_len(wnd);
zlen = min(zone_len + len, sbi->zone_max);
if (zlen == zone_len) {
/* MFT zone already has maximum size. */
} else if (!zone_len) {
/* Create MFT zone only if 'zlen' is large enough. */
if (zlen == sbi->zone_max)
wnd_zone_set(wnd, lcn, zlen);
} else {
CLST zone_lcn = wnd_zone_bit(wnd);
if (lcn + len == zone_lcn) {
/* Append into head MFT zone. */
wnd_zone_set(wnd, lcn, zlen);
} else if (zone_lcn + zone_len == lcn) {
/* Append into tail MFT zone. */
wnd_zone_set(wnd, zone_lcn, zlen);
}
}
out: out:
up_write(&wnd->rw_lock); up_write(&wnd->rw_lock);
} }
......
...@@ -1042,19 +1042,16 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1042,19 +1042,16 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
{ {
int err; int err;
struct NTFS_DE *e; struct NTFS_DE *e;
const struct INDEX_HDR *hdr;
struct indx_node *node; struct indx_node *node;
if (!root) if (!root)
root = indx_get_root(&ni->dir, ni, NULL, NULL); root = indx_get_root(&ni->dir, ni, NULL, NULL);
if (!root) { if (!root) {
err = -EINVAL; /* Should not happen. */
goto out; return -EINVAL;
} }
hdr = &root->ihdr;
/* Check cache. */ /* Check cache. */
e = fnd->level ? fnd->de[fnd->level - 1] : fnd->root_de; e = fnd->level ? fnd->de[fnd->level - 1] : fnd->root_de;
if (e && !de_is_last(e) && if (e && !de_is_last(e) &&
...@@ -1068,39 +1065,35 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1068,39 +1065,35 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
fnd_clear(fnd); fnd_clear(fnd);
/* Lookup entry that is <= to the search value. */ /* Lookup entry that is <= to the search value. */
e = hdr_find_e(indx, hdr, key, key_len, ctx, diff); e = hdr_find_e(indx, &root->ihdr, key, key_len, ctx, diff);
if (!e) if (!e)
return -EINVAL; return -EINVAL;
fnd->root_de = e; fnd->root_de = e;
err = 0;
for (;;) { for (;;) {
node = NULL; node = NULL;
if (*diff >= 0 || !de_has_vcn_ex(e)) { if (*diff >= 0 || !de_has_vcn_ex(e))
*entry = e; break;
goto out;
}
/* Read next level. */ /* Read next level. */
err = indx_read(indx, ni, de_get_vbn(e), &node); err = indx_read(indx, ni, de_get_vbn(e), &node);
if (err) if (err)
goto out; return err;
/* Lookup entry that is <= to the search value. */ /* Lookup entry that is <= to the search value. */
e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx, e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx,
diff); diff);
if (!e) { if (!e) {
err = -EINVAL;
put_indx_node(node); put_indx_node(node);
goto out; return -EINVAL;
} }
fnd_push(fnd, node, e); fnd_push(fnd, node, e);
} }
out: *entry = e;
return err; return 0;
} }
int indx_find_sort(struct ntfs_index *indx, struct ntfs_inode *ni, int indx_find_sort(struct ntfs_index *indx, struct ntfs_inode *ni,
...@@ -1354,7 +1347,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1354,7 +1347,7 @@ static int indx_create_allocate(struct ntfs_index *indx, struct ntfs_inode *ni,
goto out; goto out;
err = ni_insert_nonresident(ni, ATTR_ALLOC, in->name, in->name_len, err = ni_insert_nonresident(ni, ATTR_ALLOC, in->name, in->name_len,
&run, 0, len, 0, &alloc, NULL); &run, 0, len, 0, &alloc, NULL, NULL);
if (err) if (err)
goto out1; goto out1;
...@@ -1685,8 +1678,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1685,8 +1678,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
{ {
int err; int err;
const struct NTFS_DE *sp; const struct NTFS_DE *sp;
struct NTFS_DE *e, *de_t, *up_e = NULL; struct NTFS_DE *e, *de_t, *up_e;
struct indx_node *n2 = NULL; struct indx_node *n2;
struct indx_node *n1 = fnd->nodes[level]; struct indx_node *n1 = fnd->nodes[level];
struct INDEX_HDR *hdr1 = &n1->index->ihdr; struct INDEX_HDR *hdr1 = &n1->index->ihdr;
struct INDEX_HDR *hdr2; struct INDEX_HDR *hdr2;
...@@ -1994,7 +1987,7 @@ static int indx_free_children(struct ntfs_index *indx, struct ntfs_inode *ni, ...@@ -1994,7 +1987,7 @@ static int indx_free_children(struct ntfs_index *indx, struct ntfs_inode *ni,
const struct NTFS_DE *e, bool trim) const struct NTFS_DE *e, bool trim)
{ {
int err; int err;
struct indx_node *n; struct indx_node *n = NULL;
struct INDEX_HDR *hdr; struct INDEX_HDR *hdr;
CLST vbn = de_get_vbn(e); CLST vbn = de_get_vbn(e);
size_t i; size_t i;
......
...@@ -430,6 +430,7 @@ static struct inode *ntfs_read_mft(struct inode *inode, ...@@ -430,6 +430,7 @@ static struct inode *ntfs_read_mft(struct inode *inode,
} else if (fname && fname->home.low == cpu_to_le32(MFT_REC_EXTEND) && } else if (fname && fname->home.low == cpu_to_le32(MFT_REC_EXTEND) &&
fname->home.seq == cpu_to_le16(MFT_REC_EXTEND)) { fname->home.seq == cpu_to_le16(MFT_REC_EXTEND)) {
/* Records in $Extend are not a files or general directories. */ /* Records in $Extend are not a files or general directories. */
inode->i_op = &ntfs_file_inode_operations;
} else { } else {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
...@@ -500,7 +501,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref, ...@@ -500,7 +501,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
inode = ntfs_read_mft(inode, name, ref); inode = ntfs_read_mft(inode, name, ref);
else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) { else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
/* Inode overlaps? */ /* Inode overlaps? */
make_bad_inode(inode); _ntfs_bad_inode(inode);
} }
return inode; return inode;
...@@ -1632,7 +1633,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns, ...@@ -1632,7 +1633,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
ni->mi.dirty = false; ni->mi.dirty = false;
discard_new_inode(inode); discard_new_inode(inode);
out3: out3:
ntfs_mark_rec_free(sbi, ino); ntfs_mark_rec_free(sbi, ino, false);
out2: out2:
__putname(new_de); __putname(new_de);
...@@ -1655,7 +1656,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) ...@@ -1655,7 +1656,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
struct ntfs_inode *ni = ntfs_i(inode); struct ntfs_inode *ni = ntfs_i(inode);
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info; struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
struct NTFS_DE *de; struct NTFS_DE *de;
struct ATTR_FILE_NAME *de_name;
/* Allocate PATH_MAX bytes. */ /* Allocate PATH_MAX bytes. */
de = __getname(); de = __getname();
...@@ -1670,15 +1670,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry) ...@@ -1670,15 +1670,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
if (err) if (err)
goto out; goto out;
de_name = (struct ATTR_FILE_NAME *)(de + 1);
/* Fill duplicate info. */
de_name->dup.cr_time = de_name->dup.m_time = de_name->dup.c_time =
de_name->dup.a_time = kernel2nt(&inode->i_ctime);
de_name->dup.alloc_size = de_name->dup.data_size =
cpu_to_le64(inode->i_size);
de_name->dup.fa = ni->std_fa;
de_name->dup.ea_size = de_name->dup.reparse = 0;
err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de); err = ni_add_name(ntfs_i(d_inode(dentry->d_parent)), ni, de);
out: out:
__putname(de); __putname(de);
...@@ -1731,9 +1722,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry) ...@@ -1731,9 +1722,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
if (inode->i_nlink) if (inode->i_nlink)
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) { } else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) {
make_bad_inode(inode); _ntfs_bad_inode(inode);
ntfs_inode_err(inode, "failed to undo unlink");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
} else { } else {
if (ni_is_dirty(dir)) if (ni_is_dirty(dir))
mark_inode_dirty(dir); mark_inode_dirty(dir);
......
...@@ -208,7 +208,7 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -208,7 +208,7 @@ static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
} }
/* /*
* ntfs_rmdir - inode_operations::rm_dir * ntfs_rmdir - inode_operations::rmdir
*/ */
static int ntfs_rmdir(struct inode *dir, struct dentry *dentry) static int ntfs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
...@@ -308,9 +308,7 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -308,9 +308,7 @@ static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir,
err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad); err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad);
if (is_bad) { if (is_bad) {
/* Restore after failed rename failed too. */ /* Restore after failed rename failed too. */
make_bad_inode(inode); _ntfs_bad_inode(inode);
ntfs_inode_err(inode, "failed to undo rename");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
} else if (!err) { } else if (!err) {
inode->i_ctime = dir->i_ctime = dir->i_mtime = inode->i_ctime = dir->i_ctime = dir->i_mtime =
current_time(dir); current_time(dir);
......
...@@ -220,6 +220,7 @@ struct ntfs_sb_info { ...@@ -220,6 +220,7 @@ struct ntfs_sb_info {
u32 flags; // See NTFS_FLAGS_XXX. u32 flags; // See NTFS_FLAGS_XXX.
CLST zone_max; // Maximum MFT zone length in clusters
CLST bad_clusters; // The count of marked bad clusters. CLST bad_clusters; // The count of marked bad clusters.
u16 max_bytes_per_attr; // Maximum attribute size in record. u16 max_bytes_per_attr; // Maximum attribute size in record.
...@@ -408,8 +409,6 @@ enum REPARSE_SIGN { ...@@ -408,8 +409,6 @@ enum REPARSE_SIGN {
}; };
/* Functions from attrib.c */ /* Functions from attrib.c */
int attr_load_runs(struct ATTRIB *attr, struct ntfs_inode *ni,
struct runs_tree *run, const CLST *vcn);
int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run, int attr_allocate_clusters(struct ntfs_sb_info *sbi, struct runs_tree *run,
CLST vcn, CLST lcn, CLST len, CLST *pre_alloc, CLST vcn, CLST lcn, CLST len, CLST *pre_alloc,
enum ALLOCATE_OPT opt, CLST *alen, const size_t fr, enum ALLOCATE_OPT opt, CLST *alen, const size_t fr,
...@@ -440,6 +439,7 @@ int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr, ...@@ -440,6 +439,7 @@ int attr_is_frame_compressed(struct ntfs_inode *ni, struct ATTRIB *attr,
int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size, int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
u64 new_valid); u64 new_valid);
int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes); int attr_collapse_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
int attr_insert_range(struct ntfs_inode *ni, u64 vbo, u64 bytes);
int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size); int attr_punch_hole(struct ntfs_inode *ni, u64 vbo, u64 bytes, u32 *frame_size);
/* Functions from attrlist.c */ /* Functions from attrlist.c */
...@@ -528,7 +528,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type, ...@@ -528,7 +528,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, const __le16 *name, u8 name_len,
const struct runs_tree *run, CLST svcn, CLST len, const struct runs_tree *run, CLST svcn, CLST len,
__le16 flags, struct ATTRIB **new_attr, __le16 flags, struct ATTRIB **new_attr,
struct mft_inode **mi); struct mft_inode **mi, struct ATTR_LIST_ENTRY **le);
int ni_insert_resident(struct ntfs_inode *ni, u32 data_size, int ni_insert_resident(struct ntfs_inode *ni, u32 data_size,
enum ATTR_TYPE type, const __le16 *name, u8 name_len, enum ATTR_TYPE type, const __le16 *name, u8 name_len,
struct ATTRIB **new_attr, struct mft_inode **mi, struct ATTRIB **new_attr, struct mft_inode **mi,
...@@ -589,10 +589,12 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len, ...@@ -589,10 +589,12 @@ int ntfs_look_for_free_space(struct ntfs_sb_info *sbi, CLST lcn, CLST len,
enum ALLOCATE_OPT opt); enum ALLOCATE_OPT opt);
int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft, int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
struct ntfs_inode *ni, struct mft_inode **mi); struct ntfs_inode *ni, struct mft_inode **mi);
void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno); void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno, bool is_mft);
int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to); int ntfs_clear_mft_tail(struct ntfs_sb_info *sbi, size_t from, size_t to);
int ntfs_refresh_zone(struct ntfs_sb_info *sbi); int ntfs_refresh_zone(struct ntfs_sb_info *sbi);
int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait); void ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait);
void ntfs_bad_inode(struct inode *inode, const char *hint);
#define _ntfs_bad_inode(i) ntfs_bad_inode(i, __func__)
enum NTFS_DIRTY_FLAGS { enum NTFS_DIRTY_FLAGS {
NTFS_DIRTY_CLEAR = 0, NTFS_DIRTY_CLEAR = 0,
NTFS_DIRTY_DIRTY = 1, NTFS_DIRTY_DIRTY = 1,
...@@ -738,7 +740,6 @@ static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec, ...@@ -738,7 +740,6 @@ static inline struct ATTRIB *rec_find_attr_le(struct mft_inode *rec,
int mi_write(struct mft_inode *mi, int wait); int mi_write(struct mft_inode *mi, int wait);
int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
__le16 flags, bool is_mft); __le16 flags, bool is_mft);
void mi_mark_free(struct mft_inode *mi);
struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
const __le16 *name, u8 name_len, u32 asize, const __le16 *name, u8 name_len, u32 asize,
u16 name_off); u16 name_off);
...@@ -780,10 +781,10 @@ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn, ...@@ -780,10 +781,10 @@ bool run_lookup_entry(const struct runs_tree *run, CLST vcn, CLST *lcn,
void run_truncate(struct runs_tree *run, CLST vcn); void run_truncate(struct runs_tree *run, CLST vcn);
void run_truncate_head(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); void run_truncate_around(struct runs_tree *run, CLST vcn);
bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *Index);
bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len, bool run_add_entry(struct runs_tree *run, CLST vcn, CLST lcn, CLST len,
bool is_mft); bool is_mft);
bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len); bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len);
bool run_insert_range(struct runs_tree *run, CLST vcn, CLST len);
bool run_get_entry(const struct runs_tree *run, size_t index, CLST *vcn, bool run_get_entry(const struct runs_tree *run, size_t index, CLST *vcn,
CLST *lcn, CLST *len); CLST *lcn, CLST *len);
bool run_is_mapped_full(const struct runs_tree *run, CLST svcn, CLST evcn); bool run_is_mapped_full(const struct runs_tree *run, CLST svcn, CLST evcn);
...@@ -802,6 +803,7 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino, ...@@ -802,6 +803,7 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,
#define run_unpack_ex run_unpack #define run_unpack_ex run_unpack
#endif #endif
int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn); int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn);
int run_clone(const struct runs_tree *run, struct runs_tree *new_run);
/* Globals from super.c */ /* Globals from super.c */
void *ntfs_set_shared(void *ptr, u32 bytes); void *ntfs_set_shared(void *ptr, u32 bytes);
......
...@@ -394,28 +394,6 @@ int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno, ...@@ -394,28 +394,6 @@ int mi_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
return err; return err;
} }
/*
* mi_mark_free - Mark record as unused and marks it as free in bitmap.
*/
void mi_mark_free(struct mft_inode *mi)
{
CLST rno = mi->rno;
struct ntfs_sb_info *sbi = mi->sbi;
if (rno >= MFT_REC_RESERVED && rno < MFT_REC_FREE) {
ntfs_clear_mft_tail(sbi, rno, rno + 1);
mi->dirty = false;
return;
}
if (mi->mrec) {
clear_rec_inuse(mi->mrec);
mi->dirty = true;
mi_write(mi, 0);
}
ntfs_mark_rec_free(sbi, rno);
}
/* /*
* mi_insert_attr - Reserve space for new attribute. * mi_insert_attr - Reserve space for new attribute.
* *
...@@ -445,12 +423,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type, ...@@ -445,12 +423,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
attr = NULL; attr = NULL;
while ((attr = mi_enum_attr(mi, attr))) { while ((attr = mi_enum_attr(mi, attr))) {
diff = compare_attr(attr, type, name, name_len, upcase); diff = compare_attr(attr, type, name, name_len, upcase);
if (diff > 0)
break;
if (diff < 0) if (diff < 0)
continue; continue;
if (!is_attr_indexed(attr)) if (!diff && !is_attr_indexed(attr))
return NULL; return NULL;
break; break;
} }
......
...@@ -31,7 +31,7 @@ struct ntfs_run { ...@@ -31,7 +31,7 @@ struct ntfs_run {
* Case of entry missing from list 'index' will be set to * Case of entry missing from list 'index' will be set to
* point to insertion position for the entry question. * point to insertion position for the entry question.
*/ */
bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *index) static bool run_lookup(const struct runs_tree *run, CLST vcn, size_t *index)
{ {
size_t min_idx, max_idx, mid_idx; size_t min_idx, max_idx, mid_idx;
struct ntfs_run *r; struct ntfs_run *r;
...@@ -547,6 +547,48 @@ bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len) ...@@ -547,6 +547,48 @@ bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len)
return true; return true;
} }
/* run_insert_range
*
* Helper for attr_insert_range(),
* which is helper for fallocate(insert_range).
*/
bool run_insert_range(struct runs_tree *run, CLST vcn, CLST len)
{
size_t index;
struct ntfs_run *r, *e;
if (WARN_ON(!run_lookup(run, vcn, &index)))
return false; /* Should never be here. */
e = run->runs + run->count;
r = run->runs + index;
if (vcn > r->vcn)
r += 1;
for (; r < e; r++)
r->vcn += len;
r = run->runs + index;
if (vcn > r->vcn) {
/* split fragment. */
CLST len1 = vcn - r->vcn;
CLST len2 = r->len - len1;
CLST lcn2 = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len1);
r->len = len1;
if (!run_add_entry(run, vcn + len, lcn2, len2, false))
return false;
}
if (!run_add_entry(run, vcn, SPARSE_LCN, len, false))
return false;
return true;
}
/* /*
* run_get_entry - Return index-th mapped region. * run_get_entry - Return index-th mapped region.
*/ */
...@@ -778,26 +820,36 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf, ...@@ -778,26 +820,36 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
CLST next_vcn, vcn, lcn; CLST next_vcn, vcn, lcn;
CLST prev_lcn = 0; CLST prev_lcn = 0;
CLST evcn1 = svcn + len; CLST evcn1 = svcn + len;
const struct ntfs_run *r, *r_end;
int packed_size = 0; int packed_size = 0;
size_t i; size_t i;
bool ok;
s64 dlcn; s64 dlcn;
int offset_size, size_size, tmp; int offset_size, size_size, tmp;
next_vcn = vcn = svcn;
*packed_vcns = 0; *packed_vcns = 0;
if (!len) if (!len)
goto out; goto out;
ok = run_lookup_entry(run, vcn, &lcn, &len, &i); /* Check all required entries [svcn, encv1) available. */
if (!run_lookup(run, svcn, &i))
return -ENOENT;
if (!ok) r_end = run->runs + run->count;
goto error; r = run->runs + i;
if (next_vcn != vcn) for (next_vcn = r->vcn + r->len; next_vcn < evcn1;
goto error; next_vcn = r->vcn + r->len) {
if (++r >= r_end || r->vcn != next_vcn)
return -ENOENT;
}
/* Repeat cycle above and pack runs. Assume no errors. */
r = run->runs + i;
len = svcn - r->vcn;
vcn = svcn;
lcn = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len);
len = r->len - len;
for (;;) { for (;;) {
next_vcn = vcn + len; next_vcn = vcn + len;
...@@ -846,12 +898,10 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf, ...@@ -846,12 +898,10 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
if (packed_size + 1 >= run_buf_size || next_vcn >= evcn1) if (packed_size + 1 >= run_buf_size || next_vcn >= evcn1)
goto out; goto out;
ok = run_get_entry(run, ++i, &vcn, &lcn, &len); r += 1;
if (!ok) vcn = r->vcn;
goto error; lcn = r->lcn;
len = r->len;
if (next_vcn != vcn)
goto error;
} }
out: out:
...@@ -860,9 +910,6 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf, ...@@ -860,9 +910,6 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
run_buf[0] = 0; run_buf[0] = 0;
return packed_size + 1; return packed_size + 1;
error:
return -EOPNOTSUPP;
} }
/* /*
...@@ -1109,3 +1156,28 @@ int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn) ...@@ -1109,3 +1156,28 @@ int run_get_highest_vcn(CLST vcn, const u8 *run_buf, u64 *highest_vcn)
*highest_vcn = vcn64 - 1; *highest_vcn = vcn64 - 1;
return 0; return 0;
} }
/*
* run_clone
*
* Make a copy of run
*/
int run_clone(const struct runs_tree *run, struct runs_tree *new_run)
{
size_t bytes = run->count * sizeof(struct ntfs_run);
if (bytes > new_run->allocated) {
struct ntfs_run *new_ptr = kvmalloc(bytes, GFP_KERNEL);
if (!new_ptr)
return -ENOMEM;
kvfree(new_run->runs);
new_run->runs = new_ptr;
new_run->allocated = bytes;
}
memcpy(new_run->runs, run->runs, bytes);
new_run->count = run->count;
return 0;
}
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/fs_context.h> #include <linux/fs_context.h>
#include <linux/fs_parser.h> #include <linux/fs_parser.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/minmax.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -390,7 +391,7 @@ static int ntfs_fs_reconfigure(struct fs_context *fc) ...@@ -390,7 +391,7 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
return -EINVAL; return -EINVAL;
} }
memcpy(sbi->options, new_opts, sizeof(*new_opts)); swap(sbi->options, fc->fs_private);
return 0; return 0;
} }
...@@ -870,6 +871,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size, ...@@ -870,6 +871,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits; sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits;
#endif #endif
/*
* Compute the MFT zone at two steps.
* It would be nice if we are able to allocate 1/8 of
* total clusters for MFT but not more then 512 MB.
*/
sbi->zone_max = min_t(CLST, 0x20000000 >> sbi->cluster_bits, clusters >> 3);
err = 0; err = 0;
out: out:
...@@ -900,6 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -900,6 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
ref.high = 0; ref.high = 0;
sbi->sb = sb; sbi->sb = sb;
sbi->options = fc->fs_private;
fc->fs_private = NULL;
sb->s_flags |= SB_NODIRATIME; sb->s_flags |= SB_NODIRATIME;
sb->s_magic = 0x7366746e; // "ntfs" sb->s_magic = 0x7366746e; // "ntfs"
sb->s_op = &ntfs_sops; sb->s_op = &ntfs_sops;
...@@ -1262,8 +1272,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) ...@@ -1262,8 +1272,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
goto put_inode_out; goto put_inode_out;
} }
fc->fs_private = NULL;
return 0; return 0;
put_inode_out: put_inode_out:
...@@ -1378,7 +1386,7 @@ static const struct fs_context_operations ntfs_context_ops = { ...@@ -1378,7 +1386,7 @@ static const struct fs_context_operations ntfs_context_ops = {
/* /*
* ntfs_init_fs_context - Initialize spi and opts * ntfs_init_fs_context - Initialize spi and opts
* *
* This will called when mount/remount. We will first initiliaze * This will called when mount/remount. We will first initialize
* options so that if remount we can use just that. * options so that if remount we can use just that.
*/ */
static int ntfs_init_fs_context(struct fs_context *fc) static int ntfs_init_fs_context(struct fs_context *fc)
...@@ -1416,7 +1424,6 @@ static int ntfs_init_fs_context(struct fs_context *fc) ...@@ -1416,7 +1424,6 @@ static int ntfs_init_fs_context(struct fs_context *fc)
mutex_init(&sbi->compress.mtx_lzx); mutex_init(&sbi->compress.mtx_lzx);
#endif #endif
sbi->options = opts;
fc->s_fs_info = sbi; fc->s_fs_info = sbi;
ok: ok:
fc->fs_private = opts; fc->fs_private = opts;
......
...@@ -118,7 +118,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea, ...@@ -118,7 +118,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
run_init(&run); run_init(&run);
err = attr_load_runs(attr_ea, ni, &run, NULL); err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &run, 0, size);
if (!err) if (!err)
err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL); err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
run_close(&run); run_close(&run);
...@@ -444,6 +444,11 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name, ...@@ -444,6 +444,11 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
/* Delete xattr, ATTR_EA */ /* Delete xattr, ATTR_EA */
ni_remove_attr_le(ni, attr, mi, le); ni_remove_attr_le(ni, attr, mi, le);
} else if (attr->non_res) { } else if (attr->non_res) {
err = attr_load_runs_range(ni, ATTR_EA, NULL, 0, &ea_run, 0,
size);
if (err)
goto out;
err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0); err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0);
if (err) if (err)
goto out; goto out;
...@@ -547,28 +552,23 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, ...@@ -547,28 +552,23 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
{ {
const char *name; const char *name;
size_t size, name_len; size_t size, name_len;
void *value = NULL; void *value;
int err = 0; int err;
int flags; int flags;
umode_t mode;
if (S_ISLNK(inode->i_mode)) if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
mode = inode->i_mode;
switch (type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
/* Do not change i_mode if we are in init_acl */ /* Do not change i_mode if we are in init_acl */
if (acl && !init_acl) { if (acl && !init_acl) {
umode_t mode;
err = posix_acl_update_mode(mnt_userns, inode, &mode, err = posix_acl_update_mode(mnt_userns, inode, &mode,
&acl); &acl);
if (err) if (err)
goto out; return err;
if (inode->i_mode != mode) {
inode->i_mode = mode;
mark_inode_dirty(inode);
}
} }
name = XATTR_NAME_POSIX_ACL_ACCESS; name = XATTR_NAME_POSIX_ACL_ACCESS;
name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1; name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
...@@ -604,8 +604,13 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns, ...@@ -604,8 +604,13 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0); err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
if (err == -ENODATA && !size) if (err == -ENODATA && !size)
err = 0; /* Removing non existed xattr. */ err = 0; /* Removing non existed xattr. */
if (!err) if (!err) {
set_cached_acl(inode, type, acl); set_cached_acl(inode, type, acl);
if (inode->i_mode != mode) {
inode->i_mode = mode;
mark_inode_dirty(inode);
}
}
out: out:
kfree(value); kfree(value);
...@@ -706,13 +711,13 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode, ...@@ -706,13 +711,13 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
inode->i_default_acl = NULL; inode->i_default_acl = NULL;
} }
if (!acl) if (acl) {
inode->i_acl = NULL;
else {
if (!err) if (!err)
err = ntfs_set_acl_ex(mnt_userns, inode, acl, err = ntfs_set_acl_ex(mnt_userns, inode, acl,
ACL_TYPE_ACCESS, true); ACL_TYPE_ACCESS, true);
posix_acl_release(acl); posix_acl_release(acl);
} else {
inode->i_acl = NULL;
} }
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment