f2fs: fix to update last i_size if fallocate partially succeeds
In the case of expanding pinned file, map.m_lblk and map.m_len
will update in each round of section allocation, so in error
path, last i_size will be calculated with wrong m_lblk and m_len,
fix it.
Fixes: f5a53edcf0
("f2fs: support aligned pinned file")
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
@@ -1617,9 +1617,10 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
|||||||
struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
|
struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
|
||||||
.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
|
.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
|
||||||
.m_may_create = true };
|
.m_may_create = true };
|
||||||
pgoff_t pg_end;
|
pgoff_t pg_start, pg_end;
|
||||||
loff_t new_size = i_size_read(inode);
|
loff_t new_size = i_size_read(inode);
|
||||||
loff_t off_end;
|
loff_t off_end;
|
||||||
|
block_t expanded = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = inode_newsize_ok(inode, (len + offset));
|
err = inode_newsize_ok(inode, (len + offset));
|
||||||
@@ -1632,11 +1633,12 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
|||||||
|
|
||||||
f2fs_balance_fs(sbi, true);
|
f2fs_balance_fs(sbi, true);
|
||||||
|
|
||||||
|
pg_start = ((unsigned long long)offset) >> PAGE_SHIFT;
|
||||||
pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
|
pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
|
||||||
off_end = (offset + len) & (PAGE_SIZE - 1);
|
off_end = (offset + len) & (PAGE_SIZE - 1);
|
||||||
|
|
||||||
map.m_lblk = ((unsigned long long)offset) >> PAGE_SHIFT;
|
map.m_lblk = pg_start;
|
||||||
map.m_len = pg_end - map.m_lblk;
|
map.m_len = pg_end - pg_start;
|
||||||
if (off_end)
|
if (off_end)
|
||||||
map.m_len++;
|
map.m_len++;
|
||||||
|
|
||||||
@@ -1646,7 +1648,6 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
|||||||
if (f2fs_is_pinned_file(inode)) {
|
if (f2fs_is_pinned_file(inode)) {
|
||||||
block_t sec_blks = BLKS_PER_SEC(sbi);
|
block_t sec_blks = BLKS_PER_SEC(sbi);
|
||||||
block_t sec_len = roundup(map.m_len, sec_blks);
|
block_t sec_len = roundup(map.m_len, sec_blks);
|
||||||
block_t done = 0;
|
|
||||||
|
|
||||||
map.m_len = sec_blks;
|
map.m_len = sec_blks;
|
||||||
next_alloc:
|
next_alloc:
|
||||||
@@ -1654,10 +1655,8 @@ next_alloc:
|
|||||||
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
|
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
|
||||||
down_write(&sbi->gc_lock);
|
down_write(&sbi->gc_lock);
|
||||||
err = f2fs_gc(sbi, true, false, false, NULL_SEGNO);
|
err = f2fs_gc(sbi, true, false, false, NULL_SEGNO);
|
||||||
if (err && err != -ENODATA && err != -EAGAIN) {
|
if (err && err != -ENODATA && err != -EAGAIN)
|
||||||
map.m_len = done;
|
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
down_write(&sbi->pin_sem);
|
down_write(&sbi->pin_sem);
|
||||||
@@ -1671,24 +1670,25 @@ next_alloc:
|
|||||||
|
|
||||||
up_write(&sbi->pin_sem);
|
up_write(&sbi->pin_sem);
|
||||||
|
|
||||||
done += map.m_len;
|
expanded += map.m_len;
|
||||||
sec_len -= map.m_len;
|
sec_len -= map.m_len;
|
||||||
map.m_lblk += map.m_len;
|
map.m_lblk += map.m_len;
|
||||||
if (!err && sec_len)
|
if (!err && sec_len)
|
||||||
goto next_alloc;
|
goto next_alloc;
|
||||||
|
|
||||||
map.m_len = done;
|
map.m_len = expanded;
|
||||||
} else {
|
} else {
|
||||||
err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
|
err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO);
|
||||||
|
expanded = map.m_len;
|
||||||
}
|
}
|
||||||
out_err:
|
out_err:
|
||||||
if (err) {
|
if (err) {
|
||||||
pgoff_t last_off;
|
pgoff_t last_off;
|
||||||
|
|
||||||
if (!map.m_len)
|
if (!expanded)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
last_off = map.m_lblk + map.m_len - 1;
|
last_off = pg_start + expanded - 1;
|
||||||
|
|
||||||
/* update new size to the failed position */
|
/* update new size to the failed position */
|
||||||
new_size = (last_off == pg_end) ? offset + len :
|
new_size = (last_off == pg_end) ? offset + len :
|
||||||
|
Reference in New Issue
Block a user