2018-09-12 09:16:07 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2012-11-29 12:28:09 +08:00
|
|
|
/*
|
2012-11-02 16:09:44 +08:00
|
|
|
* fs/f2fs/file.c
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
|
|
|
* http://www.samsung.com/
|
|
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/f2fs_fs.h>
|
|
|
|
#include <linux/stat.h>
|
|
|
|
#include <linux/buffer_head.h>
|
|
|
|
#include <linux/writeback.h>
|
2013-03-16 10:13:04 +08:00
|
|
|
#include <linux/blkdev.h>
|
2012-11-02 16:09:44 +08:00
|
|
|
#include <linux/falloc.h>
|
|
|
|
#include <linux/types.h>
|
2013-02-04 22:41:41 +08:00
|
|
|
#include <linux/compat.h>
|
2012-11-02 16:09:44 +08:00
|
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <linux/mount.h>
|
2014-04-28 17:12:36 +08:00
|
|
|
#include <linux/pagevec.h>
|
2017-01-14 05:12:29 +08:00
|
|
|
#include <linux/uio.h>
|
2016-05-21 08:01:00 +08:00
|
|
|
#include <linux/uuid.h>
|
2016-07-09 06:16:47 +08:00
|
|
|
#include <linux/file.h>
|
2019-07-17 17:06:11 +08:00
|
|
|
#include <linux/nls.h>
|
2020-07-21 11:21:11 +08:00
|
|
|
#include <linux/sched/signal.h>
|
2021-04-07 20:36:43 +08:00
|
|
|
#include <linux/fileattr.h>
|
2021-08-03 12:22:45 +08:00
|
|
|
#include <linux/fadvise.h>
|
2021-07-23 15:59:21 +08:00
|
|
|
#include <linux/iomap.h>
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
#include "f2fs.h"
|
|
|
|
#include "node.h"
|
|
|
|
#include "segment.h"
|
|
|
|
#include "xattr.h"
|
|
|
|
#include "acl.h"
|
2015-07-10 18:08:10 +08:00
|
|
|
#include "gc.h"
|
2021-08-20 11:52:28 +08:00
|
|
|
#include "iostat.h"
|
2013-04-20 00:28:40 +08:00
|
|
|
#include <trace/events/f2fs.h>
|
2020-11-02 14:21:31 +08:00
|
|
|
#include <uapi/linux/f2fs.h>
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2018-04-15 04:10:02 +08:00
|
|
|
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
|
2017-05-18 11:06:45 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(vmf->vma->vm_file);
|
2018-04-15 04:10:02 +08:00
|
|
|
vm_fault_t ret;
|
2017-05-18 11:06:45 +08:00
|
|
|
|
2018-04-15 04:10:02 +08:00
|
|
|
ret = filemap_fault(vmf);
|
2020-04-16 18:16:56 +08:00
|
|
|
if (!ret)
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(F2FS_I_SB(inode), inode,
|
|
|
|
APP_MAPPED_READ_IO, F2FS_BLKSIZE);
|
2020-04-16 18:16:56 +08:00
|
|
|
|
2019-04-15 15:22:19 +08:00
|
|
|
trace_f2fs_filemap_fault(inode, vmf->pgoff, (unsigned long)ret);
|
|
|
|
|
2018-04-15 04:10:02 +08:00
|
|
|
return ret;
|
2017-05-18 11:06:45 +08:00
|
|
|
}
|
|
|
|
|
2018-04-15 04:10:02 +08:00
|
|
|
static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
|
|
|
struct page *page = vmf->page;
|
2017-02-25 06:56:41 +08:00
|
|
|
struct inode *inode = file_inode(vmf->vma->vm_file);
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2019-12-04 07:53:16 +08:00
|
|
|
struct dnode_of_data dn;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
bool need_alloc = true;
|
|
|
|
int err = 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2020-12-26 18:07:01 +08:00
|
|
|
if (unlikely(IS_IMMUTABLE(inode)))
|
|
|
|
return VM_FAULT_SIGBUS;
|
|
|
|
|
2021-05-26 02:39:35 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
|
|
|
return VM_FAULT_SIGBUS;
|
|
|
|
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(sbi))) {
|
|
|
|
err = -EIO;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2019-08-23 17:58:36 +08:00
|
|
|
if (!f2fs_is_checkpoint_ready(sbi)) {
|
|
|
|
err = -ENOSPC;
|
2019-07-22 17:57:05 +08:00
|
|
|
goto err;
|
2019-08-23 17:58:36 +08:00
|
|
|
}
|
2017-10-24 05:48:49 +08:00
|
|
|
|
2021-02-02 16:03:11 +08:00
|
|
|
err = f2fs_convert_inline_inode(inode);
|
|
|
|
if (err)
|
|
|
|
goto err;
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
|
|
|
if (f2fs_compressed_file(inode)) {
|
|
|
|
int ret = f2fs_is_compressed_cluster(inode, page->index);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
err = ret;
|
|
|
|
goto err;
|
|
|
|
} else if (ret) {
|
|
|
|
need_alloc = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2019-12-04 07:53:16 +08:00
|
|
|
/* should do out of any locked page */
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (need_alloc)
|
|
|
|
f2fs_balance_fs(sbi, true);
|
2019-12-04 07:53:16 +08:00
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
sb_start_pagefault(inode->i_sb);
|
2014-10-24 10:48:09 +08:00
|
|
|
|
|
|
|
f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
|
2014-08-08 07:32:25 +08:00
|
|
|
|
2017-02-25 06:56:41 +08:00
|
|
|
file_update_time(vmf->vma->vm_file);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock_shared(inode->i_mapping);
|
2012-11-02 16:09:44 +08:00
|
|
|
lock_page(page);
|
2013-12-06 14:00:58 +08:00
|
|
|
if (unlikely(page->mapping != inode->i_mapping ||
|
2013-04-28 08:04:18 +08:00
|
|
|
page_offset(page) > i_size_read(inode) ||
|
2013-12-06 14:00:58 +08:00
|
|
|
!PageUptodate(page))) {
|
2012-11-02 16:09:44 +08:00
|
|
|
unlock_page(page);
|
|
|
|
err = -EFAULT;
|
2017-05-18 11:06:45 +08:00
|
|
|
goto out_sem;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (need_alloc) {
|
|
|
|
/* block allocation */
|
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
2022-11-28 17:15:15 +08:00
|
|
|
err = f2fs_get_block_locked(&dn, page->index);
|
2018-09-27 18:33:18 +08:00
|
|
|
}
|
|
|
|
|
2020-03-02 17:34:27 +08:00
|
|
|
#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;
|
2018-09-27 18:33:18 +08:00
|
|
|
}
|
|
|
|
|
2018-12-25 17:43:42 +08:00
|
|
|
f2fs_wait_on_page_writeback(page, DATA, false, true);
|
2018-09-27 18:33:18 +08:00
|
|
|
|
|
|
|
/* wait for GCed page writeback via META_MAPPING */
|
|
|
|
f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
/*
|
|
|
|
* check to see if the page is mapped already (no holes)
|
|
|
|
*/
|
|
|
|
if (PageMappedToDisk(page))
|
2018-09-27 18:33:18 +08:00
|
|
|
goto out_sem;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
/* page is wholly or partially inside EOF */
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
if (((loff_t)(page->index + 1) << PAGE_SHIFT) >
|
2015-09-11 14:43:52 +08:00
|
|
|
i_size_read(inode)) {
|
2018-05-30 03:21:14 +08:00
|
|
|
loff_t offset;
|
2018-05-30 03:33:07 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
offset = i_size_read(inode) & ~PAGE_MASK;
|
|
|
|
zero_user_segment(page, offset, PAGE_SIZE);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
set_page_dirty(page);
|
|
|
|
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(sbi, inode, APP_MAPPED_IO, F2FS_BLKSIZE);
|
2018-10-05 13:17:39 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2017-08-02 23:21:48 +08:00
|
|
|
|
2013-10-25 13:26:31 +08:00
|
|
|
trace_f2fs_vm_page_mkwrite(page, DATA);
|
2017-05-18 11:06:45 +08:00
|
|
|
out_sem:
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock_shared(inode->i_mapping);
|
2018-09-27 18:33:18 +08:00
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
sb_end_pagefault(inode->i_sb);
|
2017-10-24 05:48:49 +08:00
|
|
|
err:
|
2023-08-02 01:21:57 +08:00
|
|
|
return vmf_fs_error(err);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct vm_operations_struct f2fs_file_vm_ops = {
|
2017-05-18 11:06:45 +08:00
|
|
|
.fault = f2fs_filemap_fault,
|
2014-04-08 06:37:19 +08:00
|
|
|
.map_pages = filemap_map_pages,
|
2013-01-17 17:37:41 +08:00
|
|
|
.page_mkwrite = f2fs_vm_page_mkwrite,
|
2012-11-02 16:09:44 +08:00
|
|
|
};
|
|
|
|
|
2013-06-14 07:52:35 +08:00
|
|
|
static int get_parent_ino(struct inode *inode, nid_t *pino)
|
|
|
|
{
|
|
|
|
struct dentry *dentry;
|
|
|
|
|
2020-05-06 02:41:11 +08:00
|
|
|
/*
|
|
|
|
* Make sure to get the non-deleted alias. The alias associated with
|
|
|
|
* the open file descriptor being fsync()'ed may be deleted already.
|
|
|
|
*/
|
|
|
|
dentry = d_find_alias(inode);
|
2013-06-14 07:52:35 +08:00
|
|
|
if (!dentry)
|
|
|
|
return 0;
|
|
|
|
|
2013-07-22 21:12:56 +08:00
|
|
|
*pino = parent_ino(dentry);
|
|
|
|
dput(dentry);
|
2013-06-14 07:52:35 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-11-06 22:51:45 +08:00
|
|
|
static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
|
2014-08-20 18:37:35 +08:00
|
|
|
{
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2017-11-06 22:51:45 +08:00
|
|
|
enum cp_reason_type cp_reason = CP_NO_NEEDED;
|
2014-08-20 18:37:35 +08:00
|
|
|
|
2017-11-06 22:51:45 +08:00
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
cp_reason = CP_NON_REGULAR;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
else if (f2fs_compressed_file(inode))
|
|
|
|
cp_reason = CP_COMPRESSED;
|
2017-11-06 22:51:45 +08:00
|
|
|
else if (inode->i_nlink != 1)
|
|
|
|
cp_reason = CP_HARDLINK;
|
2016-08-30 09:23:45 +08:00
|
|
|
else if (is_sbi_flag_set(sbi, SBI_NEED_CP))
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_SB_NEED_CP;
|
2014-08-20 18:37:35 +08:00
|
|
|
else if (file_wrong_pino(inode))
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_WRONG_PINO;
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
else if (!f2fs_space_for_roll_forward(sbi))
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_NO_SPC_ROLL;
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
else if (!f2fs_is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_NODE_NEED_CP;
|
2014-10-31 13:47:03 +08:00
|
|
|
else if (test_opt(sbi, FASTBOOT))
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_FASTBOOT_MODE;
|
2018-03-08 14:22:56 +08:00
|
|
|
else if (F2FS_OPTION(sbi).active_logs == 2)
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = CP_SPEC_LOG_NUM;
|
2018-03-08 14:22:56 +08:00
|
|
|
else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_need_dentry_mark(sbi, inode->i_ino) &&
|
|
|
|
f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino,
|
|
|
|
TRANS_DIR_INO))
|
2017-12-29 00:09:44 +08:00
|
|
|
cp_reason = CP_RECOVER_DIR;
|
2014-08-20 18:37:35 +08:00
|
|
|
|
2017-11-06 22:51:45 +08:00
|
|
|
return cp_reason;
|
2014-08-20 18:37:35 +08:00
|
|
|
}
|
|
|
|
|
2014-12-08 14:29:40 +08:00
|
|
|
static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
|
|
|
|
{
|
|
|
|
struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
|
|
|
|
bool ret = false;
|
|
|
|
/* But we need to avoid that there are some inode updates */
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino))
|
2014-12-08 14:29:40 +08:00
|
|
|
ret = true;
|
|
|
|
f2fs_put_page(i, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-08 14:29:41 +08:00
|
|
|
static void try_to_fix_pino(struct inode *inode)
|
|
|
|
{
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
nid_t pino;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&fi->i_sem);
|
2014-12-08 14:29:41 +08:00
|
|
|
if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
|
|
|
|
get_parent_ino(inode, &pino)) {
|
2016-05-21 00:52:20 +08:00
|
|
|
f2fs_i_pino_write(inode, pino);
|
2014-12-08 14:29:41 +08:00
|
|
|
file_got_pino(inode);
|
|
|
|
}
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&fi->i_sem);
|
2014-12-08 14:29:41 +08:00
|
|
|
}
|
|
|
|
|
2016-04-16 00:43:17 +08:00
|
|
|
static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
|
|
|
|
int datasync, bool atomic)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file->f_mapping->host;
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2014-09-11 05:58:18 +08:00
|
|
|
nid_t ino = inode->i_ino;
|
2012-11-02 16:09:44 +08:00
|
|
|
int ret = 0;
|
2017-11-06 22:51:45 +08:00
|
|
|
enum cp_reason_type cp_reason = 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
struct writeback_control wbc = {
|
2014-03-03 10:28:40 +08:00
|
|
|
.sync_mode = WB_SYNC_ALL,
|
2012-11-02 16:09:44 +08:00
|
|
|
.nr_to_write = LONG_MAX,
|
|
|
|
.for_reclaim = 0,
|
|
|
|
};
|
f2fs: fix to avoid broken of dnode block list
f2fs recovery flow is relying on dnode block link list, it means fsynced
file recovery depends on previous dnode's persistence in the list, so
during fsync() we should wait on all regular inode's dnode writebacked
before issuing flush.
By this way, we can avoid dnode block list being broken by out-of-order
IO submission due to IO scheduler or driver.
Sheng Yong helps to do the test with this patch:
Target:/data (f2fs, -)
64MB / 32768KB / 4KB / 8
1 / PERSIST / Index
Base:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 867.82 204.15 41440.03 41370.54 680.8 1025.94 1031.08
2 871.87 205.87 41370.3 40275.2 791.14 1065.84 1101.7
3 866.52 205.69 41795.67 40596.16 694.69 1037.16 1031.48
Avg 868.7366667 205.2366667 41535.33333 40747.3 722.21 1042.98 1054.753333
After:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 798.81 202.5 41143 40613.87 602.71 838.08 913.83
2 805.79 206.47 40297.2 41291.46 604.44 840.75 924.27
3 814.83 206.17 41209.57 40453.62 602.85 834.66 927.91
Avg 806.4766667 205.0466667 40883.25667 40786.31667 603.3333333 837.83 922.0033333
Patched/Original:
0.928332713 0.999074239 0.984300676 1.000957528 0.835398753 0.803303994 0.874141189
It looks like atomic write will suffer performance regression.
I suspect that the criminal is that we forcing to wait all dnode being in
storage cache before we issue PREFLUSH+FUA.
BTW, will commit ("f2fs: don't need to wait for node writes for atomic write")
cause the problem: we will lose data of last transaction after SPO, even if
atomic write return no error:
- atomic_open();
- write() P1, P2, P3;
- atomic_commit();
- writeback data: P1, P2, P3;
- writeback node: N1, N2, N3; <--- If N1, N2 is not writebacked, N3 with fsync_mark is
writebacked, In SPOR, we won't find N3 since node chain is broken, turns out that losing
last transaction.
- preflush + fua;
- power-cut
If we don't wait dnode writeback for atomic_write:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 779.91 206.03 41621.5 40333.16 716.9 1038.21 1034.85
2 848.51 204.35 40082.44 39486.17 791.83 1119.96 1083.77
3 772.12 206.27 41335.25 41599.65 723.29 1055.07 971.92
Avg 800.18 205.55 41013.06333 40472.99333 744.0066667 1071.08 1030.18
Patched/Original:
0.92108464 1.001526693 0.987425886 0.993268102 1.030180511 1.026942031 0.976702294
SQLite's performance recovers.
Jaegeuk:
"Practically, I don't see db corruption becase of this. We can excuse to lose
the last transaction."
Finally, we decide to keep original implementation of atomic write interface
sematics that we don't wait all dnode writeback before preflush+fua submission.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-02 23:03:19 +08:00
|
|
|
unsigned int seq_id = 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2021-08-20 05:00:57 +08:00
|
|
|
if (unlikely(f2fs_readonly(inode->i_sb)))
|
2012-12-01 09:56:01 +08:00
|
|
|
return 0;
|
|
|
|
|
2013-04-20 00:28:40 +08:00
|
|
|
trace_f2fs_sync_file_enter(inode);
|
2014-07-25 10:11:43 +08:00
|
|
|
|
2018-11-06 10:25:29 +08:00
|
|
|
if (S_ISDIR(inode->i_mode))
|
|
|
|
goto go_write;
|
|
|
|
|
2014-07-25 10:11:43 +08:00
|
|
|
/* if fdatasync is triggered, let's do in-place-update */
|
2016-01-01 05:49:17 +08:00
|
|
|
if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
|
2016-05-21 01:13:22 +08:00
|
|
|
set_inode_flag(inode, FI_NEED_IPU);
|
2017-07-08 03:20:52 +08:00
|
|
|
ret = file_write_and_wait_range(file, start, end);
|
2016-05-21 01:13:22 +08:00
|
|
|
clear_inode_flag(inode, FI_NEED_IPU);
|
2014-09-11 07:53:02 +08:00
|
|
|
|
2021-08-20 05:00:57 +08:00
|
|
|
if (ret || is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
|
2017-11-06 22:51:45 +08:00
|
|
|
trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
|
2012-11-02 16:09:44 +08:00
|
|
|
return ret;
|
2013-04-20 00:28:40 +08:00
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2014-12-08 14:29:40 +08:00
|
|
|
/* if the inode is dirty, let's recover all the time */
|
2016-11-17 20:53:31 +08:00
|
|
|
if (!f2fs_skip_inode_update(inode, datasync)) {
|
2015-08-16 12:51:05 +08:00
|
|
|
f2fs_write_inode(inode, NULL);
|
2014-12-08 14:29:40 +08:00
|
|
|
goto go_write;
|
|
|
|
}
|
|
|
|
|
2014-07-25 10:08:02 +08:00
|
|
|
/*
|
|
|
|
* if there is no written data, don't waste time to write recovery info.
|
|
|
|
*/
|
2016-05-21 01:13:22 +08:00
|
|
|
if (!is_inode_flag_set(inode, FI_APPEND_WRITE) &&
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
!f2fs_exist_written_data(sbi, ino, APPEND_INO)) {
|
2014-09-11 06:04:03 +08:00
|
|
|
|
2014-12-08 14:29:40 +08:00
|
|
|
/* it may call write_inode just prior to fsync */
|
|
|
|
if (need_inode_page_update(sbi, ino))
|
2014-09-11 06:04:03 +08:00
|
|
|
goto go_write;
|
|
|
|
|
2016-05-21 01:13:22 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_UPDATE_WRITE) ||
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_exist_written_data(sbi, ino, UPDATE_INO))
|
2014-07-25 10:08:02 +08:00
|
|
|
goto flush_out;
|
|
|
|
goto out;
|
f2fs: fix to force keeping write barrier for strict fsync mode
[1] https://www.mail-archive.com/linux-f2fs-devel@lists.sourceforge.net/msg15126.html
As [1] reported, if lower device doesn't support write barrier, in below
case:
- write page #0; persist
- overwrite page #0
- fsync
- write data page #0 OPU into device's cache
- write inode page into device's cache
- issue flush
If SPO is triggered during flush command, inode page can be persisted
before data page #0, so that after recovery, inode page can be recovered
with new physical block address of data page #0, however there may
contains dummy data in new physical block address.
Then what user will see is: after overwrite & fsync + SPO, old data in
file was corrupted, if any user do care about such case, we can suggest
user to use STRICT fsync mode, in this mode, we will force to use atomic
write sematics to keep write order in between data/node and last node,
so that it avoids potential data corruption during fsync().
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2021-07-20 09:03:29 +08:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* for OPU case, during fsync(), node can be persisted before
|
|
|
|
* data when lower device doesn't support write barrier, result
|
|
|
|
* in data corruption after SPO.
|
2023-02-06 19:56:00 +08:00
|
|
|
* So for strict fsync mode, force to use atomic write semantics
|
f2fs: fix to force keeping write barrier for strict fsync mode
[1] https://www.mail-archive.com/linux-f2fs-devel@lists.sourceforge.net/msg15126.html
As [1] reported, if lower device doesn't support write barrier, in below
case:
- write page #0; persist
- overwrite page #0
- fsync
- write data page #0 OPU into device's cache
- write inode page into device's cache
- issue flush
If SPO is triggered during flush command, inode page can be persisted
before data page #0, so that after recovery, inode page can be recovered
with new physical block address of data page #0, however there may
contains dummy data in new physical block address.
Then what user will see is: after overwrite & fsync + SPO, old data in
file was corrupted, if any user do care about such case, we can suggest
user to use STRICT fsync mode, in this mode, we will force to use atomic
write sematics to keep write order in between data/node and last node,
so that it avoids potential data corruption during fsync().
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2021-07-20 09:03:29 +08:00
|
|
|
* to keep write order in between data/node and last node to
|
|
|
|
* avoid potential data corruption.
|
|
|
|
*/
|
|
|
|
if (F2FS_OPTION(sbi).fsync_mode ==
|
|
|
|
FSYNC_MODE_STRICT && !atomic)
|
|
|
|
atomic = true;
|
2014-07-25 10:08:02 +08:00
|
|
|
}
|
2014-09-11 06:04:03 +08:00
|
|
|
go_write:
|
2013-07-03 09:55:52 +08:00
|
|
|
/*
|
|
|
|
* Both of fdatasync() and fsync() are able to be recovered from
|
|
|
|
* sudden-power-off.
|
|
|
|
*/
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_read(&F2FS_I(inode)->i_sem);
|
2017-11-06 22:51:45 +08:00
|
|
|
cp_reason = need_do_checkpoint(inode);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_read(&F2FS_I(inode)->i_sem);
|
2014-03-20 18:10:08 +08:00
|
|
|
|
2017-11-06 22:51:45 +08:00
|
|
|
if (cp_reason) {
|
2012-11-02 16:09:44 +08:00
|
|
|
/* all the dirty node pages should be flushed for POR */
|
|
|
|
ret = f2fs_sync_fs(inode->i_sb, 1);
|
2014-03-20 18:10:08 +08:00
|
|
|
|
2014-12-08 14:29:41 +08:00
|
|
|
/*
|
|
|
|
* We've secured consistency through sync_fs. Following pino
|
|
|
|
* will be used only for fsynced inodes after checkpoint.
|
|
|
|
*/
|
|
|
|
try_to_fix_pino(inode);
|
2016-05-21 01:13:22 +08:00
|
|
|
clear_inode_flag(inode, FI_APPEND_WRITE);
|
|
|
|
clear_inode_flag(inode, FI_UPDATE_WRITE);
|
2014-12-08 14:29:41 +08:00
|
|
|
goto out;
|
|
|
|
}
|
f2fs: fix conditions to remain recovery information in f2fs_sync_file
This patch revisited whole the recovery information during the f2fs_sync_file.
In this patch, there are three information to make a decision.
a) IS_CHECKPOINTED, /* is it checkpointed before? */
b) HAS_FSYNCED_INODE, /* is the inode fsynced before? */
c) HAS_LAST_FSYNC, /* has the latest node fsync mark? */
And, the scenarios for our rule are based on:
[Term] F: fsync_mark, D: dentry_mark
1. inode(x) | CP | inode(x) | dnode(F)
2. inode(x) | CP | inode(F) | dnode(F)
3. inode(x) | CP | dnode(F) | inode(x) | inode(F)
4. inode(x) | CP | dnode(F) | inode(F)
5. CP | inode(x) | dnode(F) | inode(DF)
6. CP | inode(DF) | dnode(F)
7. CP | dnode(F) | inode(DF)
8. CP | dnode(F) | inode(x) | inode(DF)
For example, #3, the three conditions should be changed as follows.
inode(x) | CP | dnode(F) | inode(x) | inode(F)
a) x o o o o
b) x x x x o
c) x o o x o
If f2fs_sync_file stops ------^,
it should write inode(F) --------------^
So, the need_inode_block_update should return true, since
c) get_nat_flag(e, HAS_LAST_FSYNC), is false.
For example, #8,
CP | alloc | dnode(F) | inode(x) | inode(DF)
a) o x x x x
b) x x x o
c) o o x o
If f2fs_sync_file stops -------^,
it should write inode(DF) --------------^
Note that, the roll-forward policy should follow this rule, which means,
if there are any missing blocks, we doesn't need to recover that inode.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2014-09-16 05:50:48 +08:00
|
|
|
sync_nodes:
|
2018-06-04 23:20:36 +08:00
|
|
|
atomic_inc(&sbi->wb_sync_req[NODE]);
|
f2fs: fix to avoid broken of dnode block list
f2fs recovery flow is relying on dnode block link list, it means fsynced
file recovery depends on previous dnode's persistence in the list, so
during fsync() we should wait on all regular inode's dnode writebacked
before issuing flush.
By this way, we can avoid dnode block list being broken by out-of-order
IO submission due to IO scheduler or driver.
Sheng Yong helps to do the test with this patch:
Target:/data (f2fs, -)
64MB / 32768KB / 4KB / 8
1 / PERSIST / Index
Base:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 867.82 204.15 41440.03 41370.54 680.8 1025.94 1031.08
2 871.87 205.87 41370.3 40275.2 791.14 1065.84 1101.7
3 866.52 205.69 41795.67 40596.16 694.69 1037.16 1031.48
Avg 868.7366667 205.2366667 41535.33333 40747.3 722.21 1042.98 1054.753333
After:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 798.81 202.5 41143 40613.87 602.71 838.08 913.83
2 805.79 206.47 40297.2 41291.46 604.44 840.75 924.27
3 814.83 206.17 41209.57 40453.62 602.85 834.66 927.91
Avg 806.4766667 205.0466667 40883.25667 40786.31667 603.3333333 837.83 922.0033333
Patched/Original:
0.928332713 0.999074239 0.984300676 1.000957528 0.835398753 0.803303994 0.874141189
It looks like atomic write will suffer performance regression.
I suspect that the criminal is that we forcing to wait all dnode being in
storage cache before we issue PREFLUSH+FUA.
BTW, will commit ("f2fs: don't need to wait for node writes for atomic write")
cause the problem: we will lose data of last transaction after SPO, even if
atomic write return no error:
- atomic_open();
- write() P1, P2, P3;
- atomic_commit();
- writeback data: P1, P2, P3;
- writeback node: N1, N2, N3; <--- If N1, N2 is not writebacked, N3 with fsync_mark is
writebacked, In SPOR, we won't find N3 since node chain is broken, turns out that losing
last transaction.
- preflush + fua;
- power-cut
If we don't wait dnode writeback for atomic_write:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 779.91 206.03 41621.5 40333.16 716.9 1038.21 1034.85
2 848.51 204.35 40082.44 39486.17 791.83 1119.96 1083.77
3 772.12 206.27 41335.25 41599.65 723.29 1055.07 971.92
Avg 800.18 205.55 41013.06333 40472.99333 744.0066667 1071.08 1030.18
Patched/Original:
0.92108464 1.001526693 0.987425886 0.993268102 1.030180511 1.026942031 0.976702294
SQLite's performance recovers.
Jaegeuk:
"Practically, I don't see db corruption becase of this. We can excuse to lose
the last transaction."
Finally, we decide to keep original implementation of atomic write interface
sematics that we don't wait all dnode writeback before preflush+fua submission.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-02 23:03:19 +08:00
|
|
|
ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic, &seq_id);
|
2018-06-04 23:20:36 +08:00
|
|
|
atomic_dec(&sbi->wb_sync_req[NODE]);
|
2016-04-16 00:25:04 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
2014-12-08 14:29:41 +08:00
|
|
|
|
2015-01-10 08:27:17 +08:00
|
|
|
/* if cp_error was enabled, we should avoid infinite loop */
|
2015-12-24 18:04:56 +08:00
|
|
|
if (unlikely(f2fs_cp_error(sbi))) {
|
|
|
|
ret = -EIO;
|
2015-01-10 08:27:17 +08:00
|
|
|
goto out;
|
2015-12-24 18:04:56 +08:00
|
|
|
}
|
2015-01-10 08:27:17 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
if (f2fs_need_inode_block_update(sbi, ino)) {
|
2016-10-15 02:51:23 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
2014-12-08 14:29:41 +08:00
|
|
|
f2fs_write_inode(inode, NULL);
|
|
|
|
goto sync_nodes;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
2014-12-08 14:29:41 +08:00
|
|
|
|
2017-07-28 17:29:12 +08:00
|
|
|
/*
|
|
|
|
* If it's atomic_write, it's just fine to keep write ordering. So
|
|
|
|
* here we don't need to wait for node write completion, since we use
|
|
|
|
* node chain which serializes node blocks. If one of node writes are
|
|
|
|
* reordered, we can see simply broken chain, resulting in stopping
|
|
|
|
* roll-forward recovery. It means we'll recover all or none node blocks
|
|
|
|
* given fsync mark.
|
|
|
|
*/
|
|
|
|
if (!atomic) {
|
f2fs: fix to avoid broken of dnode block list
f2fs recovery flow is relying on dnode block link list, it means fsynced
file recovery depends on previous dnode's persistence in the list, so
during fsync() we should wait on all regular inode's dnode writebacked
before issuing flush.
By this way, we can avoid dnode block list being broken by out-of-order
IO submission due to IO scheduler or driver.
Sheng Yong helps to do the test with this patch:
Target:/data (f2fs, -)
64MB / 32768KB / 4KB / 8
1 / PERSIST / Index
Base:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 867.82 204.15 41440.03 41370.54 680.8 1025.94 1031.08
2 871.87 205.87 41370.3 40275.2 791.14 1065.84 1101.7
3 866.52 205.69 41795.67 40596.16 694.69 1037.16 1031.48
Avg 868.7366667 205.2366667 41535.33333 40747.3 722.21 1042.98 1054.753333
After:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 798.81 202.5 41143 40613.87 602.71 838.08 913.83
2 805.79 206.47 40297.2 41291.46 604.44 840.75 924.27
3 814.83 206.17 41209.57 40453.62 602.85 834.66 927.91
Avg 806.4766667 205.0466667 40883.25667 40786.31667 603.3333333 837.83 922.0033333
Patched/Original:
0.928332713 0.999074239 0.984300676 1.000957528 0.835398753 0.803303994 0.874141189
It looks like atomic write will suffer performance regression.
I suspect that the criminal is that we forcing to wait all dnode being in
storage cache before we issue PREFLUSH+FUA.
BTW, will commit ("f2fs: don't need to wait for node writes for atomic write")
cause the problem: we will lose data of last transaction after SPO, even if
atomic write return no error:
- atomic_open();
- write() P1, P2, P3;
- atomic_commit();
- writeback data: P1, P2, P3;
- writeback node: N1, N2, N3; <--- If N1, N2 is not writebacked, N3 with fsync_mark is
writebacked, In SPOR, we won't find N3 since node chain is broken, turns out that losing
last transaction.
- preflush + fua;
- power-cut
If we don't wait dnode writeback for atomic_write:
SEQ-RD(MB/s) SEQ-WR(MB/s) RND-RD(IOPS) RND-WR(IOPS) Insert(TPS) Update(TPS) Delete(TPS)
1 779.91 206.03 41621.5 40333.16 716.9 1038.21 1034.85
2 848.51 204.35 40082.44 39486.17 791.83 1119.96 1083.77
3 772.12 206.27 41335.25 41599.65 723.29 1055.07 971.92
Avg 800.18 205.55 41013.06333 40472.99333 744.0066667 1071.08 1030.18
Patched/Original:
0.92108464 1.001526693 0.987425886 0.993268102 1.030180511 1.026942031 0.976702294
SQLite's performance recovers.
Jaegeuk:
"Practically, I don't see db corruption becase of this. We can excuse to lose
the last transaction."
Finally, we decide to keep original implementation of atomic write interface
sematics that we don't wait all dnode writeback before preflush+fua submission.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-02 23:03:19 +08:00
|
|
|
ret = f2fs_wait_on_node_pages_writeback(sbi, seq_id);
|
2017-07-28 17:29:12 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
2014-12-08 14:29:41 +08:00
|
|
|
|
|
|
|
/* once recovery info is written, don't need to tack this */
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_remove_ino_entry(sbi, ino, APPEND_INO);
|
2016-05-21 01:13:22 +08:00
|
|
|
clear_inode_flag(inode, FI_APPEND_WRITE);
|
2014-12-08 14:29:41 +08:00
|
|
|
flush_out:
|
2022-04-19 07:57:44 +08:00
|
|
|
if ((!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER) ||
|
|
|
|
(atomic && !test_opt(sbi, NOBARRIER) && f2fs_sb_has_blkzoned(sbi)))
|
2017-09-29 13:59:38 +08:00
|
|
|
ret = f2fs_issue_flush(sbi, inode->i_ino);
|
2017-09-29 13:59:36 +08:00
|
|
|
if (!ret) {
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_remove_ino_entry(sbi, ino, UPDATE_INO);
|
2017-09-29 13:59:36 +08:00
|
|
|
clear_inode_flag(inode, FI_UPDATE_WRITE);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_remove_ino_entry(sbi, ino, FLUSH_INO);
|
2017-09-29 13:59:36 +08:00
|
|
|
}
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2012-11-02 16:09:44 +08:00
|
|
|
out:
|
2017-11-06 22:51:45 +08:00
|
|
|
trace_f2fs_sync_file_exit(inode, cp_reason, datasync, ret);
|
2012-11-02 16:09:44 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-04-16 00:43:17 +08:00
|
|
|
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|
|
|
{
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
|
|
|
|
return -EIO;
|
2016-04-16 00:43:17 +08:00
|
|
|
return f2fs_do_sync_file(file, start, end, datasync, false);
|
|
|
|
}
|
|
|
|
|
2020-08-25 05:48:41 +08:00
|
|
|
static bool __found_offset(struct address_space *mapping, block_t blkaddr,
|
|
|
|
pgoff_t index, int whence)
|
2014-04-28 17:12:36 +08:00
|
|
|
{
|
|
|
|
switch (whence) {
|
|
|
|
case SEEK_DATA:
|
2020-08-25 05:48:41 +08:00
|
|
|
if (__is_valid_data_blkaddr(blkaddr))
|
|
|
|
return true;
|
|
|
|
if (blkaddr == NEW_ADDR &&
|
|
|
|
xa_get_mark(&mapping->i_pages, index, PAGECACHE_TAG_DIRTY))
|
2014-04-28 17:12:36 +08:00
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case SEEK_HOLE:
|
|
|
|
if (blkaddr == NULL_ADDR)
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-04-23 14:10:24 +08:00
|
|
|
static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
|
|
|
|
{
|
|
|
|
struct inode *inode = file->f_mapping->host;
|
|
|
|
loff_t maxbytes = inode->i_sb->s_maxbytes;
|
|
|
|
struct dnode_of_data dn;
|
2020-08-25 05:48:41 +08:00
|
|
|
pgoff_t pgofs, end_offset;
|
2014-04-28 17:12:36 +08:00
|
|
|
loff_t data_ofs = offset;
|
|
|
|
loff_t isize;
|
2014-04-23 14:10:24 +08:00
|
|
|
int err = 0;
|
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock(inode);
|
2014-04-23 14:10:24 +08:00
|
|
|
|
|
|
|
isize = i_size_read(inode);
|
|
|
|
if (offset >= isize)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* handle inline data case */
|
2020-11-02 17:36:58 +08:00
|
|
|
if (f2fs_has_inline_data(inode)) {
|
|
|
|
if (whence == SEEK_HOLE) {
|
|
|
|
data_ofs = isize;
|
|
|
|
goto found;
|
|
|
|
} else if (whence == SEEK_DATA) {
|
|
|
|
data_ofs = offset;
|
|
|
|
goto found;
|
|
|
|
}
|
2014-04-23 14:10:24 +08:00
|
|
|
}
|
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pgofs = (pgoff_t)(offset >> PAGE_SHIFT);
|
2014-04-23 14:10:24 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
|
2014-04-23 14:10:24 +08:00
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
|
2014-04-23 14:10:24 +08:00
|
|
|
if (err && err != -ENOENT) {
|
|
|
|
goto fail;
|
|
|
|
} else if (err == -ENOENT) {
|
2014-08-06 22:22:50 +08:00
|
|
|
/* direct node does not exists */
|
2014-04-23 14:10:24 +08:00
|
|
|
if (whence == SEEK_DATA) {
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
pgofs = f2fs_get_next_page_offset(&dn, pgofs);
|
2014-04-23 14:10:24 +08:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-26 15:39:35 +08:00
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
2014-04-23 14:10:24 +08:00
|
|
|
|
|
|
|
/* find data/hole in dnode block */
|
|
|
|
for (; dn.ofs_in_node < end_offset;
|
|
|
|
dn.ofs_in_node++, pgofs++,
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
|
2014-04-23 14:10:24 +08:00
|
|
|
block_t blkaddr;
|
2018-05-30 03:33:07 +08:00
|
|
|
|
2020-02-14 17:44:10 +08:00
|
|
|
blkaddr = f2fs_data_blkaddr(&dn);
|
2014-04-23 14:10:24 +08:00
|
|
|
|
f2fs: fix to do sanity check with block address in main area
This patch add to do sanity check with below field:
- cp_pack_total_block_count
- blkaddr of data/node
- extent info
- Overview
BUG() in verify_block_addr() when writing to a corrupted f2fs image
- Reproduce (4.18 upstream kernel)
- POC (poc.c)
static void activity(char *mpoint) {
char *foo_bar_baz;
int err;
static int buf[8192];
memset(buf, 0, sizeof(buf));
err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, (char *)buf, sizeof(buf));
fdatasync(fd);
close(fd);
}
}
int main(int argc, char *argv[]) {
activity(argv[1]);
return 0;
}
- Kernel message
[ 689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
[ 699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
[ 699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
[ 699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
[ 699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
[ 699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
[ 699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
[ 699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
[ 699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
[ 699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
[ 699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
[ 699.729154] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.729156] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.729171] Call Trace:
[ 699.729192] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.729203] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.729238] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.729269] ? __radix_tree_replace+0xa3/0x120
[ 699.729276] __write_data_page+0x5c7/0xe30
[ 699.729291] ? kasan_check_read+0x11/0x20
[ 699.729310] ? page_mapped+0x8a/0x110
[ 699.729321] ? page_mkclean+0xe9/0x160
[ 699.729327] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.729331] ? invalid_page_referenced_vma+0x130/0x130
[ 699.729345] ? clear_page_dirty_for_io+0x332/0x450
[ 699.729351] f2fs_write_cache_pages+0x4ca/0x860
[ 699.729358] ? __write_data_page+0xe30/0xe30
[ 699.729374] ? percpu_counter_add_batch+0x22/0xa0
[ 699.729380] ? kasan_check_write+0x14/0x20
[ 699.729391] ? _raw_spin_lock+0x17/0x40
[ 699.729403] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.729413] ? iov_iter_advance+0x113/0x640
[ 699.729418] ? f2fs_write_end+0x133/0x2e0
[ 699.729423] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.729428] f2fs_write_data_pages+0x329/0x520
[ 699.729433] ? generic_perform_write+0x250/0x320
[ 699.729438] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729454] ? current_time+0x110/0x110
[ 699.729459] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.729464] do_writepages+0x37/0xb0
[ 699.729468] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729472] ? do_writepages+0x37/0xb0
[ 699.729478] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.729483] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.729496] ? __vfs_write+0x2b2/0x410
[ 699.729501] file_write_and_wait_range+0x66/0xb0
[ 699.729506] f2fs_do_sync_file+0x1f9/0xd90
[ 699.729511] ? truncate_partial_data_page+0x290/0x290
[ 699.729521] ? __sb_end_write+0x30/0x50
[ 699.729526] ? vfs_write+0x20f/0x260
[ 699.729530] f2fs_sync_file+0x9a/0xb0
[ 699.729534] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.729548] vfs_fsync_range+0x68/0x100
[ 699.729554] ? __fget_light+0xc9/0xe0
[ 699.729558] do_fsync+0x3d/0x70
[ 699.729562] __x64_sys_fdatasync+0x24/0x30
[ 699.729585] do_syscall_64+0x78/0x170
[ 699.729595] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.729613] RIP: 0033:0x7f9bf930d800
[ 699.729615] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
[ 699.729782] ------------[ cut here ]------------
[ 699.729785] kernel BUG at fs/f2fs/segment.h:654!
[ 699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
[ 699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G W 4.18.0-rc1+ #4
[ 699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.748683] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.750293] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.752874] Call Trace:
[ 699.753386] ? f2fs_inplace_write_data+0x93/0x240
[ 699.754341] f2fs_inplace_write_data+0xd2/0x240
[ 699.755271] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.756214] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.757215] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.758209] ? __radix_tree_replace+0xa3/0x120
[ 699.759164] __write_data_page+0x5c7/0xe30
[ 699.760002] ? kasan_check_read+0x11/0x20
[ 699.760823] ? page_mapped+0x8a/0x110
[ 699.761573] ? page_mkclean+0xe9/0x160
[ 699.762345] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.763332] ? invalid_page_referenced_vma+0x130/0x130
[ 699.764374] ? clear_page_dirty_for_io+0x332/0x450
[ 699.765347] f2fs_write_cache_pages+0x4ca/0x860
[ 699.766276] ? __write_data_page+0xe30/0xe30
[ 699.767161] ? percpu_counter_add_batch+0x22/0xa0
[ 699.768112] ? kasan_check_write+0x14/0x20
[ 699.768951] ? _raw_spin_lock+0x17/0x40
[ 699.769739] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.770885] ? iov_iter_advance+0x113/0x640
[ 699.771743] ? f2fs_write_end+0x133/0x2e0
[ 699.772569] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.773680] f2fs_write_data_pages+0x329/0x520
[ 699.774603] ? generic_perform_write+0x250/0x320
[ 699.775544] ? f2fs_write_cache_pages+0x860/0x860
[ 699.776510] ? current_time+0x110/0x110
[ 699.777299] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.778279] do_writepages+0x37/0xb0
[ 699.779026] ? f2fs_write_cache_pages+0x860/0x860
[ 699.779978] ? do_writepages+0x37/0xb0
[ 699.780755] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.781746] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.782820] ? __vfs_write+0x2b2/0x410
[ 699.783597] file_write_and_wait_range+0x66/0xb0
[ 699.784540] f2fs_do_sync_file+0x1f9/0xd90
[ 699.785381] ? truncate_partial_data_page+0x290/0x290
[ 699.786415] ? __sb_end_write+0x30/0x50
[ 699.787204] ? vfs_write+0x20f/0x260
[ 699.787941] f2fs_sync_file+0x9a/0xb0
[ 699.788694] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.789572] vfs_fsync_range+0x68/0x100
[ 699.790360] ? __fget_light+0xc9/0xe0
[ 699.791128] do_fsync+0x3d/0x70
[ 699.791779] __x64_sys_fdatasync+0x24/0x30
[ 699.792614] do_syscall_64+0x78/0x170
[ 699.793371] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.794406] RIP: 0033:0x7f9bf930d800
[ 699.795134] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
[ 699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.831192] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.832793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.835556] ==================================================================
[ 699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
[ 699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
[ 699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G D W 4.18.0-rc1+ #4
[ 699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.843475] Call Trace:
[ 699.843982] dump_stack+0x7b/0xb5
[ 699.844661] print_address_description+0x70/0x290
[ 699.845607] kasan_report+0x291/0x390
[ 699.846351] ? update_stack_state+0x38c/0x3e0
[ 699.853831] __asan_load8+0x54/0x90
[ 699.854569] update_stack_state+0x38c/0x3e0
[ 699.855428] ? __read_once_size_nocheck.constprop.7+0x20/0x20
[ 699.856601] ? __save_stack_trace+0x5e/0x100
[ 699.857476] unwind_next_frame.part.5+0x18e/0x490
[ 699.858448] ? unwind_dump+0x290/0x290
[ 699.859217] ? clear_page_dirty_for_io+0x332/0x450
[ 699.860185] __unwind_start+0x106/0x190
[ 699.860974] __save_stack_trace+0x5e/0x100
[ 699.861808] ? __save_stack_trace+0x5e/0x100
[ 699.862691] ? unlink_anon_vmas+0xba/0x2c0
[ 699.863525] save_stack_trace+0x1f/0x30
[ 699.864312] save_stack+0x46/0xd0
[ 699.864993] ? __alloc_pages_slowpath+0x1420/0x1420
[ 699.865990] ? flush_tlb_mm_range+0x15e/0x220
[ 699.866889] ? kasan_check_write+0x14/0x20
[ 699.867724] ? __dec_node_state+0x92/0xb0
[ 699.868543] ? lock_page_memcg+0x85/0xf0
[ 699.869350] ? unlock_page_memcg+0x16/0x80
[ 699.870185] ? page_remove_rmap+0x198/0x520
[ 699.871048] ? mark_page_accessed+0x133/0x200
[ 699.871930] ? _cond_resched+0x1a/0x50
[ 699.872700] ? unmap_page_range+0xcd4/0xe50
[ 699.873551] ? rb_next+0x58/0x80
[ 699.874217] ? rb_next+0x58/0x80
[ 699.874895] __kasan_slab_free+0x13c/0x1a0
[ 699.875734] ? unlink_anon_vmas+0xba/0x2c0
[ 699.876563] kasan_slab_free+0xe/0x10
[ 699.877315] kmem_cache_free+0x89/0x1e0
[ 699.878095] unlink_anon_vmas+0xba/0x2c0
[ 699.878913] free_pgtables+0x101/0x1b0
[ 699.879677] exit_mmap+0x146/0x2a0
[ 699.880378] ? __ia32_sys_munmap+0x50/0x50
[ 699.881214] ? kasan_check_read+0x11/0x20
[ 699.882052] ? mm_update_next_owner+0x322/0x380
[ 699.882985] mmput+0x8b/0x1d0
[ 699.883602] do_exit+0x43a/0x1390
[ 699.884288] ? mm_update_next_owner+0x380/0x380
[ 699.885212] ? f2fs_sync_file+0x9a/0xb0
[ 699.885995] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.886877] ? vfs_fsync_range+0x68/0x100
[ 699.887694] ? __fget_light+0xc9/0xe0
[ 699.888442] ? do_fsync+0x3d/0x70
[ 699.889118] ? __x64_sys_fdatasync+0x24/0x30
[ 699.889996] rewind_stack_do_exit+0x17/0x20
[ 699.890860] RIP: 0033:0x7f9bf930d800
[ 699.891585] Code: Bad RIP value.
[ 699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.901241] The buggy address belongs to the page:
[ 699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
[ 699.903811] flags: 0x2ffff0000000000()
[ 699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
[ 699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
[ 699.907673] page dumped because: kasan: bad access detected
[ 699.909108] Memory state around the buggy address:
[ 699.910077] ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
[ 699.911528] ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
[ 699.914392] ^
[ 699.915758] ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
[ 699.917193] ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
[ 699.918634] ==================================================================
- Location
https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
Reported-by Wen Xu <wen.xu@gatech.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-01 19:13:44 +08:00
|
|
|
if (__is_valid_data_blkaddr(blkaddr) &&
|
|
|
|
!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
|
f2fs: introduce DATA_GENERIC_ENHANCE
Previously, f2fs_is_valid_blkaddr(, blkaddr, DATA_GENERIC) will check
whether @blkaddr locates in main area or not.
That check is weak, since the block address in range of main area can
point to the address which is not valid in segment info table, and we
can not detect such condition, we may suffer worse corruption as system
continues running.
So this patch introduce DATA_GENERIC_ENHANCE to enhance the sanity check
which trigger SIT bitmap check rather than only range check.
This patch did below changes as wel:
- set SBI_NEED_FSCK in f2fs_is_valid_blkaddr().
- get rid of is_valid_data_blkaddr() to avoid panic if blkaddr is invalid.
- introduce verify_fio_blkaddr() to wrap fio {new,old}_blkaddr validation check.
- spread blkaddr check in:
* f2fs_get_node_info()
* __read_out_blkaddrs()
* f2fs_submit_page_read()
* ra_data_block()
* do_recover_data()
This patch can fix bug reported from bugzilla below:
https://bugzilla.kernel.org/show_bug.cgi?id=203215
https://bugzilla.kernel.org/show_bug.cgi?id=203223
https://bugzilla.kernel.org/show_bug.cgi?id=203231
https://bugzilla.kernel.org/show_bug.cgi?id=203235
https://bugzilla.kernel.org/show_bug.cgi?id=203241
= Update by Jaegeuk Kim =
DATA_GENERIC_ENHANCE enhanced to validate block addresses on read/write paths.
But, xfstest/generic/446 compalins some generated kernel messages saying invalid
bitmap was detected when reading a block. The reaons is, when we get the
block addresses from extent_cache, there is no lock to synchronize it from
truncating the blocks in parallel.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-04-15 15:26:32 +08:00
|
|
|
blkaddr, DATA_GENERIC_ENHANCE)) {
|
f2fs: fix to do sanity check with block address in main area
This patch add to do sanity check with below field:
- cp_pack_total_block_count
- blkaddr of data/node
- extent info
- Overview
BUG() in verify_block_addr() when writing to a corrupted f2fs image
- Reproduce (4.18 upstream kernel)
- POC (poc.c)
static void activity(char *mpoint) {
char *foo_bar_baz;
int err;
static int buf[8192];
memset(buf, 0, sizeof(buf));
err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, (char *)buf, sizeof(buf));
fdatasync(fd);
close(fd);
}
}
int main(int argc, char *argv[]) {
activity(argv[1]);
return 0;
}
- Kernel message
[ 689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
[ 699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
[ 699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
[ 699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
[ 699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
[ 699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
[ 699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
[ 699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
[ 699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
[ 699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
[ 699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
[ 699.729154] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.729156] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.729171] Call Trace:
[ 699.729192] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.729203] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.729238] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.729269] ? __radix_tree_replace+0xa3/0x120
[ 699.729276] __write_data_page+0x5c7/0xe30
[ 699.729291] ? kasan_check_read+0x11/0x20
[ 699.729310] ? page_mapped+0x8a/0x110
[ 699.729321] ? page_mkclean+0xe9/0x160
[ 699.729327] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.729331] ? invalid_page_referenced_vma+0x130/0x130
[ 699.729345] ? clear_page_dirty_for_io+0x332/0x450
[ 699.729351] f2fs_write_cache_pages+0x4ca/0x860
[ 699.729358] ? __write_data_page+0xe30/0xe30
[ 699.729374] ? percpu_counter_add_batch+0x22/0xa0
[ 699.729380] ? kasan_check_write+0x14/0x20
[ 699.729391] ? _raw_spin_lock+0x17/0x40
[ 699.729403] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.729413] ? iov_iter_advance+0x113/0x640
[ 699.729418] ? f2fs_write_end+0x133/0x2e0
[ 699.729423] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.729428] f2fs_write_data_pages+0x329/0x520
[ 699.729433] ? generic_perform_write+0x250/0x320
[ 699.729438] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729454] ? current_time+0x110/0x110
[ 699.729459] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.729464] do_writepages+0x37/0xb0
[ 699.729468] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729472] ? do_writepages+0x37/0xb0
[ 699.729478] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.729483] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.729496] ? __vfs_write+0x2b2/0x410
[ 699.729501] file_write_and_wait_range+0x66/0xb0
[ 699.729506] f2fs_do_sync_file+0x1f9/0xd90
[ 699.729511] ? truncate_partial_data_page+0x290/0x290
[ 699.729521] ? __sb_end_write+0x30/0x50
[ 699.729526] ? vfs_write+0x20f/0x260
[ 699.729530] f2fs_sync_file+0x9a/0xb0
[ 699.729534] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.729548] vfs_fsync_range+0x68/0x100
[ 699.729554] ? __fget_light+0xc9/0xe0
[ 699.729558] do_fsync+0x3d/0x70
[ 699.729562] __x64_sys_fdatasync+0x24/0x30
[ 699.729585] do_syscall_64+0x78/0x170
[ 699.729595] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.729613] RIP: 0033:0x7f9bf930d800
[ 699.729615] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
[ 699.729782] ------------[ cut here ]------------
[ 699.729785] kernel BUG at fs/f2fs/segment.h:654!
[ 699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
[ 699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G W 4.18.0-rc1+ #4
[ 699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.748683] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.750293] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.752874] Call Trace:
[ 699.753386] ? f2fs_inplace_write_data+0x93/0x240
[ 699.754341] f2fs_inplace_write_data+0xd2/0x240
[ 699.755271] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.756214] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.757215] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.758209] ? __radix_tree_replace+0xa3/0x120
[ 699.759164] __write_data_page+0x5c7/0xe30
[ 699.760002] ? kasan_check_read+0x11/0x20
[ 699.760823] ? page_mapped+0x8a/0x110
[ 699.761573] ? page_mkclean+0xe9/0x160
[ 699.762345] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.763332] ? invalid_page_referenced_vma+0x130/0x130
[ 699.764374] ? clear_page_dirty_for_io+0x332/0x450
[ 699.765347] f2fs_write_cache_pages+0x4ca/0x860
[ 699.766276] ? __write_data_page+0xe30/0xe30
[ 699.767161] ? percpu_counter_add_batch+0x22/0xa0
[ 699.768112] ? kasan_check_write+0x14/0x20
[ 699.768951] ? _raw_spin_lock+0x17/0x40
[ 699.769739] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.770885] ? iov_iter_advance+0x113/0x640
[ 699.771743] ? f2fs_write_end+0x133/0x2e0
[ 699.772569] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.773680] f2fs_write_data_pages+0x329/0x520
[ 699.774603] ? generic_perform_write+0x250/0x320
[ 699.775544] ? f2fs_write_cache_pages+0x860/0x860
[ 699.776510] ? current_time+0x110/0x110
[ 699.777299] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.778279] do_writepages+0x37/0xb0
[ 699.779026] ? f2fs_write_cache_pages+0x860/0x860
[ 699.779978] ? do_writepages+0x37/0xb0
[ 699.780755] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.781746] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.782820] ? __vfs_write+0x2b2/0x410
[ 699.783597] file_write_and_wait_range+0x66/0xb0
[ 699.784540] f2fs_do_sync_file+0x1f9/0xd90
[ 699.785381] ? truncate_partial_data_page+0x290/0x290
[ 699.786415] ? __sb_end_write+0x30/0x50
[ 699.787204] ? vfs_write+0x20f/0x260
[ 699.787941] f2fs_sync_file+0x9a/0xb0
[ 699.788694] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.789572] vfs_fsync_range+0x68/0x100
[ 699.790360] ? __fget_light+0xc9/0xe0
[ 699.791128] do_fsync+0x3d/0x70
[ 699.791779] __x64_sys_fdatasync+0x24/0x30
[ 699.792614] do_syscall_64+0x78/0x170
[ 699.793371] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.794406] RIP: 0033:0x7f9bf930d800
[ 699.795134] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
[ 699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.831192] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.832793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.835556] ==================================================================
[ 699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
[ 699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
[ 699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G D W 4.18.0-rc1+ #4
[ 699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.843475] Call Trace:
[ 699.843982] dump_stack+0x7b/0xb5
[ 699.844661] print_address_description+0x70/0x290
[ 699.845607] kasan_report+0x291/0x390
[ 699.846351] ? update_stack_state+0x38c/0x3e0
[ 699.853831] __asan_load8+0x54/0x90
[ 699.854569] update_stack_state+0x38c/0x3e0
[ 699.855428] ? __read_once_size_nocheck.constprop.7+0x20/0x20
[ 699.856601] ? __save_stack_trace+0x5e/0x100
[ 699.857476] unwind_next_frame.part.5+0x18e/0x490
[ 699.858448] ? unwind_dump+0x290/0x290
[ 699.859217] ? clear_page_dirty_for_io+0x332/0x450
[ 699.860185] __unwind_start+0x106/0x190
[ 699.860974] __save_stack_trace+0x5e/0x100
[ 699.861808] ? __save_stack_trace+0x5e/0x100
[ 699.862691] ? unlink_anon_vmas+0xba/0x2c0
[ 699.863525] save_stack_trace+0x1f/0x30
[ 699.864312] save_stack+0x46/0xd0
[ 699.864993] ? __alloc_pages_slowpath+0x1420/0x1420
[ 699.865990] ? flush_tlb_mm_range+0x15e/0x220
[ 699.866889] ? kasan_check_write+0x14/0x20
[ 699.867724] ? __dec_node_state+0x92/0xb0
[ 699.868543] ? lock_page_memcg+0x85/0xf0
[ 699.869350] ? unlock_page_memcg+0x16/0x80
[ 699.870185] ? page_remove_rmap+0x198/0x520
[ 699.871048] ? mark_page_accessed+0x133/0x200
[ 699.871930] ? _cond_resched+0x1a/0x50
[ 699.872700] ? unmap_page_range+0xcd4/0xe50
[ 699.873551] ? rb_next+0x58/0x80
[ 699.874217] ? rb_next+0x58/0x80
[ 699.874895] __kasan_slab_free+0x13c/0x1a0
[ 699.875734] ? unlink_anon_vmas+0xba/0x2c0
[ 699.876563] kasan_slab_free+0xe/0x10
[ 699.877315] kmem_cache_free+0x89/0x1e0
[ 699.878095] unlink_anon_vmas+0xba/0x2c0
[ 699.878913] free_pgtables+0x101/0x1b0
[ 699.879677] exit_mmap+0x146/0x2a0
[ 699.880378] ? __ia32_sys_munmap+0x50/0x50
[ 699.881214] ? kasan_check_read+0x11/0x20
[ 699.882052] ? mm_update_next_owner+0x322/0x380
[ 699.882985] mmput+0x8b/0x1d0
[ 699.883602] do_exit+0x43a/0x1390
[ 699.884288] ? mm_update_next_owner+0x380/0x380
[ 699.885212] ? f2fs_sync_file+0x9a/0xb0
[ 699.885995] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.886877] ? vfs_fsync_range+0x68/0x100
[ 699.887694] ? __fget_light+0xc9/0xe0
[ 699.888442] ? do_fsync+0x3d/0x70
[ 699.889118] ? __x64_sys_fdatasync+0x24/0x30
[ 699.889996] rewind_stack_do_exit+0x17/0x20
[ 699.890860] RIP: 0033:0x7f9bf930d800
[ 699.891585] Code: Bad RIP value.
[ 699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.901241] The buggy address belongs to the page:
[ 699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
[ 699.903811] flags: 0x2ffff0000000000()
[ 699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
[ 699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
[ 699.907673] page dumped because: kasan: bad access detected
[ 699.909108] Memory state around the buggy address:
[ 699.910077] ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
[ 699.911528] ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
[ 699.914392] ^
[ 699.915758] ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
[ 699.917193] ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
[ 699.918634] ==================================================================
- Location
https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
Reported-by Wen Xu <wen.xu@gatech.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-01 19:13:44 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2020-08-25 05:48:41 +08:00
|
|
|
if (__found_offset(file->f_mapping, blkaddr,
|
2018-06-05 17:44:11 +08:00
|
|
|
pgofs, whence)) {
|
2014-04-23 14:10:24 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (whence == SEEK_DATA)
|
|
|
|
goto fail;
|
|
|
|
found:
|
2014-04-28 16:02:48 +08:00
|
|
|
if (whence == SEEK_HOLE && data_ofs > isize)
|
|
|
|
data_ofs = isize;
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2014-04-23 14:10:24 +08:00
|
|
|
return vfs_setpos(file, data_ofs, maxbytes);
|
|
|
|
fail:
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2014-04-23 14:10:24 +08:00
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
|
|
|
|
{
|
|
|
|
struct inode *inode = file->f_mapping->host;
|
|
|
|
loff_t maxbytes = inode->i_sb->s_maxbytes;
|
|
|
|
|
2021-01-13 13:21:54 +08:00
|
|
|
if (f2fs_compressed_file(inode))
|
|
|
|
maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS;
|
|
|
|
|
2014-04-23 14:10:24 +08:00
|
|
|
switch (whence) {
|
|
|
|
case SEEK_SET:
|
|
|
|
case SEEK_CUR:
|
|
|
|
case SEEK_END:
|
|
|
|
return generic_file_llseek_size(file, offset, whence,
|
|
|
|
maxbytes, i_size_read(inode));
|
|
|
|
case SEEK_DATA:
|
|
|
|
case SEEK_HOLE:
|
2014-09-09 01:59:43 +08:00
|
|
|
if (offset < 0)
|
|
|
|
return -ENXIO;
|
2014-04-23 14:10:24 +08:00
|
|
|
return f2fs_seek_block(file, offset, whence);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
|
|
|
{
|
2014-10-24 10:48:09 +08:00
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
|
|
|
return -EIO;
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
file_accessed(file);
|
|
|
|
vma->vm_ops = &f2fs_file_vm_ops;
|
2023-07-06 10:06:14 +08:00
|
|
|
|
|
|
|
f2fs_down_read(&F2FS_I(inode)->i_sem);
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
set_inode_flag(inode, FI_MMAP_FILE);
|
2023-07-06 10:06:14 +08:00
|
|
|
f2fs_up_read(&F2FS_I(inode)->i_sem);
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-22 11:39:58 +08:00
|
|
|
static int f2fs_file_open(struct inode *inode, struct file *filp)
|
|
|
|
{
|
2017-11-30 04:35:28 +08:00
|
|
|
int err = fscrypt_file_open(inode, filp);
|
2015-04-22 11:39:58 +08:00
|
|
|
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
err = fsverity_file_open(inode, filp);
|
2017-11-30 04:35:28 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2018-03-08 18:34:38 +08:00
|
|
|
|
2023-05-31 20:59:18 +08:00
|
|
|
filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
|
2023-06-12 13:37:11 +08:00
|
|
|
filp->f_mode |= FMODE_CAN_ODIRECT;
|
2018-03-08 18:34:38 +08:00
|
|
|
|
2017-07-09 00:13:07 +08:00
|
|
|
return dquot_file_open(inode, filp);
|
2015-04-22 11:39:58 +08:00
|
|
|
}
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
struct f2fs_node *raw_node;
|
f2fs: update extent tree in batches
This patch introduce a new helper f2fs_update_extent_tree_range which can
do extent mapping update at a specified range.
The main idea is:
1) punch all mapping info in extent node(s) which are at a specified range;
2) try to merge new extent mapping with adjacent node, or failing that,
insert the mapping into extent tree as a new node.
In order to see the benefit, I add a function for stating time stamping
count as below:
uint64_t rdtsc(void)
{
uint32_t lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
My test environment is: ubuntu, intel i7-3770, 16G memory, 256g micron ssd.
truncation path: update extent cache from truncate_data_blocks_range
non-truncataion path: update extent cache from other paths
total: all update paths
a) Removing 128MB file which has one extent node mapping whole range of
file:
1. dd if=/dev/zero of=/mnt/f2fs/128M bs=1M count=128
2. sync
3. rm /mnt/f2fs/128M
Before:
total count average
truncation: 7651022 32768 233.49
Patched:
total count average
truncation: 3321 33 100.64
b) fsstress:
fsstress -d /mnt/f2fs -l 5 -n 100 -p 20
Test times: 5 times.
Before:
total count average
truncation: 5812480.6 20911.6 277.95
non-truncation: 7783845.6 13440.8 579.12
total: 13596326.2 34352.4 395.79
Patched:
total count average
truncation: 1281283.0 3041.6 421.25
non-truncation: 7355844.4 13662.8 538.38
total: 8637127.4 16704.4 517.06
1) For the updates in truncation path:
- we can see updating in batches leads total tsc and update count reducing
explicitly;
- besides, for a single batched updating, punching multiple extent nodes
in a loop, result in executing more operations, so our average tsc
increase intensively.
2) For the updates in non-truncation path:
- there is a little improvement, that is because for the scenario that we
just need to update in the head or tail of extent node, new interface
optimize to update info in extent node directly, rather than removing
original extent node for updating and then inserting that updated one
into cache as new node.
Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2015-08-26 20:34:48 +08:00
|
|
|
int nr_free = 0, ofs = dn->ofs_in_node, len = count;
|
2012-11-02 16:09:44 +08:00
|
|
|
__le32 *addr;
|
2017-07-19 00:19:06 +08:00
|
|
|
int base = 0;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
bool compressed_cluster = false;
|
|
|
|
int cluster_index = 0, valid_blocks = 0;
|
|
|
|
int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
|
2020-09-08 10:44:10 +08:00
|
|
|
bool released = !atomic_read(&F2FS_I(dn->inode)->i_compr_blocks);
|
2017-07-19 00:19:06 +08:00
|
|
|
|
|
|
|
if (IS_INODE(dn->node_page) && f2fs_has_extra_attr(dn->inode))
|
|
|
|
base = get_extra_isize(dn->inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2013-07-15 17:57:38 +08:00
|
|
|
raw_node = F2FS_NODE(dn->node_page);
|
2017-07-19 00:19:06 +08:00
|
|
|
addr = blkaddr_in_node(raw_node) + base + ofs;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2022-10-27 19:01:05 +08:00
|
|
|
/* Assumption: truncation starts with cluster */
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
|
2012-11-02 16:09:44 +08:00
|
|
|
block_t blkaddr = le32_to_cpu(*addr);
|
2018-05-30 03:33:07 +08:00
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (f2fs_compressed_file(dn->inode) &&
|
|
|
|
!(cluster_index & (cluster_size - 1))) {
|
|
|
|
if (compressed_cluster)
|
|
|
|
f2fs_i_compr_blocks_update(dn->inode,
|
|
|
|
valid_blocks, false);
|
|
|
|
compressed_cluster = (blkaddr == COMPRESS_ADDR);
|
|
|
|
valid_blocks = 0;
|
|
|
|
}
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
if (blkaddr == NULL_ADDR)
|
|
|
|
continue;
|
|
|
|
|
2014-12-31 14:57:55 +08:00
|
|
|
dn->data_blkaddr = NULL_ADDR;
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_set_data_blkaddr(dn);
|
f2fs: fix to do sanity check with block address in main area
This patch add to do sanity check with below field:
- cp_pack_total_block_count
- blkaddr of data/node
- extent info
- Overview
BUG() in verify_block_addr() when writing to a corrupted f2fs image
- Reproduce (4.18 upstream kernel)
- POC (poc.c)
static void activity(char *mpoint) {
char *foo_bar_baz;
int err;
static int buf[8192];
memset(buf, 0, sizeof(buf));
err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, (char *)buf, sizeof(buf));
fdatasync(fd);
close(fd);
}
}
int main(int argc, char *argv[]) {
activity(argv[1]);
return 0;
}
- Kernel message
[ 689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
[ 699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
[ 699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
[ 699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
[ 699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
[ 699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
[ 699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
[ 699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
[ 699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
[ 699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
[ 699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
[ 699.729154] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.729156] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.729171] Call Trace:
[ 699.729192] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.729203] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.729238] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.729269] ? __radix_tree_replace+0xa3/0x120
[ 699.729276] __write_data_page+0x5c7/0xe30
[ 699.729291] ? kasan_check_read+0x11/0x20
[ 699.729310] ? page_mapped+0x8a/0x110
[ 699.729321] ? page_mkclean+0xe9/0x160
[ 699.729327] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.729331] ? invalid_page_referenced_vma+0x130/0x130
[ 699.729345] ? clear_page_dirty_for_io+0x332/0x450
[ 699.729351] f2fs_write_cache_pages+0x4ca/0x860
[ 699.729358] ? __write_data_page+0xe30/0xe30
[ 699.729374] ? percpu_counter_add_batch+0x22/0xa0
[ 699.729380] ? kasan_check_write+0x14/0x20
[ 699.729391] ? _raw_spin_lock+0x17/0x40
[ 699.729403] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.729413] ? iov_iter_advance+0x113/0x640
[ 699.729418] ? f2fs_write_end+0x133/0x2e0
[ 699.729423] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.729428] f2fs_write_data_pages+0x329/0x520
[ 699.729433] ? generic_perform_write+0x250/0x320
[ 699.729438] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729454] ? current_time+0x110/0x110
[ 699.729459] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.729464] do_writepages+0x37/0xb0
[ 699.729468] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729472] ? do_writepages+0x37/0xb0
[ 699.729478] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.729483] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.729496] ? __vfs_write+0x2b2/0x410
[ 699.729501] file_write_and_wait_range+0x66/0xb0
[ 699.729506] f2fs_do_sync_file+0x1f9/0xd90
[ 699.729511] ? truncate_partial_data_page+0x290/0x290
[ 699.729521] ? __sb_end_write+0x30/0x50
[ 699.729526] ? vfs_write+0x20f/0x260
[ 699.729530] f2fs_sync_file+0x9a/0xb0
[ 699.729534] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.729548] vfs_fsync_range+0x68/0x100
[ 699.729554] ? __fget_light+0xc9/0xe0
[ 699.729558] do_fsync+0x3d/0x70
[ 699.729562] __x64_sys_fdatasync+0x24/0x30
[ 699.729585] do_syscall_64+0x78/0x170
[ 699.729595] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.729613] RIP: 0033:0x7f9bf930d800
[ 699.729615] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
[ 699.729782] ------------[ cut here ]------------
[ 699.729785] kernel BUG at fs/f2fs/segment.h:654!
[ 699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
[ 699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G W 4.18.0-rc1+ #4
[ 699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.748683] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.750293] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.752874] Call Trace:
[ 699.753386] ? f2fs_inplace_write_data+0x93/0x240
[ 699.754341] f2fs_inplace_write_data+0xd2/0x240
[ 699.755271] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.756214] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.757215] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.758209] ? __radix_tree_replace+0xa3/0x120
[ 699.759164] __write_data_page+0x5c7/0xe30
[ 699.760002] ? kasan_check_read+0x11/0x20
[ 699.760823] ? page_mapped+0x8a/0x110
[ 699.761573] ? page_mkclean+0xe9/0x160
[ 699.762345] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.763332] ? invalid_page_referenced_vma+0x130/0x130
[ 699.764374] ? clear_page_dirty_for_io+0x332/0x450
[ 699.765347] f2fs_write_cache_pages+0x4ca/0x860
[ 699.766276] ? __write_data_page+0xe30/0xe30
[ 699.767161] ? percpu_counter_add_batch+0x22/0xa0
[ 699.768112] ? kasan_check_write+0x14/0x20
[ 699.768951] ? _raw_spin_lock+0x17/0x40
[ 699.769739] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.770885] ? iov_iter_advance+0x113/0x640
[ 699.771743] ? f2fs_write_end+0x133/0x2e0
[ 699.772569] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.773680] f2fs_write_data_pages+0x329/0x520
[ 699.774603] ? generic_perform_write+0x250/0x320
[ 699.775544] ? f2fs_write_cache_pages+0x860/0x860
[ 699.776510] ? current_time+0x110/0x110
[ 699.777299] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.778279] do_writepages+0x37/0xb0
[ 699.779026] ? f2fs_write_cache_pages+0x860/0x860
[ 699.779978] ? do_writepages+0x37/0xb0
[ 699.780755] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.781746] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.782820] ? __vfs_write+0x2b2/0x410
[ 699.783597] file_write_and_wait_range+0x66/0xb0
[ 699.784540] f2fs_do_sync_file+0x1f9/0xd90
[ 699.785381] ? truncate_partial_data_page+0x290/0x290
[ 699.786415] ? __sb_end_write+0x30/0x50
[ 699.787204] ? vfs_write+0x20f/0x260
[ 699.787941] f2fs_sync_file+0x9a/0xb0
[ 699.788694] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.789572] vfs_fsync_range+0x68/0x100
[ 699.790360] ? __fget_light+0xc9/0xe0
[ 699.791128] do_fsync+0x3d/0x70
[ 699.791779] __x64_sys_fdatasync+0x24/0x30
[ 699.792614] do_syscall_64+0x78/0x170
[ 699.793371] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.794406] RIP: 0033:0x7f9bf930d800
[ 699.795134] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
[ 699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.831192] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.832793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.835556] ==================================================================
[ 699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
[ 699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
[ 699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G D W 4.18.0-rc1+ #4
[ 699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.843475] Call Trace:
[ 699.843982] dump_stack+0x7b/0xb5
[ 699.844661] print_address_description+0x70/0x290
[ 699.845607] kasan_report+0x291/0x390
[ 699.846351] ? update_stack_state+0x38c/0x3e0
[ 699.853831] __asan_load8+0x54/0x90
[ 699.854569] update_stack_state+0x38c/0x3e0
[ 699.855428] ? __read_once_size_nocheck.constprop.7+0x20/0x20
[ 699.856601] ? __save_stack_trace+0x5e/0x100
[ 699.857476] unwind_next_frame.part.5+0x18e/0x490
[ 699.858448] ? unwind_dump+0x290/0x290
[ 699.859217] ? clear_page_dirty_for_io+0x332/0x450
[ 699.860185] __unwind_start+0x106/0x190
[ 699.860974] __save_stack_trace+0x5e/0x100
[ 699.861808] ? __save_stack_trace+0x5e/0x100
[ 699.862691] ? unlink_anon_vmas+0xba/0x2c0
[ 699.863525] save_stack_trace+0x1f/0x30
[ 699.864312] save_stack+0x46/0xd0
[ 699.864993] ? __alloc_pages_slowpath+0x1420/0x1420
[ 699.865990] ? flush_tlb_mm_range+0x15e/0x220
[ 699.866889] ? kasan_check_write+0x14/0x20
[ 699.867724] ? __dec_node_state+0x92/0xb0
[ 699.868543] ? lock_page_memcg+0x85/0xf0
[ 699.869350] ? unlock_page_memcg+0x16/0x80
[ 699.870185] ? page_remove_rmap+0x198/0x520
[ 699.871048] ? mark_page_accessed+0x133/0x200
[ 699.871930] ? _cond_resched+0x1a/0x50
[ 699.872700] ? unmap_page_range+0xcd4/0xe50
[ 699.873551] ? rb_next+0x58/0x80
[ 699.874217] ? rb_next+0x58/0x80
[ 699.874895] __kasan_slab_free+0x13c/0x1a0
[ 699.875734] ? unlink_anon_vmas+0xba/0x2c0
[ 699.876563] kasan_slab_free+0xe/0x10
[ 699.877315] kmem_cache_free+0x89/0x1e0
[ 699.878095] unlink_anon_vmas+0xba/0x2c0
[ 699.878913] free_pgtables+0x101/0x1b0
[ 699.879677] exit_mmap+0x146/0x2a0
[ 699.880378] ? __ia32_sys_munmap+0x50/0x50
[ 699.881214] ? kasan_check_read+0x11/0x20
[ 699.882052] ? mm_update_next_owner+0x322/0x380
[ 699.882985] mmput+0x8b/0x1d0
[ 699.883602] do_exit+0x43a/0x1390
[ 699.884288] ? mm_update_next_owner+0x380/0x380
[ 699.885212] ? f2fs_sync_file+0x9a/0xb0
[ 699.885995] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.886877] ? vfs_fsync_range+0x68/0x100
[ 699.887694] ? __fget_light+0xc9/0xe0
[ 699.888442] ? do_fsync+0x3d/0x70
[ 699.889118] ? __x64_sys_fdatasync+0x24/0x30
[ 699.889996] rewind_stack_do_exit+0x17/0x20
[ 699.890860] RIP: 0033:0x7f9bf930d800
[ 699.891585] Code: Bad RIP value.
[ 699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.901241] The buggy address belongs to the page:
[ 699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
[ 699.903811] flags: 0x2ffff0000000000()
[ 699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
[ 699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
[ 699.907673] page dumped because: kasan: bad access detected
[ 699.909108] Memory state around the buggy address:
[ 699.910077] ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
[ 699.911528] ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
[ 699.914392] ^
[ 699.915758] ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
[ 699.917193] ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
[ 699.918634] ==================================================================
- Location
https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
Reported-by Wen Xu <wen.xu@gatech.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-01 19:13:44 +08:00
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (__is_valid_data_blkaddr(blkaddr)) {
|
|
|
|
if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
|
f2fs: introduce DATA_GENERIC_ENHANCE
Previously, f2fs_is_valid_blkaddr(, blkaddr, DATA_GENERIC) will check
whether @blkaddr locates in main area or not.
That check is weak, since the block address in range of main area can
point to the address which is not valid in segment info table, and we
can not detect such condition, we may suffer worse corruption as system
continues running.
So this patch introduce DATA_GENERIC_ENHANCE to enhance the sanity check
which trigger SIT bitmap check rather than only range check.
This patch did below changes as wel:
- set SBI_NEED_FSCK in f2fs_is_valid_blkaddr().
- get rid of is_valid_data_blkaddr() to avoid panic if blkaddr is invalid.
- introduce verify_fio_blkaddr() to wrap fio {new,old}_blkaddr validation check.
- spread blkaddr check in:
* f2fs_get_node_info()
* __read_out_blkaddrs()
* f2fs_submit_page_read()
* ra_data_block()
* do_recover_data()
This patch can fix bug reported from bugzilla below:
https://bugzilla.kernel.org/show_bug.cgi?id=203215
https://bugzilla.kernel.org/show_bug.cgi?id=203223
https://bugzilla.kernel.org/show_bug.cgi?id=203231
https://bugzilla.kernel.org/show_bug.cgi?id=203235
https://bugzilla.kernel.org/show_bug.cgi?id=203241
= Update by Jaegeuk Kim =
DATA_GENERIC_ENHANCE enhanced to validate block addresses on read/write paths.
But, xfstest/generic/446 compalins some generated kernel messages saying invalid
bitmap was detected when reading a block. The reaons is, when we get the
block addresses from extent_cache, there is no lock to synchronize it from
truncating the blocks in parallel.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-04-15 15:26:32 +08:00
|
|
|
DATA_GENERIC_ENHANCE))
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
continue;
|
|
|
|
if (compressed_cluster)
|
|
|
|
valid_blocks++;
|
|
|
|
}
|
f2fs: fix to do sanity check with block address in main area
This patch add to do sanity check with below field:
- cp_pack_total_block_count
- blkaddr of data/node
- extent info
- Overview
BUG() in verify_block_addr() when writing to a corrupted f2fs image
- Reproduce (4.18 upstream kernel)
- POC (poc.c)
static void activity(char *mpoint) {
char *foo_bar_baz;
int err;
static int buf[8192];
memset(buf, 0, sizeof(buf));
err = asprintf(&foo_bar_baz, "%s/foo/bar/baz", mpoint);
int fd = open(foo_bar_baz, O_RDWR | O_TRUNC, 0777);
if (fd >= 0) {
write(fd, (char *)buf, sizeof(buf));
fdatasync(fd);
close(fd);
}
}
int main(int argc, char *argv[]) {
activity(argv[1]);
return 0;
}
- Kernel message
[ 689.349473] F2FS-fs (loop0): Mounted with checkpoint version = 3
[ 699.728662] WARNING: CPU: 0 PID: 1309 at fs/f2fs/segment.c:2860 f2fs_inplace_write_data+0x232/0x240
[ 699.728670] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.729056] CPU: 0 PID: 1309 Comm: a.out Not tainted 4.18.0-rc1+ #4
[ 699.729064] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.729074] RIP: 0010:f2fs_inplace_write_data+0x232/0x240
[ 699.729076] Code: ff e9 cf fe ff ff 49 8d 7d 10 e8 39 45 ad ff 4d 8b 7d 10 be 04 00 00 00 49 8d 7f 48 e8 07 49 ad ff 45 8b 7f 48 e9 fb fe ff ff <0f> 0b f0 41 80 4d 48 04 e9 65 fe ff ff 90 66 66 66 66 90 55 48 8d
[ 699.729130] RSP: 0018:ffff8801f43af568 EFLAGS: 00010202
[ 699.729139] RAX: 000000000000003f RBX: ffff8801f43af7b8 RCX: ffffffffb88c9113
[ 699.729142] RDX: 0000000000000003 RSI: dffffc0000000000 RDI: ffff8802024e5540
[ 699.729144] RBP: ffff8801f43af590 R08: 0000000000000009 R09: ffffffffffffffe8
[ 699.729147] R10: 0000000000000001 R11: ffffed0039b0596a R12: ffff8802024e5540
[ 699.729149] R13: ffff8801f0335500 R14: ffff8801e3e7a700 R15: ffff8801e1ee4450
[ 699.729154] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.729156] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.729159] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.729171] Call Trace:
[ 699.729192] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.729203] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.729238] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.729269] ? __radix_tree_replace+0xa3/0x120
[ 699.729276] __write_data_page+0x5c7/0xe30
[ 699.729291] ? kasan_check_read+0x11/0x20
[ 699.729310] ? page_mapped+0x8a/0x110
[ 699.729321] ? page_mkclean+0xe9/0x160
[ 699.729327] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.729331] ? invalid_page_referenced_vma+0x130/0x130
[ 699.729345] ? clear_page_dirty_for_io+0x332/0x450
[ 699.729351] f2fs_write_cache_pages+0x4ca/0x860
[ 699.729358] ? __write_data_page+0xe30/0xe30
[ 699.729374] ? percpu_counter_add_batch+0x22/0xa0
[ 699.729380] ? kasan_check_write+0x14/0x20
[ 699.729391] ? _raw_spin_lock+0x17/0x40
[ 699.729403] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.729413] ? iov_iter_advance+0x113/0x640
[ 699.729418] ? f2fs_write_end+0x133/0x2e0
[ 699.729423] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.729428] f2fs_write_data_pages+0x329/0x520
[ 699.729433] ? generic_perform_write+0x250/0x320
[ 699.729438] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729454] ? current_time+0x110/0x110
[ 699.729459] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.729464] do_writepages+0x37/0xb0
[ 699.729468] ? f2fs_write_cache_pages+0x860/0x860
[ 699.729472] ? do_writepages+0x37/0xb0
[ 699.729478] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.729483] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.729496] ? __vfs_write+0x2b2/0x410
[ 699.729501] file_write_and_wait_range+0x66/0xb0
[ 699.729506] f2fs_do_sync_file+0x1f9/0xd90
[ 699.729511] ? truncate_partial_data_page+0x290/0x290
[ 699.729521] ? __sb_end_write+0x30/0x50
[ 699.729526] ? vfs_write+0x20f/0x260
[ 699.729530] f2fs_sync_file+0x9a/0xb0
[ 699.729534] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.729548] vfs_fsync_range+0x68/0x100
[ 699.729554] ? __fget_light+0xc9/0xe0
[ 699.729558] do_fsync+0x3d/0x70
[ 699.729562] __x64_sys_fdatasync+0x24/0x30
[ 699.729585] do_syscall_64+0x78/0x170
[ 699.729595] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.729613] RIP: 0033:0x7f9bf930d800
[ 699.729615] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.729668] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.729673] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.729675] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.729678] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.729680] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.729683] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.729687] ---[ end trace 4ce02f25ff7d3df5 ]---
[ 699.729782] ------------[ cut here ]------------
[ 699.729785] kernel BUG at fs/f2fs/segment.h:654!
[ 699.731055] invalid opcode: 0000 [#1] SMP KASAN PTI
[ 699.732104] CPU: 0 PID: 1309 Comm: a.out Tainted: G W 4.18.0-rc1+ #4
[ 699.733684] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.735611] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.736649] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.740524] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.741573] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.743006] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.744426] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.745833] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.747256] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.748683] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.750293] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.751462] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.752874] Call Trace:
[ 699.753386] ? f2fs_inplace_write_data+0x93/0x240
[ 699.754341] f2fs_inplace_write_data+0xd2/0x240
[ 699.755271] f2fs_do_write_data_page+0x2e2/0xe00
[ 699.756214] ? f2fs_should_update_outplace+0xd0/0xd0
[ 699.757215] ? memcg_drain_all_list_lrus+0x280/0x280
[ 699.758209] ? __radix_tree_replace+0xa3/0x120
[ 699.759164] __write_data_page+0x5c7/0xe30
[ 699.760002] ? kasan_check_read+0x11/0x20
[ 699.760823] ? page_mapped+0x8a/0x110
[ 699.761573] ? page_mkclean+0xe9/0x160
[ 699.762345] ? f2fs_do_write_data_page+0xe00/0xe00
[ 699.763332] ? invalid_page_referenced_vma+0x130/0x130
[ 699.764374] ? clear_page_dirty_for_io+0x332/0x450
[ 699.765347] f2fs_write_cache_pages+0x4ca/0x860
[ 699.766276] ? __write_data_page+0xe30/0xe30
[ 699.767161] ? percpu_counter_add_batch+0x22/0xa0
[ 699.768112] ? kasan_check_write+0x14/0x20
[ 699.768951] ? _raw_spin_lock+0x17/0x40
[ 699.769739] ? f2fs_mark_inode_dirty_sync.part.18+0x16/0x30
[ 699.770885] ? iov_iter_advance+0x113/0x640
[ 699.771743] ? f2fs_write_end+0x133/0x2e0
[ 699.772569] ? balance_dirty_pages_ratelimited+0x239/0x640
[ 699.773680] f2fs_write_data_pages+0x329/0x520
[ 699.774603] ? generic_perform_write+0x250/0x320
[ 699.775544] ? f2fs_write_cache_pages+0x860/0x860
[ 699.776510] ? current_time+0x110/0x110
[ 699.777299] ? f2fs_preallocate_blocks+0x1ef/0x370
[ 699.778279] do_writepages+0x37/0xb0
[ 699.779026] ? f2fs_write_cache_pages+0x860/0x860
[ 699.779978] ? do_writepages+0x37/0xb0
[ 699.780755] __filemap_fdatawrite_range+0x19a/0x1f0
[ 699.781746] ? delete_from_page_cache_batch+0x4e0/0x4e0
[ 699.782820] ? __vfs_write+0x2b2/0x410
[ 699.783597] file_write_and_wait_range+0x66/0xb0
[ 699.784540] f2fs_do_sync_file+0x1f9/0xd90
[ 699.785381] ? truncate_partial_data_page+0x290/0x290
[ 699.786415] ? __sb_end_write+0x30/0x50
[ 699.787204] ? vfs_write+0x20f/0x260
[ 699.787941] f2fs_sync_file+0x9a/0xb0
[ 699.788694] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.789572] vfs_fsync_range+0x68/0x100
[ 699.790360] ? __fget_light+0xc9/0xe0
[ 699.791128] do_fsync+0x3d/0x70
[ 699.791779] __x64_sys_fdatasync+0x24/0x30
[ 699.792614] do_syscall_64+0x78/0x170
[ 699.793371] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 699.794406] RIP: 0033:0x7f9bf930d800
[ 699.795134] Code: 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 83 3d 49 bf 2c 00 00 75 10 b8 4b 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 31 c3 48 83 ec 08 e8 be 78 01 00 48 89 04 24
[ 699.798960] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.800483] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.801923] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.803373] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.804798] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.806233] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.807667] Modules linked in: snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd mac_hid i2c_piix4 soundcore ib_iser rdma_cm iw_cm ib_cm ib_core iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx raid1 raid0 multipath linear 8139too crct10dif_pclmul crc32_pclmul qxl drm_kms_helper syscopyarea aesni_intel sysfillrect sysimgblt fb_sys_fops ttm drm aes_x86_64 crypto_simd cryptd 8139cp glue_helper mii pata_acpi floppy
[ 699.817079] ---[ end trace 4ce02f25ff7d3df6 ]---
[ 699.818068] RIP: 0010:f2fs_submit_page_bio+0x29b/0x730
[ 699.819114] Code: 54 49 8d bd 18 04 00 00 e8 b2 59 af ff 41 8b 8d 18 04 00 00 8b 45 b8 41 d3 e6 44 01 f0 4c 8d 73 14 41 39 c7 0f 82 37 fe ff ff <0f> 0b 65 8b 05 2c 04 77 47 89 c0 48 0f a3 05 52 c1 d5 01 0f 92 c0
[ 699.822919] RSP: 0018:ffff8801f43af508 EFLAGS: 00010283
[ 699.823977] RAX: 0000000000000000 RBX: ffff8801f43af7b8 RCX: ffffffffb88a7cef
[ 699.825436] RDX: 0000000000000007 RSI: dffffc0000000000 RDI: ffff8801e3e7a64c
[ 699.826881] RBP: ffff8801f43af558 R08: ffffed003e066b55 R09: ffffed003e066b55
[ 699.828292] R10: 0000000000000001 R11: ffffed003e066b54 R12: ffffea0007876940
[ 699.829750] R13: ffff8801f0335500 R14: ffff8801e3e7a600 R15: 0000000000000001
[ 699.831192] FS: 00007f9bf97f5700(0000) GS:ffff8801f6e00000(0000) knlGS:0000000000000000
[ 699.832793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 699.833981] CR2: 00007f9bf925d170 CR3: 00000001f0c34000 CR4: 00000000000006f0
[ 699.835556] ==================================================================
[ 699.837029] BUG: KASAN: stack-out-of-bounds in update_stack_state+0x38c/0x3e0
[ 699.838462] Read of size 8 at addr ffff8801f43af970 by task a.out/1309
[ 699.840086] CPU: 0 PID: 1309 Comm: a.out Tainted: G D W 4.18.0-rc1+ #4
[ 699.841603] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
[ 699.843475] Call Trace:
[ 699.843982] dump_stack+0x7b/0xb5
[ 699.844661] print_address_description+0x70/0x290
[ 699.845607] kasan_report+0x291/0x390
[ 699.846351] ? update_stack_state+0x38c/0x3e0
[ 699.853831] __asan_load8+0x54/0x90
[ 699.854569] update_stack_state+0x38c/0x3e0
[ 699.855428] ? __read_once_size_nocheck.constprop.7+0x20/0x20
[ 699.856601] ? __save_stack_trace+0x5e/0x100
[ 699.857476] unwind_next_frame.part.5+0x18e/0x490
[ 699.858448] ? unwind_dump+0x290/0x290
[ 699.859217] ? clear_page_dirty_for_io+0x332/0x450
[ 699.860185] __unwind_start+0x106/0x190
[ 699.860974] __save_stack_trace+0x5e/0x100
[ 699.861808] ? __save_stack_trace+0x5e/0x100
[ 699.862691] ? unlink_anon_vmas+0xba/0x2c0
[ 699.863525] save_stack_trace+0x1f/0x30
[ 699.864312] save_stack+0x46/0xd0
[ 699.864993] ? __alloc_pages_slowpath+0x1420/0x1420
[ 699.865990] ? flush_tlb_mm_range+0x15e/0x220
[ 699.866889] ? kasan_check_write+0x14/0x20
[ 699.867724] ? __dec_node_state+0x92/0xb0
[ 699.868543] ? lock_page_memcg+0x85/0xf0
[ 699.869350] ? unlock_page_memcg+0x16/0x80
[ 699.870185] ? page_remove_rmap+0x198/0x520
[ 699.871048] ? mark_page_accessed+0x133/0x200
[ 699.871930] ? _cond_resched+0x1a/0x50
[ 699.872700] ? unmap_page_range+0xcd4/0xe50
[ 699.873551] ? rb_next+0x58/0x80
[ 699.874217] ? rb_next+0x58/0x80
[ 699.874895] __kasan_slab_free+0x13c/0x1a0
[ 699.875734] ? unlink_anon_vmas+0xba/0x2c0
[ 699.876563] kasan_slab_free+0xe/0x10
[ 699.877315] kmem_cache_free+0x89/0x1e0
[ 699.878095] unlink_anon_vmas+0xba/0x2c0
[ 699.878913] free_pgtables+0x101/0x1b0
[ 699.879677] exit_mmap+0x146/0x2a0
[ 699.880378] ? __ia32_sys_munmap+0x50/0x50
[ 699.881214] ? kasan_check_read+0x11/0x20
[ 699.882052] ? mm_update_next_owner+0x322/0x380
[ 699.882985] mmput+0x8b/0x1d0
[ 699.883602] do_exit+0x43a/0x1390
[ 699.884288] ? mm_update_next_owner+0x380/0x380
[ 699.885212] ? f2fs_sync_file+0x9a/0xb0
[ 699.885995] ? f2fs_do_sync_file+0xd90/0xd90
[ 699.886877] ? vfs_fsync_range+0x68/0x100
[ 699.887694] ? __fget_light+0xc9/0xe0
[ 699.888442] ? do_fsync+0x3d/0x70
[ 699.889118] ? __x64_sys_fdatasync+0x24/0x30
[ 699.889996] rewind_stack_do_exit+0x17/0x20
[ 699.890860] RIP: 0033:0x7f9bf930d800
[ 699.891585] Code: Bad RIP value.
[ 699.892268] RSP: 002b:00007ffee3606c68 EFLAGS: 00000246 ORIG_RAX: 000000000000004b
[ 699.893781] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f9bf930d800
[ 699.895220] RDX: 0000000000008000 RSI: 00000000006010a0 RDI: 0000000000000003
[ 699.896643] RBP: 00007ffee3606ca0 R08: 0000000001503010 R09: 0000000000000000
[ 699.898069] R10: 00000000000002e8 R11: 0000000000000246 R12: 0000000000400610
[ 699.899505] R13: 00007ffee3606da0 R14: 0000000000000000 R15: 0000000000000000
[ 699.901241] The buggy address belongs to the page:
[ 699.902215] page:ffffea0007d0ebc0 count:0 mapcount:0 mapping:0000000000000000 index:0x0
[ 699.903811] flags: 0x2ffff0000000000()
[ 699.904585] raw: 02ffff0000000000 0000000000000000 ffffffff07d00101 0000000000000000
[ 699.906125] raw: 0000000000000000 0000000000240000 00000000ffffffff 0000000000000000
[ 699.907673] page dumped because: kasan: bad access detected
[ 699.909108] Memory state around the buggy address:
[ 699.910077] ffff8801f43af800: 00 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 00 00 00
[ 699.911528] ffff8801f43af880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 699.912953] >ffff8801f43af900: 00 00 00 00 00 00 00 00 f1 01 f4 f4 f4 f2 f2 f2
[ 699.914392] ^
[ 699.915758] ffff8801f43af980: f2 00 f4 f4 00 00 00 00 f2 00 00 00 00 00 00 00
[ 699.917193] ffff8801f43afa00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 00 00 00 00
[ 699.918634] ==================================================================
- Location
https://elixir.bootlin.com/linux/v4.18-rc1/source/fs/f2fs/segment.h#L644
Reported-by Wen Xu <wen.xu@gatech.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-08-01 19:13:44 +08:00
|
|
|
|
2015-03-18 08:16:35 +08:00
|
|
|
if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
|
2016-05-21 01:13:22 +08:00
|
|
|
clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
|
|
|
f2fs_invalidate_blocks(sbi, blkaddr);
|
2020-03-06 15:36:09 +08:00
|
|
|
|
|
|
|
if (!released || blkaddr != COMPRESS_ADDR)
|
|
|
|
nr_free++;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
f2fs: update extent tree in batches
This patch introduce a new helper f2fs_update_extent_tree_range which can
do extent mapping update at a specified range.
The main idea is:
1) punch all mapping info in extent node(s) which are at a specified range;
2) try to merge new extent mapping with adjacent node, or failing that,
insert the mapping into extent tree as a new node.
In order to see the benefit, I add a function for stating time stamping
count as below:
uint64_t rdtsc(void)
{
uint32_t lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
My test environment is: ubuntu, intel i7-3770, 16G memory, 256g micron ssd.
truncation path: update extent cache from truncate_data_blocks_range
non-truncataion path: update extent cache from other paths
total: all update paths
a) Removing 128MB file which has one extent node mapping whole range of
file:
1. dd if=/dev/zero of=/mnt/f2fs/128M bs=1M count=128
2. sync
3. rm /mnt/f2fs/128M
Before:
total count average
truncation: 7651022 32768 233.49
Patched:
total count average
truncation: 3321 33 100.64
b) fsstress:
fsstress -d /mnt/f2fs -l 5 -n 100 -p 20
Test times: 5 times.
Before:
total count average
truncation: 5812480.6 20911.6 277.95
non-truncation: 7783845.6 13440.8 579.12
total: 13596326.2 34352.4 395.79
Patched:
total count average
truncation: 1281283.0 3041.6 421.25
non-truncation: 7355844.4 13662.8 538.38
total: 8637127.4 16704.4 517.06
1) For the updates in truncation path:
- we can see updating in batches leads total tsc and update count reducing
explicitly;
- besides, for a single batched updating, punching multiple extent nodes
in a loop, result in executing more operations, so our average tsc
increase intensively.
2) For the updates in non-truncation path:
- there is a little improvement, that is because for the scenario that we
just need to update in the head or tail of extent node, new interface
optimize to update info in extent node directly, rather than removing
original extent node for updating and then inserting that updated one
into cache as new node.
Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2015-08-26 20:34:48 +08:00
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (compressed_cluster)
|
|
|
|
f2fs_i_compr_blocks_update(dn->inode, valid_blocks, false);
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
if (nr_free) {
|
f2fs: update extent tree in batches
This patch introduce a new helper f2fs_update_extent_tree_range which can
do extent mapping update at a specified range.
The main idea is:
1) punch all mapping info in extent node(s) which are at a specified range;
2) try to merge new extent mapping with adjacent node, or failing that,
insert the mapping into extent tree as a new node.
In order to see the benefit, I add a function for stating time stamping
count as below:
uint64_t rdtsc(void)
{
uint32_t lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
My test environment is: ubuntu, intel i7-3770, 16G memory, 256g micron ssd.
truncation path: update extent cache from truncate_data_blocks_range
non-truncataion path: update extent cache from other paths
total: all update paths
a) Removing 128MB file which has one extent node mapping whole range of
file:
1. dd if=/dev/zero of=/mnt/f2fs/128M bs=1M count=128
2. sync
3. rm /mnt/f2fs/128M
Before:
total count average
truncation: 7651022 32768 233.49
Patched:
total count average
truncation: 3321 33 100.64
b) fsstress:
fsstress -d /mnt/f2fs -l 5 -n 100 -p 20
Test times: 5 times.
Before:
total count average
truncation: 5812480.6 20911.6 277.95
non-truncation: 7783845.6 13440.8 579.12
total: 13596326.2 34352.4 395.79
Patched:
total count average
truncation: 1281283.0 3041.6 421.25
non-truncation: 7355844.4 13662.8 538.38
total: 8637127.4 16704.4 517.06
1) For the updates in truncation path:
- we can see updating in batches leads total tsc and update count reducing
explicitly;
- besides, for a single batched updating, punching multiple extent nodes
in a loop, result in executing more operations, so our average tsc
increase intensively.
2) For the updates in non-truncation path:
- there is a little improvement, that is because for the scenario that we
just need to update in the head or tail of extent node, new interface
optimize to update info in extent node directly, rather than removing
original extent node for updating and then inserting that updated one
into cache as new node.
Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2015-08-26 20:34:48 +08:00
|
|
|
pgoff_t fofs;
|
|
|
|
/*
|
|
|
|
* once we invalidate valid blkaddr in range [ofs, ofs + count],
|
|
|
|
* we will invalidate all blkaddr in the whole range.
|
|
|
|
*/
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
|
2016-01-26 15:39:35 +08:00
|
|
|
dn->inode) + ofs;
|
2022-12-01 01:26:29 +08:00
|
|
|
f2fs_update_read_extent_cache_range(dn, fofs, 0, len);
|
2023-01-31 22:47:00 +08:00
|
|
|
f2fs_update_age_extent_cache_range(dn, fofs, len);
|
2013-06-08 20:25:40 +08:00
|
|
|
dec_valid_block_count(sbi, dn->inode, nr_free);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
dn->ofs_in_node = ofs;
|
2013-04-20 00:28:52 +08:00
|
|
|
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2013-04-20 00:28:52 +08:00
|
|
|
trace_f2fs_truncate_data_blocks_range(dn->inode, dn->nid,
|
|
|
|
dn->ofs_in_node, nr_free);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2015-03-10 13:16:25 +08:00
|
|
|
static int truncate_partial_data_page(struct inode *inode, u64 from,
|
2015-05-01 08:00:33 +08:00
|
|
|
bool cache_only)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2018-05-30 03:21:14 +08:00
|
|
|
loff_t offset = from & (PAGE_SIZE - 1);
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pgoff_t index = from >> PAGE_SHIFT;
|
2015-05-01 08:00:33 +08:00
|
|
|
struct address_space *mapping = inode->i_mapping;
|
2012-11-02 16:09:44 +08:00
|
|
|
struct page *page;
|
|
|
|
|
2015-05-01 08:00:33 +08:00
|
|
|
if (!offset && !cache_only)
|
2014-10-24 10:48:09 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2015-05-01 08:00:33 +08:00
|
|
|
if (cache_only) {
|
2016-09-07 06:55:54 +08:00
|
|
|
page = find_lock_page(mapping, index);
|
2015-05-01 08:00:33 +08:00
|
|
|
if (page && PageUptodate(page))
|
|
|
|
goto truncate_out;
|
|
|
|
f2fs_put_page(page, 1);
|
2014-10-24 10:48:09 +08:00
|
|
|
return 0;
|
2015-05-01 08:00:33 +08:00
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
page = f2fs_get_lock_data_page(inode, index, true);
|
2015-05-01 08:00:33 +08:00
|
|
|
if (IS_ERR(page))
|
2017-02-28 20:32:41 +08:00
|
|
|
return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
|
2015-05-01 08:00:33 +08:00
|
|
|
truncate_out:
|
2018-12-25 17:43:42 +08:00
|
|
|
f2fs_wait_on_page_writeback(page, DATA, true, true);
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
zero_user(page, offset, PAGE_SIZE - offset);
|
2017-06-14 23:05:32 +08:00
|
|
|
|
|
|
|
/* An encrypted inode should have a key and truncate the last page. */
|
2018-12-12 17:50:11 +08:00
|
|
|
f2fs_bug_on(F2FS_I_SB(inode), cache_only && IS_ENCRYPTED(inode));
|
2017-06-14 23:05:32 +08:00
|
|
|
if (!cache_only)
|
2015-03-10 13:16:25 +08:00
|
|
|
set_page_dirty(page);
|
2012-11-02 16:09:44 +08:00
|
|
|
f2fs_put_page(page, 1);
|
2014-10-24 10:48:09 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2020-03-18 16:22:59 +08:00
|
|
|
int f2fs_do_truncate_blocks(struct inode *inode, u64 from, bool lock)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
struct dnode_of_data dn;
|
|
|
|
pgoff_t free_from;
|
f2fs: handle inline data operations
Hook inline data read/write, truncate, fallocate, setattr, etc.
Files need meet following 2 requirement to inline:
1) file size is not greater than MAX_INLINE_DATA;
2) file doesn't pre-allocate data blocks by fallocate().
FI_INLINE_DATA will not be set while creating a new regular inode because
most of the files are bigger than ~3.4K. Set FI_INLINE_DATA only when
data is submitted to block layer, ranther than set it while creating a new
inode, this also avoids converting data from inline to normal data block
and vice versa.
While writting inline data to inode block, the first data block should be
released if the file has a block indexed by i_addr[0].
On the other hand, when a file operation is appied to a file with inline
data, we need to test if this file can remain inline by doing this
operation, otherwise it should be convert into normal file by reserving
a new data block, copying inline data to this new block and clear
FI_INLINE_DATA flag. Because reserve a new data block here will make use
of i_addr[0], if we save inline data in i_addr[0..872], then the first
4 bytes would be overwriten. This problem can be avoided simply by
not using i_addr[0] for inline data.
Signed-off-by: Huajun Li <huajun.li@intel.com>
Signed-off-by: Haicheng Li <haicheng.li@linux.intel.com>
Signed-off-by: Weihong Xu <weihong.xu@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-11-10 23:13:20 +08:00
|
|
|
int count = 0, err = 0;
|
2014-10-24 10:48:09 +08:00
|
|
|
struct page *ipage;
|
2015-03-10 13:16:25 +08:00
|
|
|
bool truncate_page = false;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2013-04-20 00:28:52 +08:00
|
|
|
trace_f2fs_truncate_blocks_enter(inode, from);
|
|
|
|
|
2018-03-20 23:08:29 +08:00
|
|
|
free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2021-01-13 13:21:54 +08:00
|
|
|
if (free_from >= max_file_blocks(inode))
|
2016-05-05 19:13:03 +08:00
|
|
|
goto free_partial;
|
|
|
|
|
2014-08-15 07:32:54 +08:00
|
|
|
if (lock)
|
2019-02-02 17:33:01 +08:00
|
|
|
f2fs_lock_op(sbi);
|
f2fs: handle inline data operations
Hook inline data read/write, truncate, fallocate, setattr, etc.
Files need meet following 2 requirement to inline:
1) file size is not greater than MAX_INLINE_DATA;
2) file doesn't pre-allocate data blocks by fallocate().
FI_INLINE_DATA will not be set while creating a new regular inode because
most of the files are bigger than ~3.4K. Set FI_INLINE_DATA only when
data is submitted to block layer, ranther than set it while creating a new
inode, this also avoids converting data from inline to normal data block
and vice versa.
While writting inline data to inode block, the first data block should be
released if the file has a block indexed by i_addr[0].
On the other hand, when a file operation is appied to a file with inline
data, we need to test if this file can remain inline by doing this
operation, otherwise it should be convert into normal file by reserving
a new data block, copying inline data to this new block and clear
FI_INLINE_DATA flag. Because reserve a new data block here will make use
of i_addr[0], if we save inline data in i_addr[0..872], then the first
4 bytes would be overwriten. This problem can be avoided simply by
not using i_addr[0] for inline data.
Signed-off-by: Huajun Li <huajun.li@intel.com>
Signed-off-by: Haicheng Li <haicheng.li@linux.intel.com>
Signed-off-by: Weihong Xu <weihong.xu@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-11-10 23:13:20 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
2014-10-24 10:48:09 +08:00
|
|
|
if (IS_ERR(ipage)) {
|
|
|
|
err = PTR_ERR(ipage);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f2fs_has_inline_data(inode)) {
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_truncate_inline_inode(inode, ipage, from);
|
2014-10-24 10:48:09 +08:00
|
|
|
f2fs_put_page(ipage, 1);
|
2015-03-10 13:16:25 +08:00
|
|
|
truncate_page = true;
|
2014-10-24 10:48:09 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_new_dnode(&dn, inode, ipage, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
|
2012-11-02 16:09:44 +08:00
|
|
|
if (err) {
|
|
|
|
if (err == -ENOENT)
|
|
|
|
goto free_next;
|
2014-10-24 10:48:09 +08:00
|
|
|
goto out;
|
2014-10-16 01:24:34 +08:00
|
|
|
}
|
|
|
|
|
2016-01-26 15:39:35 +08:00
|
|
|
count = ADDRS_PER_PAGE(dn.node_page, inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
count -= dn.ofs_in_node;
|
2014-09-03 06:52:58 +08:00
|
|
|
f2fs_bug_on(sbi, count < 0);
|
f2fs: introduce a new global lock scheme
In the previous version, f2fs uses global locks according to the usage types,
such as directory operations, block allocation, block write, and so on.
Reference the following lock types in f2fs.h.
enum lock_type {
RENAME, /* for renaming operations */
DENTRY_OPS, /* for directory operations */
DATA_WRITE, /* for data write */
DATA_NEW, /* for data allocation */
DATA_TRUNC, /* for data truncate */
NODE_NEW, /* for node allocation */
NODE_TRUNC, /* for node truncate */
NODE_WRITE, /* for node write */
NR_LOCK_TYPE,
};
In that case, we lose the performance under the multi-threading environment,
since every types of operations must be conducted one at a time.
In order to address the problem, let's share the locks globally with a mutex
array regardless of any types.
So, let users grab a mutex and perform their jobs in parallel as much as
possbile.
For this, I propose a new global lock scheme as follows.
0. Data structure
- f2fs_sb_info -> mutex_lock[NR_GLOBAL_LOCKS]
- f2fs_sb_info -> node_write
1. mutex_lock_op(sbi)
- try to get an avaiable lock from the array.
- returns the index of the gottern lock variable.
2. mutex_unlock_op(sbi, index of the lock)
- unlock the given index of the lock.
3. mutex_lock_all(sbi)
- grab all the locks in the array before the checkpoint.
4. mutex_unlock_all(sbi)
- release all the locks in the array after checkpoint.
5. block_operations()
- call mutex_lock_all()
- sync_dirty_dir_inodes()
- grab node_write
- sync_node_pages()
Note that,
the pairs of mutex_lock_op()/mutex_unlock_op() and
mutex_lock_all()/mutex_unlock_all() should be used together.
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2012-11-22 15:21:29 +08:00
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_truncate_data_blocks_range(&dn, count);
|
2012-11-02 16:09:44 +08:00
|
|
|
free_from += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
free_next:
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
err = f2fs_truncate_inode_blocks(inode, free_from);
|
2014-11-12 03:01:01 +08:00
|
|
|
out:
|
|
|
|
if (lock)
|
2019-02-02 17:33:01 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
2016-05-05 19:13:03 +08:00
|
|
|
free_partial:
|
2014-10-24 10:48:09 +08:00
|
|
|
/* lastly zero out the first data page */
|
|
|
|
if (!err)
|
2015-03-10 13:16:25 +08:00
|
|
|
err = truncate_partial_data_page(inode, from, truncate_page);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2013-04-20 00:28:52 +08:00
|
|
|
trace_f2fs_truncate_blocks_exit(inode, err);
|
2012-11-02 16:09:44 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
|
|
|
|
{
|
|
|
|
u64 free_from = from;
|
2020-03-18 16:22:59 +08:00
|
|
|
int err;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
2020-03-18 16:22:59 +08:00
|
|
|
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
/*
|
|
|
|
* for compressed file, only support cluster size
|
|
|
|
* aligned truncation.
|
|
|
|
*/
|
2020-04-08 19:55:17 +08:00
|
|
|
if (f2fs_compressed_file(inode))
|
|
|
|
free_from = round_up(from,
|
|
|
|
F2FS_I(inode)->i_cluster_size << PAGE_SHIFT);
|
2020-03-18 16:22:59 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
err = f2fs_do_truncate_blocks(inode, free_from, lock);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
2021-08-09 10:21:04 +08:00
|
|
|
/*
|
|
|
|
* For compressed file, after release compress blocks, don't allow write
|
|
|
|
* direct, but we should allow write direct after truncate to zero.
|
|
|
|
*/
|
|
|
|
if (f2fs_compressed_file(inode) && !free_from
|
|
|
|
&& is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
|
|
|
clear_inode_flag(inode, FI_COMPRESS_RELEASED);
|
|
|
|
|
2020-08-10 18:38:45 +08:00
|
|
|
if (from != free_from) {
|
2020-03-18 16:22:59 +08:00
|
|
|
err = f2fs_truncate_partial_cluster(inode, from, lock);
|
2020-08-10 18:38:45 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2020-03-18 16:22:59 +08:00
|
|
|
#endif
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
2020-08-10 18:38:45 +08:00
|
|
|
return 0;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
}
|
|
|
|
|
2016-06-03 04:49:38 +08:00
|
|
|
int f2fs_truncate(struct inode *inode)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2015-08-24 17:39:42 +08:00
|
|
|
int err;
|
|
|
|
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
|
|
|
return -EIO;
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
|
|
|
S_ISLNK(inode->i_mode)))
|
2015-08-24 17:39:42 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2013-04-20 00:28:52 +08:00
|
|
|
trace_f2fs_truncate(inode);
|
|
|
|
|
2022-12-21 02:39:04 +08:00
|
|
|
if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE))
|
2017-03-10 07:24:24 +08:00
|
|
|
return -EIO;
|
2018-08-14 05:38:06 +08:00
|
|
|
|
2021-10-28 21:03:05 +08:00
|
|
|
err = f2fs_dquot_initialize(inode);
|
f2fs: fix to avoid inconsistent quota data
Occasionally, quota data may be corrupted detected by fsck:
Info: checkpoint state = 45 : crc compacted_summary unmount
[QUOTA WARNING] Usage inconsistent for ID 0:actual (1543036928, 762) != expected (1543032832, 762)
[ASSERT] (fsck_chk_quota_files:1986) --> Quota file is missing or invalid quota file content found.
[QUOTA WARNING] Usage inconsistent for ID 0:actual (1352478720, 344) != expected (1352474624, 344)
[ASSERT] (fsck_chk_quota_files:1986) --> Quota file is missing or invalid quota file content found.
[FSCK] Unreachable nat entries [Ok..] [0x0]
[FSCK] SIT valid block bitmap checking [Ok..]
[FSCK] Hard link checking for regular file [Ok..] [0x0]
[FSCK] valid_block_count matching with CP [Ok..] [0xdf299]
[FSCK] valid_node_count matcing with CP (de lookup) [Ok..] [0x2b01]
[FSCK] valid_node_count matcing with CP (nat lookup) [Ok..] [0x2b01]
[FSCK] valid_inode_count matched with CP [Ok..] [0x2665]
[FSCK] free segment_count matched with CP [Ok..] [0xcb04]
[FSCK] next block offset is free [Ok..]
[FSCK] fixing SIT types
[FSCK] other corrupted bugs [Fail]
The root cause is:
If we open file w/ readonly flag, disk quota info won't be initialized
for this file, however, following mmap() will force to convert inline
inode via f2fs_convert_inline_inode(), which may increase block usage
for this inode w/o updating quota data, it causes inconsistent disk quota
info.
The issue will happen in following stack:
open(file, O_RDONLY)
mmap(file)
- f2fs_convert_inline_inode
- f2fs_convert_inline_page
- f2fs_reserve_block
- f2fs_reserve_new_block
- f2fs_reserve_new_blocks
- f2fs_i_blocks_write
- dquot_claim_block
inode->i_blocks increase, but the dqb_curspace keep the size for the dquots
is NULL.
To fix this issue, let's call dquot_initialize() anyway in both
f2fs_truncate() and f2fs_convert_inline_inode() functions to avoid potential
inconsistent quota data issue.
Fixes: 0abd675e97e6 ("f2fs: support plain user/group quota")
Signed-off-by: Daiyue Zhang <zhangdaiyue1@huawei.com>
Signed-off-by: Dehe Gu <gudehe@huawei.com>
Signed-off-by: Junchao Jiang <jiangjunchao1@huawei.com>
Signed-off-by: Ge Qiu <qiuge@huawei.com>
Signed-off-by: Yi Chen <chenyi77@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2021-01-28 17:02:56 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2014-11-12 06:10:01 +08:00
|
|
|
/* we should check inline_data size */
|
2015-12-23 03:09:35 +08:00
|
|
|
if (!f2fs_may_inline_data(inode)) {
|
2015-08-24 17:39:42 +08:00
|
|
|
err = f2fs_convert_inline_inode(inode);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2014-11-12 06:10:01 +08:00
|
|
|
}
|
|
|
|
|
2019-02-02 17:33:01 +08:00
|
|
|
err = f2fs_truncate_blocks(inode, i_size_read(inode), true);
|
2015-08-24 17:39:42 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2023-07-06 03:01:08 +08:00
|
|
|
inode->i_mtime = inode_set_ctime_current(inode);
|
2016-10-15 02:51:23 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, false);
|
2015-08-24 17:39:42 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2022-08-27 14:58:49 +08:00
|
|
|
static bool f2fs_force_buffered_io(struct inode *inode, int rw)
|
2022-08-27 14:58:48 +08:00
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
|
|
|
|
if (!fscrypt_dio_supported(inode))
|
|
|
|
return true;
|
|
|
|
if (fsverity_active(inode))
|
|
|
|
return true;
|
|
|
|
if (f2fs_compressed_file(inode))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* disallow direct IO if any of devices has unaligned blksize */
|
|
|
|
if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
|
|
|
|
return true;
|
f2fs-for-6.1-rc1
This round looks fairly small comparing to the previous updates which includes
mostly minor bug fixes. Nevertheless, as we've still interested in improving
the stability, Chao added some debugging methods to diagnoze subtle runtime
inconsistency problem.
Enhancement
- store all the corruption or failure reasons in superblock
- detect meta inode, summary info, and block address inconsistency
- increase the limit for reserve_root for low-end devices
- add the number of compressed IO in iostat
Bug fix
- DIO write fix for zoned devices
- do out-of-place writes for cold files
- fix some stat updates (FS_CP_DATA_IO, dirty page count)
- fix race condition on setting FI_NO_EXTENT flag
- fix data races when freezing super
- fix wrong continue condition check in GC
- do not allow ATGC for LFS mode
In addition, there're some code enhancement and clean-ups as usual.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmNEVIkACgkQQBSofoJI
UNL/Qg//eu7k196yIKflDZmp5aJbb5ybpFmh7XkPiqAV17ns+R2uLGq68BvTs+Tg
rqCjB7j2kkBh1kN32R7aGcx6tcbHjWc94pi59YTGQ6+pwkop3KJxFHSwAaUw6y34
8NZwmsnrm9rv0A0QPhQPK19yWmG/2smUE9b/u7M3+20I1WANaxdS/vOKbZz/amOu
f/BvsIIGS7Zzm9OpBCvGmq9Qpd83jlH6PuYGTC/OVbCrUiAJEmwN8wGsKP/9qB/5
KxVpdlh3vxulS6ixNbMu2qw9GBAQpAOz50+eDL5ZtGvGIQNHZRpGlfpJoW1lz0EO
4fJtpf5OMGqUbNaPCTG4qQGYAtKWA9YnFeWSS7RViQ6MryRXZMK8ka5eIe5Qblcf
AXD/eU2gKzOu0fuvdBRCt/wTSb4gY8sMNhe4psDsZxfhaYIpX8Ee/XVa4d+Z4frg
irN9gid1k3laMTx9dwJL8m7gIFvy3pak6l3B0bA69fAXd3faI40enuyfubFxnDet
OuRNxj8j3J5C140ag5KOuBCRub2/aPaj9YSQqUstf64d8FzN/Ypn5iVPTs2DP/3D
bcAFBwCS2+MCsk9+ra0WldZ5awdd6CRHDkvaYeDEuLCaLHUCo6CXe3aIyWawJBvJ
RnghKNv82RIV+rQlI1/sg8lseoDnEZTp5iwDGw/qZ+ZUyn05apM=
=aZ9y
-----END PGP SIGNATURE-----
Merge tag 'f2fs-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"This round looks fairly small comparing to the previous updates and
includes mostly minor bug fixes. Nevertheless, as we've still
interested in improving the stability, Chao added some debugging
methods to diagnoze subtle runtime inconsistency problem.
Enhancements:
- store all the corruption or failure reasons in superblock
- detect meta inode, summary info, and block address inconsistency
- increase the limit for reserve_root for low-end devices
- add the number of compressed IO in iostat
Bug fixes:
- DIO write fix for zoned devices
- do out-of-place writes for cold files
- fix some stat updates (FS_CP_DATA_IO, dirty page count)
- fix race condition on setting FI_NO_EXTENT flag
- fix data races when freezing super
- fix wrong continue condition check in GC
- do not allow ATGC for LFS mode
In addition, there're some code enhancement and clean-ups as usual"
* tag 'f2fs-for-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (32 commits)
f2fs: change to use atomic_t type form sbi.atomic_files
f2fs: account swapfile inodes
f2fs: allow direct read for zoned device
f2fs: support recording errors into superblock
f2fs: support recording stop_checkpoint reason into super_block
f2fs: remove the unnecessary check in f2fs_xattr_fiemap
f2fs: introduce cp_status sysfs entry
f2fs: fix to detect corrupted meta ino
f2fs: fix to account FS_CP_DATA_IO correctly
f2fs: code clean and fix a type error
f2fs: add "c_len" into trace_f2fs_update_extent_tree_range for compressed file
f2fs: fix to do sanity check on summary info
f2fs: port to vfs{g,u}id_t and associated helpers
f2fs: fix to do sanity check on destination blkaddr during recovery
f2fs: let FI_OPU_WRITE override FADVISE_COLD_BIT
f2fs: fix race condition on setting FI_NO_EXTENT flag
f2fs: remove redundant check in f2fs_sanity_check_cluster
f2fs: add static init_idisk_time function to reduce the code
f2fs: fix typo
f2fs: fix wrong dirty page count when race between mmap and fallocate.
...
2022-10-11 11:28:41 +08:00
|
|
|
/*
|
|
|
|
* for blkzoned device, fallback direct IO to buffered IO, so
|
|
|
|
* all IOs can be serialized by log-structured write.
|
|
|
|
*/
|
|
|
|
if (f2fs_sb_has_blkzoned(sbi) && (rw == WRITE))
|
|
|
|
return true;
|
2022-08-27 14:58:49 +08:00
|
|
|
if (f2fs_lfs_mode(sbi) && rw == WRITE && F2FS_IO_ALIGNED(sbi))
|
|
|
|
return true;
|
|
|
|
if (is_sbi_flag_set(sbi, SBI_CP_DISABLED))
|
2022-08-27 14:58:48 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:12 +08:00
|
|
|
int f2fs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
2021-01-21 21:19:43 +08:00
|
|
|
struct kstat *stat, u32 request_mask, unsigned int query_flags)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
statx: Add a system call to make enhanced file info available
Add a system call to make extended file information available, including
file creation and some attribute flags where available through the
underlying filesystem.
The getattr inode operation is altered to take two additional arguments: a
u32 request_mask and an unsigned int flags that indicate the
synchronisation mode. This change is propagated to the vfs_getattr*()
function.
Functions like vfs_stat() are now inline wrappers around new functions
vfs_statx() and vfs_statx_fd() to reduce stack usage.
========
OVERVIEW
========
The idea was initially proposed as a set of xattrs that could be retrieved
with getxattr(), but the general preference proved to be for a new syscall
with an extended stat structure.
A number of requests were gathered for features to be included. The
following have been included:
(1) Make the fields a consistent size on all arches and make them large.
(2) Spare space, request flags and information flags are provided for
future expansion.
(3) Better support for the y2038 problem [Arnd Bergmann] (tv_sec is an
__s64).
(4) Creation time: The SMB protocol carries the creation time, which could
be exported by Samba, which will in turn help CIFS make use of
FS-Cache as that can be used for coherency data (stx_btime).
This is also specified in NFSv4 as a recommended attribute and could
be exported by NFSD [Steve French].
(5) Lightweight stat: Ask for just those details of interest, and allow a
netfs (such as NFS) to approximate anything not of interest, possibly
without going to the server [Trond Myklebust, Ulrich Drepper, Andreas
Dilger] (AT_STATX_DONT_SYNC).
(6) Heavyweight stat: Force a netfs to go to the server, even if it thinks
its cached attributes are up to date [Trond Myklebust]
(AT_STATX_FORCE_SYNC).
And the following have been left out for future extension:
(7) Data version number: Could be used by userspace NFS servers [Aneesh
Kumar].
Can also be used to modify fill_post_wcc() in NFSD which retrieves
i_version directly, but has just called vfs_getattr(). It could get
it from the kstat struct if it used vfs_xgetattr() instead.
(There's disagreement on the exact semantics of a single field, since
not all filesystems do this the same way).
(8) BSD stat compatibility: Including more fields from the BSD stat such
as creation time (st_btime) and inode generation number (st_gen)
[Jeremy Allison, Bernd Schubert].
(9) Inode generation number: Useful for FUSE and userspace NFS servers
[Bernd Schubert].
(This was asked for but later deemed unnecessary with the
open-by-handle capability available and caused disagreement as to
whether it's a security hole or not).
(10) Extra coherency data may be useful in making backups [Andreas Dilger].
(No particular data were offered, but things like last backup
timestamp, the data version number and the DOS archive bit would come
into this category).
(11) Allow the filesystem to indicate what it can/cannot provide: A
filesystem can now say it doesn't support a standard stat feature if
that isn't available, so if, for instance, inode numbers or UIDs don't
exist or are fabricated locally...
(This requires a separate system call - I have an fsinfo() call idea
for this).
(12) Store a 16-byte volume ID in the superblock that can be returned in
struct xstat [Steve French].
(Deferred to fsinfo).
(13) Include granularity fields in the time data to indicate the
granularity of each of the times (NFSv4 time_delta) [Steve French].
(Deferred to fsinfo).
(14) FS_IOC_GETFLAGS value. These could be translated to BSD's st_flags.
Note that the Linux IOC flags are a mess and filesystems such as Ext4
define flags that aren't in linux/fs.h, so translation in the kernel
may be a necessity (or, possibly, we provide the filesystem type too).
(Some attributes are made available in stx_attributes, but the general
feeling was that the IOC flags were to ext[234]-specific and shouldn't
be exposed through statx this way).
(15) Mask of features available on file (eg: ACLs, seclabel) [Brad Boyer,
Michael Kerrisk].
(Deferred, probably to fsinfo. Finding out if there's an ACL or
seclabal might require extra filesystem operations).
(16) Femtosecond-resolution timestamps [Dave Chinner].
(A __reserved field has been left in the statx_timestamp struct for
this - if there proves to be a need).
(17) A set multiple attributes syscall to go with this.
===============
NEW SYSTEM CALL
===============
The new system call is:
int ret = statx(int dfd,
const char *filename,
unsigned int flags,
unsigned int mask,
struct statx *buffer);
The dfd, filename and flags parameters indicate the file to query, in a
similar way to fstatat(). There is no equivalent of lstat() as that can be
emulated with statx() by passing AT_SYMLINK_NOFOLLOW in flags. There is
also no equivalent of fstat() as that can be emulated by passing a NULL
filename to statx() with the fd of interest in dfd.
Whether or not statx() synchronises the attributes with the backing store
can be controlled by OR'ing a value into the flags argument (this typically
only affects network filesystems):
(1) AT_STATX_SYNC_AS_STAT tells statx() to behave as stat() does in this
respect.
(2) AT_STATX_FORCE_SYNC will require a network filesystem to synchronise
its attributes with the server - which might require data writeback to
occur to get the timestamps correct.
(3) AT_STATX_DONT_SYNC will suppress synchronisation with the server in a
network filesystem. The resulting values should be considered
approximate.
mask is a bitmask indicating the fields in struct statx that are of
interest to the caller. The user should set this to STATX_BASIC_STATS to
get the basic set returned by stat(). It should be noted that asking for
more information may entail extra I/O operations.
buffer points to the destination for the data. This must be 256 bytes in
size.
======================
MAIN ATTRIBUTES RECORD
======================
The following structures are defined in which to return the main attribute
set:
struct statx_timestamp {
__s64 tv_sec;
__s32 tv_nsec;
__s32 __reserved;
};
struct statx {
__u32 stx_mask;
__u32 stx_blksize;
__u64 stx_attributes;
__u32 stx_nlink;
__u32 stx_uid;
__u32 stx_gid;
__u16 stx_mode;
__u16 __spare0[1];
__u64 stx_ino;
__u64 stx_size;
__u64 stx_blocks;
__u64 __spare1[1];
struct statx_timestamp stx_atime;
struct statx_timestamp stx_btime;
struct statx_timestamp stx_ctime;
struct statx_timestamp stx_mtime;
__u32 stx_rdev_major;
__u32 stx_rdev_minor;
__u32 stx_dev_major;
__u32 stx_dev_minor;
__u64 __spare2[14];
};
The defined bits in request_mask and stx_mask are:
STATX_TYPE Want/got stx_mode & S_IFMT
STATX_MODE Want/got stx_mode & ~S_IFMT
STATX_NLINK Want/got stx_nlink
STATX_UID Want/got stx_uid
STATX_GID Want/got stx_gid
STATX_ATIME Want/got stx_atime{,_ns}
STATX_MTIME Want/got stx_mtime{,_ns}
STATX_CTIME Want/got stx_ctime{,_ns}
STATX_INO Want/got stx_ino
STATX_SIZE Want/got stx_size
STATX_BLOCKS Want/got stx_blocks
STATX_BASIC_STATS [The stuff in the normal stat struct]
STATX_BTIME Want/got stx_btime{,_ns}
STATX_ALL [All currently available stuff]
stx_btime is the file creation time, stx_mask is a bitmask indicating the
data provided and __spares*[] are where as-yet undefined fields can be
placed.
Time fields are structures with separate seconds and nanoseconds fields
plus a reserved field in case we want to add even finer resolution. Note
that times will be negative if before 1970; in such a case, the nanosecond
fields will also be negative if not zero.
The bits defined in the stx_attributes field convey information about a
file, how it is accessed, where it is and what it does. The following
attributes map to FS_*_FL flags and are the same numerical value:
STATX_ATTR_COMPRESSED File is compressed by the fs
STATX_ATTR_IMMUTABLE File is marked immutable
STATX_ATTR_APPEND File is append-only
STATX_ATTR_NODUMP File is not to be dumped
STATX_ATTR_ENCRYPTED File requires key to decrypt in fs
Within the kernel, the supported flags are listed by:
KSTAT_ATTR_FS_IOC_FLAGS
[Are any other IOC flags of sufficient general interest to be exposed
through this interface?]
New flags include:
STATX_ATTR_AUTOMOUNT Object is an automount trigger
These are for the use of GUI tools that might want to mark files specially,
depending on what they are.
Fields in struct statx come in a number of classes:
(0) stx_dev_*, stx_blksize.
These are local system information and are always available.
(1) stx_mode, stx_nlinks, stx_uid, stx_gid, stx_[amc]time, stx_ino,
stx_size, stx_blocks.
These will be returned whether the caller asks for them or not. The
corresponding bits in stx_mask will be set to indicate whether they
actually have valid values.
If the caller didn't ask for them, then they may be approximated. For
example, NFS won't waste any time updating them from the server,
unless as a byproduct of updating something requested.
If the values don't actually exist for the underlying object (such as
UID or GID on a DOS file), then the bit won't be set in the stx_mask,
even if the caller asked for the value. In such a case, the returned
value will be a fabrication.
Note that there are instances where the type might not be valid, for
instance Windows reparse points.
(2) stx_rdev_*.
This will be set only if stx_mode indicates we're looking at a
blockdev or a chardev, otherwise will be 0.
(3) stx_btime.
Similar to (1), except this will be set to 0 if it doesn't exist.
=======
TESTING
=======
The following test program can be used to test the statx system call:
samples/statx/test-statx.c
Just compile and run, passing it paths to the files you want to examine.
The file is built automatically if CONFIG_SAMPLES is enabled.
Here's some example output. Firstly, an NFS directory that crosses to
another FSID. Note that the AUTOMOUNT attribute is set because transiting
this directory will cause d_automount to be invoked by the VFS.
[root@andromeda ~]# /tmp/test-statx -A /warthog/data
statx(/warthog/data) = 0
results=7ff
Size: 4096 Blocks: 8 IO Block: 1048576 directory
Device: 00:26 Inode: 1703937 Links: 125
Access: (3777/drwxrwxrwx) Uid: 0 Gid: 4041
Access: 2016-11-24 09:02:12.219699527+0000
Modify: 2016-11-17 10:44:36.225653653+0000
Change: 2016-11-17 10:44:36.225653653+0000
Attributes: 0000000000001000 (-------- -------- -------- -------- -------- -------- ---m---- --------)
Secondly, the result of automounting on that directory.
[root@andromeda ~]# /tmp/test-statx /warthog/data
statx(/warthog/data) = 0
results=7ff
Size: 4096 Blocks: 8 IO Block: 1048576 directory
Device: 00:27 Inode: 2 Links: 125
Access: (3777/drwxrwxrwx) Uid: 0 Gid: 4041
Access: 2016-11-24 09:02:12.219699527+0000
Modify: 2016-11-17 10:44:36.225653653+0000
Change: 2016-11-17 10:44:36.225653653+0000
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2017-02-01 00:46:22 +08:00
|
|
|
struct inode *inode = d_inode(path->dentry);
|
2017-05-03 23:59:12 +08:00
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
2022-03-09 19:09:35 +08:00
|
|
|
struct f2fs_inode *ri = NULL;
|
2017-05-03 23:59:12 +08:00
|
|
|
unsigned int flags;
|
|
|
|
|
2018-01-25 14:54:42 +08:00
|
|
|
if (f2fs_has_extra_attr(inode) &&
|
2018-10-24 18:34:26 +08:00
|
|
|
f2fs_sb_has_inode_crtime(F2FS_I_SB(inode)) &&
|
2018-01-25 14:54:42 +08:00
|
|
|
F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_crtime)) {
|
|
|
|
stat->result_mask |= STATX_BTIME;
|
|
|
|
stat->btime.tv_sec = fi->i_crtime.tv_sec;
|
|
|
|
stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
|
|
|
|
}
|
|
|
|
|
2022-08-27 14:58:50 +08:00
|
|
|
/*
|
|
|
|
* Return the DIO alignment restrictions if requested. We only return
|
|
|
|
* this information when requested, since on encrypted files it might
|
|
|
|
* take a fair bit of work to get if the file wasn't opened recently.
|
|
|
|
*
|
|
|
|
* f2fs sometimes supports DIO reads but not DIO writes. STATX_DIOALIGN
|
|
|
|
* cannot represent that, so in that case we report no DIO support.
|
|
|
|
*/
|
|
|
|
if ((request_mask & STATX_DIOALIGN) && S_ISREG(inode->i_mode)) {
|
|
|
|
unsigned int bsize = i_blocksize(inode);
|
|
|
|
|
|
|
|
stat->result_mask |= STATX_DIOALIGN;
|
|
|
|
if (!f2fs_force_buffered_io(inode, WRITE)) {
|
|
|
|
stat->dio_mem_align = bsize;
|
|
|
|
stat->dio_offset_align = bsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-05 13:59:04 +08:00
|
|
|
flags = fi->i_flags;
|
2020-03-25 10:22:09 +08:00
|
|
|
if (flags & F2FS_COMPR_FL)
|
|
|
|
stat->attributes |= STATX_ATTR_COMPRESSED;
|
2018-04-03 15:08:17 +08:00
|
|
|
if (flags & F2FS_APPEND_FL)
|
2017-05-03 23:59:12 +08:00
|
|
|
stat->attributes |= STATX_ATTR_APPEND;
|
2018-12-12 17:50:11 +08:00
|
|
|
if (IS_ENCRYPTED(inode))
|
2017-05-03 23:59:12 +08:00
|
|
|
stat->attributes |= STATX_ATTR_ENCRYPTED;
|
2018-04-03 15:08:17 +08:00
|
|
|
if (flags & F2FS_IMMUTABLE_FL)
|
2017-05-03 23:59:12 +08:00
|
|
|
stat->attributes |= STATX_ATTR_IMMUTABLE;
|
2018-04-03 15:08:17 +08:00
|
|
|
if (flags & F2FS_NODUMP_FL)
|
2017-05-03 23:59:12 +08:00
|
|
|
stat->attributes |= STATX_ATTR_NODUMP;
|
2019-10-30 04:41:40 +08:00
|
|
|
if (IS_VERITY(inode))
|
|
|
|
stat->attributes |= STATX_ATTR_VERITY;
|
2017-05-03 23:59:12 +08:00
|
|
|
|
2020-03-25 10:22:09 +08:00
|
|
|
stat->attributes_mask |= (STATX_ATTR_COMPRESSED |
|
|
|
|
STATX_ATTR_APPEND |
|
2017-05-03 23:59:12 +08:00
|
|
|
STATX_ATTR_ENCRYPTED |
|
|
|
|
STATX_ATTR_IMMUTABLE |
|
2019-10-30 04:41:40 +08:00
|
|
|
STATX_ATTR_NODUMP |
|
|
|
|
STATX_ATTR_VERITY);
|
2017-05-03 23:59:12 +08:00
|
|
|
|
2023-08-08 03:38:33 +08:00
|
|
|
generic_fillattr(idmap, request_mask, inode, stat);
|
2017-10-14 01:27:45 +08:00
|
|
|
|
|
|
|
/* we need to show initial sectors used for inline_data/dentries */
|
|
|
|
if ((S_ISREG(inode->i_mode) && f2fs_has_inline_data(inode)) ||
|
|
|
|
f2fs_has_inline_dentry(inode))
|
|
|
|
stat->blocks += (stat->size + 511) >> 9;
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_F2FS_FS_POSIX_ACL
|
2023-01-13 19:49:11 +08:00
|
|
|
static void __setattr_copy(struct mnt_idmap *idmap,
|
2021-01-21 21:19:27 +08:00
|
|
|
struct inode *inode, const struct iattr *attr)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
|
|
|
unsigned int ia_valid = attr->ia_valid;
|
|
|
|
|
2023-01-13 19:49:29 +08:00
|
|
|
i_uid_update(idmap, attr, inode);
|
|
|
|
i_gid_update(idmap, attr, inode);
|
2019-11-25 03:31:45 +08:00
|
|
|
if (ia_valid & ATTR_ATIME)
|
|
|
|
inode->i_atime = attr->ia_atime;
|
|
|
|
if (ia_valid & ATTR_MTIME)
|
|
|
|
inode->i_mtime = attr->ia_mtime;
|
|
|
|
if (ia_valid & ATTR_CTIME)
|
2023-07-06 03:01:08 +08:00
|
|
|
inode_set_ctime_to_ts(inode, attr->ia_ctime);
|
2012-11-02 16:09:44 +08:00
|
|
|
if (ia_valid & ATTR_MODE) {
|
|
|
|
umode_t mode = attr->ia_mode;
|
2023-01-13 19:49:30 +08:00
|
|
|
vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2022-09-09 17:17:44 +08:00
|
|
|
if (!vfsgid_in_group_p(vfsgid) &&
|
2023-01-13 19:49:27 +08:00
|
|
|
!capable_wrt_inode_uidgid(idmap, inode, CAP_FSETID))
|
2012-11-02 16:09:44 +08:00
|
|
|
mode &= ~S_ISGID;
|
2016-05-21 01:13:22 +08:00
|
|
|
set_acl_inode(inode, mode);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define __setattr_copy setattr_copy
|
|
|
|
#endif
|
|
|
|
|
2023-01-13 19:49:11 +08:00
|
|
|
int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
2021-01-21 21:19:43 +08:00
|
|
|
struct iattr *attr)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct inode *inode = d_inode(dentry);
|
2012-11-02 16:09:44 +08:00
|
|
|
int err;
|
|
|
|
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
|
|
|
return -EIO;
|
|
|
|
|
2020-12-26 18:07:01 +08:00
|
|
|
if (unlikely(IS_IMMUTABLE(inode)))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (unlikely(IS_APPEND(inode) &&
|
|
|
|
(attr->ia_valid & (ATTR_MODE | ATTR_UID |
|
|
|
|
ATTR_GID | ATTR_TIMES_SET))))
|
|
|
|
return -EPERM;
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if ((attr->ia_valid & ATTR_SIZE) &&
|
|
|
|
!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-01-13 19:49:11 +08:00
|
|
|
err = setattr_prepare(idmap, dentry, attr);
|
2012-11-02 16:09:44 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2017-11-30 04:35:32 +08:00
|
|
|
err = fscrypt_prepare_setattr(dentry, attr);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
err = fsverity_prepare_setattr(dentry, attr);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2023-01-13 19:49:28 +08:00
|
|
|
if (is_quota_modification(idmap, inode, attr)) {
|
2021-10-28 21:03:05 +08:00
|
|
|
err = f2fs_dquot_initialize(inode);
|
2017-07-09 00:13:07 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2023-01-13 19:49:29 +08:00
|
|
|
if (i_uid_needs_update(idmap, attr, inode) ||
|
|
|
|
i_gid_needs_update(idmap, attr, inode)) {
|
f2fs: guarantee journalled quota data by checkpoint
For journalled quota mode, let checkpoint to flush dquot dirty data
and quota file data to guarntee persistence of all quota sysfile in
last checkpoint, by this way, we can avoid corrupting quota sysfile
when encountering SPO.
The implementation is as below:
1. add a global state SBI_QUOTA_NEED_FLUSH to indicate that there is
cached dquot metadata changes in quota subsystem, and later checkpoint
should:
a) flush dquot metadata into quota file.
b) flush quota file to storage to keep file usage be consistent.
2. add a global state SBI_QUOTA_NEED_REPAIR to indicate that quota
operation failed due to -EIO or -ENOSPC, so later,
a) checkpoint will skip syncing dquot metadata.
b) CP_QUOTA_NEED_FSCK_FLAG will be set in last cp pack to give a
hint for fsck repairing.
3. add a global state SBI_QUOTA_SKIP_FLUSH, in checkpoint, if quota
data updating is very heavy, it may cause hungtask in block_operation().
To avoid this, if our retry time exceed threshold, let's just skip
flushing and retry in next checkpoint().
Signed-off-by: Weichao Guo <guoweichao@huawei.com>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: avoid warnings and set fsck flag]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-09-20 20:05:00 +08:00
|
|
|
f2fs_lock_op(F2FS_I_SB(inode));
|
2023-01-13 19:49:28 +08:00
|
|
|
err = dquot_transfer(idmap, inode, attr);
|
f2fs: guarantee journalled quota data by checkpoint
For journalled quota mode, let checkpoint to flush dquot dirty data
and quota file data to guarntee persistence of all quota sysfile in
last checkpoint, by this way, we can avoid corrupting quota sysfile
when encountering SPO.
The implementation is as below:
1. add a global state SBI_QUOTA_NEED_FLUSH to indicate that there is
cached dquot metadata changes in quota subsystem, and later checkpoint
should:
a) flush dquot metadata into quota file.
b) flush quota file to storage to keep file usage be consistent.
2. add a global state SBI_QUOTA_NEED_REPAIR to indicate that quota
operation failed due to -EIO or -ENOSPC, so later,
a) checkpoint will skip syncing dquot metadata.
b) CP_QUOTA_NEED_FSCK_FLAG will be set in last cp pack to give a
hint for fsck repairing.
3. add a global state SBI_QUOTA_SKIP_FLUSH, in checkpoint, if quota
data updating is very heavy, it may cause hungtask in block_operation().
To avoid this, if our retry time exceed threshold, let's just skip
flushing and retry in next checkpoint().
Signed-off-by: Weichao Guo <guoweichao@huawei.com>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: avoid warnings and set fsck flag]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-09-20 20:05:00 +08:00
|
|
|
if (err) {
|
|
|
|
set_sbi_flag(F2FS_I_SB(inode),
|
|
|
|
SBI_QUOTA_NEED_REPAIR);
|
|
|
|
f2fs_unlock_op(F2FS_I_SB(inode));
|
2017-07-09 00:13:07 +08:00
|
|
|
return err;
|
f2fs: guarantee journalled quota data by checkpoint
For journalled quota mode, let checkpoint to flush dquot dirty data
and quota file data to guarntee persistence of all quota sysfile in
last checkpoint, by this way, we can avoid corrupting quota sysfile
when encountering SPO.
The implementation is as below:
1. add a global state SBI_QUOTA_NEED_FLUSH to indicate that there is
cached dquot metadata changes in quota subsystem, and later checkpoint
should:
a) flush dquot metadata into quota file.
b) flush quota file to storage to keep file usage be consistent.
2. add a global state SBI_QUOTA_NEED_REPAIR to indicate that quota
operation failed due to -EIO or -ENOSPC, so later,
a) checkpoint will skip syncing dquot metadata.
b) CP_QUOTA_NEED_FSCK_FLAG will be set in last cp pack to give a
hint for fsck repairing.
3. add a global state SBI_QUOTA_SKIP_FLUSH, in checkpoint, if quota
data updating is very heavy, it may cause hungtask in block_operation().
To avoid this, if our retry time exceed threshold, let's just skip
flushing and retry in next checkpoint().
Signed-off-by: Weichao Guo <guoweichao@huawei.com>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: avoid warnings and set fsck flag]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-09-20 20:05:00 +08:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* update uid/gid under lock_op(), so that dquot and inode can
|
|
|
|
* be updated atomically.
|
|
|
|
*/
|
2023-01-13 19:49:29 +08:00
|
|
|
i_uid_update(idmap, attr, inode);
|
|
|
|
i_gid_update(idmap, attr, inode);
|
f2fs: guarantee journalled quota data by checkpoint
For journalled quota mode, let checkpoint to flush dquot dirty data
and quota file data to guarntee persistence of all quota sysfile in
last checkpoint, by this way, we can avoid corrupting quota sysfile
when encountering SPO.
The implementation is as below:
1. add a global state SBI_QUOTA_NEED_FLUSH to indicate that there is
cached dquot metadata changes in quota subsystem, and later checkpoint
should:
a) flush dquot metadata into quota file.
b) flush quota file to storage to keep file usage be consistent.
2. add a global state SBI_QUOTA_NEED_REPAIR to indicate that quota
operation failed due to -EIO or -ENOSPC, so later,
a) checkpoint will skip syncing dquot metadata.
b) CP_QUOTA_NEED_FSCK_FLAG will be set in last cp pack to give a
hint for fsck repairing.
3. add a global state SBI_QUOTA_SKIP_FLUSH, in checkpoint, if quota
data updating is very heavy, it may cause hungtask in block_operation().
To avoid this, if our retry time exceed threshold, let's just skip
flushing and retry in next checkpoint().
Signed-off-by: Weichao Guo <guoweichao@huawei.com>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
[Jaegeuk Kim: avoid warnings and set fsck flag]
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-09-20 20:05:00 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
|
|
|
f2fs_unlock_op(F2FS_I_SB(inode));
|
2017-07-09 00:13:07 +08:00
|
|
|
}
|
|
|
|
|
2014-09-15 18:02:09 +08:00
|
|
|
if (attr->ia_valid & ATTR_SIZE) {
|
2019-09-03 10:06:26 +08:00
|
|
|
loff_t old_size = i_size_read(inode);
|
|
|
|
|
|
|
|
if (attr->ia_size > MAX_INLINE_DATA(inode)) {
|
|
|
|
/*
|
|
|
|
* should convert inline inode before i_size_write to
|
|
|
|
* keep smaller than inline_data size with inline flag.
|
|
|
|
*/
|
|
|
|
err = f2fs_convert_inline_inode(inode);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
2018-08-05 23:04:25 +08:00
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2018-08-05 23:04:25 +08:00
|
|
|
|
|
|
|
truncate_setsize(inode, attr->ia_size);
|
|
|
|
|
2019-09-03 10:06:26 +08:00
|
|
|
if (attr->ia_size <= old_size)
|
2016-06-03 04:49:38 +08:00
|
|
|
err = f2fs_truncate(inode);
|
2018-08-05 23:04:25 +08:00
|
|
|
/*
|
|
|
|
* do not trim all blocks after i_size if target size is
|
|
|
|
* larger than i_size.
|
|
|
|
*/
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2018-08-05 23:04:25 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2015-12-01 11:36:16 +08:00
|
|
|
|
2020-02-27 19:30:03 +08:00
|
|
|
spin_lock(&F2FS_I(inode)->i_size_lock);
|
2023-07-06 03:01:08 +08:00
|
|
|
inode->i_mtime = inode_set_ctime_current(inode);
|
2017-10-09 17:55:19 +08:00
|
|
|
F2FS_I(inode)->last_disk_size = i_size_read(inode);
|
2020-02-27 19:30:03 +08:00
|
|
|
spin_unlock(&F2FS_I(inode)->i_size_lock);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:11 +08:00
|
|
|
__setattr_copy(idmap, inode, attr);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
if (attr->ia_valid & ATTR_MODE) {
|
2023-01-13 19:49:20 +08:00
|
|
|
err = posix_acl_chmod(idmap, dentry, f2fs_get_inode_mode(inode));
|
2020-12-25 16:52:27 +08:00
|
|
|
|
|
|
|
if (is_inode_flag_set(inode, FI_ACL_MODE)) {
|
|
|
|
if (!err)
|
|
|
|
inode->i_mode = F2FS_I(inode)->i_acl_mode;
|
2016-05-21 01:13:22 +08:00
|
|
|
clear_inode_flag(inode, FI_ACL_MODE);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 15:35:15 +08:00
|
|
|
/* file size may changed here */
|
2019-02-23 09:48:27 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
2016-10-15 04:30:31 +08:00
|
|
|
|
|
|
|
/* inode change will produce dirty node pages flushed by checkpoint */
|
|
|
|
f2fs_balance_fs(F2FS_I_SB(inode), true);
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct inode_operations f2fs_file_inode_operations = {
|
|
|
|
.getattr = f2fs_getattr,
|
|
|
|
.setattr = f2fs_setattr,
|
2022-09-22 23:17:00 +08:00
|
|
|
.get_inode_acl = f2fs_get_acl,
|
2013-12-20 21:16:45 +08:00
|
|
|
.set_acl = f2fs_set_acl,
|
2012-11-02 16:09:44 +08:00
|
|
|
.listxattr = f2fs_listxattr,
|
2014-06-08 03:30:14 +08:00
|
|
|
.fiemap = f2fs_fiemap,
|
2021-04-07 20:36:43 +08:00
|
|
|
.fileattr_get = f2fs_fileattr_get,
|
|
|
|
.fileattr_set = f2fs_fileattr_set,
|
2012-11-02 16:09:44 +08:00
|
|
|
};
|
|
|
|
|
2015-08-07 18:36:06 +08:00
|
|
|
static int fill_zero(struct inode *inode, pgoff_t index,
|
2012-11-02 16:09:44 +08:00
|
|
|
loff_t start, loff_t len)
|
|
|
|
{
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2012-11-02 16:09:44 +08:00
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
if (!len)
|
2015-08-07 18:36:06 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2016-01-08 06:15:04 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2013-01-25 17:33:41 +08:00
|
|
|
|
f2fs: use rw_sem instead of fs_lock(locks mutex)
The fs_locks is used to block other ops(ex, recovery) when doing checkpoint.
And each other operate routine(besides checkpoint) needs to acquire a fs_lock,
there is a terrible problem here, if these are too many concurrency threads acquiring
fs_lock, so that they will block each other and may lead to some performance problem,
but this is not the phenomenon we want to see.
Though there are some optimization patches introduced to enhance the usage of fs_lock,
but the thorough solution is using a *rw_sem* to replace the fs_lock.
Checkpoint routine takes write_sem, and other ops take read_sem, so that we can block
other ops(ex, recovery) when doing checkpoint, and other ops will not disturb each other,
this can avoid the problem described above completely.
Because of the weakness of rw_sem, the above change may introduce a potential problem
that the checkpoint thread might get starved if other threads are intensively locking
the read semaphore for I/O.(Pointed out by Xu Jin)
In order to avoid this, a wait_list is introduced, the appending read semaphore ops
will be dropped into the wait_list if checkpoint thread is waiting for write semaphore,
and will be waked up when checkpoint thread gives up write semaphore.
Thanks to Kim's previous review and test, and will be very glad to see other guys'
performance tests about this patch.
V2:
-fix the potential starvation problem.
-use more suitable func name suggested by Xu Jin.
Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
[Jaegeuk Kim: adjust minor coding standard]
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-09-27 18:08:30 +08:00
|
|
|
f2fs_lock_op(sbi);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
page = f2fs_get_new_data_page(inode, NULL, index, false);
|
f2fs: use rw_sem instead of fs_lock(locks mutex)
The fs_locks is used to block other ops(ex, recovery) when doing checkpoint.
And each other operate routine(besides checkpoint) needs to acquire a fs_lock,
there is a terrible problem here, if these are too many concurrency threads acquiring
fs_lock, so that they will block each other and may lead to some performance problem,
but this is not the phenomenon we want to see.
Though there are some optimization patches introduced to enhance the usage of fs_lock,
but the thorough solution is using a *rw_sem* to replace the fs_lock.
Checkpoint routine takes write_sem, and other ops take read_sem, so that we can block
other ops(ex, recovery) when doing checkpoint, and other ops will not disturb each other,
this can avoid the problem described above completely.
Because of the weakness of rw_sem, the above change may introduce a potential problem
that the checkpoint thread might get starved if other threads are intensively locking
the read semaphore for I/O.(Pointed out by Xu Jin)
In order to avoid this, a wait_list is introduced, the appending read semaphore ops
will be dropped into the wait_list if checkpoint thread is waiting for write semaphore,
and will be waked up when checkpoint thread gives up write semaphore.
Thanks to Kim's previous review and test, and will be very glad to see other guys'
performance tests about this patch.
V2:
-fix the potential starvation problem.
-use more suitable func name suggested by Xu Jin.
Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
[Jaegeuk Kim: adjust minor coding standard]
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-09-27 18:08:30 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2015-08-07 18:36:06 +08:00
|
|
|
if (IS_ERR(page))
|
|
|
|
return PTR_ERR(page);
|
|
|
|
|
2018-12-25 17:43:42 +08:00
|
|
|
f2fs_wait_on_page_writeback(page, DATA, true, true);
|
2015-08-07 18:36:06 +08:00
|
|
|
zero_user(page, start, len);
|
|
|
|
set_page_dirty(page);
|
|
|
|
f2fs_put_page(page, 1);
|
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2015-09-17 20:22:44 +08:00
|
|
|
while (pg_start < pg_end) {
|
2012-11-02 16:09:44 +08:00
|
|
|
struct dnode_of_data dn;
|
2015-09-17 20:22:44 +08:00
|
|
|
pgoff_t end_offset, count;
|
2013-01-11 13:09:38 +08:00
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
|
2012-11-02 16:09:44 +08:00
|
|
|
if (err) {
|
2015-09-17 20:22:44 +08:00
|
|
|
if (err == -ENOENT) {
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
pg_start = f2fs_get_next_page_offset(&dn,
|
|
|
|
pg_start);
|
2012-11-02 16:09:44 +08:00
|
|
|
continue;
|
2015-09-17 20:22:44 +08:00
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2016-01-26 15:39:35 +08:00
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
2015-09-17 20:22:44 +08:00
|
|
|
count = min(end_offset - dn.ofs_in_node, pg_end - pg_start);
|
|
|
|
|
|
|
|
f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_truncate_data_blocks_range(&dn, count);
|
2012-11-02 16:09:44 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
2015-09-17 20:22:44 +08:00
|
|
|
|
|
|
|
pg_start += count;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-12-21 03:12:12 +08:00
|
|
|
static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
|
|
|
pgoff_t pg_start, pg_end;
|
|
|
|
loff_t off_start, off_end;
|
2015-12-23 03:09:35 +08:00
|
|
|
int ret;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2015-12-23 03:09:35 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
f2fs: handle inline data operations
Hook inline data read/write, truncate, fallocate, setattr, etc.
Files need meet following 2 requirement to inline:
1) file size is not greater than MAX_INLINE_DATA;
2) file doesn't pre-allocate data blocks by fallocate().
FI_INLINE_DATA will not be set while creating a new regular inode because
most of the files are bigger than ~3.4K. Set FI_INLINE_DATA only when
data is submitted to block layer, ranther than set it while creating a new
inode, this also avoids converting data from inline to normal data block
and vice versa.
While writting inline data to inode block, the first data block should be
released if the file has a block indexed by i_addr[0].
On the other hand, when a file operation is appied to a file with inline
data, we need to test if this file can remain inline by doing this
operation, otherwise it should be convert into normal file by reserving
a new data block, copying inline data to this new block and clear
FI_INLINE_DATA flag. Because reserve a new data block here will make use
of i_addr[0], if we save inline data in i_addr[0..872], then the first
4 bytes would be overwriten. This problem can be avoided simply by
not using i_addr[0] for inline data.
Signed-off-by: Huajun Li <huajun.li@intel.com>
Signed-off-by: Haicheng Li <haicheng.li@linux.intel.com>
Signed-off-by: Weihong Xu <weihong.xu@intel.com>
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-11-10 23:13:20 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
|
|
|
|
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
off_start = offset & (PAGE_SIZE - 1);
|
|
|
|
off_end = (offset + len) & (PAGE_SIZE - 1);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
if (pg_start == pg_end) {
|
2015-08-07 18:36:06 +08:00
|
|
|
ret = fill_zero(inode, pg_start, off_start,
|
2012-11-02 16:09:44 +08:00
|
|
|
off_end - off_start);
|
2015-08-07 18:36:06 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2012-11-02 16:09:44 +08:00
|
|
|
} else {
|
2015-08-07 18:36:06 +08:00
|
|
|
if (off_start) {
|
|
|
|
ret = fill_zero(inode, pg_start++, off_start,
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
PAGE_SIZE - off_start);
|
2015-08-07 18:36:06 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (off_end) {
|
|
|
|
ret = fill_zero(inode, pg_end, 0, off_end);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
|
|
|
|
if (pg_start < pg_end) {
|
|
|
|
loff_t blk_start, blk_end;
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2013-04-09 09:16:44 +08:00
|
|
|
|
2016-01-08 06:15:04 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
blk_start = (loff_t)pg_start << PAGE_SHIFT;
|
|
|
|
blk_end = (loff_t)pg_end << PAGE_SHIFT;
|
2018-08-05 23:04:25 +08:00
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
f2fs-for-5.15-rc1
In this cycle, we've addressed some performance issues such as lock contention,
misbehaving compress_cache, allowing extent_cache for compressed files, and new
sysfs to adjust ra_size for fadvise. In order to diagnose the performance issues
quickly, we also added an iostat which shows the IO latencies periodically. On
the stability side, we've found two memory leakage cases in the error path in
compression flow. And, we've also fixed various corner cases in fiemap, quota,
checkpoint=disable, zstd, and so on.
Enhancement:
- avoid long checkpoint latency by releasing nat_tree_lock
- collect and show iostats periodically
- support extent_cache for compressed files
- add a sysfs entry to manage ra_size given fadvise(POSIX_FADV_SEQUENTIAL)
- report f2fs GC status via sysfs
- add discard_unit=%s in mount option to handle zoned device
Bug fix:
- fix two memory leakages when an error happens in the compressed IO flow
- fix commpress_cache to get the right LBA
- fix fiemap to deal with compressed case correctly
- fix wrong EIO returns due to SBI_NEED_FSCK
- fix missing writes when enabling checkpoint back
- fix quota deadlock
- fix zstd level mount option
In addition to the above major updates, we've cleaned up several code paths such
as dio, unnecessary operations, debugfs/f2fs/status, sanity check, and typos.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmEyw1sACgkQQBSofoJI
UNLJmA/+NHUgwUjLMcHvmLyp6QYpQDZtKj93/sRDo+YHOYNdYFjWWUb329PYTKWS
kEdzApCP+KHfVxeSkiL/x3qWP+RlTkIf96P0kR3/BKi0tjg25G2riFWztusDDFpt
xi+AW5sUFDvIx1tFumvQHAQedSwBgcZ96ovT5EwxEuONkljhZC9phEC6vSXz9nOR
e2EQIyezbC5O21np1KSeqSgqRMpVkJkVcEHy4VmpMBCLMOOYPepWwKw+yPaV/jR/
zUXdo2/53vma50M5LCDPCtjCtWQgLoeNeGLxyjfzQuTJU6TmtPY65JObLPt6pUSj
fRW6qIziTZbVYXzOWBD0EYilv2N4c3BNJdhQCpx2Vyjw9/LLxzqKPOUyzBoa1kjY
eZVvmaLXVCKsoJdHDSi7OH/4BqS6SuSZE8eO/nGkgswqiErHZ0Vwl3bFCWC7r/Bk
r2U5spJx/83XO6c9H1bzeWEies1DRtwnCDIRRuw35RtJ4uHZaqCfkuJ7rOBwC90X
4SpaAKdUxP2RWc3GKELBIhaqPn7vyMy9ile6VU14PjM8UcY5hyE87T2azqR8gGut
nVjRL4cbMGTPj6m1Qj8KqBRSaLuShe6AncUy7bNGiM+JlcLcdB6OJ1ZYLl9hjx2r
TbIouXThgcZ4SIK0DEaBLKz2b9/0TfaO9gw1XzpRma+bWA1pApM=
=W67o
-----END PGP SIGNATURE-----
Merge tag 'f2fs-for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this cycle, we've addressed some performance issues such as lock
contention, misbehaving compress_cache, allowing extent_cache for
compressed files, and new sysfs to adjust ra_size for fadvise.
In order to diagnose the performance issues quickly, we also added an
iostat which shows the IO latencies periodically.
On the stability side, we've found two memory leakage cases in the
error path in compression flow. And, we've also fixed various corner
cases in fiemap, quota, checkpoint=disable, zstd, and so on.
Enhancements:
- avoid long checkpoint latency by releasing nat_tree_lock
- collect and show iostats periodically
- support extent_cache for compressed files
- add a sysfs entry to manage ra_size given fadvise(POSIX_FADV_SEQUENTIAL)
- report f2fs GC status via sysfs
- add discard_unit=%s in mount option to handle zoned device
Bug fixes:
- fix two memory leakages when an error happens in the compressed IO flow
- fix commpress_cache to get the right LBA
- fix fiemap to deal with compressed case correctly
- fix wrong EIO returns due to SBI_NEED_FSCK
- fix missing writes when enabling checkpoint back
- fix quota deadlock
- fix zstd level mount option
In addition to the above major updates, we've cleaned up several code
paths such as dio, unnecessary operations, debugfs/f2fs/status, sanity
check, and typos"
* tag 'f2fs-for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (46 commits)
f2fs: should put a page beyond EOF when preparing a write
f2fs: deallocate compressed pages when error happens
f2fs: enable realtime discard iff device supports discard
f2fs: guarantee to write dirty data when enabling checkpoint back
f2fs: fix to unmap pages from userspace process in punch_hole()
f2fs: fix unexpected ENOENT comes from f2fs_map_blocks()
f2fs: fix to account missing .skipped_gc_rwsem
f2fs: adjust unlock order for cleanup
f2fs: Don't create discard thread when device doesn't support realtime discard
f2fs: rebuild nat_bits during umount
f2fs: introduce periodic iostat io latency traces
f2fs: separate out iostat feature
f2fs: compress: do sanity check on cluster
f2fs: fix description about main_blkaddr node
f2fs: convert S_IRUGO to 0444
f2fs: fix to keep compatibility of fault injection interface
f2fs: support fault injection for f2fs_kmem_cache_alloc()
f2fs: compress: allow write compress released file after truncate to zero
f2fs: correct comment in segment.h
f2fs: improve sbi status info in debugfs/f2fs/status
...
2021-09-05 01:48:47 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2018-08-05 23:04:25 +08:00
|
|
|
|
2021-08-25 19:34:19 +08:00
|
|
|
truncate_pagecache_range(inode, blk_start, blk_end - 1);
|
f2fs: introduce a new global lock scheme
In the previous version, f2fs uses global locks according to the usage types,
such as directory operations, block allocation, block write, and so on.
Reference the following lock types in f2fs.h.
enum lock_type {
RENAME, /* for renaming operations */
DENTRY_OPS, /* for directory operations */
DATA_WRITE, /* for data write */
DATA_NEW, /* for data allocation */
DATA_TRUNC, /* for data truncate */
NODE_NEW, /* for node allocation */
NODE_TRUNC, /* for node truncate */
NODE_WRITE, /* for node write */
NR_LOCK_TYPE,
};
In that case, we lose the performance under the multi-threading environment,
since every types of operations must be conducted one at a time.
In order to address the problem, let's share the locks globally with a mutex
array regardless of any types.
So, let users grab a mutex and perform their jobs in parallel as much as
possbile.
For this, I propose a new global lock scheme as follows.
0. Data structure
- f2fs_sb_info -> mutex_lock[NR_GLOBAL_LOCKS]
- f2fs_sb_info -> node_write
1. mutex_lock_op(sbi)
- try to get an avaiable lock from the array.
- returns the index of the gottern lock variable.
2. mutex_unlock_op(sbi, index of the lock)
- unlock the given index of the lock.
3. mutex_lock_all(sbi)
- grab all the locks in the array before the checkpoint.
4. mutex_unlock_all(sbi)
- release all the locks in the array after checkpoint.
5. block_operations()
- call mutex_lock_all()
- sync_dirty_dir_inodes()
- grab node_write
- sync_node_pages()
Note that,
the pairs of mutex_lock_op()/mutex_unlock_op() and
mutex_lock_all()/mutex_unlock_all() should be used together.
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2012-11-22 15:21:29 +08:00
|
|
|
|
f2fs: use rw_sem instead of fs_lock(locks mutex)
The fs_locks is used to block other ops(ex, recovery) when doing checkpoint.
And each other operate routine(besides checkpoint) needs to acquire a fs_lock,
there is a terrible problem here, if these are too many concurrency threads acquiring
fs_lock, so that they will block each other and may lead to some performance problem,
but this is not the phenomenon we want to see.
Though there are some optimization patches introduced to enhance the usage of fs_lock,
but the thorough solution is using a *rw_sem* to replace the fs_lock.
Checkpoint routine takes write_sem, and other ops take read_sem, so that we can block
other ops(ex, recovery) when doing checkpoint, and other ops will not disturb each other,
this can avoid the problem described above completely.
Because of the weakness of rw_sem, the above change may introduce a potential problem
that the checkpoint thread might get starved if other threads are intensively locking
the read semaphore for I/O.(Pointed out by Xu Jin)
In order to avoid this, a wait_list is introduced, the appending read semaphore ops
will be dropped into the wait_list if checkpoint thread is waiting for write semaphore,
and will be waked up when checkpoint thread gives up write semaphore.
Thanks to Kim's previous review and test, and will be very glad to see other guys'
performance tests about this patch.
V2:
-fix the potential starvation problem.
-use more suitable func name suggested by Xu Jin.
Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
[Jaegeuk Kim: adjust minor coding standard]
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-09-27 18:08:30 +08:00
|
|
|
f2fs_lock_op(sbi);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_truncate_hole(inode, pg_start, pg_end);
|
f2fs: use rw_sem instead of fs_lock(locks mutex)
The fs_locks is used to block other ops(ex, recovery) when doing checkpoint.
And each other operate routine(besides checkpoint) needs to acquire a fs_lock,
there is a terrible problem here, if these are too many concurrency threads acquiring
fs_lock, so that they will block each other and may lead to some performance problem,
but this is not the phenomenon we want to see.
Though there are some optimization patches introduced to enhance the usage of fs_lock,
but the thorough solution is using a *rw_sem* to replace the fs_lock.
Checkpoint routine takes write_sem, and other ops take read_sem, so that we can block
other ops(ex, recovery) when doing checkpoint, and other ops will not disturb each other,
this can avoid the problem described above completely.
Because of the weakness of rw_sem, the above change may introduce a potential problem
that the checkpoint thread might get starved if other threads are intensively locking
the read semaphore for I/O.(Pointed out by Xu Jin)
In order to avoid this, a wait_list is introduced, the appending read semaphore ops
will be dropped into the wait_list if checkpoint thread is waiting for write semaphore,
and will be waked up when checkpoint thread gives up write semaphore.
Thanks to Kim's previous review and test, and will be very glad to see other guys'
performance tests about this patch.
V2:
-fix the potential starvation problem.
-use more suitable func name suggested by Xu Jin.
Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
[Jaegeuk Kim: adjust minor coding standard]
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
2013-09-27 18:08:30 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
2018-08-05 23:04:25 +08:00
|
|
|
|
f2fs-for-5.15-rc1
In this cycle, we've addressed some performance issues such as lock contention,
misbehaving compress_cache, allowing extent_cache for compressed files, and new
sysfs to adjust ra_size for fadvise. In order to diagnose the performance issues
quickly, we also added an iostat which shows the IO latencies periodically. On
the stability side, we've found two memory leakage cases in the error path in
compression flow. And, we've also fixed various corner cases in fiemap, quota,
checkpoint=disable, zstd, and so on.
Enhancement:
- avoid long checkpoint latency by releasing nat_tree_lock
- collect and show iostats periodically
- support extent_cache for compressed files
- add a sysfs entry to manage ra_size given fadvise(POSIX_FADV_SEQUENTIAL)
- report f2fs GC status via sysfs
- add discard_unit=%s in mount option to handle zoned device
Bug fix:
- fix two memory leakages when an error happens in the compressed IO flow
- fix commpress_cache to get the right LBA
- fix fiemap to deal with compressed case correctly
- fix wrong EIO returns due to SBI_NEED_FSCK
- fix missing writes when enabling checkpoint back
- fix quota deadlock
- fix zstd level mount option
In addition to the above major updates, we've cleaned up several code paths such
as dio, unnecessary operations, debugfs/f2fs/status, sanity check, and typos.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmEyw1sACgkQQBSofoJI
UNLJmA/+NHUgwUjLMcHvmLyp6QYpQDZtKj93/sRDo+YHOYNdYFjWWUb329PYTKWS
kEdzApCP+KHfVxeSkiL/x3qWP+RlTkIf96P0kR3/BKi0tjg25G2riFWztusDDFpt
xi+AW5sUFDvIx1tFumvQHAQedSwBgcZ96ovT5EwxEuONkljhZC9phEC6vSXz9nOR
e2EQIyezbC5O21np1KSeqSgqRMpVkJkVcEHy4VmpMBCLMOOYPepWwKw+yPaV/jR/
zUXdo2/53vma50M5LCDPCtjCtWQgLoeNeGLxyjfzQuTJU6TmtPY65JObLPt6pUSj
fRW6qIziTZbVYXzOWBD0EYilv2N4c3BNJdhQCpx2Vyjw9/LLxzqKPOUyzBoa1kjY
eZVvmaLXVCKsoJdHDSi7OH/4BqS6SuSZE8eO/nGkgswqiErHZ0Vwl3bFCWC7r/Bk
r2U5spJx/83XO6c9H1bzeWEies1DRtwnCDIRRuw35RtJ4uHZaqCfkuJ7rOBwC90X
4SpaAKdUxP2RWc3GKELBIhaqPn7vyMy9ile6VU14PjM8UcY5hyE87T2azqR8gGut
nVjRL4cbMGTPj6m1Qj8KqBRSaLuShe6AncUy7bNGiM+JlcLcdB6OJ1ZYLl9hjx2r
TbIouXThgcZ4SIK0DEaBLKz2b9/0TfaO9gw1XzpRma+bWA1pApM=
=W67o
-----END PGP SIGNATURE-----
Merge tag 'f2fs-for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this cycle, we've addressed some performance issues such as lock
contention, misbehaving compress_cache, allowing extent_cache for
compressed files, and new sysfs to adjust ra_size for fadvise.
In order to diagnose the performance issues quickly, we also added an
iostat which shows the IO latencies periodically.
On the stability side, we've found two memory leakage cases in the
error path in compression flow. And, we've also fixed various corner
cases in fiemap, quota, checkpoint=disable, zstd, and so on.
Enhancements:
- avoid long checkpoint latency by releasing nat_tree_lock
- collect and show iostats periodically
- support extent_cache for compressed files
- add a sysfs entry to manage ra_size given fadvise(POSIX_FADV_SEQUENTIAL)
- report f2fs GC status via sysfs
- add discard_unit=%s in mount option to handle zoned device
Bug fixes:
- fix two memory leakages when an error happens in the compressed IO flow
- fix commpress_cache to get the right LBA
- fix fiemap to deal with compressed case correctly
- fix wrong EIO returns due to SBI_NEED_FSCK
- fix missing writes when enabling checkpoint back
- fix quota deadlock
- fix zstd level mount option
In addition to the above major updates, we've cleaned up several code
paths such as dio, unnecessary operations, debugfs/f2fs/status, sanity
check, and typos"
* tag 'f2fs-for-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (46 commits)
f2fs: should put a page beyond EOF when preparing a write
f2fs: deallocate compressed pages when error happens
f2fs: enable realtime discard iff device supports discard
f2fs: guarantee to write dirty data when enabling checkpoint back
f2fs: fix to unmap pages from userspace process in punch_hole()
f2fs: fix unexpected ENOENT comes from f2fs_map_blocks()
f2fs: fix to account missing .skipped_gc_rwsem
f2fs: adjust unlock order for cleanup
f2fs: Don't create discard thread when device doesn't support realtime discard
f2fs: rebuild nat_bits during umount
f2fs: introduce periodic iostat io latency traces
f2fs: separate out iostat feature
f2fs: compress: do sanity check on cluster
f2fs: fix description about main_blkaddr node
f2fs: convert S_IRUGO to 0444
f2fs: fix to keep compatibility of fault injection interface
f2fs: support fault injection for f2fs_kmem_cache_alloc()
f2fs: compress: allow write compress released file after truncate to zero
f2fs: correct comment in segment.h
f2fs: improve sbi status info in debugfs/f2fs/status
...
2021-09-05 01:48:47 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr,
|
|
|
|
int *do_replace, pgoff_t off, pgoff_t len)
|
2015-05-06 13:09:46 +08:00
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct dnode_of_data dn;
|
2016-07-09 08:42:21 +08:00
|
|
|
int ret, done, i;
|
2015-07-16 18:18:11 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
next_dnode:
|
2015-10-08 03:28:41 +08:00
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
|
2015-10-08 03:28:41 +08:00
|
|
|
if (ret && ret != -ENOENT) {
|
|
|
|
return ret;
|
|
|
|
} else if (ret == -ENOENT) {
|
2016-07-09 08:42:21 +08:00
|
|
|
if (dn.max_level == 0)
|
|
|
|
return -ENOENT;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
done = min((pgoff_t)ADDRS_PER_BLOCK(inode) -
|
|
|
|
dn.ofs_in_node, len);
|
2016-07-09 08:42:21 +08:00
|
|
|
blkaddr += done;
|
|
|
|
do_replace += done;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
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++) {
|
2020-02-14 17:44:10 +08:00
|
|
|
*blkaddr = f2fs_data_blkaddr(&dn);
|
f2fs: introduce DATA_GENERIC_ENHANCE
Previously, f2fs_is_valid_blkaddr(, blkaddr, DATA_GENERIC) will check
whether @blkaddr locates in main area or not.
That check is weak, since the block address in range of main area can
point to the address which is not valid in segment info table, and we
can not detect such condition, we may suffer worse corruption as system
continues running.
So this patch introduce DATA_GENERIC_ENHANCE to enhance the sanity check
which trigger SIT bitmap check rather than only range check.
This patch did below changes as wel:
- set SBI_NEED_FSCK in f2fs_is_valid_blkaddr().
- get rid of is_valid_data_blkaddr() to avoid panic if blkaddr is invalid.
- introduce verify_fio_blkaddr() to wrap fio {new,old}_blkaddr validation check.
- spread blkaddr check in:
* f2fs_get_node_info()
* __read_out_blkaddrs()
* f2fs_submit_page_read()
* ra_data_block()
* do_recover_data()
This patch can fix bug reported from bugzilla below:
https://bugzilla.kernel.org/show_bug.cgi?id=203215
https://bugzilla.kernel.org/show_bug.cgi?id=203223
https://bugzilla.kernel.org/show_bug.cgi?id=203231
https://bugzilla.kernel.org/show_bug.cgi?id=203235
https://bugzilla.kernel.org/show_bug.cgi?id=203241
= Update by Jaegeuk Kim =
DATA_GENERIC_ENHANCE enhanced to validate block addresses on read/write paths.
But, xfstest/generic/446 compalins some generated kernel messages saying invalid
bitmap was detected when reading a block. The reaons is, when we get the
block addresses from extent_cache, there is no lock to synchronize it from
truncating the blocks in parallel.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-04-15 15:26:32 +08:00
|
|
|
|
|
|
|
if (__is_valid_data_blkaddr(*blkaddr) &&
|
|
|
|
!f2fs_is_valid_blkaddr(sbi, *blkaddr,
|
|
|
|
DATA_GENERIC_ENHANCE)) {
|
|
|
|
f2fs_put_dnode(&dn);
|
2022-09-28 23:38:54 +08:00
|
|
|
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
2019-06-20 11:36:14 +08:00
|
|
|
return -EFSCORRUPTED;
|
f2fs: introduce DATA_GENERIC_ENHANCE
Previously, f2fs_is_valid_blkaddr(, blkaddr, DATA_GENERIC) will check
whether @blkaddr locates in main area or not.
That check is weak, since the block address in range of main area can
point to the address which is not valid in segment info table, and we
can not detect such condition, we may suffer worse corruption as system
continues running.
So this patch introduce DATA_GENERIC_ENHANCE to enhance the sanity check
which trigger SIT bitmap check rather than only range check.
This patch did below changes as wel:
- set SBI_NEED_FSCK in f2fs_is_valid_blkaddr().
- get rid of is_valid_data_blkaddr() to avoid panic if blkaddr is invalid.
- introduce verify_fio_blkaddr() to wrap fio {new,old}_blkaddr validation check.
- spread blkaddr check in:
* f2fs_get_node_info()
* __read_out_blkaddrs()
* f2fs_submit_page_read()
* ra_data_block()
* do_recover_data()
This patch can fix bug reported from bugzilla below:
https://bugzilla.kernel.org/show_bug.cgi?id=203215
https://bugzilla.kernel.org/show_bug.cgi?id=203223
https://bugzilla.kernel.org/show_bug.cgi?id=203231
https://bugzilla.kernel.org/show_bug.cgi?id=203235
https://bugzilla.kernel.org/show_bug.cgi?id=203241
= Update by Jaegeuk Kim =
DATA_GENERIC_ENHANCE enhanced to validate block addresses on read/write paths.
But, xfstest/generic/446 compalins some generated kernel messages saying invalid
bitmap was detected when reading a block. The reaons is, when we get the
block addresses from extent_cache, there is no lock to synchronize it from
truncating the blocks in parallel.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-04-15 15:26:32 +08:00
|
|
|
}
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2020-02-14 17:44:12 +08:00
|
|
|
if (f2fs_lfs_mode(sbi)) {
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
2019-08-15 19:45:36 +08:00
|
|
|
return -EOPNOTSUPP;
|
2016-07-09 08:42:21 +08:00
|
|
|
}
|
|
|
|
|
2015-10-08 03:28:41 +08:00
|
|
|
/* do not invalidate this block address */
|
2016-02-24 17:16:47 +08:00
|
|
|
f2fs_update_data_blkaddr(&dn, NULL_ADDR);
|
2016-07-09 08:42:21 +08:00
|
|
|
*do_replace = 1;
|
2015-05-06 13:09:46 +08:00
|
|
|
}
|
2015-10-08 03:28:41 +08:00
|
|
|
}
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
next:
|
|
|
|
len -= done;
|
|
|
|
off += done;
|
|
|
|
if (len)
|
|
|
|
goto next_dnode;
|
|
|
|
return 0;
|
|
|
|
}
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,
|
|
|
|
int *do_replace, pgoff_t off, int len)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
int ret, i;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
for (i = 0; i < len; i++, do_replace++, blkaddr++) {
|
|
|
|
if (*do_replace == 0)
|
|
|
|
continue;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
|
2016-07-09 08:42:21 +08:00
|
|
|
if (ret) {
|
|
|
|
dec_valid_block_count(sbi, inode, 1);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_invalidate_blocks(sbi, *blkaddr);
|
2016-07-09 08:42:21 +08:00
|
|
|
} else {
|
|
|
|
f2fs_update_data_blkaddr(&dn, *blkaddr);
|
2016-06-04 10:29:38 +08:00
|
|
|
}
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
|
|
|
block_t *blkaddr, int *do_replace,
|
|
|
|
pgoff_t src, pgoff_t dst, pgoff_t len, bool full)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(src_inode);
|
|
|
|
pgoff_t i = 0;
|
|
|
|
int ret;
|
2016-06-04 10:29:38 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
while (i < len) {
|
|
|
|
if (blkaddr[i] == NULL_ADDR && !full) {
|
|
|
|
i++;
|
|
|
|
continue;
|
2015-10-08 03:28:41 +08:00
|
|
|
}
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
if (do_replace[i] || blkaddr[i] == NULL_ADDR) {
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
struct node_info ni;
|
|
|
|
size_t new_size;
|
|
|
|
pgoff_t ilen;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
set_new_dnode(&dn, dst_inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
|
2016-07-09 08:42:21 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2021-12-14 06:16:32 +08:00
|
|
|
ret = f2fs_get_node_info(sbi, dn.nid, &ni, false);
|
2018-07-17 00:02:17 +08:00
|
|
|
if (ret) {
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
ilen = min((pgoff_t)
|
|
|
|
ADDRS_PER_PAGE(dn.node_page, dst_inode) -
|
|
|
|
dn.ofs_in_node, len - i);
|
|
|
|
do {
|
2020-02-14 17:44:10 +08:00
|
|
|
dn.data_blkaddr = f2fs_data_blkaddr(&dn);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_truncate_data_blocks_range(&dn, 1);
|
2016-07-09 08:42:21 +08:00
|
|
|
|
|
|
|
if (do_replace[i]) {
|
|
|
|
f2fs_i_blocks_write(src_inode,
|
2017-07-09 00:13:07 +08:00
|
|
|
1, false, false);
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_i_blocks_write(dst_inode,
|
2017-07-09 00:13:07 +08:00
|
|
|
1, true, false);
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
|
|
|
|
blkaddr[i], ni.version, true, false);
|
|
|
|
|
|
|
|
do_replace[i] = 0;
|
|
|
|
}
|
|
|
|
dn.ofs_in_node++;
|
|
|
|
i++;
|
2019-11-07 17:29:00 +08:00
|
|
|
new_size = (loff_t)(dst + i) << PAGE_SHIFT;
|
2016-07-09 08:42:21 +08:00
|
|
|
if (dst_inode->i_size < new_size)
|
|
|
|
f2fs_i_size_write(dst_inode, new_size);
|
2016-11-24 02:51:17 +08:00
|
|
|
} while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
|
2015-10-08 03:28:41 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
} else {
|
|
|
|
struct page *psrc, *pdst;
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
psrc = f2fs_get_lock_data_page(src_inode,
|
|
|
|
src + i, true);
|
2016-07-09 08:42:21 +08:00
|
|
|
if (IS_ERR(psrc))
|
|
|
|
return PTR_ERR(psrc);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i,
|
2016-07-09 08:42:21 +08:00
|
|
|
true);
|
|
|
|
if (IS_ERR(pdst)) {
|
|
|
|
f2fs_put_page(psrc, 1);
|
|
|
|
return PTR_ERR(pdst);
|
|
|
|
}
|
2022-07-17 16:36:13 +08:00
|
|
|
memcpy_page(pdst, 0, psrc, 0, PAGE_SIZE);
|
2016-07-09 08:42:21 +08:00
|
|
|
set_page_dirty(pdst);
|
|
|
|
f2fs_put_page(pdst, 1);
|
2015-10-08 03:28:41 +08:00
|
|
|
f2fs_put_page(psrc, 1);
|
2015-05-06 13:09:46 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_truncate_hole(src_inode,
|
|
|
|
src + i, src + i + 1);
|
2016-07-09 08:42:21 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
i++;
|
|
|
|
}
|
2015-10-08 03:28:41 +08:00
|
|
|
}
|
|
|
|
return 0;
|
2016-07-09 08:42:21 +08:00
|
|
|
}
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
static int __exchange_data_block(struct inode *src_inode,
|
|
|
|
struct inode *dst_inode, pgoff_t src, pgoff_t dst,
|
2016-07-17 12:59:22 +08:00
|
|
|
pgoff_t len, bool full)
|
2016-07-09 08:42:21 +08:00
|
|
|
{
|
|
|
|
block_t *src_blkaddr;
|
|
|
|
int *do_replace;
|
2016-07-17 12:59:22 +08:00
|
|
|
pgoff_t olen;
|
2016-07-09 08:42:21 +08:00
|
|
|
int ret;
|
|
|
|
|
2016-07-17 12:59:22 +08:00
|
|
|
while (len) {
|
2019-03-25 21:08:19 +08:00
|
|
|
olen = min((pgoff_t)4 * ADDRS_PER_BLOCK(src_inode), len);
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2017-11-30 19:28:18 +08:00
|
|
|
src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
|
treewide: Use array_size in f2fs_kvzalloc()
The f2fs_kvzalloc() function has no 2-factor argument form, so
multiplication factors need to be wrapped in array_size(). This patch
replaces cases of:
f2fs_kvzalloc(handle, a * b, gfp)
with:
f2fs_kvzalloc(handle, array_size(a, b), gfp)
as well as handling cases of:
f2fs_kvzalloc(handle, a * b * c, gfp)
with:
f2fs_kvzalloc(handle, array3_size(a, b, c), gfp)
This does, however, attempt to ignore constant size factors like:
f2fs_kvzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
f2fs_kvzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
f2fs_kvzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
f2fs_kvzalloc(HANDLE,
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
f2fs_kvzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
f2fs_kvzalloc(HANDLE, C1 * C2 * C3, ...)
|
f2fs_kvzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression HANDLE;
expression E1, E2;
constant C1, C2;
@@
(
f2fs_kvzalloc(HANDLE, C1 * C2, ...)
|
f2fs_kvzalloc(HANDLE,
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:28:35 +08:00
|
|
|
array_size(olen, sizeof(block_t)),
|
2019-12-04 11:02:15 +08:00
|
|
|
GFP_NOFS);
|
2016-07-17 12:59:22 +08:00
|
|
|
if (!src_blkaddr)
|
|
|
|
return -ENOMEM;
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2017-11-30 19:28:18 +08:00
|
|
|
do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
|
treewide: Use array_size in f2fs_kvzalloc()
The f2fs_kvzalloc() function has no 2-factor argument form, so
multiplication factors need to be wrapped in array_size(). This patch
replaces cases of:
f2fs_kvzalloc(handle, a * b, gfp)
with:
f2fs_kvzalloc(handle, array_size(a, b), gfp)
as well as handling cases of:
f2fs_kvzalloc(handle, a * b * c, gfp)
with:
f2fs_kvzalloc(handle, array3_size(a, b, c), gfp)
This does, however, attempt to ignore constant size factors like:
f2fs_kvzalloc(handle, 4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
expression HANDLE;
type TYPE;
expression THING, E;
@@
(
f2fs_kvzalloc(HANDLE,
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
f2fs_kvzalloc(HANDLE,
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression HANDLE;
expression COUNT;
typedef u8;
typedef __u8;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(char) * COUNT
+ COUNT
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
expression HANDLE;
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
expression HANDLE;
identifier SIZE, COUNT;
@@
f2fs_kvzalloc(HANDLE,
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression HANDLE;
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression HANDLE;
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
f2fs_kvzalloc(HANDLE,
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
expression HANDLE;
identifier STRIDE, SIZE, COUNT;
@@
(
f2fs_kvzalloc(HANDLE,
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
f2fs_kvzalloc(HANDLE,
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression HANDLE;
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
f2fs_kvzalloc(HANDLE, C1 * C2 * C3, ...)
|
f2fs_kvzalloc(HANDLE,
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression HANDLE;
expression E1, E2;
constant C1, C2;
@@
(
f2fs_kvzalloc(HANDLE, C1 * C2, ...)
|
f2fs_kvzalloc(HANDLE,
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:28:35 +08:00
|
|
|
array_size(olen, sizeof(int)),
|
2019-12-04 11:02:15 +08:00
|
|
|
GFP_NOFS);
|
2016-07-17 12:59:22 +08:00
|
|
|
if (!do_replace) {
|
|
|
|
kvfree(src_blkaddr);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2016-07-17 12:59:22 +08:00
|
|
|
ret = __read_out_blkaddrs(src_inode, src_blkaddr,
|
|
|
|
do_replace, src, olen);
|
|
|
|
if (ret)
|
|
|
|
goto roll_back;
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2016-07-17 12:59:22 +08:00
|
|
|
ret = __clone_blkaddrs(src_inode, dst_inode, src_blkaddr,
|
|
|
|
do_replace, src, dst, olen, full);
|
|
|
|
if (ret)
|
|
|
|
goto roll_back;
|
|
|
|
|
|
|
|
src += olen;
|
|
|
|
dst += olen;
|
|
|
|
len -= olen;
|
|
|
|
|
|
|
|
kvfree(src_blkaddr);
|
|
|
|
kvfree(do_replace);
|
|
|
|
}
|
2016-07-09 08:42:21 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
roll_back:
|
2018-05-28 23:47:19 +08:00
|
|
|
__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen);
|
2016-07-09 08:42:21 +08:00
|
|
|
kvfree(src_blkaddr);
|
|
|
|
kvfree(do_replace);
|
2015-10-08 03:28:41 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
static int f2fs_do_collapse(struct inode *inode, loff_t offset, loff_t len)
|
2015-10-08 03:28:41 +08:00
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2019-06-20 22:42:08 +08:00
|
|
|
pgoff_t nrpages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
2018-07-25 11:11:56 +08:00
|
|
|
pgoff_t start = offset >> PAGE_SHIFT;
|
|
|
|
pgoff_t end = (offset + len) >> PAGE_SHIFT;
|
2016-07-09 08:42:21 +08:00
|
|
|
int ret;
|
2015-10-08 03:28:41 +08:00
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2016-07-13 02:07:52 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
/* avoid gc operation during block exchange */
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2016-07-13 02:07:52 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
f2fs_lock_op(sbi);
|
|
|
|
f2fs_drop_extent_tree(inode);
|
|
|
|
truncate_pagecache(inode, offset);
|
2016-07-09 08:42:21 +08:00
|
|
|
ret = __exchange_data_block(inode, inode, end, start, nrpages - end, true);
|
|
|
|
f2fs_unlock_op(sbi);
|
2018-07-25 11:11:56 +08:00
|
|
|
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2015-05-06 13:09:46 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
|
|
|
{
|
|
|
|
loff_t new_size;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (offset + len >= i_size_read(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* collapse range should be aligned to block size of f2fs. */
|
|
|
|
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-12-23 03:09:35 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-06-18 04:59:05 +08:00
|
|
|
|
2015-05-06 13:09:46 +08:00
|
|
|
/* write out all dirty pages from offset */
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
|
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
ret = f2fs_do_collapse(inode, offset, len);
|
2015-05-06 13:09:46 +08:00
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-05-06 13:09:46 +08:00
|
|
|
|
2015-10-08 03:28:41 +08:00
|
|
|
/* write out all moved pages, if possible */
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2015-10-08 03:28:41 +08:00
|
|
|
filemap_write_and_wait_range(inode->i_mapping, offset, LLONG_MAX);
|
|
|
|
truncate_pagecache(inode, offset);
|
|
|
|
|
2015-05-06 13:09:46 +08:00
|
|
|
new_size = i_size_read(inode) - len;
|
2019-02-02 17:33:01 +08:00
|
|
|
ret = f2fs_truncate_blocks(inode, new_size, true);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2015-05-06 13:09:46 +08:00
|
|
|
if (!ret)
|
2016-05-21 00:22:03 +08:00
|
|
|
f2fs_i_size_write(inode, new_size);
|
2015-05-06 13:09:46 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
|
|
|
pgoff_t end)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
|
|
|
pgoff_t index = start;
|
|
|
|
unsigned int ofs_in_node = dn->ofs_in_node;
|
|
|
|
blkcnt_t count = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (; index < end; index++, dn->ofs_in_node++) {
|
2020-02-14 17:44:10 +08:00
|
|
|
if (f2fs_data_blkaddr(dn) == NULL_ADDR)
|
2016-05-09 19:56:31 +08:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
dn->ofs_in_node = ofs_in_node;
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_reserve_new_blocks(dn, count);
|
2016-05-09 19:56:31 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
dn->ofs_in_node = ofs_in_node;
|
|
|
|
for (index = start; index < end; index++, dn->ofs_in_node++) {
|
2020-02-14 17:44:10 +08:00
|
|
|
dn->data_blkaddr = f2fs_data_blkaddr(dn);
|
2016-05-09 19:56:31 +08:00
|
|
|
/*
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
* f2fs_reserve_new_blocks will not guarantee entire block
|
2016-05-09 19:56:31 +08:00
|
|
|
* allocation.
|
|
|
|
*/
|
|
|
|
if (dn->data_blkaddr == NULL_ADDR) {
|
|
|
|
ret = -ENOSPC;
|
|
|
|
break;
|
|
|
|
}
|
2022-04-27 17:51:40 +08:00
|
|
|
|
|
|
|
if (dn->data_blkaddr == NEW_ADDR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!f2fs_is_valid_blkaddr(sbi, dn->data_blkaddr,
|
|
|
|
DATA_GENERIC_ENHANCE)) {
|
|
|
|
ret = -EFSCORRUPTED;
|
2022-09-28 23:38:54 +08:00
|
|
|
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
2022-04-27 17:51:40 +08:00
|
|
|
break;
|
2016-05-09 19:56:31 +08:00
|
|
|
}
|
2022-04-27 17:51:40 +08:00
|
|
|
|
|
|
|
f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
|
|
|
|
dn->data_blkaddr = NEW_ADDR;
|
|
|
|
f2fs_set_data_blkaddr(dn);
|
2016-05-09 19:56:31 +08:00
|
|
|
}
|
|
|
|
|
2022-12-01 01:26:29 +08:00
|
|
|
f2fs_update_read_extent_cache_range(dn, start, 0, index - start);
|
2023-01-31 22:47:01 +08:00
|
|
|
f2fs_update_age_extent_cache_range(dn, start, index - start);
|
2016-05-09 19:56:31 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
|
|
|
|
int mode)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct address_space *mapping = inode->i_mapping;
|
|
|
|
pgoff_t index, pg_start, pg_end;
|
|
|
|
loff_t new_size = i_size_read(inode);
|
|
|
|
loff_t off_start, off_end;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ret = inode_newsize_ok(inode, (len + offset));
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2015-12-23 03:09:35 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-05-06 13:11:13 +08:00
|
|
|
|
|
|
|
ret = filemap_write_and_wait_range(mapping, offset, offset + len - 1);
|
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-05-06 13:11:13 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pg_start = ((unsigned long long) offset) >> PAGE_SHIFT;
|
|
|
|
pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT;
|
2015-05-06 13:11:13 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
off_start = offset & (PAGE_SIZE - 1);
|
|
|
|
off_end = (offset + len) & (PAGE_SIZE - 1);
|
2015-05-06 13:11:13 +08:00
|
|
|
|
|
|
|
if (pg_start == pg_end) {
|
2015-08-07 18:36:06 +08:00
|
|
|
ret = fill_zero(inode, pg_start, off_start,
|
|
|
|
off_end - off_start);
|
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-08-07 18:36:06 +08:00
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
new_size = max_t(loff_t, new_size, offset + len);
|
|
|
|
} else {
|
|
|
|
if (off_start) {
|
2015-08-07 18:36:06 +08:00
|
|
|
ret = fill_zero(inode, pg_start++, off_start,
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
PAGE_SIZE - off_start);
|
2015-08-07 18:36:06 +08:00
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-08-07 18:36:06 +08:00
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
new_size = max_t(loff_t, new_size,
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
(loff_t)pg_start << PAGE_SHIFT);
|
2015-05-06 13:11:13 +08:00
|
|
|
}
|
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
for (index = pg_start; index < pg_end;) {
|
2015-05-06 13:11:13 +08:00
|
|
|
struct dnode_of_data dn;
|
2016-05-09 19:56:31 +08:00
|
|
|
unsigned int end_offset;
|
|
|
|
pgoff_t end;
|
2015-05-06 13:11:13 +08:00
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(mapping);
|
2018-08-05 23:02:22 +08:00
|
|
|
|
|
|
|
truncate_pagecache_range(inode,
|
|
|
|
(loff_t)index << PAGE_SHIFT,
|
|
|
|
((loff_t)pg_end << PAGE_SHIFT) - 1);
|
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
f2fs_lock_op(sbi);
|
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
|
2015-05-06 13:11:13 +08:00
|
|
|
if (ret) {
|
|
|
|
f2fs_unlock_op(sbi);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2015-05-06 13:11:13 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
|
|
|
end = min(pg_end, end_offset - dn.ofs_in_node + index);
|
|
|
|
|
|
|
|
ret = f2fs_do_zero_range(&dn, index, end);
|
2015-05-06 13:11:13 +08:00
|
|
|
f2fs_put_dnode(&dn);
|
2018-08-05 23:02:22 +08:00
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2016-10-11 22:57:02 +08:00
|
|
|
|
|
|
|
f2fs_balance_fs(sbi, dn.node_changed);
|
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
2015-05-06 13:11:13 +08:00
|
|
|
|
2016-05-09 19:56:31 +08:00
|
|
|
index = end;
|
2015-05-06 13:11:13 +08:00
|
|
|
new_size = max_t(loff_t, new_size,
|
2016-05-09 19:56:31 +08:00
|
|
|
(loff_t)index << PAGE_SHIFT);
|
2015-05-06 13:11:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (off_end) {
|
2015-08-07 18:36:06 +08:00
|
|
|
ret = fill_zero(inode, pg_end, 0, off_end);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2015-05-06 13:11:13 +08:00
|
|
|
new_size = max_t(loff_t, new_size, offset + len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2018-02-25 23:38:21 +08:00
|
|
|
if (new_size > i_size_read(inode)) {
|
|
|
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
|
|
|
file_set_keep_isize(inode);
|
|
|
|
else
|
|
|
|
f2fs_i_size_write(inode, new_size);
|
|
|
|
}
|
2015-05-06 13:11:13 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-05-28 19:16:57 +08:00
|
|
|
static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2021-04-14 00:10:37 +08:00
|
|
|
struct address_space *mapping = inode->i_mapping;
|
2016-07-09 08:42:21 +08:00
|
|
|
pgoff_t nr, pg_start, pg_end, delta, idx;
|
2015-05-28 19:16:57 +08:00
|
|
|
loff_t new_size;
|
2015-10-08 03:28:41 +08:00
|
|
|
int ret = 0;
|
2015-05-28 19:16:57 +08:00
|
|
|
|
|
|
|
new_size = i_size_read(inode) + len;
|
2017-03-10 17:54:52 +08:00
|
|
|
ret = inode_newsize_ok(inode, new_size);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-05-28 19:16:57 +08:00
|
|
|
|
|
|
|
if (offset >= i_size_read(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* insert range should be aligned to block size of f2fs. */
|
|
|
|
if (offset & (F2FS_BLKSIZE - 1) || len & (F2FS_BLKSIZE - 1))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-12-23 03:09:35 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2015-06-18 04:59:05 +08:00
|
|
|
|
2016-01-08 06:15:04 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2015-12-23 05:23:35 +08:00
|
|
|
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(mapping);
|
2019-02-02 17:33:01 +08:00
|
|
|
ret = f2fs_truncate_blocks(inode, i_size_read(inode), true);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2015-05-28 19:16:57 +08:00
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-05-28 19:16:57 +08:00
|
|
|
|
|
|
|
/* write out all dirty pages from offset */
|
2021-04-14 00:10:37 +08:00
|
|
|
ret = filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
|
2015-05-28 19:16:57 +08:00
|
|
|
if (ret)
|
2018-07-25 11:11:56 +08:00
|
|
|
return ret;
|
2015-05-28 19:16:57 +08:00
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pg_start = offset >> PAGE_SHIFT;
|
|
|
|
pg_end = (offset + len) >> PAGE_SHIFT;
|
2015-05-28 19:16:57 +08:00
|
|
|
delta = pg_end - pg_start;
|
2019-06-20 22:42:08 +08:00
|
|
|
idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
2016-07-09 08:42:21 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
/* avoid gc operation during block exchange */
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(mapping);
|
2018-07-25 11:11:56 +08:00
|
|
|
truncate_pagecache(inode, offset);
|
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
while (!ret && idx > pg_start) {
|
|
|
|
nr = idx - pg_start;
|
|
|
|
if (nr > delta)
|
|
|
|
nr = delta;
|
|
|
|
idx -= nr;
|
2015-05-28 19:16:57 +08:00
|
|
|
|
|
|
|
f2fs_lock_op(sbi);
|
2016-07-13 02:07:52 +08:00
|
|
|
f2fs_drop_extent_tree(inode);
|
|
|
|
|
2016-07-09 08:42:21 +08:00
|
|
|
ret = __exchange_data_block(inode, inode, idx,
|
|
|
|
idx + delta, nr, false);
|
2015-05-28 19:16:57 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
|
|
|
}
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2015-05-28 19:16:57 +08:00
|
|
|
|
2015-10-08 03:28:41 +08:00
|
|
|
/* write out all moved pages, if possible */
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(mapping);
|
|
|
|
filemap_write_and_wait_range(mapping, offset, LLONG_MAX);
|
2015-10-08 03:28:41 +08:00
|
|
|
truncate_pagecache(inode, offset);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2015-10-08 03:28:41 +08:00
|
|
|
|
|
|
|
if (!ret)
|
2016-05-21 00:22:03 +08:00
|
|
|
f2fs_i_size_write(inode, new_size);
|
2015-05-28 19:16:57 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-12-21 03:12:12 +08:00
|
|
|
static int f2fs_expand_inode_data(struct inode *inode, loff_t offset,
|
2012-11-02 16:09:44 +08:00
|
|
|
loff_t len, int mode)
|
|
|
|
{
|
2014-09-03 06:31:18 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2017-11-28 08:23:00 +08:00
|
|
|
struct f2fs_map_blocks map = { .m_next_pgofs = NULL,
|
2018-11-13 14:33:45 +08:00
|
|
|
.m_next_extent = NULL, .m_seg_type = NO_CHECK_TYPE,
|
|
|
|
.m_may_create = true };
|
2022-05-07 02:40:33 +08:00
|
|
|
struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
|
|
|
|
.init_gc_type = FG_GC,
|
|
|
|
.should_migrate_blocks = false,
|
2022-05-07 04:34:41 +08:00
|
|
|
.err_gc_skipped = true,
|
|
|
|
.nr_free_secs = 0 };
|
2021-03-24 11:24:33 +08:00
|
|
|
pgoff_t pg_start, pg_end;
|
2022-12-21 01:17:32 +08:00
|
|
|
loff_t new_size;
|
2016-05-07 06:30:38 +08:00
|
|
|
loff_t off_end;
|
2021-03-24 11:24:33 +08:00
|
|
|
block_t expanded = 0;
|
2016-11-12 08:31:56 +08:00
|
|
|
int err;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2016-11-12 08:31:56 +08:00
|
|
|
err = inode_newsize_ok(inode, (len + offset));
|
|
|
|
if (err)
|
|
|
|
return err;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2016-11-12 08:31:56 +08:00
|
|
|
err = f2fs_convert_inline_inode(inode);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2013-12-27 11:28:59 +08:00
|
|
|
|
2016-01-08 06:15:04 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2015-12-23 05:23:35 +08:00
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
pg_start = ((unsigned long long)offset) >> PAGE_SHIFT;
|
2016-05-07 06:30:38 +08:00
|
|
|
pg_end = ((unsigned long long)offset + len) >> PAGE_SHIFT;
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
off_end = (offset + len) & (PAGE_SIZE - 1);
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
map.m_lblk = pg_start;
|
|
|
|
map.m_len = pg_end - pg_start;
|
2016-05-07 06:30:38 +08:00
|
|
|
if (off_end)
|
|
|
|
map.m_len++;
|
2014-06-13 12:05:55 +08:00
|
|
|
|
2019-10-19 01:06:40 +08:00
|
|
|
if (!map.m_len)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (f2fs_is_pinned_file(inode)) {
|
2022-06-29 02:03:57 +08:00
|
|
|
block_t sec_blks = CAP_BLKS_PER_SEC(sbi);
|
2021-03-05 17:56:01 +08:00
|
|
|
block_t sec_len = roundup(map.m_len, sec_blks);
|
2019-10-19 01:06:40 +08:00
|
|
|
|
2021-03-05 17:56:01 +08:00
|
|
|
map.m_len = sec_blks;
|
2019-10-19 01:06:40 +08:00
|
|
|
next_alloc:
|
|
|
|
if (has_not_enough_free_secs(sbi, 0,
|
|
|
|
GET_SEC_FROM_SEG(sbi, overprovision_segments(sbi)))) {
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->gc_lock);
|
2023-08-08 08:59:48 +08:00
|
|
|
stat_inc_gc_call_count(sbi, FOREGROUND);
|
2022-05-07 02:40:33 +08:00
|
|
|
err = f2fs_gc(sbi, &gc_control);
|
2022-05-07 05:17:32 +08:00
|
|
|
if (err && err != -ENODATA)
|
2019-10-19 01:06:40 +08:00
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->pin_sem);
|
2020-05-27 12:02:31 +08:00
|
|
|
|
|
|
|
f2fs_lock_op(sbi);
|
2021-04-21 09:54:55 +08:00
|
|
|
f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
|
2020-05-27 12:02:31 +08:00
|
|
|
f2fs_unlock_op(sbi);
|
|
|
|
|
f2fs: introduce inmem curseg
Previous implementation of aligned pinfile allocation will:
- allocate new segment on cold data log no matter whether last used
segment is partially used or not, it makes IOs more random;
- force concurrent cold data/GCed IO going into warm data area, it
can make a bad effect on hot/cold data separation;
In this patch, we introduce a new type of log named 'inmem curseg',
the differents from normal curseg is:
- it reuses existed segment type (CURSEG_XXX_NODE/DATA);
- it only exists in memory, its segno, blkofs, summary will not b
persisted into checkpoint area;
With this new feature, we can enhance scalability of log, special
allocators can be created for purposes:
- pure lfs allocator for aligned pinfile allocation or file
defragmentation
- pure ssr allocator for later feature
So that, let's update aligned pinfile allocation to use this new
inmem curseg fwk.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2020-08-04 21:14:45 +08:00
|
|
|
map.m_seg_type = CURSEG_COLD_DATA_PINNED;
|
2022-11-28 17:15:20 +08:00
|
|
|
err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO);
|
2021-11-13 06:31:16 +08:00
|
|
|
file_dont_truncate(inode);
|
f2fs: introduce inmem curseg
Previous implementation of aligned pinfile allocation will:
- allocate new segment on cold data log no matter whether last used
segment is partially used or not, it makes IOs more random;
- force concurrent cold data/GCed IO going into warm data area, it
can make a bad effect on hot/cold data separation;
In this patch, we introduce a new type of log named 'inmem curseg',
the differents from normal curseg is:
- it reuses existed segment type (CURSEG_XXX_NODE/DATA);
- it only exists in memory, its segno, blkofs, summary will not b
persisted into checkpoint area;
With this new feature, we can enhance scalability of log, special
allocators can be created for purposes:
- pure lfs allocator for aligned pinfile allocation or file
defragmentation
- pure ssr allocator for later feature
So that, let's update aligned pinfile allocation to use this new
inmem curseg fwk.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2020-08-04 21:14:45 +08:00
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&sbi->pin_sem);
|
2019-06-27 09:23:05 +08:00
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
expanded += map.m_len;
|
2021-03-05 17:56:01 +08:00
|
|
|
sec_len -= map.m_len;
|
2019-10-19 01:06:40 +08:00
|
|
|
map.m_lblk += map.m_len;
|
2021-03-05 17:56:01 +08:00
|
|
|
if (!err && sec_len)
|
2019-10-19 01:06:40 +08:00
|
|
|
goto next_alloc;
|
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
map.m_len = expanded;
|
2019-10-19 01:06:40 +08:00
|
|
|
} else {
|
2022-11-28 17:15:20 +08:00
|
|
|
err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO);
|
2021-03-24 11:24:33 +08:00
|
|
|
expanded = map.m_len;
|
2019-10-19 01:06:40 +08:00
|
|
|
}
|
|
|
|
out_err:
|
2016-11-12 08:31:56 +08:00
|
|
|
if (err) {
|
2016-05-07 06:30:38 +08:00
|
|
|
pgoff_t last_off;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
if (!expanded)
|
2016-11-12 08:31:56 +08:00
|
|
|
return err;
|
2014-06-13 12:07:31 +08:00
|
|
|
|
2021-03-24 11:24:33 +08:00
|
|
|
last_off = pg_start + expanded - 1;
|
2016-05-07 06:30:38 +08:00
|
|
|
|
|
|
|
/* update new size to the failed position */
|
2018-05-30 03:34:58 +08:00
|
|
|
new_size = (last_off == pg_end) ? offset + len :
|
2016-05-07 06:30:38 +08:00
|
|
|
(loff_t)(last_off + 1) << PAGE_SHIFT;
|
|
|
|
} else {
|
|
|
|
new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2017-11-05 21:53:30 +08:00
|
|
|
if (new_size > i_size_read(inode)) {
|
|
|
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
|
|
|
file_set_keep_isize(inode);
|
|
|
|
else
|
|
|
|
f2fs_i_size_write(inode, new_size);
|
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2016-11-12 08:31:56 +08:00
|
|
|
return err;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static long f2fs_fallocate(struct file *file, int mode,
|
|
|
|
loff_t offset, loff_t len)
|
|
|
|
{
|
2013-02-28 05:59:05 +08:00
|
|
|
struct inode *inode = file_inode(file);
|
2015-04-21 14:59:12 +08:00
|
|
|
long ret = 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2017-10-24 05:48:49 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
|
|
|
return -EIO;
|
2019-08-23 17:58:36 +08:00
|
|
|
if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
|
|
|
|
return -ENOSPC;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
2017-10-24 05:48:49 +08:00
|
|
|
|
2015-09-11 14:39:02 +08:00
|
|
|
/* f2fs only support ->fallocate for regular file */
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-12-12 17:50:11 +08:00
|
|
|
if (IS_ENCRYPTED(inode) &&
|
2015-05-28 19:16:57 +08:00
|
|
|
(mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE)))
|
2015-04-22 11:39:58 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2022-01-08 12:08:45 +08:00
|
|
|
/*
|
2023-02-06 19:56:00 +08:00
|
|
|
* Pinned file should not support partial truncation since the block
|
2022-01-08 12:08:45 +08:00
|
|
|
* can be used by applications.
|
|
|
|
*/
|
|
|
|
if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) &&
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE |
|
|
|
|
FALLOC_FL_ZERO_RANGE | FALLOC_FL_INSERT_RANGE)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2015-05-06 13:09:46 +08:00
|
|
|
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
|
2015-05-28 19:16:57 +08:00
|
|
|
FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE |
|
|
|
|
FALLOC_FL_INSERT_RANGE))
|
2012-11-02 16:09:44 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock(inode);
|
2014-01-28 10:29:26 +08:00
|
|
|
|
2022-05-17 11:37:23 +08:00
|
|
|
ret = file_modified(file);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2015-04-21 14:59:12 +08:00
|
|
|
if (mode & FALLOC_FL_PUNCH_HOLE) {
|
|
|
|
if (offset >= inode->i_size)
|
|
|
|
goto out;
|
|
|
|
|
2022-12-21 03:12:12 +08:00
|
|
|
ret = f2fs_punch_hole(inode, offset, len);
|
2015-05-06 13:09:46 +08:00
|
|
|
} else if (mode & FALLOC_FL_COLLAPSE_RANGE) {
|
|
|
|
ret = f2fs_collapse_range(inode, offset, len);
|
2015-05-06 13:11:13 +08:00
|
|
|
} else if (mode & FALLOC_FL_ZERO_RANGE) {
|
|
|
|
ret = f2fs_zero_range(inode, offset, len, mode);
|
2015-05-28 19:16:57 +08:00
|
|
|
} else if (mode & FALLOC_FL_INSERT_RANGE) {
|
|
|
|
ret = f2fs_insert_range(inode, offset, len);
|
2015-05-06 13:09:46 +08:00
|
|
|
} else {
|
2022-12-21 03:12:12 +08:00
|
|
|
ret = f2fs_expand_inode_data(inode, offset, len, mode);
|
2015-05-06 13:09:46 +08:00
|
|
|
}
|
2012-11-02 16:09:44 +08:00
|
|
|
|
2012-12-30 13:52:37 +08:00
|
|
|
if (!ret) {
|
2023-07-06 03:01:08 +08:00
|
|
|
inode->i_mtime = inode_set_ctime_current(inode);
|
2016-10-15 02:51:23 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, false);
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
2012-12-30 13:52:37 +08:00
|
|
|
}
|
2014-01-28 10:29:26 +08:00
|
|
|
|
2015-04-21 14:59:12 +08:00
|
|
|
out:
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2014-01-28 10:29:26 +08:00
|
|
|
|
2013-04-23 16:00:52 +08:00
|
|
|
trace_f2fs_fallocate(inode, mode, offset, len, ret);
|
2012-11-02 16:09:44 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-12-09 22:08:59 +08:00
|
|
|
static int f2fs_release_file(struct inode *inode, struct file *filp)
|
|
|
|
{
|
2016-04-12 02:51:51 +08:00
|
|
|
/*
|
2023-02-06 19:56:00 +08:00
|
|
|
* f2fs_release_file is called at every close calls. So we should
|
2016-04-12 02:51:51 +08:00
|
|
|
* not drop any inmemory pages by close called by other process.
|
|
|
|
*/
|
|
|
|
if (!(filp->f_mode & FMODE_WRITE) ||
|
|
|
|
atomic_read(&inode->i_writecount) != 1)
|
|
|
|
return 0;
|
|
|
|
|
2023-02-10 02:18:19 +08:00
|
|
|
inode_lock(inode);
|
2022-08-04 21:38:21 +08:00
|
|
|
f2fs_abort_atomic_write(inode, true);
|
2023-02-10 02:18:19 +08:00
|
|
|
inode_unlock(inode);
|
|
|
|
|
2014-12-09 22:08:59 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-25 10:46:29 +08:00
|
|
|
static int f2fs_file_flush(struct file *file, fl_owner_t id)
|
2012-11-02 16:09:44 +08:00
|
|
|
{
|
2017-07-25 10:46:29 +08:00
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the process doing a transaction is crashed, we should do
|
|
|
|
* roll-back. Otherwise, other reader/write can see corrupted database
|
|
|
|
* until all the writers close its file. Since this should be done
|
|
|
|
* before dropping file lock, it needs to do in ->flush.
|
|
|
|
*/
|
2023-01-09 11:44:51 +08:00
|
|
|
if (F2FS_I(inode)->atomic_write_task == current &&
|
2023-02-10 02:18:19 +08:00
|
|
|
(current->flags & PF_EXITING)) {
|
|
|
|
inode_lock(inode);
|
2022-04-29 02:18:09 +08:00
|
|
|
f2fs_abort_atomic_write(inode, true);
|
2023-02-10 02:18:19 +08:00
|
|
|
inode_unlock(inode);
|
|
|
|
}
|
|
|
|
|
2017-07-25 10:46:29 +08:00
|
|
|
return 0;
|
2012-11-02 16:09:44 +08:00
|
|
|
}
|
|
|
|
|
2019-06-05 13:59:04 +08:00
|
|
|
static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
2017-07-29 00:32:52 +08:00
|
|
|
{
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
2020-03-06 07:20:26 +08:00
|
|
|
u32 masked_flags = fi->i_flags & mask;
|
|
|
|
|
2021-05-07 03:11:14 +08:00
|
|
|
/* mask can be shrunk by flags_valid selector */
|
|
|
|
iflags &= mask;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
|
|
|
/* Is it quota file? Do not allow user to mess with it */
|
|
|
|
if (IS_NOQUOTA(inode))
|
|
|
|
return -EPERM;
|
|
|
|
|
2020-03-06 07:20:26 +08:00
|
|
|
if ((iflags ^ masked_flags) & F2FS_CASEFOLD_FL) {
|
f2fs: Support case-insensitive file name lookups
Modeled after commit b886ee3e778e ("ext4: Support case-insensitive file
name lookups")
"""
This patch implements the actual support for case-insensitive file name
lookups in f2fs, based on the feature bit and the encoding stored in the
superblock.
A filesystem that has the casefold feature set is able to configure
directories with the +F (F2FS_CASEFOLD_FL) attribute, enabling lookups
to succeed in that directory in a case-insensitive fashion, i.e: match
a directory entry even if the name used by userspace is not a byte per
byte match with the disk name, but is an equivalent case-insensitive
version of the Unicode string. This operation is called a
case-insensitive file name lookup.
The feature is configured as an inode attribute applied to directories
and inherited by its children. This attribute can only be enabled on
empty directories for filesystems that support the encoding feature,
thus preventing collision of file names that only differ by case.
* dcache handling:
For a +F directory, F2Fs only stores the first equivalent name dentry
used in the dcache. This is done to prevent unintentional duplication of
dentries in the dcache, while also allowing the VFS code to quickly find
the right entry in the cache despite which equivalent string was used in
a previous lookup, without having to resort to ->lookup().
d_hash() of casefolded directories is implemented as the hash of the
casefolded string, such that we always have a well-known bucket for all
the equivalencies of the same string. d_compare() uses the
utf8_strncasecmp() infrastructure, which handles the comparison of
equivalent, same case, names as well.
For now, negative lookups are not inserted in the dcache, since they
would need to be invalidated anyway, because we can't trust missing file
dentries. This is bad for performance but requires some leveraging of
the vfs layer to fix. We can live without that for now, and so does
everyone else.
* on-disk data:
Despite using a specific version of the name as the internal
representation within the dcache, the name stored and fetched from the
disk is a byte-per-byte match with what the user requested, making this
implementation 'name-preserving'. i.e. no actual information is lost
when writing to storage.
DX is supported by modifying the hashes used in +F directories to make
them case/encoding-aware. The new disk hashes are calculated as the
hash of the full casefolded string, instead of the string directly.
This allows us to efficiently search for file names in the htree without
requiring the user to provide an exact name.
* Dealing with invalid sequences:
By default, when a invalid UTF-8 sequence is identified, ext4 will treat
it as an opaque byte sequence, ignoring the encoding and reverting to
the old behavior for that unique file. This means that case-insensitive
file name lookup will not work only for that file. An optional bit can
be set in the superblock telling the filesystem code and userspace tools
to enforce the encoding. When that optional bit is set, any attempt to
create a file name using an invalid UTF-8 sequence will fail and return
an error to userspace.
* Normalization algorithm:
The UTF-8 algorithms used to compare strings in f2fs is implemented
in fs/unicode, and is based on a previous version developed by
SGI. It implements the Canonical decomposition (NFD) algorithm
described by the Unicode specification 12.1, or higher, combined with
the elimination of ignorable code points (NFDi) and full
case-folding (CF) as documented in fs/unicode/utf8_norm.c.
NFD seems to be the best normalization method for F2FS because:
- It has a lower cost than NFC/NFKC (which requires
decomposing to NFD as an intermediary step)
- It doesn't eliminate important semantic meaning like
compatibility decompositions.
Although:
- This implementation is not completely linguistic accurate, because
different languages have conflicting rules, which would require the
specialization of the filesystem to a given locale, which brings all
sorts of problems for removable media and for users who use more than
one language.
"""
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-07-24 07:05:29 +08:00
|
|
|
if (!f2fs_sb_has_casefold(F2FS_I_SB(inode)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
if (!f2fs_empty_dir(inode))
|
|
|
|
return -ENOTEMPTY;
|
|
|
|
}
|
|
|
|
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
if (iflags & (F2FS_COMPR_FL | F2FS_NOCOMP_FL)) {
|
|
|
|
if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
if ((iflags & F2FS_COMPR_FL) && (iflags & F2FS_NOCOMP_FL))
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2020-03-06 07:20:26 +08:00
|
|
|
if ((iflags ^ masked_flags) & F2FS_COMPR_FL) {
|
2020-03-27 18:29:51 +08:00
|
|
|
if (masked_flags & F2FS_COMPR_FL) {
|
2020-09-08 10:44:11 +08:00
|
|
|
if (!f2fs_disable_compressed_file(inode))
|
2020-03-10 20:50:09 +08:00
|
|
|
return -EINVAL;
|
2022-07-25 18:16:33 +08:00
|
|
|
} else {
|
2022-10-25 07:00:35 +08:00
|
|
|
/* try to convert inline_data to support compression */
|
|
|
|
int err = f2fs_convert_inline_inode(inode);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2023-07-06 10:06:14 +08:00
|
|
|
|
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_sem);
|
|
|
|
if (!f2fs_may_compress(inode) ||
|
|
|
|
(S_ISREG(inode->i_mode) &&
|
|
|
|
F2FS_HAS_BLOCKS(inode))) {
|
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_sem);
|
2020-09-18 11:03:49 +08:00
|
|
|
return -EINVAL;
|
2023-07-06 10:06:14 +08:00
|
|
|
}
|
|
|
|
err = set_compress_context(inode);
|
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_sem);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return err;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-02 04:26:30 +08:00
|
|
|
fi->i_flags = iflags | (fi->i_flags & ~mask);
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
f2fs_bug_on(F2FS_I_SB(inode), (fi->i_flags & F2FS_COMPR_FL) &&
|
|
|
|
(fi->i_flags & F2FS_NOCOMP_FL));
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2018-04-03 15:08:17 +08:00
|
|
|
if (fi->i_flags & F2FS_PROJINHERIT_FL)
|
2017-07-29 00:32:52 +08:00
|
|
|
set_inode_flag(inode, FI_PROJ_INHERIT);
|
|
|
|
else
|
|
|
|
clear_inode_flag(inode, FI_PROJ_INHERIT);
|
|
|
|
|
2023-07-06 03:01:08 +08:00
|
|
|
inode_set_ctime_current(inode);
|
2017-07-29 00:32:52 +08:00
|
|
|
f2fs_set_inode_flags(inode);
|
2018-12-18 19:20:17 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
2017-07-29 00:32:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
/* FS_IOC_[GS]ETFLAGS and FS_IOC_FS[GS]ETXATTR support */
|
2019-06-05 13:59:04 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* To make a new on-disk f2fs i_flag gettable via FS_IOC_GETFLAGS, add an entry
|
|
|
|
* for it to f2fs_fsflags_map[], and add its FS_*_FL equivalent to
|
|
|
|
* F2FS_GETTABLE_FS_FL. To also make it settable via FS_IOC_SETFLAGS, also add
|
|
|
|
* its FS_*_FL equivalent to F2FS_SETTABLE_FS_FL.
|
2021-04-07 20:36:43 +08:00
|
|
|
*
|
|
|
|
* Translating flags to fsx_flags value used by FS_IOC_FSGETXATTR and
|
|
|
|
* FS_IOC_FSSETXATTR is done by the VFS.
|
2019-06-05 13:59:04 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
u32 iflag;
|
|
|
|
u32 fsflag;
|
|
|
|
} f2fs_fsflags_map[] = {
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
{ F2FS_COMPR_FL, FS_COMPR_FL },
|
2019-06-05 13:59:04 +08:00
|
|
|
{ F2FS_SYNC_FL, FS_SYNC_FL },
|
|
|
|
{ F2FS_IMMUTABLE_FL, FS_IMMUTABLE_FL },
|
|
|
|
{ F2FS_APPEND_FL, FS_APPEND_FL },
|
|
|
|
{ F2FS_NODUMP_FL, FS_NODUMP_FL },
|
|
|
|
{ F2FS_NOATIME_FL, FS_NOATIME_FL },
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
{ F2FS_NOCOMP_FL, FS_NOCOMP_FL },
|
2019-06-05 13:59:04 +08:00
|
|
|
{ F2FS_INDEX_FL, FS_INDEX_FL },
|
|
|
|
{ F2FS_DIRSYNC_FL, FS_DIRSYNC_FL },
|
|
|
|
{ F2FS_PROJINHERIT_FL, FS_PROJINHERIT_FL },
|
f2fs: Support case-insensitive file name lookups
Modeled after commit b886ee3e778e ("ext4: Support case-insensitive file
name lookups")
"""
This patch implements the actual support for case-insensitive file name
lookups in f2fs, based on the feature bit and the encoding stored in the
superblock.
A filesystem that has the casefold feature set is able to configure
directories with the +F (F2FS_CASEFOLD_FL) attribute, enabling lookups
to succeed in that directory in a case-insensitive fashion, i.e: match
a directory entry even if the name used by userspace is not a byte per
byte match with the disk name, but is an equivalent case-insensitive
version of the Unicode string. This operation is called a
case-insensitive file name lookup.
The feature is configured as an inode attribute applied to directories
and inherited by its children. This attribute can only be enabled on
empty directories for filesystems that support the encoding feature,
thus preventing collision of file names that only differ by case.
* dcache handling:
For a +F directory, F2Fs only stores the first equivalent name dentry
used in the dcache. This is done to prevent unintentional duplication of
dentries in the dcache, while also allowing the VFS code to quickly find
the right entry in the cache despite which equivalent string was used in
a previous lookup, without having to resort to ->lookup().
d_hash() of casefolded directories is implemented as the hash of the
casefolded string, such that we always have a well-known bucket for all
the equivalencies of the same string. d_compare() uses the
utf8_strncasecmp() infrastructure, which handles the comparison of
equivalent, same case, names as well.
For now, negative lookups are not inserted in the dcache, since they
would need to be invalidated anyway, because we can't trust missing file
dentries. This is bad for performance but requires some leveraging of
the vfs layer to fix. We can live without that for now, and so does
everyone else.
* on-disk data:
Despite using a specific version of the name as the internal
representation within the dcache, the name stored and fetched from the
disk is a byte-per-byte match with what the user requested, making this
implementation 'name-preserving'. i.e. no actual information is lost
when writing to storage.
DX is supported by modifying the hashes used in +F directories to make
them case/encoding-aware. The new disk hashes are calculated as the
hash of the full casefolded string, instead of the string directly.
This allows us to efficiently search for file names in the htree without
requiring the user to provide an exact name.
* Dealing with invalid sequences:
By default, when a invalid UTF-8 sequence is identified, ext4 will treat
it as an opaque byte sequence, ignoring the encoding and reverting to
the old behavior for that unique file. This means that case-insensitive
file name lookup will not work only for that file. An optional bit can
be set in the superblock telling the filesystem code and userspace tools
to enforce the encoding. When that optional bit is set, any attempt to
create a file name using an invalid UTF-8 sequence will fail and return
an error to userspace.
* Normalization algorithm:
The UTF-8 algorithms used to compare strings in f2fs is implemented
in fs/unicode, and is based on a previous version developed by
SGI. It implements the Canonical decomposition (NFD) algorithm
described by the Unicode specification 12.1, or higher, combined with
the elimination of ignorable code points (NFDi) and full
case-folding (CF) as documented in fs/unicode/utf8_norm.c.
NFD seems to be the best normalization method for F2FS because:
- It has a lower cost than NFC/NFKC (which requires
decomposing to NFD as an intermediary step)
- It doesn't eliminate important semantic meaning like
compatibility decompositions.
Although:
- This implementation is not completely linguistic accurate, because
different languages have conflicting rules, which would require the
specialization of the filesystem to a given locale, which brings all
sorts of problems for removable media and for users who use more than
one language.
"""
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-07-24 07:05:29 +08:00
|
|
|
{ F2FS_CASEFOLD_FL, FS_CASEFOLD_FL },
|
2019-06-05 13:59:04 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define F2FS_GETTABLE_FS_FL ( \
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
FS_COMPR_FL | \
|
2019-06-05 13:59:04 +08:00
|
|
|
FS_SYNC_FL | \
|
|
|
|
FS_IMMUTABLE_FL | \
|
|
|
|
FS_APPEND_FL | \
|
|
|
|
FS_NODUMP_FL | \
|
|
|
|
FS_NOATIME_FL | \
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
FS_NOCOMP_FL | \
|
2019-06-05 13:59:04 +08:00
|
|
|
FS_INDEX_FL | \
|
|
|
|
FS_DIRSYNC_FL | \
|
|
|
|
FS_PROJINHERIT_FL | \
|
|
|
|
FS_ENCRYPT_FL | \
|
|
|
|
FS_INLINE_DATA_FL | \
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
FS_NOCOW_FL | \
|
f2fs-for-5.4-rc1
In this round, we introduced casefolding support in f2fs, and fixed various bugs
in individual features such as IO alignment, checkpoint=disable, quota, and
swapfile.
Enhancement:
- support casefolding w/ enhancement in ext4
- support fiemap for directory
- support FS_IO_GET|SET_FSLABEL
Bug fix:
- fix IO stuck during checkpoint=disable
- avoid infinite GC loop
- fix panic/overflow related to IO alignment feature
- fix livelock in swap file
- fix discard command leak
- disallow dio for atomic_write
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAl2FL1wACgkQQBSofoJI
UNIRdg/+M6QNiAazIbqzPXyUUkyZQYR5YKhu2abd49o/g38xjTq1afH0PZpQyDrA
9RncR4xsW8F241vPLVoCSanfaa+MxN6xHi3TrD8zYtZWxOcPF6v1ETHeUXGTHuJ2
gqlk+mm+CnY02M6rxW7XwixuXwttT3bF9+cf1YBWRpNoVrR+SjNqgeJS7FmJwXKd
nGKb+94OxuygL1NUop+LDUo3qRQjc0Sxv/7qj/K4lhqgTjhAxMYT2KvUP/1MZ7U0
Kh9WIayDXnpoioxMPnt4VEb+JgXfLLFELvQzNjwulk15GIweuJzwVYCBXcRoX0cK
eRBRmRy/kRp/e0R1gvl3kYrXQC2AC5QTlBVH/0ESwnaukFiUBKB509vH4aqE/vpB
Krldjfg+uMHkc7XiNBf1boDp713vJ76iRKUDWoVb6H/sPbdJ+jtrnUNeBP8CVpWh
u31SY1MppnmKhhsoCHQRbhbXO/Z29imBQgF9Tm3IFWImyLY3IU40vFj2fR15gJkL
X3x/HWxQynSqyqEOwAZrvhCRTvBAIGIVy5292Di1RkqIoh8saxcqiaywgLz1+eVE
0DCOoh8R6sSbfN/EEh+yZqTxmjo0VGVTw30XVI6QEo4cY5Vfc9u6dN6SRWVRvbjb
kPb3dKcMrttgbn3fcXU8Jbw1AOor9N6afHaqs0swQJyci2RwJyc=
=oonf
-----END PGP SIGNATURE-----
Merge tag 'f2fs-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this round, we introduced casefolding support in f2fs, and fixed
various bugs in individual features such as IO alignment,
checkpoint=disable, quota, and swapfile.
Enhancement:
- support casefolding w/ enhancement in ext4
- support fiemap for directory
- support FS_IO_GET|SET_FSLABEL
Bug fix:
- fix IO stuck during checkpoint=disable
- avoid infinite GC loop
- fix panic/overflow related to IO alignment feature
- fix livelock in swap file
- fix discard command leak
- disallow dio for atomic_write"
* tag 'f2fs-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (51 commits)
f2fs: add a condition to detect overflow in f2fs_ioc_gc_range()
f2fs: fix to add missing F2FS_IO_ALIGNED() condition
f2fs: fix to fallback to buffered IO in IO aligned mode
f2fs: fix to handle error path correctly in f2fs_map_blocks
f2fs: fix extent corrupotion during directIO in LFS mode
f2fs: check all the data segments against all node ones
f2fs: Add a small clarification to CONFIG_FS_F2FS_FS_SECURITY
f2fs: fix inode rwsem regression
f2fs: fix to avoid accessing uninitialized field of inode page in is_alive()
f2fs: avoid infinite GC loop due to stale atomic files
f2fs: Fix indefinite loop in f2fs_gc()
f2fs: convert inline_data in prior to i_size_write
f2fs: fix error path of f2fs_convert_inline_page()
f2fs: add missing documents of reserve_root/resuid/resgid
f2fs: fix flushing node pages when checkpoint is disabled
f2fs: enhance f2fs_is_checkpoint_ready()'s readability
f2fs: clean up __bio_alloc()'s parameter
f2fs: fix wrong error injection path in inc_valid_block_count()
f2fs: fix to writeout dirty inode during node flush
f2fs: optimize case-insensitive lookups
...
2019-09-22 05:26:33 +08:00
|
|
|
FS_VERITY_FL | \
|
f2fs: Support case-insensitive file name lookups
Modeled after commit b886ee3e778e ("ext4: Support case-insensitive file
name lookups")
"""
This patch implements the actual support for case-insensitive file name
lookups in f2fs, based on the feature bit and the encoding stored in the
superblock.
A filesystem that has the casefold feature set is able to configure
directories with the +F (F2FS_CASEFOLD_FL) attribute, enabling lookups
to succeed in that directory in a case-insensitive fashion, i.e: match
a directory entry even if the name used by userspace is not a byte per
byte match with the disk name, but is an equivalent case-insensitive
version of the Unicode string. This operation is called a
case-insensitive file name lookup.
The feature is configured as an inode attribute applied to directories
and inherited by its children. This attribute can only be enabled on
empty directories for filesystems that support the encoding feature,
thus preventing collision of file names that only differ by case.
* dcache handling:
For a +F directory, F2Fs only stores the first equivalent name dentry
used in the dcache. This is done to prevent unintentional duplication of
dentries in the dcache, while also allowing the VFS code to quickly find
the right entry in the cache despite which equivalent string was used in
a previous lookup, without having to resort to ->lookup().
d_hash() of casefolded directories is implemented as the hash of the
casefolded string, such that we always have a well-known bucket for all
the equivalencies of the same string. d_compare() uses the
utf8_strncasecmp() infrastructure, which handles the comparison of
equivalent, same case, names as well.
For now, negative lookups are not inserted in the dcache, since they
would need to be invalidated anyway, because we can't trust missing file
dentries. This is bad for performance but requires some leveraging of
the vfs layer to fix. We can live without that for now, and so does
everyone else.
* on-disk data:
Despite using a specific version of the name as the internal
representation within the dcache, the name stored and fetched from the
disk is a byte-per-byte match with what the user requested, making this
implementation 'name-preserving'. i.e. no actual information is lost
when writing to storage.
DX is supported by modifying the hashes used in +F directories to make
them case/encoding-aware. The new disk hashes are calculated as the
hash of the full casefolded string, instead of the string directly.
This allows us to efficiently search for file names in the htree without
requiring the user to provide an exact name.
* Dealing with invalid sequences:
By default, when a invalid UTF-8 sequence is identified, ext4 will treat
it as an opaque byte sequence, ignoring the encoding and reverting to
the old behavior for that unique file. This means that case-insensitive
file name lookup will not work only for that file. An optional bit can
be set in the superblock telling the filesystem code and userspace tools
to enforce the encoding. When that optional bit is set, any attempt to
create a file name using an invalid UTF-8 sequence will fail and return
an error to userspace.
* Normalization algorithm:
The UTF-8 algorithms used to compare strings in f2fs is implemented
in fs/unicode, and is based on a previous version developed by
SGI. It implements the Canonical decomposition (NFD) algorithm
described by the Unicode specification 12.1, or higher, combined with
the elimination of ignorable code points (NFDi) and full
case-folding (CF) as documented in fs/unicode/utf8_norm.c.
NFD seems to be the best normalization method for F2FS because:
- It has a lower cost than NFC/NFKC (which requires
decomposing to NFD as an intermediary step)
- It doesn't eliminate important semantic meaning like
compatibility decompositions.
Although:
- This implementation is not completely linguistic accurate, because
different languages have conflicting rules, which would require the
specialization of the filesystem to a given locale, which brings all
sorts of problems for removable media and for users who use more than
one language.
"""
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-07-24 07:05:29 +08:00
|
|
|
FS_CASEFOLD_FL)
|
2019-06-05 13:59:04 +08:00
|
|
|
|
|
|
|
#define F2FS_SETTABLE_FS_FL ( \
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
FS_COMPR_FL | \
|
2019-06-05 13:59:04 +08:00
|
|
|
FS_SYNC_FL | \
|
|
|
|
FS_IMMUTABLE_FL | \
|
|
|
|
FS_APPEND_FL | \
|
|
|
|
FS_NODUMP_FL | \
|
|
|
|
FS_NOATIME_FL | \
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
FS_NOCOMP_FL | \
|
2019-06-05 13:59:04 +08:00
|
|
|
FS_DIRSYNC_FL | \
|
f2fs: Support case-insensitive file name lookups
Modeled after commit b886ee3e778e ("ext4: Support case-insensitive file
name lookups")
"""
This patch implements the actual support for case-insensitive file name
lookups in f2fs, based on the feature bit and the encoding stored in the
superblock.
A filesystem that has the casefold feature set is able to configure
directories with the +F (F2FS_CASEFOLD_FL) attribute, enabling lookups
to succeed in that directory in a case-insensitive fashion, i.e: match
a directory entry even if the name used by userspace is not a byte per
byte match with the disk name, but is an equivalent case-insensitive
version of the Unicode string. This operation is called a
case-insensitive file name lookup.
The feature is configured as an inode attribute applied to directories
and inherited by its children. This attribute can only be enabled on
empty directories for filesystems that support the encoding feature,
thus preventing collision of file names that only differ by case.
* dcache handling:
For a +F directory, F2Fs only stores the first equivalent name dentry
used in the dcache. This is done to prevent unintentional duplication of
dentries in the dcache, while also allowing the VFS code to quickly find
the right entry in the cache despite which equivalent string was used in
a previous lookup, without having to resort to ->lookup().
d_hash() of casefolded directories is implemented as the hash of the
casefolded string, such that we always have a well-known bucket for all
the equivalencies of the same string. d_compare() uses the
utf8_strncasecmp() infrastructure, which handles the comparison of
equivalent, same case, names as well.
For now, negative lookups are not inserted in the dcache, since they
would need to be invalidated anyway, because we can't trust missing file
dentries. This is bad for performance but requires some leveraging of
the vfs layer to fix. We can live without that for now, and so does
everyone else.
* on-disk data:
Despite using a specific version of the name as the internal
representation within the dcache, the name stored and fetched from the
disk is a byte-per-byte match with what the user requested, making this
implementation 'name-preserving'. i.e. no actual information is lost
when writing to storage.
DX is supported by modifying the hashes used in +F directories to make
them case/encoding-aware. The new disk hashes are calculated as the
hash of the full casefolded string, instead of the string directly.
This allows us to efficiently search for file names in the htree without
requiring the user to provide an exact name.
* Dealing with invalid sequences:
By default, when a invalid UTF-8 sequence is identified, ext4 will treat
it as an opaque byte sequence, ignoring the encoding and reverting to
the old behavior for that unique file. This means that case-insensitive
file name lookup will not work only for that file. An optional bit can
be set in the superblock telling the filesystem code and userspace tools
to enforce the encoding. When that optional bit is set, any attempt to
create a file name using an invalid UTF-8 sequence will fail and return
an error to userspace.
* Normalization algorithm:
The UTF-8 algorithms used to compare strings in f2fs is implemented
in fs/unicode, and is based on a previous version developed by
SGI. It implements the Canonical decomposition (NFD) algorithm
described by the Unicode specification 12.1, or higher, combined with
the elimination of ignorable code points (NFDi) and full
case-folding (CF) as documented in fs/unicode/utf8_norm.c.
NFD seems to be the best normalization method for F2FS because:
- It has a lower cost than NFC/NFKC (which requires
decomposing to NFD as an intermediary step)
- It doesn't eliminate important semantic meaning like
compatibility decompositions.
Although:
- This implementation is not completely linguistic accurate, because
different languages have conflicting rules, which would require the
specialization of the filesystem to a given locale, which brings all
sorts of problems for removable media and for users who use more than
one language.
"""
Signed-off-by: Daniel Rosenberg <drosen@google.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-07-24 07:05:29 +08:00
|
|
|
FS_PROJINHERIT_FL | \
|
|
|
|
FS_CASEFOLD_FL)
|
2019-06-05 13:59:04 +08:00
|
|
|
|
|
|
|
/* Convert f2fs on-disk i_flags to FS_IOC_{GET,SET}FLAGS flags */
|
|
|
|
static inline u32 f2fs_iflags_to_fsflags(u32 iflags)
|
|
|
|
{
|
|
|
|
u32 fsflags = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
|
|
|
|
if (iflags & f2fs_fsflags_map[i].iflag)
|
|
|
|
fsflags |= f2fs_fsflags_map[i].fsflag;
|
|
|
|
|
|
|
|
return fsflags;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert FS_IOC_{GET,SET}FLAGS flags to f2fs on-disk i_flags */
|
|
|
|
static inline u32 f2fs_fsflags_to_iflags(u32 fsflags)
|
|
|
|
{
|
|
|
|
u32 iflags = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(f2fs_fsflags_map); i++)
|
|
|
|
if (fsflags & f2fs_fsflags_map[i].fsflag)
|
|
|
|
iflags |= f2fs_fsflags_map[i].iflag;
|
|
|
|
|
|
|
|
return iflags;
|
|
|
|
}
|
|
|
|
|
2015-01-23 20:36:04 +08:00
|
|
|
static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
|
|
|
|
return put_user(inode->i_generation, (int __user *)arg);
|
|
|
|
}
|
|
|
|
|
2022-11-12 01:04:06 +08:00
|
|
|
static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
2014-10-07 08:39:50 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
2023-01-13 19:49:25 +08:00
|
|
|
struct mnt_idmap *idmap = file_mnt_idmap(filp);
|
f2fs: avoid infinite GC loop due to stale atomic files
If committing atomic pages is failed when doing f2fs_do_sync_file(), we can
get commited pages but atomic_file being still set like:
- inmem: 0, atomic IO: 4 (Max. 10), volatile IO: 0 (Max. 0)
If GC selects this block, we can get an infinite loop like this:
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
In that moment, we can observe:
[Before]
Try to move 5084219 blocks (BG: 384508)
- data blocks : 4962373 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4534686 (10)
[After]
Try to move 5088973 blocks (BG: 384508)
- data blocks : 4967127 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4539440 (10)
So, refactor atomic_write flow like this:
1. start_atomic_write
- add inmem_list and set atomic_file
2. write()
- register it in inmem_pages
3. commit_atomic_write
- if no error, f2fs_drop_inmem_pages()
- f2fs_commit_inmme_pages() failed
: __revoked_inmem_pages() was done
- f2fs_do_sync_file failed
: abort_atomic_write later
4. abort_atomic_write
- f2fs_drop_inmem_pages
5. f2fs_drop_inmem_pages
- clear atomic_file
- remove inmem_list
Based on this change, when GC fails to move block in atomic_file,
f2fs_drop_inmem_pages_all() can call f2fs_drop_inmem_pages().
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-09-09 20:10:59 +08:00
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2022-04-29 02:18:09 +08:00
|
|
|
struct inode *pinode;
|
2022-11-01 03:24:15 +08:00
|
|
|
loff_t isize;
|
2015-07-17 18:06:35 +08:00
|
|
|
int ret;
|
2014-10-07 08:39:50 +08:00
|
|
|
|
2023-01-13 19:49:26 +08:00
|
|
|
if (!inode_owner_or_capable(idmap, inode))
|
2014-10-07 08:39:50 +08:00
|
|
|
return -EACCES;
|
|
|
|
|
2017-03-17 10:04:15 +08:00
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2019-07-25 22:39:11 +08:00
|
|
|
if (filp->f_flags & O_DIRECT)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-05-09 19:56:33 +08:00
|
|
|
inode_lock(inode);
|
|
|
|
|
f2fs: fix compressed file start atomic write may cause data corruption
When compressed file has blocks, f2fs_ioc_start_atomic_write will succeed,
but compressed flag will be remained in inode. If write partial compreseed
cluster and commit atomic write will cause data corruption.
This is the reproduction process:
Step 1:
create a compressed file ,write 64K data , call fsync(), then the blocks
are write as compressed cluster.
Step2:
iotcl(F2FS_IOC_START_ATOMIC_WRITE) --- this should be fail, but not.
write page 0 and page 3.
iotcl(F2FS_IOC_COMMIT_ATOMIC_WRITE) -- page 0 and 3 write as normal file,
Step3:
drop cache.
read page 0-4 -- Since page 0 has a valid block address, read as
non-compressed cluster, page 1 and 2 will be filled with compressed data
or zero.
The root cause is, after commit 7eab7a696827 ("f2fs: compress: remove
unneeded read when rewrite whole cluster"), in step 2, f2fs_write_begin()
only set target page dirty, and in f2fs_commit_inmem_pages(), we will write
partial raw pages into compressed cluster, result in corrupting compressed
cluster layout.
Fixes: 4c8ff7095bef ("f2fs: support data compression")
Fixes: 7eab7a696827 ("f2fs: compress: remove unneeded read when rewrite whole cluster")
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Fengnan Chang <changfengnan@vivo.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2022-03-18 09:23:04 +08:00
|
|
|
if (!f2fs_disable_compressed_file(inode)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
2022-04-29 02:18:09 +08:00
|
|
|
if (f2fs_is_atomic_file(inode))
|
2016-05-09 19:56:32 +08:00
|
|
|
goto out;
|
2014-10-07 08:39:50 +08:00
|
|
|
|
2015-07-17 18:06:35 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
2016-05-09 19:56:32 +08:00
|
|
|
goto out;
|
2014-10-07 08:39:50 +08:00
|
|
|
|
2022-05-26 10:21:06 +08:00
|
|
|
f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
|
2018-07-25 11:11:56 +08:00
|
|
|
|
2018-12-29 03:00:38 +08:00
|
|
|
/*
|
|
|
|
* Should wait end_io to count F2FS_WB_CP_DATA correctly by
|
|
|
|
* f2fs_is_atomic_file.
|
|
|
|
*/
|
|
|
|
if (get_dirty_pages(inode))
|
2022-05-26 10:21:06 +08:00
|
|
|
f2fs_warn(sbi, "Unexpected flush for atomic writes: ino=%lu, npages=%u",
|
2019-06-18 17:48:42 +08:00
|
|
|
inode->i_ino, get_dirty_pages(inode));
|
2016-04-13 05:36:11 +08:00
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
2018-07-25 11:11:56 +08:00
|
|
|
if (ret) {
|
2022-05-26 10:21:06 +08:00
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
2017-03-18 09:20:55 +08:00
|
|
|
goto out;
|
2018-07-25 11:11:56 +08:00
|
|
|
}
|
2018-12-29 03:00:38 +08:00
|
|
|
|
2023-02-10 02:18:19 +08:00
|
|
|
/* Check if the inode already has a COW inode */
|
|
|
|
if (fi->cow_inode == NULL) {
|
|
|
|
/* Create a COW inode for atomic write */
|
|
|
|
pinode = f2fs_iget(inode->i_sb, fi->i_pino);
|
|
|
|
if (IS_ERR(pinode)) {
|
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
|
|
|
ret = PTR_ERR(pinode);
|
|
|
|
goto out;
|
|
|
|
}
|
2022-04-29 02:18:09 +08:00
|
|
|
|
f2fs-for-6.3-rc1
In this round, we've got a huge number of patches that improve code readability
along with minor bug fixes, while we've mainly fixed some critical issues in
recently-added per-block age-based extent_cache, atomic write support, and some
folio cases.
Enhancement:
- add sysfs nodes to set last_age_weight and manage discard_io_aware_gran
- show ipu policy in debugfs
- reduce stack memory cost by using bitfield in struct f2fs_io_info
- introduce trace_f2fs_replace_atomic_write_block
- enhance iostat support and adds flush commands
Bug fix:
- revert "f2fs: truncate blocks in batch in __complete_revoke_list()"
- fix kernel crash on the atomic write abort flow
- call clear_page_private_reference in .{release,invalid}_folio
- support .migrate_folio for compressed inode
- fix cgroup writeback accounting with fs-layer encryption
- retry to update the inode page given data corruption
- fix kernel crash due to null io->bio
- fix some bugs in per-block age-based extent_cache:
a. wrong calculation of block age
b. update age extent in f2fs_do_zero_range()
c. update age extent correctly during truncation
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmP9M/cACgkQQBSofoJI
UNIX1Q//Yp+nDeY91H3IO6aMSHPqRoBBnVTr8ERtLUF0fuQbBkzcQE+t8cMSoYDM
88sxoC+F7UnovNr84VeuKlHN4hYyAXuxj8OZetXI3XX+yiO+auEPtljGA0BaGwqL
93lIg8nIQ2ing/oZ/4+h4dvpYCPrhKOQS6h1sHhIWlql6Wxwxq01uA47i0Ni6y/o
D23JPFaDQfumN8qy1bm5xfLRhTQmaE35n5NhcBJpUD/rGK92NPXv7RLKPgZc3tKN
tJmL+NXa3NNEx5e5TSP7JX+rhD7KlL5XlB/m8LbpPIx338I0pt0uzAc7nTIOlzM3
DI0q3HXe9U3+JBHi+rKxkIniiRDmvhPx3NzdgcsYg75EnwdrNazsRHulBUEAXB4v
ghHbx53OxA2uSnUVbkY4HXNYf7cYjrx5vbX0oqEx48btBCC8KGFIcHtI72tIBee3
xdCxoM3e2AWijkFBOCkThXNuNNbdifQzn2e7xR7W+o0L9hwdR5t7tHhHT+cqG9Ox
6UKWoZZUjYUAV/YQT5Qh6570GsGncM8gHAUMz7DVTIOB9wYkHtb0Q9tUmoQccwf5
46r84c4/jxUQHt8SkXBBl1aiqHmR7EF17YvM5AXIdG3DqqOy70NWkM48hMOyIy2G
eY/wTVJwpd6oDveQPtxaHn7Wo3jSPNUlidOfAYQ7Itm34VXY/zc=
=yXLl
-----END PGP SIGNATURE-----
Merge tag 'f2fs-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this round, we've got a huge number of patches that improve code
readability along with minor bug fixes, while we've mainly fixed some
critical issues in recently-added per-block age-based extent_cache,
atomic write support, and some folio cases.
Enhancements:
- add sysfs nodes to set last_age_weight and manage
discard_io_aware_gran
- show ipu policy in debugfs
- reduce stack memory cost by using bitfield in struct f2fs_io_info
- introduce trace_f2fs_replace_atomic_write_block
- enhance iostat support and adds flush commands
Bug fixes:
- revert "f2fs: truncate blocks in batch in __complete_revoke_list()"
- fix kernel crash on the atomic write abort flow
- call clear_page_private_reference in .{release,invalid}_folio
- support .migrate_folio for compressed inode
- fix cgroup writeback accounting with fs-layer encryption
- retry to update the inode page given data corruption
- fix kernel crash due to NULL io->bio
- fix some bugs in per-block age-based extent_cache:
- wrong calculation of block age
- update age extent in f2fs_do_zero_range()
- update age extent correctly during truncation"
* tag 'f2fs-for-6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (81 commits)
f2fs: drop unnecessary arg for f2fs_ioc_*()
f2fs: Revert "f2fs: truncate blocks in batch in __complete_revoke_list()"
f2fs: synchronize atomic write aborts
f2fs: fix wrong segment count
f2fs: replace si->sbi w/ sbi in stat_show()
f2fs: export ipu policy in debugfs
f2fs: make kobj_type structures constant
f2fs: fix to do sanity check on extent cache correctly
f2fs: add missing description for ipu_policy node
f2fs: fix to set ipu policy
f2fs: fix typos in comments
f2fs: fix kernel crash due to null io->bio
f2fs: use iostat_lat_type directly as a parameter in the iostat_update_and_unbind_ctx()
f2fs: add sysfs nodes to set last_age_weight
f2fs: fix f2fs_show_options to show nogc_merge mount option
f2fs: fix cgroup writeback accounting with fs-layer encryption
f2fs: fix wrong calculation of block age
f2fs: fix to update age extent in f2fs_do_zero_range()
f2fs: fix to update age extent correctly during truncation
f2fs: fix to avoid potential memory corruption in __update_iostat_latency()
...
2023-02-28 08:18:51 +08:00
|
|
|
ret = f2fs_get_tmpfile(idmap, pinode, &fi->cow_inode);
|
2023-02-10 02:18:19 +08:00
|
|
|
iput(pinode);
|
|
|
|
if (ret) {
|
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_inode_flag(fi->cow_inode, FI_COW_FILE);
|
|
|
|
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
|
|
|
|
} else {
|
|
|
|
/* Reuse the already created COW inode */
|
2023-04-05 22:44:53 +08:00
|
|
|
ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);
|
|
|
|
if (ret) {
|
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
|
|
|
goto out;
|
|
|
|
}
|
2018-07-25 11:11:56 +08:00
|
|
|
}
|
2022-11-01 03:24:15 +08:00
|
|
|
|
|
|
|
f2fs_write_inode(inode, NULL);
|
2018-12-29 03:00:38 +08:00
|
|
|
|
2022-10-04 09:41:02 +08:00
|
|
|
stat_inc_atomic_inode(inode);
|
f2fs: avoid infinite GC loop due to stale atomic files
If committing atomic pages is failed when doing f2fs_do_sync_file(), we can
get commited pages but atomic_file being still set like:
- inmem: 0, atomic IO: 4 (Max. 10), volatile IO: 0 (Max. 0)
If GC selects this block, we can get an infinite loop like this:
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
In that moment, we can observe:
[Before]
Try to move 5084219 blocks (BG: 384508)
- data blocks : 4962373 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4534686 (10)
[After]
Try to move 5088973 blocks (BG: 384508)
- data blocks : 4967127 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4539440 (10)
So, refactor atomic_write flow like this:
1. start_atomic_write
- add inmem_list and set atomic_file
2. write()
- register it in inmem_pages
3. commit_atomic_write
- if no error, f2fs_drop_inmem_pages()
- f2fs_commit_inmme_pages() failed
: __revoked_inmem_pages() was done
- f2fs_do_sync_file failed
: abort_atomic_write later
4. abort_atomic_write
- f2fs_drop_inmem_pages
5. f2fs_drop_inmem_pages
- clear atomic_file
- remove inmem_list
Based on this change, when GC fails to move block in atomic_file,
f2fs_drop_inmem_pages_all() can call f2fs_drop_inmem_pages().
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-09-09 20:10:59 +08:00
|
|
|
|
2018-04-18 11:06:39 +08:00
|
|
|
set_inode_flag(inode, FI_ATOMIC_FILE);
|
2022-11-12 01:04:06 +08:00
|
|
|
|
|
|
|
isize = i_size_read(inode);
|
|
|
|
fi->original_i_size = isize;
|
|
|
|
if (truncate) {
|
|
|
|
set_inode_flag(inode, FI_ATOMIC_REPLACE);
|
|
|
|
truncate_inode_pages_final(inode->i_mapping);
|
|
|
|
f2fs_i_size_write(inode, 0);
|
|
|
|
isize = 0;
|
|
|
|
}
|
|
|
|
f2fs_i_size_write(fi->cow_inode, isize);
|
|
|
|
|
2022-05-26 10:21:06 +08:00
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
2017-03-18 09:20:55 +08:00
|
|
|
|
2022-05-26 10:21:06 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
|
|
|
fi->atomic_write_task = current;
|
2016-12-29 05:55:09 +08:00
|
|
|
stat_update_max_atomic_write(inode);
|
2022-07-19 07:02:48 +08:00
|
|
|
fi->atomic_write_cnt = 0;
|
2017-03-18 09:20:55 +08:00
|
|
|
out:
|
2016-05-09 19:56:33 +08:00
|
|
|
inode_unlock(inode);
|
2016-05-09 19:56:32 +08:00
|
|
|
mnt_drop_write_file(filp);
|
2016-04-13 05:36:11 +08:00
|
|
|
return ret;
|
2014-10-07 08:39:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_commit_atomic_write(struct file *filp)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
2023-01-13 19:49:26 +08:00
|
|
|
struct mnt_idmap *idmap = file_mnt_idmap(filp);
|
2014-10-07 08:39:50 +08:00
|
|
|
int ret;
|
|
|
|
|
2023-01-13 19:49:26 +08:00
|
|
|
if (!inode_owner_or_capable(idmap, inode))
|
2014-10-07 08:39:50 +08:00
|
|
|
return -EACCES;
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
f2fs_balance_fs(F2FS_I_SB(inode), true);
|
2016-05-09 19:56:33 +08:00
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
inode_lock(inode);
|
2018-02-27 22:45:24 +08:00
|
|
|
|
2015-07-25 15:29:17 +08:00
|
|
|
if (f2fs_is_atomic_file(inode)) {
|
2022-04-29 02:18:09 +08:00
|
|
|
ret = f2fs_commit_atomic_write(inode);
|
f2fs: avoid infinite GC loop due to stale atomic files
If committing atomic pages is failed when doing f2fs_do_sync_file(), we can
get commited pages but atomic_file being still set like:
- inmem: 0, atomic IO: 4 (Max. 10), volatile IO: 0 (Max. 0)
If GC selects this block, we can get an infinite loop like this:
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
f2fs_submit_page_bio: dev = (253,7), ino = 2, page_index = 0x2359a8, oldaddr = 0x2359a8, newaddr = 0x2359a8, rw = READ(), type = COLD_DATA
f2fs_submit_read_bio: dev = (253,7)/(253,7), rw = READ(), DATA, sector = 18533696, size = 4096
f2fs_get_victim: dev = (253,7), type = No TYPE, policy = (Foreground GC, LFS-mode, Greedy), victim = 4355, cost = 1, ofs_unit = 1, pre_victim_secno = 4355, prefree = 0, free = 234
f2fs_iget: dev = (253,7), ino = 6247, pino = 5845, i_mode = 0x81b0, i_size = 319488, i_nlink = 1, i_blocks = 624, i_advise = 0x2c
In that moment, we can observe:
[Before]
Try to move 5084219 blocks (BG: 384508)
- data blocks : 4962373 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4534686 (10)
[After]
Try to move 5088973 blocks (BG: 384508)
- data blocks : 4967127 (274483)
- node blocks : 121846 (110025)
Skipped : atomic write 4539440 (10)
So, refactor atomic_write flow like this:
1. start_atomic_write
- add inmem_list and set atomic_file
2. write()
- register it in inmem_pages
3. commit_atomic_write
- if no error, f2fs_drop_inmem_pages()
- f2fs_commit_inmme_pages() failed
: __revoked_inmem_pages() was done
- f2fs_do_sync_file failed
: abort_atomic_write later
4. abort_atomic_write
- f2fs_drop_inmem_pages
5. f2fs_drop_inmem_pages
- clear atomic_file
- remove inmem_list
Based on this change, when GC fails to move block in atomic_file,
f2fs_drop_inmem_pages_all() can call f2fs_drop_inmem_pages().
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-09-09 20:10:59 +08:00
|
|
|
if (!ret)
|
2022-11-01 03:24:15 +08:00
|
|
|
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
|
|
|
|
|
|
|
f2fs_abort_atomic_write(inode, ret);
|
2016-12-29 05:55:09 +08:00
|
|
|
} else {
|
2017-08-23 18:23:25 +08:00
|
|
|
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
|
2015-07-25 15:29:17 +08:00
|
|
|
}
|
2022-11-01 03:24:15 +08:00
|
|
|
|
2016-05-09 19:56:33 +08:00
|
|
|
inode_unlock(inode);
|
2014-12-09 22:08:59 +08:00
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-08-02 01:08:08 +08:00
|
|
|
static int f2fs_ioc_abort_atomic_write(struct file *filp)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
2023-01-13 19:49:26 +08:00
|
|
|
struct mnt_idmap *idmap = file_mnt_idmap(filp);
|
2022-08-02 01:08:08 +08:00
|
|
|
int ret;
|
|
|
|
|
2023-01-13 19:49:26 +08:00
|
|
|
if (!inode_owner_or_capable(idmap, inode))
|
2022-08-02 01:08:08 +08:00
|
|
|
return -EACCES;
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
inode_lock(inode);
|
|
|
|
|
2022-08-04 21:38:21 +08:00
|
|
|
f2fs_abort_atomic_write(inode, true);
|
2022-08-02 01:08:08 +08:00
|
|
|
|
|
|
|
inode_unlock(inode);
|
|
|
|
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-01-09 11:15:53 +08:00
|
|
|
static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct super_block *sb = sbi->sb;
|
|
|
|
__u32 in;
|
2018-06-20 18:39:53 +08:00
|
|
|
int ret = 0;
|
2015-01-09 11:15:53 +08:00
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (get_user(in, (__u32 __user *)arg))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2018-05-18 14:21:52 +08:00
|
|
|
if (in != F2FS_GOING_DOWN_FULLSYNC) {
|
|
|
|
ret = mnt_want_write_file(filp);
|
2020-06-08 20:03:16 +08:00
|
|
|
if (ret) {
|
|
|
|
if (ret == -EROFS) {
|
|
|
|
ret = 0;
|
2022-09-28 23:38:53 +08:00
|
|
|
f2fs_stop_checkpoint(sbi, false,
|
|
|
|
STOP_CP_REASON_SHUTDOWN);
|
2020-06-08 20:03:16 +08:00
|
|
|
trace_f2fs_shutdown(sbi, in, ret);
|
|
|
|
}
|
2018-05-18 14:21:52 +08:00
|
|
|
return ret;
|
2020-06-08 20:03:16 +08:00
|
|
|
}
|
2018-05-18 14:21:52 +08:00
|
|
|
}
|
2016-05-09 19:56:32 +08:00
|
|
|
|
2015-01-09 11:15:53 +08:00
|
|
|
switch (in) {
|
|
|
|
case F2FS_GOING_DOWN_FULLSYNC:
|
2020-11-24 18:54:06 +08:00
|
|
|
ret = freeze_bdev(sb->s_bdev);
|
|
|
|
if (ret)
|
2018-01-17 22:28:52 +08:00
|
|
|
goto out;
|
2022-09-28 23:38:53 +08:00
|
|
|
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
|
2020-11-24 18:54:06 +08:00
|
|
|
thaw_bdev(sb->s_bdev);
|
2015-01-09 11:15:53 +08:00
|
|
|
break;
|
|
|
|
case F2FS_GOING_DOWN_METASYNC:
|
|
|
|
/* do checkpoint only */
|
2018-01-17 22:28:52 +08:00
|
|
|
ret = f2fs_sync_fs(sb, 1);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2022-09-28 23:38:53 +08:00
|
|
|
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
|
2015-01-09 11:15:53 +08:00
|
|
|
break;
|
|
|
|
case F2FS_GOING_DOWN_NOSYNC:
|
2022-09-28 23:38:53 +08:00
|
|
|
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
|
2015-01-09 11:15:53 +08:00
|
|
|
break;
|
2015-10-08 00:46:37 +08:00
|
|
|
case F2FS_GOING_DOWN_METAFLUSH:
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
|
2022-09-28 23:38:53 +08:00
|
|
|
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_SHUTDOWN);
|
2015-10-08 00:46:37 +08:00
|
|
|
break;
|
2018-11-29 05:26:03 +08:00
|
|
|
case F2FS_GOING_DOWN_NEED_FSCK:
|
|
|
|
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
2019-01-25 09:48:38 +08:00
|
|
|
set_sbi_flag(sbi, SBI_CP_DISABLED_QUICK);
|
|
|
|
set_sbi_flag(sbi, SBI_IS_DIRTY);
|
2018-11-29 05:26:03 +08:00
|
|
|
/* do checkpoint only */
|
|
|
|
ret = f2fs_sync_fs(sb, 1);
|
2019-01-25 09:48:38 +08:00
|
|
|
goto out;
|
2015-01-09 11:15:53 +08:00
|
|
|
default:
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
2015-01-09 11:15:53 +08:00
|
|
|
}
|
2018-01-18 17:23:29 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_stop_gc_thread(sbi);
|
|
|
|
f2fs_stop_discard_thread(sbi);
|
2018-01-18 17:23:29 +08:00
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
f2fs_drop_discard_cmd(sbi);
|
2018-01-18 17:23:29 +08:00
|
|
|
clear_opt(sbi, DISCARD);
|
|
|
|
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2016-05-09 19:56:32 +08:00
|
|
|
out:
|
2018-05-18 14:21:52 +08:00
|
|
|
if (in != F2FS_GOING_DOWN_FULLSYNC)
|
|
|
|
mnt_drop_write_file(filp);
|
2019-02-26 19:01:15 +08:00
|
|
|
|
|
|
|
trace_f2fs_shutdown(sbi, in, ret);
|
|
|
|
|
2016-05-09 19:56:32 +08:00
|
|
|
return ret;
|
2015-01-09 11:15:53 +08:00
|
|
|
}
|
|
|
|
|
2014-09-25 06:37:02 +08:00
|
|
|
static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct super_block *sb = inode->i_sb;
|
|
|
|
struct fstrim_range range;
|
|
|
|
int ret;
|
2014-09-21 13:06:39 +08:00
|
|
|
|
2014-09-25 06:37:02 +08:00
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
2014-09-21 13:06:39 +08:00
|
|
|
|
f2fs: fix to avoid NULL pointer dereference on se->discard_map
https://bugzilla.kernel.org/show_bug.cgi?id=200951
These is a NULL pointer dereference issue reported in bugzilla:
Hi,
in the setup there is a SATA SSD connected to a SATA-to-USB bridge.
The disc is "Samsung SSD 850 PRO 256G" which supports TRIM.
There are four partitions:
sda1: FAT /boot
sda2: F2FS /
sda3: F2FS /home
sda4: F2FS
The bridge is ASMT1153e which uses the "uas" driver.
There is no TRIM pass-through, so, when mounting it reports:
mounting with "discard" option, but the device does not support discard
The USB host is USB3.0 and UASP capable. It is the one on RK3399.
Given this everything works fine, except there is no TRIM support.
In order to enable TRIM a new UDEV rule is added [1]:
/etc/udev/rules.d/10-sata-bridge-trim.rules:
ACTION=="add|change", ATTRS{idVendor}=="174c", ATTRS{idProduct}=="55aa", SUBSYSTEM=="scsi_disk", ATTR{provisioning_mode}="unmap"
After reboot any F2FS write hangs forever and dmesg reports:
Unable to handle kernel NULL pointer dereference
Also tested on a x86_64 system: works fine even with TRIM enabled.
same disc
same bridge
different usb host controller
different cpu architecture
not root filesystem
Regards,
Vicenç.
[1] Post #5 in https://bbs.archlinux.org/viewtopic.php?id=236280
Unable to handle kernel NULL pointer dereference at virtual address 000000000000003e
Mem abort info:
ESR = 0x96000004
Exception class = DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
Data abort info:
ISV = 0, ISS = 0x00000004
CM = 0, WnR = 0
user pgtable: 4k pages, 48-bit VAs, pgdp = 00000000626e3122
[000000000000003e] pgd=0000000000000000
Internal error: Oops: 96000004 [#1] SMP
Modules linked in: overlay snd_soc_hdmi_codec rc_cec dw_hdmi_i2s_audio dw_hdmi_cec snd_soc_simple_card snd_soc_simple_card_utils snd_soc_rockchip_i2s rockchip_rga snd_soc_rockchip_pcm rockchipdrm videobuf2_dma_sg v4l2_mem2mem rtc_rk808 videobuf2_memops analogix_dp videobuf2_v4l2 videobuf2_common dw_hdmi dw_wdt cec rc_core videodev drm_kms_helper media drm rockchip_thermal rockchip_saradc realtek drm_panel_orientation_quirks syscopyarea sysfillrect sysimgblt fb_sys_fops dwmac_rk stmmac_platform stmmac pwm_bl squashfs loop crypto_user gpio_keys hid_kensington
CPU: 5 PID: 957 Comm: nvim Not tainted 4.19.0-rc1-1-ARCH #1
Hardware name: Sapphire-RK3399 Board (DT)
pstate: 00000005 (nzcv daif -PAN -UAO)
pc : update_sit_entry+0x304/0x4b0
lr : update_sit_entry+0x108/0x4b0
sp : ffff00000ca13bd0
x29: ffff00000ca13bd0 x28: 000000000000003e
x27: 0000000000000020 x26: 0000000000080000
x25: 0000000000000048 x24: ffff8000ebb85cf8
x23: 0000000000000253 x22: 00000000ffffffff
x21: 00000000000535f2 x20: 00000000ffffffdf
x19: ffff8000eb9e6800 x18: ffff8000eb9e6be8
x17: 0000000007ce6926 x16: 000000001c83ffa8
x15: 0000000000000000 x14: ffff8000f602df90
x13: 0000000000000006 x12: 0000000000000040
x11: 0000000000000228 x10: 0000000000000000
x9 : 0000000000000000 x8 : 0000000000000000
x7 : 00000000000535f2 x6 : ffff8000ebff3440
x5 : ffff8000ebff3440 x4 : ffff8000ebe3a6c8
x3 : 00000000ffffffff x2 : 0000000000000020
x1 : 0000000000000000 x0 : ffff8000eb9e5800
Process nvim (pid: 957, stack limit = 0x0000000063a78320)
Call trace:
update_sit_entry+0x304/0x4b0
f2fs_invalidate_blocks+0x98/0x140
truncate_node+0x90/0x400
f2fs_remove_inode_page+0xe8/0x340
f2fs_evict_inode+0x2b0/0x408
evict+0xe0/0x1e0
iput+0x160/0x260
do_unlinkat+0x214/0x298
__arm64_sys_unlinkat+0x3c/0x68
el0_svc_handler+0x94/0x118
el0_svc+0x8/0xc
Code: f9400800 b9488400 36080140 f9400f01 (387c4820)
---[ end trace a0f21a307118c477 ]---
The reason is it is possible to enable discard flag on block queue via
UDEV, but during mount, f2fs will initialize se->discard_map only if
this flag is set, once the flag is set after mount, f2fs may dereference
NULL pointer on se->discard_map.
So this patch does below changes to fix this issue:
- initialize and update se->discard_map all the time.
- don't clear DISCARD option if device has no QUEUE_FLAG_DISCARD flag
during mount.
- don't issue small discard on zoned block device.
- introduce some functions to enhance the readability.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Tested-by: Vicente Bergas <vicencb@gmail.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-09-04 03:52:17 +08:00
|
|
|
if (!f2fs_hw_support_discard(F2FS_SB(sb)))
|
2014-09-25 06:37:02 +08:00
|
|
|
return -EOPNOTSUPP;
|
2014-09-21 13:06:39 +08:00
|
|
|
|
2014-09-25 06:37:02 +08:00
|
|
|
if (copy_from_user(&range, (struct fstrim_range __user *)arg,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
2014-09-21 13:06:39 +08:00
|
|
|
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2014-09-25 06:37:02 +08:00
|
|
|
range.minlen = max((unsigned int)range.minlen,
|
2022-04-15 12:52:56 +08:00
|
|
|
bdev_discard_granularity(sb->s_bdev));
|
2014-09-25 06:37:02 +08:00
|
|
|
ret = f2fs_trim_fs(F2FS_SB(sb), &range);
|
2016-05-09 19:56:32 +08:00
|
|
|
mnt_drop_write_file(filp);
|
2014-09-25 06:37:02 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2014-09-21 13:06:39 +08:00
|
|
|
|
2014-09-25 06:37:02 +08:00
|
|
|
if (copy_to_user((struct fstrim_range __user *)arg, &range,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
2014-09-25 06:37:02 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-21 06:19:06 +08:00
|
|
|
static bool uuid_is_nonzero(__u8 u[16])
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
if (u[i])
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
|
2018-10-24 18:34:26 +08:00
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(inode)))
|
2017-11-14 19:28:42 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
2016-05-09 19:56:32 +08:00
|
|
|
|
2016-11-27 08:07:49 +08:00
|
|
|
return fscrypt_ioctl_set_policy(filp, (const void __user *)arg);
|
2015-04-21 06:19:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
|
|
|
|
{
|
2018-10-24 18:34:26 +08:00
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
2017-11-14 19:28:42 +08:00
|
|
|
return -EOPNOTSUPP;
|
2016-11-27 08:07:49 +08:00
|
|
|
return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
|
2015-04-21 06:19:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2022-12-16 23:50:00 +08:00
|
|
|
u8 encrypt_pw_salt[16];
|
2015-04-21 06:19:06 +08:00
|
|
|
int err;
|
|
|
|
|
2018-10-24 18:34:26 +08:00
|
|
|
if (!f2fs_sb_has_encrypt(sbi))
|
2015-04-21 06:19:06 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
err = mnt_want_write_file(filp);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->sb_lock);
|
2018-02-11 22:53:20 +08:00
|
|
|
|
|
|
|
if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
|
|
|
|
goto got_it;
|
|
|
|
|
2015-04-21 06:19:06 +08:00
|
|
|
/* update superblock with uuid */
|
|
|
|
generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
|
|
|
|
|
2015-06-08 13:28:03 +08:00
|
|
|
err = f2fs_commit_super(sbi, false);
|
2015-04-21 06:19:06 +08:00
|
|
|
if (err) {
|
|
|
|
/* undo new data */
|
|
|
|
memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
|
2018-02-11 22:53:20 +08:00
|
|
|
goto out_err;
|
2015-04-21 06:19:06 +08:00
|
|
|
}
|
|
|
|
got_it:
|
2022-12-16 23:50:00 +08:00
|
|
|
memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16);
|
2018-02-11 22:53:20 +08:00
|
|
|
out_err:
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&sbi->sb_lock);
|
2018-02-11 22:53:20 +08:00
|
|
|
mnt_drop_write_file(filp);
|
2022-12-16 23:50:00 +08:00
|
|
|
|
|
|
|
if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16))
|
|
|
|
err = -EFAULT;
|
|
|
|
|
2018-02-11 22:53:20 +08:00
|
|
|
return err;
|
2015-04-21 06:19:06 +08:00
|
|
|
}
|
|
|
|
|
2019-08-05 10:35:48 +08:00
|
|
|
static int f2fs_ioc_get_encryption_policy_ex(struct file *filp,
|
|
|
|
unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_get_policy_ex(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_add_encryption_key(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_add_key(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_remove_encryption_key(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_remove_key(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_remove_encryption_key_all_users(struct file *filp,
|
|
|
|
unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_remove_key_all_users(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_get_encryption_key_status(struct file *filp,
|
|
|
|
unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_get_key_status(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
2020-03-15 04:50:51 +08:00
|
|
|
static int f2fs_ioc_get_encryption_nonce(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_encrypt(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fscrypt_ioctl_get_nonce(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
2015-07-10 18:08:10 +08:00
|
|
|
static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2022-05-07 02:40:33 +08:00
|
|
|
struct f2fs_gc_control gc_control = { .victim_segno = NULL_SEGNO,
|
|
|
|
.no_bg_gc = false,
|
2022-05-07 04:34:41 +08:00
|
|
|
.should_migrate_blocks = false,
|
|
|
|
.nr_free_secs = 0 };
|
2015-10-05 22:22:44 +08:00
|
|
|
__u32 sync;
|
2016-05-09 19:56:32 +08:00
|
|
|
int ret;
|
2015-07-10 18:08:10 +08:00
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2015-10-05 22:22:44 +08:00
|
|
|
if (get_user(sync, (__u32 __user *)arg))
|
2015-07-10 18:08:10 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
2015-10-05 22:22:44 +08:00
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
2015-07-10 18:08:10 +08:00
|
|
|
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2015-10-05 22:22:44 +08:00
|
|
|
if (!sync) {
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
2015-10-05 22:22:44 +08:00
|
|
|
} else {
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->gc_lock);
|
2015-07-10 18:08:10 +08:00
|
|
|
}
|
|
|
|
|
2022-05-07 02:40:33 +08:00
|
|
|
gc_control.init_gc_type = sync ? FG_GC : BG_GC;
|
|
|
|
gc_control.err_gc_skipped = sync;
|
2023-08-08 08:59:48 +08:00
|
|
|
stat_inc_gc_call_count(sbi, FOREGROUND);
|
2022-05-07 02:40:33 +08:00
|
|
|
ret = f2fs_gc(sbi, &gc_control);
|
2016-05-09 19:56:32 +08:00
|
|
|
out:
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
2015-07-10 18:08:10 +08:00
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
static int __f2fs_ioc_gc_range(struct file *filp, struct f2fs_gc_range *range)
|
2017-06-16 07:44:42 +08:00
|
|
|
{
|
2020-11-10 09:24:37 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
|
2022-05-07 02:40:33 +08:00
|
|
|
struct f2fs_gc_control gc_control = {
|
|
|
|
.init_gc_type = range->sync ? FG_GC : BG_GC,
|
|
|
|
.no_bg_gc = false,
|
|
|
|
.should_migrate_blocks = false,
|
2022-05-07 04:34:41 +08:00
|
|
|
.err_gc_skipped = range->sync,
|
|
|
|
.nr_free_secs = 0 };
|
2017-06-16 07:44:42 +08:00
|
|
|
u64 end;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
end = range->start + range->len;
|
|
|
|
if (end < range->start || range->start < MAIN_BLKADDR(sbi) ||
|
2019-09-17 12:49:23 +08:00
|
|
|
end >= MAX_BLKADDR(sbi))
|
2018-04-24 11:40:30 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-06-16 07:44:42 +08:00
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
do_more:
|
2020-11-10 09:24:37 +08:00
|
|
|
if (!range->sync) {
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
|
2017-06-16 07:44:42 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->gc_lock);
|
2017-06-16 07:44:42 +08:00
|
|
|
}
|
|
|
|
|
2022-05-07 02:40:33 +08:00
|
|
|
gc_control.victim_segno = GET_SEGNO(sbi, range->start);
|
2023-08-08 08:59:48 +08:00
|
|
|
stat_inc_gc_call_count(sbi, FOREGROUND);
|
2022-05-07 02:40:33 +08:00
|
|
|
ret = f2fs_gc(sbi, &gc_control);
|
2020-06-28 19:23:03 +08:00
|
|
|
if (ret) {
|
|
|
|
if (ret == -EBUSY)
|
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
2022-06-29 02:03:57 +08:00
|
|
|
range->start += CAP_BLKS_PER_SEC(sbi);
|
2020-11-10 09:24:37 +08:00
|
|
|
if (range->start <= end)
|
2017-06-16 07:44:42 +08:00
|
|
|
goto do_more;
|
|
|
|
out:
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct f2fs_gc_range range;
|
|
|
|
|
|
|
|
if (copy_from_user(&range, (struct f2fs_gc_range __user *)arg,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
|
|
|
return __f2fs_ioc_gc_range(filp, &range);
|
|
|
|
}
|
|
|
|
|
2023-02-15 14:17:01 +08:00
|
|
|
static int f2fs_ioc_write_checkpoint(struct file *filp)
|
2015-10-05 22:24:19 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2016-05-09 19:56:32 +08:00
|
|
|
int ret;
|
2015-10-05 22:24:19 +08:00
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
2018-08-21 10:21:43 +08:00
|
|
|
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED))) {
|
2019-06-18 17:48:42 +08:00
|
|
|
f2fs_info(sbi, "Skipping Checkpoint. Checkpoints currently disabled.");
|
2018-08-21 10:21:43 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-05-09 19:56:32 +08:00
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = f2fs_sync_fs(sbi->sb, 1);
|
|
|
|
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
2015-10-05 22:24:19 +08:00
|
|
|
}
|
|
|
|
|
2015-10-27 09:53:45 +08:00
|
|
|
static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
|
|
|
struct file *filp,
|
|
|
|
struct f2fs_defragment *range)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
2018-01-10 18:18:52 +08:00
|
|
|
struct f2fs_map_blocks map = { .m_next_extent = NULL,
|
2021-04-06 09:47:35 +08:00
|
|
|
.m_seg_type = NO_CHECK_TYPE,
|
2018-11-20 04:29:35 +08:00
|
|
|
.m_may_create = false };
|
2022-12-17 06:05:44 +08:00
|
|
|
struct extent_info ei = {};
|
2018-01-10 18:18:52 +08:00
|
|
|
pgoff_t pg_start, pg_end, next_pgofs;
|
2015-12-01 11:56:52 +08:00
|
|
|
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
2015-10-27 09:53:45 +08:00
|
|
|
unsigned int total = 0, sec_num;
|
|
|
|
block_t blk_end = 0;
|
|
|
|
bool fragmented = false;
|
|
|
|
int err;
|
|
|
|
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
pg_start = range->start >> PAGE_SHIFT;
|
|
|
|
pg_end = (range->start + range->len) >> PAGE_SHIFT;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
2016-01-08 06:15:04 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2015-10-27 09:53:45 +08:00
|
|
|
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_lock(inode);
|
2015-10-27 09:53:45 +08:00
|
|
|
|
2023-04-26 00:47:11 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto unlock_out;
|
|
|
|
}
|
|
|
|
|
2022-02-04 15:19:46 +08:00
|
|
|
/* if in-place-update policy is enabled, don't waste time here */
|
|
|
|
set_inode_flag(inode, FI_OPU_WRITE);
|
|
|
|
if (f2fs_should_update_inplace(inode, NULL)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2015-10-27 09:53:45 +08:00
|
|
|
/* writeback all dirty pages in the range */
|
|
|
|
err = filemap_write_and_wait_range(inode->i_mapping, range->start,
|
2015-12-14 13:34:00 +08:00
|
|
|
range->start + range->len - 1);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* lookup mapping info in extent cache, skip defragmenting if physical
|
|
|
|
* block addresses are continuous.
|
|
|
|
*/
|
2022-12-01 01:26:29 +08:00
|
|
|
if (f2fs_lookup_read_extent_cache(inode, pg_start, &ei)) {
|
2015-10-27 09:53:45 +08:00
|
|
|
if (ei.fofs + ei.len >= pg_end)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
map.m_lblk = pg_start;
|
2018-01-10 18:18:52 +08:00
|
|
|
map.m_next_pgofs = &next_pgofs;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* lookup mapping info in dnode page cache, skip defragmenting if all
|
|
|
|
* physical block addresses are continuous even if there are hole(s)
|
|
|
|
* in logical blocks.
|
|
|
|
*/
|
|
|
|
while (map.m_lblk < pg_end) {
|
2015-12-15 17:02:41 +08:00
|
|
|
map.m_len = pg_end - map.m_lblk;
|
2022-11-28 17:15:20 +08:00
|
|
|
err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
|
2018-01-10 18:18:52 +08:00
|
|
|
map.m_lblk = next_pgofs;
|
2015-10-27 09:53:45 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-01-10 18:18:51 +08:00
|
|
|
if (blk_end && blk_end != map.m_pblk)
|
2015-10-27 09:53:45 +08:00
|
|
|
fragmented = true;
|
2018-01-10 18:18:51 +08:00
|
|
|
|
|
|
|
/* record total count of block that we're going to move */
|
|
|
|
total += map.m_len;
|
|
|
|
|
2015-10-27 09:53:45 +08:00
|
|
|
blk_end = map.m_pblk + map.m_len;
|
|
|
|
|
|
|
|
map.m_lblk += map.m_len;
|
|
|
|
}
|
|
|
|
|
2019-07-29 23:02:29 +08:00
|
|
|
if (!fragmented) {
|
|
|
|
total = 0;
|
2015-10-27 09:53:45 +08:00
|
|
|
goto out;
|
2019-07-29 23:02:29 +08:00
|
|
|
}
|
2015-10-27 09:53:45 +08:00
|
|
|
|
2022-06-29 02:03:57 +08:00
|
|
|
sec_num = DIV_ROUND_UP(total, CAP_BLKS_PER_SEC(sbi));
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* make sure there are enough free section for LFS allocation, this can
|
|
|
|
* avoid defragment running in SSR mode when free section are allocated
|
|
|
|
* intensively
|
|
|
|
*/
|
2016-09-02 03:02:51 +08:00
|
|
|
if (has_not_enough_free_secs(sbi, 0, sec_num)) {
|
2015-10-27 09:53:45 +08:00
|
|
|
err = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-01-10 18:18:51 +08:00
|
|
|
map.m_lblk = pg_start;
|
|
|
|
map.m_len = pg_end - pg_start;
|
|
|
|
total = 0;
|
|
|
|
|
2015-10-27 09:53:45 +08:00
|
|
|
while (map.m_lblk < pg_end) {
|
|
|
|
pgoff_t idx;
|
|
|
|
int cnt = 0;
|
|
|
|
|
|
|
|
do_map:
|
2015-12-15 17:02:41 +08:00
|
|
|
map.m_len = pg_end - map.m_lblk;
|
2022-11-28 17:15:20 +08:00
|
|
|
err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (err)
|
|
|
|
goto clear_out;
|
|
|
|
|
|
|
|
if (!(map.m_flags & F2FS_MAP_FLAGS)) {
|
2018-01-10 18:18:52 +08:00
|
|
|
map.m_lblk = next_pgofs;
|
2019-07-29 23:02:29 +08:00
|
|
|
goto check;
|
2015-10-27 09:53:45 +08:00
|
|
|
}
|
|
|
|
|
2022-02-04 15:19:46 +08:00
|
|
|
set_inode_flag(inode, FI_SKIP_WRITES);
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
idx = map.m_lblk;
|
|
|
|
while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
|
|
|
|
struct page *page;
|
|
|
|
|
f2fs: clean up symbol namespace
As Ted reported:
"Hi, I was looking at f2fs's sources recently, and I noticed that there
is a very large number of non-static symbols which don't have a f2fs
prefix. There's well over a hundred (see attached below).
As one example, in fs/f2fs/dir.c there is:
unsigned char get_de_type(struct f2fs_dir_entry *de)
This function is clearly only useful for f2fs, but it has a generic
name. This means that if any other file system tries to have the same
symbol name, there will be a symbol conflict and the kernel would not
successfully build. It also means that when someone is looking f2fs
sources, it's not at all obvious whether a function such as
read_data_page(), invalidate_blocks(), is a generic kernel function
found in the fs, mm, or block layers, or a f2fs specific function.
You might want to fix this at some point. Hopefully Kent's bcachefs
isn't similarly using genericly named functions, since that might
cause conflicts with f2fs's functions --- but just as this would be a
problem that we would rightly insist that Kent fix, this is something
that we should have rightly insisted that f2fs should have fixed
before it was integrated into the mainline kernel.
acquire_orphan_inode
add_ino_entry
add_orphan_inode
allocate_data_block
allocate_new_segments
alloc_nid
alloc_nid_done
alloc_nid_failed
available_free_memory
...."
This patch adds "f2fs_" prefix for all non-static symbols in order to:
a) avoid conflict with other kernel generic symbols;
b) to indicate the function is f2fs specific one instead of generic
one;
Reported-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-30 00:20:41 +08:00
|
|
|
page = f2fs_get_lock_data_page(inode, idx, true);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (IS_ERR(page)) {
|
|
|
|
err = PTR_ERR(page);
|
|
|
|
goto clear_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_page_dirty(page);
|
2022-05-27 12:13:30 +08:00
|
|
|
set_page_private_gcing(page);
|
2015-10-27 09:53:45 +08:00
|
|
|
f2fs_put_page(page, 1);
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
cnt++;
|
|
|
|
total++;
|
|
|
|
}
|
|
|
|
|
|
|
|
map.m_lblk = idx;
|
2019-07-29 23:02:29 +08:00
|
|
|
check:
|
|
|
|
if (map.m_lblk < pg_end && cnt < blk_per_seg)
|
2015-10-27 09:53:45 +08:00
|
|
|
goto do_map;
|
|
|
|
|
2022-02-04 15:19:46 +08:00
|
|
|
clear_inode_flag(inode, FI_SKIP_WRITES);
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
err = filemap_fdatawrite(inode->i_mapping);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
clear_out:
|
2022-02-04 15:19:46 +08:00
|
|
|
clear_inode_flag(inode, FI_SKIP_WRITES);
|
2015-10-27 09:53:45 +08:00
|
|
|
out:
|
2022-02-04 15:19:46 +08:00
|
|
|
clear_inode_flag(inode, FI_OPU_WRITE);
|
2023-04-26 00:47:11 +08:00
|
|
|
unlock_out:
|
2016-01-23 04:40:57 +08:00
|
|
|
inode_unlock(inode);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (!err)
|
mm, fs: get rid of PAGE_CACHE_* and page_cache_{get,release} macros
PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} macros were introduced *long* time
ago with promise that one day it will be possible to implement page
cache with bigger chunks than PAGE_SIZE.
This promise never materialized. And unlikely will.
We have many places where PAGE_CACHE_SIZE assumed to be equal to
PAGE_SIZE. And it's constant source of confusion on whether
PAGE_CACHE_* or PAGE_* constant should be used in a particular case,
especially on the border between fs and mm.
Global switching to PAGE_CACHE_SIZE != PAGE_SIZE would cause to much
breakage to be doable.
Let's stop pretending that pages in page cache are special. They are
not.
The changes are pretty straight-forward:
- <foo> << (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- <foo> >> (PAGE_CACHE_SHIFT - PAGE_SHIFT) -> <foo>;
- PAGE_CACHE_{SIZE,SHIFT,MASK,ALIGN} -> PAGE_{SIZE,SHIFT,MASK,ALIGN};
- page_cache_get() -> get_page();
- page_cache_release() -> put_page();
This patch contains automated changes generated with coccinelle using
script below. For some reason, coccinelle doesn't patch header files.
I've called spatch for them manually.
The only adjustment after coccinelle is revert of changes to
PAGE_CAHCE_ALIGN definition: we are going to drop it later.
There are few places in the code where coccinelle didn't reach. I'll
fix them manually in a separate patch. Comments and documentation also
will be addressed with the separate patch.
virtual patch
@@
expression E;
@@
- E << (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
expression E;
@@
- E >> (PAGE_CACHE_SHIFT - PAGE_SHIFT)
+ E
@@
@@
- PAGE_CACHE_SHIFT
+ PAGE_SHIFT
@@
@@
- PAGE_CACHE_SIZE
+ PAGE_SIZE
@@
@@
- PAGE_CACHE_MASK
+ PAGE_MASK
@@
expression E;
@@
- PAGE_CACHE_ALIGN(E)
+ PAGE_ALIGN(E)
@@
expression E;
@@
- page_cache_get(E)
+ get_page(E)
@@
expression E;
@@
- page_cache_release(E)
+ put_page(E)
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-04-01 20:29:47 +08:00
|
|
|
range->len = (u64)total << PAGE_SHIFT;
|
2015-10-27 09:53:45 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_defragment(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct f2fs_defragment range;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
2017-04-25 20:45:12 +08:00
|
|
|
if (!S_ISREG(inode->i_mode) || f2fs_is_atomic_file(inode))
|
2015-10-27 09:53:45 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-03-10 17:55:07 +08:00
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
if (copy_from_user(&range, (struct f2fs_defragment __user *)arg,
|
2017-03-10 17:55:07 +08:00
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
/* verify alignment of offset & size */
|
2017-03-10 17:55:07 +08:00
|
|
|
if (range.start & (F2FS_BLKSIZE - 1) || range.len & (F2FS_BLKSIZE - 1))
|
|
|
|
return -EINVAL;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
2017-03-08 10:47:12 +08:00
|
|
|
if (unlikely((range.start + range.len) >> PAGE_SHIFT >
|
2021-01-13 13:21:54 +08:00
|
|
|
max_file_blocks(inode)))
|
2017-03-10 17:55:07 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
err = mnt_want_write_file(filp);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2017-03-08 10:47:12 +08:00
|
|
|
|
2015-10-27 09:53:45 +08:00
|
|
|
err = f2fs_defragment_range(sbi, filp, &range);
|
2017-03-10 17:55:07 +08:00
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
|
2016-01-09 08:57:48 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2015-10-27 09:53:45 +08:00
|
|
|
if (err < 0)
|
2017-03-10 17:55:07 +08:00
|
|
|
return err;
|
2015-10-27 09:53:45 +08:00
|
|
|
|
|
|
|
if (copy_to_user((struct f2fs_defragment __user *)arg, &range,
|
|
|
|
sizeof(range)))
|
2017-03-10 17:55:07 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
2015-10-27 09:53:45 +08:00
|
|
|
}
|
|
|
|
|
2016-07-09 06:16:47 +08:00
|
|
|
static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
|
|
|
|
struct file *file_out, loff_t pos_out, size_t len)
|
|
|
|
{
|
|
|
|
struct inode *src = file_inode(file_in);
|
|
|
|
struct inode *dst = file_inode(file_out);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(src);
|
|
|
|
size_t olen = len, dst_max_i_size = 0;
|
|
|
|
size_t dst_osize;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (file_in->f_path.mnt != file_out->f_path.mnt ||
|
|
|
|
src->i_sb != dst->i_sb)
|
|
|
|
return -EXDEV;
|
|
|
|
|
|
|
|
if (unlikely(f2fs_readonly(src->i_sb)))
|
|
|
|
return -EROFS;
|
|
|
|
|
2016-08-04 20:13:02 +08:00
|
|
|
if (!S_ISREG(src->i_mode) || !S_ISREG(dst->i_mode))
|
|
|
|
return -EINVAL;
|
2016-07-09 06:16:47 +08:00
|
|
|
|
2018-12-12 17:50:11 +08:00
|
|
|
if (IS_ENCRYPTED(src) || IS_ENCRYPTED(dst))
|
2016-07-09 06:16:47 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2020-08-31 05:45:23 +08:00
|
|
|
if (pos_out < 0 || pos_in < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-09-13 11:35:42 +08:00
|
|
|
if (src == dst) {
|
|
|
|
if (pos_in == pos_out)
|
|
|
|
return 0;
|
|
|
|
if (pos_out > pos_in && pos_out < pos_in + len)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2016-07-09 06:16:47 +08:00
|
|
|
inode_lock(src);
|
2016-08-04 20:13:03 +08:00
|
|
|
if (src != dst) {
|
2017-11-03 10:21:05 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
if (!inode_trylock(dst))
|
|
|
|
goto out;
|
2016-08-04 20:13:03 +08:00
|
|
|
}
|
2016-07-09 06:16:47 +08:00
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
if (pos_in + len > src->i_size || pos_in + len < pos_in)
|
|
|
|
goto out_unlock;
|
|
|
|
if (len == 0)
|
|
|
|
olen = len = src->i_size - pos_in;
|
|
|
|
if (pos_in + len == src->i_size)
|
|
|
|
len = ALIGN(src->i_size, F2FS_BLKSIZE) - pos_in;
|
|
|
|
if (len == 0) {
|
|
|
|
ret = 0;
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
dst_osize = dst->i_size;
|
|
|
|
if (pos_out + olen > dst->i_size)
|
|
|
|
dst_max_i_size = pos_out + olen;
|
|
|
|
|
|
|
|
/* verify the end result is block aligned */
|
|
|
|
if (!IS_ALIGNED(pos_in, F2FS_BLKSIZE) ||
|
|
|
|
!IS_ALIGNED(pos_in + len, F2FS_BLKSIZE) ||
|
|
|
|
!IS_ALIGNED(pos_out, F2FS_BLKSIZE))
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
ret = f2fs_convert_inline_inode(src);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
ret = f2fs_convert_inline_inode(dst);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
/* write out all dirty pages from offset */
|
|
|
|
ret = filemap_write_and_wait_range(src->i_mapping,
|
|
|
|
pos_in, pos_in + len);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
ret = filemap_write_and_wait_range(dst->i_mapping,
|
|
|
|
pos_out, pos_out + len);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
f2fs_balance_fs(sbi, true);
|
2018-07-25 11:11:56 +08:00
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
|
2018-07-25 11:11:56 +08:00
|
|
|
if (src != dst) {
|
|
|
|
ret = -EBUSY;
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE]))
|
2018-07-25 11:11:56 +08:00
|
|
|
goto out_src;
|
|
|
|
}
|
|
|
|
|
2016-07-09 06:16:47 +08:00
|
|
|
f2fs_lock_op(sbi);
|
2016-09-10 11:19:37 +08:00
|
|
|
ret = __exchange_data_block(src, dst, pos_in >> F2FS_BLKSIZE_BITS,
|
|
|
|
pos_out >> F2FS_BLKSIZE_BITS,
|
|
|
|
len >> F2FS_BLKSIZE_BITS, false);
|
2016-07-09 06:16:47 +08:00
|
|
|
|
|
|
|
if (!ret) {
|
|
|
|
if (dst_max_i_size)
|
|
|
|
f2fs_i_size_write(dst, dst_max_i_size);
|
|
|
|
else if (dst_osize != dst->i_size)
|
|
|
|
f2fs_i_size_write(dst, dst_osize);
|
|
|
|
}
|
|
|
|
f2fs_unlock_op(sbi);
|
2018-07-25 11:11:56 +08:00
|
|
|
|
|
|
|
if (src != dst)
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
|
2018-07-25 11:11:56 +08:00
|
|
|
out_src:
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
|
2023-06-23 00:16:46 +08:00
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2023-07-06 03:01:08 +08:00
|
|
|
src->i_mtime = inode_set_ctime_current(src);
|
2023-06-23 00:16:46 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(src, false);
|
|
|
|
if (src != dst) {
|
2023-07-06 03:01:08 +08:00
|
|
|
dst->i_mtime = inode_set_ctime_current(dst);
|
2023-06-23 00:16:46 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(dst, false);
|
|
|
|
}
|
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
|
|
|
|
2018-07-25 11:11:56 +08:00
|
|
|
out_unlock:
|
|
|
|
if (src != dst)
|
2016-07-09 06:16:47 +08:00
|
|
|
inode_unlock(dst);
|
2016-08-04 20:13:03 +08:00
|
|
|
out:
|
2016-07-09 06:16:47 +08:00
|
|
|
inode_unlock(src);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
static int __f2fs_ioc_move_range(struct file *filp,
|
|
|
|
struct f2fs_move_range *range)
|
2016-07-09 06:16:47 +08:00
|
|
|
{
|
|
|
|
struct fd dst;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!(filp->f_mode & FMODE_READ) ||
|
|
|
|
!(filp->f_mode & FMODE_WRITE))
|
|
|
|
return -EBADF;
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
dst = fdget(range->dst_fd);
|
2016-07-09 06:16:47 +08:00
|
|
|
if (!dst.file)
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
if (!(dst.file->f_mode & FMODE_WRITE)) {
|
|
|
|
err = -EBADF;
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = mnt_want_write_file(filp);
|
|
|
|
if (err)
|
|
|
|
goto err_out;
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
err = f2fs_move_file_range(filp, range->pos_in, dst.file,
|
|
|
|
range->pos_out, range->len);
|
2016-07-09 06:16:47 +08:00
|
|
|
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
err_out:
|
|
|
|
fdput(dst);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
static int f2fs_ioc_move_range(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct f2fs_move_range range;
|
|
|
|
|
|
|
|
if (copy_from_user(&range, (struct f2fs_move_range __user *)arg,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
|
|
|
return __f2fs_ioc_move_range(filp, &range);
|
|
|
|
}
|
|
|
|
|
2017-04-14 06:17:00 +08:00
|
|
|
static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct sit_info *sm = SIT_I(sbi);
|
|
|
|
unsigned int start_segno = 0, end_segno = 0;
|
|
|
|
unsigned int dev_start_segno = 0, dev_end_segno = 0;
|
|
|
|
struct f2fs_flush_device range;
|
2022-05-07 02:40:33 +08:00
|
|
|
struct f2fs_gc_control gc_control = {
|
|
|
|
.init_gc_type = FG_GC,
|
|
|
|
.should_migrate_blocks = true,
|
2022-05-07 04:34:41 +08:00
|
|
|
.err_gc_skipped = true,
|
|
|
|
.nr_free_secs = 0 };
|
2017-04-14 06:17:00 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
2018-08-21 10:21:43 +08:00
|
|
|
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-04-14 06:17:00 +08:00
|
|
|
if (copy_from_user(&range, (struct f2fs_flush_device __user *)arg,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2019-03-16 08:13:06 +08:00
|
|
|
if (!f2fs_is_multi_device(sbi) || sbi->s_ndevs - 1 <= range.dev_num ||
|
2018-10-24 18:37:26 +08:00
|
|
|
__is_large_section(sbi)) {
|
2019-06-18 17:48:42 +08:00
|
|
|
f2fs_warn(sbi, "Can't flush %u in %d for segs_per_sec %u != 1",
|
|
|
|
range.dev_num, sbi->s_ndevs, sbi->segs_per_sec);
|
2017-04-14 06:17:00 +08:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (range.dev_num != 0)
|
|
|
|
dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk);
|
|
|
|
dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk);
|
|
|
|
|
|
|
|
start_segno = sm->last_victim[FLUSH_DEVICE];
|
|
|
|
if (start_segno < dev_start_segno || start_segno >= dev_end_segno)
|
|
|
|
start_segno = dev_start_segno;
|
|
|
|
end_segno = min(start_segno + range.segments, dev_end_segno);
|
|
|
|
|
|
|
|
while (start_segno < end_segno) {
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_write_trylock(&sbi->gc_lock)) {
|
2017-04-14 06:17:00 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
sm->last_victim[GC_CB] = end_segno + 1;
|
|
|
|
sm->last_victim[GC_GREEDY] = end_segno + 1;
|
|
|
|
sm->last_victim[ALLOC_NEXT] = end_segno + 1;
|
2022-05-07 02:40:33 +08:00
|
|
|
|
|
|
|
gc_control.victim_segno = start_segno;
|
2023-08-08 08:59:48 +08:00
|
|
|
stat_inc_gc_call_count(sbi, FOREGROUND);
|
2022-05-07 02:40:33 +08:00
|
|
|
ret = f2fs_gc(sbi, &gc_control);
|
2017-04-14 06:17:00 +08:00
|
|
|
if (ret == -EAGAIN)
|
|
|
|
ret = 0;
|
|
|
|
else if (ret < 0)
|
|
|
|
break;
|
|
|
|
start_segno++;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-07-22 03:58:59 +08:00
|
|
|
static int f2fs_ioc_get_features(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
u32 sb_feature = le32_to_cpu(F2FS_I_SB(inode)->raw_super->feature);
|
|
|
|
|
|
|
|
/* Must validate to set it with SQLite behavior in Android. */
|
|
|
|
sb_feature |= F2FS_FEATURE_ATOMIC_WRITE;
|
|
|
|
|
|
|
|
return put_user(sb_feature, (u32 __user *)arg);
|
|
|
|
}
|
2017-04-14 06:17:00 +08:00
|
|
|
|
2017-07-29 00:32:52 +08:00
|
|
|
#ifdef CONFIG_QUOTA
|
2018-09-25 15:36:02 +08:00
|
|
|
int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
|
|
|
|
{
|
|
|
|
struct dquot *transfer_to[MAXQUOTAS] = {};
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct super_block *sb = sbi->sb;
|
2023-02-21 22:45:50 +08:00
|
|
|
int err;
|
2018-09-25 15:36:02 +08:00
|
|
|
|
|
|
|
transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid));
|
2023-02-21 22:45:50 +08:00
|
|
|
if (IS_ERR(transfer_to[PRJQUOTA]))
|
|
|
|
return PTR_ERR(transfer_to[PRJQUOTA]);
|
|
|
|
|
|
|
|
err = __dquot_transfer(inode, transfer_to);
|
|
|
|
if (err)
|
|
|
|
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
|
|
|
|
dqput(transfer_to[PRJQUOTA]);
|
2018-09-25 15:36:02 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
|
2017-07-29 00:32:52 +08:00
|
|
|
{
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
2022-03-09 19:09:35 +08:00
|
|
|
struct f2fs_inode *ri = NULL;
|
2017-07-29 00:32:52 +08:00
|
|
|
kprojid_t kprojid;
|
|
|
|
int err;
|
|
|
|
|
2018-10-24 18:34:26 +08:00
|
|
|
if (!f2fs_sb_has_project_quota(sbi)) {
|
2017-07-29 00:32:52 +08:00
|
|
|
if (projid != F2FS_DEF_PROJID)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!f2fs_has_extra_attr(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
kprojid = make_kprojid(&init_user_ns, (projid_t)projid);
|
|
|
|
|
2022-05-26 10:21:06 +08:00
|
|
|
if (projid_eq(kprojid, fi->i_projid))
|
2017-07-29 00:32:52 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err = -EPERM;
|
|
|
|
/* Is it quota file? Do not allow user to mess with it */
|
|
|
|
if (IS_NOQUOTA(inode))
|
2018-09-11 07:54:21 +08:00
|
|
|
return err;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2022-03-09 19:09:35 +08:00
|
|
|
if (!F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_projid))
|
|
|
|
return -EOVERFLOW;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2021-10-28 21:03:05 +08:00
|
|
|
err = f2fs_dquot_initialize(inode);
|
2018-04-21 17:53:52 +08:00
|
|
|
if (err)
|
2018-09-11 07:54:21 +08:00
|
|
|
return err;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2018-09-25 15:36:02 +08:00
|
|
|
f2fs_lock_op(sbi);
|
|
|
|
err = f2fs_transfer_project_quota(inode, kprojid);
|
|
|
|
if (err)
|
|
|
|
goto out_unlock;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2022-05-26 10:21:06 +08:00
|
|
|
fi->i_projid = kprojid;
|
2023-07-06 03:01:08 +08:00
|
|
|
inode_set_ctime_current(inode);
|
2017-07-29 00:32:52 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
2018-09-25 15:36:02 +08:00
|
|
|
out_unlock:
|
|
|
|
f2fs_unlock_op(sbi);
|
2017-07-29 00:32:52 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
#else
|
2018-09-25 15:36:02 +08:00
|
|
|
int f2fs_transfer_project_quota(struct inode *inode, kprojid_t kprojid)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
|
2017-07-29 00:32:52 +08:00
|
|
|
{
|
|
|
|
if (projid != F2FS_DEF_PROJID)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
|
2017-07-29 00:32:52 +08:00
|
|
|
{
|
2021-04-07 20:36:43 +08:00
|
|
|
struct inode *inode = d_inode(dentry);
|
2017-07-29 00:32:52 +08:00
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
2021-04-07 20:36:43 +08:00
|
|
|
u32 fsflags = f2fs_iflags_to_fsflags(fi->i_flags);
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
if (IS_ENCRYPTED(inode))
|
|
|
|
fsflags |= FS_ENCRYPT_FL;
|
|
|
|
if (IS_VERITY(inode))
|
|
|
|
fsflags |= FS_VERITY_FL;
|
|
|
|
if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
|
|
|
|
fsflags |= FS_INLINE_DATA_FL;
|
|
|
|
if (is_inode_flag_set(inode, FI_PIN_FILE))
|
|
|
|
fsflags |= FS_NOCOW_FL;
|
|
|
|
|
|
|
|
fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL);
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2018-10-24 18:34:26 +08:00
|
|
|
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
|
2019-07-02 04:26:29 +08:00
|
|
|
fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2018-09-11 07:54:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-01-13 19:49:21 +08:00
|
|
|
int f2fs_fileattr_set(struct mnt_idmap *idmap,
|
2021-04-07 20:36:43 +08:00
|
|
|
struct dentry *dentry, struct fileattr *fa)
|
2017-07-29 00:32:52 +08:00
|
|
|
{
|
2021-04-07 20:36:43 +08:00
|
|
|
struct inode *inode = d_inode(dentry);
|
|
|
|
u32 fsflags = fa->flags, mask = F2FS_SETTABLE_FS_FL;
|
2019-06-05 13:59:04 +08:00
|
|
|
u32 iflags;
|
2017-07-29 00:32:52 +08:00
|
|
|
int err;
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
|
|
|
return -EIO;
|
|
|
|
if (!f2fs_is_checkpoint_ready(F2FS_I_SB(inode)))
|
|
|
|
return -ENOSPC;
|
|
|
|
if (fsflags & ~F2FS_GETTABLE_FS_FL)
|
2017-07-29 00:32:52 +08:00
|
|
|
return -EOPNOTSUPP;
|
2021-04-07 20:36:43 +08:00
|
|
|
fsflags &= F2FS_SETTABLE_FS_FL;
|
|
|
|
if (!fa->flags_valid)
|
|
|
|
mask &= FS_COMMON_FL;
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
iflags = f2fs_fsflags_to_iflags(fsflags);
|
2019-06-05 13:59:04 +08:00
|
|
|
if (f2fs_mask_flags(inode->i_mode, iflags) != iflags)
|
2017-07-29 00:32:52 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2021-04-07 20:36:43 +08:00
|
|
|
err = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(mask));
|
|
|
|
if (!err)
|
|
|
|
err = f2fs_ioc_setproject(inode, fa->fsx_projid);
|
2017-07-29 00:32:52 +08:00
|
|
|
|
2018-09-11 07:54:21 +08:00
|
|
|
return err;
|
2017-07-29 00:32:52 +08:00
|
|
|
}
|
2017-04-14 06:17:00 +08:00
|
|
|
|
2017-12-08 08:25:39 +08:00
|
|
|
int f2fs_pin_file_control(struct inode *inode, bool inc)
|
|
|
|
{
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
|
|
|
|
/* Use i_gc_failures for normal file as a risk signal. */
|
|
|
|
if (inc)
|
f2fs: avoid stucking GC due to atomic write
f2fs doesn't allow abuse on atomic write class interface, so except
limiting in-mem pages' total memory usage capacity, we need to limit
atomic-write usage as well when filesystem is seriously fragmented,
otherwise we may run into infinite loop during foreground GC because
target blocks in victim segment are belong to atomic opened file for
long time.
Now, we will detect failure due to atomic write in foreground GC, if
the count exceeds threshold, we will drop all atomic written data in
cache, by this, I expect it can keep our system running safely to
prevent Dos attack.
In addition, his patch adds to show GC skip information in debugfs,
now it just shows count of skipped caused by atomic write.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-07 20:28:54 +08:00
|
|
|
f2fs_i_gc_failures_write(inode,
|
|
|
|
fi->i_gc_failures[GC_FAILURE_PIN] + 1);
|
2017-12-08 08:25:39 +08:00
|
|
|
|
f2fs: avoid stucking GC due to atomic write
f2fs doesn't allow abuse on atomic write class interface, so except
limiting in-mem pages' total memory usage capacity, we need to limit
atomic-write usage as well when filesystem is seriously fragmented,
otherwise we may run into infinite loop during foreground GC because
target blocks in victim segment are belong to atomic opened file for
long time.
Now, we will detect failure due to atomic write in foreground GC, if
the count exceeds threshold, we will drop all atomic written data in
cache, by this, I expect it can keep our system running safely to
prevent Dos attack.
In addition, his patch adds to show GC skip information in debugfs,
now it just shows count of skipped caused by atomic write.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-07 20:28:54 +08:00
|
|
|
if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
|
2019-06-18 17:48:42 +08:00
|
|
|
f2fs_warn(sbi, "%s: Enable GC = ino %lx after %x GC trials",
|
|
|
|
__func__, inode->i_ino,
|
|
|
|
fi->i_gc_failures[GC_FAILURE_PIN]);
|
2017-12-08 08:25:39 +08:00
|
|
|
clear_inode_flag(inode, FI_PIN_FILE);
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
__u32 pin;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (get_user(pin, (__u32 __user *)arg))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (!S_ISREG(inode->i_mode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (f2fs_readonly(F2FS_I_SB(inode)->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
inode_lock(inode);
|
|
|
|
|
|
|
|
if (!pin) {
|
|
|
|
clear_inode_flag(inode, FI_PIN_FILE);
|
2018-07-28 18:37:58 +08:00
|
|
|
f2fs_i_gc_failures_write(inode, 0);
|
2017-12-08 08:25:39 +08:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2021-12-10 02:25:43 +08:00
|
|
|
if (f2fs_should_update_outplace(inode, NULL)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-12-08 08:25:39 +08:00
|
|
|
if (f2fs_pin_file_control(inode, false)) {
|
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
2017-12-08 08:25:39 +08:00
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2020-09-08 10:44:11 +08:00
|
|
|
if (!f2fs_disable_compressed_file(inode)) {
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-12-08 08:25:39 +08:00
|
|
|
set_inode_flag(inode, FI_PIN_FILE);
|
f2fs: avoid stucking GC due to atomic write
f2fs doesn't allow abuse on atomic write class interface, so except
limiting in-mem pages' total memory usage capacity, we need to limit
atomic-write usage as well when filesystem is seriously fragmented,
otherwise we may run into infinite loop during foreground GC because
target blocks in victim segment are belong to atomic opened file for
long time.
Now, we will detect failure due to atomic write in foreground GC, if
the count exceeds threshold, we will drop all atomic written data in
cache, by this, I expect it can keep our system running safely to
prevent Dos attack.
In addition, his patch adds to show GC skip information in debugfs,
now it just shows count of skipped caused by atomic write.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-07 20:28:54 +08:00
|
|
|
ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
2017-12-08 08:25:39 +08:00
|
|
|
done:
|
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
|
|
|
out:
|
|
|
|
inode_unlock(inode);
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
__u32 pin = 0;
|
|
|
|
|
|
|
|
if (is_inode_flag_set(inode, FI_PIN_FILE))
|
f2fs: avoid stucking GC due to atomic write
f2fs doesn't allow abuse on atomic write class interface, so except
limiting in-mem pages' total memory usage capacity, we need to limit
atomic-write usage as well when filesystem is seriously fragmented,
otherwise we may run into infinite loop during foreground GC because
target blocks in victim segment are belong to atomic opened file for
long time.
Now, we will detect failure due to atomic write in foreground GC, if
the count exceeds threshold, we will drop all atomic written data in
cache, by this, I expect it can keep our system running safely to
prevent Dos attack.
In addition, his patch adds to show GC skip information in debugfs,
now it just shows count of skipped caused by atomic write.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2018-05-07 20:28:54 +08:00
|
|
|
pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
2017-12-08 08:25:39 +08:00
|
|
|
return put_user(pin, (u32 __user *)arg);
|
|
|
|
}
|
|
|
|
|
2018-01-11 14:42:30 +08:00
|
|
|
int f2fs_precache_extents(struct inode *inode)
|
|
|
|
{
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
struct f2fs_map_blocks map;
|
|
|
|
pgoff_t m_next_extent;
|
|
|
|
loff_t end;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (is_inode_flag_set(inode, FI_NO_EXTENT))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
map.m_lblk = 0;
|
2023-10-07 15:45:52 +08:00
|
|
|
map.m_pblk = 0;
|
2018-01-11 14:42:30 +08:00
|
|
|
map.m_next_pgofs = NULL;
|
|
|
|
map.m_next_extent = &m_next_extent;
|
|
|
|
map.m_seg_type = NO_CHECK_TYPE;
|
2018-11-20 04:29:35 +08:00
|
|
|
map.m_may_create = false;
|
2023-10-10 09:34:59 +08:00
|
|
|
end = F2FS_BLK_ALIGN(i_size_read(inode));
|
2018-01-11 14:42:30 +08:00
|
|
|
|
|
|
|
while (map.m_lblk < end) {
|
|
|
|
map.m_len = end - map.m_lblk;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&fi->i_gc_rwsem[WRITE]);
|
2022-11-28 17:15:20 +08:00
|
|
|
err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
f2fs: stop iterating f2fs_map_block if hole exists
Let's avoid unnecessary f2fs_map_block calls to load extents.
# f2fs_io fadvise willneed 0 4096 /data/local/tmp/test
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 386, start blkaddr = 0x34ac00, len = 0x1400, flags = 2,
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 5506, start blkaddr = 0x34c200, len = 0x1000, flags = 2,
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 9602, start blkaddr = 0x34d600, len = 0x1200, flags = 2,
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 14210, start blkaddr = 0x34ec00, len = 0x400, flags = 2,
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 15235, start blkaddr = 0x34f401, len = 0xbff, flags = 2,
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 18306, start blkaddr = 0x350200, len = 0x1200, flags = 2
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 22915, start blkaddr = 0x351601, len = 0xa7d, flags = 2
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 25600, start blkaddr = 0x351601, len = 0x0, flags = 0
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 25601, start blkaddr = 0x351601, len = 0x0, flags = 0
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 25602, start blkaddr = 0x351601, len = 0x0, flags = 0
...
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 1037188, start blkaddr = 0x351601, len = 0x0, flags = 0
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 1038206, start blkaddr = 0x351601, len = 0x0, flags = 0
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 1039224, start blkaddr = 0x351601, len = 0x0, flags = 0
f2fs_map_blocks: dev = (254,51), ino = 85845, file offset = 2075548, start blkaddr = 0x351601, len = 0x0, flags = 0
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2023-10-04 06:51:49 +08:00
|
|
|
if (err || !map.m_len)
|
2018-01-11 14:42:30 +08:00
|
|
|
return err;
|
|
|
|
|
|
|
|
map.m_lblk = m_next_extent;
|
|
|
|
}
|
|
|
|
|
2021-05-16 02:09:41 +08:00
|
|
|
return 0;
|
2018-01-11 14:42:30 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 14:17:01 +08:00
|
|
|
static int f2fs_ioc_precache_extents(struct file *filp)
|
2018-01-11 14:42:30 +08:00
|
|
|
{
|
|
|
|
return f2fs_precache_extents(file_inode(filp));
|
|
|
|
}
|
|
|
|
|
2019-06-05 11:33:25 +08:00
|
|
|
static int f2fs_ioc_resize_fs(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(filp));
|
|
|
|
__u64 block_count;
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
|
|
|
if (copy_from_user(&block_count, (void __user *)arg,
|
|
|
|
sizeof(block_count)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
2023-05-23 14:17:25 +08:00
|
|
|
return f2fs_resize_fs(filp, block_count);
|
2019-06-05 11:33:25 +08:00
|
|
|
}
|
|
|
|
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
static int f2fs_ioc_enable_verity(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
|
|
|
|
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
|
|
|
|
|
|
|
if (!f2fs_sb_has_verity(F2FS_I_SB(inode))) {
|
|
|
|
f2fs_warn(F2FS_I_SB(inode),
|
2021-05-27 04:05:36 +08:00
|
|
|
"Can't enable fs-verity on inode %lu: the verity feature is not enabled on this filesystem",
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
inode->i_ino);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fsverity_ioctl_enable(filp, (const void __user *)arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_measure_verity(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fsverity_ioctl_measure(filp, (void __user *)arg);
|
|
|
|
}
|
|
|
|
|
fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl
Add an ioctl FS_IOC_READ_VERITY_METADATA which will allow reading verity
metadata from a file that has fs-verity enabled, including:
- The Merkle tree
- The fsverity_descriptor (not including the signature if present)
- The built-in signature, if present
This ioctl has similar semantics to pread(). It is passed the type of
metadata to read (one of the above three), and a buffer, offset, and
size. It returns the number of bytes read or an error.
Separate patches will add support for each of the above metadata types.
This patch just adds the ioctl itself.
This ioctl doesn't make any assumption about where the metadata is
stored on-disk. It does assume the metadata is in a stable format, but
that's basically already the case:
- The Merkle tree and fsverity_descriptor are defined by how fs-verity
file digests are computed; see the "File digest computation" section
of Documentation/filesystems/fsverity.rst. Technically, the way in
which the levels of the tree are ordered relative to each other wasn't
previously specified, but it's logical to put the root level first.
- The built-in signature is the value passed to FS_IOC_ENABLE_VERITY.
This ioctl is useful because it allows writing a server program that
takes a verity file and serves it to a client program, such that the
client can do its own fs-verity compatible verification of the file.
This only makes sense if the client doesn't trust the server and if the
server needs to provide the storage for the client.
More concretely, there is interest in using this ability in Android to
export APK files (which are protected by fs-verity) to "protected VMs".
This would use Protected KVM (https://lwn.net/Articles/836693), which
provides an isolated execution environment without having to trust the
traditional "host". A "guest" VM can boot from a signed image and
perform specific tasks in a minimum trusted environment using files that
have fs-verity enabled on the host, without trusting the host or
requiring that the guest has its own trusted storage.
Technically, it would be possible to duplicate the metadata and store it
in separate files for serving. However, that would be less efficient
and would require extra care in userspace to maintain file consistency.
In addition to the above, the ability to read the built-in signatures is
useful because it allows a system that is using the in-kernel signature
verification to migrate to userspace signature verification.
Link: https://lore.kernel.org/r/20210115181819.34732-4-ebiggers@kernel.org
Reviewed-by: Victor Hsieh <victorhsieh@google.com>
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-01-16 02:18:16 +08:00
|
|
|
static int f2fs_ioc_read_verity_metadata(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_verity(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
return fsverity_ioctl_read_metadata(filp, (const void __user *)arg);
|
|
|
|
}
|
|
|
|
|
2020-07-15 06:18:12 +08:00
|
|
|
static int f2fs_ioc_getfslabel(struct file *filp, unsigned long arg)
|
2019-07-17 17:06:11 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
char *vbuf;
|
|
|
|
int count;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
vbuf = f2fs_kzalloc(sbi, MAX_VOLUME_NAME, GFP_KERNEL);
|
|
|
|
if (!vbuf)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_read(&sbi->sb_lock);
|
2019-07-17 17:06:11 +08:00
|
|
|
count = utf16s_to_utf8s(sbi->raw_super->volume_name,
|
|
|
|
ARRAY_SIZE(sbi->raw_super->volume_name),
|
|
|
|
UTF16_LITTLE_ENDIAN, vbuf, MAX_VOLUME_NAME);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_read(&sbi->sb_lock);
|
2019-07-17 17:06:11 +08:00
|
|
|
|
|
|
|
if (copy_to_user((char __user *)arg, vbuf,
|
|
|
|
min(FSLABEL_MAX, count)))
|
|
|
|
err = -EFAULT;
|
|
|
|
|
2020-09-14 16:47:00 +08:00
|
|
|
kfree(vbuf);
|
2019-07-17 17:06:11 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2020-07-15 06:18:12 +08:00
|
|
|
static int f2fs_ioc_setfslabel(struct file *filp, unsigned long arg)
|
2019-07-17 17:06:11 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
char *vbuf;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
vbuf = strndup_user((const char __user *)arg, FSLABEL_MAX);
|
|
|
|
if (IS_ERR(vbuf))
|
|
|
|
return PTR_ERR(vbuf);
|
|
|
|
|
|
|
|
err = mnt_want_write_file(filp);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&sbi->sb_lock);
|
2019-07-17 17:06:11 +08:00
|
|
|
|
|
|
|
memset(sbi->raw_super->volume_name, 0,
|
|
|
|
sizeof(sbi->raw_super->volume_name));
|
|
|
|
utf8s_to_utf16s(vbuf, strlen(vbuf), UTF16_LITTLE_ENDIAN,
|
|
|
|
sbi->raw_super->volume_name,
|
|
|
|
ARRAY_SIZE(sbi->raw_super->volume_name));
|
|
|
|
|
|
|
|
err = f2fs_commit_super(sbi, false);
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&sbi->sb_lock);
|
2019-07-17 17:06:11 +08:00
|
|
|
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
out:
|
|
|
|
kfree(vbuf);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2023-06-12 11:01:19 +08:00
|
|
|
static int f2fs_get_compress_blocks(struct inode *inode, __u64 *blocks)
|
2020-02-21 18:09:21 +08:00
|
|
|
{
|
|
|
|
if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-06-12 11:01:19 +08:00
|
|
|
*blocks = atomic_read(&F2FS_I(inode)->i_compr_blocks);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_ioc_get_compress_blocks(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
__u64 blocks;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = f2fs_get_compress_blocks(inode, &blocks);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2020-02-21 18:09:21 +08:00
|
|
|
return put_user(blocks, (u64 __user *)arg);
|
|
|
|
}
|
|
|
|
|
2020-03-06 15:36:09 +08:00
|
|
|
static int release_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
|
|
|
unsigned int released_blocks = 0;
|
|
|
|
int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
|
|
|
|
block_t blkaddr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
blkaddr = data_blkaddr(dn->inode, dn->node_page,
|
|
|
|
dn->ofs_in_node + i);
|
|
|
|
|
|
|
|
if (!__is_valid_data_blkaddr(blkaddr))
|
|
|
|
continue;
|
|
|
|
if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
|
2022-09-28 23:38:54 +08:00
|
|
|
DATA_GENERIC_ENHANCE))) {
|
|
|
|
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
2020-03-06 15:36:09 +08:00
|
|
|
return -EFSCORRUPTED;
|
2022-09-28 23:38:54 +08:00
|
|
|
}
|
2020-03-06 15:36:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
int compr_blocks = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
|
|
|
|
blkaddr = f2fs_data_blkaddr(dn);
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
if (blkaddr == COMPRESS_ADDR)
|
|
|
|
continue;
|
|
|
|
dn->ofs_in_node += cluster_size;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__is_valid_data_blkaddr(blkaddr))
|
|
|
|
compr_blocks++;
|
|
|
|
|
|
|
|
if (blkaddr != NEW_ADDR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dn->data_blkaddr = NULL_ADDR;
|
|
|
|
f2fs_set_data_blkaddr(dn);
|
|
|
|
}
|
|
|
|
|
|
|
|
f2fs_i_compr_blocks_update(dn->inode, compr_blocks, false);
|
|
|
|
dec_valid_block_count(sbi, dn->inode,
|
|
|
|
cluster_size - compr_blocks);
|
|
|
|
|
|
|
|
released_blocks += cluster_size - compr_blocks;
|
|
|
|
next:
|
|
|
|
count -= cluster_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return released_blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
pgoff_t page_idx = 0, last_idx;
|
|
|
|
unsigned int released_blocks = 0;
|
|
|
|
int ret;
|
|
|
|
int writecount;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
if (!f2fs_sb_has_compression(sbi))
|
2020-03-06 15:36:09 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2020-03-06 15:36:09 +08:00
|
|
|
|
|
|
|
inode_lock(inode);
|
|
|
|
|
|
|
|
writecount = atomic_read(&inode->i_writecount);
|
2020-10-12 12:59:47 +08:00
|
|
|
if ((filp->f_mode & FMODE_WRITE && writecount != 1) ||
|
|
|
|
(!(filp->f_mode & FMODE_WRITE) && writecount)) {
|
2020-03-06 15:36:09 +08:00
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-05-26 02:39:35 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
2020-03-06 15:36:09 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2023-06-27 20:21:53 +08:00
|
|
|
if (!atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
|
|
|
|
ret = -EPERM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2021-05-26 02:39:35 +08:00
|
|
|
set_inode_flag(inode, FI_COMPRESS_RELEASED);
|
2023-07-06 03:01:08 +08:00
|
|
|
inode_set_ctime_current(inode);
|
2020-03-06 15:36:09 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2020-03-06 15:36:09 +08:00
|
|
|
|
|
|
|
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
|
|
|
|
|
|
|
while (page_idx < last_idx) {
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
pgoff_t end_offset, count;
|
|
|
|
|
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
|
|
|
ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
|
|
|
|
if (ret) {
|
|
|
|
if (ret == -ENOENT) {
|
|
|
|
page_idx = f2fs_get_next_page_offset(&dn,
|
|
|
|
page_idx);
|
|
|
|
ret = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
|
|
|
count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
|
2020-04-08 19:55:17 +08:00
|
|
|
count = round_up(count, F2FS_I(inode)->i_cluster_size);
|
2020-03-06 15:36:09 +08:00
|
|
|
|
|
|
|
ret = release_compress_blocks(&dn, count);
|
|
|
|
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
page_idx += count;
|
|
|
|
released_blocks += ret;
|
|
|
|
}
|
|
|
|
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2020-03-06 15:36:09 +08:00
|
|
|
out:
|
|
|
|
inode_unlock(inode);
|
|
|
|
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
|
|
|
|
if (ret >= 0) {
|
|
|
|
ret = put_user(released_blocks, (u64 __user *)arg);
|
2020-09-08 10:44:10 +08:00
|
|
|
} else if (released_blocks &&
|
|
|
|
atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
|
2020-03-06 15:36:09 +08:00
|
|
|
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
|
|
|
f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
|
2020-09-08 10:44:10 +08:00
|
|
|
"iblocks=%llu, released=%u, compr_blocks=%u, "
|
2020-03-06 15:36:09 +08:00
|
|
|
"run fsck to fix.",
|
|
|
|
__func__, inode->i_ino, inode->i_blocks,
|
|
|
|
released_blocks,
|
2020-09-08 10:44:10 +08:00
|
|
|
atomic_read(&F2FS_I(inode)->i_compr_blocks));
|
2020-03-06 15:36:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-06 14:35:33 +08:00
|
|
|
static int reserve_compress_blocks(struct dnode_of_data *dn, pgoff_t count)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
|
|
|
unsigned int reserved_blocks = 0;
|
|
|
|
int cluster_size = F2FS_I(dn->inode)->i_cluster_size;
|
|
|
|
block_t blkaddr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
blkaddr = data_blkaddr(dn->inode, dn->node_page,
|
|
|
|
dn->ofs_in_node + i);
|
|
|
|
|
|
|
|
if (!__is_valid_data_blkaddr(blkaddr))
|
|
|
|
continue;
|
|
|
|
if (unlikely(!f2fs_is_valid_blkaddr(sbi, blkaddr,
|
2022-09-28 23:38:54 +08:00
|
|
|
DATA_GENERIC_ENHANCE))) {
|
|
|
|
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
2020-03-06 14:35:33 +08:00
|
|
|
return -EFSCORRUPTED;
|
2022-09-28 23:38:54 +08:00
|
|
|
}
|
2020-03-06 14:35:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
int compr_blocks = 0;
|
|
|
|
blkcnt_t reserved;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
for (i = 0; i < cluster_size; i++, dn->ofs_in_node++) {
|
|
|
|
blkaddr = f2fs_data_blkaddr(dn);
|
|
|
|
|
|
|
|
if (i == 0) {
|
|
|
|
if (blkaddr == COMPRESS_ADDR)
|
|
|
|
continue;
|
|
|
|
dn->ofs_in_node += cluster_size;
|
|
|
|
goto next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__is_valid_data_blkaddr(blkaddr)) {
|
|
|
|
compr_blocks++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
dn->data_blkaddr = NEW_ADDR;
|
|
|
|
f2fs_set_data_blkaddr(dn);
|
|
|
|
}
|
|
|
|
|
|
|
|
reserved = cluster_size - compr_blocks;
|
|
|
|
ret = inc_valid_block_count(sbi, dn->inode, &reserved);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (reserved != cluster_size - compr_blocks)
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
f2fs_i_compr_blocks_update(dn->inode, compr_blocks, true);
|
|
|
|
|
|
|
|
reserved_blocks += reserved;
|
|
|
|
next:
|
|
|
|
count -= cluster_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return reserved_blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
pgoff_t page_idx = 0, last_idx;
|
|
|
|
unsigned int reserved_blocks = 0;
|
|
|
|
int ret;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
if (!f2fs_sb_has_compression(sbi))
|
2020-03-06 14:35:33 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (f2fs_readonly(sbi->sb))
|
|
|
|
return -EROFS;
|
|
|
|
|
|
|
|
ret = mnt_want_write_file(filp);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2020-09-08 10:44:10 +08:00
|
|
|
if (atomic_read(&F2FS_I(inode)->i_compr_blocks))
|
2020-03-06 14:35:33 +08:00
|
|
|
goto out;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2020-03-06 14:35:33 +08:00
|
|
|
|
|
|
|
inode_lock(inode);
|
|
|
|
|
2021-05-26 02:39:35 +08:00
|
|
|
if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
2020-03-06 14:35:33 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto unlock_inode;
|
|
|
|
}
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2020-03-06 14:35:33 +08:00
|
|
|
|
|
|
|
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
|
|
|
|
|
|
|
while (page_idx < last_idx) {
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
pgoff_t end_offset, count;
|
|
|
|
|
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
|
|
|
ret = f2fs_get_dnode_of_data(&dn, page_idx, LOOKUP_NODE);
|
|
|
|
if (ret) {
|
|
|
|
if (ret == -ENOENT) {
|
|
|
|
page_idx = f2fs_get_next_page_offset(&dn,
|
|
|
|
page_idx);
|
|
|
|
ret = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
|
|
|
count = min(end_offset - dn.ofs_in_node, last_idx - page_idx);
|
2020-04-08 19:55:17 +08:00
|
|
|
count = round_up(count, F2FS_I(inode)->i_cluster_size);
|
2020-03-06 14:35:33 +08:00
|
|
|
|
|
|
|
ret = reserve_compress_blocks(&dn, count);
|
|
|
|
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
page_idx += count;
|
|
|
|
reserved_blocks += ret;
|
|
|
|
}
|
|
|
|
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2020-03-06 14:35:33 +08:00
|
|
|
|
|
|
|
if (ret >= 0) {
|
2021-05-26 02:39:35 +08:00
|
|
|
clear_inode_flag(inode, FI_COMPRESS_RELEASED);
|
2023-07-06 03:01:08 +08:00
|
|
|
inode_set_ctime_current(inode);
|
2020-03-06 14:35:33 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
|
|
|
}
|
|
|
|
unlock_inode:
|
|
|
|
inode_unlock(inode);
|
|
|
|
out:
|
|
|
|
mnt_drop_write_file(filp);
|
|
|
|
|
|
|
|
if (ret >= 0) {
|
|
|
|
ret = put_user(reserved_blocks, (u64 __user *)arg);
|
2020-09-08 10:44:10 +08:00
|
|
|
} else if (reserved_blocks &&
|
|
|
|
atomic_read(&F2FS_I(inode)->i_compr_blocks)) {
|
2020-03-06 14:35:33 +08:00
|
|
|
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
|
|
|
f2fs_warn(sbi, "%s: partial blocks were released i_ino=%lx "
|
2020-09-08 10:44:10 +08:00
|
|
|
"iblocks=%llu, reserved=%u, compr_blocks=%u, "
|
2020-03-06 14:35:33 +08:00
|
|
|
"run fsck to fix.",
|
|
|
|
__func__, inode->i_ino, inode->i_blocks,
|
|
|
|
reserved_blocks,
|
2020-09-08 10:44:10 +08:00
|
|
|
atomic_read(&F2FS_I(inode)->i_compr_blocks));
|
2020-03-06 14:35:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-07-21 11:21:11 +08:00
|
|
|
static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode,
|
|
|
|
pgoff_t off, block_t block, block_t len, u32 flags)
|
|
|
|
{
|
|
|
|
sector_t sector = SECTOR_FROM_BLOCK(block);
|
|
|
|
sector_t nr_sects = SECTOR_FROM_BLOCK(len);
|
|
|
|
int ret = 0;
|
|
|
|
|
2022-04-15 12:52:57 +08:00
|
|
|
if (flags & F2FS_TRIM_FILE_DISCARD) {
|
|
|
|
if (bdev_max_secure_erase_sectors(bdev))
|
|
|
|
ret = blkdev_issue_secure_erase(bdev, sector, nr_sects,
|
|
|
|
GFP_NOFS);
|
|
|
|
else
|
|
|
|
ret = blkdev_issue_discard(bdev, sector, nr_sects,
|
|
|
|
GFP_NOFS);
|
|
|
|
}
|
2020-07-21 11:21:11 +08:00
|
|
|
|
|
|
|
if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) {
|
|
|
|
if (IS_ENCRYPTED(inode))
|
|
|
|
ret = fscrypt_zeroout_range(inode, off, block, len);
|
|
|
|
else
|
|
|
|
ret = blkdev_issue_zeroout(bdev, sector, nr_sects,
|
|
|
|
GFP_NOFS, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_sec_trim_file(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct address_space *mapping = inode->i_mapping;
|
|
|
|
struct block_device *prev_bdev = NULL;
|
|
|
|
struct f2fs_sectrim_range range;
|
|
|
|
pgoff_t index, pg_end, prev_index = 0;
|
|
|
|
block_t prev_block = 0, len = 0;
|
|
|
|
loff_t end_addr;
|
|
|
|
bool to_end = false;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!(filp->f_mode & FMODE_WRITE))
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
if (copy_from_user(&range, (struct f2fs_sectrim_range __user *)arg,
|
|
|
|
sizeof(range)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (range.flags == 0 || (range.flags & ~F2FS_TRIM_FILE_MASK) ||
|
|
|
|
!S_ISREG(inode->i_mode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (((range.flags & F2FS_TRIM_FILE_DISCARD) &&
|
|
|
|
!f2fs_hw_support_discard(sbi)) ||
|
|
|
|
((range.flags & F2FS_TRIM_FILE_ZEROOUT) &&
|
|
|
|
IS_ENCRYPTED(inode) && f2fs_is_multi_device(sbi)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
file_start_write(filp);
|
|
|
|
inode_lock(inode);
|
|
|
|
|
|
|
|
if (f2fs_is_atomic_file(inode) || f2fs_compressed_file(inode) ||
|
|
|
|
range.start >= inode->i_size) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (range.len == 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (inode->i_size - range.start > range.len) {
|
|
|
|
end_addr = range.start + range.len;
|
|
|
|
} else {
|
|
|
|
end_addr = range.len == (u64)-1 ?
|
|
|
|
sbi->sb->s_maxbytes : inode->i_size;
|
|
|
|
to_end = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IS_ALIGNED(range.start, F2FS_BLKSIZE) ||
|
|
|
|
(!to_end && !IS_ALIGNED(end_addr, F2FS_BLKSIZE))) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
index = F2FS_BYTES_TO_BLK(range.start);
|
|
|
|
pg_end = DIV_ROUND_UP(end_addr, F2FS_BLKSIZE);
|
|
|
|
|
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_lock(mapping);
|
2020-07-21 11:21:11 +08:00
|
|
|
|
|
|
|
ret = filemap_write_and_wait_range(mapping, range.start,
|
|
|
|
to_end ? LLONG_MAX : end_addr - 1);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
truncate_inode_pages_range(mapping, range.start,
|
|
|
|
to_end ? -1 : end_addr - 1);
|
|
|
|
|
|
|
|
while (index < pg_end) {
|
|
|
|
struct dnode_of_data dn;
|
|
|
|
pgoff_t end_offset, count;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
|
|
|
ret = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
|
|
|
if (ret) {
|
|
|
|
if (ret == -ENOENT) {
|
|
|
|
index = f2fs_get_next_page_offset(&dn, index);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
end_offset = ADDRS_PER_PAGE(dn.node_page, inode);
|
|
|
|
count = min(end_offset - dn.ofs_in_node, pg_end - index);
|
|
|
|
for (i = 0; i < count; i++, index++, dn.ofs_in_node++) {
|
|
|
|
struct block_device *cur_bdev;
|
|
|
|
block_t blkaddr = f2fs_data_blkaddr(&dn);
|
|
|
|
|
|
|
|
if (!__is_valid_data_blkaddr(blkaddr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
|
|
|
|
DATA_GENERIC_ENHANCE)) {
|
|
|
|
ret = -EFSCORRUPTED;
|
|
|
|
f2fs_put_dnode(&dn);
|
2022-09-28 23:38:54 +08:00
|
|
|
f2fs_handle_error(sbi,
|
|
|
|
ERROR_INVALID_BLKADDR);
|
2020-07-21 11:21:11 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur_bdev = f2fs_target_device(sbi, blkaddr, NULL);
|
|
|
|
if (f2fs_is_multi_device(sbi)) {
|
|
|
|
int di = f2fs_target_device_index(sbi, blkaddr);
|
|
|
|
|
|
|
|
blkaddr -= FDEV(di).start_blk;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len) {
|
|
|
|
if (prev_bdev == cur_bdev &&
|
|
|
|
index == prev_index + len &&
|
|
|
|
blkaddr == prev_block + len) {
|
|
|
|
len++;
|
|
|
|
} else {
|
|
|
|
ret = f2fs_secure_erase(prev_bdev,
|
|
|
|
inode, prev_index, prev_block,
|
|
|
|
len, range.flags);
|
|
|
|
if (ret) {
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!len) {
|
|
|
|
prev_bdev = cur_bdev;
|
|
|
|
prev_index = index;
|
|
|
|
prev_block = blkaddr;
|
|
|
|
len = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f2fs_put_dnode(&dn);
|
|
|
|
|
|
|
|
if (fatal_signal_pending(current)) {
|
|
|
|
ret = -EINTR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
cond_resched();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len)
|
|
|
|
ret = f2fs_secure_erase(prev_bdev, inode, prev_index,
|
|
|
|
prev_block, len, range.flags);
|
|
|
|
out:
|
2021-04-14 00:10:37 +08:00
|
|
|
filemap_invalidate_unlock(mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2020-07-21 11:21:11 +08:00
|
|
|
err:
|
|
|
|
inode_unlock(inode);
|
|
|
|
file_end_write(filp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-10-30 12:10:34 +08:00
|
|
|
static int f2fs_ioc_get_compress_option(struct file *filp, unsigned long arg)
|
2014-09-25 06:37:02 +08:00
|
|
|
{
|
2020-10-30 12:10:34 +08:00
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_comp_option option;
|
|
|
|
|
|
|
|
if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
inode_lock_shared(inode);
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode)) {
|
|
|
|
inode_unlock_shared(inode);
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
option.algorithm = F2FS_I(inode)->i_compress_algorithm;
|
|
|
|
option.log_cluster_size = F2FS_I(inode)->i_log_cluster_size;
|
|
|
|
|
|
|
|
inode_unlock_shared(inode);
|
|
|
|
|
|
|
|
if (copy_to_user((struct f2fs_comp_option __user *)arg, &option,
|
|
|
|
sizeof(option)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-10-30 12:10:35 +08:00
|
|
|
static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct f2fs_comp_option option;
|
|
|
|
int ret = 0;
|
2017-10-24 05:48:49 +08:00
|
|
|
|
2020-10-30 12:10:35 +08:00
|
|
|
if (!f2fs_sb_has_compression(sbi))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!(filp->f_mode & FMODE_WRITE))
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
if (copy_from_user(&option, (struct f2fs_comp_option __user *)arg,
|
|
|
|
sizeof(option)))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode) ||
|
|
|
|
option.log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
|
|
|
|
option.log_cluster_size > MAX_COMPRESS_LOG_SIZE ||
|
|
|
|
option.algorithm >= COMPRESS_MAX)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
file_start_write(filp);
|
|
|
|
inode_lock(inode);
|
|
|
|
|
2023-07-06 10:06:14 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_sem);
|
2020-10-30 12:10:35 +08:00
|
|
|
if (f2fs_is_mmap_file(inode) || get_dirty_pages(inode)) {
|
|
|
|
ret = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2023-01-23 17:46:01 +08:00
|
|
|
if (F2FS_HAS_BLOCKS(inode)) {
|
2020-10-30 12:10:35 +08:00
|
|
|
ret = -EFBIG;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
F2FS_I(inode)->i_compress_algorithm = option.algorithm;
|
|
|
|
F2FS_I(inode)->i_log_cluster_size = option.log_cluster_size;
|
2023-02-16 21:53:24 +08:00
|
|
|
F2FS_I(inode)->i_cluster_size = BIT(option.log_cluster_size);
|
2023-09-09 06:41:42 +08:00
|
|
|
/* Set default level */
|
|
|
|
if (F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD)
|
|
|
|
F2FS_I(inode)->i_compress_level = F2FS_ZSTD_DEFAULT_CLEVEL;
|
|
|
|
else
|
|
|
|
F2FS_I(inode)->i_compress_level = 0;
|
|
|
|
/* Adjust mount option level */
|
|
|
|
if (option.algorithm == F2FS_OPTION(sbi).compress_algorithm &&
|
|
|
|
F2FS_OPTION(sbi).compress_level)
|
|
|
|
F2FS_I(inode)->i_compress_level = F2FS_OPTION(sbi).compress_level;
|
2020-10-30 12:10:35 +08:00
|
|
|
f2fs_mark_inode_dirty_sync(inode, true);
|
|
|
|
|
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
f2fs_warn(sbi, "compression algorithm is successfully set, "
|
|
|
|
"but current kernel doesn't support this algorithm.");
|
|
|
|
out:
|
2023-07-06 10:06:14 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_sem);
|
2020-10-30 12:10:35 +08:00
|
|
|
inode_unlock(inode);
|
|
|
|
file_end_write(filp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-12-03 14:56:15 +08:00
|
|
|
static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len)
|
|
|
|
{
|
2021-04-08 04:18:55 +08:00
|
|
|
DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, page_idx);
|
2020-12-03 14:56:15 +08:00
|
|
|
struct address_space *mapping = inode->i_mapping;
|
|
|
|
struct page *page;
|
|
|
|
pgoff_t redirty_idx = page_idx;
|
|
|
|
int i, page_len = 0, ret = 0;
|
|
|
|
|
|
|
|
page_cache_ra_unbounded(&ractl, len, 0);
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++, page_idx++) {
|
|
|
|
page = read_cache_page(mapping, page_idx, NULL, NULL);
|
|
|
|
if (IS_ERR(page)) {
|
|
|
|
ret = PTR_ERR(page);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
page_len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < page_len; i++, redirty_idx++) {
|
|
|
|
page = find_lock_page(mapping, redirty_idx);
|
2022-05-31 09:16:56 +08:00
|
|
|
|
|
|
|
/* It will never fail, when page has pinned above */
|
|
|
|
f2fs_bug_on(F2FS_I_SB(inode), !page);
|
|
|
|
|
2020-12-03 14:56:15 +08:00
|
|
|
set_page_dirty(page);
|
|
|
|
f2fs_put_page(page, 1);
|
|
|
|
f2fs_put_page(page, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-02-15 14:17:01 +08:00
|
|
|
static int f2fs_ioc_decompress_file(struct file *filp)
|
2020-12-03 14:56:15 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
pgoff_t page_idx = 0, last_idx;
|
|
|
|
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
2022-05-26 10:21:06 +08:00
|
|
|
int cluster_size = fi->i_cluster_size;
|
2020-12-03 14:56:15 +08:00
|
|
|
int count, ret;
|
|
|
|
|
|
|
|
if (!f2fs_sb_has_compression(sbi) ||
|
|
|
|
F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!(filp->f_mode & FMODE_WRITE))
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2020-12-03 14:56:15 +08:00
|
|
|
|
|
|
|
file_start_write(filp);
|
|
|
|
inode_lock(inode);
|
|
|
|
|
|
|
|
if (!f2fs_is_compress_backend_ready(inode)) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-08-03 16:53:58 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-12-03 14:56:15 +08:00
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (!atomic_read(&fi->i_compr_blocks))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
|
|
|
|
|
|
|
count = last_idx - page_idx;
|
2023-07-12 04:08:06 +08:00
|
|
|
while (count && count >= cluster_size) {
|
|
|
|
ret = redirty_blocks(inode, page_idx, cluster_size);
|
2020-12-03 14:56:15 +08:00
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
2023-03-02 17:55:09 +08:00
|
|
|
if (get_dirty_pages(inode) >= blk_per_seg) {
|
|
|
|
ret = filemap_fdatawrite(inode->i_mapping);
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
}
|
2020-12-03 14:56:15 +08:00
|
|
|
|
2023-07-12 04:08:06 +08:00
|
|
|
count -= cluster_size;
|
|
|
|
page_idx += cluster_size;
|
2023-07-12 04:08:05 +08:00
|
|
|
|
|
|
|
cond_resched();
|
|
|
|
if (fatal_signal_pending(current)) {
|
|
|
|
ret = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
2020-12-03 14:56:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0,
|
|
|
|
LLONG_MAX);
|
|
|
|
|
|
|
|
if (ret)
|
2021-05-27 04:05:36 +08:00
|
|
|
f2fs_warn(sbi, "%s: The file might be partially decompressed (errno=%d). Please delete the file.",
|
|
|
|
__func__, ret);
|
2020-12-03 14:56:15 +08:00
|
|
|
out:
|
|
|
|
inode_unlock(inode);
|
|
|
|
file_end_write(filp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-02-15 14:17:01 +08:00
|
|
|
static int f2fs_ioc_compress_file(struct file *filp)
|
2020-12-03 14:56:15 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
pgoff_t page_idx = 0, last_idx;
|
|
|
|
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
|
|
|
int cluster_size = F2FS_I(inode)->i_cluster_size;
|
|
|
|
int count, ret;
|
|
|
|
|
|
|
|
if (!f2fs_sb_has_compression(sbi) ||
|
|
|
|
F2FS_OPTION(sbi).compress_mode != COMPR_MODE_USER)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (!(filp->f_mode & FMODE_WRITE))
|
|
|
|
return -EBADF;
|
|
|
|
|
|
|
|
if (!f2fs_compressed_file(inode))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-06-13 15:51:57 +08:00
|
|
|
f2fs_balance_fs(sbi, true);
|
2020-12-03 14:56:15 +08:00
|
|
|
|
|
|
|
file_start_write(filp);
|
|
|
|
inode_lock(inode);
|
|
|
|
|
|
|
|
if (!f2fs_is_compress_backend_ready(inode)) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-08-03 16:53:58 +08:00
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-12-03 14:56:15 +08:00
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
set_inode_flag(inode, FI_ENABLE_COMPRESS);
|
|
|
|
|
|
|
|
last_idx = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
|
|
|
|
|
|
|
|
count = last_idx - page_idx;
|
2023-07-12 04:08:06 +08:00
|
|
|
while (count && count >= cluster_size) {
|
|
|
|
ret = redirty_blocks(inode, page_idx, cluster_size);
|
2020-12-03 14:56:15 +08:00
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
|
2023-03-02 17:55:09 +08:00
|
|
|
if (get_dirty_pages(inode) >= blk_per_seg) {
|
|
|
|
ret = filemap_fdatawrite(inode->i_mapping);
|
|
|
|
if (ret < 0)
|
|
|
|
break;
|
|
|
|
}
|
2020-12-03 14:56:15 +08:00
|
|
|
|
2023-07-12 04:08:06 +08:00
|
|
|
count -= cluster_size;
|
|
|
|
page_idx += cluster_size;
|
2023-07-12 04:08:05 +08:00
|
|
|
|
|
|
|
cond_resched();
|
|
|
|
if (fatal_signal_pending(current)) {
|
|
|
|
ret = -EINTR;
|
|
|
|
break;
|
|
|
|
}
|
2020-12-03 14:56:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, 0,
|
|
|
|
LLONG_MAX);
|
|
|
|
|
|
|
|
clear_inode_flag(inode, FI_ENABLE_COMPRESS);
|
|
|
|
|
|
|
|
if (ret)
|
2021-05-27 04:05:36 +08:00
|
|
|
f2fs_warn(sbi, "%s: The file might be partially compressed (errno=%d). Please delete the file.",
|
|
|
|
__func__, ret);
|
2020-12-03 14:56:15 +08:00
|
|
|
out:
|
|
|
|
inode_unlock(inode);
|
|
|
|
file_end_write(filp);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
2014-09-25 06:37:02 +08:00
|
|
|
{
|
|
|
|
switch (cmd) {
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_GETVERSION:
|
2015-01-23 20:36:04 +08:00
|
|
|
return f2fs_ioc_getversion(filp, arg);
|
2014-10-07 08:39:50 +08:00
|
|
|
case F2FS_IOC_START_ATOMIC_WRITE:
|
2022-11-12 01:04:06 +08:00
|
|
|
return f2fs_ioc_start_atomic_write(filp, false);
|
|
|
|
case F2FS_IOC_START_ATOMIC_REPLACE:
|
|
|
|
return f2fs_ioc_start_atomic_write(filp, true);
|
2014-10-07 08:39:50 +08:00
|
|
|
case F2FS_IOC_COMMIT_ATOMIC_WRITE:
|
|
|
|
return f2fs_ioc_commit_atomic_write(filp);
|
2022-08-02 01:08:08 +08:00
|
|
|
case F2FS_IOC_ABORT_ATOMIC_WRITE:
|
|
|
|
return f2fs_ioc_abort_atomic_write(filp);
|
2014-10-07 07:11:16 +08:00
|
|
|
case F2FS_IOC_START_VOLATILE_WRITE:
|
2014-12-09 22:08:59 +08:00
|
|
|
case F2FS_IOC_RELEASE_VOLATILE_WRITE:
|
2022-05-06 08:49:18 +08:00
|
|
|
return -EOPNOTSUPP;
|
2015-01-09 11:15:53 +08:00
|
|
|
case F2FS_IOC_SHUTDOWN:
|
|
|
|
return f2fs_ioc_shutdown(filp, arg);
|
2014-09-25 06:37:02 +08:00
|
|
|
case FITRIM:
|
|
|
|
return f2fs_ioc_fitrim(filp, arg);
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_SET_ENCRYPTION_POLICY:
|
2015-04-21 06:19:06 +08:00
|
|
|
return f2fs_ioc_set_encryption_policy(filp, arg);
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_POLICY:
|
2015-04-21 06:19:06 +08:00
|
|
|
return f2fs_ioc_get_encryption_policy(filp, arg);
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_PWSALT:
|
2015-04-21 06:19:06 +08:00
|
|
|
return f2fs_ioc_get_encryption_pwsalt(filp, arg);
|
2019-08-05 10:35:48 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_POLICY_EX:
|
|
|
|
return f2fs_ioc_get_encryption_policy_ex(filp, arg);
|
|
|
|
case FS_IOC_ADD_ENCRYPTION_KEY:
|
|
|
|
return f2fs_ioc_add_encryption_key(filp, arg);
|
|
|
|
case FS_IOC_REMOVE_ENCRYPTION_KEY:
|
|
|
|
return f2fs_ioc_remove_encryption_key(filp, arg);
|
|
|
|
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
|
|
|
|
return f2fs_ioc_remove_encryption_key_all_users(filp, arg);
|
|
|
|
case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
|
|
|
|
return f2fs_ioc_get_encryption_key_status(filp, arg);
|
2020-03-15 04:50:51 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_NONCE:
|
|
|
|
return f2fs_ioc_get_encryption_nonce(filp, arg);
|
2015-07-10 18:08:10 +08:00
|
|
|
case F2FS_IOC_GARBAGE_COLLECT:
|
|
|
|
return f2fs_ioc_gc(filp, arg);
|
2017-06-16 07:44:42 +08:00
|
|
|
case F2FS_IOC_GARBAGE_COLLECT_RANGE:
|
|
|
|
return f2fs_ioc_gc_range(filp, arg);
|
2015-10-05 22:24:19 +08:00
|
|
|
case F2FS_IOC_WRITE_CHECKPOINT:
|
2023-02-15 14:17:01 +08:00
|
|
|
return f2fs_ioc_write_checkpoint(filp);
|
2015-10-27 09:53:45 +08:00
|
|
|
case F2FS_IOC_DEFRAGMENT:
|
|
|
|
return f2fs_ioc_defragment(filp, arg);
|
2016-07-09 06:16:47 +08:00
|
|
|
case F2FS_IOC_MOVE_RANGE:
|
|
|
|
return f2fs_ioc_move_range(filp, arg);
|
2017-04-14 06:17:00 +08:00
|
|
|
case F2FS_IOC_FLUSH_DEVICE:
|
|
|
|
return f2fs_ioc_flush_device(filp, arg);
|
2017-07-22 03:58:59 +08:00
|
|
|
case F2FS_IOC_GET_FEATURES:
|
|
|
|
return f2fs_ioc_get_features(filp, arg);
|
2017-12-08 08:25:39 +08:00
|
|
|
case F2FS_IOC_GET_PIN_FILE:
|
|
|
|
return f2fs_ioc_get_pin_file(filp, arg);
|
|
|
|
case F2FS_IOC_SET_PIN_FILE:
|
|
|
|
return f2fs_ioc_set_pin_file(filp, arg);
|
2018-01-11 14:42:30 +08:00
|
|
|
case F2FS_IOC_PRECACHE_EXTENTS:
|
2023-02-15 14:17:01 +08:00
|
|
|
return f2fs_ioc_precache_extents(filp);
|
2019-06-05 11:33:25 +08:00
|
|
|
case F2FS_IOC_RESIZE_FS:
|
|
|
|
return f2fs_ioc_resize_fs(filp, arg);
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
case FS_IOC_ENABLE_VERITY:
|
|
|
|
return f2fs_ioc_enable_verity(filp, arg);
|
|
|
|
case FS_IOC_MEASURE_VERITY:
|
|
|
|
return f2fs_ioc_measure_verity(filp, arg);
|
fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl
Add an ioctl FS_IOC_READ_VERITY_METADATA which will allow reading verity
metadata from a file that has fs-verity enabled, including:
- The Merkle tree
- The fsverity_descriptor (not including the signature if present)
- The built-in signature, if present
This ioctl has similar semantics to pread(). It is passed the type of
metadata to read (one of the above three), and a buffer, offset, and
size. It returns the number of bytes read or an error.
Separate patches will add support for each of the above metadata types.
This patch just adds the ioctl itself.
This ioctl doesn't make any assumption about where the metadata is
stored on-disk. It does assume the metadata is in a stable format, but
that's basically already the case:
- The Merkle tree and fsverity_descriptor are defined by how fs-verity
file digests are computed; see the "File digest computation" section
of Documentation/filesystems/fsverity.rst. Technically, the way in
which the levels of the tree are ordered relative to each other wasn't
previously specified, but it's logical to put the root level first.
- The built-in signature is the value passed to FS_IOC_ENABLE_VERITY.
This ioctl is useful because it allows writing a server program that
takes a verity file and serves it to a client program, such that the
client can do its own fs-verity compatible verification of the file.
This only makes sense if the client doesn't trust the server and if the
server needs to provide the storage for the client.
More concretely, there is interest in using this ability in Android to
export APK files (which are protected by fs-verity) to "protected VMs".
This would use Protected KVM (https://lwn.net/Articles/836693), which
provides an isolated execution environment without having to trust the
traditional "host". A "guest" VM can boot from a signed image and
perform specific tasks in a minimum trusted environment using files that
have fs-verity enabled on the host, without trusting the host or
requiring that the guest has its own trusted storage.
Technically, it would be possible to duplicate the metadata and store it
in separate files for serving. However, that would be less efficient
and would require extra care in userspace to maintain file consistency.
In addition to the above, the ability to read the built-in signatures is
useful because it allows a system that is using the in-kernel signature
verification to migrate to userspace signature verification.
Link: https://lore.kernel.org/r/20210115181819.34732-4-ebiggers@kernel.org
Reviewed-by: Victor Hsieh <victorhsieh@google.com>
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-01-16 02:18:16 +08:00
|
|
|
case FS_IOC_READ_VERITY_METADATA:
|
|
|
|
return f2fs_ioc_read_verity_metadata(filp, arg);
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_GETFSLABEL:
|
|
|
|
return f2fs_ioc_getfslabel(filp, arg);
|
|
|
|
case FS_IOC_SETFSLABEL:
|
|
|
|
return f2fs_ioc_setfslabel(filp, arg);
|
2020-02-21 18:09:21 +08:00
|
|
|
case F2FS_IOC_GET_COMPRESS_BLOCKS:
|
2023-06-12 11:01:19 +08:00
|
|
|
return f2fs_ioc_get_compress_blocks(filp, arg);
|
2020-03-06 15:36:09 +08:00
|
|
|
case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
|
|
|
|
return f2fs_release_compress_blocks(filp, arg);
|
2020-03-06 14:35:33 +08:00
|
|
|
case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
|
|
|
|
return f2fs_reserve_compress_blocks(filp, arg);
|
2020-07-21 11:21:11 +08:00
|
|
|
case F2FS_IOC_SEC_TRIM_FILE:
|
|
|
|
return f2fs_sec_trim_file(filp, arg);
|
2020-10-30 12:10:34 +08:00
|
|
|
case F2FS_IOC_GET_COMPRESS_OPTION:
|
|
|
|
return f2fs_ioc_get_compress_option(filp, arg);
|
2020-10-30 12:10:35 +08:00
|
|
|
case F2FS_IOC_SET_COMPRESS_OPTION:
|
|
|
|
return f2fs_ioc_set_compress_option(filp, arg);
|
2020-12-03 14:56:15 +08:00
|
|
|
case F2FS_IOC_DECOMPRESS_FILE:
|
2023-02-15 14:17:01 +08:00
|
|
|
return f2fs_ioc_decompress_file(filp);
|
2020-12-03 14:56:15 +08:00
|
|
|
case F2FS_IOC_COMPRESS_FILE:
|
2023-02-15 14:17:01 +08:00
|
|
|
return f2fs_ioc_compress_file(filp);
|
2012-11-02 16:09:44 +08:00
|
|
|
default:
|
|
|
|
return -ENOTTY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 09:24:37 +08:00
|
|
|
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(filp)))))
|
|
|
|
return -EIO;
|
|
|
|
if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(filp))))
|
|
|
|
return -ENOSPC;
|
|
|
|
|
|
|
|
return __f2fs_ioctl(filp, cmd, arg);
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
/*
|
|
|
|
* Return %true if the given read or write request should use direct I/O, or
|
|
|
|
* %false if it should use buffered I/O.
|
|
|
|
*/
|
|
|
|
static bool f2fs_should_use_dio(struct inode *inode, struct kiocb *iocb,
|
|
|
|
struct iov_iter *iter)
|
|
|
|
{
|
|
|
|
unsigned int align;
|
|
|
|
|
|
|
|
if (!(iocb->ki_flags & IOCB_DIRECT))
|
|
|
|
return false;
|
|
|
|
|
2022-08-27 14:58:49 +08:00
|
|
|
if (f2fs_force_buffered_io(inode, iov_iter_rw(iter)))
|
2021-07-23 15:59:21 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Direct I/O not aligned to the disk's logical_block_size will be
|
|
|
|
* attempted, but will fail with -EINVAL.
|
|
|
|
*
|
|
|
|
* f2fs additionally requires that direct I/O be aligned to the
|
|
|
|
* filesystem block size, which is often a stricter requirement.
|
|
|
|
* However, f2fs traditionally falls back to buffered I/O on requests
|
|
|
|
* that are logical_block_size-aligned but not fs-block aligned.
|
|
|
|
*
|
|
|
|
* The below logic implements this behavior.
|
|
|
|
*/
|
|
|
|
align = iocb->ki_pos | iov_iter_alignment(iter);
|
|
|
|
if (!IS_ALIGNED(align, i_blocksize(inode)) &&
|
|
|
|
IS_ALIGNED(align, bdev_logical_block_size(inode->i_sb->s_bdev)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_dio_read_end_io(struct kiocb *iocb, ssize_t size, int error,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
|
|
|
|
|
|
|
|
dec_page_count(sbi, F2FS_DIO_READ);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(sbi, NULL, APP_DIRECT_READ_IO, size);
|
2021-07-23 15:59:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct iomap_dio_ops f2fs_iomap_dio_read_ops = {
|
|
|
|
.end_io = f2fs_dio_read_end_io,
|
|
|
|
};
|
|
|
|
|
|
|
|
static ssize_t f2fs_dio_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct inode *inode = file_inode(file);
|
2021-07-23 15:59:21 +08:00
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
const loff_t pos = iocb->ki_pos;
|
|
|
|
const size_t count = iov_iter_count(to);
|
|
|
|
struct iomap_dio *dio;
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
return 0; /* skip atime update */
|
|
|
|
|
2021-11-20 03:20:33 +08:00
|
|
|
trace_f2fs_direct_IO_enter(inode, iocb, count, READ);
|
2021-07-23 15:59:21 +08:00
|
|
|
|
|
|
|
if (iocb->ki_flags & IOCB_NOWAIT) {
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
|
2021-07-23 15:59:21 +08:00
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_read(&fi->i_gc_rwsem[READ]);
|
2021-07-23 15:59:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
|
|
|
|
* the higher-level function iomap_dio_rw() in order to ensure that the
|
|
|
|
* F2FS_DIO_READ counter will be decremented correctly in all cases.
|
|
|
|
*/
|
|
|
|
inc_page_count(sbi, F2FS_DIO_READ);
|
|
|
|
dio = __iomap_dio_rw(iocb, to, &f2fs_iomap_ops,
|
2022-05-06 04:11:11 +08:00
|
|
|
&f2fs_iomap_dio_read_ops, 0, NULL, 0);
|
2021-07-23 15:59:21 +08:00
|
|
|
if (IS_ERR_OR_NULL(dio)) {
|
|
|
|
ret = PTR_ERR_OR_ZERO(dio);
|
|
|
|
if (ret != -EIOCBQUEUED)
|
|
|
|
dec_page_count(sbi, F2FS_DIO_READ);
|
|
|
|
} else {
|
|
|
|
ret = iomap_dio_complete(dio);
|
|
|
|
}
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_read(&fi->i_gc_rwsem[READ]);
|
2021-07-23 15:59:21 +08:00
|
|
|
|
|
|
|
file_accessed(file);
|
|
|
|
out:
|
|
|
|
trace_f2fs_direct_IO_exit(inode, pos, count, READ, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-05-22 21:50:06 +08:00
|
|
|
static void f2fs_trace_rw_file_path(struct file *file, loff_t pos, size_t count,
|
|
|
|
int rw)
|
2023-01-19 14:36:21 +08:00
|
|
|
{
|
2023-05-22 21:50:06 +08:00
|
|
|
struct inode *inode = file_inode(file);
|
2023-01-19 14:36:21 +08:00
|
|
|
char *buf, *path;
|
|
|
|
|
2023-04-14 18:43:08 +08:00
|
|
|
buf = f2fs_getname(F2FS_I_SB(inode));
|
2023-01-19 14:36:21 +08:00
|
|
|
if (!buf)
|
|
|
|
return;
|
2023-05-22 21:50:06 +08:00
|
|
|
path = dentry_path_raw(file_dentry(file), buf, PATH_MAX);
|
2023-01-19 14:36:21 +08:00
|
|
|
if (IS_ERR(path))
|
|
|
|
goto free_buf;
|
|
|
|
if (rw == WRITE)
|
2023-05-22 21:50:06 +08:00
|
|
|
trace_f2fs_datawrite_start(inode, pos, count,
|
2023-01-19 14:36:21 +08:00
|
|
|
current->pid, path, current->comm);
|
|
|
|
else
|
2023-05-22 21:50:06 +08:00
|
|
|
trace_f2fs_dataread_start(inode, pos, count,
|
2023-01-19 14:36:21 +08:00
|
|
|
current->pid, path, current->comm);
|
|
|
|
free_buf:
|
2023-04-14 18:43:08 +08:00
|
|
|
f2fs_putname(buf);
|
2023-01-19 14:36:21 +08:00
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(iocb->ki_filp);
|
2022-03-22 06:13:06 +08:00
|
|
|
const loff_t pos = iocb->ki_pos;
|
2021-07-23 15:59:21 +08:00
|
|
|
ssize_t ret;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2023-01-19 14:36:21 +08:00
|
|
|
if (trace_f2fs_dataread_start_enabled())
|
2023-05-22 21:50:06 +08:00
|
|
|
f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
|
|
|
|
iov_iter_count(to), READ);
|
2022-03-22 06:13:06 +08:00
|
|
|
|
|
|
|
if (f2fs_should_use_dio(inode, iocb, to)) {
|
|
|
|
ret = f2fs_dio_read_iter(iocb, to);
|
|
|
|
} else {
|
|
|
|
ret = filemap_read(iocb, to, 0);
|
|
|
|
if (ret > 0)
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(F2FS_I_SB(inode), inode,
|
|
|
|
APP_BUFFERED_READ_IO, ret);
|
2022-03-22 06:13:06 +08:00
|
|
|
}
|
|
|
|
if (trace_f2fs_dataread_end_enabled())
|
|
|
|
trace_f2fs_dataread_end(inode, pos, ret);
|
2020-04-16 18:16:56 +08:00
|
|
|
return ret;
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
}
|
|
|
|
|
2023-05-22 21:50:06 +08:00
|
|
|
static ssize_t f2fs_file_splice_read(struct file *in, loff_t *ppos,
|
|
|
|
struct pipe_inode_info *pipe,
|
|
|
|
size_t len, unsigned int flags)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(in);
|
|
|
|
const loff_t pos = *ppos;
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (!f2fs_is_compress_backend_ready(inode))
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (trace_f2fs_dataread_start_enabled())
|
|
|
|
f2fs_trace_rw_file_path(in, pos, len, READ);
|
|
|
|
|
|
|
|
ret = filemap_splice_read(in, ppos, pipe, len, flags);
|
|
|
|
if (ret > 0)
|
|
|
|
f2fs_update_iostat(F2FS_I_SB(inode), inode,
|
|
|
|
APP_BUFFERED_READ_IO, ret);
|
|
|
|
|
|
|
|
if (trace_f2fs_dataread_end_enabled())
|
|
|
|
trace_f2fs_dataread_end(inode, pos, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
static ssize_t f2fs_write_checks(struct kiocb *iocb, struct iov_iter *from)
|
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
ssize_t count;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (IS_IMMUTABLE(inode))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
count = generic_write_checks(iocb, from);
|
|
|
|
if (count <= 0)
|
|
|
|
return count;
|
|
|
|
|
|
|
|
err = file_modified(file);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2021-07-16 22:39:13 +08:00
|
|
|
/*
|
|
|
|
* Preallocate blocks for a write request, if it is possible and helpful to do
|
|
|
|
* so. Returns a positive number if blocks may have been preallocated, 0 if no
|
|
|
|
* blocks were preallocated, or a negative errno value if something went
|
|
|
|
* seriously wrong. Also sets FI_PREALLOCATED_ALL on the inode if *all* the
|
|
|
|
* requested blocks (not just some of them) have been allocated.
|
|
|
|
*/
|
2021-07-23 15:59:21 +08:00
|
|
|
static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter,
|
|
|
|
bool dio)
|
2021-07-16 22:39:13 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(iocb->ki_filp);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
const loff_t pos = iocb->ki_pos;
|
|
|
|
const size_t count = iov_iter_count(iter);
|
|
|
|
struct f2fs_map_blocks map = {};
|
|
|
|
int flag;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* If it will be an out-of-place direct write, don't bother. */
|
|
|
|
if (dio && f2fs_lfs_mode(sbi))
|
|
|
|
return 0;
|
2021-11-13 06:31:16 +08:00
|
|
|
/*
|
|
|
|
* Don't preallocate holes aligned to DIO_SKIP_HOLES which turns into
|
|
|
|
* buffered IO, if DIO meets any holes.
|
|
|
|
*/
|
|
|
|
if (dio && i_size_read(inode) &&
|
|
|
|
(F2FS_BYTES_TO_BLK(pos) < F2FS_BLK_ALIGN(i_size_read(inode))))
|
|
|
|
return 0;
|
2021-07-16 22:39:13 +08:00
|
|
|
|
|
|
|
/* No-wait I/O can't allocate blocks. */
|
|
|
|
if (iocb->ki_flags & IOCB_NOWAIT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* If it will be a short write, don't bother. */
|
|
|
|
if (fault_in_iov_iter_readable(iter, count))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (f2fs_has_inline_data(inode)) {
|
|
|
|
/* If the data will fit inline, don't bother. */
|
|
|
|
if (pos + count <= MAX_INLINE_DATA(inode))
|
|
|
|
return 0;
|
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Do not preallocate blocks that will be written partially in 4KB. */
|
|
|
|
map.m_lblk = F2FS_BLK_ALIGN(pos);
|
|
|
|
map.m_len = F2FS_BYTES_TO_BLK(pos + count);
|
|
|
|
if (map.m_len > map.m_lblk)
|
|
|
|
map.m_len -= map.m_lblk;
|
|
|
|
else
|
|
|
|
map.m_len = 0;
|
|
|
|
map.m_may_create = true;
|
|
|
|
if (dio) {
|
|
|
|
map.m_seg_type = f2fs_rw_hint_to_seg_type(inode->i_write_hint);
|
|
|
|
flag = F2FS_GET_BLOCK_PRE_DIO;
|
|
|
|
} else {
|
|
|
|
map.m_seg_type = NO_CHECK_TYPE;
|
|
|
|
flag = F2FS_GET_BLOCK_PRE_AIO;
|
|
|
|
}
|
|
|
|
|
2022-11-28 17:15:20 +08:00
|
|
|
ret = f2fs_map_blocks(inode, &map, flag);
|
2021-11-13 06:31:16 +08:00
|
|
|
/* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */
|
|
|
|
if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0))
|
2021-07-16 22:39:13 +08:00
|
|
|
return ret;
|
|
|
|
if (ret == 0)
|
|
|
|
set_inode_flag(inode, FI_PREALLOCATED_ALL);
|
|
|
|
return map.m_len;
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
static ssize_t f2fs_buffered_write_iter(struct kiocb *iocb,
|
|
|
|
struct iov_iter *from)
|
2015-04-22 11:39:58 +08:00
|
|
|
{
|
2016-02-04 05:09:09 +08:00
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct inode *inode = file_inode(file);
|
2021-07-23 15:59:21 +08:00
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
if (iocb->ki_flags & IOCB_NOWAIT)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
2022-02-20 12:19:49 +08:00
|
|
|
ret = generic_perform_write(iocb, from);
|
2021-07-23 15:59:21 +08:00
|
|
|
|
|
|
|
if (ret > 0) {
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(F2FS_I_SB(inode), inode,
|
|
|
|
APP_BUFFERED_IO, ret);
|
2021-07-23 15:59:21 +08:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int f2fs_dio_write_end_io(struct kiocb *iocb, ssize_t size, int error,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(file_inode(iocb->ki_filp));
|
|
|
|
|
|
|
|
dec_page_count(sbi, F2FS_DIO_WRITE);
|
|
|
|
if (error)
|
|
|
|
return error;
|
2023-08-10 16:40:00 +08:00
|
|
|
f2fs_update_time(sbi, REQ_TIME);
|
2022-08-20 11:04:41 +08:00
|
|
|
f2fs_update_iostat(sbi, NULL, APP_DIRECT_IO, size);
|
2021-07-23 15:59:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct iomap_dio_ops f2fs_iomap_dio_write_ops = {
|
|
|
|
.end_io = f2fs_dio_write_end_io,
|
|
|
|
};
|
|
|
|
|
2023-02-20 20:20:04 +08:00
|
|
|
static void f2fs_flush_buffered_write(struct address_space *mapping,
|
|
|
|
loff_t start_pos, loff_t end_pos)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = filemap_write_and_wait_range(mapping, start_pos, end_pos);
|
|
|
|
if (ret < 0)
|
|
|
|
return;
|
|
|
|
invalidate_mapping_pages(mapping,
|
|
|
|
start_pos >> PAGE_SHIFT,
|
|
|
|
end_pos >> PAGE_SHIFT);
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
static ssize_t f2fs_dio_write_iter(struct kiocb *iocb, struct iov_iter *from,
|
|
|
|
bool *may_need_sync)
|
|
|
|
{
|
|
|
|
struct file *file = iocb->ki_filp;
|
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
struct f2fs_inode_info *fi = F2FS_I(inode);
|
|
|
|
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
|
|
|
const bool do_opu = f2fs_lfs_mode(sbi);
|
|
|
|
const loff_t pos = iocb->ki_pos;
|
|
|
|
const ssize_t count = iov_iter_count(from);
|
|
|
|
unsigned int dio_flags;
|
|
|
|
struct iomap_dio *dio;
|
|
|
|
ssize_t ret;
|
|
|
|
|
2021-11-20 03:20:33 +08:00
|
|
|
trace_f2fs_direct_IO_enter(inode, iocb, count, WRITE);
|
2021-07-23 15:59:21 +08:00
|
|
|
|
|
|
|
if (iocb->ki_flags & IOCB_NOWAIT) {
|
|
|
|
/* f2fs_convert_inline_inode() and block allocation can block */
|
|
|
|
if (f2fs_has_inline_data(inode) ||
|
|
|
|
!f2fs_overwrite_io(inode, pos, count)) {
|
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
if (!f2fs_down_read_trylock(&fi->i_gc_rwsem[WRITE])) {
|
2021-07-23 15:59:21 +08:00
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
2022-01-08 04:48:44 +08:00
|
|
|
if (do_opu && !f2fs_down_read_trylock(&fi->i_gc_rwsem[READ])) {
|
|
|
|
f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
|
2021-07-23 15:59:21 +08:00
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = f2fs_convert_inline_inode(inode);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_read(&fi->i_gc_rwsem[WRITE]);
|
2021-07-23 15:59:21 +08:00
|
|
|
if (do_opu)
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_read(&fi->i_gc_rwsem[READ]);
|
2021-07-23 15:59:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We have to use __iomap_dio_rw() and iomap_dio_complete() instead of
|
|
|
|
* the higher-level function iomap_dio_rw() in order to ensure that the
|
|
|
|
* F2FS_DIO_WRITE counter will be decremented correctly in all cases.
|
|
|
|
*/
|
|
|
|
inc_page_count(sbi, F2FS_DIO_WRITE);
|
|
|
|
dio_flags = 0;
|
|
|
|
if (pos + count > inode->i_size)
|
|
|
|
dio_flags |= IOMAP_DIO_FORCE_WAIT;
|
|
|
|
dio = __iomap_dio_rw(iocb, from, &f2fs_iomap_ops,
|
2022-05-06 04:11:11 +08:00
|
|
|
&f2fs_iomap_dio_write_ops, dio_flags, NULL, 0);
|
2021-07-23 15:59:21 +08:00
|
|
|
if (IS_ERR_OR_NULL(dio)) {
|
|
|
|
ret = PTR_ERR_OR_ZERO(dio);
|
|
|
|
if (ret == -ENOTBLK)
|
|
|
|
ret = 0;
|
|
|
|
if (ret != -EIOCBQUEUED)
|
|
|
|
dec_page_count(sbi, F2FS_DIO_WRITE);
|
|
|
|
} else {
|
|
|
|
ret = iomap_dio_complete(dio);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (do_opu)
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_read(&fi->i_gc_rwsem[READ]);
|
|
|
|
f2fs_up_read(&fi->i_gc_rwsem[WRITE]);
|
2021-07-23 15:59:21 +08:00
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
if (pos + ret > inode->i_size)
|
|
|
|
f2fs_i_size_write(inode, pos + ret);
|
|
|
|
if (!do_opu)
|
|
|
|
set_inode_flag(inode, FI_UPDATE_WRITE);
|
|
|
|
|
|
|
|
if (iov_iter_count(from)) {
|
|
|
|
ssize_t ret2;
|
|
|
|
loff_t bufio_start_pos = iocb->ki_pos;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The direct write was partial, so we need to fall back to a
|
|
|
|
* buffered write for the remainder.
|
|
|
|
*/
|
|
|
|
|
|
|
|
ret2 = f2fs_buffered_write_iter(iocb, from);
|
|
|
|
if (iov_iter_count(from))
|
|
|
|
f2fs_write_failed(inode, iocb->ki_pos);
|
|
|
|
if (ret2 < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that the pagecache pages are written to disk and
|
|
|
|
* invalidated to preserve the expected O_DIRECT semantics.
|
|
|
|
*/
|
|
|
|
if (ret2 > 0) {
|
|
|
|
loff_t bufio_end_pos = bufio_start_pos + ret2 - 1;
|
|
|
|
|
|
|
|
ret += ret2;
|
|
|
|
|
2023-02-20 20:20:04 +08:00
|
|
|
f2fs_flush_buffered_write(file->f_mapping,
|
|
|
|
bufio_start_pos,
|
|
|
|
bufio_end_pos);
|
2021-07-23 15:59:21 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* iomap_dio_rw() already handled the generic_write_sync(). */
|
|
|
|
*may_need_sync = false;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
trace_f2fs_direct_IO_exit(inode, pos, count, WRITE, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|
|
|
{
|
|
|
|
struct inode *inode = file_inode(iocb->ki_filp);
|
2021-07-16 22:39:15 +08:00
|
|
|
const loff_t orig_pos = iocb->ki_pos;
|
|
|
|
const size_t orig_count = iov_iter_count(from);
|
2021-07-16 22:39:13 +08:00
|
|
|
loff_t target_size;
|
2021-07-23 15:59:21 +08:00
|
|
|
bool dio;
|
|
|
|
bool may_need_sync = true;
|
2021-07-16 22:39:13 +08:00
|
|
|
int preallocated;
|
2016-02-04 05:09:09 +08:00
|
|
|
ssize_t ret;
|
2015-04-22 11:39:58 +08:00
|
|
|
|
2019-04-02 18:52:22 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
|
|
|
|
ret = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
2017-10-24 05:48:49 +08:00
|
|
|
|
2020-02-24 19:20:15 +08:00
|
|
|
if (!f2fs_is_compress_backend_ready(inode)) {
|
|
|
|
ret = -EOPNOTSUPP;
|
|
|
|
goto out;
|
|
|
|
}
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
|
2019-09-12 00:45:17 +08:00
|
|
|
if (iocb->ki_flags & IOCB_NOWAIT) {
|
|
|
|
if (!inode_trylock(inode)) {
|
2019-04-02 18:52:22 +08:00
|
|
|
ret = -EAGAIN;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-09-12 00:45:17 +08:00
|
|
|
} else {
|
2018-03-08 18:34:38 +08:00
|
|
|
inode_lock(inode);
|
|
|
|
}
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
ret = f2fs_write_checks(iocb, from);
|
2021-07-16 22:39:14 +08:00
|
|
|
if (ret <= 0)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
/* Determine whether we will do a direct write or a buffered write. */
|
|
|
|
dio = f2fs_should_use_dio(inode, iocb, from);
|
2021-07-16 22:39:13 +08:00
|
|
|
|
2021-07-16 22:39:14 +08:00
|
|
|
/* Possibly preallocate the blocks for the write. */
|
|
|
|
target_size = iocb->ki_pos + iov_iter_count(from);
|
2021-07-23 15:59:21 +08:00
|
|
|
preallocated = f2fs_preallocate_blocks(iocb, from, dio);
|
2022-03-22 06:13:06 +08:00
|
|
|
if (preallocated < 0) {
|
2021-07-16 22:39:14 +08:00
|
|
|
ret = preallocated;
|
2022-03-22 06:13:06 +08:00
|
|
|
} else {
|
2023-01-19 14:36:21 +08:00
|
|
|
if (trace_f2fs_datawrite_start_enabled())
|
2023-05-22 21:50:06 +08:00
|
|
|
f2fs_trace_rw_file_path(iocb->ki_filp, iocb->ki_pos,
|
|
|
|
orig_count, WRITE);
|
2023-01-19 14:36:21 +08:00
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
/* Do the actual write. */
|
|
|
|
ret = dio ?
|
2022-09-14 09:33:22 +08:00
|
|
|
f2fs_dio_write_iter(iocb, from, &may_need_sync) :
|
2021-07-23 15:59:21 +08:00
|
|
|
f2fs_buffered_write_iter(iocb, from);
|
2018-03-31 08:58:13 +08:00
|
|
|
|
2022-03-22 06:13:06 +08:00
|
|
|
if (trace_f2fs_datawrite_end_enabled())
|
|
|
|
trace_f2fs_datawrite_end(inode, orig_pos, ret);
|
|
|
|
}
|
|
|
|
|
2021-07-16 22:39:14 +08:00
|
|
|
/* Don't leave any preallocated blocks around past i_size. */
|
2021-11-13 06:31:16 +08:00
|
|
|
if (preallocated && i_size_read(inode) < target_size) {
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-07-16 22:39:14 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
2021-11-13 06:31:16 +08:00
|
|
|
if (!f2fs_truncate(inode))
|
|
|
|
file_dont_truncate(inode);
|
2021-07-16 22:39:14 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2022-01-08 04:48:44 +08:00
|
|
|
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
2021-11-13 06:31:16 +08:00
|
|
|
} else {
|
|
|
|
file_dont_truncate(inode);
|
2016-02-04 05:09:09 +08:00
|
|
|
}
|
2021-07-16 22:39:14 +08:00
|
|
|
|
|
|
|
clear_inode_flag(inode, FI_PREALLOCATED_ALL);
|
2021-07-16 22:39:13 +08:00
|
|
|
out_unlock:
|
2016-02-04 05:09:09 +08:00
|
|
|
inode_unlock(inode);
|
2019-04-02 18:52:22 +08:00
|
|
|
out:
|
2021-07-16 22:39:15 +08:00
|
|
|
trace_f2fs_file_write_iter(inode, orig_pos, orig_count, ret);
|
2023-02-20 20:20:04 +08:00
|
|
|
|
2021-07-23 15:59:21 +08:00
|
|
|
if (ret > 0 && may_need_sync)
|
2016-04-07 23:52:01 +08:00
|
|
|
ret = generic_write_sync(iocb, ret);
|
2023-02-20 20:20:04 +08:00
|
|
|
|
|
|
|
/* If buffered IO was forced, flush and drop the data from
|
|
|
|
* the page cache to preserve O_DIRECT semantics
|
|
|
|
*/
|
|
|
|
if (ret > 0 && !dio && (iocb->ki_flags & IOCB_DIRECT))
|
|
|
|
f2fs_flush_buffered_write(iocb->ki_filp->f_mapping,
|
|
|
|
orig_pos,
|
|
|
|
orig_pos + ret - 1);
|
|
|
|
|
2016-02-04 05:09:09 +08:00
|
|
|
return ret;
|
2015-04-22 11:39:58 +08:00
|
|
|
}
|
|
|
|
|
2021-08-03 12:22:45 +08:00
|
|
|
static int f2fs_file_fadvise(struct file *filp, loff_t offset, loff_t len,
|
|
|
|
int advice)
|
|
|
|
{
|
|
|
|
struct address_space *mapping;
|
|
|
|
struct backing_dev_info *bdi;
|
2021-11-29 10:13:41 +08:00
|
|
|
struct inode *inode = file_inode(filp);
|
|
|
|
int err;
|
2021-08-03 12:22:45 +08:00
|
|
|
|
|
|
|
if (advice == POSIX_FADV_SEQUENTIAL) {
|
|
|
|
if (S_ISFIFO(inode->i_mode))
|
|
|
|
return -ESPIPE;
|
|
|
|
|
|
|
|
mapping = filp->f_mapping;
|
|
|
|
if (!mapping || len < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
bdi = inode_to_bdi(mapping->host);
|
|
|
|
filp->f_ra.ra_pages = bdi->ra_pages *
|
|
|
|
F2FS_I_SB(inode)->seq_file_ra_mul;
|
|
|
|
spin_lock(&filp->f_lock);
|
|
|
|
filp->f_mode &= ~FMODE_RANDOM;
|
|
|
|
spin_unlock(&filp->f_lock);
|
|
|
|
return 0;
|
2023-09-20 08:43:52 +08:00
|
|
|
} else if (advice == POSIX_FADV_WILLNEED && offset == 0) {
|
|
|
|
/* Load extent cache at the first readahead. */
|
|
|
|
f2fs_precache_extents(inode);
|
2021-08-03 12:22:45 +08:00
|
|
|
}
|
|
|
|
|
2021-11-29 10:13:41 +08:00
|
|
|
err = generic_fadvise(filp, offset, len, advice);
|
|
|
|
if (!err && advice == POSIX_FADV_DONTNEED &&
|
|
|
|
test_opt(F2FS_I_SB(inode), COMPRESS_CACHE) &&
|
|
|
|
f2fs_compressed_file(inode))
|
|
|
|
f2fs_invalidate_compress_pages(F2FS_I_SB(inode), inode->i_ino);
|
|
|
|
|
|
|
|
return err;
|
2021-08-03 12:22:45 +08:00
|
|
|
}
|
|
|
|
|
2013-02-04 22:41:41 +08:00
|
|
|
#ifdef CONFIG_COMPAT
|
2020-11-10 09:24:37 +08:00
|
|
|
struct compat_f2fs_gc_range {
|
|
|
|
u32 sync;
|
|
|
|
compat_u64 start;
|
|
|
|
compat_u64 len;
|
|
|
|
};
|
|
|
|
#define F2FS_IOC32_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11,\
|
|
|
|
struct compat_f2fs_gc_range)
|
|
|
|
|
|
|
|
static int f2fs_compat_ioc_gc_range(struct file *file, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct compat_f2fs_gc_range __user *urange;
|
|
|
|
struct f2fs_gc_range range;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
urange = compat_ptr(arg);
|
|
|
|
err = get_user(range.sync, &urange->sync);
|
|
|
|
err |= get_user(range.start, &urange->start);
|
|
|
|
err |= get_user(range.len, &urange->len);
|
|
|
|
if (err)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return __f2fs_ioc_gc_range(file, &range);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct compat_f2fs_move_range {
|
|
|
|
u32 dst_fd;
|
|
|
|
compat_u64 pos_in;
|
|
|
|
compat_u64 pos_out;
|
|
|
|
compat_u64 len;
|
|
|
|
};
|
|
|
|
#define F2FS_IOC32_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \
|
|
|
|
struct compat_f2fs_move_range)
|
|
|
|
|
|
|
|
static int f2fs_compat_ioc_move_range(struct file *file, unsigned long arg)
|
|
|
|
{
|
|
|
|
struct compat_f2fs_move_range __user *urange;
|
|
|
|
struct f2fs_move_range range;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
urange = compat_ptr(arg);
|
|
|
|
err = get_user(range.dst_fd, &urange->dst_fd);
|
|
|
|
err |= get_user(range.pos_in, &urange->pos_in);
|
|
|
|
err |= get_user(range.pos_out, &urange->pos_out);
|
|
|
|
err |= get_user(range.len, &urange->len);
|
|
|
|
if (err)
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
return __f2fs_ioc_move_range(file, &range);
|
|
|
|
}
|
|
|
|
|
2013-02-04 22:41:41 +08:00
|
|
|
long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
|
{
|
2020-11-10 09:24:37 +08:00
|
|
|
if (unlikely(f2fs_cp_error(F2FS_I_SB(file_inode(file)))))
|
|
|
|
return -EIO;
|
|
|
|
if (!f2fs_is_checkpoint_ready(F2FS_I_SB(file_inode(file))))
|
|
|
|
return -ENOSPC;
|
|
|
|
|
2013-02-04 22:41:41 +08:00
|
|
|
switch (cmd) {
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC32_GETVERSION:
|
|
|
|
cmd = FS_IOC_GETVERSION;
|
2015-11-10 18:44:20 +08:00
|
|
|
break;
|
2020-11-10 09:24:37 +08:00
|
|
|
case F2FS_IOC32_GARBAGE_COLLECT_RANGE:
|
|
|
|
return f2fs_compat_ioc_gc_range(file, arg);
|
|
|
|
case F2FS_IOC32_MOVE_RANGE:
|
|
|
|
return f2fs_compat_ioc_move_range(file, arg);
|
2015-11-10 18:44:20 +08:00
|
|
|
case F2FS_IOC_START_ATOMIC_WRITE:
|
2023-01-28 18:32:26 +08:00
|
|
|
case F2FS_IOC_START_ATOMIC_REPLACE:
|
2015-11-10 18:44:20 +08:00
|
|
|
case F2FS_IOC_COMMIT_ATOMIC_WRITE:
|
|
|
|
case F2FS_IOC_START_VOLATILE_WRITE:
|
|
|
|
case F2FS_IOC_RELEASE_VOLATILE_WRITE:
|
2022-08-02 01:08:08 +08:00
|
|
|
case F2FS_IOC_ABORT_ATOMIC_WRITE:
|
2015-11-10 18:44:20 +08:00
|
|
|
case F2FS_IOC_SHUTDOWN:
|
2019-06-03 19:51:58 +08:00
|
|
|
case FITRIM:
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_SET_ENCRYPTION_POLICY:
|
|
|
|
case FS_IOC_GET_ENCRYPTION_PWSALT:
|
|
|
|
case FS_IOC_GET_ENCRYPTION_POLICY:
|
2019-08-05 10:35:48 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_POLICY_EX:
|
|
|
|
case FS_IOC_ADD_ENCRYPTION_KEY:
|
|
|
|
case FS_IOC_REMOVE_ENCRYPTION_KEY:
|
|
|
|
case FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
|
|
|
|
case FS_IOC_GET_ENCRYPTION_KEY_STATUS:
|
2020-03-15 04:50:51 +08:00
|
|
|
case FS_IOC_GET_ENCRYPTION_NONCE:
|
2015-11-10 18:44:20 +08:00
|
|
|
case F2FS_IOC_GARBAGE_COLLECT:
|
|
|
|
case F2FS_IOC_WRITE_CHECKPOINT:
|
|
|
|
case F2FS_IOC_DEFRAGMENT:
|
2017-04-14 06:17:00 +08:00
|
|
|
case F2FS_IOC_FLUSH_DEVICE:
|
2017-07-22 03:58:59 +08:00
|
|
|
case F2FS_IOC_GET_FEATURES:
|
2017-12-08 08:25:39 +08:00
|
|
|
case F2FS_IOC_GET_PIN_FILE:
|
|
|
|
case F2FS_IOC_SET_PIN_FILE:
|
2018-01-11 14:42:30 +08:00
|
|
|
case F2FS_IOC_PRECACHE_EXTENTS:
|
2019-06-05 11:33:25 +08:00
|
|
|
case F2FS_IOC_RESIZE_FS:
|
f2fs: add fs-verity support
Add fs-verity support to f2fs. fs-verity is a filesystem feature that
enables transparent integrity protection and authentication of read-only
files. It uses a dm-verity like mechanism at the file level: a Merkle
tree is used to verify any block in the file in log(filesize) time. It
is implemented mainly by helper functions in fs/verity/. See
Documentation/filesystems/fsverity.rst for the full documentation.
The f2fs support for fs-verity consists of:
- Adding a filesystem feature flag and an inode flag for fs-verity.
- Implementing the fsverity_operations to support enabling verity on an
inode and reading/writing the verity metadata.
- Updating ->readpages() to verify data as it's read from verity files
and to support reading verity metadata pages.
- Updating ->write_begin(), ->write_end(), and ->writepages() to support
writing verity metadata pages.
- Calling the fs-verity hooks for ->open(), ->setattr(), and ->ioctl().
Like ext4, f2fs stores the verity metadata (Merkle tree and
fsverity_descriptor) past the end of the file, starting at the first 64K
boundary beyond i_size. This approach works because (a) verity files
are readonly, and (b) pages fully beyond i_size aren't visible to
userspace but can be read/written internally by f2fs with only some
relatively small changes to f2fs. Extended attributes cannot be used
because (a) f2fs limits the total size of an inode's xattr entries to
4096 bytes, which wouldn't be enough for even a single Merkle tree
block, and (b) f2fs encryption doesn't encrypt xattrs, yet the verity
metadata *must* be encrypted when the file is because it contains hashes
of the plaintext data.
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Acked-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2019-07-23 00:26:24 +08:00
|
|
|
case FS_IOC_ENABLE_VERITY:
|
|
|
|
case FS_IOC_MEASURE_VERITY:
|
fs-verity: add FS_IOC_READ_VERITY_METADATA ioctl
Add an ioctl FS_IOC_READ_VERITY_METADATA which will allow reading verity
metadata from a file that has fs-verity enabled, including:
- The Merkle tree
- The fsverity_descriptor (not including the signature if present)
- The built-in signature, if present
This ioctl has similar semantics to pread(). It is passed the type of
metadata to read (one of the above three), and a buffer, offset, and
size. It returns the number of bytes read or an error.
Separate patches will add support for each of the above metadata types.
This patch just adds the ioctl itself.
This ioctl doesn't make any assumption about where the metadata is
stored on-disk. It does assume the metadata is in a stable format, but
that's basically already the case:
- The Merkle tree and fsverity_descriptor are defined by how fs-verity
file digests are computed; see the "File digest computation" section
of Documentation/filesystems/fsverity.rst. Technically, the way in
which the levels of the tree are ordered relative to each other wasn't
previously specified, but it's logical to put the root level first.
- The built-in signature is the value passed to FS_IOC_ENABLE_VERITY.
This ioctl is useful because it allows writing a server program that
takes a verity file and serves it to a client program, such that the
client can do its own fs-verity compatible verification of the file.
This only makes sense if the client doesn't trust the server and if the
server needs to provide the storage for the client.
More concretely, there is interest in using this ability in Android to
export APK files (which are protected by fs-verity) to "protected VMs".
This would use Protected KVM (https://lwn.net/Articles/836693), which
provides an isolated execution environment without having to trust the
traditional "host". A "guest" VM can boot from a signed image and
perform specific tasks in a minimum trusted environment using files that
have fs-verity enabled on the host, without trusting the host or
requiring that the guest has its own trusted storage.
Technically, it would be possible to duplicate the metadata and store it
in separate files for serving. However, that would be less efficient
and would require extra care in userspace to maintain file consistency.
In addition to the above, the ability to read the built-in signatures is
useful because it allows a system that is using the in-kernel signature
verification to migrate to userspace signature verification.
Link: https://lore.kernel.org/r/20210115181819.34732-4-ebiggers@kernel.org
Reviewed-by: Victor Hsieh <victorhsieh@google.com>
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-01-16 02:18:16 +08:00
|
|
|
case FS_IOC_READ_VERITY_METADATA:
|
2020-07-15 06:18:12 +08:00
|
|
|
case FS_IOC_GETFSLABEL:
|
|
|
|
case FS_IOC_SETFSLABEL:
|
2020-02-21 18:09:21 +08:00
|
|
|
case F2FS_IOC_GET_COMPRESS_BLOCKS:
|
2020-03-06 15:36:09 +08:00
|
|
|
case F2FS_IOC_RELEASE_COMPRESS_BLOCKS:
|
2020-03-06 14:35:33 +08:00
|
|
|
case F2FS_IOC_RESERVE_COMPRESS_BLOCKS:
|
2020-07-21 11:21:11 +08:00
|
|
|
case F2FS_IOC_SEC_TRIM_FILE:
|
2020-10-30 12:10:34 +08:00
|
|
|
case F2FS_IOC_GET_COMPRESS_OPTION:
|
2020-10-30 12:10:35 +08:00
|
|
|
case F2FS_IOC_SET_COMPRESS_OPTION:
|
2020-12-03 14:56:15 +08:00
|
|
|
case F2FS_IOC_DECOMPRESS_FILE:
|
|
|
|
case F2FS_IOC_COMPRESS_FILE:
|
2016-07-09 06:16:47 +08:00
|
|
|
break;
|
2013-02-04 22:41:41 +08:00
|
|
|
default:
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
2020-11-10 09:24:37 +08:00
|
|
|
return __f2fs_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
|
2013-02-04 22:41:41 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-02 16:09:44 +08:00
|
|
|
const struct file_operations f2fs_file_operations = {
|
2014-04-23 14:10:24 +08:00
|
|
|
.llseek = f2fs_llseek,
|
f2fs: support data compression
This patch tries to support compression in f2fs.
- New term named cluster is defined as basic unit of compression, file can
be divided into multiple clusters logically. One cluster includes 4 << n
(n >= 0) logical pages, compression size is also cluster size, each of
cluster can be compressed or not.
- In cluster metadata layout, one special flag is used to indicate cluster
is compressed one or normal one, for compressed cluster, following metadata
maps cluster to [1, 4 << n - 1] physical blocks, in where f2fs stores
data including compress header and compressed data.
- In order to eliminate write amplification during overwrite, F2FS only
support compression on write-once file, data can be compressed only when
all logical blocks in file are valid and cluster compress ratio is lower
than specified threshold.
- To enable compression on regular inode, there are three ways:
* chattr +c file
* chattr +c dir; touch dir/file
* mount w/ -o compress_extension=ext; touch file.ext
Compress metadata layout:
[Dnode Structure]
+-----------------------------------------------+
| cluster 1 | cluster 2 | ......... | cluster N |
+-----------------------------------------------+
. . . .
. . . .
. Compressed Cluster . . Normal Cluster .
+----------+---------+---------+---------+ +---------+---------+---------+---------+
|compr flag| block 1 | block 2 | block 3 | | block 1 | block 2 | block 3 | block 4 |
+----------+---------+---------+---------+ +---------+---------+---------+---------+
. .
. .
. .
+-------------+-------------+----------+----------------------------+
| data length | data chksum | reserved | compressed data |
+-------------+-------------+----------+----------------------------+
Changelog:
20190326:
- fix error handling of read_end_io().
- remove unneeded comments in f2fs_encrypt_one_page().
20190327:
- fix wrong use of f2fs_cluster_is_full() in f2fs_mpage_readpages().
- don't jump into loop directly to avoid uninitialized variables.
- add TODO tag in error path of f2fs_write_cache_pages().
20190328:
- fix wrong merge condition in f2fs_read_multi_pages().
- check compressed file in f2fs_post_read_required().
20190401
- allow overwrite on non-compressed cluster.
- check cluster meta before writing compressed data.
20190402
- don't preallocate blocks for compressed file.
- add lz4 compress algorithm
- process multiple post read works in one workqueue
Now f2fs supports processing post read work in multiple workqueue,
it shows low performance due to schedule overhead of multiple
workqueue executing orderly.
20190921
- compress: support buffered overwrite
C: compress cluster flag
V: valid block address
N: NEW_ADDR
One cluster contain 4 blocks
before overwrite after overwrite
- VVVV -> CVNN
- CVNN -> VVVV
- CVNN -> CVNN
- CVNN -> CVVV
- CVVV -> CVNN
- CVVV -> CVVV
20191029
- add kconfig F2FS_FS_COMPRESSION to isolate compression related
codes, add kconfig F2FS_FS_{LZO,LZ4} to cover backend algorithm.
note that: will remove lzo backend if Jaegeuk agreed that too.
- update codes according to Eric's comments.
20191101
- apply fixes from Jaegeuk
20191113
- apply fixes from Jaegeuk
- split workqueue for fsverity
20191216
- apply fixes from Jaegeuk
20200117
- fix to avoid NULL pointer dereference
[Jaegeuk Kim]
- add tracepoint for f2fs_{,de}compress_pages()
- fix many bugs and add some compression stats
- fix overwrite/mmap bugs
- address 32bit build error, reported by Geert.
- bug fixes when handling errors and i_compressed_blocks
Reported-by: <noreply@ellerman.id.au>
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
2019-11-01 18:07:14 +08:00
|
|
|
.read_iter = f2fs_file_read_iter,
|
2015-04-22 11:39:58 +08:00
|
|
|
.write_iter = f2fs_file_write_iter,
|
2023-04-13 18:17:11 +08:00
|
|
|
.iopoll = iocb_bio_iopoll,
|
2015-04-22 11:39:58 +08:00
|
|
|
.open = f2fs_file_open,
|
2014-12-06 06:37:37 +08:00
|
|
|
.release = f2fs_release_file,
|
2012-11-02 16:09:44 +08:00
|
|
|
.mmap = f2fs_file_mmap,
|
2017-07-25 10:46:29 +08:00
|
|
|
.flush = f2fs_file_flush,
|
2012-11-02 16:09:44 +08:00
|
|
|
.fsync = f2fs_sync_file,
|
|
|
|
.fallocate = f2fs_fallocate,
|
|
|
|
.unlocked_ioctl = f2fs_ioctl,
|
2013-02-04 22:41:41 +08:00
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
|
.compat_ioctl = f2fs_compat_ioctl,
|
|
|
|
#endif
|
2023-05-22 21:50:06 +08:00
|
|
|
.splice_read = f2fs_file_splice_read,
|
2014-04-05 16:27:08 +08:00
|
|
|
.splice_write = iter_file_splice_write,
|
2021-08-03 12:22:45 +08:00
|
|
|
.fadvise = f2fs_file_fadvise,
|
2012-11-02 16:09:44 +08:00
|
|
|
};
|