mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 02:36:21 +00:00
fs/ntfs3: Refactoring attr_punch_hole to restore after errors
Added comments to code Added new function run_clone to make a copy of run Added done and undo labels for restoring after errors Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
parent
0e5b044cbf
commit
20abc64f78
@ -140,7 +140,10 @@ failed:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lcn != SPARSE_LCN) {
|
if (lcn != SPARSE_LCN) {
|
||||||
mark_as_free_ex(sbi, lcn, clen, trim);
|
if (sbi) {
|
||||||
|
/* mark bitmap range [lcn + clen) as free and trim clusters. */
|
||||||
|
mark_as_free_ex(sbi, lcn, clen, trim);
|
||||||
|
}
|
||||||
dn += clen;
|
dn += clen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2002,10 +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, next_svcn;
|
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;
|
__le16 a_flags;
|
||||||
|
struct runs_tree run2;
|
||||||
|
|
||||||
if (!bytes)
|
if (!bytes)
|
||||||
return 0;
|
return 0;
|
||||||
@ -2057,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.
|
||||||
*/
|
*/
|
||||||
@ -2064,7 +2071,7 @@ 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;
|
||||||
@ -2076,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);
|
||||||
@ -2091,69 +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)) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
|
/* Make a clone of run to undo. */
|
||||||
if (err)
|
err = run_clone(run, &run2);
|
||||||
goto out;
|
if (err)
|
||||||
next_svcn = le64_to_cpu(attr->nres.evcn) + 1;
|
goto done;
|
||||||
if (next_svcn < evcn1) {
|
|
||||||
err = ni_insert_nonresident(ni, ATTR_DATA, NULL,
|
/* Make a hole range (sparse) [vcn1 + zero). */
|
||||||
0, run, next_svcn,
|
if (!run_add_entry(run, vcn1, SPARSE_LCN, zero, false)) {
|
||||||
evcn1 - next_svcn,
|
err = -ENOMEM;
|
||||||
a_flags, &attr, &mi,
|
goto done;
|
||||||
&le);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
/* Layout of records maybe changed. */
|
|
||||||
attr_b = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update run in attribute segment. */
|
||||||
|
err = mi_pack_runs(mi, attr, run, evcn1 - svcn);
|
||||||
|
if (err)
|
||||||
|
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) {
|
if (!attr_b) {
|
||||||
attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
|
attr_b = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
|
||||||
&mi_b);
|
&mi_b);
|
||||||
if (!attr_b) {
|
if (!attr_b) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
goto out;
|
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;
|
||||||
|
|
||||||
@ -2163,11 +2192,23 @@ 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);
|
||||||
if (err)
|
|
||||||
_ntfs_bad_inode(&ni->vfs_inode);
|
|
||||||
|
|
||||||
return err;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -798,6 +798,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);
|
||||||
|
@ -1156,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;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user