forked from Minki/linux
f2fs-for-5.7-rc1
In this round, we've mainly focused on fixing bugs and addressing issues in recently introduced compression support. Enhancement: - add zstd support, and set LZ4 by default - add ioctl() to show # of compressed blocks - show mount time in debugfs - replace rwsem with spinlock - avoid lock contention in DIO reads Some major bug fixes wrt compression: - compressed block count - memory access and leak - remove obsolete fields - flag controls Other bug fixes and clean ups: - fix overflow when handling .flags in inode_info - fix SPO issue during resize FS flow - fix compression with fsverity enabled - potential deadlock when writing compressed pages - show missing mount options -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAl6L5f0ACgkQQBSofoJI UNImoQ/7BHKpwgpgH/DuydO9ess0XuUgQPQxyj+LE79l0jdBo8FxQZJVNAekx2+h ANTDHjsgqry6xuczOJXzFhECoOrCqZuffrkQM1p3owfzOH9Wrx6aiOomFBJyk/WB kXAY7LDPUwGF5uDB8tvVhM082qLXOlP0coO57f9Ip/OpaG8YOkti+KbcOKJrJ9o3 63IAzu89D/9XJw8834rDSersiEenSJm3jLC12uOxgXMzjDb1Ul1JH0P51gEu6g6O 3df5tiGJcFfaKVVWPHG+UEfav6mvi28+zU9f+dSmL0Wvb8dIqSgUf6ty8KCuRBYw kQYi+E0G1dcGi99AitCOrFxzY+oEo/A5wq2HDI6RkNlu6krD8qYNyWcMbP7dNHnU /5BVN+5d78iR1vKZpTo4X6dojf6B21Tn/OmABSZ5d7B6pI2fY5bjy2WgSLSY7YvP A6sepb9RAAGvpKvvkHI7gYwDKFMel+vfD6em1SKH5iKaDC0rJTUDUy8PTz/qMPBS vMn396dLx+TzTa0dZUuSF8NNk6sPZEReC3AuMNAIPSKiuD7tatRxvutHeEg5ktrr ggOQB67MfKjPMBKmgMIm6XMuILcCGIB1MqbPRlyKtC6rjdMPIKKOfeHJlLFmYwfF gqvCIFlW4DlxHpHH+LbUFKoUA3zofltL91SHUVATJjmiZIT2pqQ= =FVxq -----END PGP SIGNATURE----- Merge tag 'f2fs-for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs Pull f2fs updates from Jaegeuk Kim: "In this round, we've mainly focused on fixing bugs and addressing issues in recently introduced compression support. Enhancement: - add zstd support, and set LZ4 by default - add ioctl() to show # of compressed blocks - show mount time in debugfs - replace rwsem with spinlock - avoid lock contention in DIO reads Some major bug fixes wrt compression: - compressed block count - memory access and leak - remove obsolete fields - flag controls Other bug fixes and clean ups: - fix overflow when handling .flags in inode_info - fix SPO issue during resize FS flow - fix compression with fsverity enabled - potential deadlock when writing compressed pages - show missing mount options" * tag 'f2fs-for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (66 commits) f2fs: keep inline_data when compression conversion f2fs: fix to disable compression on directory f2fs: add missing CONFIG_F2FS_FS_COMPRESSION f2fs: switch discard_policy.timeout to bool type f2fs: fix to verify tpage before releasing in f2fs_free_dic() f2fs: show compression in statx f2fs: clean up dic->tpages assignment f2fs: compress: support zstd compress algorithm f2fs: compress: add .{init,destroy}_decompress_ctx callback f2fs: compress: fix to call missing destroy_compress_ctx() f2fs: change default compression algorithm f2fs: clean up {cic,dic}.ref handling f2fs: fix to use f2fs_readpage_limit() in f2fs_read_multi_pages() f2fs: xattr.h: Make stub helpers inline f2fs: fix to avoid double unlock f2fs: fix potential .flags overflow on 32bit architecture f2fs: fix NULL pointer dereference in f2fs_verity_work() f2fs: fix to clear PG_error if fsverity failed f2fs: don't call fscrypt_get_encryption_info() explicitly in f2fs_tmpfile() f2fs: don't trigger data flush in foreground operation ...
This commit is contained in:
commit
f40f31cadc
@ -318,3 +318,8 @@ Date: September 2019
|
||||
Contact: "Hridya Valsaraju" <hridya@google.com>
|
||||
Description: Average number of valid blocks.
|
||||
Available when CONFIG_F2FS_STAT_FS=y.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/mounted_time_sec
|
||||
Date: February 2020
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: Show the mounted time in secs of this partition.
|
||||
|
@ -243,8 +243,8 @@ checkpoint=%s[:%u[%]] Set to "disable" to turn off checkpointing. Set to "enabl
|
||||
hide up to all remaining free space. The actual space that
|
||||
would be unusable can be viewed at /sys/fs/f2fs/<disk>/unusable
|
||||
This space is reclaimed once checkpoint=enable.
|
||||
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo"
|
||||
and "lz4" algorithm.
|
||||
compress_algorithm=%s Control compress algorithm, currently f2fs supports "lzo",
|
||||
"lz4" and "zstd" algorithm.
|
||||
compress_log_size=%u Support configuring compress cluster size, the size will
|
||||
be 4KB * (1 << %u), 16KB is minimum size, also it's
|
||||
default size.
|
||||
|
@ -118,3 +118,12 @@ config F2FS_FS_LZ4
|
||||
default y
|
||||
help
|
||||
Support LZ4 compress algorithm, if unsure, say Y.
|
||||
|
||||
config F2FS_FS_ZSTD
|
||||
bool "ZSTD compression support"
|
||||
depends on F2FS_FS_COMPRESSION
|
||||
select ZSTD_COMPRESS
|
||||
select ZSTD_DECOMPRESS
|
||||
default y
|
||||
help
|
||||
Support ZSTD compress algorithm, if unsure, say Y.
|
||||
|
@ -50,9 +50,6 @@ repeat:
|
||||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
* We guarantee no failure on the returned page.
|
||||
*/
|
||||
static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
|
||||
bool is_meta)
|
||||
{
|
||||
@ -206,7 +203,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
|
||||
/*
|
||||
* Readahead CP/NAT/SIT/SSA pages
|
||||
* Readahead CP/NAT/SIT/SSA/POR pages
|
||||
*/
|
||||
int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int type, bool sync)
|
||||
@ -898,7 +895,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* Finding out valid cp block involves read both
|
||||
* sets( cp pack1 and cp pack 2)
|
||||
* sets( cp pack 1 and cp pack 2)
|
||||
*/
|
||||
cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr);
|
||||
cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version);
|
||||
@ -1250,20 +1247,20 @@ static void unblock_operations(struct f2fs_sb_info *sbi)
|
||||
f2fs_unlock_all(sbi);
|
||||
}
|
||||
|
||||
void f2fs_wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
|
||||
void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
|
||||
|
||||
if (!get_pages(sbi, F2FS_WB_CP_DATA))
|
||||
if (!get_pages(sbi, type))
|
||||
break;
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
break;
|
||||
|
||||
io_schedule_timeout(5*HZ);
|
||||
io_schedule_timeout(DEFAULT_IO_TIMEOUT);
|
||||
}
|
||||
finish_wait(&sbi->cp_wait, &wait);
|
||||
}
|
||||
@ -1301,10 +1298,14 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
else
|
||||
__clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) ||
|
||||
is_sbi_flag_set(sbi, SBI_IS_RESIZEFS))
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
||||
__set_ckpt_flags(ckpt, CP_FSCK_FLAG);
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_IS_RESIZEFS))
|
||||
__set_ckpt_flags(ckpt, CP_RESIZEFS_FLAG);
|
||||
else
|
||||
__clear_ckpt_flags(ckpt, CP_RESIZEFS_FLAG);
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
|
||||
__set_ckpt_flags(ckpt, CP_DISABLED_FLAG);
|
||||
else
|
||||
@ -1384,13 +1385,8 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* Flush all the NAT/SIT pages */
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) &&
|
||||
!f2fs_cp_error(sbi));
|
||||
|
||||
/*
|
||||
* modify checkpoint
|
||||
* version number is already updated
|
||||
*/
|
||||
/* start to update checkpoint, cp ver is already updated previously */
|
||||
ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true));
|
||||
ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
|
||||
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
|
||||
@ -1493,11 +1489,11 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* Here, we have one bio having CP pack except cp pack 2 page */
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_META) &&
|
||||
!f2fs_cp_error(sbi));
|
||||
/* Wait for all dirty meta pages to be submitted for IO */
|
||||
f2fs_wait_on_all_pages(sbi, F2FS_DIRTY_META);
|
||||
|
||||
/* wait for previous submitted meta pages writeback */
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
|
||||
|
||||
/* flush all device cache */
|
||||
err = f2fs_flush_device_cache(sbi);
|
||||
@ -1506,7 +1502,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* barrier and flush checkpoint cp pack 2 page if it can */
|
||||
commit_checkpoint(sbi, ckpt, start_blk);
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
|
||||
|
||||
/*
|
||||
* invalidate intermediate page cache borrowed from meta inode which are
|
||||
@ -1543,9 +1539,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We guarantee that this checkpoint procedure will not fail.
|
||||
*/
|
||||
int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
{
|
||||
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
|
||||
@ -1613,7 +1606,6 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
f2fs_flush_sit_entries(sbi, cpc);
|
||||
|
||||
/* unlock all the fs_lock[] in do_checkpoint() */
|
||||
err = do_checkpoint(sbi, cpc);
|
||||
if (err)
|
||||
f2fs_release_discard_addrs(sbi);
|
||||
@ -1626,7 +1618,7 @@ stop:
|
||||
if (cpc->reason & CP_RECOVERY)
|
||||
f2fs_notice(sbi, "checkpoint: version = %llx", ckpt_ver);
|
||||
|
||||
/* do checkpoint periodically */
|
||||
/* update CP_TIME to trigger checkpoint periodically */
|
||||
f2fs_update_time(sbi, CP_TIME);
|
||||
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
|
||||
out:
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/lzo.h>
|
||||
#include <linux/lz4.h>
|
||||
#include <linux/zstd.h>
|
||||
|
||||
#include "f2fs.h"
|
||||
#include "node.h"
|
||||
@ -20,6 +21,8 @@ struct f2fs_compress_ops {
|
||||
int (*init_compress_ctx)(struct compress_ctx *cc);
|
||||
void (*destroy_compress_ctx)(struct compress_ctx *cc);
|
||||
int (*compress_pages)(struct compress_ctx *cc);
|
||||
int (*init_decompress_ctx)(struct decompress_io_ctx *dic);
|
||||
void (*destroy_decompress_ctx)(struct decompress_io_ctx *dic);
|
||||
int (*decompress_pages)(struct decompress_io_ctx *dic);
|
||||
};
|
||||
|
||||
@ -52,7 +55,7 @@ bool f2fs_is_compressed_page(struct page *page)
|
||||
}
|
||||
|
||||
static void f2fs_set_compressed_page(struct page *page,
|
||||
struct inode *inode, pgoff_t index, void *data, refcount_t *r)
|
||||
struct inode *inode, pgoff_t index, void *data)
|
||||
{
|
||||
SetPagePrivate(page);
|
||||
set_page_private(page, (unsigned long)data);
|
||||
@ -60,8 +63,6 @@ static void f2fs_set_compressed_page(struct page *page,
|
||||
/* i_crypto_info and iv index */
|
||||
page->index = index;
|
||||
page->mapping = inode->i_mapping;
|
||||
if (r)
|
||||
refcount_inc(r);
|
||||
}
|
||||
|
||||
static void f2fs_put_compressed_page(struct page *page)
|
||||
@ -291,6 +292,165 @@ static const struct f2fs_compress_ops f2fs_lz4_ops = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_ZSTD
|
||||
#define F2FS_ZSTD_DEFAULT_CLEVEL 1
|
||||
|
||||
static int zstd_init_compress_ctx(struct compress_ctx *cc)
|
||||
{
|
||||
ZSTD_parameters params;
|
||||
ZSTD_CStream *stream;
|
||||
void *workspace;
|
||||
unsigned int workspace_size;
|
||||
|
||||
params = ZSTD_getParams(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen, 0);
|
||||
workspace_size = ZSTD_CStreamWorkspaceBound(params.cParams);
|
||||
|
||||
workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode),
|
||||
workspace_size, GFP_NOFS);
|
||||
if (!workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
stream = ZSTD_initCStream(params, 0, workspace, workspace_size);
|
||||
if (!stream) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initCStream failed\n",
|
||||
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||
__func__);
|
||||
kvfree(workspace);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cc->private = workspace;
|
||||
cc->private2 = stream;
|
||||
|
||||
cc->clen = cc->rlen - PAGE_SIZE - COMPRESS_HEADER_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zstd_destroy_compress_ctx(struct compress_ctx *cc)
|
||||
{
|
||||
kvfree(cc->private);
|
||||
cc->private = NULL;
|
||||
cc->private2 = NULL;
|
||||
}
|
||||
|
||||
static int zstd_compress_pages(struct compress_ctx *cc)
|
||||
{
|
||||
ZSTD_CStream *stream = cc->private2;
|
||||
ZSTD_inBuffer inbuf;
|
||||
ZSTD_outBuffer outbuf;
|
||||
int src_size = cc->rlen;
|
||||
int dst_size = src_size - PAGE_SIZE - COMPRESS_HEADER_SIZE;
|
||||
int ret;
|
||||
|
||||
inbuf.pos = 0;
|
||||
inbuf.src = cc->rbuf;
|
||||
inbuf.size = src_size;
|
||||
|
||||
outbuf.pos = 0;
|
||||
outbuf.dst = cc->cbuf->cdata;
|
||||
outbuf.size = dst_size;
|
||||
|
||||
ret = ZSTD_compressStream(stream, &outbuf, &inbuf);
|
||||
if (ZSTD_isError(ret)) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
|
||||
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||
__func__, ZSTD_getErrorCode(ret));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = ZSTD_endStream(stream, &outbuf);
|
||||
if (ZSTD_isError(ret)) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_endStream returned %d\n",
|
||||
KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id,
|
||||
__func__, ZSTD_getErrorCode(ret));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cc->clen = outbuf.pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
|
||||
{
|
||||
ZSTD_DStream *stream;
|
||||
void *workspace;
|
||||
unsigned int workspace_size;
|
||||
|
||||
workspace_size = ZSTD_DStreamWorkspaceBound(MAX_COMPRESS_WINDOW_SIZE);
|
||||
|
||||
workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode),
|
||||
workspace_size, GFP_NOFS);
|
||||
if (!workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
stream = ZSTD_initDStream(MAX_COMPRESS_WINDOW_SIZE,
|
||||
workspace, workspace_size);
|
||||
if (!stream) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_initDStream failed\n",
|
||||
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
|
||||
__func__);
|
||||
kvfree(workspace);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
dic->private = workspace;
|
||||
dic->private2 = stream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zstd_destroy_decompress_ctx(struct decompress_io_ctx *dic)
|
||||
{
|
||||
kvfree(dic->private);
|
||||
dic->private = NULL;
|
||||
dic->private2 = NULL;
|
||||
}
|
||||
|
||||
static int zstd_decompress_pages(struct decompress_io_ctx *dic)
|
||||
{
|
||||
ZSTD_DStream *stream = dic->private2;
|
||||
ZSTD_inBuffer inbuf;
|
||||
ZSTD_outBuffer outbuf;
|
||||
int ret;
|
||||
|
||||
inbuf.pos = 0;
|
||||
inbuf.src = dic->cbuf->cdata;
|
||||
inbuf.size = dic->clen;
|
||||
|
||||
outbuf.pos = 0;
|
||||
outbuf.dst = dic->rbuf;
|
||||
outbuf.size = dic->rlen;
|
||||
|
||||
ret = ZSTD_decompressStream(stream, &outbuf, &inbuf);
|
||||
if (ZSTD_isError(ret)) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD_compressStream failed, ret: %d\n",
|
||||
KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id,
|
||||
__func__, ZSTD_getErrorCode(ret));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (dic->rlen != outbuf.pos) {
|
||||
printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, "
|
||||
"expected:%lu\n", KERN_ERR,
|
||||
F2FS_I_SB(dic->inode)->sb->s_id,
|
||||
__func__, dic->rlen,
|
||||
PAGE_SIZE << dic->log_cluster_size);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct f2fs_compress_ops f2fs_zstd_ops = {
|
||||
.init_compress_ctx = zstd_init_compress_ctx,
|
||||
.destroy_compress_ctx = zstd_destroy_compress_ctx,
|
||||
.compress_pages = zstd_compress_pages,
|
||||
.init_decompress_ctx = zstd_init_decompress_ctx,
|
||||
.destroy_decompress_ctx = zstd_destroy_decompress_ctx,
|
||||
.decompress_pages = zstd_decompress_pages,
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
|
||||
#ifdef CONFIG_F2FS_FS_LZO
|
||||
&f2fs_lzo_ops,
|
||||
@ -302,6 +462,11 @@ static const struct f2fs_compress_ops *f2fs_cops[COMPRESS_MAX] = {
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_F2FS_FS_ZSTD
|
||||
&f2fs_zstd_ops,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
bool f2fs_is_compress_backend_ready(struct inode *inode)
|
||||
@ -334,9 +499,11 @@ static int f2fs_compress_pages(struct compress_ctx *cc)
|
||||
trace_f2fs_compress_pages_start(cc->inode, cc->cluster_idx,
|
||||
cc->cluster_size, fi->i_compress_algorithm);
|
||||
|
||||
ret = cops->init_compress_ctx(cc);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (cops->init_compress_ctx) {
|
||||
ret = cops->init_compress_ctx(cc);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
max_len = COMPRESS_HEADER_SIZE + cc->clen;
|
||||
cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE);
|
||||
@ -380,21 +547,27 @@ static int f2fs_compress_pages(struct compress_ctx *cc)
|
||||
}
|
||||
|
||||
cc->cbuf->clen = cpu_to_le32(cc->clen);
|
||||
cc->cbuf->chksum = cpu_to_le32(0);
|
||||
|
||||
for (i = 0; i < COMPRESS_DATA_RESERVED_SIZE; i++)
|
||||
cc->cbuf->reserved[i] = cpu_to_le32(0);
|
||||
|
||||
nr_cpages = DIV_ROUND_UP(cc->clen + COMPRESS_HEADER_SIZE, PAGE_SIZE);
|
||||
|
||||
/* zero out any unused part of the last page */
|
||||
memset(&cc->cbuf->cdata[cc->clen], 0,
|
||||
(nr_cpages * PAGE_SIZE) - (cc->clen + COMPRESS_HEADER_SIZE));
|
||||
|
||||
vunmap(cc->cbuf);
|
||||
vunmap(cc->rbuf);
|
||||
|
||||
nr_cpages = DIV_ROUND_UP(cc->clen + COMPRESS_HEADER_SIZE, PAGE_SIZE);
|
||||
|
||||
for (i = nr_cpages; i < cc->nr_cpages; i++) {
|
||||
f2fs_put_compressed_page(cc->cpages[i]);
|
||||
cc->cpages[i] = NULL;
|
||||
}
|
||||
|
||||
if (cops->destroy_compress_ctx)
|
||||
cops->destroy_compress_ctx(cc);
|
||||
|
||||
cc->nr_cpages = nr_cpages;
|
||||
|
||||
trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx,
|
||||
@ -413,7 +586,8 @@ out_free_cpages:
|
||||
kfree(cc->cpages);
|
||||
cc->cpages = NULL;
|
||||
destroy_compress_ctx:
|
||||
cops->destroy_compress_ctx(cc);
|
||||
if (cops->destroy_compress_ctx)
|
||||
cops->destroy_compress_ctx(cc);
|
||||
out:
|
||||
trace_f2fs_compress_pages_end(cc->inode, cc->cluster_idx,
|
||||
cc->clen, ret);
|
||||
@ -447,10 +621,16 @@ void f2fs_decompress_pages(struct bio *bio, struct page *page, bool verity)
|
||||
goto out_free_dic;
|
||||
}
|
||||
|
||||
if (cops->init_decompress_ctx) {
|
||||
ret = cops->init_decompress_ctx(dic);
|
||||
if (ret)
|
||||
goto out_free_dic;
|
||||
}
|
||||
|
||||
dic->rbuf = vmap(dic->tpages, dic->cluster_size, VM_MAP, PAGE_KERNEL);
|
||||
if (!dic->rbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_dic;
|
||||
goto destroy_decompress_ctx;
|
||||
}
|
||||
|
||||
dic->cbuf = vmap(dic->cpages, dic->nr_cpages, VM_MAP, PAGE_KERNEL_RO);
|
||||
@ -473,7 +653,12 @@ out_vunmap_cbuf:
|
||||
vunmap(dic->cbuf);
|
||||
out_vunmap_rbuf:
|
||||
vunmap(dic->rbuf);
|
||||
destroy_decompress_ctx:
|
||||
if (cops->destroy_decompress_ctx)
|
||||
cops->destroy_decompress_ctx(dic);
|
||||
out_free_dic:
|
||||
if (verity)
|
||||
refcount_set(&dic->ref, dic->nr_cpages);
|
||||
if (!verity)
|
||||
f2fs_decompress_end_io(dic->rpages, dic->cluster_size,
|
||||
ret, false);
|
||||
@ -532,8 +717,7 @@ static bool __cluster_may_compress(struct compress_ctx *cc)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* return # of compressed block addresses */
|
||||
static int f2fs_compressed_blocks(struct compress_ctx *cc)
|
||||
static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
|
||||
{
|
||||
struct dnode_of_data dn;
|
||||
int ret;
|
||||
@ -554,10 +738,15 @@ static int f2fs_compressed_blocks(struct compress_ctx *cc)
|
||||
for (i = 1; i < cc->cluster_size; i++) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode,
|
||||
blkaddr = data_blkaddr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node + i);
|
||||
if (blkaddr != NULL_ADDR)
|
||||
ret++;
|
||||
if (compr) {
|
||||
if (__is_valid_data_blkaddr(blkaddr))
|
||||
ret++;
|
||||
} else {
|
||||
if (blkaddr != NULL_ADDR)
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fail:
|
||||
@ -565,6 +754,18 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return # of compressed blocks in compressed cluster */
|
||||
static int f2fs_compressed_blocks(struct compress_ctx *cc)
|
||||
{
|
||||
return __f2fs_cluster_blocks(cc, true);
|
||||
}
|
||||
|
||||
/* return # of valid blocks in compressed cluster */
|
||||
static int f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
|
||||
{
|
||||
return __f2fs_cluster_blocks(cc, false);
|
||||
}
|
||||
|
||||
int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
|
||||
{
|
||||
struct compress_ctx cc = {
|
||||
@ -574,7 +775,7 @@ int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
|
||||
.cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size,
|
||||
};
|
||||
|
||||
return f2fs_compressed_blocks(&cc);
|
||||
return f2fs_cluster_blocks(&cc, false);
|
||||
}
|
||||
|
||||
static bool cluster_may_compress(struct compress_ctx *cc)
|
||||
@ -623,7 +824,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
|
||||
bool prealloc;
|
||||
|
||||
retry:
|
||||
ret = f2fs_compressed_blocks(cc);
|
||||
ret = f2fs_cluster_blocks(cc, false);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
@ -653,7 +854,7 @@ retry:
|
||||
struct bio *bio = NULL;
|
||||
|
||||
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
|
||||
&last_block_in_bio, false);
|
||||
&last_block_in_bio, false, true);
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
if (ret)
|
||||
goto release_pages;
|
||||
@ -772,7 +973,6 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
.encrypted_page = NULL,
|
||||
.compressed_page = NULL,
|
||||
.submitted = false,
|
||||
.need_lock = LOCK_RETRY,
|
||||
.io_type = io_type,
|
||||
.io_wbc = wbc,
|
||||
.encrypted = f2fs_encrypted_file(cc->inode),
|
||||
@ -785,16 +985,17 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
loff_t psize;
|
||||
int i, err;
|
||||
|
||||
set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
|
||||
if (!f2fs_trylock_op(sbi))
|
||||
return -EAGAIN;
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
|
||||
|
||||
err = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE);
|
||||
if (err)
|
||||
goto out_unlock_op;
|
||||
|
||||
for (i = 0; i < cc->cluster_size; i++) {
|
||||
if (datablock_addr(dn.inode, dn.node_page,
|
||||
if (data_blkaddr(dn.inode, dn.node_page,
|
||||
dn.ofs_in_node + i) == NULL_ADDR)
|
||||
goto out_put_dnode;
|
||||
}
|
||||
@ -813,7 +1014,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
|
||||
cic->magic = F2FS_COMPRESSED_PAGE_MAGIC;
|
||||
cic->inode = inode;
|
||||
refcount_set(&cic->ref, 1);
|
||||
refcount_set(&cic->ref, cc->nr_cpages);
|
||||
cic->rpages = f2fs_kzalloc(sbi, sizeof(struct page *) <<
|
||||
cc->log_cluster_size, GFP_NOFS);
|
||||
if (!cic->rpages)
|
||||
@ -823,8 +1024,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
|
||||
for (i = 0; i < cc->nr_cpages; i++) {
|
||||
f2fs_set_compressed_page(cc->cpages[i], inode,
|
||||
cc->rpages[i + 1]->index,
|
||||
cic, i ? &cic->ref : NULL);
|
||||
cc->rpages[i + 1]->index, cic);
|
||||
fio.compressed_page = cc->cpages[i];
|
||||
if (fio.encrypted) {
|
||||
fio.page = cc->rpages[i + 1];
|
||||
@ -843,9 +1043,8 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
for (i = 0; i < cc->cluster_size; i++, dn.ofs_in_node++) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page,
|
||||
dn.ofs_in_node);
|
||||
fio.page = cic->rpages[i];
|
||||
blkaddr = f2fs_data_blkaddr(&dn);
|
||||
fio.page = cc->rpages[i];
|
||||
fio.old_blkaddr = blkaddr;
|
||||
|
||||
/* cluster header */
|
||||
@ -895,10 +1094,10 @@ unlock_continue:
|
||||
f2fs_put_dnode(&dn);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
down_write(&fi->i_sem);
|
||||
spin_lock(&fi->i_size_lock);
|
||||
if (fi->last_disk_size < psize)
|
||||
fi->last_disk_size = psize;
|
||||
up_write(&fi->i_sem);
|
||||
spin_unlock(&fi->i_size_lock);
|
||||
|
||||
f2fs_put_rpages(cc);
|
||||
f2fs_destroy_compress_ctx(cc);
|
||||
@ -984,24 +1183,30 @@ retry_write:
|
||||
unlock_page(cc->rpages[i]);
|
||||
ret = 0;
|
||||
} else if (ret == -EAGAIN) {
|
||||
/*
|
||||
* for quota file, just redirty left pages to
|
||||
* avoid deadlock caused by cluster update race
|
||||
* from foreground operation.
|
||||
*/
|
||||
if (IS_NOQUOTA(cc->inode)) {
|
||||
err = 0;
|
||||
goto out_err;
|
||||
}
|
||||
ret = 0;
|
||||
cond_resched();
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
lock_page(cc->rpages[i]);
|
||||
clear_page_dirty_for_io(cc->rpages[i]);
|
||||
goto retry_write;
|
||||
}
|
||||
err = ret;
|
||||
goto out_fail;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
*submitted += _submitted;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_fail:
|
||||
/* TODO: revoke partially updated block addresses */
|
||||
BUG_ON(compr_blocks);
|
||||
out_err:
|
||||
for (++i; i < cc->cluster_size; i++) {
|
||||
if (!cc->rpages[i])
|
||||
@ -1069,7 +1274,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
|
||||
|
||||
dic->magic = F2FS_COMPRESSED_PAGE_MAGIC;
|
||||
dic->inode = cc->inode;
|
||||
refcount_set(&dic->ref, 1);
|
||||
refcount_set(&dic->ref, cc->nr_cpages);
|
||||
dic->cluster_idx = cc->cluster_idx;
|
||||
dic->cluster_size = cc->cluster_size;
|
||||
dic->log_cluster_size = cc->log_cluster_size;
|
||||
@ -1093,8 +1298,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
|
||||
goto out_free;
|
||||
|
||||
f2fs_set_compressed_page(page, cc->inode,
|
||||
start_idx + i + 1,
|
||||
dic, i ? &dic->ref : NULL);
|
||||
start_idx + i + 1, dic);
|
||||
dic->cpages[i] = page;
|
||||
}
|
||||
|
||||
@ -1104,20 +1308,16 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
|
||||
goto out_free;
|
||||
|
||||
for (i = 0; i < dic->cluster_size; i++) {
|
||||
if (cc->rpages[i])
|
||||
if (cc->rpages[i]) {
|
||||
dic->tpages[i] = cc->rpages[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
dic->tpages[i] = f2fs_grab_page();
|
||||
if (!dic->tpages[i])
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
for (i = 0; i < dic->cluster_size; i++) {
|
||||
if (dic->tpages[i])
|
||||
continue;
|
||||
dic->tpages[i] = cc->rpages[i];
|
||||
}
|
||||
|
||||
return dic;
|
||||
|
||||
out_free:
|
||||
@ -1133,7 +1333,10 @@ void f2fs_free_dic(struct decompress_io_ctx *dic)
|
||||
for (i = 0; i < dic->cluster_size; i++) {
|
||||
if (dic->rpages[i])
|
||||
continue;
|
||||
f2fs_put_page(dic->tpages[i], 1);
|
||||
if (!dic->tpages[i])
|
||||
continue;
|
||||
unlock_page(dic->tpages[i]);
|
||||
put_page(dic->tpages[i]);
|
||||
}
|
||||
kfree(dic->tpages);
|
||||
}
|
||||
@ -1162,15 +1365,17 @@ void f2fs_decompress_end_io(struct page **rpages,
|
||||
if (!rpage)
|
||||
continue;
|
||||
|
||||
if (err || PageError(rpage)) {
|
||||
ClearPageUptodate(rpage);
|
||||
ClearPageError(rpage);
|
||||
} else {
|
||||
if (!verity || fsverity_verify_page(rpage))
|
||||
SetPageUptodate(rpage);
|
||||
else
|
||||
SetPageError(rpage);
|
||||
if (err || PageError(rpage))
|
||||
goto clear_uptodate;
|
||||
|
||||
if (!verity || fsverity_verify_page(rpage)) {
|
||||
SetPageUptodate(rpage);
|
||||
goto unlock;
|
||||
}
|
||||
clear_uptodate:
|
||||
ClearPageUptodate(rpage);
|
||||
ClearPageError(rpage);
|
||||
unlock:
|
||||
unlock_page(rpage);
|
||||
}
|
||||
}
|
||||
|
143
fs/f2fs/data.c
143
fs/f2fs/data.c
@ -54,17 +54,13 @@ static inline struct bio *__f2fs_bio_alloc(gfp_t gfp_mask,
|
||||
return bio_alloc_bioset(gfp_mask, nr_iovecs, &f2fs_bioset);
|
||||
}
|
||||
|
||||
struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool no_fail)
|
||||
struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool noio)
|
||||
{
|
||||
struct bio *bio;
|
||||
|
||||
if (no_fail) {
|
||||
if (noio) {
|
||||
/* No failure on bio allocation */
|
||||
bio = __f2fs_bio_alloc(GFP_NOIO, npages);
|
||||
if (!bio)
|
||||
bio = __f2fs_bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages);
|
||||
return bio;
|
||||
return __f2fs_bio_alloc(GFP_NOIO, npages);
|
||||
}
|
||||
|
||||
if (time_to_inject(sbi, FAULT_ALLOC_BIO)) {
|
||||
f2fs_show_injection_info(sbi, FAULT_ALLOC_BIO);
|
||||
return NULL;
|
||||
@ -143,6 +139,8 @@ static void __read_end_io(struct bio *bio, bool compr, bool verity)
|
||||
f2fs_decompress_pages(bio, page, verity);
|
||||
continue;
|
||||
}
|
||||
if (verity)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* PG_error was set if any post_read step failed */
|
||||
@ -191,12 +189,38 @@ static void f2fs_verify_pages(struct page **rpages, unsigned int cluster_size)
|
||||
|
||||
static void f2fs_verify_bio(struct bio *bio)
|
||||
{
|
||||
struct page *page = bio_first_page_all(bio);
|
||||
struct decompress_io_ctx *dic =
|
||||
(struct decompress_io_ctx *)page_private(page);
|
||||
struct bio_vec *bv;
|
||||
struct bvec_iter_all iter_all;
|
||||
|
||||
f2fs_verify_pages(dic->rpages, dic->cluster_size);
|
||||
f2fs_free_dic(dic);
|
||||
bio_for_each_segment_all(bv, bio, iter_all) {
|
||||
struct page *page = bv->bv_page;
|
||||
struct decompress_io_ctx *dic;
|
||||
|
||||
dic = (struct decompress_io_ctx *)page_private(page);
|
||||
|
||||
if (dic) {
|
||||
if (refcount_dec_not_one(&dic->ref))
|
||||
continue;
|
||||
f2fs_verify_pages(dic->rpages,
|
||||
dic->cluster_size);
|
||||
f2fs_free_dic(dic);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bio->bi_status || PageError(page))
|
||||
goto clear_uptodate;
|
||||
|
||||
if (fsverity_verify_page(page)) {
|
||||
SetPageUptodate(page);
|
||||
goto unlock;
|
||||
}
|
||||
clear_uptodate:
|
||||
ClearPageUptodate(page);
|
||||
ClearPageError(page);
|
||||
unlock:
|
||||
dec_page_count(F2FS_P_SB(page), __read_io_type(page));
|
||||
unlock_page(page);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -364,9 +388,6 @@ static void f2fs_write_end_io(struct bio *bio)
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true, if pre_bio's bdev is same as its target device.
|
||||
*/
|
||||
struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
|
||||
block_t blk_addr, struct bio *bio)
|
||||
{
|
||||
@ -403,6 +424,9 @@ int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true, if pre_bio's bdev is same as its target device.
|
||||
*/
|
||||
static bool __same_bdev(struct f2fs_sb_info *sbi,
|
||||
block_t blk_addr, struct bio *bio)
|
||||
{
|
||||
@ -410,9 +434,6 @@ static bool __same_bdev(struct f2fs_sb_info *sbi,
|
||||
return bio->bi_disk == b->bd_disk && bio->bi_partno == b->bd_partno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Low-level block read/write IO operations.
|
||||
*/
|
||||
static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
@ -445,7 +466,7 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
|
||||
if (type != DATA && type != NODE)
|
||||
goto submit_io;
|
||||
|
||||
if (test_opt(sbi, LFS) && current->plug)
|
||||
if (f2fs_lfs_mode(sbi) && current->plug)
|
||||
blk_finish_plug(current->plug);
|
||||
|
||||
if (F2FS_IO_ALIGNED(sbi))
|
||||
@ -928,14 +949,15 @@ static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx)
|
||||
|
||||
static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
|
||||
unsigned nr_pages, unsigned op_flag,
|
||||
pgoff_t first_idx)
|
||||
pgoff_t first_idx, bool for_write)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct bio *bio;
|
||||
struct bio_post_read_ctx *ctx;
|
||||
unsigned int post_read_steps = 0;
|
||||
|
||||
bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
|
||||
bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES),
|
||||
for_write);
|
||||
if (!bio)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
f2fs_target_device(sbi, blkaddr, bio);
|
||||
@ -970,12 +992,12 @@ static void f2fs_release_read_bio(struct bio *bio)
|
||||
|
||||
/* This can handle encryption stuffs */
|
||||
static int f2fs_submit_page_read(struct inode *inode, struct page *page,
|
||||
block_t blkaddr)
|
||||
block_t blkaddr, bool for_write)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct bio *bio;
|
||||
|
||||
bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index);
|
||||
bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0, page->index, for_write);
|
||||
if (IS_ERR(bio))
|
||||
return PTR_ERR(bio);
|
||||
|
||||
@ -1047,8 +1069,7 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
|
||||
f2fs_wait_on_page_writeback(dn->node_page, NODE, true, true);
|
||||
|
||||
for (; count > 0; dn->ofs_in_node++) {
|
||||
block_t blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
block_t blkaddr = f2fs_data_blkaddr(dn);
|
||||
if (blkaddr == NULL_ADDR) {
|
||||
dn->data_blkaddr = NEW_ADDR;
|
||||
__set_data_blkaddr(dn);
|
||||
@ -1162,7 +1183,7 @@ got_it:
|
||||
return page;
|
||||
}
|
||||
|
||||
err = f2fs_submit_page_read(inode, page, dn.data_blkaddr);
|
||||
err = f2fs_submit_page_read(inode, page, dn.data_blkaddr, for_write);
|
||||
if (err)
|
||||
goto put_err;
|
||||
return page;
|
||||
@ -1300,8 +1321,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dn->data_blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
dn->data_blkaddr = f2fs_data_blkaddr(dn);
|
||||
if (dn->data_blkaddr != NULL_ADDR)
|
||||
goto alloc;
|
||||
|
||||
@ -1388,13 +1408,9 @@ void __do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock)
|
||||
}
|
||||
|
||||
/*
|
||||
* f2fs_map_blocks() now supported readahead/bmap/rw direct_IO with
|
||||
* f2fs_map_blocks structure.
|
||||
* If original data blocks are allocated, then give them to blockdev.
|
||||
* Otherwise,
|
||||
* a. preallocate requested block addresses
|
||||
* b. do not use extent cache for better performance
|
||||
* c. give the block addresses to blockdev
|
||||
* f2fs_map_blocks() tries to find or build mapping relationship which
|
||||
* maps continuous logical blocks to physical blocks, and return such
|
||||
* info via f2fs_map_blocks structure.
|
||||
*/
|
||||
int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
int create, int flag)
|
||||
@ -1422,7 +1438,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
end = pgofs + maxblocks;
|
||||
|
||||
if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
|
||||
if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
|
||||
if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO &&
|
||||
map->m_may_create)
|
||||
goto next_dnode;
|
||||
|
||||
@ -1467,7 +1483,7 @@ next_dnode:
|
||||
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
||||
|
||||
next_block:
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
|
||||
blkaddr = f2fs_data_blkaddr(&dn);
|
||||
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
|
||||
@ -1477,7 +1493,7 @@ next_block:
|
||||
|
||||
if (__is_valid_data_blkaddr(blkaddr)) {
|
||||
/* use out-place-update for driect IO under LFS mode */
|
||||
if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
|
||||
if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO &&
|
||||
map->m_may_create) {
|
||||
err = __allocate_data_block(&dn, map->m_seg_type);
|
||||
if (err)
|
||||
@ -1980,7 +1996,8 @@ submit_and_realloc:
|
||||
}
|
||||
if (bio == NULL) {
|
||||
bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
|
||||
is_readahead ? REQ_RAHEAD : 0, page->index);
|
||||
is_readahead ? REQ_RAHEAD : 0, page->index,
|
||||
false);
|
||||
if (IS_ERR(bio)) {
|
||||
ret = PTR_ERR(bio);
|
||||
bio = NULL;
|
||||
@ -2015,7 +2032,7 @@ out:
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
unsigned nr_pages, sector_t *last_block_in_bio,
|
||||
bool is_readahead)
|
||||
bool is_readahead, bool for_write)
|
||||
{
|
||||
struct dnode_of_data dn;
|
||||
struct inode *inode = cc->inode;
|
||||
@ -2031,7 +2048,8 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
|
||||
f2fs_bug_on(sbi, f2fs_cluster_is_empty(cc));
|
||||
|
||||
last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
|
||||
last_block_in_file = (f2fs_readpage_limit(inode) +
|
||||
blocksize - 1) >> blkbits;
|
||||
|
||||
/* get rid of pages beyond EOF */
|
||||
for (i = 0; i < cc->cluster_size; i++) {
|
||||
@ -2067,7 +2085,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
for (i = 1; i < cc->cluster_size; i++) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page,
|
||||
blkaddr = data_blkaddr(dn.inode, dn.node_page,
|
||||
dn.ofs_in_node + i);
|
||||
|
||||
if (!__is_valid_data_blkaddr(blkaddr))
|
||||
@ -2096,7 +2114,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
struct page *page = dic->cpages[i];
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page,
|
||||
blkaddr = data_blkaddr(dn.inode, dn.node_page,
|
||||
dn.ofs_in_node + i + 1);
|
||||
|
||||
if (bio && !page_is_mergeable(sbi, bio,
|
||||
@ -2109,7 +2127,7 @@ submit_and_realloc:
|
||||
if (!bio) {
|
||||
bio = f2fs_grab_read_bio(inode, blkaddr, nr_pages,
|
||||
is_readahead ? REQ_RAHEAD : 0,
|
||||
page->index);
|
||||
page->index, for_write);
|
||||
if (IS_ERR(bio)) {
|
||||
ret = PTR_ERR(bio);
|
||||
bio = NULL;
|
||||
@ -2210,7 +2228,7 @@ int f2fs_mpage_readpages(struct address_space *mapping,
|
||||
ret = f2fs_read_multi_pages(&cc, &bio,
|
||||
max_nr_pages,
|
||||
&last_block_in_bio,
|
||||
is_readahead);
|
||||
is_readahead, false);
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
if (ret)
|
||||
goto set_error_page;
|
||||
@ -2253,7 +2271,7 @@ next_page:
|
||||
ret = f2fs_read_multi_pages(&cc, &bio,
|
||||
max_nr_pages,
|
||||
&last_block_in_bio,
|
||||
is_readahead);
|
||||
is_readahead, false);
|
||||
f2fs_destroy_compress_ctx(&cc);
|
||||
}
|
||||
}
|
||||
@ -2326,7 +2344,7 @@ retry_encrypt:
|
||||
/* flush pending IOs and wait for a while in the ENOMEM case */
|
||||
if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
|
||||
f2fs_flush_merged_writes(fio->sbi);
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
gfp_flags |= __GFP_NOFAIL;
|
||||
goto retry_encrypt;
|
||||
}
|
||||
@ -2397,7 +2415,7 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
if (f2fs_lfs_mode(sbi))
|
||||
return true;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
return true;
|
||||
@ -2647,10 +2665,10 @@ write:
|
||||
if (err) {
|
||||
file_set_keep_isize(inode);
|
||||
} else {
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
spin_lock(&F2FS_I(inode)->i_size_lock);
|
||||
if (F2FS_I(inode)->last_disk_size < psize)
|
||||
F2FS_I(inode)->last_disk_size = psize;
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
spin_unlock(&F2FS_I(inode)->i_size_lock);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -2917,7 +2935,7 @@ result:
|
||||
if (wbc->sync_mode == WB_SYNC_ALL) {
|
||||
cond_resched();
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
HZ/50);
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
goto retry_write;
|
||||
}
|
||||
goto next;
|
||||
@ -2973,15 +2991,17 @@ next:
|
||||
static inline bool __should_serialize_io(struct inode *inode,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return false;
|
||||
if (f2fs_compressed_file(inode))
|
||||
return true;
|
||||
if (IS_NOQUOTA(inode))
|
||||
return false;
|
||||
/* to avoid deadlock in path of data flush */
|
||||
if (F2FS_I(inode)->cp_task)
|
||||
return false;
|
||||
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return false;
|
||||
if (IS_NOQUOTA(inode))
|
||||
return false;
|
||||
|
||||
if (f2fs_compressed_file(inode))
|
||||
return true;
|
||||
if (wbc->sync_mode != WB_SYNC_ALL)
|
||||
return true;
|
||||
if (get_dirty_pages(inode) >= SM_I(F2FS_I_SB(inode))->min_seq_blocks)
|
||||
@ -3283,7 +3303,7 @@ repeat:
|
||||
err = -EFSCORRUPTED;
|
||||
goto fail;
|
||||
}
|
||||
err = f2fs_submit_page_read(inode, page, blkaddr);
|
||||
err = f2fs_submit_page_read(inode, page, blkaddr, true);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
@ -3464,7 +3484,8 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
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,
|
||||
DIO_LOCKING | DIO_SKIP_HOLES);
|
||||
rw == WRITE ? DIO_LOCKING | DIO_SKIP_HOLES :
|
||||
DIO_SKIP_HOLES);
|
||||
|
||||
if (do_opu)
|
||||
up_read(&fi->i_gc_rwsem[READ]);
|
||||
@ -3861,7 +3882,7 @@ void f2fs_destroy_post_read_wq(struct f2fs_sb_info *sbi)
|
||||
|
||||
int __init f2fs_init_bio_entry_cache(void)
|
||||
{
|
||||
bio_entry_slab = f2fs_kmem_cache_create("bio_entry_slab",
|
||||
bio_entry_slab = f2fs_kmem_cache_create("f2fs_bio_entry_slab",
|
||||
sizeof(struct bio_entry));
|
||||
if (!bio_entry_slab)
|
||||
return -ENOMEM;
|
||||
|
@ -301,6 +301,9 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->ssa_area_segs, si->main_area_segs);
|
||||
seq_printf(s, "(OverProv:%d Resv:%d)]\n\n",
|
||||
si->overp_segs, si->rsvd_segs);
|
||||
seq_printf(s, "Current Time Sec: %llu / Mounted Time Sec: %llu\n\n",
|
||||
ktime_get_boottime_seconds(),
|
||||
SIT_I(si->sbi)->mounted_time);
|
||||
if (test_opt(si->sbi, DISCARD))
|
||||
seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n",
|
||||
si->utilization, si->valid_count, si->discard_blks);
|
||||
|
@ -471,7 +471,6 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
struct page *dpage)
|
||||
{
|
||||
struct page *page;
|
||||
int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir));
|
||||
int err;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_NEW_INODE)) {
|
||||
@ -498,8 +497,7 @@ struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
if (err)
|
||||
goto put_error;
|
||||
|
||||
if ((IS_ENCRYPTED(dir) || dummy_encrypt) &&
|
||||
f2fs_may_encrypt(inode)) {
|
||||
if (IS_ENCRYPTED(inode)) {
|
||||
err = fscrypt_inherit_context(dir, inode, page, false);
|
||||
if (err)
|
||||
goto put_error;
|
||||
@ -850,12 +848,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
0);
|
||||
set_page_dirty(page);
|
||||
|
||||
dir->i_ctime = dir->i_mtime = current_time(dir);
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
|
||||
if (bit_pos == NR_DENTRY_IN_BLOCK &&
|
||||
!f2fs_truncate_hole(dir, page->index, page->index + 1)) {
|
||||
f2fs_clear_page_cache_dirty_tag(page);
|
||||
@ -867,6 +859,12 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
f2fs_remove_dirty_inode(dir);
|
||||
}
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
dir->i_ctime = dir->i_mtime = current_time(dir);
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
}
|
||||
|
||||
bool f2fs_empty_dir(struct inode *dir)
|
||||
|
206
fs/f2fs/f2fs.h
206
fs/f2fs/f2fs.h
@ -75,7 +75,6 @@ extern const char *f2fs_fault_name[FAULT_MAX];
|
||||
/*
|
||||
* For mount options
|
||||
*/
|
||||
#define F2FS_MOUNT_BG_GC 0x00000001
|
||||
#define F2FS_MOUNT_DISABLE_ROLL_FORWARD 0x00000002
|
||||
#define F2FS_MOUNT_DISCARD 0x00000004
|
||||
#define F2FS_MOUNT_NOHEAP 0x00000008
|
||||
@ -89,11 +88,8 @@ extern const char *f2fs_fault_name[FAULT_MAX];
|
||||
#define F2FS_MOUNT_NOBARRIER 0x00000800
|
||||
#define F2FS_MOUNT_FASTBOOT 0x00001000
|
||||
#define F2FS_MOUNT_EXTENT_CACHE 0x00002000
|
||||
#define F2FS_MOUNT_FORCE_FG_GC 0x00004000
|
||||
#define F2FS_MOUNT_DATA_FLUSH 0x00008000
|
||||
#define F2FS_MOUNT_FAULT_INJECTION 0x00010000
|
||||
#define F2FS_MOUNT_ADAPTIVE 0x00020000
|
||||
#define F2FS_MOUNT_LFS 0x00040000
|
||||
#define F2FS_MOUNT_USRQUOTA 0x00080000
|
||||
#define F2FS_MOUNT_GRPQUOTA 0x00100000
|
||||
#define F2FS_MOUNT_PRJQUOTA 0x00200000
|
||||
@ -101,6 +97,7 @@ extern const char *f2fs_fault_name[FAULT_MAX];
|
||||
#define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000
|
||||
#define F2FS_MOUNT_RESERVE_ROOT 0x01000000
|
||||
#define F2FS_MOUNT_DISABLE_CHECKPOINT 0x02000000
|
||||
#define F2FS_MOUNT_NORECOVERY 0x04000000
|
||||
|
||||
#define F2FS_OPTION(sbi) ((sbi)->mount_opt)
|
||||
#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
|
||||
@ -139,6 +136,8 @@ struct f2fs_mount_info {
|
||||
int whint_mode;
|
||||
int alloc_mode; /* segment allocation policy */
|
||||
int fsync_mode; /* fsync policy */
|
||||
int fs_mode; /* fs mode: LFS or ADAPTIVE */
|
||||
int bggc_mode; /* bggc mode: off, on or sync */
|
||||
bool test_dummy_encryption; /* test dummy encryption */
|
||||
block_t unusable_cap; /* Amount of space allowed to be
|
||||
* unusable when disabling checkpoint
|
||||
@ -332,8 +331,8 @@ struct discard_policy {
|
||||
bool io_aware; /* issue discard in idle time */
|
||||
bool sync; /* submit discard with REQ_SYNC flag */
|
||||
bool ordered; /* issue discard by lba order */
|
||||
bool timeout; /* discard timeout for put_super */
|
||||
unsigned int granularity; /* discard granularity */
|
||||
int timeout; /* discard timeout for put_super */
|
||||
};
|
||||
|
||||
struct discard_cmd_control {
|
||||
@ -428,6 +427,7 @@ static inline bool __has_cursum_space(struct f2fs_journal *journal,
|
||||
#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
|
||||
#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15)
|
||||
#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, __u64)
|
||||
#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, __u64)
|
||||
|
||||
#define F2FS_IOC_GET_VOLUME_NAME FS_IOC_GETFSLABEL
|
||||
#define F2FS_IOC_SET_VOLUME_NAME FS_IOC_SETFSLABEL
|
||||
@ -560,6 +560,9 @@ enum {
|
||||
|
||||
#define DEFAULT_RETRY_IO_COUNT 8 /* maximum retry read IO count */
|
||||
|
||||
/* congestion wait timeout value, default: 20ms */
|
||||
#define DEFAULT_IO_TIMEOUT (msecs_to_jiffies(20))
|
||||
|
||||
/* maximum retry quota flush count */
|
||||
#define DEFAULT_RETRY_QUOTA_FLUSH_COUNT 8
|
||||
|
||||
@ -676,6 +679,44 @@ enum {
|
||||
MAX_GC_FAILURE
|
||||
};
|
||||
|
||||
/* used for f2fs_inode_info->flags */
|
||||
enum {
|
||||
FI_NEW_INODE, /* indicate newly allocated inode */
|
||||
FI_DIRTY_INODE, /* indicate inode is dirty or not */
|
||||
FI_AUTO_RECOVER, /* indicate inode is recoverable */
|
||||
FI_DIRTY_DIR, /* indicate directory has dirty pages */
|
||||
FI_INC_LINK, /* need to increment i_nlink */
|
||||
FI_ACL_MODE, /* indicate acl mode */
|
||||
FI_NO_ALLOC, /* should not allocate any blocks */
|
||||
FI_FREE_NID, /* free allocated nide */
|
||||
FI_NO_EXTENT, /* not to use the extent cache */
|
||||
FI_INLINE_XATTR, /* used for inline xattr */
|
||||
FI_INLINE_DATA, /* used for inline data*/
|
||||
FI_INLINE_DENTRY, /* used for inline dentry */
|
||||
FI_APPEND_WRITE, /* inode has appended data */
|
||||
FI_UPDATE_WRITE, /* inode has in-place-update data */
|
||||
FI_NEED_IPU, /* used for ipu per file */
|
||||
FI_ATOMIC_FILE, /* indicate atomic file */
|
||||
FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */
|
||||
FI_VOLATILE_FILE, /* indicate volatile file */
|
||||
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
|
||||
FI_DROP_CACHE, /* drop dirty page cache */
|
||||
FI_DATA_EXIST, /* indicate data exists */
|
||||
FI_INLINE_DOTS, /* indicate inline dot dentries */
|
||||
FI_DO_DEFRAG, /* indicate defragment is running */
|
||||
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
|
||||
FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
|
||||
FI_HOT_DATA, /* indicate file is hot */
|
||||
FI_EXTRA_ATTR, /* indicate file has extra attribute */
|
||||
FI_PROJ_INHERIT, /* indicate file inherits projectid */
|
||||
FI_PIN_FILE, /* indicate file should not be gced */
|
||||
FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */
|
||||
FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */
|
||||
FI_COMPRESSED_FILE, /* indicate file's data can be compressed */
|
||||
FI_MMAP_FILE, /* indicate file was mmapped */
|
||||
FI_MAX, /* max flag, never be used */
|
||||
};
|
||||
|
||||
struct f2fs_inode_info {
|
||||
struct inode vfs_inode; /* serve a vfs inode */
|
||||
unsigned long i_flags; /* keep an inode flags for ioctl */
|
||||
@ -688,7 +729,7 @@ struct f2fs_inode_info {
|
||||
umode_t i_acl_mode; /* keep file acl mode temporarily */
|
||||
|
||||
/* Use below internally in f2fs*/
|
||||
unsigned long flags; /* use to pass per-file flags */
|
||||
unsigned long flags[BITS_TO_LONGS(FI_MAX)]; /* use to pass per-file flags */
|
||||
struct rw_semaphore i_sem; /* protect fi info */
|
||||
atomic_t dirty_pages; /* # of dirty pages */
|
||||
f2fs_hash_t chash; /* hash value of given file name */
|
||||
@ -697,6 +738,7 @@ struct f2fs_inode_info {
|
||||
struct task_struct *cp_task; /* separate cp/wb IO stats*/
|
||||
nid_t i_xattr_nid; /* node id that contains xattrs */
|
||||
loff_t last_disk_size; /* lastly written file size */
|
||||
spinlock_t i_size_lock; /* protect last_disk_size */
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
struct dquot *i_dquot[MAXQUOTAS];
|
||||
@ -1172,6 +1214,20 @@ enum {
|
||||
GC_URGENT,
|
||||
};
|
||||
|
||||
enum {
|
||||
BGGC_MODE_ON, /* background gc is on */
|
||||
BGGC_MODE_OFF, /* background gc is off */
|
||||
BGGC_MODE_SYNC, /*
|
||||
* background gc is on, migrating blocks
|
||||
* like foreground gc
|
||||
*/
|
||||
};
|
||||
|
||||
enum {
|
||||
FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
|
||||
FS_MODE_LFS, /* use lfs allocation only */
|
||||
};
|
||||
|
||||
enum {
|
||||
WHINT_MODE_OFF, /* not pass down write hints */
|
||||
WHINT_MODE_USER, /* try to pass down hints given by users */
|
||||
@ -1212,13 +1268,13 @@ enum fsync_mode {
|
||||
enum compress_algorithm_type {
|
||||
COMPRESS_LZO,
|
||||
COMPRESS_LZ4,
|
||||
COMPRESS_ZSTD,
|
||||
COMPRESS_MAX,
|
||||
};
|
||||
|
||||
#define COMPRESS_DATA_RESERVED_SIZE 4
|
||||
#define COMPRESS_DATA_RESERVED_SIZE 5
|
||||
struct compress_data {
|
||||
__le32 clen; /* compressed data size */
|
||||
__le32 chksum; /* checksum of compressed data */
|
||||
__le32 reserved[COMPRESS_DATA_RESERVED_SIZE]; /* reserved */
|
||||
u8 cdata[]; /* compressed data */
|
||||
};
|
||||
@ -1242,6 +1298,7 @@ struct compress_ctx {
|
||||
size_t rlen; /* valid data length in rbuf */
|
||||
size_t clen; /* valid data length in cbuf */
|
||||
void *private; /* payload buffer for specified compression algorithm */
|
||||
void *private2; /* extra payload buffer */
|
||||
};
|
||||
|
||||
/* compress context for write IO path */
|
||||
@ -1271,11 +1328,14 @@ struct decompress_io_ctx {
|
||||
size_t clen; /* valid data length in cbuf */
|
||||
refcount_t ref; /* referrence count of compressed page */
|
||||
bool failed; /* indicate IO error during decompression */
|
||||
void *private; /* payload buffer for specified decompression algorithm */
|
||||
void *private2; /* extra payload buffer */
|
||||
};
|
||||
|
||||
#define NULL_CLUSTER ((unsigned int)(~0))
|
||||
#define MIN_COMPRESS_LOG_SIZE 2
|
||||
#define MAX_COMPRESS_LOG_SIZE 8
|
||||
#define MAX_COMPRESS_WINDOW_SIZE ((PAGE_SIZE) << MAX_COMPRESS_LOG_SIZE)
|
||||
|
||||
struct f2fs_sb_info {
|
||||
struct super_block *sb; /* pointer to VFS super block */
|
||||
@ -1471,6 +1531,9 @@ struct f2fs_sb_info {
|
||||
__u32 s_chksum_seed;
|
||||
|
||||
struct workqueue_struct *post_read_wq; /* post read workqueue */
|
||||
|
||||
struct kmem_cache *inline_xattr_slab; /* inline xattr entry */
|
||||
unsigned int inline_xattr_slab_size; /* default inline xattr slab size */
|
||||
};
|
||||
|
||||
struct f2fs_private_dio {
|
||||
@ -2211,7 +2274,7 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
|
||||
dquot_free_inode(inode);
|
||||
} else {
|
||||
if (unlikely(inode->i_blocks == 0)) {
|
||||
f2fs_warn(sbi, "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
|
||||
f2fs_warn(sbi, "dec_valid_node_count: inconsistent i_blocks, ino:%lu, iblocks:%llu",
|
||||
inode->i_ino,
|
||||
(unsigned long long)inode->i_blocks);
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
@ -2379,7 +2442,7 @@ static inline __le32 *blkaddr_in_node(struct f2fs_node *node)
|
||||
}
|
||||
|
||||
static inline int f2fs_has_extra_attr(struct inode *inode);
|
||||
static inline block_t datablock_addr(struct inode *inode,
|
||||
static inline block_t data_blkaddr(struct inode *inode,
|
||||
struct page *node_page, unsigned int offset)
|
||||
{
|
||||
struct f2fs_node *raw_node;
|
||||
@ -2389,9 +2452,9 @@ static inline block_t datablock_addr(struct inode *inode,
|
||||
|
||||
raw_node = F2FS_NODE(node_page);
|
||||
|
||||
/* from GC path only */
|
||||
if (is_inode) {
|
||||
if (!inode)
|
||||
/* from GC path only */
|
||||
base = offset_in_addr(&raw_node->i);
|
||||
else if (f2fs_has_extra_attr(inode))
|
||||
base = get_extra_isize(inode);
|
||||
@ -2401,6 +2464,11 @@ static inline block_t datablock_addr(struct inode *inode,
|
||||
return le32_to_cpu(addr_array[base + offset]);
|
||||
}
|
||||
|
||||
static inline block_t f2fs_data_blkaddr(struct dnode_of_data *dn)
|
||||
{
|
||||
return data_blkaddr(dn->inode, dn->node_page, dn->ofs_in_node);
|
||||
}
|
||||
|
||||
static inline int f2fs_test_bit(unsigned int nr, char *addr)
|
||||
{
|
||||
int mask;
|
||||
@ -2498,43 +2566,6 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
|
||||
return flags & F2FS_OTHER_FLMASK;
|
||||
}
|
||||
|
||||
/* used for f2fs_inode_info->flags */
|
||||
enum {
|
||||
FI_NEW_INODE, /* indicate newly allocated inode */
|
||||
FI_DIRTY_INODE, /* indicate inode is dirty or not */
|
||||
FI_AUTO_RECOVER, /* indicate inode is recoverable */
|
||||
FI_DIRTY_DIR, /* indicate directory has dirty pages */
|
||||
FI_INC_LINK, /* need to increment i_nlink */
|
||||
FI_ACL_MODE, /* indicate acl mode */
|
||||
FI_NO_ALLOC, /* should not allocate any blocks */
|
||||
FI_FREE_NID, /* free allocated nide */
|
||||
FI_NO_EXTENT, /* not to use the extent cache */
|
||||
FI_INLINE_XATTR, /* used for inline xattr */
|
||||
FI_INLINE_DATA, /* used for inline data*/
|
||||
FI_INLINE_DENTRY, /* used for inline dentry */
|
||||
FI_APPEND_WRITE, /* inode has appended data */
|
||||
FI_UPDATE_WRITE, /* inode has in-place-update data */
|
||||
FI_NEED_IPU, /* used for ipu per file */
|
||||
FI_ATOMIC_FILE, /* indicate atomic file */
|
||||
FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */
|
||||
FI_VOLATILE_FILE, /* indicate volatile file */
|
||||
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
|
||||
FI_DROP_CACHE, /* drop dirty page cache */
|
||||
FI_DATA_EXIST, /* indicate data exists */
|
||||
FI_INLINE_DOTS, /* indicate inline dot dentries */
|
||||
FI_DO_DEFRAG, /* indicate defragment is running */
|
||||
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
|
||||
FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
|
||||
FI_HOT_DATA, /* indicate file is hot */
|
||||
FI_EXTRA_ATTR, /* indicate file has extra attribute */
|
||||
FI_PROJ_INHERIT, /* indicate file inherits projectid */
|
||||
FI_PIN_FILE, /* indicate file should not be gced */
|
||||
FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */
|
||||
FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */
|
||||
FI_COMPRESSED_FILE, /* indicate file's data can be compressed */
|
||||
FI_MMAP_FILE, /* indicate file was mmapped */
|
||||
};
|
||||
|
||||
static inline void __mark_inode_dirty_flag(struct inode *inode,
|
||||
int flag, bool set)
|
||||
{
|
||||
@ -2549,27 +2580,24 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
|
||||
case FI_DATA_EXIST:
|
||||
case FI_INLINE_DOTS:
|
||||
case FI_PIN_FILE:
|
||||
case FI_COMPRESSED_FILE:
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_inode_flag(struct inode *inode, int flag)
|
||||
{
|
||||
if (!test_bit(flag, &F2FS_I(inode)->flags))
|
||||
set_bit(flag, &F2FS_I(inode)->flags);
|
||||
test_and_set_bit(flag, F2FS_I(inode)->flags);
|
||||
__mark_inode_dirty_flag(inode, flag, true);
|
||||
}
|
||||
|
||||
static inline int is_inode_flag_set(struct inode *inode, int flag)
|
||||
{
|
||||
return test_bit(flag, &F2FS_I(inode)->flags);
|
||||
return test_bit(flag, F2FS_I(inode)->flags);
|
||||
}
|
||||
|
||||
static inline void clear_inode_flag(struct inode *inode, int flag)
|
||||
{
|
||||
if (test_bit(flag, &F2FS_I(inode)->flags))
|
||||
clear_bit(flag, &F2FS_I(inode)->flags);
|
||||
test_and_clear_bit(flag, F2FS_I(inode)->flags);
|
||||
__mark_inode_dirty_flag(inode, flag, false);
|
||||
}
|
||||
|
||||
@ -2660,19 +2688,19 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
|
||||
if (ri->i_inline & F2FS_INLINE_XATTR)
|
||||
set_bit(FI_INLINE_XATTR, &fi->flags);
|
||||
set_bit(FI_INLINE_XATTR, fi->flags);
|
||||
if (ri->i_inline & F2FS_INLINE_DATA)
|
||||
set_bit(FI_INLINE_DATA, &fi->flags);
|
||||
set_bit(FI_INLINE_DATA, fi->flags);
|
||||
if (ri->i_inline & F2FS_INLINE_DENTRY)
|
||||
set_bit(FI_INLINE_DENTRY, &fi->flags);
|
||||
set_bit(FI_INLINE_DENTRY, fi->flags);
|
||||
if (ri->i_inline & F2FS_DATA_EXIST)
|
||||
set_bit(FI_DATA_EXIST, &fi->flags);
|
||||
set_bit(FI_DATA_EXIST, fi->flags);
|
||||
if (ri->i_inline & F2FS_INLINE_DOTS)
|
||||
set_bit(FI_INLINE_DOTS, &fi->flags);
|
||||
set_bit(FI_INLINE_DOTS, fi->flags);
|
||||
if (ri->i_inline & F2FS_EXTRA_ATTR)
|
||||
set_bit(FI_EXTRA_ATTR, &fi->flags);
|
||||
set_bit(FI_EXTRA_ATTR, fi->flags);
|
||||
if (ri->i_inline & F2FS_PIN_FILE)
|
||||
set_bit(FI_PIN_FILE, &fi->flags);
|
||||
set_bit(FI_PIN_FILE, fi->flags);
|
||||
}
|
||||
|
||||
static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
|
||||
@ -2857,9 +2885,9 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync)
|
||||
if (!f2fs_is_time_consistent(inode))
|
||||
return false;
|
||||
|
||||
down_read(&F2FS_I(inode)->i_sem);
|
||||
spin_lock(&F2FS_I(inode)->i_size_lock);
|
||||
ret = F2FS_I(inode)->last_disk_size == i_size_read(inode);
|
||||
up_read(&F2FS_I(inode)->i_sem);
|
||||
spin_unlock(&F2FS_I(inode)->i_size_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -3213,7 +3241,7 @@ void f2fs_drop_inmem_pages(struct inode *inode);
|
||||
void f2fs_drop_inmem_page(struct inode *inode, struct page *page);
|
||||
int f2fs_commit_inmem_pages(struct inode *inode);
|
||||
void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need);
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi);
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg);
|
||||
int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi);
|
||||
int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);
|
||||
@ -3309,7 +3337,7 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi);
|
||||
void f2fs_update_dirty_page(struct inode *inode, struct page *page);
|
||||
void f2fs_remove_dirty_inode(struct inode *inode);
|
||||
int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type);
|
||||
void f2fs_wait_on_all_pages_writeback(struct f2fs_sb_info *sbi);
|
||||
void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type);
|
||||
int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_checkpoint_caches(void);
|
||||
@ -3320,7 +3348,7 @@ void f2fs_destroy_checkpoint_caches(void);
|
||||
*/
|
||||
int __init f2fs_init_bioset(void);
|
||||
void f2fs_destroy_bioset(void);
|
||||
struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool no_fail);
|
||||
struct bio *f2fs_bio_alloc(struct f2fs_sb_info *sbi, int npages, bool noio);
|
||||
int f2fs_init_bio_entry_cache(void);
|
||||
void f2fs_destroy_bio_entry_cache(void);
|
||||
void f2fs_submit_bio(struct f2fs_sb_info *sbi,
|
||||
@ -3776,7 +3804,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
|
||||
int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index);
|
||||
int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
unsigned nr_pages, sector_t *last_block_in_bio,
|
||||
bool is_readahead);
|
||||
bool is_readahead, bool for_write);
|
||||
struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
|
||||
void f2fs_free_dic(struct decompress_io_ctx *dic);
|
||||
void f2fs_decompress_end_io(struct page **rpages,
|
||||
@ -3813,6 +3841,7 @@ static inline void set_compress_context(struct inode *inode)
|
||||
F2FS_I(inode)->i_flags |= F2FS_COMPR_FL;
|
||||
set_inode_flag(inode, FI_COMPRESSED_FILE);
|
||||
stat_inc_compr_inode(inode);
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
|
||||
static inline u64 f2fs_disable_compressed_file(struct inode *inode)
|
||||
@ -3821,12 +3850,17 @@ static inline u64 f2fs_disable_compressed_file(struct inode *inode)
|
||||
|
||||
if (!f2fs_compressed_file(inode))
|
||||
return 0;
|
||||
if (fi->i_compr_blocks)
|
||||
return fi->i_compr_blocks;
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (get_dirty_pages(inode))
|
||||
return 1;
|
||||
if (fi->i_compr_blocks)
|
||||
return fi->i_compr_blocks;
|
||||
}
|
||||
|
||||
fi->i_flags &= ~F2FS_COMPR_FL;
|
||||
clear_inode_flag(inode, FI_COMPRESSED_FILE);
|
||||
stat_dec_compr_inode(inode);
|
||||
clear_inode_flag(inode, FI_COMPRESSED_FILE);
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3903,31 +3937,25 @@ static inline bool f2fs_hw_is_readonly(struct f2fs_sb_info *sbi)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
|
||||
static inline bool f2fs_lfs_mode(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
clear_opt(sbi, ADAPTIVE);
|
||||
clear_opt(sbi, LFS);
|
||||
|
||||
switch (mt) {
|
||||
case F2FS_MOUNT_ADAPTIVE:
|
||||
set_opt(sbi, ADAPTIVE);
|
||||
break;
|
||||
case F2FS_MOUNT_LFS:
|
||||
set_opt(sbi, LFS);
|
||||
break;
|
||||
}
|
||||
return F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS;
|
||||
}
|
||||
|
||||
static inline bool f2fs_may_encrypt(struct inode *inode)
|
||||
static inline bool f2fs_may_encrypt(struct inode *dir, struct inode *inode)
|
||||
{
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
umode_t mode = inode->i_mode;
|
||||
|
||||
return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode));
|
||||
#else
|
||||
return false;
|
||||
/*
|
||||
* If the directory encrypted or dummy encryption enabled,
|
||||
* then we should encrypt the inode.
|
||||
*/
|
||||
if (IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi))
|
||||
return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode));
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool f2fs_may_compress(struct inode *inode)
|
||||
@ -3971,7 +3999,7 @@ static inline int allow_outplace_dio(struct inode *inode,
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
int rw = iov_iter_rw(iter);
|
||||
|
||||
return (test_opt(sbi, LFS) && (rw == WRITE) &&
|
||||
return (f2fs_lfs_mode(sbi) && (rw == WRITE) &&
|
||||
!block_unaligned_IO(inode, iocb, iter));
|
||||
}
|
||||
|
||||
@ -3993,7 +4021,7 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
|
||||
*/
|
||||
if (f2fs_sb_has_blkzoned(sbi))
|
||||
return true;
|
||||
if (test_opt(sbi, LFS) && (rw == WRITE)) {
|
||||
if (f2fs_lfs_mode(sbi) && (rw == WRITE)) {
|
||||
if (block_unaligned_IO(inode, iocb, iter))
|
||||
return true;
|
||||
if (F2FS_IO_ALIGNED(sbi))
|
||||
|
@ -106,13 +106,20 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
err = f2fs_get_block(&dn, page->index);
|
||||
f2fs_put_dnode(&dn);
|
||||
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
|
||||
if (err) {
|
||||
unlock_page(page);
|
||||
goto out_sem;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the page */
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
if (!need_alloc) {
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
|
||||
f2fs_put_dnode(&dn);
|
||||
}
|
||||
#endif
|
||||
if (err) {
|
||||
unlock_page(page);
|
||||
goto out_sem;
|
||||
}
|
||||
|
||||
f2fs_wait_on_page_writeback(page, DATA, false, true);
|
||||
|
||||
/* wait for GCed page writeback via META_MAPPING */
|
||||
@ -448,8 +455,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
|
||||
data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
blkaddr = f2fs_data_blkaddr(&dn);
|
||||
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
|
||||
@ -793,6 +799,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
|
||||
}
|
||||
|
||||
flags = fi->i_flags;
|
||||
if (flags & F2FS_COMPR_FL)
|
||||
stat->attributes |= STATX_ATTR_COMPRESSED;
|
||||
if (flags & F2FS_APPEND_FL)
|
||||
stat->attributes |= STATX_ATTR_APPEND;
|
||||
if (IS_ENCRYPTED(inode))
|
||||
@ -804,7 +812,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
|
||||
if (IS_VERITY(inode))
|
||||
stat->attributes |= STATX_ATTR_VERITY;
|
||||
|
||||
stat->attributes_mask |= (STATX_ATTR_APPEND |
|
||||
stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
|
||||
STATX_ATTR_APPEND |
|
||||
STATX_ATTR_ENCRYPTED |
|
||||
STATX_ATTR_IMMUTABLE |
|
||||
STATX_ATTR_NODUMP |
|
||||
@ -929,10 +938,10 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
spin_lock(&F2FS_I(inode)->i_size_lock);
|
||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
F2FS_I(inode)->last_disk_size = i_size_read(inode);
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
spin_unlock(&F2FS_I(inode)->i_size_lock);
|
||||
}
|
||||
|
||||
__setattr_copy(inode, attr);
|
||||
@ -1109,8 +1118,7 @@ next_dnode:
|
||||
done = min((pgoff_t)ADDRS_PER_PAGE(dn.node_page, inode) -
|
||||
dn.ofs_in_node, len);
|
||||
for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
|
||||
*blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
*blkaddr = f2fs_data_blkaddr(&dn);
|
||||
|
||||
if (__is_valid_data_blkaddr(*blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, *blkaddr,
|
||||
@ -1121,7 +1129,7 @@ next_dnode:
|
||||
|
||||
if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
|
||||
|
||||
if (test_opt(sbi, LFS)) {
|
||||
if (f2fs_lfs_mode(sbi)) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@ -1199,8 +1207,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
ADDRS_PER_PAGE(dn.node_page, dst_inode) -
|
||||
dn.ofs_in_node, len - i);
|
||||
do {
|
||||
dn.data_blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
dn.data_blkaddr = f2fs_data_blkaddr(&dn);
|
||||
f2fs_truncate_data_blocks_range(&dn, 1);
|
||||
|
||||
if (do_replace[i]) {
|
||||
@ -1376,8 +1383,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
int ret;
|
||||
|
||||
for (; index < end; index++, dn->ofs_in_node++) {
|
||||
if (datablock_addr(dn->inode, dn->node_page,
|
||||
dn->ofs_in_node) == NULL_ADDR)
|
||||
if (f2fs_data_blkaddr(dn) == NULL_ADDR)
|
||||
count++;
|
||||
}
|
||||
|
||||
@ -1388,8 +1394,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
|
||||
dn->ofs_in_node = ofs_in_node;
|
||||
for (index = start; index < end; index++, dn->ofs_in_node++) {
|
||||
dn->data_blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
dn->data_blkaddr = f2fs_data_blkaddr(dn);
|
||||
/*
|
||||
* f2fs_reserve_new_blocks will not guarantee entire block
|
||||
* allocation.
|
||||
@ -1787,12 +1792,15 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id)
|
||||
static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
u32 masked_flags = fi->i_flags & mask;
|
||||
|
||||
f2fs_bug_on(F2FS_I_SB(inode), (iflags & ~mask));
|
||||
|
||||
/* Is it quota file? Do not allow user to mess with it */
|
||||
if (IS_NOQUOTA(inode))
|
||||
return -EPERM;
|
||||
|
||||
if ((iflags ^ fi->i_flags) & F2FS_CASEFOLD_FL) {
|
||||
if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
|
||||
if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
|
||||
return -EOPNOTSUPP;
|
||||
if (!f2fs_empty_dir(inode))
|
||||
@ -1806,27 +1814,22 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((iflags ^ fi->i_flags) & F2FS_COMPR_FL) {
|
||||
if (S_ISREG(inode->i_mode) &&
|
||||
(fi->i_flags & F2FS_COMPR_FL || i_size_read(inode) ||
|
||||
F2FS_HAS_BLOCKS(inode)))
|
||||
return -EINVAL;
|
||||
if ((iflags ^ masked_flags) & F2FS_COMPR_FL) {
|
||||
if (masked_flags & F2FS_COMPR_FL) {
|
||||
if (f2fs_disable_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
}
|
||||
if (iflags & F2FS_NOCOMP_FL)
|
||||
return -EINVAL;
|
||||
if (iflags & F2FS_COMPR_FL) {
|
||||
int err = f2fs_convert_inline_inode(inode);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!f2fs_may_compress(inode))
|
||||
return -EINVAL;
|
||||
|
||||
set_compress_context(inode);
|
||||
}
|
||||
}
|
||||
if ((iflags ^ fi->i_flags) & F2FS_NOCOMP_FL) {
|
||||
if (fi->i_flags & F2FS_COMPR_FL)
|
||||
if ((iflags ^ masked_flags) & F2FS_NOCOMP_FL) {
|
||||
if (masked_flags & F2FS_COMPR_FL)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -3401,6 +3404,21 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int f2fs_get_compress_blocks(struct file *filp, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
__u64 blocks;
|
||||
|
||||
if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!f2fs_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
|
||||
blocks = F2FS_I(inode)->i_compr_blocks;
|
||||
return put_user(blocks, (u64 __user *)arg);
|
||||
}
|
||||
|
||||
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
|
||||
@ -3481,6 +3499,8 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
return f2fs_get_volume_name(filp, arg);
|
||||
case F2FS_IOC_SET_VOLUME_NAME:
|
||||
return f2fs_set_volume_name(filp, arg);
|
||||
case F2FS_IOC_GET_COMPRESS_BLOCKS:
|
||||
return f2fs_get_compress_blocks(filp, arg);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
@ -3508,8 +3528,10 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!f2fs_is_compress_backend_ready(inode))
|
||||
return -EOPNOTSUPP;
|
||||
if (!f2fs_is_compress_backend_ready(inode)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
if (!inode_trylock(inode)) {
|
||||
@ -3639,6 +3661,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
case FS_IOC_MEASURE_VERITY:
|
||||
case F2FS_IOC_GET_VOLUME_NAME:
|
||||
case F2FS_IOC_SET_VOLUME_NAME:
|
||||
case F2FS_IOC_GET_COMPRESS_BLOCKS:
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
|
51
fs/f2fs/gc.c
51
fs/f2fs/gc.c
@ -31,6 +31,8 @@ static int gc_thread_func(void *data)
|
||||
|
||||
set_freezable();
|
||||
do {
|
||||
bool sync_mode;
|
||||
|
||||
wait_event_interruptible_timeout(*wq,
|
||||
kthread_should_stop() || freezing(current) ||
|
||||
gc_th->gc_wake,
|
||||
@ -101,15 +103,17 @@ static int gc_thread_func(void *data)
|
||||
do_gc:
|
||||
stat_inc_bggc_count(sbi->stat_info);
|
||||
|
||||
sync_mode = F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC;
|
||||
|
||||
/* if return value is not zero, no victim was selected */
|
||||
if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
|
||||
if (f2fs_gc(sbi, sync_mode, true, NULL_SEGNO))
|
||||
wait_ms = gc_th->no_gc_sleep_time;
|
||||
|
||||
trace_f2fs_background_gc(sbi->sb, wait_ms,
|
||||
prefree_segments(sbi), free_segments(sbi));
|
||||
|
||||
/* balancing f2fs's metadata periodically */
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
f2fs_balance_fs_bg(sbi, true);
|
||||
next:
|
||||
sb_end_write(sbi->sb);
|
||||
|
||||
@ -192,7 +196,10 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
|
||||
p->ofs_unit = sbi->segs_per_sec;
|
||||
}
|
||||
|
||||
/* we need to check every dirty segments in the FG_GC case */
|
||||
/*
|
||||
* adjust candidates range, should select all dirty segments for
|
||||
* foreground GC and urgent GC cases.
|
||||
*/
|
||||
if (gc_type != FG_GC &&
|
||||
(sbi->gc_mode != GC_URGENT) &&
|
||||
p->max_search > sbi->max_victim_search)
|
||||
@ -634,7 +641,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
}
|
||||
|
||||
*nofs = ofs_of_node(node_page);
|
||||
source_blkaddr = datablock_addr(NULL, node_page, ofs_in_node);
|
||||
source_blkaddr = data_blkaddr(NULL, node_page, ofs_in_node);
|
||||
f2fs_put_page(node_page, 1);
|
||||
|
||||
if (source_blkaddr != blkaddr) {
|
||||
@ -762,7 +769,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
struct page *page, *mpage;
|
||||
block_t newaddr;
|
||||
int err = 0;
|
||||
bool lfs_mode = test_opt(fio.sbi, LFS);
|
||||
bool lfs_mode = f2fs_lfs_mode(fio.sbi);
|
||||
|
||||
/* do not read out */
|
||||
page = f2fs_grab_cache_page(inode->i_mapping, bidx, false);
|
||||
@ -970,7 +977,8 @@ retry:
|
||||
if (err) {
|
||||
clear_cold_data(page);
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
goto retry;
|
||||
}
|
||||
if (is_dirty)
|
||||
@ -1018,8 +1026,8 @@ next_step:
|
||||
* race condition along with SSR block allocation.
|
||||
*/
|
||||
if ((gc_type == BG_GC && has_not_enough_free_secs(sbi, 0, 0)) ||
|
||||
get_valid_blocks(sbi, segno, false) ==
|
||||
sbi->blocks_per_seg)
|
||||
get_valid_blocks(sbi, segno, true) ==
|
||||
BLKS_PER_SEC(sbi))
|
||||
return submitted;
|
||||
|
||||
if (check_valid_map(sbi, segno, off) == 0)
|
||||
@ -1203,7 +1211,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
||||
|
||||
if (get_valid_blocks(sbi, segno, false) == 0)
|
||||
goto freed;
|
||||
if (__is_large_section(sbi) &&
|
||||
if (gc_type == BG_GC && __is_large_section(sbi) &&
|
||||
migrated >= sbi->migration_granularity)
|
||||
goto skip;
|
||||
if (!PageUptodate(sum_page) || unlikely(f2fs_cp_error(sbi)))
|
||||
@ -1233,12 +1241,12 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
||||
segno, gc_type);
|
||||
|
||||
stat_inc_seg_count(sbi, type, gc_type);
|
||||
migrated++;
|
||||
|
||||
freed:
|
||||
if (gc_type == FG_GC &&
|
||||
get_valid_blocks(sbi, segno, false) == 0)
|
||||
seg_freed++;
|
||||
migrated++;
|
||||
|
||||
if (__is_large_section(sbi) && segno + 1 < end_segno)
|
||||
sbi->next_victim_seg[gc_type] = segno + 1;
|
||||
@ -1434,12 +1442,19 @@ static int free_segment_range(struct f2fs_sb_info *sbi, unsigned int start,
|
||||
static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
|
||||
{
|
||||
struct f2fs_super_block *raw_sb = F2FS_RAW_SUPER(sbi);
|
||||
int section_count = le32_to_cpu(raw_sb->section_count);
|
||||
int segment_count = le32_to_cpu(raw_sb->segment_count);
|
||||
int segment_count_main = le32_to_cpu(raw_sb->segment_count_main);
|
||||
long long block_count = le64_to_cpu(raw_sb->block_count);
|
||||
int section_count;
|
||||
int segment_count;
|
||||
int segment_count_main;
|
||||
long long block_count;
|
||||
int segs = secs * sbi->segs_per_sec;
|
||||
|
||||
down_write(&sbi->sb_lock);
|
||||
|
||||
section_count = le32_to_cpu(raw_sb->section_count);
|
||||
segment_count = le32_to_cpu(raw_sb->segment_count);
|
||||
segment_count_main = le32_to_cpu(raw_sb->segment_count_main);
|
||||
block_count = le64_to_cpu(raw_sb->block_count);
|
||||
|
||||
raw_sb->section_count = cpu_to_le32(section_count + secs);
|
||||
raw_sb->segment_count = cpu_to_le32(segment_count + segs);
|
||||
raw_sb->segment_count_main = cpu_to_le32(segment_count_main + segs);
|
||||
@ -1453,6 +1468,8 @@ static void update_sb_metadata(struct f2fs_sb_info *sbi, int secs)
|
||||
raw_sb->devs[last_dev].total_segments =
|
||||
cpu_to_le32(dev_segs + segs);
|
||||
}
|
||||
|
||||
up_write(&sbi->sb_lock);
|
||||
}
|
||||
|
||||
static void update_fs_metadata(struct f2fs_sb_info *sbi, int secs)
|
||||
@ -1570,11 +1587,17 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 block_count)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&sbi->cp_mutex);
|
||||
update_fs_metadata(sbi, -secs);
|
||||
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
set_sbi_flag(sbi, SBI_IS_DIRTY);
|
||||
mutex_unlock(&sbi->cp_mutex);
|
||||
|
||||
err = f2fs_sync_fs(sbi->sb, 1);
|
||||
if (err) {
|
||||
mutex_lock(&sbi->cp_mutex);
|
||||
update_fs_metadata(sbi, secs);
|
||||
mutex_unlock(&sbi->cp_mutex);
|
||||
update_sb_metadata(sbi, secs);
|
||||
f2fs_commit_super(sbi, false);
|
||||
}
|
||||
|
@ -291,13 +291,30 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
|
||||
fi->i_flags & F2FS_COMPR_FL &&
|
||||
F2FS_FITS_IN_INODE(ri, fi->i_extra_isize,
|
||||
i_log_cluster_size)) {
|
||||
if (ri->i_compress_algorithm >= COMPRESS_MAX)
|
||||
if (ri->i_compress_algorithm >= COMPRESS_MAX) {
|
||||
f2fs_warn(sbi, "%s: inode (ino=%lx) has unsupported "
|
||||
"compress algorithm: %u, run fsck to fix",
|
||||
__func__, inode->i_ino,
|
||||
ri->i_compress_algorithm);
|
||||
return false;
|
||||
if (le64_to_cpu(ri->i_compr_blocks) > inode->i_blocks)
|
||||
}
|
||||
if (le64_to_cpu(ri->i_compr_blocks) >
|
||||
SECTOR_TO_BLOCK(inode->i_blocks)) {
|
||||
f2fs_warn(sbi, "%s: inode (ino=%lx) has inconsistent "
|
||||
"i_compr_blocks:%llu, i_blocks:%llu, run fsck to fix",
|
||||
__func__, inode->i_ino,
|
||||
le64_to_cpu(ri->i_compr_blocks),
|
||||
SECTOR_TO_BLOCK(inode->i_blocks));
|
||||
return false;
|
||||
}
|
||||
if (ri->i_log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
|
||||
ri->i_log_cluster_size > MAX_COMPRESS_LOG_SIZE)
|
||||
ri->i_log_cluster_size > MAX_COMPRESS_LOG_SIZE) {
|
||||
f2fs_warn(sbi, "%s: inode (ino=%lx) has unsupported "
|
||||
"log cluster size: %u, run fsck to fix",
|
||||
__func__, inode->i_ino,
|
||||
ri->i_log_cluster_size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -345,7 +362,7 @@ static int do_read_inode(struct inode *inode)
|
||||
fi->i_flags = le32_to_cpu(ri->i_flags);
|
||||
if (S_ISREG(inode->i_mode))
|
||||
fi->i_flags &= ~F2FS_PROJINHERIT_FL;
|
||||
fi->flags = 0;
|
||||
bitmap_zero(fi->flags, FI_MAX);
|
||||
fi->i_advise = ri->i_advise;
|
||||
fi->i_pino = le32_to_cpu(ri->i_pino);
|
||||
fi->i_dir_level = ri->i_dir_level;
|
||||
@ -518,7 +535,7 @@ retry:
|
||||
inode = f2fs_iget(sb, ino);
|
||||
if (IS_ERR(inode)) {
|
||||
if (PTR_ERR(inode) == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
@ -759,7 +776,7 @@ no_delete:
|
||||
else
|
||||
f2fs_inode_synced(inode);
|
||||
|
||||
/* ino == 0, if f2fs_new_inode() was failed t*/
|
||||
/* for the case f2fs_new_inode() was failed, .i_ino is zero, skip it */
|
||||
if (inode->i_ino)
|
||||
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino,
|
||||
inode->i_ino);
|
||||
|
@ -75,9 +75,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
|
||||
set_inode_flag(inode, FI_NEW_INODE);
|
||||
|
||||
/* If the directory encrypted, then we should encrypt the inode. */
|
||||
if ((IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) &&
|
||||
f2fs_may_encrypt(inode))
|
||||
if (f2fs_may_encrypt(dir, inode))
|
||||
f2fs_set_encrypted_inode(inode);
|
||||
|
||||
if (f2fs_sb_has_extra_attr(sbi)) {
|
||||
@ -177,7 +175,7 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub)
|
||||
}
|
||||
|
||||
/*
|
||||
* Set multimedia files as cold files for hot/cold data separation
|
||||
* Set file's temperature for hot/cold data separation
|
||||
*/
|
||||
static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
@ -876,12 +874,6 @@ static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
if (!f2fs_is_checkpoint_ready(sbi))
|
||||
return -ENOSPC;
|
||||
|
||||
if (IS_ENCRYPTED(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) {
|
||||
int err = fscrypt_get_encryption_info(dir);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return __f2fs_tmpfile(dir, dentry, mode, NULL);
|
||||
}
|
||||
|
||||
|
@ -510,9 +510,6 @@ int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
return nr - nr_shrink;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function always returns success
|
||||
*/
|
||||
int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||
struct node_info *ni)
|
||||
{
|
||||
@ -716,8 +713,7 @@ got:
|
||||
/*
|
||||
* Caller should call f2fs_put_dnode(dn).
|
||||
* Also, it should grab and release a rwsem by calling f2fs_lock_op() and
|
||||
* f2fs_unlock_op() only if ro is not set RDONLY_NODE.
|
||||
* In the case of RDONLY_NODE, we don't need to care about mutex.
|
||||
* f2fs_unlock_op() only if mode is set with ALLOC_NODE.
|
||||
*/
|
||||
int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
{
|
||||
@ -809,8 +805,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
dn->nid = nids[level];
|
||||
dn->ofs_in_node = offset[level];
|
||||
dn->node_page = npage[level];
|
||||
dn->data_blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
dn->data_blkaddr = f2fs_data_blkaddr(dn);
|
||||
return 0;
|
||||
|
||||
release_pages:
|
||||
@ -1188,8 +1183,9 @@ int f2fs_remove_inode_page(struct inode *inode)
|
||||
}
|
||||
|
||||
if (unlikely(inode->i_blocks != 0 && inode->i_blocks != 8)) {
|
||||
f2fs_warn(F2FS_I_SB(inode), "Inconsistent i_blocks, ino:%lu, iblocks:%llu",
|
||||
inode->i_ino, (unsigned long long)inode->i_blocks);
|
||||
f2fs_warn(F2FS_I_SB(inode),
|
||||
"f2fs_remove_inode_page: inconsistent i_blocks, ino:%lu, iblocks:%llu",
|
||||
inode->i_ino, (unsigned long long)inode->i_blocks);
|
||||
set_sbi_flag(F2FS_I_SB(inode), SBI_NEED_FSCK);
|
||||
}
|
||||
|
||||
@ -1562,15 +1558,16 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
||||
if (atomic && !test_opt(sbi, NOBARRIER))
|
||||
fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
|
||||
|
||||
set_page_writeback(page);
|
||||
ClearPageError(page);
|
||||
|
||||
/* should add to global list before clearing PAGECACHE status */
|
||||
if (f2fs_in_warm_node_list(sbi, page)) {
|
||||
seq = f2fs_add_fsync_node_entry(sbi, page);
|
||||
if (seq_id)
|
||||
*seq_id = seq;
|
||||
}
|
||||
|
||||
set_page_writeback(page);
|
||||
ClearPageError(page);
|
||||
|
||||
fio.old_blkaddr = ni.blk_addr;
|
||||
f2fs_do_write_node_page(nid, &fio);
|
||||
set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
|
||||
@ -1979,7 +1976,7 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
goto skip_write;
|
||||
|
||||
/* balancing f2fs's metadata in background */
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
f2fs_balance_fs_bg(sbi, true);
|
||||
|
||||
/* collect a number of dirty node pages and write together */
|
||||
if (wbc->sync_mode != WB_SYNC_ALL &&
|
||||
@ -2602,7 +2599,7 @@ int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
retry:
|
||||
ipage = f2fs_grab_cache_page(NODE_MAPPING(sbi), ino, false);
|
||||
if (!ipage) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@ -3193,22 +3190,22 @@ void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
|
||||
int __init f2fs_create_node_manager_caches(void)
|
||||
{
|
||||
nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
|
||||
nat_entry_slab = f2fs_kmem_cache_create("f2fs_nat_entry",
|
||||
sizeof(struct nat_entry));
|
||||
if (!nat_entry_slab)
|
||||
goto fail;
|
||||
|
||||
free_nid_slab = f2fs_kmem_cache_create("free_nid",
|
||||
free_nid_slab = f2fs_kmem_cache_create("f2fs_free_nid",
|
||||
sizeof(struct free_nid));
|
||||
if (!free_nid_slab)
|
||||
goto destroy_nat_entry;
|
||||
|
||||
nat_entry_set_slab = f2fs_kmem_cache_create("nat_entry_set",
|
||||
nat_entry_set_slab = f2fs_kmem_cache_create("f2fs_nat_entry_set",
|
||||
sizeof(struct nat_entry_set));
|
||||
if (!nat_entry_set_slab)
|
||||
goto destroy_free_nid;
|
||||
|
||||
fsync_node_entry_slab = f2fs_kmem_cache_create("fsync_node_entry",
|
||||
fsync_node_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_node_entry",
|
||||
sizeof(struct fsync_node_entry));
|
||||
if (!fsync_node_entry_slab)
|
||||
goto destroy_nat_entry_set;
|
||||
|
@ -496,8 +496,7 @@ out:
|
||||
return 0;
|
||||
|
||||
truncate_out:
|
||||
if (datablock_addr(tdn.inode, tdn.node_page,
|
||||
tdn.ofs_in_node) == blkaddr)
|
||||
if (f2fs_data_blkaddr(&tdn) == blkaddr)
|
||||
f2fs_truncate_data_blocks_range(&tdn, 1);
|
||||
if (dn->inode->i_ino == nid && !dn->inode_page_locked)
|
||||
unlock_page(dn->inode_page);
|
||||
@ -535,7 +534,7 @@ retry_dn:
|
||||
err = f2fs_get_dnode_of_data(&dn, start, ALLOC_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
goto retry_dn;
|
||||
}
|
||||
goto out;
|
||||
@ -560,8 +559,8 @@ retry_dn:
|
||||
for (; start < end; start++, dn.ofs_in_node++) {
|
||||
block_t src, dest;
|
||||
|
||||
src = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
|
||||
dest = datablock_addr(dn.inode, page, dn.ofs_in_node);
|
||||
src = f2fs_data_blkaddr(&dn);
|
||||
dest = data_blkaddr(dn.inode, page, dn.ofs_in_node);
|
||||
|
||||
if (__is_valid_data_blkaddr(src) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
|
||||
@ -618,7 +617,8 @@ retry_prev:
|
||||
err = check_index_in_prev_nodes(sbi, dest, &dn);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
goto retry_prev;
|
||||
}
|
||||
goto err;
|
||||
|
@ -172,7 +172,7 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi)
|
||||
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
||||
int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA);
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
if (f2fs_lfs_mode(sbi))
|
||||
return false;
|
||||
if (sbi->gc_mode == GC_URGENT)
|
||||
return true;
|
||||
@ -245,7 +245,8 @@ retry:
|
||||
LOOKUP_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
@ -312,7 +313,7 @@ next:
|
||||
skip:
|
||||
iput(inode);
|
||||
}
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
cond_resched();
|
||||
if (gc_failure) {
|
||||
if (++looped >= count)
|
||||
@ -415,7 +416,8 @@ retry:
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
@ -494,7 +496,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
|
||||
|
||||
/* balance_fs_bg is able to be pending */
|
||||
if (need && excess_cached_nats(sbi))
|
||||
f2fs_balance_fs_bg(sbi);
|
||||
f2fs_balance_fs_bg(sbi, false);
|
||||
|
||||
if (!f2fs_is_checkpoint_ready(sbi))
|
||||
return;
|
||||
@ -509,7 +511,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
|
||||
}
|
||||
}
|
||||
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
|
||||
{
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
||||
return;
|
||||
@ -538,7 +540,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
excess_dirty_nats(sbi) ||
|
||||
excess_dirty_nodes(sbi) ||
|
||||
f2fs_time_over(sbi, CP_TIME)) {
|
||||
if (test_opt(sbi, DATA_FLUSH)) {
|
||||
if (test_opt(sbi, DATA_FLUSH) && from_bg) {
|
||||
struct blk_plug plug;
|
||||
|
||||
mutex_lock(&sbi->flush_lock);
|
||||
@ -1078,7 +1080,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
|
||||
dpolicy->max_requests = DEF_MAX_DISCARD_REQUEST;
|
||||
dpolicy->io_aware_gran = MAX_PLIST_NUM;
|
||||
dpolicy->timeout = 0;
|
||||
dpolicy->timeout = false;
|
||||
|
||||
if (discard_type == DPOLICY_BG) {
|
||||
dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
@ -1103,6 +1105,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
dpolicy->io_aware = false;
|
||||
/* we need to issue all to keep CP_TRIMMED_FLAG */
|
||||
dpolicy->granularity = 1;
|
||||
dpolicy->timeout = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1471,12 +1474,12 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
int i, issued = 0;
|
||||
bool io_interrupted = false;
|
||||
|
||||
if (dpolicy->timeout != 0)
|
||||
f2fs_update_time(sbi, dpolicy->timeout);
|
||||
if (dpolicy->timeout)
|
||||
f2fs_update_time(sbi, UMOUNT_DISCARD_TIMEOUT);
|
||||
|
||||
for (i = MAX_PLIST_NUM - 1; i >= 0; i--) {
|
||||
if (dpolicy->timeout != 0 &&
|
||||
f2fs_time_over(sbi, dpolicy->timeout))
|
||||
if (dpolicy->timeout &&
|
||||
f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
|
||||
break;
|
||||
|
||||
if (i + 1 < dpolicy->granularity)
|
||||
@ -1497,8 +1500,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
list_for_each_entry_safe(dc, tmp, pend_list, list) {
|
||||
f2fs_bug_on(sbi, dc->state != D_PREP);
|
||||
|
||||
if (dpolicy->timeout != 0 &&
|
||||
f2fs_time_over(sbi, dpolicy->timeout))
|
||||
if (dpolicy->timeout &&
|
||||
f2fs_time_over(sbi, UMOUNT_DISCARD_TIMEOUT))
|
||||
break;
|
||||
|
||||
if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
|
||||
@ -1677,7 +1680,6 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
|
||||
|
||||
__init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,
|
||||
dcc->discard_granularity);
|
||||
dpolicy.timeout = UMOUNT_DISCARD_TIMEOUT;
|
||||
__issue_discard_cmd(sbi, &dpolicy);
|
||||
dropped = __drop_discard_cmd(sbi);
|
||||
|
||||
@ -1940,7 +1942,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
|
||||
unsigned int start = 0, end = -1;
|
||||
unsigned int secno, start_segno;
|
||||
bool force = (cpc->reason & CP_DISCARD);
|
||||
bool need_align = test_opt(sbi, LFS) && __is_large_section(sbi);
|
||||
bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
|
||||
|
||||
mutex_lock(&dirty_i->seglist_lock);
|
||||
|
||||
@ -1972,7 +1974,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
|
||||
(end - 1) <= cpc->trim_end)
|
||||
continue;
|
||||
|
||||
if (!test_opt(sbi, LFS) || !__is_large_section(sbi)) {
|
||||
if (!f2fs_lfs_mode(sbi) || !__is_large_section(sbi)) {
|
||||
f2fs_issue_discard(sbi, START_BLOCK(sbi, start),
|
||||
(end - start) << sbi->log_blocks_per_seg);
|
||||
continue;
|
||||
@ -2801,7 +2803,7 @@ next:
|
||||
blk_finish_plug(&plug);
|
||||
mutex_unlock(&dcc->cmd_lock);
|
||||
trimmed += __wait_all_discard_cmd(sbi, NULL);
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC, DEFAULT_IO_TIMEOUT);
|
||||
goto next;
|
||||
}
|
||||
skip:
|
||||
@ -2830,7 +2832,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
|
||||
struct discard_policy dpolicy;
|
||||
unsigned long long trimmed = 0;
|
||||
int err = 0;
|
||||
bool need_align = test_opt(sbi, LFS) && __is_large_section(sbi);
|
||||
bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
|
||||
|
||||
if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
|
||||
return -EINVAL;
|
||||
@ -3193,7 +3195,7 @@ static void update_device_state(struct f2fs_io_info *fio)
|
||||
static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
|
||||
{
|
||||
int type = __get_segment_type(fio);
|
||||
bool keep_order = (test_opt(fio->sbi, LFS) && type == CURSEG_COLD_DATA);
|
||||
bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA);
|
||||
|
||||
if (keep_order)
|
||||
down_read(&fio->sbi->io_order_lock);
|
||||
@ -4071,7 +4073,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
|
||||
sit_i->dirty_sentries = 0;
|
||||
sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
|
||||
sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
|
||||
sit_i->mounted_time = ktime_get_real_seconds();
|
||||
sit_i->mounted_time = ktime_get_boottime_seconds();
|
||||
init_rwsem(&sit_i->sentry_lock);
|
||||
return 0;
|
||||
}
|
||||
@ -4678,7 +4680,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
if (sm_info->rec_prefree_segments > DEF_MAX_RECLAIM_PREFREE_SEGMENTS)
|
||||
sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS;
|
||||
|
||||
if (!test_opt(sbi, LFS))
|
||||
if (!f2fs_lfs_mode(sbi))
|
||||
sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
|
||||
sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
|
||||
sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
|
||||
@ -4830,22 +4832,22 @@ void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi)
|
||||
|
||||
int __init f2fs_create_segment_manager_caches(void)
|
||||
{
|
||||
discard_entry_slab = f2fs_kmem_cache_create("discard_entry",
|
||||
discard_entry_slab = f2fs_kmem_cache_create("f2fs_discard_entry",
|
||||
sizeof(struct discard_entry));
|
||||
if (!discard_entry_slab)
|
||||
goto fail;
|
||||
|
||||
discard_cmd_slab = f2fs_kmem_cache_create("discard_cmd",
|
||||
discard_cmd_slab = f2fs_kmem_cache_create("f2fs_discard_cmd",
|
||||
sizeof(struct discard_cmd));
|
||||
if (!discard_cmd_slab)
|
||||
goto destroy_discard_entry;
|
||||
|
||||
sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set",
|
||||
sit_entry_set_slab = f2fs_kmem_cache_create("f2fs_sit_entry_set",
|
||||
sizeof(struct sit_entry_set));
|
||||
if (!sit_entry_set_slab)
|
||||
goto destroy_discard_cmd;
|
||||
|
||||
inmem_entry_slab = f2fs_kmem_cache_create("inmem_page_entry",
|
||||
inmem_entry_slab = f2fs_kmem_cache_create("f2fs_inmem_page_entry",
|
||||
sizeof(struct inmem_pages));
|
||||
if (!inmem_entry_slab)
|
||||
goto destroy_sit_entry_set;
|
||||
|
@ -756,7 +756,7 @@ static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi,
|
||||
bool base_time)
|
||||
{
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
time64_t diff, now = ktime_get_real_seconds();
|
||||
time64_t diff, now = ktime_get_boottime_seconds();
|
||||
|
||||
if (now >= sit_i->mounted_time)
|
||||
return sit_i->elapsed_time + now - sit_i->mounted_time;
|
||||
|
@ -58,7 +58,7 @@ unsigned long f2fs_shrink_count(struct shrinker *shrink,
|
||||
/* count extent cache entries */
|
||||
count += __count_extent_cache(sbi);
|
||||
|
||||
/* shrink clean nat cache entries */
|
||||
/* count clean nat cache entries */
|
||||
count += __count_nat_entries(sbi);
|
||||
|
||||
/* count free nids cache entries */
|
||||
|
@ -428,14 +428,11 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
if (strlen(name) == 2 && !strncmp(name, "on", 2)) {
|
||||
set_opt(sbi, BG_GC);
|
||||
clear_opt(sbi, FORCE_FG_GC);
|
||||
F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
|
||||
} else if (strlen(name) == 3 && !strncmp(name, "off", 3)) {
|
||||
clear_opt(sbi, BG_GC);
|
||||
clear_opt(sbi, FORCE_FG_GC);
|
||||
F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_OFF;
|
||||
} else if (strlen(name) == 4 && !strncmp(name, "sync", 4)) {
|
||||
set_opt(sbi, BG_GC);
|
||||
set_opt(sbi, FORCE_FG_GC);
|
||||
F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_SYNC;
|
||||
} else {
|
||||
kvfree(name);
|
||||
return -EINVAL;
|
||||
@ -447,7 +444,7 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
break;
|
||||
case Opt_norecovery:
|
||||
/* this option mounts f2fs with ro */
|
||||
set_opt(sbi, DISABLE_ROLL_FORWARD);
|
||||
set_opt(sbi, NORECOVERY);
|
||||
if (!f2fs_readonly(sb))
|
||||
return -EINVAL;
|
||||
break;
|
||||
@ -601,10 +598,10 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
kvfree(name);
|
||||
return -EINVAL;
|
||||
}
|
||||
set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
|
||||
F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
|
||||
} else if (strlen(name) == 3 &&
|
||||
!strncmp(name, "lfs", 3)) {
|
||||
set_opt_mode(sbi, F2FS_MOUNT_LFS);
|
||||
F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
|
||||
} else {
|
||||
kvfree(name);
|
||||
return -EINVAL;
|
||||
@ -833,6 +830,10 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
!strcmp(name, "lz4")) {
|
||||
F2FS_OPTION(sbi).compress_algorithm =
|
||||
COMPRESS_LZ4;
|
||||
} else if (strlen(name) == 4 &&
|
||||
!strcmp(name, "zstd")) {
|
||||
F2FS_OPTION(sbi).compress_algorithm =
|
||||
COMPRESS_ZSTD;
|
||||
} else {
|
||||
kfree(name);
|
||||
return -EINVAL;
|
||||
@ -905,7 +906,7 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
|
||||
if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) {
|
||||
f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO",
|
||||
F2FS_IO_SIZE_KB(sbi));
|
||||
return -EINVAL;
|
||||
@ -935,7 +936,7 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
}
|
||||
}
|
||||
|
||||
if (test_opt(sbi, DISABLE_CHECKPOINT) && test_opt(sbi, LFS)) {
|
||||
if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) {
|
||||
f2fs_err(sbi, "LFS not compatible with checkpoint=disable\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -961,6 +962,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
|
||||
/* Initialize f2fs-specific inode info */
|
||||
atomic_set(&fi->dirty_pages, 0);
|
||||
init_rwsem(&fi->i_sem);
|
||||
spin_lock_init(&fi->i_size_lock);
|
||||
INIT_LIST_HEAD(&fi->dirty_list);
|
||||
INIT_LIST_HEAD(&fi->gdirty_list);
|
||||
INIT_LIST_HEAD(&fi->inmem_ilist);
|
||||
@ -1173,7 +1175,7 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
/* our cp_error case, we can wait for any writeback page */
|
||||
f2fs_flush_merged_writes(sbi);
|
||||
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
|
||||
|
||||
f2fs_bug_on(sbi, sbi->fsync_node_num);
|
||||
|
||||
@ -1205,6 +1207,7 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
kvfree(sbi->raw_super);
|
||||
|
||||
destroy_device_list(sbi);
|
||||
f2fs_destroy_xattr_caches(sbi);
|
||||
mempool_destroy(sbi->write_io_dummy);
|
||||
#ifdef CONFIG_QUOTA
|
||||
for (i = 0; i < MAXQUOTAS; i++)
|
||||
@ -1421,6 +1424,9 @@ static inline void f2fs_show_compress_options(struct seq_file *seq,
|
||||
case COMPRESS_LZ4:
|
||||
algtype = "lz4";
|
||||
break;
|
||||
case COMPRESS_ZSTD:
|
||||
algtype = "zstd";
|
||||
break;
|
||||
}
|
||||
seq_printf(seq, ",compress_algorithm=%s", algtype);
|
||||
|
||||
@ -1437,16 +1443,17 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
|
||||
|
||||
if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC)) {
|
||||
if (test_opt(sbi, FORCE_FG_GC))
|
||||
seq_printf(seq, ",background_gc=%s", "sync");
|
||||
else
|
||||
seq_printf(seq, ",background_gc=%s", "on");
|
||||
} else {
|
||||
if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_SYNC)
|
||||
seq_printf(seq, ",background_gc=%s", "sync");
|
||||
else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_ON)
|
||||
seq_printf(seq, ",background_gc=%s", "on");
|
||||
else if (F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF)
|
||||
seq_printf(seq, ",background_gc=%s", "off");
|
||||
}
|
||||
|
||||
if (test_opt(sbi, DISABLE_ROLL_FORWARD))
|
||||
seq_puts(seq, ",disable_roll_forward");
|
||||
if (test_opt(sbi, NORECOVERY))
|
||||
seq_puts(seq, ",norecovery");
|
||||
if (test_opt(sbi, DISCARD))
|
||||
seq_puts(seq, ",discard");
|
||||
else
|
||||
@ -1498,9 +1505,9 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
seq_puts(seq, ",data_flush");
|
||||
|
||||
seq_puts(seq, ",mode=");
|
||||
if (test_opt(sbi, ADAPTIVE))
|
||||
if (F2FS_OPTION(sbi).fs_mode == FS_MODE_ADAPTIVE)
|
||||
seq_puts(seq, "adaptive");
|
||||
else if (test_opt(sbi, LFS))
|
||||
else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS)
|
||||
seq_puts(seq, "lfs");
|
||||
seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
|
||||
if (test_opt(sbi, RESERVE_ROOT))
|
||||
@ -1571,11 +1578,11 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
F2FS_OPTION(sbi).test_dummy_encryption = false;
|
||||
F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
|
||||
F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
|
||||
F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZO;
|
||||
F2FS_OPTION(sbi).compress_algorithm = COMPRESS_LZ4;
|
||||
F2FS_OPTION(sbi).compress_log_size = MIN_COMPRESS_LOG_SIZE;
|
||||
F2FS_OPTION(sbi).compress_ext_cnt = 0;
|
||||
F2FS_OPTION(sbi).bggc_mode = BGGC_MODE_ON;
|
||||
|
||||
set_opt(sbi, BG_GC);
|
||||
set_opt(sbi, INLINE_XATTR);
|
||||
set_opt(sbi, INLINE_DATA);
|
||||
set_opt(sbi, INLINE_DENTRY);
|
||||
@ -1587,9 +1594,9 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
set_opt(sbi, FLUSH_MERGE);
|
||||
set_opt(sbi, DISCARD);
|
||||
if (f2fs_sb_has_blkzoned(sbi))
|
||||
set_opt_mode(sbi, F2FS_MOUNT_LFS);
|
||||
F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
|
||||
else
|
||||
set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
|
||||
F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_XATTR
|
||||
set_opt(sbi, XATTR_USER);
|
||||
@ -1658,7 +1665,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
out_unlock:
|
||||
up_write(&sbi->gc_lock);
|
||||
restore_flag:
|
||||
sbi->sb->s_flags = s_flags; /* Restore MS_RDONLY status */
|
||||
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1781,7 +1788,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
|
||||
* or if background_gc = off is passed in mount
|
||||
* option. Also sync the filesystem.
|
||||
*/
|
||||
if ((*flags & SB_RDONLY) || !test_opt(sbi, BG_GC)) {
|
||||
if ((*flags & SB_RDONLY) ||
|
||||
F2FS_OPTION(sbi).bggc_mode == BGGC_MODE_OFF) {
|
||||
if (sbi->gc_thread) {
|
||||
f2fs_stop_gc_thread(sbi);
|
||||
need_restart_gc = true;
|
||||
@ -1886,7 +1894,8 @@ repeat:
|
||||
page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS);
|
||||
if (IS_ERR(page)) {
|
||||
if (PTR_ERR(page) == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
goto repeat;
|
||||
}
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
|
||||
@ -1928,6 +1937,7 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type,
|
||||
int offset = off & (sb->s_blocksize - 1);
|
||||
size_t towrite = len;
|
||||
struct page *page;
|
||||
void *fsdata = NULL;
|
||||
char *kaddr;
|
||||
int err = 0;
|
||||
int tocopy;
|
||||
@ -1937,10 +1947,11 @@ static ssize_t f2fs_quota_write(struct super_block *sb, int type,
|
||||
towrite);
|
||||
retry:
|
||||
err = a_ops->write_begin(NULL, mapping, off, tocopy, 0,
|
||||
&page, NULL);
|
||||
&page, &fsdata);
|
||||
if (unlikely(err)) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
goto retry;
|
||||
}
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
|
||||
@ -1953,7 +1964,7 @@ retry:
|
||||
flush_dcache_page(page);
|
||||
|
||||
a_ops->write_end(NULL, mapping, off, tocopy, tocopy,
|
||||
page, NULL);
|
||||
page, fsdata);
|
||||
offset = 0;
|
||||
towrite -= tocopy;
|
||||
off += tocopy;
|
||||
@ -3457,12 +3468,17 @@ try_onemore:
|
||||
}
|
||||
}
|
||||
|
||||
/* init per sbi slab cache */
|
||||
err = f2fs_init_xattr_caches(sbi);
|
||||
if (err)
|
||||
goto free_io_dummy;
|
||||
|
||||
/* get an inode for meta space */
|
||||
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
|
||||
if (IS_ERR(sbi->meta_inode)) {
|
||||
f2fs_err(sbi, "Failed to read F2FS meta data inode");
|
||||
err = PTR_ERR(sbi->meta_inode);
|
||||
goto free_io_dummy;
|
||||
goto free_xattr_cache;
|
||||
}
|
||||
|
||||
err = f2fs_get_valid_checkpoint(sbi);
|
||||
@ -3590,7 +3606,7 @@ try_onemore:
|
||||
f2fs_err(sbi, "Cannot turn on quotas: error %d", err);
|
||||
}
|
||||
#endif
|
||||
/* if there are nt orphan nodes free them */
|
||||
/* if there are any orphan inodes, free them */
|
||||
err = f2fs_recover_orphan_inodes(sbi);
|
||||
if (err)
|
||||
goto free_meta;
|
||||
@ -3599,7 +3615,8 @@ try_onemore:
|
||||
goto reset_checkpoint;
|
||||
|
||||
/* recover fsynced data */
|
||||
if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
|
||||
if (!test_opt(sbi, DISABLE_ROLL_FORWARD) &&
|
||||
!test_opt(sbi, NORECOVERY)) {
|
||||
/*
|
||||
* mount should be failed, when device has readonly mode, and
|
||||
* previous checkpoint was not done by clean system shutdown.
|
||||
@ -3665,7 +3682,7 @@ reset_checkpoint:
|
||||
* If filesystem is not mounted as read-only then
|
||||
* do start the gc_thread.
|
||||
*/
|
||||
if (test_opt(sbi, BG_GC) && !f2fs_readonly(sb)) {
|
||||
if (F2FS_OPTION(sbi).bggc_mode != BGGC_MODE_OFF && !f2fs_readonly(sb)) {
|
||||
/* After POR, we can run background GC thread.*/
|
||||
err = f2fs_start_gc_thread(sbi);
|
||||
if (err)
|
||||
@ -3734,6 +3751,8 @@ free_meta_inode:
|
||||
make_bad_inode(sbi->meta_inode);
|
||||
iput(sbi->meta_inode);
|
||||
sbi->meta_inode = NULL;
|
||||
free_xattr_cache:
|
||||
f2fs_destroy_xattr_caches(sbi);
|
||||
free_io_dummy:
|
||||
mempool_destroy(sbi->write_io_dummy);
|
||||
free_percpu:
|
||||
|
@ -109,47 +109,47 @@ static ssize_t features_show(struct f2fs_attr *a,
|
||||
return sprintf(buf, "0\n");
|
||||
|
||||
if (f2fs_sb_has_encrypt(sbi))
|
||||
len += snprintf(buf, PAGE_SIZE - len, "%s",
|
||||
len += scnprintf(buf, PAGE_SIZE - len, "%s",
|
||||
"encryption");
|
||||
if (f2fs_sb_has_blkzoned(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "blkzoned");
|
||||
if (f2fs_sb_has_extra_attr(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "extra_attr");
|
||||
if (f2fs_sb_has_project_quota(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "projquota");
|
||||
if (f2fs_sb_has_inode_chksum(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "inode_checksum");
|
||||
if (f2fs_sb_has_flexible_inline_xattr(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "flexible_inline_xattr");
|
||||
if (f2fs_sb_has_quota_ino(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "quota_ino");
|
||||
if (f2fs_sb_has_inode_crtime(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "inode_crtime");
|
||||
if (f2fs_sb_has_lost_found(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "lost_found");
|
||||
if (f2fs_sb_has_verity(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "verity");
|
||||
if (f2fs_sb_has_sb_chksum(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "sb_checksum");
|
||||
if (f2fs_sb_has_casefold(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "casefold");
|
||||
if (f2fs_sb_has_compression(sbi))
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "compression");
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s%s",
|
||||
len ? ", " : "", "pin_file");
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -185,6 +185,12 @@ static ssize_t encoding_show(struct f2fs_attr *a,
|
||||
return sprintf(buf, "(none)");
|
||||
}
|
||||
|
||||
static ssize_t mounted_time_sec_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%llu", SIT_I(sbi)->mounted_time);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
static ssize_t moved_blocks_foreground_show(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi, char *buf)
|
||||
@ -233,16 +239,16 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
int hot_count = sbi->raw_super->hot_ext_count;
|
||||
int len = 0, i;
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"cold file extension:\n");
|
||||
for (i = 0; i < cold_count; i++)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
extlist[i]);
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"hot file extension:\n");
|
||||
for (i = cold_count; i < cold_count + hot_count; i++)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
extlist[i]);
|
||||
return len;
|
||||
}
|
||||
@ -544,6 +550,7 @@ F2FS_GENERAL_RO_ATTR(features);
|
||||
F2FS_GENERAL_RO_ATTR(current_reserved_blocks);
|
||||
F2FS_GENERAL_RO_ATTR(unusable);
|
||||
F2FS_GENERAL_RO_ATTR(encoding);
|
||||
F2FS_GENERAL_RO_ATTR(mounted_time_sec);
|
||||
#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);
|
||||
@ -573,7 +580,9 @@ F2FS_FEATURE_RO_ATTR(verity, FEAT_VERITY);
|
||||
#endif
|
||||
F2FS_FEATURE_RO_ATTR(sb_checksum, FEAT_SB_CHECKSUM);
|
||||
F2FS_FEATURE_RO_ATTR(casefold, FEAT_CASEFOLD);
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
F2FS_FEATURE_RO_ATTR(compression, FEAT_COMPRESSION);
|
||||
#endif
|
||||
|
||||
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
|
||||
static struct attribute *f2fs_attrs[] = {
|
||||
@ -621,6 +630,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(reserved_blocks),
|
||||
ATTR_LIST(current_reserved_blocks),
|
||||
ATTR_LIST(encoding),
|
||||
ATTR_LIST(mounted_time_sec),
|
||||
#ifdef CONFIG_F2FS_STAT_FS
|
||||
ATTR_LIST(cp_foreground_calls),
|
||||
ATTR_LIST(cp_background_calls),
|
||||
@ -654,7 +664,9 @@ static struct attribute *f2fs_feat_attrs[] = {
|
||||
#endif
|
||||
ATTR_LIST(sb_checksum),
|
||||
ATTR_LIST(casefold),
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
ATTR_LIST(compression),
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(f2fs_feat);
|
||||
|
@ -23,6 +23,25 @@
|
||||
#include "xattr.h"
|
||||
#include "segment.h"
|
||||
|
||||
static void *xattr_alloc(struct f2fs_sb_info *sbi, int size, bool *is_inline)
|
||||
{
|
||||
if (likely(size == sbi->inline_xattr_slab_size)) {
|
||||
*is_inline = true;
|
||||
return kmem_cache_zalloc(sbi->inline_xattr_slab, GFP_NOFS);
|
||||
}
|
||||
*is_inline = false;
|
||||
return f2fs_kzalloc(sbi, size, GFP_NOFS);
|
||||
}
|
||||
|
||||
static void xattr_free(struct f2fs_sb_info *sbi, void *xattr_addr,
|
||||
bool is_inline)
|
||||
{
|
||||
if (is_inline)
|
||||
kmem_cache_free(sbi->inline_xattr_slab, xattr_addr);
|
||||
else
|
||||
kvfree(xattr_addr);
|
||||
}
|
||||
|
||||
static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
|
||||
struct dentry *unused, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
@ -301,7 +320,8 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr)
|
||||
static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||
unsigned int index, unsigned int len,
|
||||
const char *name, struct f2fs_xattr_entry **xe,
|
||||
void **base_addr, int *base_size)
|
||||
void **base_addr, int *base_size,
|
||||
bool *is_inline)
|
||||
{
|
||||
void *cur_addr, *txattr_addr, *last_txattr_addr;
|
||||
void *last_addr = NULL;
|
||||
@ -312,12 +332,12 @@ static int lookup_all_xattrs(struct inode *inode, struct page *ipage,
|
||||
if (!xnid && !inline_size)
|
||||
return -ENODATA;
|
||||
|
||||
*base_size = XATTR_SIZE(xnid, inode) + XATTR_PADDING_SIZE;
|
||||
txattr_addr = f2fs_kzalloc(F2FS_I_SB(inode), *base_size, GFP_NOFS);
|
||||
*base_size = XATTR_SIZE(inode) + XATTR_PADDING_SIZE;
|
||||
txattr_addr = xattr_alloc(F2FS_I_SB(inode), *base_size, is_inline);
|
||||
if (!txattr_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(xnid, inode);
|
||||
last_txattr_addr = (void *)txattr_addr + XATTR_SIZE(inode);
|
||||
|
||||
/* read from inline xattr */
|
||||
if (inline_size) {
|
||||
@ -362,7 +382,7 @@ check:
|
||||
*base_addr = txattr_addr;
|
||||
return 0;
|
||||
out:
|
||||
kvfree(txattr_addr);
|
||||
xattr_free(F2FS_I_SB(inode), txattr_addr, *is_inline);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -499,6 +519,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
unsigned int size, len;
|
||||
void *base_addr = NULL;
|
||||
int base_size;
|
||||
bool is_inline;
|
||||
|
||||
if (name == NULL)
|
||||
return -EINVAL;
|
||||
@ -509,7 +530,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
|
||||
down_read(&F2FS_I(inode)->i_xattr_sem);
|
||||
error = lookup_all_xattrs(inode, ipage, index, len, name,
|
||||
&entry, &base_addr, &base_size);
|
||||
&entry, &base_addr, &base_size, &is_inline);
|
||||
up_read(&F2FS_I(inode)->i_xattr_sem);
|
||||
if (error)
|
||||
return error;
|
||||
@ -532,14 +553,13 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
|
||||
}
|
||||
error = size;
|
||||
out:
|
||||
kvfree(base_addr);
|
||||
xattr_free(F2FS_I_SB(inode), base_addr, is_inline);
|
||||
return error;
|
||||
}
|
||||
|
||||
ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
||||
struct f2fs_xattr_entry *entry;
|
||||
void *base_addr, *last_base_addr;
|
||||
int error = 0;
|
||||
@ -551,7 +571,7 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
|
||||
last_base_addr = (void *)base_addr + XATTR_SIZE(inode);
|
||||
|
||||
list_for_each_xattr(entry, base_addr) {
|
||||
const struct xattr_handler *handler =
|
||||
@ -609,7 +629,6 @@ static int __f2fs_setxattr(struct inode *inode, int index,
|
||||
{
|
||||
struct f2fs_xattr_entry *here, *last;
|
||||
void *base_addr, *last_base_addr;
|
||||
nid_t xnid = F2FS_I(inode)->i_xattr_nid;
|
||||
int found, newsize;
|
||||
size_t len;
|
||||
__u32 new_hsize;
|
||||
@ -633,7 +652,7 @@ static int __f2fs_setxattr(struct inode *inode, int index,
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
last_base_addr = (void *)base_addr + XATTR_SIZE(xnid, inode);
|
||||
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);
|
||||
@ -758,14 +777,34 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
/* protect xattr_ver */
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
down_write(&F2FS_I(inode)->i_xattr_sem);
|
||||
err = __f2fs_setxattr(inode, index, name, value, size, ipage, flags);
|
||||
up_write(&F2FS_I(inode)->i_xattr_sem);
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
return err;
|
||||
}
|
||||
|
||||
int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
char slab_name[32];
|
||||
|
||||
sprintf(slab_name, "f2fs_xattr_entry-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
|
||||
sbi->inline_xattr_slab_size = F2FS_OPTION(sbi).inline_xattr_size *
|
||||
sizeof(__le32) + XATTR_PADDING_SIZE;
|
||||
|
||||
sbi->inline_xattr_slab = f2fs_kmem_cache_create(slab_name,
|
||||
sbi->inline_xattr_slab_size);
|
||||
if (!sbi->inline_xattr_slab)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
kmem_cache_destroy(sbi->inline_xattr_slab);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ struct f2fs_xattr_entry {
|
||||
__u8 e_name_index;
|
||||
__u8 e_name_len;
|
||||
__le16 e_value_size; /* size of attribute value */
|
||||
char e_name[0]; /* attribute name */
|
||||
char e_name[]; /* attribute name */
|
||||
};
|
||||
|
||||
#define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr))
|
||||
@ -73,7 +73,8 @@ struct f2fs_xattr_entry {
|
||||
entry = XATTR_NEXT_ENTRY(entry))
|
||||
#define VALID_XATTR_BLOCK_SIZE (PAGE_SIZE - sizeof(struct node_footer))
|
||||
#define XATTR_PADDING_SIZE (sizeof(__u32))
|
||||
#define XATTR_SIZE(x,i) (((x) ? VALID_XATTR_BLOCK_SIZE : 0) + \
|
||||
#define XATTR_SIZE(i) ((F2FS_I(i)->i_xattr_nid ? \
|
||||
VALID_XATTR_BLOCK_SIZE : 0) + \
|
||||
(inline_xattr_size(i)))
|
||||
#define MIN_OFFSET(i) XATTR_ALIGN(inline_xattr_size(i) + \
|
||||
VALID_XATTR_BLOCK_SIZE)
|
||||
@ -130,6 +131,8 @@ extern int f2fs_setxattr(struct inode *, int, const char *,
|
||||
extern int f2fs_getxattr(struct inode *, int, const char *, void *,
|
||||
size_t, struct page *);
|
||||
extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
|
||||
extern int f2fs_init_xattr_caches(struct f2fs_sb_info *);
|
||||
extern void f2fs_destroy_xattr_caches(struct f2fs_sb_info *);
|
||||
#else
|
||||
|
||||
#define f2fs_xattr_handlers NULL
|
||||
@ -150,6 +153,8 @@ static inline ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer,
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int f2fs_init_xattr_caches(struct f2fs_sb_info *sbi) { return 0; }
|
||||
static inline void f2fs_destroy_xattr_caches(struct f2fs_sb_info *sbi) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_SECURITY
|
||||
|
@ -125,6 +125,7 @@ struct f2fs_super_block {
|
||||
/*
|
||||
* For checkpoint
|
||||
*/
|
||||
#define CP_RESIZEFS_FLAG 0x00004000
|
||||
#define CP_DISABLED_QUICK_FLAG 0x00002000
|
||||
#define CP_DISABLED_FLAG 0x00001000
|
||||
#define CP_QUOTA_NEED_FSCK_FLAG 0x00000800
|
||||
|
@ -153,7 +153,8 @@ TRACE_DEFINE_ENUM(CP_PAUSE);
|
||||
#define show_compress_algorithm(type) \
|
||||
__print_symbolic(type, \
|
||||
{ COMPRESS_LZO, "LZO" }, \
|
||||
{ COMPRESS_LZ4, "LZ4" })
|
||||
{ COMPRESS_LZ4, "LZ4" }, \
|
||||
{ COMPRESS_ZSTD, "ZSTD" })
|
||||
|
||||
struct f2fs_sb_info;
|
||||
struct f2fs_io_info;
|
||||
|
Loading…
Reference in New Issue
Block a user