fs/ntfs3: Enable FALLOC_FL_INSERT_RANGE
Changed logic in ntfs_fallocate - more clear checks in beginning
instead of the middle of function and added FALLOC_FL_INSERT_RANGE.
Fixes xfstest generic/064
Fixes: 4342306f0f
("fs/ntfs3: Add file operations and implementation")
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
parent
aa30eccb24
commit
e4d2f4fd53
@ -533,21 +533,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;
|
||||||
@ -557,6 +571,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. */
|
||||||
@ -564,38 +580,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);
|
||||||
@ -627,17 +632,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;
|
||||||
|
|
||||||
@ -645,34 +644,45 @@ 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 {
|
} else if (mode & FALLOC_FL_INSERT_RANGE) {
|
||||||
/*
|
/* Check new size. */
|
||||||
* Normal file: Allocate clusters, do not change 'valid' size.
|
|
||||||
*/
|
|
||||||
loff_t new_size = max(end, i_size);
|
|
||||||
|
|
||||||
err = inode_newsize_ok(inode, new_size);
|
err = inode_newsize_ok(inode, new_size);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
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 {
|
||||||
|
/* Check new size. */
|
||||||
|
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);
|
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);
|
||||||
@ -720,6 +730,9 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
if (map_locked)
|
||||||
|
filemap_invalidate_unlock(mapping);
|
||||||
|
|
||||||
if (err == -EFBIG)
|
if (err == -EFBIG)
|
||||||
err = -ENOSPC;
|
err = -ENOSPC;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user