mirror of
https://github.com/torvalds/linux.git
synced 2026-08-02 05:12:01 +02:00
Merge 1d1df41c5a ("Merge tag 'f2fs-for-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs") into android-mainline
Steps on the way to 5.17-rc1 Resolves conflicts in: fs/f2fs/data.c Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> [ebiggers: folded in https://r.android.com/1956401 ("ANDROID: f2fs: fix fscrypt direct I/O support") to keep the fscrypt direct I/O support working despite f2fs's change to use iomap] [ebiggers: moved Android tracepoints for DIO reads and writes to fs/f2fs/file.c, based on android13-5.10] Signed-off-by: Eric Biggers <ebiggers@google.com> Change-Id: I5a4e9a6d2bba0438230a3e5baff5a9d6c76a060f
This commit is contained in:
commit
9ab35b9e14
|
|
@ -112,6 +112,11 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
|||
Description: Set timeout to issue discard commands during umount.
|
||||
Default: 5 secs
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/pending_discard
|
||||
Date: November 2021
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Shows the number of pending discard commands in the queue.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_victim_search
|
||||
Date: January 2014
|
||||
Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
|
||||
|
|
@ -528,3 +533,10 @@ Description: With "mode=fragment:block" mount options, we can scatter block allo
|
|||
f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
|
||||
in the length of 1..<max_fragment_hole> by turns. This value can be set
|
||||
between 1..512 and the default value is 4.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_urgent_high_remaining
|
||||
Date: December 2021
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: You can set the trial count limit for GC urgent high mode with this value.
|
||||
If GC thread gets to the limit, the mode will turn back to GC normal mode.
|
||||
By default, the value is zero, which means there is no limit like before.
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ fault_type=%d Support configuring fault injection type, should be
|
|||
FAULT_WRITE_IO 0x000004000
|
||||
FAULT_SLAB_ALLOC 0x000008000
|
||||
FAULT_DQUOT_INIT 0x000010000
|
||||
FAULT_LOCK_OP 0x000020000
|
||||
=================== ===========
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fscrypt.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/highmem.h>
|
||||
|
|
@ -392,7 +391,6 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
|
|||
sector_t first_sector, int nr_vecs)
|
||||
{
|
||||
struct bio *bio;
|
||||
struct inode *inode = dio->inode;
|
||||
|
||||
/*
|
||||
* bio_alloc() is guaranteed to return a bio when allowed to sleep and
|
||||
|
|
@ -400,9 +398,6 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
|
|||
*/
|
||||
bio = bio_alloc(GFP_KERNEL, nr_vecs);
|
||||
|
||||
fscrypt_set_bio_crypt_ctx(bio, inode,
|
||||
sdio->cur_page_fs_offset >> inode->i_blkbits,
|
||||
GFP_KERNEL);
|
||||
bio_set_dev(bio, bdev);
|
||||
bio->bi_iter.bi_sector = first_sector;
|
||||
bio_set_op_attrs(bio, dio->op, dio->op_flags);
|
||||
|
|
@ -766,17 +761,9 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio,
|
|||
* current logical offset in the file does not equal what would
|
||||
* be the next logical offset in the bio, submit the bio we
|
||||
* have.
|
||||
*
|
||||
* When fscrypt inline encryption is used, data unit number
|
||||
* (DUN) contiguity is also required. Normally that's implied
|
||||
* by logical contiguity. However, certain IV generation
|
||||
* methods (e.g. IV_INO_LBLK_32) don't guarantee it. So, we
|
||||
* must explicitly check fscrypt_mergeable_bio() too.
|
||||
*/
|
||||
if (sdio->final_block_in_bio != sdio->cur_page_block ||
|
||||
cur_offset != bio_next_offset ||
|
||||
!fscrypt_mergeable_bio(sdio->bio, dio->inode,
|
||||
cur_offset >> dio->inode->i_blkbits))
|
||||
cur_offset != bio_next_offset)
|
||||
dio_bio_submit(dio, sdio);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -664,7 +664,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
|||
/* truncate all the data during iput */
|
||||
iput(inode);
|
||||
|
||||
err = f2fs_get_node_info(sbi, ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, ino, &ni, false);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
|
|
@ -1302,8 +1302,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
|||
unsigned long flags;
|
||||
|
||||
if (cpc->reason & CP_UMOUNT) {
|
||||
if (le32_to_cpu(ckpt->cp_pack_total_block_count) >
|
||||
sbi->blocks_per_seg - NM_I(sbi)->nat_bits_blocks) {
|
||||
if (le32_to_cpu(ckpt->cp_pack_total_block_count) +
|
||||
NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) {
|
||||
clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG);
|
||||
f2fs_notice(sbi, "Disable nat_bits due to no space");
|
||||
} else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) &&
|
||||
|
|
|
|||
|
|
@ -1286,7 +1286,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
|||
|
||||
psize = (loff_t)(cc->rpages[last_index]->index + 1) << PAGE_SHIFT;
|
||||
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni, false);
|
||||
if (err)
|
||||
goto out_put_dnode;
|
||||
|
||||
|
|
@ -1456,25 +1456,38 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
|
|||
enum iostat_type io_type)
|
||||
{
|
||||
struct address_space *mapping = cc->inode->i_mapping;
|
||||
int _submitted, compr_blocks, ret;
|
||||
int i = -1, err = 0;
|
||||
int _submitted, compr_blocks, ret, i;
|
||||
|
||||
compr_blocks = f2fs_compressed_blocks(cc);
|
||||
if (compr_blocks < 0) {
|
||||
err = compr_blocks;
|
||||
goto out_err;
|
||||
|
||||
for (i = 0; i < cc->cluster_size; i++) {
|
||||
if (!cc->rpages[i])
|
||||
continue;
|
||||
|
||||
redirty_page_for_writepage(wbc, cc->rpages[i]);
|
||||
unlock_page(cc->rpages[i]);
|
||||
}
|
||||
|
||||
if (compr_blocks < 0)
|
||||
return compr_blocks;
|
||||
|
||||
for (i = 0; i < cc->cluster_size; i++) {
|
||||
if (!cc->rpages[i])
|
||||
continue;
|
||||
retry_write:
|
||||
lock_page(cc->rpages[i]);
|
||||
|
||||
if (cc->rpages[i]->mapping != mapping) {
|
||||
continue_unlock:
|
||||
unlock_page(cc->rpages[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
BUG_ON(!PageLocked(cc->rpages[i]));
|
||||
if (!PageDirty(cc->rpages[i]))
|
||||
goto continue_unlock;
|
||||
|
||||
if (!clear_page_dirty_for_io(cc->rpages[i]))
|
||||
goto continue_unlock;
|
||||
|
||||
ret = f2fs_write_single_data_page(cc->rpages[i], &_submitted,
|
||||
NULL, NULL, wbc, io_type,
|
||||
|
|
@ -1489,26 +1502,15 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
|
|||
* avoid deadlock caused by cluster update race
|
||||
* from foreground operation.
|
||||
*/
|
||||
if (IS_NOQUOTA(cc->inode)) {
|
||||
err = 0;
|
||||
goto out_err;
|
||||
}
|
||||
if (IS_NOQUOTA(cc->inode))
|
||||
return 0;
|
||||
ret = 0;
|
||||
cond_resched();
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
lock_page(cc->rpages[i]);
|
||||
|
||||
if (!PageDirty(cc->rpages[i])) {
|
||||
unlock_page(cc->rpages[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
clear_page_dirty_for_io(cc->rpages[i]);
|
||||
goto retry_write;
|
||||
}
|
||||
err = ret;
|
||||
goto out_err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*submitted += _submitted;
|
||||
|
|
@ -1517,14 +1519,6 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
|
|||
f2fs_balance_fs(F2FS_M_SB(mapping), true);
|
||||
|
||||
return 0;
|
||||
out_err:
|
||||
for (++i; i < cc->cluster_size; i++) {
|
||||
if (!cc->rpages[i])
|
||||
continue;
|
||||
redirty_page_for_writepage(wbc, cc->rpages[i]);
|
||||
unlock_page(cc->rpages[i]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int f2fs_write_multi_pages(struct compress_ctx *cc,
|
||||
|
|
|
|||
271
fs/f2fs/data.c
271
fs/f2fs/data.c
|
|
@ -1360,7 +1360,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
|||
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
|
||||
return -EPERM;
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1382,11 +1382,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
|||
f2fs_invalidate_compress_page(sbi, old_blkaddr);
|
||||
}
|
||||
f2fs_update_data_blkaddr(dn, dn->data_blkaddr);
|
||||
|
||||
/*
|
||||
* i_size will be updated by direct_IO. Otherwise, we'll get stale
|
||||
* data from unwritten block via dio_read.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1748,50 +1743,6 @@ static inline u64 blks_to_bytes(struct inode *inode, u64 blks)
|
|||
return (blks << inode->i_blkbits);
|
||||
}
|
||||
|
||||
static int __get_data_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh, int create, int flag,
|
||||
pgoff_t *next_pgofs, int seg_type, bool may_write)
|
||||
{
|
||||
struct f2fs_map_blocks map;
|
||||
int err;
|
||||
|
||||
map.m_lblk = iblock;
|
||||
map.m_len = bytes_to_blks(inode, bh->b_size);
|
||||
map.m_next_pgofs = next_pgofs;
|
||||
map.m_next_extent = NULL;
|
||||
map.m_seg_type = seg_type;
|
||||
map.m_may_create = may_write;
|
||||
|
||||
err = f2fs_map_blocks(inode, &map, create, flag);
|
||||
if (!err) {
|
||||
map_bh(bh, inode->i_sb, map.m_pblk);
|
||||
bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
|
||||
bh->b_size = blks_to_bytes(inode, map.m_len);
|
||||
|
||||
if (map.m_multidev_dio)
|
||||
bh->b_bdev = map.m_bdev;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_data_block_dio_write(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
return __get_data_block(inode, iblock, bh_result, create,
|
||||
F2FS_GET_BLOCK_DIO, NULL,
|
||||
f2fs_rw_hint_to_seg_type(inode->i_write_hint),
|
||||
true);
|
||||
}
|
||||
|
||||
static int get_data_block_dio(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
return __get_data_block(inode, iblock, bh_result, create,
|
||||
F2FS_GET_BLOCK_DIO, NULL,
|
||||
f2fs_rw_hint_to_seg_type(inode->i_write_hint),
|
||||
false);
|
||||
}
|
||||
|
||||
static int f2fs_xattr_fiemap(struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo)
|
||||
{
|
||||
|
|
@ -1811,7 +1762,7 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
|||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni, false);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
|
|
@ -1843,7 +1794,7 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
|||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
err = f2fs_get_node_info(sbi, xnid, &ni);
|
||||
err = f2fs_get_node_info(sbi, xnid, &ni, false);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
|
|
@ -2579,6 +2530,11 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
|||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
|
||||
/* The below cases were checked when setting it. */
|
||||
if (f2fs_is_pinned_file(inode))
|
||||
return false;
|
||||
if (fio && is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
||||
return true;
|
||||
if (f2fs_lfs_mode(sbi))
|
||||
return true;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
|
|
@ -2587,8 +2543,6 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
|||
return true;
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
return true;
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
||||
return true;
|
||||
|
||||
/* swap file is migrating in aligned write mode */
|
||||
if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
|
||||
|
|
@ -2700,7 +2654,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
|||
fio->need_lock = LOCK_REQ;
|
||||
}
|
||||
|
||||
err = f2fs_get_node_info(fio->sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio->sbi, dn.nid, &ni, false);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
|
|
@ -3268,7 +3222,7 @@ static int f2fs_write_data_pages(struct address_space *mapping,
|
|||
FS_CP_DATA_IO : FS_DATA_IO);
|
||||
}
|
||||
|
||||
static void f2fs_write_failed(struct inode *inode, loff_t to)
|
||||
void f2fs_write_failed(struct inode *inode, loff_t to)
|
||||
{
|
||||
loff_t i_size = i_size_read(inode);
|
||||
|
||||
|
|
@ -3573,188 +3527,6 @@ static int f2fs_write_end(struct file *file,
|
|||
return copied;
|
||||
}
|
||||
|
||||
static int check_direct_IO(struct inode *inode, struct iov_iter *iter,
|
||||
loff_t offset)
|
||||
{
|
||||
unsigned i_blkbits = READ_ONCE(inode->i_blkbits);
|
||||
unsigned blkbits = i_blkbits;
|
||||
unsigned blocksize_mask = (1 << blkbits) - 1;
|
||||
unsigned long align = offset | iov_iter_alignment(iter);
|
||||
struct block_device *bdev = inode->i_sb->s_bdev;
|
||||
|
||||
if (iov_iter_rw(iter) == READ && offset >= i_size_read(inode))
|
||||
return 1;
|
||||
|
||||
if (align & blocksize_mask) {
|
||||
if (bdev)
|
||||
blkbits = blksize_bits(bdev_logical_block_size(bdev));
|
||||
blocksize_mask = (1 << blkbits) - 1;
|
||||
if (align & blocksize_mask)
|
||||
return -EINVAL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void f2fs_dio_end_io(struct bio *bio)
|
||||
{
|
||||
struct f2fs_private_dio *dio = bio->bi_private;
|
||||
|
||||
dec_page_count(F2FS_I_SB(dio->inode),
|
||||
dio->write ? F2FS_DIO_WRITE : F2FS_DIO_READ);
|
||||
|
||||
bio->bi_private = dio->orig_private;
|
||||
bio->bi_end_io = dio->orig_end_io;
|
||||
|
||||
kfree(dio);
|
||||
|
||||
bio_endio(bio);
|
||||
}
|
||||
|
||||
static void f2fs_dio_submit_bio(struct bio *bio, struct inode *inode,
|
||||
loff_t file_offset)
|
||||
{
|
||||
struct f2fs_private_dio *dio;
|
||||
bool write = (bio_op(bio) == REQ_OP_WRITE);
|
||||
|
||||
dio = f2fs_kzalloc(F2FS_I_SB(inode),
|
||||
sizeof(struct f2fs_private_dio), GFP_NOFS);
|
||||
if (!dio)
|
||||
goto out;
|
||||
|
||||
dio->inode = inode;
|
||||
dio->orig_end_io = bio->bi_end_io;
|
||||
dio->orig_private = bio->bi_private;
|
||||
dio->write = write;
|
||||
|
||||
bio->bi_end_io = f2fs_dio_end_io;
|
||||
bio->bi_private = dio;
|
||||
|
||||
inc_page_count(F2FS_I_SB(inode),
|
||||
write ? F2FS_DIO_WRITE : F2FS_DIO_READ);
|
||||
|
||||
submit_bio(bio);
|
||||
return;
|
||||
out:
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
bio_endio(bio);
|
||||
}
|
||||
|
||||
static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
{
|
||||
struct address_space *mapping = iocb->ki_filp->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
size_t count = iov_iter_count(iter);
|
||||
loff_t offset = iocb->ki_pos;
|
||||
int rw = iov_iter_rw(iter);
|
||||
int err;
|
||||
enum rw_hint hint = iocb->ki_hint;
|
||||
int whint_mode = F2FS_OPTION(sbi).whint_mode;
|
||||
bool do_opu;
|
||||
|
||||
err = check_direct_IO(inode, iter, offset);
|
||||
if (err)
|
||||
return err < 0 ? err : 0;
|
||||
|
||||
if (f2fs_force_buffered_io(inode, iocb, iter))
|
||||
return 0;
|
||||
|
||||
do_opu = rw == WRITE && f2fs_lfs_mode(sbi);
|
||||
|
||||
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_dataread_start(inode, offset,
|
||||
count, current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, offset, count,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
|
||||
if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = WRITE_LIFE_NOT_SET;
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
if (!down_read_trylock(&fi->i_gc_rwsem[rw])) {
|
||||
iocb->ki_hint = hint;
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
if (do_opu && !down_read_trylock(&fi->i_gc_rwsem[READ])) {
|
||||
up_read(&fi->i_gc_rwsem[rw]);
|
||||
iocb->ki_hint = hint;
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
down_read(&fi->i_gc_rwsem[rw]);
|
||||
if (do_opu)
|
||||
down_read(&fi->i_gc_rwsem[READ]);
|
||||
}
|
||||
|
||||
err = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
|
||||
iter, rw == WRITE ? get_data_block_dio_write :
|
||||
get_data_block_dio, NULL, f2fs_dio_submit_bio,
|
||||
rw == WRITE ? DIO_LOCKING | DIO_SKIP_HOLES :
|
||||
DIO_SKIP_HOLES);
|
||||
|
||||
if (do_opu)
|
||||
up_read(&fi->i_gc_rwsem[READ]);
|
||||
|
||||
up_read(&fi->i_gc_rwsem[rw]);
|
||||
|
||||
if (rw == WRITE) {
|
||||
if (whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = hint;
|
||||
if (err > 0) {
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
|
||||
err);
|
||||
if (!do_opu)
|
||||
set_inode_flag(inode, FI_UPDATE_WRITE);
|
||||
} else if (err == -EIOCBQUEUED) {
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
|
||||
count - iov_iter_count(iter));
|
||||
} else if (err < 0) {
|
||||
f2fs_write_failed(inode, offset + count);
|
||||
}
|
||||
} else {
|
||||
if (err > 0)
|
||||
f2fs_update_iostat(sbi, APP_DIRECT_READ_IO, err);
|
||||
else if (err == -EIOCBQUEUED)
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_READ_IO,
|
||||
count - iov_iter_count(iter));
|
||||
}
|
||||
|
||||
out:
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ))
|
||||
trace_android_fs_dataread_end(inode, offset, count);
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE))
|
||||
trace_android_fs_datawrite_end(inode, offset, count);
|
||||
|
||||
trace_f2fs_direct_IO_exit(inode, offset, count, rw, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
unsigned int length)
|
||||
{
|
||||
|
|
@ -3778,12 +3550,9 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
|||
|
||||
clear_page_private_gcing(page);
|
||||
|
||||
if (test_opt(sbi, COMPRESS_CACHE)) {
|
||||
if (f2fs_compressed_file(inode))
|
||||
f2fs_invalidate_compress_pages(sbi, inode->i_ino);
|
||||
if (inode->i_ino == F2FS_COMPRESS_INO(sbi))
|
||||
clear_page_private_data(page);
|
||||
}
|
||||
if (test_opt(sbi, COMPRESS_CACHE) &&
|
||||
inode->i_ino == F2FS_COMPRESS_INO(sbi))
|
||||
clear_page_private_data(page);
|
||||
|
||||
if (page_private_atomic(page))
|
||||
return f2fs_drop_inmem_page(inode, page);
|
||||
|
|
@ -3803,12 +3572,9 @@ int f2fs_release_page(struct page *page, gfp_t wait)
|
|||
return 0;
|
||||
|
||||
if (test_opt(F2FS_P_SB(page), COMPRESS_CACHE)) {
|
||||
struct f2fs_sb_info *sbi = F2FS_P_SB(page);
|
||||
struct inode *inode = page->mapping->host;
|
||||
|
||||
if (f2fs_compressed_file(inode))
|
||||
f2fs_invalidate_compress_pages(sbi, inode->i_ino);
|
||||
if (inode->i_ino == F2FS_COMPRESS_INO(sbi))
|
||||
if (inode->i_ino == F2FS_COMPRESS_INO(F2FS_I_SB(inode)))
|
||||
clear_page_private_data(page);
|
||||
}
|
||||
|
||||
|
|
@ -4210,7 +3976,7 @@ const struct address_space_operations f2fs_dblock_aops = {
|
|||
.set_page_dirty = f2fs_set_data_page_dirty,
|
||||
.invalidatepage = f2fs_invalidate_page,
|
||||
.releasepage = f2fs_release_page,
|
||||
.direct_IO = f2fs_direct_IO,
|
||||
.direct_IO = noop_direct_IO,
|
||||
.bmap = f2fs_bmap,
|
||||
.swap_activate = f2fs_swap_activate,
|
||||
.swap_deactivate = f2fs_swap_deactivate,
|
||||
|
|
@ -4313,6 +4079,13 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
|
|||
|
||||
iomap->offset = blks_to_bytes(inode, map.m_lblk);
|
||||
|
||||
/*
|
||||
* When inline encryption is enabled, sometimes I/O to an encrypted file
|
||||
* has to be broken up to guarantee DUN contiguity. Handle this by
|
||||
* limiting the length of the mapping returned.
|
||||
*/
|
||||
map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len);
|
||||
|
||||
if (map.m_flags & (F2FS_MAP_MAPPED | F2FS_MAP_UNWRITTEN)) {
|
||||
iomap->length = blks_to_bytes(inode, map.m_len);
|
||||
if (map.m_flags & F2FS_MAP_MAPPED) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ enum {
|
|||
FAULT_WRITE_IO,
|
||||
FAULT_SLAB_ALLOC,
|
||||
FAULT_DQUOT_INIT,
|
||||
FAULT_LOCK_OP,
|
||||
FAULT_MAX,
|
||||
};
|
||||
|
||||
|
|
@ -1025,6 +1026,7 @@ struct f2fs_sm_info {
|
|||
unsigned int segment_count; /* total # of segments */
|
||||
unsigned int main_segments; /* # of segments in main area */
|
||||
unsigned int reserved_segments; /* # of reserved segments */
|
||||
unsigned int additional_reserved_segments;/* reserved segs for IO align feature */
|
||||
unsigned int ovp_segments; /* # of overprovision segments */
|
||||
|
||||
/* a threshold to reclaim prefree segments */
|
||||
|
|
@ -1685,6 +1687,9 @@ struct f2fs_sb_info {
|
|||
unsigned int cur_victim_sec; /* current victim section num */
|
||||
unsigned int gc_mode; /* current GC state */
|
||||
unsigned int next_victim_seg[2]; /* next segment in victim section */
|
||||
spinlock_t gc_urgent_high_lock;
|
||||
bool gc_urgent_high_limited; /* indicates having limited trial count */
|
||||
unsigned int gc_urgent_high_remaining; /* remaining trial count for GC_URGENT_HIGH */
|
||||
|
||||
/* for skip statistic */
|
||||
unsigned int atomic_files; /* # of opened atomic file */
|
||||
|
|
@ -1809,13 +1814,6 @@ struct f2fs_sb_info {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct f2fs_private_dio {
|
||||
struct inode *inode;
|
||||
void *orig_private;
|
||||
bio_end_io_t *orig_end_io;
|
||||
bool write;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
#define f2fs_show_injection_info(sbi, type) \
|
||||
printk_ratelimited("%sF2FS-fs (%s) : inject %s in %s of %pS\n", \
|
||||
|
|
@ -2101,6 +2099,10 @@ static inline void f2fs_lock_op(struct f2fs_sb_info *sbi)
|
|||
|
||||
static inline int f2fs_trylock_op(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
if (time_to_inject(sbi, FAULT_LOCK_OP)) {
|
||||
f2fs_show_injection_info(sbi, FAULT_LOCK_OP);
|
||||
return 0;
|
||||
}
|
||||
return down_read_trylock(&sbi->cp_rwsem);
|
||||
}
|
||||
|
||||
|
|
@ -2206,6 +2208,11 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi,
|
|||
|
||||
if (!__allow_reserved_blocks(sbi, inode, true))
|
||||
avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
|
||||
|
||||
if (F2FS_IO_ALIGNED(sbi))
|
||||
avail_user_block_count -= sbi->blocks_per_seg *
|
||||
SM_I(sbi)->additional_reserved_segments;
|
||||
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
|
||||
if (avail_user_block_count > sbi->unusable_block_count)
|
||||
avail_user_block_count -= sbi->unusable_block_count;
|
||||
|
|
@ -2452,6 +2459,11 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi,
|
|||
|
||||
if (!__allow_reserved_blocks(sbi, inode, false))
|
||||
valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
|
||||
|
||||
if (F2FS_IO_ALIGNED(sbi))
|
||||
valid_block_count += sbi->blocks_per_seg *
|
||||
SM_I(sbi)->additional_reserved_segments;
|
||||
|
||||
user_block_count = sbi->user_block_count;
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
|
||||
user_block_count -= sbi->unusable_block_count;
|
||||
|
|
@ -3124,12 +3136,16 @@ static inline int is_file(struct inode *inode, int type)
|
|||
|
||||
static inline void set_file(struct inode *inode, int type)
|
||||
{
|
||||
if (is_file(inode, type))
|
||||
return;
|
||||
F2FS_I(inode)->i_advise |= type;
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
|
||||
static inline void clear_file(struct inode *inode, int type)
|
||||
{
|
||||
if (!is_file(inode, type))
|
||||
return;
|
||||
F2FS_I(inode)->i_advise &= ~type;
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
|
|
@ -3414,7 +3430,7 @@ int f2fs_need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid);
|
|||
bool f2fs_is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||
struct node_info *ni);
|
||||
struct node_info *ni, bool checkpoint_context);
|
||||
pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs);
|
||||
int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode);
|
||||
int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from);
|
||||
|
|
@ -3644,6 +3660,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
|
|||
struct writeback_control *wbc,
|
||||
enum iostat_type io_type,
|
||||
int compr_blocks, bool allow_balance);
|
||||
void f2fs_write_failed(struct inode *inode, loff_t to);
|
||||
void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
unsigned int length);
|
||||
int f2fs_release_page(struct page *page, gfp_t wait);
|
||||
|
|
|
|||
397
fs/f2fs/file.c
397
fs/f2fs/file.c
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/sched/signal.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include <linux/fadvise.h>
|
||||
#include <linux/iomap.h>
|
||||
|
||||
#include "f2fs.h"
|
||||
#include "node.h"
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
#include "gc.h"
|
||||
#include "iostat.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
#include <trace/events/android_fs.h>
|
||||
#include <uapi/linux/f2fs.h>
|
||||
|
||||
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
|
||||
|
|
@ -1232,7 +1234,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
ret = f2fs_get_node_info(sbi, dn.nid, &ni, false);
|
||||
if (ret) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return ret;
|
||||
|
|
@ -1749,7 +1751,11 @@ static long f2fs_fallocate(struct file *file, int mode,
|
|||
(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (f2fs_compressed_file(inode) &&
|
||||
/*
|
||||
* Pinned file should not support partial trucation since the block
|
||||
* can be used by applications.
|
||||
*/
|
||||
if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) &&
|
||||
(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
|
||||
FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE)))
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -3144,17 +3150,17 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
|||
|
||||
inode_lock(inode);
|
||||
|
||||
if (f2fs_should_update_outplace(inode, NULL)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pin) {
|
||||
clear_inode_flag(inode, FI_PIN_FILE);
|
||||
f2fs_i_gc_failures_write(inode, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (f2fs_should_update_outplace(inode, NULL)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f2fs_pin_file_control(inode, false)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
|
|
@ -4219,23 +4225,157 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
return __f2fs_ioctl(filp, cmd, arg);
|
||||
}
|
||||
|
||||
static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
||||
/*
|
||||
* Return %true if the given read or write request should use direct I/O, or
|
||||
* %false if it should use buffered I/O.
|
||||
*/
|
||||
static bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb,
|
||||
struct iov_iter *iter)
|
||||
{
|
||||
unsigned int align;
|
||||
|
||||
if (!(iocb->ki_flags & IOCB_DIRECT))
|
||||
return false;
|
||||
|
||||
if (f2fs_force_buffered_io(inode, iocb, iter))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Direct I/O not aligned to the disk's logical_block_size will be
|
||||
* attempted, but will fail with -EINVAL.
|
||||
*
|
||||
* f2fs additionally requires that direct I/O be aligned to the
|
||||
* filesystem block size, which is often a stricter requirement.
|
||||
* However, f2fs traditionally falls back to buffered I/O on requests
|
||||
* that are logical_block_size-aligned but not fs-block aligned.
|
||||
*
|
||||
* The below logic implements this behavior.
|
||||
*/
|
||||
align = iocb->ki_pos | iov_iter_alignment(iter);
|
||||
if (!IS_ALIGNED(align, i_blocksize(inode)) &&
|
||||
IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int f2fs_dio_read_end_io(struct kiocb *iocb, ssize_t size, int error,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
|
||||
|
||||
dec_page_count(sbi, F2FS_DIO_READ);
|
||||
if (error)
|
||||
return error;
|
||||
f2fs_update_iostat(sbi, APP_DIRECT_READ_IO, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iomap_dio_ops f2fs_iomap_dio_read_ops = {
|
||||
.end_io = f2fs_dio_read_end_io,
|
||||
};
|
||||
|
||||
static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
int ret;
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
const loff_t pos = iocb->ki_pos;
|
||||
const size_t count = iov_iter_count(to);
|
||||
struct iomap_dio *dio;
|
||||
ssize_t ret;
|
||||
|
||||
if (count == 0)
|
||||
return 0; /* skip atime update */
|
||||
|
||||
trace_f2fs_direct_IO_enter(inode, iocb, count, READ);
|
||||
if (trace_android_fs_dataread_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_dataread_start(inode, pos,
|
||||
count, current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
if (!down_read_trylock(&fi->i_gc_rwsem[READ])) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
down_read(&fi->i_gc_rwsem[READ]);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
|
||||
* the higher-level function iomap_dio_rw() in order to ensure that the
|
||||
* F2FS_DIO_READ counter will be decremented correctly in all cases.
|
||||
*/
|
||||
inc_page_count(sbi, F2FS_DIO_READ);
|
||||
dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
|
||||
&f2fs_iomap_dio_read_ops, 0, 0);
|
||||
if (IS_ERR_OR_NULL(dio)) {
|
||||
ret = PTR_ERR_OR_ZERO(dio);
|
||||
if (ret != -EIOCBQUEUED)
|
||||
dec_page_count(sbi, F2FS_DIO_READ);
|
||||
} else {
|
||||
ret = iomap_dio_complete(dio);
|
||||
}
|
||||
|
||||
up_read(&fi->i_gc_rwsem[READ]);
|
||||
|
||||
file_accessed(file);
|
||||
out:
|
||||
if (trace_android_fs_dataread_start_enabled())
|
||||
trace_android_fs_dataread_end(inode, pos, count);
|
||||
trace_f2fs_direct_IO_exit(inode, pos, count, READ, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
ssize_t ret;
|
||||
|
||||
if (!f2fs_is_compress_backend_ready(inode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = generic_file_read_iter(iocb, iter);
|
||||
if (f2fs_should_use_dio(inode, iocb, to))
|
||||
return f2fs_dio_read_iter(iocb, to);
|
||||
|
||||
ret = filemap_read(iocb, to, 0);
|
||||
if (ret > 0)
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_READ_IO, ret);
|
||||
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_BUFFERED_READ_IO, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
ssize_t count;
|
||||
int err;
|
||||
|
||||
if (IS_IMMUTABLE(inode))
|
||||
return -EPERM;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
||||
return -EPERM;
|
||||
|
||||
count = generic_write_checks(iocb, from);
|
||||
if (count <= 0)
|
||||
return count;
|
||||
|
||||
err = file_modified(file);
|
||||
if (err)
|
||||
return err;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preallocate blocks for a write request, if it is possible and helpful to do
|
||||
* so. Returns a positive number if blocks may have been preallocated, 0 if no
|
||||
|
|
@ -4243,15 +4383,14 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
|
|||
* seriously wrong. Also sets FI_PREALLOCATED_ALL on the inode if *all* the
|
||||
* requested blocks (not just some of them) have been allocated.
|
||||
*/
|
||||
static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter)
|
||||
static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter,
|
||||
bool dio)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
const loff_t pos = iocb->ki_pos;
|
||||
const size_t count = iov_iter_count(iter);
|
||||
struct f2fs_map_blocks map = {};
|
||||
bool dio = (iocb->ki_flags & IOCB_DIRECT) &&
|
||||
!f2fs_force_buffered_io(inode, iocb, iter);
|
||||
int flag;
|
||||
int ret;
|
||||
|
||||
|
|
@ -4308,13 +4447,186 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter)
|
|||
return map.m_len;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
static ssize_t f2fs_buffered_write_iter(struct kiocb *iocb,
|
||||
struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
ssize_t ret;
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
current->backing_dev_info = inode_to_bdi(inode);
|
||||
ret = generic_perform_write(file, from, iocb->ki_pos);
|
||||
current->backing_dev_info = NULL;
|
||||
|
||||
if (ret > 0) {
|
||||
iocb->ki_pos += ret;
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_BUFFERED_IO, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
|
||||
|
||||
dec_page_count(sbi, F2FS_DIO_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
f2fs_update_iostat(sbi, APP_DIRECT_IO, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iomap_dio_ops f2fs_iomap_dio_write_ops = {
|
||||
.end_io = f2fs_dio_write_end_io,
|
||||
};
|
||||
|
||||
static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
|
||||
bool *may_need_sync)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
const bool do_opu = f2fs_lfs_mode(sbi);
|
||||
const int whint_mode = F2FS_OPTION(sbi).whint_mode;
|
||||
const loff_t pos = iocb->ki_pos;
|
||||
const ssize_t count = iov_iter_count(from);
|
||||
const enum rw_hint hint = iocb->ki_hint;
|
||||
unsigned int dio_flags;
|
||||
struct iomap_dio *dio;
|
||||
ssize_t ret;
|
||||
|
||||
trace_f2fs_direct_IO_enter(inode, iocb, count, WRITE);
|
||||
if (trace_android_fs_datawrite_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, pos, count,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
/* f2fs_convert_inline_inode() and block allocation can block */
|
||||
if (f2fs_has_inline_data(inode) ||
|
||||
!f2fs_overwrite_io(inode, pos, count)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!down_read_trylock(&fi->i_gc_rwsem[WRITE])) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
if (do_opu && !down_read_trylock(&fi->i_gc_rwsem[READ])) {
|
||||
up_read(&fi->i_gc_rwsem[WRITE]);
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
ret = f2fs_convert_inline_inode(inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
down_read(&fi->i_gc_rwsem[WRITE]);
|
||||
if (do_opu)
|
||||
down_read(&fi->i_gc_rwsem[READ]);
|
||||
}
|
||||
if (whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = WRITE_LIFE_NOT_SET;
|
||||
|
||||
/*
|
||||
* We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
|
||||
* the higher-level function iomap_dio_rw() in order to ensure that the
|
||||
* F2FS_DIO_WRITE counter will be decremented correctly in all cases.
|
||||
*/
|
||||
inc_page_count(sbi, F2FS_DIO_WRITE);
|
||||
dio_flags = 0;
|
||||
if (pos + count > inode->i_size)
|
||||
dio_flags |= IOMAP_DIO_FORCE_WAIT;
|
||||
dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
|
||||
&f2fs_iomap_dio_write_ops, dio_flags, 0);
|
||||
if (IS_ERR_OR_NULL(dio)) {
|
||||
ret = PTR_ERR_OR_ZERO(dio);
|
||||
if (ret == -ENOTBLK)
|
||||
ret = 0;
|
||||
if (ret != -EIOCBQUEUED)
|
||||
dec_page_count(sbi, F2FS_DIO_WRITE);
|
||||
} else {
|
||||
ret = iomap_dio_complete(dio);
|
||||
}
|
||||
|
||||
if (whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = hint;
|
||||
if (do_opu)
|
||||
up_read(&fi->i_gc_rwsem[READ]);
|
||||
up_read(&fi->i_gc_rwsem[WRITE]);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (pos + ret > inode->i_size)
|
||||
f2fs_i_size_write(inode, pos + ret);
|
||||
if (!do_opu)
|
||||
set_inode_flag(inode, FI_UPDATE_WRITE);
|
||||
|
||||
if (iov_iter_count(from)) {
|
||||
ssize_t ret2;
|
||||
loff_t bufio_start_pos = iocb->ki_pos;
|
||||
|
||||
/*
|
||||
* The direct write was partial, so we need to fall back to a
|
||||
* buffered write for the remainder.
|
||||
*/
|
||||
|
||||
ret2 = f2fs_buffered_write_iter(iocb, from);
|
||||
if (iov_iter_count(from))
|
||||
f2fs_write_failed(inode, iocb->ki_pos);
|
||||
if (ret2 < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Ensure that the pagecache pages are written to disk and
|
||||
* invalidated to preserve the expected O_DIRECT semantics.
|
||||
*/
|
||||
if (ret2 > 0) {
|
||||
loff_t bufio_end_pos = bufio_start_pos + ret2 - 1;
|
||||
|
||||
ret += ret2;
|
||||
|
||||
ret2 = filemap_write_and_wait_range(file->f_mapping,
|
||||
bufio_start_pos,
|
||||
bufio_end_pos);
|
||||
if (ret2 < 0)
|
||||
goto out;
|
||||
invalidate_mapping_pages(file->f_mapping,
|
||||
bufio_start_pos >> PAGE_SHIFT,
|
||||
bufio_end_pos >> PAGE_SHIFT);
|
||||
}
|
||||
} else {
|
||||
/* iomap_dio_rw() already handled the generic_write_sync(). */
|
||||
*may_need_sync = false;
|
||||
}
|
||||
out:
|
||||
if (trace_android_fs_datawrite_start_enabled())
|
||||
trace_android_fs_datawrite_end(inode, pos, count);
|
||||
trace_f2fs_direct_IO_exit(inode, pos, count, WRITE, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct inode *inode = file_inode(iocb->ki_filp);
|
||||
const loff_t orig_pos = iocb->ki_pos;
|
||||
const size_t orig_count = iov_iter_count(from);
|
||||
loff_t target_size;
|
||||
bool dio;
|
||||
bool may_need_sync = true;
|
||||
int preallocated;
|
||||
ssize_t ret;
|
||||
|
||||
|
|
@ -4337,42 +4649,23 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
inode_lock(inode);
|
||||
}
|
||||
|
||||
if (unlikely(IS_IMMUTABLE(inode))) {
|
||||
ret = -EPERM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
||||
ret = -EPERM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
ret = f2fs_write_checks(iocb, from);
|
||||
if (ret <= 0)
|
||||
goto out_unlock;
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
if (!f2fs_overwrite_io(inode, iocb->ki_pos,
|
||||
iov_iter_count(from)) ||
|
||||
f2fs_has_inline_data(inode) ||
|
||||
f2fs_force_buffered_io(inode, iocb, from)) {
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
/* Determine whether we will do a direct write or a buffered write. */
|
||||
dio = f2fs_should_use_dio(inode, iocb, from);
|
||||
|
||||
if (iocb->ki_flags & IOCB_DIRECT) {
|
||||
ret = f2fs_convert_inline_inode(inode);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
/* Possibly preallocate the blocks for the write. */
|
||||
target_size = iocb->ki_pos + iov_iter_count(from);
|
||||
preallocated = f2fs_preallocate_blocks(iocb, from);
|
||||
preallocated = f2fs_preallocate_blocks(iocb, from, dio);
|
||||
if (preallocated < 0)
|
||||
ret = preallocated;
|
||||
else
|
||||
ret = __generic_file_write_iter(iocb, from);
|
||||
/* Do the actual write. */
|
||||
ret = dio ?
|
||||
f2fs_dio_write_iter(iocb, from, &may_need_sync):
|
||||
f2fs_buffered_write_iter(iocb, from);
|
||||
|
||||
/* Don't leave any preallocated blocks around past i_size. */
|
||||
if (preallocated && i_size_read(inode) < target_size) {
|
||||
|
|
@ -4387,15 +4680,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
}
|
||||
|
||||
clear_inode_flag(inode, FI_PREALLOCATED_ALL);
|
||||
|
||||
if (ret > 0)
|
||||
f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
|
||||
|
||||
out_unlock:
|
||||
inode_unlock(inode);
|
||||
out:
|
||||
trace_f2fs_file_write_iter(inode, orig_pos, orig_count, ret);
|
||||
if (ret > 0)
|
||||
if (ret > 0 && may_need_sync)
|
||||
ret = generic_write_sync(iocb, ret);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -4403,12 +4692,12 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
|
||||
int advice)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct address_space *mapping;
|
||||
struct backing_dev_info *bdi;
|
||||
struct inode *inode = file_inode(filp);
|
||||
int err;
|
||||
|
||||
if (advice == POSIX_FADV_SEQUENTIAL) {
|
||||
inode = file_inode(filp);
|
||||
if (S_ISFIFO(inode->i_mode))
|
||||
return -ESPIPE;
|
||||
|
||||
|
|
@ -4425,7 +4714,13 @@ static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
return generic_fadvise(filp, offset, len, advice);
|
||||
err = generic_fadvise(filp, offset, len, advice);
|
||||
if (!err && advice == POSIX_FADV_DONTNEED &&
|
||||
test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
|
||||
f2fs_compressed_file(inode))
|
||||
f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
|
|||
26
fs/f2fs/gc.c
26
fs/f2fs/gc.c
|
|
@ -92,6 +92,18 @@ static int gc_thread_func(void *data)
|
|||
* So, I'd like to wait some time to collect dirty segments.
|
||||
*/
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH) {
|
||||
spin_lock(&sbi->gc_urgent_high_lock);
|
||||
if (sbi->gc_urgent_high_limited) {
|
||||
if (!sbi->gc_urgent_high_remaining) {
|
||||
sbi->gc_urgent_high_limited = false;
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
continue;
|
||||
}
|
||||
sbi->gc_urgent_high_remaining--;
|
||||
}
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
|
||||
wait_ms = gc_th->urgent_sleep_time;
|
||||
down_write(&sbi->gc_lock);
|
||||
goto do_gc;
|
||||
|
|
@ -947,7 +959,7 @@ static int gc_node_segment(struct f2fs_sb_info *sbi,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (f2fs_get_node_info(sbi, nid, &ni)) {
|
||||
if (f2fs_get_node_info(sbi, nid, &ni, false)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1015,7 +1027,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
|||
if (IS_ERR(node_page))
|
||||
return false;
|
||||
|
||||
if (f2fs_get_node_info(sbi, nid, dni)) {
|
||||
if (f2fs_get_node_info(sbi, nid, dni, false)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1026,6 +1038,9 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
|||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
}
|
||||
|
||||
if (f2fs_check_nid_range(sbi, dni->ino))
|
||||
return false;
|
||||
|
||||
*nofs = ofs_of_node(node_page);
|
||||
source_blkaddr = data_blkaddr(NULL, node_page, ofs_in_node);
|
||||
f2fs_put_page(node_page, 1);
|
||||
|
|
@ -1039,7 +1054,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
|||
if (!test_and_set_bit(segno, SIT_I(sbi)->invalid_segmap)) {
|
||||
f2fs_err(sbi, "mismatched blkaddr %u (source_blkaddr %u) in seg %u",
|
||||
blkaddr, source_blkaddr, segno);
|
||||
f2fs_bug_on(sbi, 1);
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1206,7 +1221,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
|||
|
||||
f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
|
||||
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni, false);
|
||||
if (err)
|
||||
goto put_out;
|
||||
|
||||
|
|
@ -1456,7 +1471,8 @@ static int gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
|||
|
||||
if (phase == 3) {
|
||||
inode = f2fs_iget(sb, dni.ino);
|
||||
if (IS_ERR(inode) || is_bad_inode(inode))
|
||||
if (IS_ERR(inode) || is_bad_inode(inode) ||
|
||||
special_file(inode->i_mode))
|
||||
continue;
|
||||
|
||||
if (!down_write_trylock(
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = f2fs_get_node_info(fio.sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn->nid, &ni, false);
|
||||
if (err) {
|
||||
f2fs_truncate_data_blocks_range(dn, 1);
|
||||
f2fs_put_dnode(dn);
|
||||
|
|
@ -804,7 +804,7 @@ int f2fs_inline_data_fiemap(struct inode *inode,
|
|||
ilen = start + len;
|
||||
ilen -= start;
|
||||
|
||||
err = f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni, false);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
|
|
|||
|
|
@ -516,6 +516,11 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
|
|||
} else if (ino == F2FS_COMPRESS_INO(sbi)) {
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
inode->i_mapping->a_ops = &f2fs_compress_aops;
|
||||
/*
|
||||
* generic_error_remove_page only truncates pages of regular
|
||||
* inode
|
||||
*/
|
||||
inode->i_mode |= S_IFREG;
|
||||
#endif
|
||||
mapping_set_gfp_mask(inode->i_mapping,
|
||||
GFP_NOFS | __GFP_HIGHMEM | __GFP_MOVABLE);
|
||||
|
|
@ -746,7 +751,8 @@ void f2fs_evict_inode(struct inode *inode)
|
|||
trace_f2fs_evict_inode(inode);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
if (test_opt(sbi, COMPRESS_CACHE) && f2fs_compressed_file(inode))
|
||||
if ((inode->i_nlink || is_bad_inode(inode)) &&
|
||||
test_opt(sbi, COMPRESS_CACHE) && f2fs_compressed_file(inode))
|
||||
f2fs_invalidate_compress_pages(sbi, inode->i_ino);
|
||||
|
||||
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||
|
|
@ -876,7 +882,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
|
|||
* so we can prevent losing this orphan when encoutering checkpoint
|
||||
* and following suddenly power-off.
|
||||
*/
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni, false);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_warn(sbi, "May loss orphan inode, run fsck to fix.");
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ static inline void __record_iostat_latency(struct f2fs_sb_info *sbi)
|
|||
struct f2fs_iostat_latency iostat_lat[MAX_IO_TYPE][NR_PAGE_TYPE];
|
||||
struct iostat_lat_info *io_lat = sbi->iostat_io_lat;
|
||||
|
||||
spin_lock_irq(&sbi->iostat_lat_lock);
|
||||
spin_lock_bh(&sbi->iostat_lat_lock);
|
||||
for (idx = 0; idx < MAX_IO_TYPE; idx++) {
|
||||
for (io = 0; io < NR_PAGE_TYPE; io++) {
|
||||
cnt = io_lat->bio_cnt[idx][io];
|
||||
|
|
@ -106,7 +106,7 @@ static inline void __record_iostat_latency(struct f2fs_sb_info *sbi)
|
|||
io_lat->bio_cnt[idx][io] = 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&sbi->iostat_lat_lock);
|
||||
spin_unlock_bh(&sbi->iostat_lat_lock);
|
||||
|
||||
trace_f2fs_iostat_latency(sbi, iostat_lat);
|
||||
}
|
||||
|
|
@ -120,9 +120,9 @@ static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi)
|
|||
return;
|
||||
|
||||
/* Need double check under the lock */
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
spin_lock_bh(&sbi->iostat_lock);
|
||||
if (time_is_after_jiffies(sbi->iostat_next_period)) {
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
spin_unlock_bh(&sbi->iostat_lock);
|
||||
return;
|
||||
}
|
||||
sbi->iostat_next_period = jiffies +
|
||||
|
|
@ -133,7 +133,7 @@ static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi)
|
|||
sbi->prev_rw_iostat[i];
|
||||
sbi->prev_rw_iostat[i] = sbi->rw_iostat[i];
|
||||
}
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
spin_unlock_bh(&sbi->iostat_lock);
|
||||
|
||||
trace_f2fs_iostat(sbi, iostat_diff);
|
||||
|
||||
|
|
@ -145,16 +145,16 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi)
|
|||
struct iostat_lat_info *io_lat = sbi->iostat_io_lat;
|
||||
int i;
|
||||
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
spin_lock_bh(&sbi->iostat_lock);
|
||||
for (i = 0; i < NR_IO_TYPE; i++) {
|
||||
sbi->rw_iostat[i] = 0;
|
||||
sbi->prev_rw_iostat[i] = 0;
|
||||
}
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
spin_unlock_bh(&sbi->iostat_lock);
|
||||
|
||||
spin_lock_irq(&sbi->iostat_lat_lock);
|
||||
spin_lock_bh(&sbi->iostat_lat_lock);
|
||||
memset(io_lat, 0, sizeof(struct iostat_lat_info));
|
||||
spin_unlock_irq(&sbi->iostat_lat_lock);
|
||||
spin_unlock_bh(&sbi->iostat_lat_lock);
|
||||
}
|
||||
|
||||
void f2fs_update_iostat(struct f2fs_sb_info *sbi,
|
||||
|
|
@ -163,19 +163,16 @@ void f2fs_update_iostat(struct f2fs_sb_info *sbi,
|
|||
if (!sbi->iostat_enable)
|
||||
return;
|
||||
|
||||
spin_lock(&sbi->iostat_lock);
|
||||
spin_lock_bh(&sbi->iostat_lock);
|
||||
sbi->rw_iostat[type] += io_bytes;
|
||||
|
||||
if (type == APP_WRITE_IO || type == APP_DIRECT_IO)
|
||||
sbi->rw_iostat[APP_BUFFERED_IO] =
|
||||
sbi->rw_iostat[APP_WRITE_IO] -
|
||||
sbi->rw_iostat[APP_DIRECT_IO];
|
||||
if (type == APP_BUFFERED_IO || type == APP_DIRECT_IO)
|
||||
sbi->rw_iostat[APP_WRITE_IO] += io_bytes;
|
||||
|
||||
if (type == APP_READ_IO || type == APP_DIRECT_READ_IO)
|
||||
sbi->rw_iostat[APP_BUFFERED_READ_IO] =
|
||||
sbi->rw_iostat[APP_READ_IO] -
|
||||
sbi->rw_iostat[APP_DIRECT_READ_IO];
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
if (type == APP_BUFFERED_READ_IO || type == APP_DIRECT_READ_IO)
|
||||
sbi->rw_iostat[APP_READ_IO] += io_bytes;
|
||||
|
||||
spin_unlock_bh(&sbi->iostat_lock);
|
||||
|
||||
f2fs_record_iostat(sbi);
|
||||
}
|
||||
|
|
@ -185,7 +182,6 @@ static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx,
|
|||
{
|
||||
unsigned long ts_diff;
|
||||
unsigned int iotype = iostat_ctx->type;
|
||||
unsigned long flags;
|
||||
struct f2fs_sb_info *sbi = iostat_ctx->sbi;
|
||||
struct iostat_lat_info *io_lat = sbi->iostat_io_lat;
|
||||
int idx;
|
||||
|
|
@ -206,12 +202,12 @@ static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx,
|
|||
idx = WRITE_ASYNC_IO;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sbi->iostat_lat_lock, flags);
|
||||
spin_lock_bh(&sbi->iostat_lat_lock);
|
||||
io_lat->sum_lat[idx][iotype] += ts_diff;
|
||||
io_lat->bio_cnt[idx][iotype]++;
|
||||
if (ts_diff > io_lat->peak_lat[idx][iotype])
|
||||
io_lat->peak_lat[idx][iotype] = ts_diff;
|
||||
spin_unlock_irqrestore(&sbi->iostat_lat_lock, flags);
|
||||
spin_unlock_bh(&sbi->iostat_lat_lock);
|
||||
}
|
||||
|
||||
void iostat_update_and_unbind_ctx(struct bio *bio, int rw)
|
||||
|
|
|
|||
|
|
@ -430,6 +430,10 @@ static void cache_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
|
|||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct nat_entry *new, *e;
|
||||
|
||||
/* Let's mitigate lock contention of nat_tree_lock during checkpoint */
|
||||
if (rwsem_is_locked(&sbi->cp_global_sem))
|
||||
return;
|
||||
|
||||
new = __alloc_nat_entry(sbi, nid, false);
|
||||
if (!new)
|
||||
return;
|
||||
|
|
@ -539,7 +543,7 @@ int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
|||
}
|
||||
|
||||
int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||
struct node_info *ni)
|
||||
struct node_info *ni, bool checkpoint_context)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
|
|
@ -572,9 +576,10 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
|||
* nat_tree_lock. Therefore, we should retry, if we failed to grab here
|
||||
* while not bothering checkpoint.
|
||||
*/
|
||||
if (!rwsem_is_locked(&sbi->cp_global_sem)) {
|
||||
if (!rwsem_is_locked(&sbi->cp_global_sem) || checkpoint_context) {
|
||||
down_read(&curseg->journal_rwsem);
|
||||
} else if (!down_read_trylock(&curseg->journal_rwsem)) {
|
||||
} else if (rwsem_is_contended(&nm_i->nat_tree_lock) ||
|
||||
!down_read_trylock(&curseg->journal_rwsem)) {
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
goto retry;
|
||||
}
|
||||
|
|
@ -887,7 +892,7 @@ static int truncate_node(struct dnode_of_data *dn)
|
|||
int err;
|
||||
pgoff_t index;
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1286,7 +1291,7 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
|
|||
goto fail;
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &new_ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &new_ni, false);
|
||||
if (err) {
|
||||
dec_valid_node_count(sbi, dn->inode, !ofs);
|
||||
goto fail;
|
||||
|
|
@ -1348,7 +1353,7 @@ static int read_node_page(struct page *page, int op_flags)
|
|||
return LOCKED_PAGE;
|
||||
}
|
||||
|
||||
err = f2fs_get_node_info(sbi, page->index, &ni);
|
||||
err = f2fs_get_node_info(sbi, page->index, &ni, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -1600,7 +1605,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
|||
nid = nid_of_node(page);
|
||||
f2fs_bug_on(sbi, page->index != nid);
|
||||
|
||||
if (f2fs_get_node_info(sbi, nid, &ni))
|
||||
if (f2fs_get_node_info(sbi, nid, &ni, !do_balance))
|
||||
goto redirty_out;
|
||||
|
||||
if (wbc->for_reclaim) {
|
||||
|
|
@ -2701,7 +2706,7 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page)
|
|||
goto recover_xnid;
|
||||
|
||||
/* 1: invalidate the previous xattr nid */
|
||||
err = f2fs_get_node_info(sbi, prev_xnid, &ni);
|
||||
err = f2fs_get_node_info(sbi, prev_xnid, &ni, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -2741,7 +2746,7 @@ int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
|||
struct page *ipage;
|
||||
int err;
|
||||
|
||||
err = f2fs_get_node_info(sbi, ino, &old_ni);
|
||||
err = f2fs_get_node_info(sbi, ino, &old_ni, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
|
|||
|
|
@ -596,7 +596,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
|||
|
||||
f2fs_wait_on_page_writeback(dn.node_page, NODE, true, true);
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni, false);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ static int __revoke_inmem_pages(struct inode *inode,
|
|||
goto next;
|
||||
}
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni, false);
|
||||
if (err) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -538,7 +538,8 @@ static inline unsigned int free_segments(struct f2fs_sb_info *sbi)
|
|||
|
||||
static inline unsigned int reserved_segments(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return SM_I(sbi)->reserved_segments;
|
||||
return SM_I(sbi)->reserved_segments +
|
||||
SM_I(sbi)->additional_reserved_segments;
|
||||
}
|
||||
|
||||
static inline unsigned int free_sections(struct f2fs_sb_info *sbi)
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
|
|||
[FAULT_WRITE_IO] = "write IO error",
|
||||
[FAULT_SLAB_ALLOC] = "slab alloc",
|
||||
[FAULT_DQUOT_INIT] = "dquot initialize",
|
||||
[FAULT_LOCK_OP] = "lock_op",
|
||||
};
|
||||
|
||||
void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
|
||||
|
|
@ -321,6 +322,46 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
|
|||
F2FS_OPTION(sbi).s_resgid));
|
||||
}
|
||||
|
||||
static inline int adjust_reserved_segment(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned int sec_blks = sbi->blocks_per_seg * sbi->segs_per_sec;
|
||||
unsigned int avg_vblocks;
|
||||
unsigned int wanted_reserved_segments;
|
||||
block_t avail_user_block_count;
|
||||
|
||||
if (!F2FS_IO_ALIGNED(sbi))
|
||||
return 0;
|
||||
|
||||
/* average valid block count in section in worst case */
|
||||
avg_vblocks = sec_blks / F2FS_IO_SIZE(sbi);
|
||||
|
||||
/*
|
||||
* we need enough free space when migrating one section in worst case
|
||||
*/
|
||||
wanted_reserved_segments = (F2FS_IO_SIZE(sbi) / avg_vblocks) *
|
||||
reserved_segments(sbi);
|
||||
wanted_reserved_segments -= reserved_segments(sbi);
|
||||
|
||||
avail_user_block_count = sbi->user_block_count -
|
||||
sbi->current_reserved_blocks -
|
||||
F2FS_OPTION(sbi).root_reserved_blocks;
|
||||
|
||||
if (wanted_reserved_segments * sbi->blocks_per_seg >
|
||||
avail_user_block_count) {
|
||||
f2fs_err(sbi, "IO align feature can't grab additional reserved segment: %u, available segments: %u",
|
||||
wanted_reserved_segments,
|
||||
avail_user_block_count >> sbi->log_blocks_per_seg);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
SM_I(sbi)->additional_reserved_segments = wanted_reserved_segments;
|
||||
|
||||
f2fs_info(sbi, "IO align feature needs additional reserved segment: %u",
|
||||
wanted_reserved_segments);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void adjust_unusable_cap_perc(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
if (!F2FS_OPTION(sbi).unusable_cap_perc)
|
||||
|
|
@ -3540,6 +3581,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
|||
sbi->seq_file_ra_mul = MIN_RA_MUL;
|
||||
sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
|
||||
sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
|
||||
spin_lock_init(&sbi->gc_urgent_high_lock);
|
||||
|
||||
sbi->dir_level = DEF_DIR_LEVEL;
|
||||
sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
|
||||
|
|
@ -4179,6 +4221,10 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
goto free_nm;
|
||||
}
|
||||
|
||||
err = adjust_reserved_segment(sbi);
|
||||
if (err)
|
||||
goto free_nm;
|
||||
|
||||
/* For write statistics */
|
||||
sbi->sectors_written_start = f2fs_get_sectors_written(sbi);
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,15 @@ static ssize_t sb_status_show(struct f2fs_attr *a,
|
|||
return sprintf(buf, "%lx\n", sbi->s_flag);
|
||||
}
|
||||
|
||||
static ssize_t pending_discard_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
if (!SM_I(sbi)->dcc_info)
|
||||
return -EINVAL;
|
||||
return sprintf(buf, "%llu\n", (unsigned long long)atomic_read(
|
||||
&SM_I(sbi)->dcc_info->discard_cmd_cnt));
|
||||
}
|
||||
|
||||
static ssize_t features_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
|
|
@ -414,7 +423,9 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
|
|||
if (a->struct_type == RESERVED_BLOCKS) {
|
||||
spin_lock(&sbi->stat_lock);
|
||||
if (t > (unsigned long)(sbi->user_block_count -
|
||||
F2FS_OPTION(sbi).root_reserved_blocks)) {
|
||||
F2FS_OPTION(sbi).root_reserved_blocks -
|
||||
sbi->blocks_per_seg *
|
||||
SM_I(sbi)->additional_reserved_segments)) {
|
||||
spin_unlock(&sbi->stat_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -477,6 +488,15 @@ static ssize_t __sbi_store(struct f2fs_attr *a,
|
|||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_urgent_high_remaining")) {
|
||||
spin_lock(&sbi->gc_urgent_high_lock);
|
||||
sbi->gc_urgent_high_limited = t != 0;
|
||||
sbi->gc_urgent_high_remaining = t;
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_IOSTAT
|
||||
if (!strcmp(a->attr.name, "iostat_enable")) {
|
||||
sbi->iostat_enable = !!t;
|
||||
|
|
@ -732,6 +752,7 @@ F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
|
|||
#endif
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, data_io_flag, data_io_flag);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, node_io_flag, node_io_flag);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent_high_remaining, gc_urgent_high_remaining);
|
||||
F2FS_RW_ATTR(CPRC_INFO, ckpt_req_control, ckpt_thread_ioprio, ckpt_thread_ioprio);
|
||||
F2FS_GENERAL_RO_ATTR(dirty_segments);
|
||||
F2FS_GENERAL_RO_ATTR(free_segments);
|
||||
|
|
@ -743,6 +764,7 @@ F2FS_GENERAL_RO_ATTR(unusable);
|
|||
F2FS_GENERAL_RO_ATTR(encoding);
|
||||
F2FS_GENERAL_RO_ATTR(mounted_time_sec);
|
||||
F2FS_GENERAL_RO_ATTR(main_blkaddr);
|
||||
F2FS_GENERAL_RO_ATTR(pending_discard);
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_foreground_calls, cp_count);
|
||||
F2FS_STAT_ATTR(STAT_INFO, f2fs_stat_info, cp_background_calls, bg_cp_count);
|
||||
|
|
@ -811,6 +833,7 @@ static struct attribute *f2fs_attrs[] = {
|
|||
ATTR_LIST(main_blkaddr),
|
||||
ATTR_LIST(max_small_discards),
|
||||
ATTR_LIST(discard_granularity),
|
||||
ATTR_LIST(pending_discard),
|
||||
ATTR_LIST(batched_trim_sections),
|
||||
ATTR_LIST(ipu_policy),
|
||||
ATTR_LIST(min_ipu_util),
|
||||
|
|
@ -843,6 +866,7 @@ static struct attribute *f2fs_attrs[] = {
|
|||
#endif
|
||||
ATTR_LIST(data_io_flag),
|
||||
ATTR_LIST(node_io_flag),
|
||||
ATTR_LIST(gc_urgent_high_remaining),
|
||||
ATTR_LIST(ckpt_thread_ioprio),
|
||||
ATTR_LIST(dirty_segments),
|
||||
ATTR_LIST(free_segments),
|
||||
|
|
|
|||
|
|
@ -226,15 +226,18 @@ static inline const struct xattr_handler *f2fs_xattr_handler(int index)
|
|||
}
|
||||
|
||||
static struct f2fs_xattr_entry *__find_xattr(void *base_addr,
|
||||
void *last_base_addr, int index,
|
||||
size_t len, const char *name)
|
||||
void *last_base_addr, void **last_addr,
|
||||
int index, size_t len, const char *name)
|
||||
{
|
||||
struct f2fs_xattr_entry *entry;
|
||||
|
||||
list_for_each_xattr(entry, base_addr) {
|
||||
if ((void *)(entry) + sizeof(__u32) > last_base_addr ||
|
||||
(void *)XATTR_NEXT_ENTRY(entry) > last_base_addr)
|
||||
(void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) {
|
||||
if (last_addr)
|
||||
*last_addr = entry;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (entry->e_name_index != index)
|
||||
continue;
|
||||
|
|
@ -254,19 +257,9 @@ static struct f2fs_xattr_entry *__find_inline_xattr(struct inode *inode,
|
|||
unsigned int inline_size = inline_xattr_size(inode);
|
||||
void *max_addr = base_addr + inline_size;
|
||||
|
||||
list_for_each_xattr(entry, base_addr) {
|
||||
if ((void *)entry + sizeof(__u32) > max_addr ||
|
||||
(void *)XATTR_NEXT_ENTRY(entry) > max_addr) {
|
||||
*last_addr = entry;
|
||||
return NULL;
|
||||
}
|
||||
if (entry->e_name_index != index)
|
||||
continue;
|
||||
if (entry->e_name_len != len)
|
||||
continue;
|
||||
if (!memcmp(entry->e_name, name, len))
|
||||
break;
|
||||
}
|
||||
entry = __find_xattr(base_addr, max_addr, last_addr, index, len, name);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
/* inline xattr header or entry across max inline xattr size */
|
||||
if (IS_XATTR_LAST_ENTRY(entry) &&
|
||||
|
|
@ -368,7 +361,7 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
|||
else
|
||||
cur_addr = txattr_addr;
|
||||
|
||||
*xe = __find_xattr(cur_addr, last_txattr_addr, index, len, name);
|
||||
*xe = __find_xattr(cur_addr, last_txattr_addr, NULL, index, len, name);
|
||||
if (!*xe) {
|
||||
f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
|
||||
inode->i_ino);
|
||||
|
|
@ -659,7 +652,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
|
|||
last_base_addr = (void *)base_addr + XATTR_SIZE(inode);
|
||||
|
||||
/* find entry with wanted name. */
|
||||
here = __find_xattr(base_addr, last_base_addr, index, len, name);
|
||||
here = __find_xattr(base_addr, last_base_addr, NULL, index, len, name);
|
||||
if (!here) {
|
||||
f2fs_err(F2FS_I_SB(inode), "inode (%lu) has corrupted xattr",
|
||||
inode->i_ino);
|
||||
|
|
@ -684,8 +677,17 @@ static int __f2fs_setxattr(struct inode *inode, int index,
|
|||
}
|
||||
|
||||
last = here;
|
||||
while (!IS_XATTR_LAST_ENTRY(last))
|
||||
while (!IS_XATTR_LAST_ENTRY(last)) {
|
||||
if ((void *)(last) + sizeof(__u32) > last_base_addr ||
|
||||
(void *)XATTR_NEXT_ENTRY(last) > last_base_addr) {
|
||||
f2fs_err(F2FS_I_SB(inode), "inode (%lu) has invalid last xattr entry, entry_size: %zu",
|
||||
inode->i_ino, ENTRY_SIZE(last));
|
||||
set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
|
||||
error = -EFSCORRUPTED;
|
||||
goto exit;
|
||||
}
|
||||
last = XATTR_NEXT_ENTRY(last);
|
||||
}
|
||||
|
||||
newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size);
|
||||
|
||||
|
|
|
|||
|
|
@ -936,14 +936,14 @@ TRACE_EVENT(f2fs_fallocate,
|
|||
|
||||
TRACE_EVENT(f2fs_direct_IO_enter,
|
||||
|
||||
TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw),
|
||||
TP_PROTO(struct inode *inode, struct kiocb *iocb, long len, int rw),
|
||||
|
||||
TP_ARGS(inode, offset, len, rw),
|
||||
TP_ARGS(inode, iocb, len, rw),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(ino_t, ino)
|
||||
__field(loff_t, pos)
|
||||
__field(struct kiocb *, iocb)
|
||||
__field(unsigned long, len)
|
||||
__field(int, rw)
|
||||
),
|
||||
|
|
@ -951,15 +951,18 @@ TRACE_EVENT(f2fs_direct_IO_enter,
|
|||
TP_fast_assign(
|
||||
__entry->dev = inode->i_sb->s_dev;
|
||||
__entry->ino = inode->i_ino;
|
||||
__entry->pos = offset;
|
||||
__entry->iocb = iocb;
|
||||
__entry->len = len;
|
||||
__entry->rw = rw;
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), ino = %lu pos = %lld len = %lu rw = %d",
|
||||
TP_printk("dev = (%d,%d), ino = %lu pos = %lld len = %lu ki_flags = %x ki_hint = %x ki_ioprio = %x rw = %d",
|
||||
show_dev_ino(__entry),
|
||||
__entry->pos,
|
||||
__entry->iocb->ki_pos,
|
||||
__entry->len,
|
||||
__entry->iocb->ki_flags,
|
||||
__entry->iocb->ki_hint,
|
||||
__entry->iocb->ki_ioprio,
|
||||
__entry->rw)
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user