mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
fs/ntfs3: fold file size handling into ntfs_set_size()
Remove the separate ntfs_extend() and ntfs_truncate() helpers and route file size changes through ntfs_set_size(). This consolidates ntfs3 size updates in one place and lets the write, fallocate, and setattr paths share the same logic for updating i_size, valid data length, and preallocated extents. This patch fixes a few issues found during internal tests. Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
This commit is contained in:
parent
9245b4adb1
commit
ecbb433f9a
178
fs/ntfs3/file.c
178
fs/ntfs3/file.c
|
|
@ -450,93 +450,6 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int ntfs_extend(struct inode *inode, loff_t pos, size_t count,
|
||||
struct file *file)
|
||||
{
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
loff_t end = pos + count;
|
||||
bool extend_init = file && pos > ni->i_valid;
|
||||
int err;
|
||||
|
||||
if (end <= inode->i_size && !extend_init)
|
||||
return 0;
|
||||
|
||||
/* Mark rw ntfs as dirty. It will be cleared at umount. */
|
||||
ntfs_set_state(ni->mi.sbi, NTFS_DIRTY_DIRTY);
|
||||
|
||||
if (end > inode->i_size) {
|
||||
/*
|
||||
* Normal files: increase file size, allocate space.
|
||||
* Sparse/Compressed: increase file size. No space allocated.
|
||||
*/
|
||||
err = ntfs_set_size(inode, end);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (extend_init && !is_compressed(ni)) {
|
||||
err = ntfs_extend_initialized_size(file, ni, pos);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
if (IS_SYNC(inode)) {
|
||||
int err2;
|
||||
|
||||
err = filemap_fdatawrite_range(mapping, pos, end - 1);
|
||||
err2 = write_inode_now(inode, 1);
|
||||
if (!err)
|
||||
err = err2;
|
||||
if (!err)
|
||||
err = filemap_fdatawait_range(mapping, pos, end - 1);
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ntfs_truncate(struct inode *inode, loff_t new_size)
|
||||
{
|
||||
int err;
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
u64 new_valid = min_t(u64, ni->i_valid, new_size);
|
||||
|
||||
truncate_setsize(inode, new_size);
|
||||
|
||||
ni_lock(ni);
|
||||
|
||||
down_write(&ni->file.run_lock);
|
||||
err = attr_set_size_ex(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size,
|
||||
&new_valid, ni->mi.sbi->options->prealloc, NULL,
|
||||
false);
|
||||
up_write(&ni->file.run_lock);
|
||||
|
||||
ni->i_valid = new_valid;
|
||||
|
||||
ni_unlock(ni);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ni->std_fa |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||
if (!IS_DIRSYNC(inode)) {
|
||||
mark_inode_dirty(inode);
|
||||
} else {
|
||||
err = ntfs_sync_inode(inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_fallocate - file_operations::ntfs_fallocate
|
||||
*
|
||||
|
|
@ -743,57 +656,25 @@ static long ntfs_fallocate(struct file *file, int mode, loff_t vbo, loff_t len)
|
|||
if (is_supported_holes) {
|
||||
CLST vcn = vbo >> cluster_bits;
|
||||
CLST cend = bytes_to_cluster(sbi, end);
|
||||
CLST cend_v = bytes_to_cluster(sbi, ni->i_valid);
|
||||
CLST lcn, clen;
|
||||
bool new;
|
||||
|
||||
if (cend_v > cend)
|
||||
cend_v = cend;
|
||||
|
||||
/*
|
||||
* Allocate and zero new clusters.
|
||||
* Zeroing these clusters may be too long.
|
||||
*/
|
||||
for (; vcn < cend_v; vcn += clen) {
|
||||
err = attr_data_get_block(ni, vcn, cend_v - vcn,
|
||||
&lcn, &clen, &new,
|
||||
true, NULL, false);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Moving up 'valid size'.
|
||||
*/
|
||||
err = ntfs_extend_initialized_size(
|
||||
file, ni, (u64)cend_v << cluster_bits);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Allocate but not zero new clusters.
|
||||
*/
|
||||
for (; vcn < cend; vcn += clen) {
|
||||
err = attr_data_get_block(ni, vcn, cend - vcn,
|
||||
&lcn, &clen, &new,
|
||||
false, NULL, false);
|
||||
true, NULL, false);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & FALLOC_FL_KEEP_SIZE) {
|
||||
ni_lock(ni);
|
||||
/* True - Keep preallocated. */
|
||||
err = attr_set_size(ni, ATTR_DATA, NULL, 0,
|
||||
&ni->file.run, i_size, &ni->i_valid,
|
||||
true);
|
||||
ni_unlock(ni);
|
||||
err = ntfs_set_size(inode, i_size);
|
||||
if (err)
|
||||
goto out;
|
||||
i_size_write(inode, i_size);
|
||||
} else if (new_size > i_size) {
|
||||
i_size_write(inode, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -850,16 +731,20 @@ int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
oldsize = i_size_read(inode);
|
||||
newsize = attr->ia_size;
|
||||
|
||||
if (newsize <= oldsize)
|
||||
err = ntfs_truncate(inode, newsize);
|
||||
else
|
||||
err = ntfs_extend(inode, newsize, 0, NULL);
|
||||
if (newsize != oldsize) {
|
||||
truncate_setsize(inode, newsize);
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
err = ntfs_set_size(inode, newsize);
|
||||
if (err) {
|
||||
i_size_write(inode, oldsize);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
i_size_write(inode, newsize);
|
||||
ni->std_fa |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
ni->ni_flags |= NI_FLAG_UPDATE_PARENT;
|
||||
inode_set_mtime_to_ts(inode,
|
||||
inode_set_ctime_current(inode));
|
||||
}
|
||||
}
|
||||
|
||||
setattr_copy(idmap, inode, attr);
|
||||
|
|
@ -1333,6 +1218,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct ntfs_inode *ni = ntfs_i(inode);
|
||||
loff_t vbo, endbyte;
|
||||
ssize_t ret, err;
|
||||
|
||||
if (!inode_trylock(inode)) {
|
||||
|
|
@ -1367,15 +1253,30 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = ntfs_extend(inode, iocb->ki_pos, ret, file);
|
||||
if (ret)
|
||||
goto out;
|
||||
vbo = iocb->ki_pos;
|
||||
endbyte = vbo + ret;
|
||||
|
||||
if (endbyte > inode->i_size) {
|
||||
/*
|
||||
* Normal files: increase file size, allocate space.
|
||||
* Sparse/Compressed: increase file size. No space allocated.
|
||||
*/
|
||||
ret = ntfs_set_size(inode, endbyte);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_compressed(ni)) {
|
||||
ret = ntfs_compress_write(iocb, from);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vbo > ni->i_valid) {
|
||||
ret = ntfs_extend_initialized_size(file, ni, vbo);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Fallback to buffered I/O if the inode does not support direct I/O. */
|
||||
if (!(iocb->ki_flags & IOCB_DIRECT) ||
|
||||
!ntfs_should_use_dio(iocb, from)) {
|
||||
|
|
@ -1408,7 +1309,7 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
}
|
||||
|
||||
if (ret >= 0 && iov_iter_count(from)) {
|
||||
loff_t offset = iocb->ki_pos, endbyte;
|
||||
vbo = iocb->ki_pos;
|
||||
|
||||
iocb->ki_flags &= ~IOCB_DIRECT;
|
||||
err = iomap_file_buffered_write(iocb, from, &ntfs_iomap_ops,
|
||||
|
|
@ -1426,15 +1327,15 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
* to complete off the I/O request.
|
||||
*/
|
||||
ret += err;
|
||||
endbyte = offset + err - 1;
|
||||
err = filemap_write_and_wait_range(inode->i_mapping, offset,
|
||||
endbyte = vbo + err - 1;
|
||||
err = filemap_write_and_wait_range(inode->i_mapping, vbo,
|
||||
endbyte);
|
||||
if (err) {
|
||||
ret = err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
invalidate_mapping_pages(inode->i_mapping, offset >> PAGE_SHIFT,
|
||||
invalidate_mapping_pages(inode->i_mapping, vbo >> PAGE_SHIFT,
|
||||
endbyte >> PAGE_SHIFT);
|
||||
}
|
||||
|
||||
|
|
@ -1515,8 +1416,9 @@ static int ntfs_file_release(struct inode *inode, struct file *file)
|
|||
down_write(&ni->file.run_lock);
|
||||
|
||||
/* Deallocate preallocated. */
|
||||
err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run,
|
||||
inode->i_size, &ni->i_valid, false);
|
||||
err = attr_set_size_ex(ni, ATTR_DATA, NULL, 0, &ni->file.run,
|
||||
inode->i_size, &ni->i_valid, false, NULL,
|
||||
true);
|
||||
|
||||
up_write(&ni->file.run_lock);
|
||||
ni_unlock(ni);
|
||||
|
|
|
|||
|
|
@ -693,17 +693,18 @@ int ntfs_set_size(struct inode *inode, u64 new_size)
|
|||
return -EFBIG;
|
||||
}
|
||||
|
||||
/* Mark rw ntfs as dirty. It will be cleared at umount. */
|
||||
ntfs_set_state(sbi, NTFS_DIRTY_DIRTY);
|
||||
|
||||
ni_lock(ni);
|
||||
down_write(&ni->file.run_lock);
|
||||
if (new_size < ni->i_valid)
|
||||
ni->i_valid = new_size;
|
||||
|
||||
/* last 'true' means keep preallocated. */
|
||||
err = attr_set_size(ni, ATTR_DATA, NULL, 0, &ni->file.run, new_size,
|
||||
&ni->i_valid, true);
|
||||
|
||||
if (!err) {
|
||||
i_size_write(inode, new_size);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
|
||||
up_write(&ni->file.run_lock);
|
||||
ni_unlock(ni);
|
||||
|
||||
|
|
@ -778,11 +779,6 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!clen) {
|
||||
/* broken file? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (lcn == EOF_LCN) {
|
||||
/* request out of file. */
|
||||
if (flags & IOMAP_REPORT) {
|
||||
|
|
@ -816,6 +812,11 @@ static int ntfs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!clen) {
|
||||
/* broken file? */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iomap->bdev = inode->i_sb->s_bdev;
|
||||
iomap->offset = offset;
|
||||
iomap->length = ((loff_t)clen << cluster_bits) - off;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user