mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ntfs: do not turn an unmappable runlist fragment into delalloc on write
ntfs_write_simple_iomap_begin_non_resident() has the same unchecked
retry. LCN_RL_NOT_MAPPED passes its "lcn <= LCN_HOLE" test, so a
buffered write into a range whose extent record cannot be read is
merged into the runlist as LCN_DELALLOC over clusters that are already
allocated on disk, and write() succeeds. If the record stays
unreadable, writeback fails too and the data never reaches the disk;
the error only shows up at a later fsync() or a synchronous write.
On the volume from the previous patch, after a read of the file, an
8 KiB pwrite() at vcn 1000 returns 8192, fsync() returns -EIO, and
after remount the range is unchanged.
Fail the lookup here too, with -ENOMEM or -EIO. That pwrite() now
fails with -EIO. Writes whose range can be mapped are unaffected.
Fixes: b041ca5625 ("ntfs: update iomap and address space operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
2b451a6565
commit
26e51efbcb
|
|
@ -394,7 +394,7 @@ static int ntfs_write_simple_iomap_begin_non_resident(struct inode *inode, loff_
|
|||
loff_t vcn_ofs, rl_length;
|
||||
struct runlist_element *rl, *rlc;
|
||||
bool is_retry = false;
|
||||
int err = 0;
|
||||
int err = 0, map_err = 0;
|
||||
s64 vcn, lcn;
|
||||
s64 max_clu_count =
|
||||
ntfs_bytes_to_cluster(vol, round_up(length, vol->cluster_size));
|
||||
|
|
@ -429,12 +429,24 @@ static int ntfs_write_simple_iomap_begin_non_resident(struct inode *inode, loff_
|
|||
|
||||
if (lcn <= LCN_RL_NOT_MAPPED && is_retry == false) {
|
||||
is_retry = true;
|
||||
if (!ntfs_map_runlist_nolock(ni, vcn, NULL)) {
|
||||
map_err = ntfs_map_runlist_nolock(ni, vcn, NULL);
|
||||
if (!map_err) {
|
||||
rl = ni->runlist.rl;
|
||||
goto remap_rl;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As in ntfs_attr_vcn_to_rl(): a runlist fragment that could not be
|
||||
* mapped is not a hole. Treating it as one would put a delalloc
|
||||
* extent over clusters that are allocated on disk but unknown to us.
|
||||
*/
|
||||
if (lcn == LCN_RL_NOT_MAPPED) {
|
||||
up_write(&ni->runlist.lock);
|
||||
mutex_unlock(&ni->mrec_lock);
|
||||
return map_err == -ENOMEM ? -ENOMEM : -EIO;
|
||||
}
|
||||
|
||||
max_clu_count = min(max_clu_count, rl->length - (vcn - rl->vcn));
|
||||
if (max_clu_count == 0) {
|
||||
ntfs_error(inode->i_sb,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user