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
This diff is collapsed.
......@@ -51,11 +51,6 @@ void ntfs3_exit_bitmap(void)
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
*
......@@ -1333,9 +1328,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
if (!new_free)
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,
(new_wnd - wnd->nwnd) * sizeof(short));
kfree(wnd->free_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)
{
size_t zlen;
size_t zlen = wnd->zone_end - wnd->zone_bit;
zlen = wnd->zone_end - wnd->zone_bit;
if (zlen)
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)
static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
{
struct inode *inode = file->f_mapping->host;
struct address_space *mapping = inode->i_mapping;
struct super_block *sb = inode->i_sb;
struct ntfs_sb_info *sbi = sb->s_fs_info;
struct ntfs_inode *ni = ntfs_i(inode);
loff_t end = vbo + len;
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;
/* No support for dir. */
if (!S_ISREG(inode->i_mode))
return -EOPNOTSUPP;
/* Return error if mode is not supported. */
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
FALLOC_FL_COLLAPSE_RANGE)) {
/*
* vfs_fallocate checks all possible combinations of mode.
* 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",
mode);
return -EOPNOTSUPP;
......@@ -554,6 +568,8 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
inode_lock(inode);
i_size = inode->i_size;
new_size = max(end, i_size);
map_locked = false;
if (WARN_ON(ni->ni_flags & NI_FLAG_COMPRESSED_MASK)) {
/* 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)
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) {
u32 frame_size;
loff_t mask, vbo_a, end_a, tmp;
if (!(mode & FALLOC_FL_KEEP_SIZE)) {
err = -EINVAL;
goto out;
}
err = filemap_write_and_wait_range(inode->i_mapping, vbo,
end - 1);
err = filemap_write_and_wait_range(mapping, vbo, end - 1);
if (err)
goto out;
err = filemap_write_and_wait_range(inode->i_mapping, end,
LLONG_MAX);
err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
if (err)
goto out;
inode_dio_wait(inode);
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);
err = attr_punch_hole(ni, vbo, len, &frame_size);
ni_unlock(ni);
......@@ -624,17 +629,11 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
ni_unlock(ni);
}
} 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
* it will get removed from the page cache below.
*/
err = filemap_write_and_wait_range(inode->i_mapping, vbo_down,
vbo);
err = filemap_write_and_wait_range(mapping, vbo_down, vbo);
if (err)
goto out;
......@@ -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
* when discarding page cache below.
*/
err = filemap_write_and_wait_range(inode->i_mapping, end,
LLONG_MAX);
err = filemap_write_and_wait_range(mapping, end, LLONG_MAX);
if (err)
goto out;
/* Wait for existing dio to complete. */
inode_dio_wait(inode);
truncate_pagecache(inode, vbo_down);
ni_lock(ni);
err = attr_collapse_range(ni, vbo, len);
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 {
/*
* Normal file: Allocate clusters, do not change 'valid' size.
*/
loff_t new_size = max(end, i_size);
/* Check new size. */
/* generic/213: expected -ENOSPC instead of -EFBIG. */
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);
if (err)
goto out;
/*
* Allocate clusters, do not change 'valid' size.
*/
err = ntfs_set_size(inode, new_size);
if (err)
goto out;
if (is_sparsed(ni) || is_compressed(ni)) {
if (is_supported_holes) {
CLST vcn_v = ni->i_valid >> sbi->cluster_bits;
CLST vcn = vbo >> sbi->cluster_bits;
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)
}
out:
if (err == -EFBIG)
err = -ENOSPC;
if (map_locked)
filemap_invalidate_unlock(mapping);
if (!err) {
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)
if (bytes > count)
bytes = count;
frame = pos >> frame_bits;
frame_vbo = pos & ~(frame_size - 1);
index = frame_vbo >> PAGE_SHIFT;
......
This diff is collapsed.
......@@ -3843,6 +3843,8 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)
memset(&rst_info2, 0, sizeof(struct restart_info));
err = log_read_rst(log, l_size, false, &rst_info2);
if (err)
goto out;
/* Determine which restart area to use. */
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)
goto add_allocated_vcns;
vcn = le64_to_cpu(lrh->target_vcn);
vcn &= ~(log->clst_per_page - 1);
vcn &= ~(u64)(log->clst_per_page - 1);
add_allocated_vcns:
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,
/*
* 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;
if (!is_mft)
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
if (rno >= wnd->nbits)
goto out;
......@@ -727,6 +729,7 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno)
sbi->mft.next_free = rno;
out:
if (!is_mft)
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)
*/
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;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
struct ntfs_inode *ni = sbi->mft.ni;
......@@ -789,16 +792,6 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
if (wnd_zone_len(wnd))
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,
(u64)sbi->mft.bitmap.nbits << sbi->record_bits);
......@@ -812,13 +805,7 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
lcn_s = lcn + 1;
/* Try to allocate clusters after last MFT run. */
zlen = wnd_find(wnd, zone_max, lcn_s, 0, &lcn_s);
if (!zlen) {
ntfs_notice(sbi->sb, "MftZone: unavailable");
return 0;
}
/* Truncate too large zone. */
zlen = wnd_find(wnd, sbi->zone_max, lcn_s, 0, &lcn_s);
wnd_zone_set(wnd, lcn_s, zlen);
return 0;
......@@ -827,16 +814,21 @@ int ntfs_refresh_zone(struct ntfs_sb_info *sbi)
/*
* 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;
struct super_block *sb = sbi->sb;
u32 blocksize = sb->s_blocksize;
u32 blocksize;
sector_t block1, block2;
u32 bytes;
if (!sb)
return;
blocksize = sb->s_blocksize;
if (!(sbi->flags & NTFS_FLAGS_MFTMIRR))
return 0;
return;
err = 0;
bytes = sbi->mft.recs_mirr << sbi->record_bits;
......@@ -847,16 +839,13 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
struct buffer_head *bh1, *bh2;
bh1 = sb_bread(sb, block1++);
if (!bh1) {
err = -EIO;
goto out;
}
if (!bh1)
return;
bh2 = sb_getblk(sb, block2++);
if (!bh2) {
put_bh(bh1);
err = -EIO;
goto out;
return;
}
if (buffer_locked(bh2))
......@@ -876,13 +865,24 @@ int ntfs_update_mftmirr(struct ntfs_sb_info *sbi, int wait)
put_bh(bh2);
if (err)
goto out;
return;
}
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,
if (buffer_locked(bh))
__wait_on_buffer(bh);
lock_buffer(nb->bh[idx]);
lock_buffer(bh);
bh_data = bh->b_data + off;
end_data = Add2Ptr(bh_data, op);
......@@ -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)
{
CLST end, i;
CLST end, i, zone_len, zlen;
struct wnd_bitmap *wnd = &sbi->used.bitmap;
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)
ntfs_unmap_and_discard(sbi, 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:
up_write(&wnd->rw_lock);
}
......
......@@ -1042,19 +1042,16 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
{
int err;
struct NTFS_DE *e;
const struct INDEX_HDR *hdr;
struct indx_node *node;
if (!root)
root = indx_get_root(&ni->dir, ni, NULL, NULL);
if (!root) {
err = -EINVAL;
goto out;
/* Should not happen. */
return -EINVAL;
}
hdr = &root->ihdr;
/* Check cache. */
e = fnd->level ? fnd->de[fnd->level - 1] : fnd->root_de;
if (e && !de_is_last(e) &&
......@@ -1068,39 +1065,35 @@ int indx_find(struct ntfs_index *indx, struct ntfs_inode *ni,
fnd_clear(fnd);
/* 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)
return -EINVAL;
fnd->root_de = e;
err = 0;
for (;;) {
node = NULL;
if (*diff >= 0 || !de_has_vcn_ex(e)) {
*entry = e;
goto out;
}
if (*diff >= 0 || !de_has_vcn_ex(e))
break;
/* Read next level. */
err = indx_read(indx, ni, de_get_vbn(e), &node);
if (err)
goto out;
return err;
/* Lookup entry that is <= to the search value. */
e = hdr_find_e(indx, &node->index->ihdr, key, key_len, ctx,
diff);
if (!e) {
err = -EINVAL;
put_indx_node(node);
goto out;
return -EINVAL;
}
fnd_push(fnd, node, e);
}
out:
return err;
*entry = e;
return 0;
}
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,
goto out;
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)
goto out1;
......@@ -1685,8 +1678,8 @@ indx_insert_into_buffer(struct ntfs_index *indx, struct ntfs_inode *ni,
{
int err;
const struct NTFS_DE *sp;
struct NTFS_DE *e, *de_t, *up_e = NULL;
struct indx_node *n2 = NULL;
struct NTFS_DE *e, *de_t, *up_e;
struct indx_node *n2;
struct indx_node *n1 = fnd->nodes[level];
struct INDEX_HDR *hdr1 = &n1->index->ihdr;
struct INDEX_HDR *hdr2;
......@@ -1994,7 +1987,7 @@ static int indx_free_children(struct ntfs_index *indx, struct ntfs_inode *ni,
const struct NTFS_DE *e, bool trim)
{
int err;
struct indx_node *n;
struct indx_node *n = NULL;
struct INDEX_HDR *hdr;
CLST vbn = de_get_vbn(e);
size_t i;
......
......@@ -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) &&
fname->home.seq == cpu_to_le16(MFT_REC_EXTEND)) {
/* Records in $Extend are not a files or general directories. */
inode->i_op = &ntfs_file_inode_operations;
} else {
err = -EINVAL;
goto out;
......@@ -500,7 +501,7 @@ struct inode *ntfs_iget5(struct super_block *sb, const struct MFT_REF *ref,
inode = ntfs_read_mft(inode, name, ref);
else if (ref->seq != ntfs_i(inode)->mi.mrec->seq) {
/* Inode overlaps? */
make_bad_inode(inode);
_ntfs_bad_inode(inode);
}
return inode;
......@@ -1632,7 +1633,7 @@ struct inode *ntfs_create_inode(struct user_namespace *mnt_userns,
ni->mi.dirty = false;
discard_new_inode(inode);
out3:
ntfs_mark_rec_free(sbi, ino);
ntfs_mark_rec_free(sbi, ino, false);
out2:
__putname(new_de);
......@@ -1655,7 +1656,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
struct ntfs_inode *ni = ntfs_i(inode);
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
struct NTFS_DE *de;
struct ATTR_FILE_NAME *de_name;
/* Allocate PATH_MAX bytes. */
de = __getname();
......@@ -1670,15 +1670,6 @@ int ntfs_link_inode(struct inode *inode, struct dentry *dentry)
if (err)
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);
out:
__putname(de);
......@@ -1731,9 +1722,7 @@ int ntfs_unlink_inode(struct inode *dir, const struct dentry *dentry)
if (inode->i_nlink)
mark_inode_dirty(inode);
} else if (!ni_remove_name_undo(dir_ni, ni, de, de2, undo_remove)) {
make_bad_inode(inode);
ntfs_inode_err(inode, "failed to undo unlink");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
_ntfs_bad_inode(inode);
} else {
if (ni_is_dirty(dir))
mark_inode_dirty(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)
{
......@@ -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);
if (is_bad) {
/* Restore after failed rename failed too. */
make_bad_inode(inode);
ntfs_inode_err(inode, "failed to undo rename");
ntfs_set_state(sbi, NTFS_DIRTY_ERROR);
_ntfs_bad_inode(inode);
} else if (!err) {
inode->i_ctime = dir->i_ctime = dir->i_mtime =
current_time(dir);
......
......@@ -220,6 +220,7 @@ struct ntfs_sb_info {
u32 flags; // See NTFS_FLAGS_XXX.
CLST zone_max; // Maximum MFT zone length in clusters
CLST bad_clusters; // The count of marked bad clusters.
u16 max_bytes_per_attr; // Maximum attribute size in record.
......@@ -408,8 +409,6 @@ enum REPARSE_SIGN {
};
/* 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,
CLST vcn, CLST lcn, CLST len, CLST *pre_alloc,
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,
int attr_allocate_frame(struct ntfs_inode *ni, CLST frame, size_t compr_size,
u64 new_valid);
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);
/* Functions from attrlist.c */
......@@ -528,7 +528,7 @@ int ni_insert_nonresident(struct ntfs_inode *ni, enum ATTR_TYPE type,
const __le16 *name, u8 name_len,
const struct runs_tree *run, CLST svcn, CLST len,
__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,
enum ATTR_TYPE type, const __le16 *name, u8 name_len,
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,
enum ALLOCATE_OPT opt);
int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft,
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_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 {
NTFS_DIRTY_CLEAR = 0,
NTFS_DIRTY_DIRTY = 1,
......@@ -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_format_new(struct mft_inode *mi, struct ntfs_sb_info *sbi, CLST rno,
__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,
const __le16 *name, u8 name_len, u32 asize,
u16 name_off);
......@@ -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_head(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 is_mft);
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,
CLST *lcn, CLST *len);
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,
#define run_unpack_ex run_unpack
#endif
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 */
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,
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.
*
......@@ -445,12 +423,11 @@ struct ATTRIB *mi_insert_attr(struct mft_inode *mi, enum ATTR_TYPE type,
attr = NULL;
while ((attr = mi_enum_attr(mi, attr))) {
diff = compare_attr(attr, type, name, name_len, upcase);
if (diff > 0)
break;
if (diff < 0)
continue;
if (!is_attr_indexed(attr))
if (!diff && !is_attr_indexed(attr))
return NULL;
break;
}
......
......@@ -31,7 +31,7 @@ struct ntfs_run {
* Case of entry missing from list 'index' will be set to
* 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;
struct ntfs_run *r;
......@@ -547,6 +547,48 @@ bool run_collapse_range(struct runs_tree *run, CLST vcn, CLST len)
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.
*/
......@@ -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 prev_lcn = 0;
CLST evcn1 = svcn + len;
const struct ntfs_run *r, *r_end;
int packed_size = 0;
size_t i;
bool ok;
s64 dlcn;
int offset_size, size_size, tmp;
next_vcn = vcn = svcn;
*packed_vcns = 0;
if (!len)
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)
goto error;
r_end = run->runs + run->count;
r = run->runs + i;
if (next_vcn != vcn)
goto error;
for (next_vcn = r->vcn + r->len; next_vcn < evcn1;
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 (;;) {
next_vcn = vcn + len;
......@@ -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)
goto out;
ok = run_get_entry(run, ++i, &vcn, &lcn, &len);
if (!ok)
goto error;
if (next_vcn != vcn)
goto error;
r += 1;
vcn = r->vcn;
lcn = r->lcn;
len = r->len;
}
out:
......@@ -860,9 +910,6 @@ int run_pack(const struct runs_tree *run, CLST svcn, CLST len, u8 *run_buf,
run_buf[0] = 0;
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)
*highest_vcn = vcn64 - 1;
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 @@
#include <linux/fs_context.h>
#include <linux/fs_parser.h>
#include <linux/log2.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/seq_file.h>
......@@ -390,7 +391,7 @@ static int ntfs_fs_reconfigure(struct fs_context *fc)
return -EINVAL;
}
memcpy(sbi->options, new_opts, sizeof(*new_opts));
swap(sbi->options, fc->fs_private);
return 0;
}
......@@ -870,6 +871,13 @@ static int ntfs_init_from_boot(struct super_block *sb, u32 sector_size,
sb->s_maxbytes = 0xFFFFFFFFull << sbi->cluster_bits;
#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;
out:
......@@ -900,6 +908,8 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
ref.high = 0;
sbi->sb = sb;
sbi->options = fc->fs_private;
fc->fs_private = NULL;
sb->s_flags |= SB_NODIRATIME;
sb->s_magic = 0x7366746e; // "ntfs"
sb->s_op = &ntfs_sops;
......@@ -1262,8 +1272,6 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
goto put_inode_out;
}
fc->fs_private = NULL;
return 0;
put_inode_out:
......@@ -1378,7 +1386,7 @@ static const struct fs_context_operations ntfs_context_ops = {
/*
* 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.
*/
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);
#endif
sbi->options = opts;
fc->s_fs_info = sbi;
ok:
fc->fs_private = opts;
......
......@@ -118,7 +118,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
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)
err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
run_close(&run);
......@@ -444,6 +444,11 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
/* Delete xattr, ATTR_EA */
ni_remove_attr_le(ni, attr, mi, le);
} 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);
if (err)
goto out;
......@@ -547,28 +552,23 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
{
const char *name;
size_t size, name_len;
void *value = NULL;
int err = 0;
void *value;
int err;
int flags;
umode_t mode;
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
mode = inode->i_mode;
switch (type) {
case ACL_TYPE_ACCESS:
/* Do not change i_mode if we are in init_acl */
if (acl && !init_acl) {
umode_t mode;
err = posix_acl_update_mode(mnt_userns, inode, &mode,
&acl);
if (err)
goto out;
if (inode->i_mode != mode) {
inode->i_mode = mode;
mark_inode_dirty(inode);
}
return err;
}
name = XATTR_NAME_POSIX_ACL_ACCESS;
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,
err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
if (err == -ENODATA && !size)
err = 0; /* Removing non existed xattr. */
if (!err)
if (!err) {
set_cached_acl(inode, type, acl);
if (inode->i_mode != mode) {
inode->i_mode = mode;
mark_inode_dirty(inode);
}
}
out:
kfree(value);
......@@ -706,13 +711,13 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
inode->i_default_acl = NULL;
}
if (!acl)
inode->i_acl = NULL;
else {
if (acl) {
if (!err)
err = ntfs_set_acl_ex(mnt_userns, inode, acl,
ACL_TYPE_ACCESS, true);
posix_acl_release(acl);
} else {
inode->i_acl = NULL;
}
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