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) ...@@ -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;
......
This diff is collapsed.
...@@ -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,12 +703,14 @@ int ntfs_look_free_mft(struct ntfs_sb_info *sbi, CLST *rno, bool mft, ...@@ -703,12 +703,14 @@ 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;
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT); if (!is_mft)
down_write_nested(&wnd->rw_lock, BITMAP_MUTEX_MFT);
if (rno >= wnd->nbits) if (rno >= wnd->nbits)
goto out; goto out;
...@@ -727,7 +729,8 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno) ...@@ -727,7 +729,8 @@ void ntfs_mark_rec_free(struct ntfs_sb_info *sbi, CLST rno)
sbi->mft.next_free = rno; sbi->mft.next_free = rno;
out: out:
up_write(&wnd->rw_lock); 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) ...@@ -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;
r_end = run->runs + run->count;
r = run->runs + i;
if (!ok) 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;
}
if (next_vcn != vcn) /* Repeat cycle above and pack runs. Assume no errors. */
goto error; 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