mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge android-4.14 (73421a4) into msm-4.14
* refs/heads/tmp-73421a4: Revert "f2fs: let discard thread wait a little longer if dev is busy" Revert "f2fs: clean up with is_valid_blkaddr()" Revert "f2fs: fix race in between GC and atomic open" treewide: Use array_size in f2fs_kvzalloc() treewide: Use array_size() in f2fs_kzalloc() treewide: Use array_size() in f2fs_kmalloc() overflow.h: Add allocation size calculation helpers f2fs: fix to clear FI_VOLATILE_FILE correctly f2fs: let sync node IO interrupt async one f2fs: don't change wbc->sync_mode f2fs: fix to update mtime correctly fs: f2fs: insert space around that ':' and ', ' fs: f2fs: add missing blank lines after declarations fs: f2fs: changed variable type of offset "unsigned" to "loff_t" f2fs: clean up symbol namespace f2fs: make set_de_type() static f2fs: make __f2fs_write_data_pages() static f2fs: fix to avoid accessing cross the boundary f2fs: fix to let caller retry allocating block address disable loading f2fs module on PAGE_SIZE > 4KB f2fs: fix error path of move_data_page f2fs: don't drop dentry pages after fs shutdown f2fs: fix to avoid race during access gc_thread pointer f2fs: clean up with clear_radix_tree_dirty_tag f2fs: fix to don't trigger writeback during recovery f2fs: clear discard_wake earlier f2fs: let discard thread wait a little longer if dev is busy f2fs: avoid stucking GC due to atomic write f2fs: introduce sbi->gc_mode to determine the policy f2fs: keep migration IO order in LFS mode f2fs: fix to wait page writeback during revoking atomic write f2fs: Fix deadlock in shutdown ioctl f2fs: detect synchronous writeback more earlier mm: remove nr_pages argument from pagevec_lookup_{,range}_tag() ceph: use pagevec_lookup_range_nr_tag() mm: add variant of pagevec_lookup_range_tag() taking number of pages mm: use pagevec_lookup_range_tag() in write_cache_pages() mm: use pagevec_lookup_range_tag() in __filemap_fdatawait_range() nilfs2: use pagevec_lookup_range_tag() gfs2: use pagevec_lookup_range_tag() f2fs: use find_get_pages_tag() for looking up single page f2fs: simplify page iteration loops f2fs: use pagevec_lookup_range_tag() ext4: use pagevec_lookup_range_tag() ceph: use pagevec_lookup_range_tag() btrfs: use pagevec_lookup_range_tag() mm: implement find_get_pages_range_tag() f2fs: clean up with is_valid_blkaddr() f2fs: fix to initialize min_mtime with ULLONG_MAX f2fs: fix to let checkpoint guarantee atomic page persistence f2fs: fix to initialize i_current_depth according to inode type Revert "f2fs: add ovp valid_blocks check for bg gc victim to fg_gc" f2fs: don't drop any page on f2fs_cp_error() case f2fs: fix spelling mistake: "extenstion" -> "extension" f2fs: enhance sanity_check_raw_super() to avoid potential overflows f2fs: treat volatile file's data as hot one f2fs: introduce release_discard_addr() for cleanup f2fs: fix potential overflow f2fs: rename dio_rwsem to i_gc_rwsem f2fs: move mnt_want_write_file after range check f2fs: fix missing clear FI_NO_PREALLOC in some error case f2fs: enforce fsync_mode=strict for renamed directory f2fs: sanity check for total valid node blocks f2fs: sanity check on sit entry f2fs: avoid bug_on on corrupted inode f2fs: give message and set need_fsck given broken node id f2fs: clean up commit_inmem_pages() f2fs: do not check F2FS_INLINE_DOTS in recover f2fs: remove duplicated dquot_initialize and fix error handling f2fs: fix to detect failure of dquot_initialize f2fs: stop issue discard if something wrong with f2fs f2fs: fix return value in f2fs_ioc_commit_atomic_write f2fs: allocate hot_data for atomic write more strictly f2fs: check if inmem_pages list is empty correctly f2fs: fix race in between GC and atomic open f2fs: change le32 to le16 of f2fs_inode->i_extra_size f2fs: check cur_valid_map_mir & raw_sit block count when flush sit entries f2fs: correct return value of f2fs_trim_fs f2fs: fix to show missing bits in FS_IOC_GETFLAGS f2fs: remove unneeded F2FS_PROJINHERIT_FL f2fs: don't use GFP_ZERO for page caches f2fs: issue all big range discards in umount process f2fs: remove redundant block plug f2fs: remove unmatched zero_user_segment when convert inline dentry f2fs: introduce private inode status mapping fscrypt: log the crypto algorithm implementations fscrypt: add Speck128/256 support fscrypt: only derive the needed portion of the key fscrypt: separate key lookup from key derivation fscrypt: use a common logging function fscrypt: remove internal key size constants fscrypt: remove unnecessary check for non-logon key type fscrypt: make fscrypt_operations.max_namelen an integer fscrypt: drop empty name check from fname_decrypt() fscrypt: drop max_namelen check from fname_decrypt() fscrypt: don't special-case EOPNOTSUPP from fscrypt_get_encryption_info() fscrypt: don't clear flags on crypto transform fscrypt: remove stale comment from fscrypt_d_revalidate() fscrypt: remove error messages for skcipher_request_alloc() failure fscrypt: remove unnecessary NULL check when allocating skcipher fscrypt: clean up after fscrypt_prepare_lookup() conversions ubifs: switch to fscrypt_prepare_lookup() ext4: switch to fscrypt_prepare_lookup() fscrypt: use unbound workqueue for decryption Conflicts: fs/crypto/keyinfo.c fs/ext4/super.c fs/f2fs/checkpoint.c fs/f2fs/data.c fs/f2fs/f2fs.h fs/f2fs/file.c fs/f2fs/gc.c fs/f2fs/inline.c fs/f2fs/inode.c fs/f2fs/node.c fs/f2fs/recovery.c fs/f2fs/segment.c fs/f2fs/super.c include/linux/fscrypt_supp.h include/linux/overflow.h Extra changes were required in below files due to hard conflicts against HW based FBE: fs/crypto/fscrypt_ice.c fs/crypto/fscrypt_ice.h fs/crypto/fscrypt_private.h fs/crypto/keyinfo.c Change-Id: I01d788e7cd36539f6228742c99820a94a2cc5e46 Signed-off-by: Blagovest Kolenichev <bkolenichev@codeaurora.org>
This commit is contained in:
commit
5c033b4894
626
Documentation/filesystems/fscrypt.rst
Normal file
626
Documentation/filesystems/fscrypt.rst
Normal file
@ -0,0 +1,626 @@
|
||||
=====================================
|
||||
Filesystem-level encryption (fscrypt)
|
||||
=====================================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
fscrypt is a library which filesystems can hook into to support
|
||||
transparent encryption of files and directories.
|
||||
|
||||
Note: "fscrypt" in this document refers to the kernel-level portion,
|
||||
implemented in ``fs/crypto/``, as opposed to the userspace tool
|
||||
`fscrypt <https://github.com/google/fscrypt>`_. This document only
|
||||
covers the kernel-level portion. For command-line examples of how to
|
||||
use encryption, see the documentation for the userspace tool `fscrypt
|
||||
<https://github.com/google/fscrypt>`_. Also, it is recommended to use
|
||||
the fscrypt userspace tool, or other existing userspace tools such as
|
||||
`fscryptctl <https://github.com/google/fscryptctl>`_ or `Android's key
|
||||
management system
|
||||
<https://source.android.com/security/encryption/file-based>`_, over
|
||||
using the kernel's API directly. Using existing tools reduces the
|
||||
chance of introducing your own security bugs. (Nevertheless, for
|
||||
completeness this documentation covers the kernel's API anyway.)
|
||||
|
||||
Unlike dm-crypt, fscrypt operates at the filesystem level rather than
|
||||
at the block device level. This allows it to encrypt different files
|
||||
with different keys and to have unencrypted files on the same
|
||||
filesystem. This is useful for multi-user systems where each user's
|
||||
data-at-rest needs to be cryptographically isolated from the others.
|
||||
However, except for filenames, fscrypt does not encrypt filesystem
|
||||
metadata.
|
||||
|
||||
Unlike eCryptfs, which is a stacked filesystem, fscrypt is integrated
|
||||
directly into supported filesystems --- currently ext4, F2FS, and
|
||||
UBIFS. This allows encrypted files to be read and written without
|
||||
caching both the decrypted and encrypted pages in the pagecache,
|
||||
thereby nearly halving the memory used and bringing it in line with
|
||||
unencrypted files. Similarly, half as many dentries and inodes are
|
||||
needed. eCryptfs also limits encrypted filenames to 143 bytes,
|
||||
causing application compatibility issues; fscrypt allows the full 255
|
||||
bytes (NAME_MAX). Finally, unlike eCryptfs, the fscrypt API can be
|
||||
used by unprivileged users, with no need to mount anything.
|
||||
|
||||
fscrypt does not support encrypting files in-place. Instead, it
|
||||
supports marking an empty directory as encrypted. Then, after
|
||||
userspace provides the key, all regular files, directories, and
|
||||
symbolic links created in that directory tree are transparently
|
||||
encrypted.
|
||||
|
||||
Threat model
|
||||
============
|
||||
|
||||
Offline attacks
|
||||
---------------
|
||||
|
||||
Provided that userspace chooses a strong encryption key, fscrypt
|
||||
protects the confidentiality of file contents and filenames in the
|
||||
event of a single point-in-time permanent offline compromise of the
|
||||
block device content. fscrypt does not protect the confidentiality of
|
||||
non-filename metadata, e.g. file sizes, file permissions, file
|
||||
timestamps, and extended attributes. Also, the existence and location
|
||||
of holes (unallocated blocks which logically contain all zeroes) in
|
||||
files is not protected.
|
||||
|
||||
fscrypt is not guaranteed to protect confidentiality or authenticity
|
||||
if an attacker is able to manipulate the filesystem offline prior to
|
||||
an authorized user later accessing the filesystem.
|
||||
|
||||
Online attacks
|
||||
--------------
|
||||
|
||||
fscrypt (and storage encryption in general) can only provide limited
|
||||
protection, if any at all, against online attacks. In detail:
|
||||
|
||||
fscrypt is only resistant to side-channel attacks, such as timing or
|
||||
electromagnetic attacks, to the extent that the underlying Linux
|
||||
Cryptographic API algorithms are. If a vulnerable algorithm is used,
|
||||
such as a table-based implementation of AES, it may be possible for an
|
||||
attacker to mount a side channel attack against the online system.
|
||||
Side channel attacks may also be mounted against applications
|
||||
consuming decrypted data.
|
||||
|
||||
After an encryption key has been provided, fscrypt is not designed to
|
||||
hide the plaintext file contents or filenames from other users on the
|
||||
same system, regardless of the visibility of the keyring key.
|
||||
Instead, existing access control mechanisms such as file mode bits,
|
||||
POSIX ACLs, LSMs, or mount namespaces should be used for this purpose.
|
||||
Also note that as long as the encryption keys are *anywhere* in
|
||||
memory, an online attacker can necessarily compromise them by mounting
|
||||
a physical attack or by exploiting any kernel security vulnerability
|
||||
which provides an arbitrary memory read primitive.
|
||||
|
||||
While it is ostensibly possible to "evict" keys from the system,
|
||||
recently accessed encrypted files will remain accessible at least
|
||||
until the filesystem is unmounted or the VFS caches are dropped, e.g.
|
||||
using ``echo 2 > /proc/sys/vm/drop_caches``. Even after that, if the
|
||||
RAM is compromised before being powered off, it will likely still be
|
||||
possible to recover portions of the plaintext file contents, if not
|
||||
some of the encryption keys as well. (Since Linux v4.12, all
|
||||
in-kernel keys related to fscrypt are sanitized before being freed.
|
||||
However, userspace would need to do its part as well.)
|
||||
|
||||
Currently, fscrypt does not prevent a user from maliciously providing
|
||||
an incorrect key for another user's existing encrypted files. A
|
||||
protection against this is planned.
|
||||
|
||||
Key hierarchy
|
||||
=============
|
||||
|
||||
Master Keys
|
||||
-----------
|
||||
|
||||
Each encrypted directory tree is protected by a *master key*. Master
|
||||
keys can be up to 64 bytes long, and must be at least as long as the
|
||||
greater of the key length needed by the contents and filenames
|
||||
encryption modes being used. For example, if AES-256-XTS is used for
|
||||
contents encryption, the master key must be 64 bytes (512 bits). Note
|
||||
that the XTS mode is defined to require a key twice as long as that
|
||||
required by the underlying block cipher.
|
||||
|
||||
To "unlock" an encrypted directory tree, userspace must provide the
|
||||
appropriate master key. There can be any number of master keys, each
|
||||
of which protects any number of directory trees on any number of
|
||||
filesystems.
|
||||
|
||||
Userspace should generate master keys either using a cryptographically
|
||||
secure random number generator, or by using a KDF (Key Derivation
|
||||
Function). Note that whenever a KDF is used to "stretch" a
|
||||
lower-entropy secret such as a passphrase, it is critical that a KDF
|
||||
designed for this purpose be used, such as scrypt, PBKDF2, or Argon2.
|
||||
|
||||
Per-file keys
|
||||
-------------
|
||||
|
||||
Master keys are not used to encrypt file contents or names directly.
|
||||
Instead, a unique key is derived for each encrypted file, including
|
||||
each regular file, directory, and symbolic link. This has several
|
||||
advantages:
|
||||
|
||||
- In cryptosystems, the same key material should never be used for
|
||||
different purposes. Using the master key as both an XTS key for
|
||||
contents encryption and as a CTS-CBC key for filenames encryption
|
||||
would violate this rule.
|
||||
- Per-file keys simplify the choice of IVs (Initialization Vectors)
|
||||
for contents encryption. Without per-file keys, to ensure IV
|
||||
uniqueness both the inode and logical block number would need to be
|
||||
encoded in the IVs. This would make it impossible to renumber
|
||||
inodes, which e.g. ``resize2fs`` can do when resizing an ext4
|
||||
filesystem. With per-file keys, it is sufficient to encode just the
|
||||
logical block number in the IVs.
|
||||
- Per-file keys strengthen the encryption of filenames, where IVs are
|
||||
reused out of necessity. With a unique key per directory, IV reuse
|
||||
is limited to within a single directory.
|
||||
- Per-file keys allow individual files to be securely erased simply by
|
||||
securely erasing their keys. (Not yet implemented.)
|
||||
|
||||
A KDF (Key Derivation Function) is used to derive per-file keys from
|
||||
the master key. This is done instead of wrapping a randomly-generated
|
||||
key for each file because it reduces the size of the encryption xattr,
|
||||
which for some filesystems makes the xattr more likely to fit in-line
|
||||
in the filesystem's inode table. With a KDF, only a 16-byte nonce is
|
||||
required --- long enough to make key reuse extremely unlikely. A
|
||||
wrapped key, on the other hand, would need to be up to 64 bytes ---
|
||||
the length of an AES-256-XTS key. Furthermore, currently there is no
|
||||
requirement to support unlocking a file with multiple alternative
|
||||
master keys or to support rotating master keys. Instead, the master
|
||||
keys may be wrapped in userspace, e.g. as done by the `fscrypt
|
||||
<https://github.com/google/fscrypt>`_ tool.
|
||||
|
||||
The current KDF encrypts the master key using the 16-byte nonce as an
|
||||
AES-128-ECB key. The output is used as the derived key. If the
|
||||
output is longer than needed, then it is truncated to the needed
|
||||
length. Truncation is the norm for directories and symlinks, since
|
||||
those use the CTS-CBC encryption mode which requires a key half as
|
||||
long as that required by the XTS encryption mode.
|
||||
|
||||
Note: this KDF meets the primary security requirement, which is to
|
||||
produce unique derived keys that preserve the entropy of the master
|
||||
key, assuming that the master key is already a good pseudorandom key.
|
||||
However, it is nonstandard and has some problems such as being
|
||||
reversible, so it is generally considered to be a mistake! It may be
|
||||
replaced with HKDF or another more standard KDF in the future.
|
||||
|
||||
Encryption modes and usage
|
||||
==========================
|
||||
|
||||
fscrypt allows one encryption mode to be specified for file contents
|
||||
and one encryption mode to be specified for filenames. Different
|
||||
directory trees are permitted to use different encryption modes.
|
||||
Currently, the following pairs of encryption modes are supported:
|
||||
|
||||
- AES-256-XTS for contents and AES-256-CTS-CBC for filenames
|
||||
- AES-128-CBC for contents and AES-128-CTS-CBC for filenames
|
||||
- Speck128/256-XTS for contents and Speck128/256-CTS-CBC for filenames
|
||||
|
||||
It is strongly recommended to use AES-256-XTS for contents encryption.
|
||||
AES-128-CBC was added only for low-powered embedded devices with
|
||||
crypto accelerators such as CAAM or CESA that do not support XTS.
|
||||
|
||||
Similarly, Speck128/256 support was only added for older or low-end
|
||||
CPUs which cannot do AES fast enough -- especially ARM CPUs which have
|
||||
NEON instructions but not the Cryptography Extensions -- and for which
|
||||
it would not otherwise be feasible to use encryption at all. It is
|
||||
not recommended to use Speck on CPUs that have AES instructions.
|
||||
Speck support is only available if it has been enabled in the crypto
|
||||
API via CONFIG_CRYPTO_SPECK. Also, on ARM platforms, to get
|
||||
acceptable performance CONFIG_CRYPTO_SPECK_NEON must be enabled.
|
||||
|
||||
New encryption modes can be added relatively easily, without changes
|
||||
to individual filesystems. However, authenticated encryption (AE)
|
||||
modes are not currently supported because of the difficulty of dealing
|
||||
with ciphertext expansion.
|
||||
|
||||
For file contents, each filesystem block is encrypted independently.
|
||||
Currently, only the case where the filesystem block size is equal to
|
||||
the system's page size (usually 4096 bytes) is supported. With the
|
||||
XTS mode of operation (recommended), the logical block number within
|
||||
the file is used as the IV. With the CBC mode of operation (not
|
||||
recommended), ESSIV is used; specifically, the IV for CBC is the
|
||||
logical block number encrypted with AES-256, where the AES-256 key is
|
||||
the SHA-256 hash of the inode's data encryption key.
|
||||
|
||||
For filenames, the full filename is encrypted at once. Because of the
|
||||
requirements to retain support for efficient directory lookups and
|
||||
filenames of up to 255 bytes, a constant initialization vector (IV) is
|
||||
used. However, each encrypted directory uses a unique key, which
|
||||
limits IV reuse to within a single directory. Note that IV reuse in
|
||||
the context of CTS-CBC encryption means that when the original
|
||||
filenames share a common prefix at least as long as the cipher block
|
||||
size (16 bytes for AES), the corresponding encrypted filenames will
|
||||
also share a common prefix. This is undesirable; it may be fixed in
|
||||
the future by switching to an encryption mode that is a strong
|
||||
pseudorandom permutation on arbitrary-length messages, e.g. the HEH
|
||||
(Hash-Encrypt-Hash) mode.
|
||||
|
||||
Since filenames are encrypted with the CTS-CBC mode of operation, the
|
||||
plaintext and ciphertext filenames need not be multiples of the AES
|
||||
block size, i.e. 16 bytes. However, the minimum size that can be
|
||||
encrypted is 16 bytes, so shorter filenames are NUL-padded to 16 bytes
|
||||
before being encrypted. In addition, to reduce leakage of filename
|
||||
lengths via their ciphertexts, all filenames are NUL-padded to the
|
||||
next 4, 8, 16, or 32-byte boundary (configurable). 32 is recommended
|
||||
since this provides the best confidentiality, at the cost of making
|
||||
directory entries consume slightly more space. Note that since NUL
|
||||
(``\0``) is not otherwise a valid character in filenames, the padding
|
||||
will never produce duplicate plaintexts.
|
||||
|
||||
Symbolic link targets are considered a type of filename and are
|
||||
encrypted in the same way as filenames in directory entries. Each
|
||||
symlink also uses a unique key; hence, the hardcoded IV is not a
|
||||
problem for symlinks.
|
||||
|
||||
User API
|
||||
========
|
||||
|
||||
Setting an encryption policy
|
||||
----------------------------
|
||||
|
||||
The FS_IOC_SET_ENCRYPTION_POLICY ioctl sets an encryption policy on an
|
||||
empty directory or verifies that a directory or regular file already
|
||||
has the specified encryption policy. It takes in a pointer to a
|
||||
:c:type:`struct fscrypt_policy`, defined as follows::
|
||||
|
||||
#define FS_KEY_DESCRIPTOR_SIZE 8
|
||||
|
||||
struct fscrypt_policy {
|
||||
__u8 version;
|
||||
__u8 contents_encryption_mode;
|
||||
__u8 filenames_encryption_mode;
|
||||
__u8 flags;
|
||||
__u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
};
|
||||
|
||||
This structure must be initialized as follows:
|
||||
|
||||
- ``version`` must be 0.
|
||||
|
||||
- ``contents_encryption_mode`` and ``filenames_encryption_mode`` must
|
||||
be set to constants from ``<linux/fs.h>`` which identify the
|
||||
encryption modes to use. If unsure, use
|
||||
FS_ENCRYPTION_MODE_AES_256_XTS (1) for ``contents_encryption_mode``
|
||||
and FS_ENCRYPTION_MODE_AES_256_CTS (4) for
|
||||
``filenames_encryption_mode``.
|
||||
|
||||
- ``flags`` must be set to a value from ``<linux/fs.h>`` which
|
||||
identifies the amount of NUL-padding to use when encrypting
|
||||
filenames. If unsure, use FS_POLICY_FLAGS_PAD_32 (0x3).
|
||||
|
||||
- ``master_key_descriptor`` specifies how to find the master key in
|
||||
the keyring; see `Adding keys`_. It is up to userspace to choose a
|
||||
unique ``master_key_descriptor`` for each master key. The e4crypt
|
||||
and fscrypt tools use the first 8 bytes of
|
||||
``SHA-512(SHA-512(master_key))``, but this particular scheme is not
|
||||
required. Also, the master key need not be in the keyring yet when
|
||||
FS_IOC_SET_ENCRYPTION_POLICY is executed. However, it must be added
|
||||
before any files can be created in the encrypted directory.
|
||||
|
||||
If the file is not yet encrypted, then FS_IOC_SET_ENCRYPTION_POLICY
|
||||
verifies that the file is an empty directory. If so, the specified
|
||||
encryption policy is assigned to the directory, turning it into an
|
||||
encrypted directory. After that, and after providing the
|
||||
corresponding master key as described in `Adding keys`_, all regular
|
||||
files, directories (recursively), and symlinks created in the
|
||||
directory will be encrypted, inheriting the same encryption policy.
|
||||
The filenames in the directory's entries will be encrypted as well.
|
||||
|
||||
Alternatively, if the file is already encrypted, then
|
||||
FS_IOC_SET_ENCRYPTION_POLICY validates that the specified encryption
|
||||
policy exactly matches the actual one. If they match, then the ioctl
|
||||
returns 0. Otherwise, it fails with EEXIST. This works on both
|
||||
regular files and directories, including nonempty directories.
|
||||
|
||||
Note that the ext4 filesystem does not allow the root directory to be
|
||||
encrypted, even if it is empty. Users who want to encrypt an entire
|
||||
filesystem with one key should consider using dm-crypt instead.
|
||||
|
||||
FS_IOC_SET_ENCRYPTION_POLICY can fail with the following errors:
|
||||
|
||||
- ``EACCES``: the file is not owned by the process's uid, nor does the
|
||||
process have the CAP_FOWNER capability in a namespace with the file
|
||||
owner's uid mapped
|
||||
- ``EEXIST``: the file is already encrypted with an encryption policy
|
||||
different from the one specified
|
||||
- ``EINVAL``: an invalid encryption policy was specified (invalid
|
||||
version, mode(s), or flags)
|
||||
- ``ENOTDIR``: the file is unencrypted and is a regular file, not a
|
||||
directory
|
||||
- ``ENOTEMPTY``: the file is unencrypted and is a nonempty directory
|
||||
- ``ENOTTY``: this type of filesystem does not implement encryption
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with encryption
|
||||
support for this filesystem, or the filesystem superblock has not
|
||||
had encryption enabled on it. (For example, to use encryption on an
|
||||
ext4 filesystem, CONFIG_EXT4_ENCRYPTION must be enabled in the
|
||||
kernel config, and the superblock must have had the "encrypt"
|
||||
feature flag enabled using ``tune2fs -O encrypt`` or ``mkfs.ext4 -O
|
||||
encrypt``.)
|
||||
- ``EPERM``: this directory may not be encrypted, e.g. because it is
|
||||
the root directory of an ext4 filesystem
|
||||
- ``EROFS``: the filesystem is readonly
|
||||
|
||||
Getting an encryption policy
|
||||
----------------------------
|
||||
|
||||
The FS_IOC_GET_ENCRYPTION_POLICY ioctl retrieves the :c:type:`struct
|
||||
fscrypt_policy`, if any, for a directory or regular file. See above
|
||||
for the struct definition. No additional permissions are required
|
||||
beyond the ability to open the file.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_POLICY can fail with the following errors:
|
||||
|
||||
- ``EINVAL``: the file is encrypted, but it uses an unrecognized
|
||||
encryption context format
|
||||
- ``ENODATA``: the file is not encrypted
|
||||
- ``ENOTTY``: this type of filesystem does not implement encryption
|
||||
- ``EOPNOTSUPP``: the kernel was not configured with encryption
|
||||
support for this filesystem
|
||||
|
||||
Note: if you only need to know whether a file is encrypted or not, on
|
||||
most filesystems it is also possible to use the FS_IOC_GETFLAGS ioctl
|
||||
and check for FS_ENCRYPT_FL, or to use the statx() system call and
|
||||
check for STATX_ATTR_ENCRYPTED in stx_attributes.
|
||||
|
||||
Getting the per-filesystem salt
|
||||
-------------------------------
|
||||
|
||||
Some filesystems, such as ext4 and F2FS, also support the deprecated
|
||||
ioctl FS_IOC_GET_ENCRYPTION_PWSALT. This ioctl retrieves a randomly
|
||||
generated 16-byte value stored in the filesystem superblock. This
|
||||
value is intended to used as a salt when deriving an encryption key
|
||||
from a passphrase or other low-entropy user credential.
|
||||
|
||||
FS_IOC_GET_ENCRYPTION_PWSALT is deprecated. Instead, prefer to
|
||||
generate and manage any needed salt(s) in userspace.
|
||||
|
||||
Adding keys
|
||||
-----------
|
||||
|
||||
To provide a master key, userspace must add it to an appropriate
|
||||
keyring using the add_key() system call (see:
|
||||
``Documentation/security/keys/core.rst``). The key type must be
|
||||
"logon"; keys of this type are kept in kernel memory and cannot be
|
||||
read back by userspace. The key description must be "fscrypt:"
|
||||
followed by the 16-character lower case hex representation of the
|
||||
``master_key_descriptor`` that was set in the encryption policy. The
|
||||
key payload must conform to the following structure::
|
||||
|
||||
#define FS_MAX_KEY_SIZE 64
|
||||
|
||||
struct fscrypt_key {
|
||||
u32 mode;
|
||||
u8 raw[FS_MAX_KEY_SIZE];
|
||||
u32 size;
|
||||
};
|
||||
|
||||
``mode`` is ignored; just set it to 0. The actual key is provided in
|
||||
``raw`` with ``size`` indicating its size in bytes. That is, the
|
||||
bytes ``raw[0..size-1]`` (inclusive) are the actual key.
|
||||
|
||||
The key description prefix "fscrypt:" may alternatively be replaced
|
||||
with a filesystem-specific prefix such as "ext4:". However, the
|
||||
filesystem-specific prefixes are deprecated and should not be used in
|
||||
new programs.
|
||||
|
||||
There are several different types of keyrings in which encryption keys
|
||||
may be placed, such as a session keyring, a user session keyring, or a
|
||||
user keyring. Each key must be placed in a keyring that is "attached"
|
||||
to all processes that might need to access files encrypted with it, in
|
||||
the sense that request_key() will find the key. Generally, if only
|
||||
processes belonging to a specific user need to access a given
|
||||
encrypted directory and no session keyring has been installed, then
|
||||
that directory's key should be placed in that user's user session
|
||||
keyring or user keyring. Otherwise, a session keyring should be
|
||||
installed if needed, and the key should be linked into that session
|
||||
keyring, or in a keyring linked into that session keyring.
|
||||
|
||||
Note: introducing the complex visibility semantics of keyrings here
|
||||
was arguably a mistake --- especially given that by design, after any
|
||||
process successfully opens an encrypted file (thereby setting up the
|
||||
per-file key), possessing the keyring key is not actually required for
|
||||
any process to read/write the file until its in-memory inode is
|
||||
evicted. In the future there probably should be a way to provide keys
|
||||
directly to the filesystem instead, which would make the intended
|
||||
semantics clearer.
|
||||
|
||||
Access semantics
|
||||
================
|
||||
|
||||
With the key
|
||||
------------
|
||||
|
||||
With the encryption key, encrypted regular files, directories, and
|
||||
symlinks behave very similarly to their unencrypted counterparts ---
|
||||
after all, the encryption is intended to be transparent. However,
|
||||
astute users may notice some differences in behavior:
|
||||
|
||||
- Unencrypted files, or files encrypted with a different encryption
|
||||
policy (i.e. different key, modes, or flags), cannot be renamed or
|
||||
linked into an encrypted directory; see `Encryption policy
|
||||
enforcement`_. Attempts to do so will fail with EPERM. However,
|
||||
encrypted files can be renamed within an encrypted directory, or
|
||||
into an unencrypted directory.
|
||||
|
||||
- Direct I/O is not supported on encrypted files. Attempts to use
|
||||
direct I/O on such files will fall back to buffered I/O.
|
||||
|
||||
- The fallocate operations FALLOC_FL_COLLAPSE_RANGE,
|
||||
FALLOC_FL_INSERT_RANGE, and FALLOC_FL_ZERO_RANGE are not supported
|
||||
on encrypted files and will fail with EOPNOTSUPP.
|
||||
|
||||
- Online defragmentation of encrypted files is not supported. The
|
||||
EXT4_IOC_MOVE_EXT and F2FS_IOC_MOVE_RANGE ioctls will fail with
|
||||
EOPNOTSUPP.
|
||||
|
||||
- The ext4 filesystem does not support data journaling with encrypted
|
||||
regular files. It will fall back to ordered data mode instead.
|
||||
|
||||
- DAX (Direct Access) is not supported on encrypted files.
|
||||
|
||||
- The st_size of an encrypted symlink will not necessarily give the
|
||||
length of the symlink target as required by POSIX. It will actually
|
||||
give the length of the ciphertext, which will be slightly longer
|
||||
than the plaintext due to NUL-padding and an extra 2-byte overhead.
|
||||
|
||||
- The maximum length of an encrypted symlink is 2 bytes shorter than
|
||||
the maximum length of an unencrypted symlink. For example, on an
|
||||
EXT4 filesystem with a 4K block size, unencrypted symlinks can be up
|
||||
to 4095 bytes long, while encrypted symlinks can only be up to 4093
|
||||
bytes long (both lengths excluding the terminating null).
|
||||
|
||||
Note that mmap *is* supported. This is possible because the pagecache
|
||||
for an encrypted file contains the plaintext, not the ciphertext.
|
||||
|
||||
Without the key
|
||||
---------------
|
||||
|
||||
Some filesystem operations may be performed on encrypted regular
|
||||
files, directories, and symlinks even before their encryption key has
|
||||
been provided:
|
||||
|
||||
- File metadata may be read, e.g. using stat().
|
||||
|
||||
- Directories may be listed, in which case the filenames will be
|
||||
listed in an encoded form derived from their ciphertext. The
|
||||
current encoding algorithm is described in `Filename hashing and
|
||||
encoding`_. The algorithm is subject to change, but it is
|
||||
guaranteed that the presented filenames will be no longer than
|
||||
NAME_MAX bytes, will not contain the ``/`` or ``\0`` characters, and
|
||||
will uniquely identify directory entries.
|
||||
|
||||
The ``.`` and ``..`` directory entries are special. They are always
|
||||
present and are not encrypted or encoded.
|
||||
|
||||
- Files may be deleted. That is, nondirectory files may be deleted
|
||||
with unlink() as usual, and empty directories may be deleted with
|
||||
rmdir() as usual. Therefore, ``rm`` and ``rm -r`` will work as
|
||||
expected.
|
||||
|
||||
- Symlink targets may be read and followed, but they will be presented
|
||||
in encrypted form, similar to filenames in directories. Hence, they
|
||||
are unlikely to point to anywhere useful.
|
||||
|
||||
Without the key, regular files cannot be opened or truncated.
|
||||
Attempts to do so will fail with ENOKEY. This implies that any
|
||||
regular file operations that require a file descriptor, such as
|
||||
read(), write(), mmap(), fallocate(), and ioctl(), are also forbidden.
|
||||
|
||||
Also without the key, files of any type (including directories) cannot
|
||||
be created or linked into an encrypted directory, nor can a name in an
|
||||
encrypted directory be the source or target of a rename, nor can an
|
||||
O_TMPFILE temporary file be created in an encrypted directory. All
|
||||
such operations will fail with ENOKEY.
|
||||
|
||||
It is not currently possible to backup and restore encrypted files
|
||||
without the encryption key. This would require special APIs which
|
||||
have not yet been implemented.
|
||||
|
||||
Encryption policy enforcement
|
||||
=============================
|
||||
|
||||
After an encryption policy has been set on a directory, all regular
|
||||
files, directories, and symbolic links created in that directory
|
||||
(recursively) will inherit that encryption policy. Special files ---
|
||||
that is, named pipes, device nodes, and UNIX domain sockets --- will
|
||||
not be encrypted.
|
||||
|
||||
Except for those special files, it is forbidden to have unencrypted
|
||||
files, or files encrypted with a different encryption policy, in an
|
||||
encrypted directory tree. Attempts to link or rename such a file into
|
||||
an encrypted directory will fail with EPERM. This is also enforced
|
||||
during ->lookup() to provide limited protection against offline
|
||||
attacks that try to disable or downgrade encryption in known locations
|
||||
where applications may later write sensitive data. It is recommended
|
||||
that systems implementing a form of "verified boot" take advantage of
|
||||
this by validating all top-level encryption policies prior to access.
|
||||
|
||||
Implementation details
|
||||
======================
|
||||
|
||||
Encryption context
|
||||
------------------
|
||||
|
||||
An encryption policy is represented on-disk by a :c:type:`struct
|
||||
fscrypt_context`. It is up to individual filesystems to decide where
|
||||
to store it, but normally it would be stored in a hidden extended
|
||||
attribute. It should *not* be exposed by the xattr-related system
|
||||
calls such as getxattr() and setxattr() because of the special
|
||||
semantics of the encryption xattr. (In particular, there would be
|
||||
much confusion if an encryption policy were to be added to or removed
|
||||
from anything other than an empty directory.) The struct is defined
|
||||
as follows::
|
||||
|
||||
#define FS_KEY_DESCRIPTOR_SIZE 8
|
||||
#define FS_KEY_DERIVATION_NONCE_SIZE 16
|
||||
|
||||
struct fscrypt_context {
|
||||
u8 format;
|
||||
u8 contents_encryption_mode;
|
||||
u8 filenames_encryption_mode;
|
||||
u8 flags;
|
||||
u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE];
|
||||
u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
|
||||
};
|
||||
|
||||
Note that :c:type:`struct fscrypt_context` contains the same
|
||||
information as :c:type:`struct fscrypt_policy` (see `Setting an
|
||||
encryption policy`_), except that :c:type:`struct fscrypt_context`
|
||||
also contains a nonce. The nonce is randomly generated by the kernel
|
||||
and is used to derive the inode's encryption key as described in
|
||||
`Per-file keys`_.
|
||||
|
||||
Data path changes
|
||||
-----------------
|
||||
|
||||
For the read path (->readpage()) of regular files, filesystems can
|
||||
read the ciphertext into the page cache and decrypt it in-place. The
|
||||
page lock must be held until decryption has finished, to prevent the
|
||||
page from becoming visible to userspace prematurely.
|
||||
|
||||
For the write path (->writepage()) of regular files, filesystems
|
||||
cannot encrypt data in-place in the page cache, since the cached
|
||||
plaintext must be preserved. Instead, filesystems must encrypt into a
|
||||
temporary buffer or "bounce page", then write out the temporary
|
||||
buffer. Some filesystems, such as UBIFS, already use temporary
|
||||
buffers regardless of encryption. Other filesystems, such as ext4 and
|
||||
F2FS, have to allocate bounce pages specially for encryption.
|
||||
|
||||
Filename hashing and encoding
|
||||
-----------------------------
|
||||
|
||||
Modern filesystems accelerate directory lookups by using indexed
|
||||
directories. An indexed directory is organized as a tree keyed by
|
||||
filename hashes. When a ->lookup() is requested, the filesystem
|
||||
normally hashes the filename being looked up so that it can quickly
|
||||
find the corresponding directory entry, if any.
|
||||
|
||||
With encryption, lookups must be supported and efficient both with and
|
||||
without the encryption key. Clearly, it would not work to hash the
|
||||
plaintext filenames, since the plaintext filenames are unavailable
|
||||
without the key. (Hashing the plaintext filenames would also make it
|
||||
impossible for the filesystem's fsck tool to optimize encrypted
|
||||
directories.) Instead, filesystems hash the ciphertext filenames,
|
||||
i.e. the bytes actually stored on-disk in the directory entries. When
|
||||
asked to do a ->lookup() with the key, the filesystem just encrypts
|
||||
the user-supplied name to get the ciphertext.
|
||||
|
||||
Lookups without the key are more complicated. The raw ciphertext may
|
||||
contain the ``\0`` and ``/`` characters, which are illegal in
|
||||
filenames. Therefore, readdir() must base64-encode the ciphertext for
|
||||
presentation. For most filenames, this works fine; on ->lookup(), the
|
||||
filesystem just base64-decodes the user-supplied name to get back to
|
||||
the raw ciphertext.
|
||||
|
||||
However, for very long filenames, base64 encoding would cause the
|
||||
filename length to exceed NAME_MAX. To prevent this, readdir()
|
||||
actually presents long filenames in an abbreviated form which encodes
|
||||
a strong "hash" of the ciphertext filename, along with the optional
|
||||
filesystem-specific hash(es) needed for directory lookups. This
|
||||
allows the filesystem to still, with a high degree of confidence, map
|
||||
the filename given in ->lookup() back to a particular directory entry
|
||||
that was previously listed by readdir(). See :c:type:`struct
|
||||
fscrypt_digested_name` in the source for more details.
|
||||
|
||||
Note that the precise way that filenames are presented to userspace
|
||||
without the key is subject to change in the future. It is only meant
|
||||
as a way to temporarily present valid filenames so that commands like
|
||||
``rm -r`` work as expected on encrypted directories.
|
@ -548,14 +548,14 @@ static int adjoin(struct dm_table *table, struct dm_target *ti)
|
||||
* On the other hand, dm-switch needs to process bulk data using messages and
|
||||
* excessive use of GFP_NOIO could cause trouble.
|
||||
*/
|
||||
static char **realloc_argv(unsigned *array_size, char **old_argv)
|
||||
static char **realloc_argv(unsigned *size, char **old_argv)
|
||||
{
|
||||
char **argv;
|
||||
unsigned new_size;
|
||||
gfp_t gfp;
|
||||
|
||||
if (*array_size) {
|
||||
new_size = *array_size * 2;
|
||||
if (*size) {
|
||||
new_size = *size * 2;
|
||||
gfp = GFP_KERNEL;
|
||||
} else {
|
||||
new_size = 8;
|
||||
@ -563,8 +563,8 @@ static char **realloc_argv(unsigned *array_size, char **old_argv)
|
||||
}
|
||||
argv = kmalloc(new_size * sizeof(*argv), gfp);
|
||||
if (argv) {
|
||||
memcpy(argv, old_argv, *array_size * sizeof(*argv));
|
||||
*array_size = new_size;
|
||||
memcpy(argv, old_argv, *size * sizeof(*argv));
|
||||
*size = new_size;
|
||||
}
|
||||
|
||||
kfree(old_argv);
|
||||
|
@ -3819,8 +3819,8 @@ retry:
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
tag_pages_for_writeback(mapping, index, end);
|
||||
while (!done && !nr_to_write_done && (index <= end) &&
|
||||
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
|
||||
(nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag))) {
|
||||
unsigned i;
|
||||
|
||||
scanned = 1;
|
||||
@ -3830,11 +3830,6 @@ retry:
|
||||
if (!PagePrivate(page))
|
||||
continue;
|
||||
|
||||
if (!wbc->range_cyclic && page->index > end) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock(&mapping->private_lock);
|
||||
if (!PagePrivate(page)) {
|
||||
spin_unlock(&mapping->private_lock);
|
||||
@ -3966,8 +3961,8 @@ retry:
|
||||
tag_pages_for_writeback(mapping, index, end);
|
||||
done_index = index;
|
||||
while (!done && !nr_to_write_done && (index <= end) &&
|
||||
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
|
||||
(nr_pages = pagevec_lookup_range_tag(&pvec, mapping,
|
||||
&index, end, tag))) {
|
||||
unsigned i;
|
||||
|
||||
scanned = 1;
|
||||
@ -3992,12 +3987,6 @@ retry:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!wbc->range_cyclic && page->index > end) {
|
||||
done = 1;
|
||||
unlock_page(page);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wbc->sync_mode != WB_SYNC_NONE) {
|
||||
if (PageWriteback(page))
|
||||
flush_fn(data);
|
||||
|
@ -870,15 +870,10 @@ retry:
|
||||
max_pages = wsize >> PAGE_SHIFT;
|
||||
|
||||
get_more_pages:
|
||||
pvec_pages = min_t(unsigned, PAGEVEC_SIZE,
|
||||
max_pages - locked_pages);
|
||||
if (end - index < (u64)(pvec_pages - 1))
|
||||
pvec_pages = (unsigned)(end - index) + 1;
|
||||
|
||||
pvec_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
pvec_pages);
|
||||
dout("pagevec_lookup_tag got %d\n", pvec_pages);
|
||||
pvec_pages = pagevec_lookup_range_nr_tag(&pvec, mapping, &index,
|
||||
end, PAGECACHE_TAG_DIRTY,
|
||||
max_pages - locked_pages);
|
||||
dout("pagevec_lookup_range_tag got %d\n", pvec_pages);
|
||||
if (!pvec_pages && !locked_pages)
|
||||
break;
|
||||
for (i = 0; i < pvec_pages && locked_pages < max_pages; i++) {
|
||||
@ -896,16 +891,6 @@ get_more_pages:
|
||||
unlock_page(page);
|
||||
continue;
|
||||
}
|
||||
if (page->index > end) {
|
||||
dout("end of range %p\n", page);
|
||||
/* can't be range_cyclic (1st pass) because
|
||||
* end == -1 in that case. */
|
||||
stop = true;
|
||||
if (ceph_wbc.head_snapc)
|
||||
done = true;
|
||||
unlock_page(page);
|
||||
break;
|
||||
}
|
||||
if (strip_unit_end && (page->index > strip_unit_end)) {
|
||||
dout("end of strip unit %p\n", page);
|
||||
unlock_page(page);
|
||||
@ -1177,8 +1162,7 @@ release_pvec_pages:
|
||||
index = 0;
|
||||
while ((index <= end) &&
|
||||
(nr = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_WRITEBACK,
|
||||
PAGEVEC_SIZE))) {
|
||||
PAGECACHE_TAG_WRITEBACK))) {
|
||||
for (i = 0; i < nr; i++) {
|
||||
page = pvec.pages[i];
|
||||
if (page_snap_context(page) != snapc)
|
||||
|
@ -162,12 +162,8 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
||||
}
|
||||
|
||||
req = skcipher_request_alloc(tfm, gfp_flags);
|
||||
if (!req) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: crypto_request_alloc() failed\n",
|
||||
__func__);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
skcipher_request_set_callback(
|
||||
req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
@ -184,9 +180,10 @@ int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: crypto_skcipher_encrypt() returned %d\n",
|
||||
__func__, res);
|
||||
fscrypt_err(inode->i_sb,
|
||||
"%scryption failed for inode %lu, block %llu: %d",
|
||||
(rw == FS_DECRYPT ? "de" : "en"),
|
||||
inode->i_ino, lblk_num, res);
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
@ -332,7 +329,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this should eventually be an flag in d_flags */
|
||||
spin_lock(&dentry->d_lock);
|
||||
cached_with_key = dentry->d_flags & DCACHE_ENCRYPTED_WITH_KEY;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
@ -359,7 +355,6 @@ static int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
const struct dentry_operations fscrypt_d_ops = {
|
||||
.d_revalidate = fscrypt_d_revalidate,
|
||||
};
|
||||
EXPORT_SYMBOL(fscrypt_d_ops);
|
||||
|
||||
void fscrypt_restore_control_page(struct page *page)
|
||||
{
|
||||
@ -428,6 +423,27 @@ fail:
|
||||
return res;
|
||||
}
|
||||
|
||||
void fscrypt_msg(struct super_block *sb, const char *level,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
|
||||
DEFAULT_RATELIMIT_BURST);
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
if (!__ratelimit(&rs))
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
if (sb)
|
||||
printk("%sfscrypt (%s): %pV\n", level, sb->s_id, &vaf);
|
||||
else
|
||||
printk("%sfscrypt: %pV\n", level, &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* fscrypt_init() - Set up for fs encryption.
|
||||
*/
|
||||
|
@ -59,11 +59,8 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
|
||||
/* Set up the encryption request */
|
||||
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
||||
if (!req) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: skcipher_request_alloc() failed\n", __func__);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
@ -74,8 +71,9 @@ int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: Error (error code %d)\n", __func__, res);
|
||||
fscrypt_err(inode->i_sb,
|
||||
"Filename encryption failed for inode %lu: %d",
|
||||
inode->i_ino, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -96,23 +94,14 @@ static int fname_decrypt(struct inode *inode,
|
||||
struct skcipher_request *req = NULL;
|
||||
DECLARE_CRYPTO_WAIT(wait);
|
||||
struct scatterlist src_sg, dst_sg;
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
struct crypto_skcipher *tfm = ci->ci_ctfm;
|
||||
struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
|
||||
int res = 0;
|
||||
char iv[FS_CRYPTO_BLOCK_SIZE];
|
||||
unsigned lim;
|
||||
|
||||
lim = inode->i_sb->s_cop->max_namelen(inode);
|
||||
if (iname->len <= 0 || iname->len > lim)
|
||||
return -EIO;
|
||||
|
||||
/* Allocate request */
|
||||
req = skcipher_request_alloc(tfm, GFP_NOFS);
|
||||
if (!req) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: crypto_request_alloc() failed\n", __func__);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
}
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
@ -127,8 +116,9 @@ static int fname_decrypt(struct inode *inode,
|
||||
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
|
||||
skcipher_request_free(req);
|
||||
if (res < 0) {
|
||||
printk_ratelimited(KERN_ERR
|
||||
"%s: Error (error code %d)\n", __func__, res);
|
||||
fscrypt_err(inode->i_sb,
|
||||
"Filename decryption failed for inode %lu: %d",
|
||||
inode->i_ino, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -341,12 +331,12 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
|
||||
return 0;
|
||||
}
|
||||
ret = fscrypt_get_encryption_info(dir);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (dir->i_crypt_info) {
|
||||
if (!fscrypt_fname_encrypted_size(dir, iname->len,
|
||||
dir->i_sb->s_cop->max_namelen(dir),
|
||||
dir->i_sb->s_cop->max_namelen,
|
||||
&fname->crypto_buf.len))
|
||||
return -ENAMETOOLONG;
|
||||
fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
#include "fscrypt_ice.h"
|
||||
|
||||
extern int fscrypt_get_mode_key_size(int mode);
|
||||
|
||||
int fscrypt_using_hardware_encryption(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = inode->i_crypt_info;
|
||||
@ -21,6 +23,30 @@ int fscrypt_using_hardware_encryption(const struct inode *inode)
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_using_hardware_encryption);
|
||||
|
||||
size_t fscrypt_get_ice_encryption_key_size(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = NULL;
|
||||
|
||||
if (inode)
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return 0;
|
||||
|
||||
return fscrypt_get_mode_key_size(ci->ci_data_mode) / 2;
|
||||
}
|
||||
|
||||
size_t fscrypt_get_ice_encryption_salt_size(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = NULL;
|
||||
|
||||
if (inode)
|
||||
ci = inode->i_crypt_info;
|
||||
if (!ci)
|
||||
return 0;
|
||||
|
||||
return fscrypt_get_mode_key_size(ci->ci_data_mode) / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves encryption key from the inode
|
||||
*/
|
||||
@ -44,6 +70,7 @@ char *fscrypt_get_ice_encryption_key(const struct inode *inode)
|
||||
char *fscrypt_get_ice_encryption_salt(const struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *ci = NULL;
|
||||
int size = 0;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
@ -52,7 +79,11 @@ char *fscrypt_get_ice_encryption_salt(const struct inode *inode)
|
||||
if (!ci)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[fscrypt_get_ice_encryption_key_size(inode)]);
|
||||
size = fscrypt_get_ice_encryption_key_size(inode);
|
||||
if (!size)
|
||||
return NULL;
|
||||
|
||||
return &(ci->ci_raw_key[size]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -21,7 +21,7 @@ static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
if (!inode->i_sb->s_cop)
|
||||
return 0;
|
||||
if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode))
|
||||
if (!IS_ENCRYPTED((struct inode *)inode))
|
||||
return 0;
|
||||
|
||||
return fscrypt_using_hardware_encryption(inode);
|
||||
@ -40,17 +40,10 @@ char *fscrypt_get_ice_encryption_salt(const struct inode *inode);
|
||||
bool fscrypt_is_ice_encryption_info_equal(const struct inode *inode1,
|
||||
const struct inode *inode2);
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_key_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return FS_AES_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
size_t fscrypt_get_ice_encryption_key_size(const struct inode *inode);
|
||||
|
||||
size_t fscrypt_get_ice_encryption_salt_size(const struct inode *inode);
|
||||
|
||||
static inline size_t fscrypt_get_ice_encryption_salt_size(
|
||||
const struct inode *inode)
|
||||
{
|
||||
return FS_AES_256_XTS_KEY_SIZE / 2;
|
||||
}
|
||||
#else
|
||||
static inline bool fscrypt_should_be_processed_by_ice(const struct inode *inode)
|
||||
{
|
||||
|
@ -21,15 +21,7 @@
|
||||
|
||||
/* Encryption parameters */
|
||||
#define FS_IV_SIZE 16
|
||||
#define FS_AES_128_ECB_KEY_SIZE 16
|
||||
#define FS_AES_128_CBC_KEY_SIZE 16
|
||||
#define FS_AES_128_CTS_KEY_SIZE 16
|
||||
#define FS_AES_256_GCM_KEY_SIZE 32
|
||||
#define FS_AES_256_CBC_KEY_SIZE 32
|
||||
#define FS_AES_256_CTS_KEY_SIZE 32
|
||||
#define FS_AES_256_XTS_KEY_SIZE 64
|
||||
|
||||
#define FS_KEY_DERIVATION_NONCE_SIZE 16
|
||||
#define FS_KEY_DERIVATION_NONCE_SIZE 16
|
||||
|
||||
/**
|
||||
* Encryption context for inode
|
||||
@ -62,12 +54,6 @@ struct fscrypt_symlink_data {
|
||||
char encrypted_path[1];
|
||||
} __packed;
|
||||
|
||||
enum ci_mode_info {
|
||||
CI_NONE_MODE = 0,
|
||||
CI_DATA_MODE,
|
||||
CI_FNAME_MODE,
|
||||
};
|
||||
|
||||
/*
|
||||
* A pointer to this structure is stored in the file system's in-core
|
||||
* representation of an inode.
|
||||
@ -113,10 +99,9 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_private_data_mode(struct fscrypt_info *ci)
|
||||
static inline bool is_private_data_mode(const struct fscrypt_context *ctx)
|
||||
{
|
||||
return ci->ci_mode == CI_DATA_MODE &&
|
||||
ci->ci_data_mode == FS_ENCRYPTION_MODE_PRIVATE;
|
||||
return ctx->contents_encryption_mode == FS_ENCRYPTION_MODE_PRIVATE;
|
||||
}
|
||||
|
||||
/* crypto.c */
|
||||
@ -130,6 +115,15 @@ extern int fscrypt_do_page_crypto(const struct inode *inode,
|
||||
gfp_t gfp_flags);
|
||||
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
|
||||
gfp_t gfp_flags);
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
|
||||
extern void __printf(3, 4) __cold
|
||||
fscrypt_msg(struct super_block *sb, const char *level, const char *fmt, ...);
|
||||
|
||||
#define fscrypt_warn(sb, fmt, ...) \
|
||||
fscrypt_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
|
||||
#define fscrypt_err(sb, fmt, ...) \
|
||||
fscrypt_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
|
||||
|
||||
/* fname.c */
|
||||
extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
|
||||
|
@ -39,8 +39,9 @@ int fscrypt_file_open(struct inode *inode, struct file *filp)
|
||||
dir = dget_parent(file_dentry(filp));
|
||||
if (IS_ENCRYPTED(d_inode(dir)) &&
|
||||
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
|
||||
pr_warn_ratelimited("fscrypt: inconsistent encryption contexts: %lu/%lu",
|
||||
d_inode(dir)->i_ino, inode->i_ino);
|
||||
fscrypt_warn(inode->i_sb,
|
||||
"inconsistent encryption contexts: %lu/%lu",
|
||||
d_inode(dir)->i_ino, inode->i_ino);
|
||||
err = -EPERM;
|
||||
}
|
||||
dput(dir);
|
||||
|
@ -20,17 +20,16 @@
|
||||
|
||||
static struct crypto_shash *essiv_hash_tfm;
|
||||
|
||||
/**
|
||||
* derive_key_aes() - Derive a key using AES-128-ECB
|
||||
* @deriving_key: Encryption key used for derivation.
|
||||
* @source_key: Source key to which to apply derivation.
|
||||
* @derived_raw_key: Derived raw key.
|
||||
/*
|
||||
* Key derivation function. This generates the derived key by encrypting the
|
||||
* master key with AES-128-ECB using the inode's nonce as the AES key.
|
||||
*
|
||||
* Return: Zero on success; non-zero otherwise.
|
||||
* The master key must be at least as long as the derived key. If the master
|
||||
* key is longer, then only the first 'derived_keysize' bytes are used.
|
||||
*/
|
||||
static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
|
||||
const struct fscrypt_key *source_key,
|
||||
u8 derived_raw_key[FS_MAX_KEY_SIZE])
|
||||
static int derive_key_aes(const u8 *master_key,
|
||||
const struct fscrypt_context *ctx,
|
||||
u8 *derived_key, unsigned int derived_keysize)
|
||||
{
|
||||
int res = 0;
|
||||
struct skcipher_request *req = NULL;
|
||||
@ -52,14 +51,13 @@ static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
|
||||
skcipher_request_set_callback(req,
|
||||
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &wait);
|
||||
res = crypto_skcipher_setkey(tfm, deriving_key,
|
||||
FS_AES_128_ECB_KEY_SIZE);
|
||||
res = crypto_skcipher_setkey(tfm, ctx->nonce, sizeof(ctx->nonce));
|
||||
if (res < 0)
|
||||
goto out;
|
||||
|
||||
sg_init_one(&src_sg, source_key->raw, source_key->size);
|
||||
sg_init_one(&dst_sg, derived_raw_key, source_key->size);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, source_key->size,
|
||||
sg_init_one(&src_sg, master_key, derived_keysize);
|
||||
sg_init_one(&dst_sg, derived_key, derived_keysize);
|
||||
skcipher_request_set_crypt(req, &src_sg, &dst_sg, derived_keysize,
|
||||
NULL);
|
||||
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
|
||||
out:
|
||||
@ -68,123 +66,168 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int validate_user_key(struct fscrypt_info *crypt_info,
|
||||
struct fscrypt_context *ctx,
|
||||
const char *prefix, int min_keysize)
|
||||
/*
|
||||
* Search the current task's subscribed keyrings for a "logon" key with
|
||||
* description prefix:descriptor, and if found acquire a read lock on it and
|
||||
* return a pointer to its validated payload in *payload_ret.
|
||||
*/
|
||||
static struct key *
|
||||
find_and_lock_process_key(const char *prefix,
|
||||
const u8 descriptor[FS_KEY_DESCRIPTOR_SIZE],
|
||||
unsigned int min_keysize,
|
||||
const struct fscrypt_key **payload_ret)
|
||||
{
|
||||
char *description;
|
||||
struct key *keyring_key;
|
||||
struct fscrypt_key *master_key;
|
||||
struct key *key;
|
||||
const struct user_key_payload *ukp;
|
||||
int res;
|
||||
const struct fscrypt_key *payload;
|
||||
|
||||
description = kasprintf(GFP_NOFS, "%s%*phN", prefix,
|
||||
FS_KEY_DESCRIPTOR_SIZE,
|
||||
ctx->master_key_descriptor);
|
||||
FS_KEY_DESCRIPTOR_SIZE, descriptor);
|
||||
if (!description)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
keyring_key = request_key(&key_type_logon, description, NULL);
|
||||
key = request_key(&key_type_logon, description, NULL);
|
||||
kfree(description);
|
||||
if (IS_ERR(keyring_key))
|
||||
return PTR_ERR(keyring_key);
|
||||
down_read(&keyring_key->sem);
|
||||
if (IS_ERR(key))
|
||||
return key;
|
||||
|
||||
if (keyring_key->type != &key_type_logon) {
|
||||
printk_once(KERN_WARNING
|
||||
"%s: key type must be logon\n", __func__);
|
||||
res = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
ukp = user_key_payload_locked(keyring_key);
|
||||
if (!ukp) {
|
||||
/* key was revoked before we acquired its semaphore */
|
||||
res = -EKEYREVOKED;
|
||||
goto out;
|
||||
}
|
||||
if (ukp->datalen != sizeof(struct fscrypt_key)) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
master_key = (struct fscrypt_key *)ukp->data;
|
||||
BUILD_BUG_ON(FS_AES_128_ECB_KEY_SIZE != FS_KEY_DERIVATION_NONCE_SIZE);
|
||||
down_read(&key->sem);
|
||||
ukp = user_key_payload_locked(key);
|
||||
|
||||
if (master_key->size < min_keysize || master_key->size > FS_MAX_KEY_SIZE
|
||||
|| master_key->size % AES_BLOCK_SIZE != 0) {
|
||||
printk_once(KERN_WARNING
|
||||
"%s: key size incorrect: %d\n",
|
||||
__func__, master_key->size);
|
||||
res = -ENOKEY;
|
||||
goto out;
|
||||
if (!ukp) /* was the key revoked before we acquired its semaphore? */
|
||||
goto invalid;
|
||||
|
||||
payload = (const struct fscrypt_key *)ukp->data;
|
||||
|
||||
if (ukp->datalen != sizeof(struct fscrypt_key) ||
|
||||
payload->size < 1 || payload->size > FS_MAX_KEY_SIZE) {
|
||||
fscrypt_warn(NULL,
|
||||
"key with description '%s' has invalid payload",
|
||||
key->description);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
if (payload->size < min_keysize) {
|
||||
fscrypt_warn(NULL,
|
||||
"key with description '%s' is too short (got %u bytes, need %u+ bytes)",
|
||||
key->description, payload->size, min_keysize);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
*payload_ret = payload;
|
||||
return key;
|
||||
|
||||
invalid:
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
return ERR_PTR(-ENOKEY);
|
||||
}
|
||||
|
||||
/* Find the master key, then derive the inode's actual encryption key */
|
||||
static int find_and_derive_key(const struct inode *inode,
|
||||
const struct fscrypt_context *ctx,
|
||||
u8 *derived_key, unsigned int derived_keysize)
|
||||
{
|
||||
struct key *key;
|
||||
const struct fscrypt_key *payload;
|
||||
int err;
|
||||
|
||||
key = find_and_lock_process_key(FS_KEY_DESC_PREFIX,
|
||||
ctx->master_key_descriptor,
|
||||
derived_keysize, &payload);
|
||||
if (key == ERR_PTR(-ENOKEY) && inode->i_sb->s_cop->key_prefix) {
|
||||
key = find_and_lock_process_key(inode->i_sb->s_cop->key_prefix,
|
||||
ctx->master_key_descriptor,
|
||||
derived_keysize, &payload);
|
||||
}
|
||||
if (IS_ERR(key))
|
||||
return PTR_ERR(key);
|
||||
/* If we don't need to derive, we still want to do everything
|
||||
* up until now to validate the key. It's cleaner to fail now
|
||||
* than to fail in block I/O.
|
||||
*/
|
||||
if (!is_private_data_mode(crypt_info)) {
|
||||
res = derive_key_aes(ctx->nonce, master_key,
|
||||
crypt_info->ci_raw_key);
|
||||
} else {
|
||||
if (S_ISREG(inode->i_mode) && is_private_data_mode(ctx)) {
|
||||
/* Inline encryption: no key derivation required because IVs are
|
||||
* assigned based on iv_sector.
|
||||
*/
|
||||
BUILD_BUG_ON(sizeof(crypt_info->ci_raw_key) !=
|
||||
sizeof(master_key->raw));
|
||||
memcpy(crypt_info->ci_raw_key,
|
||||
master_key->raw, sizeof(crypt_info->ci_raw_key));
|
||||
res = 0;
|
||||
if (derived_keysize != sizeof(payload->raw)) {
|
||||
err = -ENOKEY;
|
||||
} else {
|
||||
memcpy(derived_key, payload->raw, derived_keysize);
|
||||
err = 0;
|
||||
}
|
||||
} else {
|
||||
err = derive_key_aes(payload->raw, ctx, derived_key, derived_keysize);
|
||||
}
|
||||
out:
|
||||
up_read(&keyring_key->sem);
|
||||
key_put(keyring_key);
|
||||
return res;
|
||||
up_read(&key->sem);
|
||||
key_put(key);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
static struct fscrypt_mode {
|
||||
const char *friendly_name;
|
||||
const char *cipher_str;
|
||||
int keysize;
|
||||
bool logged_impl_name;
|
||||
} available_modes[] = {
|
||||
[FS_ENCRYPTION_MODE_AES_256_XTS] = { "xts(aes)",
|
||||
FS_AES_256_XTS_KEY_SIZE },
|
||||
[FS_ENCRYPTION_MODE_AES_256_CTS] = { "cts(cbc(aes))",
|
||||
FS_AES_256_CTS_KEY_SIZE },
|
||||
[FS_ENCRYPTION_MODE_AES_128_CBC] = { "cbc(aes)",
|
||||
FS_AES_128_CBC_KEY_SIZE },
|
||||
[FS_ENCRYPTION_MODE_AES_128_CTS] = { "cts(cbc(aes))",
|
||||
FS_AES_128_CTS_KEY_SIZE },
|
||||
[FS_ENCRYPTION_MODE_SPECK128_256_XTS] = { "xts(speck128)", 64 },
|
||||
[FS_ENCRYPTION_MODE_SPECK128_256_CTS] = { "cts(cbc(speck128))", 32 },
|
||||
[FS_ENCRYPTION_MODE_PRIVATE] = { "bugon",
|
||||
FS_AES_256_XTS_KEY_SIZE },
|
||||
[FS_ENCRYPTION_MODE_AES_256_XTS] = {
|
||||
.friendly_name = "AES-256-XTS",
|
||||
.cipher_str = "xts(aes)",
|
||||
.keysize = 64,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_AES_256_CTS] = {
|
||||
.friendly_name = "AES-256-CTS-CBC",
|
||||
.cipher_str = "cts(cbc(aes))",
|
||||
.keysize = 32,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_AES_128_CBC] = {
|
||||
.friendly_name = "AES-128-CBC",
|
||||
.cipher_str = "cbc(aes)",
|
||||
.keysize = 16,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_AES_128_CTS] = {
|
||||
.friendly_name = "AES-128-CTS-CBC",
|
||||
.cipher_str = "cts(cbc(aes))",
|
||||
.keysize = 16,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_SPECK128_256_XTS] = {
|
||||
.friendly_name = "Speck128/256-XTS",
|
||||
.cipher_str = "xts(speck128)",
|
||||
.keysize = 64,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_SPECK128_256_CTS] = {
|
||||
.friendly_name = "Speck128/256-CTS-CBC",
|
||||
.cipher_str = "cts(cbc(speck128))",
|
||||
.keysize = 32,
|
||||
},
|
||||
[FS_ENCRYPTION_MODE_PRIVATE] = {
|
||||
.friendly_name = "ICE",
|
||||
.cipher_str = "bugon",
|
||||
.keysize = 64,
|
||||
},
|
||||
};
|
||||
|
||||
static int determine_cipher_type(struct fscrypt_info *ci, struct inode *inode,
|
||||
const char **cipher_str_ret, int *keysize_ret)
|
||||
static struct fscrypt_mode *
|
||||
select_encryption_mode(const struct fscrypt_info *ci, const struct inode *inode)
|
||||
{
|
||||
u32 mode;
|
||||
|
||||
if (!fscrypt_valid_enc_modes(ci->ci_data_mode, ci->ci_filename_mode)) {
|
||||
pr_warn_ratelimited("fscrypt: inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)\n",
|
||||
inode->i_ino,
|
||||
ci->ci_data_mode, ci->ci_filename_mode);
|
||||
return -EINVAL;
|
||||
fscrypt_warn(inode->i_sb,
|
||||
"inode %lu uses unsupported encryption modes (contents mode %d, filenames mode %d)",
|
||||
inode->i_ino, ci->ci_data_mode,
|
||||
ci->ci_filename_mode);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
ci->ci_mode = CI_DATA_MODE;
|
||||
mode = ci->ci_data_mode;
|
||||
} else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) {
|
||||
ci->ci_mode = CI_FNAME_MODE;
|
||||
mode = ci->ci_filename_mode;
|
||||
} else {
|
||||
WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
|
||||
inode->i_ino, (inode->i_mode & S_IFMT));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (S_ISREG(inode->i_mode))
|
||||
return &available_modes[ci->ci_data_mode];
|
||||
|
||||
*cipher_str_ret = available_modes[mode].cipher_str;
|
||||
*keysize_ret = available_modes[mode].keysize;
|
||||
return 0;
|
||||
if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
|
||||
return &available_modes[ci->ci_filename_mode];
|
||||
|
||||
WARN_ONCE(1, "fscrypt: filesystem tried to load encryption info for inode %lu, which is not encryptable (file type %d)\n",
|
||||
inode->i_ino, (inode->i_mode & S_IFMT));
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static void put_crypt_info(struct fscrypt_info *ci)
|
||||
@ -209,8 +252,9 @@ static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
|
||||
|
||||
tfm = crypto_alloc_shash("sha256", 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
pr_warn_ratelimited("fscrypt: error allocating SHA-256 transform: %ld\n",
|
||||
PTR_ERR(tfm));
|
||||
fscrypt_warn(NULL,
|
||||
"error allocating SHA-256 transform: %ld",
|
||||
PTR_ERR(tfm));
|
||||
return PTR_ERR(tfm);
|
||||
}
|
||||
prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
|
||||
@ -271,13 +315,18 @@ static int fscrypt_data_encryption_mode(struct inode *inode)
|
||||
FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS;
|
||||
}
|
||||
|
||||
int fscrypt_get_mode_key_size(int mode)
|
||||
{
|
||||
return available_modes[mode].keysize;
|
||||
}
|
||||
EXPORT_SYMBOL(fscrypt_get_mode_key_size);
|
||||
|
||||
int fscrypt_get_encryption_info(struct inode *inode)
|
||||
{
|
||||
struct fscrypt_info *crypt_info;
|
||||
struct fscrypt_context ctx;
|
||||
struct crypto_skcipher *ctfm;
|
||||
const char *cipher_str;
|
||||
int keysize;
|
||||
struct fscrypt_mode *mode;
|
||||
u8 *raw_key = NULL;
|
||||
int res;
|
||||
|
||||
@ -322,77 +371,76 @@ int fscrypt_get_encryption_info(struct inode *inode)
|
||||
memcpy(crypt_info->ci_master_key, ctx.master_key_descriptor,
|
||||
sizeof(crypt_info->ci_master_key));
|
||||
|
||||
res = determine_cipher_type(crypt_info, inode, &cipher_str, &keysize);
|
||||
if (res)
|
||||
mode = select_encryption_mode(crypt_info, inode);
|
||||
if (IS_ERR(mode)) {
|
||||
res = PTR_ERR(mode);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* This cannot be a stack buffer because it is passed to the scatterlist
|
||||
* crypto API as part of key derivation.
|
||||
*/
|
||||
res = -ENOMEM;
|
||||
raw_key = kmalloc(FS_MAX_KEY_SIZE, GFP_NOFS);
|
||||
raw_key = kmalloc(mode->keysize, GFP_NOFS);
|
||||
if (!raw_key)
|
||||
goto out;
|
||||
|
||||
res = validate_user_key(crypt_info, &ctx, FS_KEY_DESC_PREFIX,
|
||||
keysize);
|
||||
if (res && inode->i_sb->s_cop->key_prefix) {
|
||||
int res2 = validate_user_key(crypt_info, &ctx,
|
||||
inode->i_sb->s_cop->key_prefix,
|
||||
keysize);
|
||||
if (res2) {
|
||||
if (res2 == -ENOKEY)
|
||||
res = -ENOKEY;
|
||||
goto out;
|
||||
}
|
||||
res = 0;
|
||||
} else if (res) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_private_data_mode(crypt_info)) {
|
||||
if (S_ISREG(inode->i_mode) && is_private_data_mode(&ctx)) {
|
||||
if (!fscrypt_is_ice_capable(inode->i_sb)) {
|
||||
pr_warn("%s: ICE support not available\n",
|
||||
__func__);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
res = find_and_derive_key(inode, &ctx, crypt_info->ci_raw_key, mode->keysize);
|
||||
if (res)
|
||||
goto out;
|
||||
/* Let's encrypt/decrypt by ICE */
|
||||
goto do_ice;
|
||||
}
|
||||
} else {
|
||||
res = find_and_derive_key(inode, &ctx, raw_key, mode->keysize);
|
||||
if (res)
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
ctfm = crypto_alloc_skcipher(cipher_str, 0, 0);
|
||||
if (!ctfm || IS_ERR(ctfm)) {
|
||||
res = ctfm ? PTR_ERR(ctfm) : -ENOMEM;
|
||||
pr_debug("%s: error %d (inode %lu) allocating crypto tfm\n",
|
||||
__func__, res, inode->i_ino);
|
||||
ctfm = crypto_alloc_skcipher(mode->cipher_str, 0, 0);
|
||||
if (IS_ERR(ctfm)) {
|
||||
res = PTR_ERR(ctfm);
|
||||
fscrypt_warn(inode->i_sb,
|
||||
"error allocating '%s' transform for inode %lu: %d",
|
||||
mode->cipher_str, inode->i_ino, res);
|
||||
goto out;
|
||||
}
|
||||
if (unlikely(!mode->logged_impl_name)) {
|
||||
/*
|
||||
* fscrypt performance can vary greatly depending on which
|
||||
* crypto algorithm implementation is used. Help people debug
|
||||
* performance problems by logging the ->cra_driver_name the
|
||||
* first time a mode is used. Note that multiple threads can
|
||||
* race here, but it doesn't really matter.
|
||||
*/
|
||||
mode->logged_impl_name = true;
|
||||
pr_info("fscrypt: %s using implementation \"%s\"\n",
|
||||
mode->friendly_name,
|
||||
crypto_skcipher_alg(ctfm)->base.cra_driver_name);
|
||||
}
|
||||
crypt_info->ci_ctfm = ctfm;
|
||||
crypto_skcipher_clear_flags(ctfm, ~0);
|
||||
crypto_skcipher_set_flags(ctfm, CRYPTO_TFM_REQ_WEAK_KEY);
|
||||
/*
|
||||
* if the provided key is longer than keysize, we use the first
|
||||
* keysize bytes of the derived key only
|
||||
*/
|
||||
res = crypto_skcipher_setkey(ctfm, crypt_info->ci_raw_key, keysize);
|
||||
res = crypto_skcipher_setkey(ctfm, raw_key, mode->keysize);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
if (S_ISREG(inode->i_mode) &&
|
||||
crypt_info->ci_data_mode == FS_ENCRYPTION_MODE_AES_128_CBC) {
|
||||
res = init_essiv_generator(crypt_info, crypt_info->ci_raw_key,
|
||||
keysize);
|
||||
res = init_essiv_generator(crypt_info, raw_key, mode->keysize);
|
||||
if (res) {
|
||||
pr_debug("%s: error %d (inode %lu) allocating essiv tfm\n",
|
||||
__func__, res, inode->i_ino);
|
||||
fscrypt_warn(inode->i_sb,
|
||||
"error initializing ESSIV generator for inode %lu: %d",
|
||||
inode->i_ino, res);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
memzero_explicit(crypt_info->ci_raw_key,
|
||||
sizeof(crypt_info->ci_raw_key));
|
||||
do_ice:
|
||||
if (cmpxchg(&inode->i_crypt_info, NULL, crypt_info) == NULL)
|
||||
crypt_info = NULL;
|
||||
|
@ -2642,24 +2642,14 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
|
||||
mpd->map.m_len = 0;
|
||||
mpd->next_page = index;
|
||||
while (index <= end) {
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag);
|
||||
if (nr_pages == 0)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
/*
|
||||
* At this point, the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or
|
||||
* even swizzled back from swapper_space to tmpfs file
|
||||
* mapping. However, page->index will not change
|
||||
* because we have a reference on the page.
|
||||
*/
|
||||
if (page->index > end)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Accumulated enough dirty pages? This doesn't apply
|
||||
* to WB_SYNC_ALL mode. For integrity sync we have to
|
||||
|
@ -1545,24 +1545,14 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
|
||||
struct inode *inode;
|
||||
struct ext4_dir_entry_2 *de;
|
||||
struct buffer_head *bh;
|
||||
int err;
|
||||
|
||||
if (ext4_encrypted_inode(dir)) {
|
||||
int res = fscrypt_get_encryption_info(dir);
|
||||
err = fscrypt_prepare_lookup(dir, dentry, flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/*
|
||||
* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
|
||||
* created while the directory was encrypted and we
|
||||
* have access to the key.
|
||||
*/
|
||||
if (fscrypt_has_encryption_key(dir))
|
||||
fscrypt_set_encrypted_dentry(dentry);
|
||||
fscrypt_set_d_op(dentry);
|
||||
if (res && res != -ENOKEY)
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
|
||||
if (dentry->d_name.len > EXT4_NAME_LEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
if (dentry->d_name.len > EXT4_NAME_LEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
|
||||
if (IS_ERR(bh))
|
||||
|
@ -1275,25 +1275,13 @@ static bool ext4_dummy_context(struct inode *inode)
|
||||
return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb));
|
||||
}
|
||||
|
||||
static unsigned ext4_max_namelen(struct inode *inode)
|
||||
{
|
||||
return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize :
|
||||
EXT4_NAME_LEN;
|
||||
}
|
||||
|
||||
static inline bool ext4_is_encrypted(struct inode *inode)
|
||||
{
|
||||
return ext4_encrypted_inode(inode);
|
||||
}
|
||||
|
||||
static const struct fscrypt_operations ext4_cryptops = {
|
||||
.key_prefix = "ext4:",
|
||||
.get_context = ext4_get_context,
|
||||
.set_context = ext4_set_context,
|
||||
.dummy_context = ext4_dummy_context,
|
||||
.empty_dir = ext4_empty_dir,
|
||||
.max_namelen = ext4_max_namelen,
|
||||
.is_encrypted = ext4_is_encrypted,
|
||||
.max_namelen = EXT4_NAME_LEN,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
static struct kmem_cache *ino_entry_slab;
|
||||
struct kmem_cache *inode_entry_slab;
|
||||
struct kmem_cache *f2fs_inode_entry_slab;
|
||||
|
||||
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
|
||||
{
|
||||
@ -36,7 +36,7 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
|
||||
/*
|
||||
* We guarantee no failure on the returned page.
|
||||
*/
|
||||
struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
struct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
struct address_space *mapping = META_MAPPING(sbi);
|
||||
struct page *page = NULL;
|
||||
@ -105,7 +105,7 @@ out:
|
||||
return page;
|
||||
}
|
||||
|
||||
struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
return __get_meta_page(sbi, index, true);
|
||||
}
|
||||
@ -127,7 +127,7 @@ retry:
|
||||
}
|
||||
|
||||
/* for POR only */
|
||||
struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
return __get_meta_page(sbi, index, false);
|
||||
}
|
||||
@ -179,7 +179,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
/*
|
||||
* Readahead CP/NAT/SIT/SSA pages
|
||||
*/
|
||||
int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int type, bool sync)
|
||||
{
|
||||
struct page *page;
|
||||
@ -245,7 +245,7 @@ out:
|
||||
return blkno - start;
|
||||
}
|
||||
|
||||
void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
struct page *page;
|
||||
bool readahead = false;
|
||||
@ -256,7 +256,7 @@ void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
if (readahead)
|
||||
ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
|
||||
f2fs_ra_meta_pages(sbi, index, BIO_MAX_PAGES, META_POR, true);
|
||||
}
|
||||
|
||||
static int __f2fs_write_meta_page(struct page *page,
|
||||
@ -277,7 +277,7 @@ static int __f2fs_write_meta_page(struct page *page,
|
||||
if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
|
||||
goto redirty_out;
|
||||
|
||||
write_meta_page(sbi, page, io_type);
|
||||
f2fs_do_write_meta_page(sbi, page, io_type);
|
||||
dec_page_count(sbi, F2FS_DIRTY_META);
|
||||
|
||||
if (wbc->for_reclaim)
|
||||
@ -322,7 +322,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
|
||||
|
||||
trace_f2fs_writepages(mapping->host, wbc, META);
|
||||
diff = nr_pages_to_write(sbi, META, wbc);
|
||||
written = sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO);
|
||||
written = f2fs_sync_meta_pages(sbi, META, wbc->nr_to_write, FS_META_IO);
|
||||
mutex_unlock(&sbi->cp_mutex);
|
||||
wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
|
||||
return 0;
|
||||
@ -333,13 +333,14 @@ skip_write:
|
||||
return 0;
|
||||
}
|
||||
|
||||
long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
long nr_to_write, enum iostat_type io_type)
|
||||
{
|
||||
struct address_space *mapping = META_MAPPING(sbi);
|
||||
pgoff_t index = 0, end = ULONG_MAX, prev = ULONG_MAX;
|
||||
pgoff_t index = 0, prev = ULONG_MAX;
|
||||
struct pagevec pvec;
|
||||
long nwritten = 0;
|
||||
int nr_pages;
|
||||
struct writeback_control wbc = {
|
||||
.for_reclaim = 0,
|
||||
};
|
||||
@ -349,13 +350,9 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
|
||||
blk_start_plug(&plug);
|
||||
|
||||
while (index <= end) {
|
||||
int i, nr_pages;
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
if (unlikely(nr_pages == 0))
|
||||
break;
|
||||
while ((nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
@ -486,20 +483,20 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
|
||||
spin_unlock(&im->ino_lock);
|
||||
}
|
||||
|
||||
void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
|
||||
void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
|
||||
{
|
||||
/* add new dirty ino entry into list */
|
||||
__add_ino_entry(sbi, ino, 0, type);
|
||||
}
|
||||
|
||||
void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
|
||||
void f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
|
||||
{
|
||||
/* remove dirty ino entry from list */
|
||||
__remove_ino_entry(sbi, ino, type);
|
||||
}
|
||||
|
||||
/* mode should be APPEND_INO or UPDATE_INO */
|
||||
bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
|
||||
bool f2fs_exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
|
||||
{
|
||||
struct inode_management *im = &sbi->im[mode];
|
||||
struct ino_entry *e;
|
||||
@ -510,7 +507,7 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
|
||||
return e ? true : false;
|
||||
}
|
||||
|
||||
void release_ino_entry(struct f2fs_sb_info *sbi, bool all)
|
||||
void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all)
|
||||
{
|
||||
struct ino_entry *e, *tmp;
|
||||
int i;
|
||||
@ -529,13 +526,13 @@ void release_ino_entry(struct f2fs_sb_info *sbi, bool all)
|
||||
}
|
||||
}
|
||||
|
||||
void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
void f2fs_set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
unsigned int devidx, int type)
|
||||
{
|
||||
__add_ino_entry(sbi, ino, devidx, type);
|
||||
}
|
||||
|
||||
bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
bool f2fs_is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
unsigned int devidx, int type)
|
||||
{
|
||||
struct inode_management *im = &sbi->im[type];
|
||||
@ -550,7 +547,7 @@ bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
return is_dirty;
|
||||
}
|
||||
|
||||
int acquire_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
int f2fs_acquire_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct inode_management *im = &sbi->im[ORPHAN_INO];
|
||||
int err = 0;
|
||||
@ -573,7 +570,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
return err;
|
||||
}
|
||||
|
||||
void release_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
void f2fs_release_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct inode_management *im = &sbi->im[ORPHAN_INO];
|
||||
|
||||
@ -583,14 +580,14 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
spin_unlock(&im->ino_lock);
|
||||
}
|
||||
|
||||
void add_orphan_inode(struct inode *inode)
|
||||
void f2fs_add_orphan_inode(struct inode *inode)
|
||||
{
|
||||
/* add new orphan ino entry into list */
|
||||
__add_ino_entry(F2FS_I_SB(inode), inode->i_ino, 0, ORPHAN_INO);
|
||||
update_inode_page(inode);
|
||||
f2fs_update_inode_page(inode);
|
||||
}
|
||||
|
||||
void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
void f2fs_remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
/* remove orphan entry from orphan list */
|
||||
__remove_ino_entry(sbi, ino, ORPHAN_INO);
|
||||
@ -600,7 +597,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct node_info ni;
|
||||
int err = acquire_orphan_inode(sbi);
|
||||
int err = f2fs_acquire_orphan_inode(sbi);
|
||||
|
||||
if (err)
|
||||
goto err_out;
|
||||
@ -618,16 +615,17 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
}
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
if (err)
|
||||
if (err) {
|
||||
iput(inode);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
dquot_initialize(inode);
|
||||
clear_nlink(inode);
|
||||
|
||||
/* truncate all the data during iput */
|
||||
iput(inode);
|
||||
|
||||
err = get_node_info(sbi, ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, ino, &ni);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@ -647,7 +645,7 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
block_t start_blk, orphan_blocks, i, j;
|
||||
unsigned int s_flags = sbi->sb->s_flags;
|
||||
@ -675,13 +673,13 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
|
||||
orphan_blocks = __start_sum_addr(sbi) - 1 - __cp_payload(sbi);
|
||||
|
||||
ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true);
|
||||
f2fs_ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true);
|
||||
|
||||
for (i = 0; i < orphan_blocks; i++) {
|
||||
struct page *page;
|
||||
struct f2fs_orphan_block *orphan_blk;
|
||||
|
||||
page = get_meta_page(sbi, start_blk + i);
|
||||
page = f2fs_get_meta_page(sbi, start_blk + i);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
goto out;
|
||||
@ -734,7 +732,7 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
/* loop for each orphan inode entry and write them in Jornal block */
|
||||
list_for_each_entry(orphan, head, list) {
|
||||
if (!page) {
|
||||
page = grab_meta_page(sbi, start_blk++);
|
||||
page = f2fs_grab_meta_page(sbi, start_blk++);
|
||||
orphan_blk =
|
||||
(struct f2fs_orphan_block *)page_address(page);
|
||||
memset(orphan_blk, 0, sizeof(*orphan_blk));
|
||||
@ -776,7 +774,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
|
||||
size_t crc_offset = 0;
|
||||
__u32 crc = 0;
|
||||
|
||||
*cp_page = get_meta_page(sbi, cp_addr);
|
||||
*cp_page = f2fs_get_meta_page(sbi, cp_addr);
|
||||
if (IS_ERR(*cp_page))
|
||||
return PTR_ERR(*cp_page);
|
||||
|
||||
@ -841,7 +839,7 @@ invalid_cp:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_checkpoint *cp_block;
|
||||
struct f2fs_super_block *fsb = sbi->raw_super;
|
||||
@ -853,7 +851,8 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
block_t cp_blk_no;
|
||||
int i;
|
||||
|
||||
sbi->ckpt = f2fs_kzalloc(sbi, cp_blks * blk_size, GFP_KERNEL);
|
||||
sbi->ckpt = f2fs_kzalloc(sbi, array_size(blk_size, cp_blks),
|
||||
GFP_KERNEL);
|
||||
if (!sbi->ckpt)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
@ -890,7 +889,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
sbi->cur_cp_pack = 2;
|
||||
|
||||
/* Sanity checking of checkpoint */
|
||||
if (sanity_check_ckpt(sbi))
|
||||
if (f2fs_sanity_check_ckpt(sbi))
|
||||
goto free_fail_no_cp;
|
||||
|
||||
if (cp_blks <= 1)
|
||||
@ -904,7 +903,7 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
void *sit_bitmap_ptr;
|
||||
unsigned char *ckpt = (unsigned char *)sbi->ckpt;
|
||||
|
||||
cur_page = get_meta_page(sbi, cp_blk_no + i);
|
||||
cur_page = f2fs_get_meta_page(sbi, cp_blk_no + i);
|
||||
if (IS_ERR(cur_page))
|
||||
goto free_fail_no_cp;
|
||||
sit_bitmap_ptr = page_address(cur_page);
|
||||
@ -951,7 +950,7 @@ static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
|
||||
stat_dec_dirty_inode(F2FS_I_SB(inode), type);
|
||||
}
|
||||
|
||||
void update_dirty_page(struct inode *inode, struct page *page)
|
||||
void f2fs_update_dirty_page(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
|
||||
@ -970,7 +969,7 @@ void update_dirty_page(struct inode *inode, struct page *page)
|
||||
f2fs_trace_pid(page);
|
||||
}
|
||||
|
||||
void remove_dirty_inode(struct inode *inode)
|
||||
void f2fs_remove_dirty_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
|
||||
@ -987,7 +986,7 @@ void remove_dirty_inode(struct inode *inode)
|
||||
spin_unlock(&sbi->inode_lock[type]);
|
||||
}
|
||||
|
||||
int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
|
||||
int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct inode *inode;
|
||||
@ -1070,7 +1069,7 @@ int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi)
|
||||
|
||||
/* it's on eviction */
|
||||
if (is_inode_flag_set(inode, FI_DIRTY_INODE))
|
||||
update_inode_page(inode);
|
||||
f2fs_update_inode_page(inode);
|
||||
iput(inode);
|
||||
}
|
||||
}
|
||||
@ -1110,7 +1109,7 @@ retry_flush_dents:
|
||||
/* write all the dirty dentry pages */
|
||||
if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
|
||||
f2fs_unlock_all(sbi);
|
||||
err = sync_dirty_inodes(sbi, DIR_INODE);
|
||||
err = f2fs_sync_dirty_inodes(sbi, DIR_INODE);
|
||||
if (err)
|
||||
goto out;
|
||||
cond_resched();
|
||||
@ -1138,7 +1137,9 @@ retry_flush_nodes:
|
||||
|
||||
if (get_pages(sbi, F2FS_DIRTY_NODES)) {
|
||||
up_write(&sbi->node_write);
|
||||
err = sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO);
|
||||
atomic_inc(&sbi->wb_sync_req[NODE]);
|
||||
err = f2fs_sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO);
|
||||
atomic_dec(&sbi->wb_sync_req[NODE]);
|
||||
if (err) {
|
||||
up_write(&sbi->node_change);
|
||||
f2fs_unlock_all(sbi);
|
||||
@ -1232,10 +1233,10 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,
|
||||
|
||||
/*
|
||||
* pagevec_lookup_tag and lock_page again will take
|
||||
* some extra time. Therefore, update_meta_pages and
|
||||
* sync_meta_pages are combined in this function.
|
||||
* some extra time. Therefore, f2fs_update_meta_pages and
|
||||
* f2fs_sync_meta_pages are combined in this function.
|
||||
*/
|
||||
struct page *page = grab_meta_page(sbi, blk_addr);
|
||||
struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
|
||||
int err;
|
||||
|
||||
memcpy(page_address(page), src, PAGE_SIZE);
|
||||
@ -1273,7 +1274,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* Flush all the NAT/SIT pages */
|
||||
while (get_pages(sbi, F2FS_DIRTY_META)) {
|
||||
sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
}
|
||||
@ -1282,7 +1283,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
* modify checkpoint
|
||||
* version number is already updated
|
||||
*/
|
||||
ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi));
|
||||
ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true));
|
||||
ckpt->free_segment_count = cpu_to_le32(free_segments(sbi));
|
||||
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
|
||||
ckpt->cur_node_segno[i] =
|
||||
@ -1302,7 +1303,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
}
|
||||
|
||||
/* 2 cp + n data seg summary + orphan inode blocks */
|
||||
data_sum_blocks = npages_for_summary_flush(sbi, false);
|
||||
data_sum_blocks = f2fs_npages_for_summary_flush(sbi, false);
|
||||
spin_lock_irqsave(&sbi->cp_lock, flags);
|
||||
if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
|
||||
__set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
|
||||
@ -1347,22 +1348,23 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks;
|
||||
for (i = 0; i < nm_i->nat_bits_blocks; i++)
|
||||
update_meta_page(sbi, nm_i->nat_bits +
|
||||
f2fs_update_meta_page(sbi, nm_i->nat_bits +
|
||||
(i << F2FS_BLKSIZE_BITS), blk + i);
|
||||
|
||||
/* Flush all the NAT BITS pages */
|
||||
while (get_pages(sbi, F2FS_DIRTY_META)) {
|
||||
sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX,
|
||||
FS_CP_META_IO);
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* write out checkpoint buffer at block 0 */
|
||||
update_meta_page(sbi, ckpt, start_blk++);
|
||||
f2fs_update_meta_page(sbi, ckpt, start_blk++);
|
||||
|
||||
for (i = 1; i < 1 + cp_payload_blks; i++)
|
||||
update_meta_page(sbi, (char *)ckpt + i * F2FS_BLKSIZE,
|
||||
f2fs_update_meta_page(sbi, (char *)ckpt + i * F2FS_BLKSIZE,
|
||||
start_blk++);
|
||||
|
||||
if (orphan_num) {
|
||||
@ -1370,7 +1372,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
start_blk += orphan_blocks;
|
||||
}
|
||||
|
||||
write_data_summaries(sbi, start_blk);
|
||||
f2fs_write_data_summaries(sbi, start_blk);
|
||||
start_blk += data_sum_blocks;
|
||||
|
||||
/* Record write statistics in the hot node summary */
|
||||
@ -1381,7 +1383,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
seg_i->journal->info.kbytes_written = cpu_to_le64(kbytes_written);
|
||||
|
||||
if (__remain_node_summaries(cpc->reason)) {
|
||||
write_node_summaries(sbi, start_blk);
|
||||
f2fs_write_node_summaries(sbi, start_blk);
|
||||
start_blk += NR_CURSEG_NODE_TYPE;
|
||||
}
|
||||
|
||||
@ -1390,7 +1392,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
percpu_counter_set(&sbi->alloc_valid_block_count, 0);
|
||||
|
||||
/* Here, we have one bio having CP pack except cp pack 2 page */
|
||||
sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
|
||||
/* wait for previous submitted meta pages writeback */
|
||||
wait_on_all_pages_writeback(sbi);
|
||||
@ -1407,7 +1409,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
commit_checkpoint(sbi, ckpt, start_blk);
|
||||
wait_on_all_pages_writeback(sbi);
|
||||
|
||||
release_ino_entry(sbi, false);
|
||||
f2fs_release_ino_entry(sbi, false);
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
@ -1432,7 +1434,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
/*
|
||||
* We guarantee that this checkpoint procedure will not fail.
|
||||
*/
|
||||
int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
{
|
||||
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
|
||||
unsigned long long ckpt_ver;
|
||||
@ -1465,7 +1467,7 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* this is the case of multiple fstrims without any changes */
|
||||
if (cpc->reason & CP_DISCARD) {
|
||||
if (!exist_trim_candidates(sbi, cpc)) {
|
||||
if (!f2fs_exist_trim_candidates(sbi, cpc)) {
|
||||
unblock_operations(sbi);
|
||||
goto out;
|
||||
}
|
||||
@ -1473,8 +1475,8 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
if (NM_I(sbi)->dirty_nat_cnt == 0 &&
|
||||
SIT_I(sbi)->dirty_sentries == 0 &&
|
||||
prefree_segments(sbi) == 0) {
|
||||
flush_sit_entries(sbi, cpc);
|
||||
clear_prefree_segments(sbi, cpc);
|
||||
f2fs_flush_sit_entries(sbi, cpc);
|
||||
f2fs_clear_prefree_segments(sbi, cpc);
|
||||
unblock_operations(sbi);
|
||||
goto out;
|
||||
}
|
||||
@ -1489,18 +1491,18 @@ int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
|
||||
|
||||
/* write cached NAT/SIT entries to NAT/SIT area */
|
||||
err = flush_nat_entries(sbi, cpc);
|
||||
err = f2fs_flush_nat_entries(sbi, cpc);
|
||||
if (err)
|
||||
goto stop;
|
||||
|
||||
flush_sit_entries(sbi, cpc);
|
||||
f2fs_flush_sit_entries(sbi, cpc);
|
||||
|
||||
/* unlock all the fs_lock[] in do_checkpoint() */
|
||||
err = do_checkpoint(sbi, cpc);
|
||||
if (err)
|
||||
release_discard_addrs(sbi);
|
||||
f2fs_release_discard_addrs(sbi);
|
||||
else
|
||||
clear_prefree_segments(sbi, cpc);
|
||||
f2fs_clear_prefree_segments(sbi, cpc);
|
||||
stop:
|
||||
unblock_operations(sbi);
|
||||
stat_inc_cp_count(sbi->stat_info);
|
||||
@ -1517,7 +1519,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void init_ino_entry_info(struct f2fs_sb_info *sbi)
|
||||
void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1535,23 +1537,23 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
|
||||
F2FS_ORPHANS_PER_BLOCK;
|
||||
}
|
||||
|
||||
int __init create_checkpoint_caches(void)
|
||||
int __init f2fs_create_checkpoint_caches(void)
|
||||
{
|
||||
ino_entry_slab = f2fs_kmem_cache_create("f2fs_ino_entry",
|
||||
sizeof(struct ino_entry));
|
||||
if (!ino_entry_slab)
|
||||
return -ENOMEM;
|
||||
inode_entry_slab = f2fs_kmem_cache_create("f2fs_inode_entry",
|
||||
f2fs_inode_entry_slab = f2fs_kmem_cache_create("f2fs_inode_entry",
|
||||
sizeof(struct inode_entry));
|
||||
if (!inode_entry_slab) {
|
||||
if (!f2fs_inode_entry_slab) {
|
||||
kmem_cache_destroy(ino_entry_slab);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void destroy_checkpoint_caches(void)
|
||||
void f2fs_destroy_checkpoint_caches(void)
|
||||
{
|
||||
kmem_cache_destroy(ino_entry_slab);
|
||||
kmem_cache_destroy(inode_entry_slab);
|
||||
kmem_cache_destroy(f2fs_inode_entry_slab);
|
||||
}
|
||||
|
175
fs/f2fs/data.c
175
fs/f2fs/data.c
@ -49,6 +49,8 @@ static bool __is_cp_guaranteed(struct page *page)
|
||||
if (inode->i_ino == F2FS_META_INO(sbi) ||
|
||||
inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||
S_ISDIR(inode->i_mode) ||
|
||||
(S_ISREG(inode->i_mode) &&
|
||||
is_inode_flag_set(inode, FI_ATOMIC_FILE)) ||
|
||||
is_cold_data(page))
|
||||
return true;
|
||||
return false;
|
||||
@ -246,7 +248,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
|
||||
} else {
|
||||
bio->bi_end_io = f2fs_write_end_io;
|
||||
bio->bi_private = sbi;
|
||||
bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp);
|
||||
bio->bi_write_hint = f2fs_io_type_to_rw_hint(sbi, type, temp);
|
||||
}
|
||||
if (wbc)
|
||||
wbc_init_bio(wbc, bio);
|
||||
@ -470,7 +472,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||
void f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
|
||||
@ -480,7 +482,6 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio)
|
||||
bool bio_encrypted;
|
||||
int bi_crypt_skip;
|
||||
u64 dun;
|
||||
int err = 0;
|
||||
|
||||
f2fs_bug_on(sbi, is_read_io(fio->op));
|
||||
|
||||
@ -490,7 +491,7 @@ next:
|
||||
spin_lock(&io->io_lock);
|
||||
if (list_empty(&io->io_list)) {
|
||||
spin_unlock(&io->io_lock);
|
||||
goto out_fail;
|
||||
goto out;
|
||||
}
|
||||
fio = list_first_entry(&io->io_list,
|
||||
struct f2fs_io_info, list);
|
||||
@ -527,9 +528,9 @@ alloc_new:
|
||||
if (io->bio == NULL) {
|
||||
if ((fio->type == DATA || fio->type == NODE) &&
|
||||
fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
|
||||
err = -EAGAIN;
|
||||
dec_page_count(sbi, WB_DATA_TYPE(bio_page));
|
||||
goto out_fail;
|
||||
fio->retry = true;
|
||||
goto skip;
|
||||
}
|
||||
io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
|
||||
BIO_MAX_PAGES, false,
|
||||
@ -552,12 +553,11 @@ alloc_new:
|
||||
f2fs_trace_ios(fio, 0);
|
||||
|
||||
trace_f2fs_submit_page_write(fio->page, fio);
|
||||
|
||||
skip:
|
||||
if (fio->in_list)
|
||||
goto next;
|
||||
out_fail:
|
||||
out:
|
||||
up_write(&io->io_rwsem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
|
||||
@ -641,7 +641,7 @@ static void __set_data_blkaddr(struct dnode_of_data *dn)
|
||||
* ->node_page
|
||||
* update block addresses in the node page
|
||||
*/
|
||||
void set_data_blkaddr(struct dnode_of_data *dn)
|
||||
void f2fs_set_data_blkaddr(struct dnode_of_data *dn)
|
||||
{
|
||||
f2fs_wait_on_page_writeback(dn->node_page, NODE, true);
|
||||
__set_data_blkaddr(dn);
|
||||
@ -652,12 +652,12 @@ void set_data_blkaddr(struct dnode_of_data *dn)
|
||||
void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
|
||||
{
|
||||
dn->data_blkaddr = blkaddr;
|
||||
set_data_blkaddr(dn);
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
f2fs_update_extent_cache(dn);
|
||||
}
|
||||
|
||||
/* dn->ofs_in_node will be returned with up-to-date last block pointer */
|
||||
int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
|
||||
int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
int err;
|
||||
@ -691,12 +691,12 @@ int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)
|
||||
}
|
||||
|
||||
/* Should keep dn->ofs_in_node unchanged */
|
||||
int reserve_new_block(struct dnode_of_data *dn)
|
||||
int f2fs_reserve_new_block(struct dnode_of_data *dn)
|
||||
{
|
||||
unsigned int ofs_in_node = dn->ofs_in_node;
|
||||
int ret;
|
||||
|
||||
ret = reserve_new_blocks(dn, 1);
|
||||
ret = f2fs_reserve_new_blocks(dn, 1);
|
||||
dn->ofs_in_node = ofs_in_node;
|
||||
return ret;
|
||||
}
|
||||
@ -706,12 +706,12 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)
|
||||
bool need_put = dn->inode_page ? false : true;
|
||||
int err;
|
||||
|
||||
err = get_dnode_of_data(dn, index, ALLOC_NODE);
|
||||
err = f2fs_get_dnode_of_data(dn, index, ALLOC_NODE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (dn->data_blkaddr == NULL_ADDR)
|
||||
err = reserve_new_block(dn);
|
||||
err = f2fs_reserve_new_block(dn);
|
||||
if (err || need_put)
|
||||
f2fs_put_dnode(dn);
|
||||
return err;
|
||||
@ -730,7 +730,7 @@ int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
|
||||
return f2fs_reserve_block(dn, index);
|
||||
}
|
||||
|
||||
struct page *get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
int op_flags, bool for_write)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
@ -749,7 +749,7 @@ struct page *get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
}
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
if (err)
|
||||
goto put_err;
|
||||
f2fs_put_dnode(&dn);
|
||||
@ -768,7 +768,8 @@ got_it:
|
||||
* A new dentry page is allocated but not able to be written, since its
|
||||
* new inode page couldn't be allocated due to -ENOSPC.
|
||||
* In such the case, its blkaddr can be remained as NEW_ADDR.
|
||||
* see, f2fs_add_link -> get_new_data_page -> init_inode_metadata.
|
||||
* see, f2fs_add_link -> f2fs_get_new_data_page ->
|
||||
* f2fs_init_inode_metadata.
|
||||
*/
|
||||
if (dn.data_blkaddr == NEW_ADDR) {
|
||||
zero_user_segment(page, 0, PAGE_SIZE);
|
||||
@ -788,7 +789,7 @@ put_err:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct page *find_data_page(struct inode *inode, pgoff_t index)
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
@ -798,7 +799,7 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
|
||||
return page;
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
page = get_read_data_page(inode, index, 0, false);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, false);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@ -818,13 +819,13 @@ struct page *find_data_page(struct inode *inode, pgoff_t index)
|
||||
* Because, the callers, functions in dir.c and GC, should be able to know
|
||||
* whether this page exists or not.
|
||||
*/
|
||||
struct page *get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
bool for_write)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
repeat:
|
||||
page = get_read_data_page(inode, index, 0, for_write);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, for_write);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@ -850,7 +851,7 @@ repeat:
|
||||
* Note that, ipage is set only by make_empty_dir, and if any error occur,
|
||||
* ipage should be released by this function.
|
||||
*/
|
||||
struct page *get_new_data_page(struct inode *inode,
|
||||
struct page *f2fs_get_new_data_page(struct inode *inode,
|
||||
struct page *ipage, pgoff_t index, bool new_i_size)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
@ -889,7 +890,7 @@ struct page *get_new_data_page(struct inode *inode,
|
||||
|
||||
/* if ipage exists, blkaddr should be NEW_ADDR */
|
||||
f2fs_bug_on(F2FS_I_SB(inode), ipage);
|
||||
page = get_lock_data_page(inode, index, true);
|
||||
page = f2fs_get_lock_data_page(inode, index, true);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
}
|
||||
@ -912,7 +913,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
|
||||
return -EPERM;
|
||||
|
||||
err = get_node_info(sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -927,12 +928,12 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
alloc:
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
|
||||
|
||||
allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
|
||||
f2fs_allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
|
||||
&sum, seg_type, NULL, false);
|
||||
set_data_blkaddr(dn);
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
|
||||
/* update i_size */
|
||||
fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
|
||||
fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
|
||||
dn->ofs_in_node;
|
||||
if (i_size_read(dn->inode) < ((loff_t)(fofs + 1) << PAGE_SHIFT))
|
||||
f2fs_i_size_write(dn->inode,
|
||||
@ -970,7 +971,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
|
||||
map.m_seg_type = NO_CHECK_TYPE;
|
||||
|
||||
if (direct_io) {
|
||||
map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint);
|
||||
map.m_seg_type = f2fs_rw_hint_to_seg_type(iocb->ki_hint);
|
||||
flag = f2fs_force_buffered_io(inode, WRITE) ?
|
||||
F2FS_GET_BLOCK_PRE_AIO :
|
||||
F2FS_GET_BLOCK_PRE_DIO;
|
||||
@ -1060,7 +1061,7 @@ next_dnode:
|
||||
|
||||
/* When reading holes, we need its node page */
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, pgofs, mode);
|
||||
err = f2fs_get_dnode_of_data(&dn, pgofs, mode);
|
||||
if (err) {
|
||||
if (flag == F2FS_GET_BLOCK_BMAP)
|
||||
map->m_pblk = 0;
|
||||
@ -1068,10 +1069,10 @@ next_dnode:
|
||||
err = 0;
|
||||
if (map->m_next_pgofs)
|
||||
*map->m_next_pgofs =
|
||||
get_next_page_offset(&dn, pgofs);
|
||||
f2fs_get_next_page_offset(&dn, pgofs);
|
||||
if (map->m_next_extent)
|
||||
*map->m_next_extent =
|
||||
get_next_page_offset(&dn, pgofs);
|
||||
f2fs_get_next_page_offset(&dn, pgofs);
|
||||
}
|
||||
goto unlock_out;
|
||||
}
|
||||
@ -1163,7 +1164,7 @@ skip:
|
||||
(pgofs == end || dn.ofs_in_node == end_offset)) {
|
||||
|
||||
dn.ofs_in_node = ofs_in_node;
|
||||
err = reserve_new_blocks(&dn, prealloc);
|
||||
err = f2fs_reserve_new_blocks(&dn, prealloc);
|
||||
if (err)
|
||||
goto sync_out;
|
||||
|
||||
@ -1282,7 +1283,7 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock,
|
||||
{
|
||||
return __get_data_block(inode, iblock, bh_result, create,
|
||||
F2FS_GET_BLOCK_DEFAULT, NULL,
|
||||
rw_hint_to_seg_type(
|
||||
f2fs_rw_hint_to_seg_type(
|
||||
inode->i_write_hint));
|
||||
}
|
||||
|
||||
@ -1327,7 +1328,7 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
err = get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
@ -1359,7 +1360,7 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
err = get_node_info(sbi, xnid, &ni);
|
||||
err = f2fs_get_node_info(sbi, xnid, &ni);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
@ -1691,12 +1692,12 @@ static inline bool check_inplace_update_policy(struct inode *inode,
|
||||
|
||||
if (policy & (0x1 << F2FS_IPU_FORCE))
|
||||
return true;
|
||||
if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi))
|
||||
if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi))
|
||||
return true;
|
||||
if (policy & (0x1 << F2FS_IPU_UTIL) &&
|
||||
utilization(sbi) > SM_I(sbi)->min_ipu_util)
|
||||
return true;
|
||||
if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && need_SSR(sbi) &&
|
||||
if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && f2fs_need_SSR(sbi) &&
|
||||
utilization(sbi) > SM_I(sbi)->min_ipu_util)
|
||||
return true;
|
||||
|
||||
@ -1717,7 +1718,7 @@ static inline bool check_inplace_update_policy(struct inode *inode,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
{
|
||||
if (f2fs_is_pinned_file(inode))
|
||||
return true;
|
||||
@ -1729,7 +1730,7 @@ bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
return check_inplace_update_policy(inode, fio);
|
||||
}
|
||||
|
||||
bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
|
||||
@ -1752,13 +1753,13 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio)
|
||||
{
|
||||
struct inode *inode = fio->page->mapping->host;
|
||||
|
||||
if (should_update_outplace(inode, fio))
|
||||
if (f2fs_should_update_outplace(inode, fio))
|
||||
return false;
|
||||
|
||||
return should_update_inplace(inode, fio);
|
||||
return f2fs_should_update_inplace(inode, fio);
|
||||
}
|
||||
|
||||
int do_write_data_page(struct f2fs_io_info *fio)
|
||||
int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
{
|
||||
struct page *page = fio->page;
|
||||
struct inode *inode = page->mapping->host;
|
||||
@ -1786,7 +1787,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
|
||||
if (fio->need_lock == LOCK_REQ && !f2fs_trylock_op(fio->sbi))
|
||||
return -EAGAIN;
|
||||
|
||||
err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -1819,7 +1820,7 @@ got_it:
|
||||
f2fs_put_dnode(&dn);
|
||||
if (fio->need_lock == LOCK_REQ)
|
||||
f2fs_unlock_op(fio->sbi);
|
||||
err = rewrite_data_page(fio);
|
||||
err = f2fs_inplace_write_data(fio);
|
||||
trace_f2fs_do_write_data_page(fio->page, IPU);
|
||||
set_inode_flag(inode, FI_UPDATE_WRITE);
|
||||
return err;
|
||||
@ -1833,7 +1834,7 @@ got_it:
|
||||
fio->need_lock = LOCK_REQ;
|
||||
}
|
||||
|
||||
err = get_node_info(fio->sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio->sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
@ -1847,7 +1848,7 @@ got_it:
|
||||
ClearPageError(page);
|
||||
|
||||
/* LFS mode write path */
|
||||
write_data_page(&dn, fio);
|
||||
f2fs_outplace_write_data(&dn, fio);
|
||||
trace_f2fs_do_write_data_page(page, OPU);
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
if (page->index == 0)
|
||||
@ -1893,6 +1894,12 @@ static int __write_data_page(struct page *page, bool *submitted,
|
||||
/* we should bypass data pages to proceed the kworkder jobs */
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
mapping_set_error(page->mapping, -EIO);
|
||||
/*
|
||||
* don't drop any dirty dentry pages for keeping lastest
|
||||
* directory structure.
|
||||
*/
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
goto redirty_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1917,13 +1924,13 @@ write:
|
||||
/* we should not write 0'th page having journal header */
|
||||
if (f2fs_is_volatile_file(inode) && (!page->index ||
|
||||
(!wbc->for_reclaim &&
|
||||
available_free_memory(sbi, BASE_CHECK))))
|
||||
f2fs_available_free_memory(sbi, BASE_CHECK))))
|
||||
goto redirty_out;
|
||||
|
||||
/* Dentry blocks are controlled by checkpoint */
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
fio.need_lock = LOCK_DONE;
|
||||
err = do_write_data_page(&fio);
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -1942,10 +1949,10 @@ write:
|
||||
}
|
||||
|
||||
if (err == -EAGAIN) {
|
||||
err = do_write_data_page(&fio);
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
if (err == -EAGAIN) {
|
||||
fio.need_lock = LOCK_REQ;
|
||||
err = do_write_data_page(&fio);
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1970,7 +1977,7 @@ out:
|
||||
if (wbc->for_reclaim) {
|
||||
f2fs_submit_merged_write_cond(sbi, inode, 0, page->index, DATA);
|
||||
clear_inode_flag(inode, FI_HOT_DATA);
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
submitted = NULL;
|
||||
}
|
||||
|
||||
@ -2020,6 +2027,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
|
||||
int ret = 0;
|
||||
int done = 0;
|
||||
struct pagevec pvec;
|
||||
struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
|
||||
int nr_pages;
|
||||
pgoff_t uninitialized_var(writeback_index);
|
||||
pgoff_t index;
|
||||
@ -2064,8 +2072,8 @@ retry:
|
||||
while (!done && (index <= end)) {
|
||||
int i;
|
||||
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1);
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
|
||||
@ -2073,7 +2081,9 @@ retry:
|
||||
struct page *page = pvec.pages[i];
|
||||
bool submitted = false;
|
||||
|
||||
if (page->index > end) {
|
||||
/* give a priority to WB_SYNC threads */
|
||||
if (atomic_read(&sbi->wb_sync_req[DATA]) &&
|
||||
wbc->sync_mode == WB_SYNC_NONE) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
@ -2132,9 +2142,7 @@ continue_unlock:
|
||||
last_idx = page->index;
|
||||
}
|
||||
|
||||
/* give a priority to WB_SYNC threads */
|
||||
if ((atomic_read(&F2FS_M_SB(mapping)->wb_sync_req) ||
|
||||
--wbc->nr_to_write <= 0) &&
|
||||
if (--wbc->nr_to_write <= 0 &&
|
||||
wbc->sync_mode == WB_SYNC_NONE) {
|
||||
done = 1;
|
||||
break;
|
||||
@ -2172,7 +2180,7 @@ static inline bool __should_serialize_io(struct inode *inode,
|
||||
return false;
|
||||
}
|
||||
|
||||
int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc,
|
||||
enum iostat_type io_type)
|
||||
{
|
||||
@ -2196,7 +2204,7 @@ int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
|
||||
if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
|
||||
get_dirty_pages(inode) < nr_pages_to_skip(sbi, DATA) &&
|
||||
available_free_memory(sbi, DIRTY_DENTS))
|
||||
f2fs_available_free_memory(sbi, DIRTY_DENTS))
|
||||
goto skip_write;
|
||||
|
||||
/* skip writing during file defragment */
|
||||
@ -2207,8 +2215,8 @@ int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
|
||||
/* to avoid spliting IOs due to mixed WB_SYNC_ALL and WB_SYNC_NONE */
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_inc(&sbi->wb_sync_req);
|
||||
else if (atomic_read(&sbi->wb_sync_req))
|
||||
atomic_inc(&sbi->wb_sync_req[DATA]);
|
||||
else if (atomic_read(&sbi->wb_sync_req[DATA]))
|
||||
goto skip_write;
|
||||
|
||||
if (__should_serialize_io(inode, wbc)) {
|
||||
@ -2224,13 +2232,13 @@ int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
mutex_unlock(&sbi->writepages);
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_dec(&sbi->wb_sync_req);
|
||||
atomic_dec(&sbi->wb_sync_req[DATA]);
|
||||
/*
|
||||
* if some pages were truncated, we cannot guarantee its mapping->host
|
||||
* to detect pending bios.
|
||||
*/
|
||||
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
return ret;
|
||||
|
||||
skip_write:
|
||||
@ -2257,7 +2265,7 @@ static void f2fs_write_failed(struct address_space *mapping, loff_t to)
|
||||
if (to > i_size) {
|
||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
truncate_pagecache(inode, i_size);
|
||||
truncate_blocks(inode, i_size, true);
|
||||
f2fs_truncate_blocks(inode, i_size, true);
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
}
|
||||
}
|
||||
@ -2296,7 +2304,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
restart:
|
||||
/* check inline_data */
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
err = PTR_ERR(ipage);
|
||||
goto unlock_out;
|
||||
@ -2306,7 +2314,7 @@ restart:
|
||||
|
||||
if (f2fs_has_inline_data(inode)) {
|
||||
if (pos + len <= MAX_INLINE_DATA(inode)) {
|
||||
read_inline_data(page, ipage);
|
||||
f2fs_do_read_inline_data(page, ipage);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
if (inode->i_nlink)
|
||||
set_inline_node(ipage);
|
||||
@ -2324,7 +2332,7 @@ restart:
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
} else {
|
||||
/* hole case */
|
||||
err = get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
if (err || dn.data_blkaddr == NULL_ADDR) {
|
||||
f2fs_put_dnode(&dn);
|
||||
__do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
|
||||
@ -2372,7 +2380,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
trace_f2fs_write_begin(inode, pos, len, flags);
|
||||
|
||||
if (f2fs_is_atomic_file(inode) &&
|
||||
!available_free_memory(sbi, INMEM_PAGES)) {
|
||||
!f2fs_available_free_memory(sbi, INMEM_PAGES)) {
|
||||
err = -ENOMEM;
|
||||
drop_atomic = true;
|
||||
goto fail;
|
||||
@ -2452,7 +2460,7 @@ fail:
|
||||
f2fs_put_page(page, 1);
|
||||
f2fs_write_failed(mapping, pos + len);
|
||||
if (drop_atomic)
|
||||
drop_inmem_pages_all(sbi);
|
||||
f2fs_drop_inmem_pages_all(sbi, false);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -2550,17 +2558,17 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = WRITE_LIFE_NOT_SET;
|
||||
|
||||
if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) {
|
||||
if (!down_read_trylock(&F2FS_I(inode)->i_gc_rwsem[rw])) {
|
||||
if (iocb->ki_flags & IOCB_NOWAIT) {
|
||||
iocb->ki_hint = hint;
|
||||
err = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
down_read(&F2FS_I(inode)->dio_rwsem[rw]);
|
||||
down_read(&F2FS_I(inode)->i_gc_rwsem[rw]);
|
||||
}
|
||||
|
||||
err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
|
||||
up_read(&F2FS_I(inode)->dio_rwsem[rw]);
|
||||
up_read(&F2FS_I(inode)->i_gc_rwsem[rw]);
|
||||
|
||||
if (rw == WRITE) {
|
||||
if (whint_mode == WHINT_MODE_OFF)
|
||||
@ -2603,13 +2611,13 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
dec_page_count(sbi, F2FS_DIRTY_NODES);
|
||||
} else {
|
||||
inode_dec_dirty_pages(inode);
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
/* This is atomic written page, keep Private */
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page))
|
||||
return drop_inmem_page(inode, page);
|
||||
return f2fs_drop_inmem_page(inode, page);
|
||||
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
@ -2642,7 +2650,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
||||
|
||||
if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
|
||||
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
|
||||
register_inmem_page(inode, page);
|
||||
f2fs_register_inmem_page(inode, page);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
@ -2654,7 +2662,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
||||
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
update_dirty_page(inode, page);
|
||||
f2fs_update_dirty_page(inode, page);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -2750,6 +2758,17 @@ const struct address_space_operations f2fs_dblock_aops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
void f2fs_clear_radix_tree_dirty_tag(struct page *page)
|
||||
{
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
}
|
||||
|
||||
int __init f2fs_init_post_read_processing(void)
|
||||
{
|
||||
bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0);
|
||||
|
@ -104,6 +104,8 @@ static void update_general_status(struct f2fs_sb_info *sbi)
|
||||
si->avail_nids = NM_I(sbi)->available_nids;
|
||||
si->alloc_nids = NM_I(sbi)->nid_cnt[PREALLOC_NID];
|
||||
si->bg_gc = sbi->bg_gc;
|
||||
si->skipped_atomic_files[BG_GC] = sbi->skipped_atomic_files[BG_GC];
|
||||
si->skipped_atomic_files[FG_GC] = sbi->skipped_atomic_files[FG_GC];
|
||||
si->util_free = (int)(free_user_blocks(sbi) >> sbi->log_blocks_per_seg)
|
||||
* 100 / (int)(sbi->user_block_count >> sbi->log_blocks_per_seg)
|
||||
/ 2;
|
||||
@ -342,6 +344,10 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->bg_data_blks);
|
||||
seq_printf(s, " - node blocks : %d (%d)\n", si->node_blks,
|
||||
si->bg_node_blks);
|
||||
seq_printf(s, "Skipped : atomic write %llu (%llu)\n",
|
||||
si->skipped_atomic_files[BG_GC] +
|
||||
si->skipped_atomic_files[FG_GC],
|
||||
si->skipped_atomic_files[BG_GC]);
|
||||
seq_puts(s, "\nExtent Cache:\n");
|
||||
seq_printf(s, " - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n",
|
||||
si->hit_largest, si->hit_cached,
|
||||
|
@ -60,12 +60,12 @@ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
|
||||
[S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK,
|
||||
};
|
||||
|
||||
void set_de_type(struct f2fs_dir_entry *de, umode_t mode)
|
||||
static void set_de_type(struct f2fs_dir_entry *de, umode_t mode)
|
||||
{
|
||||
de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
|
||||
}
|
||||
|
||||
unsigned char get_de_type(struct f2fs_dir_entry *de)
|
||||
unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de)
|
||||
{
|
||||
if (de->file_type < F2FS_FT_MAX)
|
||||
return f2fs_filetype_table[de->file_type];
|
||||
@ -97,14 +97,14 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
|
||||
dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page);
|
||||
|
||||
make_dentry_ptr_block(NULL, &d, dentry_blk);
|
||||
de = find_target_dentry(fname, namehash, max_slots, &d);
|
||||
de = f2fs_find_target_dentry(fname, namehash, max_slots, &d);
|
||||
if (de)
|
||||
*res_page = dentry_page;
|
||||
|
||||
return de;
|
||||
}
|
||||
|
||||
struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
|
||||
struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
|
||||
f2fs_hash_t namehash, int *max_slots,
|
||||
struct f2fs_dentry_ptr *d)
|
||||
{
|
||||
@ -171,7 +171,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
|
||||
for (; bidx < end_block; bidx++) {
|
||||
/* no need to allocate new dentry pages to all the indices */
|
||||
dentry_page = find_data_page(dir, bidx);
|
||||
dentry_page = f2fs_find_data_page(dir, bidx);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
room = true;
|
||||
@ -210,7 +210,7 @@ struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
|
||||
|
||||
if (f2fs_has_inline_dentry(dir)) {
|
||||
*res_page = NULL;
|
||||
de = find_in_inline_dir(dir, fname, res_page);
|
||||
de = f2fs_find_in_inline_dir(dir, fname, res_page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -319,7 +319,7 @@ static void init_dent_inode(const struct qstr *name, struct page *ipage)
|
||||
set_page_dirty(ipage);
|
||||
}
|
||||
|
||||
void do_make_empty_dir(struct inode *inode, struct inode *parent,
|
||||
void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent,
|
||||
struct f2fs_dentry_ptr *d)
|
||||
{
|
||||
struct qstr dot = QSTR_INIT(".", 1);
|
||||
@ -340,23 +340,23 @@ static int make_empty_dir(struct inode *inode,
|
||||
struct f2fs_dentry_ptr d;
|
||||
|
||||
if (f2fs_has_inline_dentry(inode))
|
||||
return make_empty_inline_dir(inode, parent, page);
|
||||
return f2fs_make_empty_inline_dir(inode, parent, page);
|
||||
|
||||
dentry_page = get_new_data_page(inode, page, 0, true);
|
||||
dentry_page = f2fs_get_new_data_page(inode, page, 0, true);
|
||||
if (IS_ERR(dentry_page))
|
||||
return PTR_ERR(dentry_page);
|
||||
|
||||
dentry_blk = page_address(dentry_page);
|
||||
|
||||
make_dentry_ptr_block(NULL, &d, dentry_blk);
|
||||
do_make_empty_dir(inode, parent, &d);
|
||||
f2fs_do_make_empty_dir(inode, parent, &d);
|
||||
|
||||
set_page_dirty(dentry_page);
|
||||
f2fs_put_page(dentry_page, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *new_name, const struct qstr *orig_name,
|
||||
struct page *dpage)
|
||||
{
|
||||
@ -365,7 +365,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
int err;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_NEW_INODE)) {
|
||||
page = new_inode_page(inode);
|
||||
page = f2fs_new_inode_page(inode);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@ -395,7 +395,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
goto put_error;
|
||||
}
|
||||
} else {
|
||||
page = get_node_page(F2FS_I_SB(dir), inode->i_ino);
|
||||
page = f2fs_get_node_page(F2FS_I_SB(dir), inode->i_ino);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
}
|
||||
@ -418,19 +418,19 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
* we should remove this inode from orphan list.
|
||||
*/
|
||||
if (inode->i_nlink == 0)
|
||||
remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino);
|
||||
f2fs_remove_orphan_inode(F2FS_I_SB(dir), inode->i_ino);
|
||||
f2fs_i_links_write(inode, true);
|
||||
}
|
||||
return page;
|
||||
|
||||
put_error:
|
||||
clear_nlink(inode);
|
||||
update_inode(inode, page);
|
||||
f2fs_update_inode(inode, page);
|
||||
f2fs_put_page(page, 1);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
void f2fs_update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
unsigned int current_depth)
|
||||
{
|
||||
if (inode && is_inode_flag_set(inode, FI_NEW_INODE)) {
|
||||
@ -448,7 +448,7 @@ void update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
clear_inode_flag(inode, FI_INC_LINK);
|
||||
}
|
||||
|
||||
int room_for_filename(const void *bitmap, int slots, int max_slots)
|
||||
int f2fs_room_for_filename(const void *bitmap, int slots, int max_slots)
|
||||
{
|
||||
int bit_start = 0;
|
||||
int zero_start, zero_end;
|
||||
@ -537,12 +537,12 @@ start:
|
||||
(le32_to_cpu(dentry_hash) % nbucket));
|
||||
|
||||
for (block = bidx; block <= (bidx + nblock - 1); block++) {
|
||||
dentry_page = get_new_data_page(dir, NULL, block, true);
|
||||
dentry_page = f2fs_get_new_data_page(dir, NULL, block, true);
|
||||
if (IS_ERR(dentry_page))
|
||||
return PTR_ERR(dentry_page);
|
||||
|
||||
dentry_blk = page_address(dentry_page);
|
||||
bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
|
||||
bit_pos = f2fs_room_for_filename(&dentry_blk->dentry_bitmap,
|
||||
slots, NR_DENTRY_IN_BLOCK);
|
||||
if (bit_pos < NR_DENTRY_IN_BLOCK)
|
||||
goto add_dentry;
|
||||
@ -558,7 +558,7 @@ add_dentry:
|
||||
|
||||
if (inode) {
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
page = init_inode_metadata(inode, dir, new_name,
|
||||
page = f2fs_init_inode_metadata(inode, dir, new_name,
|
||||
orig_name, NULL);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
@ -576,7 +576,7 @@ add_dentry:
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
update_parent_metadata(dir, inode, current_depth);
|
||||
f2fs_update_parent_metadata(dir, inode, current_depth);
|
||||
fail:
|
||||
if (inode)
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
@ -586,7 +586,7 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname,
|
||||
int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname,
|
||||
struct inode *inode, nid_t ino, umode_t mode)
|
||||
{
|
||||
struct qstr new_name;
|
||||
@ -610,7 +610,7 @@ int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname,
|
||||
* Caller should grab and release a rwsem by calling f2fs_lock_op() and
|
||||
* f2fs_unlock_op().
|
||||
*/
|
||||
int __f2fs_add_link(struct inode *dir, const struct qstr *name,
|
||||
int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
|
||||
struct inode *inode, nid_t ino, umode_t mode)
|
||||
{
|
||||
struct fscrypt_name fname;
|
||||
@ -639,7 +639,7 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
|
||||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
} else {
|
||||
err = __f2fs_do_add_link(dir, &fname, inode, ino, mode);
|
||||
err = f2fs_add_dentry(dir, &fname, inode, ino, mode);
|
||||
}
|
||||
fscrypt_free_filename(&fname);
|
||||
return err;
|
||||
@ -651,7 +651,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
|
||||
int err = 0;
|
||||
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
page = init_inode_metadata(inode, dir, NULL, NULL, NULL);
|
||||
page = f2fs_init_inode_metadata(inode, dir, NULL, NULL, NULL);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
goto fail;
|
||||
@ -683,9 +683,9 @@ void f2fs_drop_nlink(struct inode *dir, struct inode *inode)
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
|
||||
if (inode->i_nlink == 0)
|
||||
add_orphan_inode(inode);
|
||||
f2fs_add_orphan_inode(inode);
|
||||
else
|
||||
release_orphan_inode(sbi);
|
||||
f2fs_release_orphan_inode(sbi);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -698,14 +698,12 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
struct f2fs_dentry_block *dentry_blk;
|
||||
unsigned int bit_pos;
|
||||
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
|
||||
|
||||
if (F2FS_OPTION(F2FS_I_SB(dir)).fsync_mode == FSYNC_MODE_STRICT)
|
||||
add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
|
||||
f2fs_add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
|
||||
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
return f2fs_delete_inline_entry(dentry, page, dir, inode);
|
||||
@ -731,17 +729,13 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
|
||||
if (bit_pos == NR_DENTRY_IN_BLOCK &&
|
||||
!truncate_hole(dir, page->index, page->index + 1)) {
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
|
||||
!f2fs_truncate_hole(dir, page->index, page->index + 1)) {
|
||||
f2fs_clear_radix_tree_dirty_tag(page);
|
||||
clear_page_dirty_for_io(page);
|
||||
ClearPagePrivate(page);
|
||||
ClearPageUptodate(page);
|
||||
inode_dec_dirty_pages(dir);
|
||||
remove_dirty_inode(dir);
|
||||
f2fs_remove_dirty_inode(dir);
|
||||
}
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
@ -758,7 +752,7 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||
return f2fs_empty_inline_dir(dir);
|
||||
|
||||
for (bidx = 0; bidx < nblock; bidx++) {
|
||||
dentry_page = get_lock_data_page(dir, bidx, false);
|
||||
dentry_page = f2fs_get_lock_data_page(dir, bidx, false);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT)
|
||||
continue;
|
||||
@ -806,7 +800,7 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
|
||||
continue;
|
||||
}
|
||||
|
||||
d_type = get_de_type(de);
|
||||
d_type = f2fs_get_de_type(de);
|
||||
|
||||
de_name.name = d->filename[bit_pos];
|
||||
de_name.len = le16_to_cpu(de->name_len);
|
||||
@ -830,7 +824,7 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
|
||||
return 1;
|
||||
|
||||
if (sbi->readdir_ra == 1)
|
||||
ra_node_page(sbi, le32_to_cpu(de->ino));
|
||||
f2fs_ra_node_page(sbi, le32_to_cpu(de->ino));
|
||||
|
||||
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
|
||||
ctx->pos = start_pos + bit_pos;
|
||||
@ -880,7 +874,7 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
|
||||
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
|
||||
|
||||
dentry_page = get_lock_data_page(inode, n, false);
|
||||
dentry_page = f2fs_get_lock_data_page(inode, n, false);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
err = PTR_ERR(dentry_page);
|
||||
if (err == -ENOENT) {
|
||||
|
@ -49,7 +49,7 @@ static struct rb_entry *__lookup_rb_tree_slow(struct rb_root *root,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rb_entry *__lookup_rb_tree(struct rb_root *root,
|
||||
struct rb_entry *f2fs_lookup_rb_tree(struct rb_root *root,
|
||||
struct rb_entry *cached_re, unsigned int ofs)
|
||||
{
|
||||
struct rb_entry *re;
|
||||
@ -61,7 +61,7 @@ struct rb_entry *__lookup_rb_tree(struct rb_root *root,
|
||||
return re;
|
||||
}
|
||||
|
||||
struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||
struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||
struct rb_root *root, struct rb_node **parent,
|
||||
unsigned int ofs)
|
||||
{
|
||||
@ -92,7 +92,7 @@ struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||
* in order to simpfy the insertion after.
|
||||
* tree must stay unchanged between lookup and insertion.
|
||||
*/
|
||||
struct rb_entry *__lookup_rb_tree_ret(struct rb_root *root,
|
||||
struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root,
|
||||
struct rb_entry *cached_re,
|
||||
unsigned int ofs,
|
||||
struct rb_entry **prev_entry,
|
||||
@ -159,7 +159,7 @@ lookup_neighbors:
|
||||
return re;
|
||||
}
|
||||
|
||||
bool __check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
||||
bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
||||
struct rb_root *root)
|
||||
{
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
@ -390,7 +390,7 @@ static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
|
||||
goto out;
|
||||
}
|
||||
|
||||
en = (struct extent_node *)__lookup_rb_tree(&et->root,
|
||||
en = (struct extent_node *)f2fs_lookup_rb_tree(&et->root,
|
||||
(struct rb_entry *)et->cached_en, pgofs);
|
||||
if (!en)
|
||||
goto out;
|
||||
@ -470,7 +470,7 @@ static struct extent_node *__insert_extent_tree(struct inode *inode,
|
||||
goto do_insert;
|
||||
}
|
||||
|
||||
p = __lookup_rb_tree_for_insert(sbi, &et->root, &parent, ei->fofs);
|
||||
p = f2fs_lookup_rb_tree_for_insert(sbi, &et->root, &parent, ei->fofs);
|
||||
do_insert:
|
||||
en = __attach_extent_node(sbi, et, ei, parent, p);
|
||||
if (!en)
|
||||
@ -520,7 +520,7 @@ static void f2fs_update_extent_tree_range(struct inode *inode,
|
||||
__drop_largest_extent(inode, fofs, len);
|
||||
|
||||
/* 1. lookup first extent node in range [fofs, fofs + len - 1] */
|
||||
en = (struct extent_node *)__lookup_rb_tree_ret(&et->root,
|
||||
en = (struct extent_node *)f2fs_lookup_rb_tree_ret(&et->root,
|
||||
(struct rb_entry *)et->cached_en, fofs,
|
||||
(struct rb_entry **)&prev_en,
|
||||
(struct rb_entry **)&next_en,
|
||||
@ -773,7 +773,7 @@ void f2fs_update_extent_cache(struct dnode_of_data *dn)
|
||||
else
|
||||
blkaddr = dn->data_blkaddr;
|
||||
|
||||
fofs = start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
|
||||
fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) +
|
||||
dn->ofs_in_node;
|
||||
f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, 1);
|
||||
}
|
||||
@ -788,7 +788,7 @@ void f2fs_update_extent_cache_range(struct dnode_of_data *dn,
|
||||
f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len);
|
||||
}
|
||||
|
||||
void init_extent_cache_info(struct f2fs_sb_info *sbi)
|
||||
void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
INIT_RADIX_TREE(&sbi->extent_tree_root, GFP_NOIO);
|
||||
mutex_init(&sbi->extent_tree_lock);
|
||||
@ -800,7 +800,7 @@ void init_extent_cache_info(struct f2fs_sb_info *sbi)
|
||||
atomic_set(&sbi->total_ext_node, 0);
|
||||
}
|
||||
|
||||
int __init create_extent_cache(void)
|
||||
int __init f2fs_create_extent_cache(void)
|
||||
{
|
||||
extent_tree_slab = f2fs_kmem_cache_create("f2fs_extent_tree",
|
||||
sizeof(struct extent_tree));
|
||||
@ -815,7 +815,7 @@ int __init create_extent_cache(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void destroy_extent_cache(void)
|
||||
void f2fs_destroy_extent_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(extent_node_slab);
|
||||
kmem_cache_destroy(extent_tree_slab);
|
||||
|
417
fs/f2fs/f2fs.h
417
fs/f2fs/f2fs.h
@ -25,6 +25,7 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/overflow.h>
|
||||
|
||||
#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_F2FS_FS_ENCRYPTION)
|
||||
#include <linux/fscrypt.h>
|
||||
@ -623,15 +624,20 @@ enum {
|
||||
|
||||
#define DEF_DIR_LEVEL 0
|
||||
|
||||
enum {
|
||||
GC_FAILURE_PIN,
|
||||
GC_FAILURE_ATOMIC,
|
||||
MAX_GC_FAILURE
|
||||
};
|
||||
|
||||
struct f2fs_inode_info {
|
||||
struct inode vfs_inode; /* serve a vfs inode */
|
||||
unsigned long i_flags; /* keep an inode flags for ioctl */
|
||||
unsigned char i_advise; /* use to give file attribute hints */
|
||||
unsigned char i_dir_level; /* use for dentry level for large dir */
|
||||
union {
|
||||
unsigned int i_current_depth; /* only for directory depth */
|
||||
unsigned short i_gc_failures; /* only for regular file */
|
||||
};
|
||||
unsigned int i_current_depth; /* only for directory depth */
|
||||
/* for gc failure statistic */
|
||||
unsigned int i_gc_failures[MAX_GC_FAILURE];
|
||||
unsigned int i_pino; /* parent inode number */
|
||||
umode_t i_acl_mode; /* keep file acl mode temporarily */
|
||||
|
||||
@ -659,7 +665,9 @@ struct f2fs_inode_info {
|
||||
struct task_struct *inmem_task; /* store inmemory task */
|
||||
struct mutex inmem_lock; /* lock for inmemory pages */
|
||||
struct extent_tree *extent_tree; /* cached extent_tree entry */
|
||||
struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */
|
||||
|
||||
/* avoid racing between foreground op and gc */
|
||||
struct rw_semaphore i_gc_rwsem[2];
|
||||
struct rw_semaphore i_mmap_sem;
|
||||
struct rw_semaphore i_xattr_sem; /* avoid racing between reading and changing EAs */
|
||||
|
||||
@ -1010,6 +1018,7 @@ struct f2fs_io_info {
|
||||
int need_lock; /* indicate we need to lock cp_rwsem */
|
||||
bool in_list; /* indicate fio is in io_list */
|
||||
bool is_meta; /* indicate borrow meta inode mapping or not */
|
||||
bool retry; /* need to reallocate block address */
|
||||
enum iostat_type io_type; /* io type */
|
||||
struct writeback_control *io_wbc; /* writeback control */
|
||||
unsigned char version; /* version of the node */
|
||||
@ -1072,6 +1081,13 @@ enum {
|
||||
MAX_TIME,
|
||||
};
|
||||
|
||||
enum {
|
||||
GC_NORMAL,
|
||||
GC_IDLE_CB,
|
||||
GC_IDLE_GREEDY,
|
||||
GC_URGENT,
|
||||
};
|
||||
|
||||
enum {
|
||||
WHINT_MODE_OFF, /* not pass down write hints */
|
||||
WHINT_MODE_USER, /* try to pass down hints given by users */
|
||||
@ -1121,6 +1137,8 @@ struct f2fs_sb_info {
|
||||
struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */
|
||||
struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE];
|
||||
/* bio ordering for NODE/DATA */
|
||||
/* keep migration IO order for LFS mode */
|
||||
struct rw_semaphore io_order_lock;
|
||||
mempool_t *write_io_dummy; /* Dummy pages */
|
||||
|
||||
/* for checkpoint */
|
||||
@ -1191,7 +1209,7 @@ struct f2fs_sb_info {
|
||||
struct percpu_counter alloc_valid_block_count;
|
||||
|
||||
/* writeback control */
|
||||
atomic_t wb_sync_req; /* count # of WB_SYNC threads */
|
||||
atomic_t wb_sync_req[META]; /* count # of WB_SYNC threads */
|
||||
|
||||
/* valid inode count */
|
||||
struct percpu_counter total_valid_inode_count;
|
||||
@ -1202,9 +1220,9 @@ struct f2fs_sb_info {
|
||||
struct mutex gc_mutex; /* mutex for GC */
|
||||
struct f2fs_gc_kthread *gc_thread; /* GC thread */
|
||||
unsigned int cur_victim_sec; /* current victim section num */
|
||||
|
||||
/* threshold for converting bg victims for fg */
|
||||
u64 fggc_threshold;
|
||||
unsigned int gc_mode; /* current GC state */
|
||||
/* for skip statistic */
|
||||
unsigned long long skipped_atomic_files[2]; /* FG_GC and BG_GC */
|
||||
|
||||
/* threshold for gc trials on pinned files */
|
||||
u64 gc_pin_file_threshold;
|
||||
@ -1594,18 +1612,6 @@ static inline bool __exist_node_summaries(struct f2fs_sb_info *sbi)
|
||||
is_set_ckpt_flags(sbi, CP_FASTBOOT_FLAG));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the given nid is within node id range.
|
||||
*/
|
||||
static inline int check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
if (unlikely(nid < F2FS_ROOT_INO(sbi)))
|
||||
return -EINVAL;
|
||||
if (unlikely(nid >= NM_I(sbi)->max_nid))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the inode has blocks or not
|
||||
*/
|
||||
@ -2169,9 +2175,60 @@ static inline void f2fs_change_bit(unsigned int nr, char *addr)
|
||||
*addr ^= mask;
|
||||
}
|
||||
|
||||
#define F2FS_REG_FLMASK (~(FS_DIRSYNC_FL | FS_TOPDIR_FL))
|
||||
#define F2FS_OTHER_FLMASK (FS_NODUMP_FL | FS_NOATIME_FL)
|
||||
#define F2FS_FL_INHERITED (FS_PROJINHERIT_FL)
|
||||
/*
|
||||
* Inode flags
|
||||
*/
|
||||
#define F2FS_SECRM_FL 0x00000001 /* Secure deletion */
|
||||
#define F2FS_UNRM_FL 0x00000002 /* Undelete */
|
||||
#define F2FS_COMPR_FL 0x00000004 /* Compress file */
|
||||
#define F2FS_SYNC_FL 0x00000008 /* Synchronous updates */
|
||||
#define F2FS_IMMUTABLE_FL 0x00000010 /* Immutable file */
|
||||
#define F2FS_APPEND_FL 0x00000020 /* writes to file may only append */
|
||||
#define F2FS_NODUMP_FL 0x00000040 /* do not dump file */
|
||||
#define F2FS_NOATIME_FL 0x00000080 /* do not update atime */
|
||||
/* Reserved for compression usage... */
|
||||
#define F2FS_DIRTY_FL 0x00000100
|
||||
#define F2FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
|
||||
#define F2FS_NOCOMPR_FL 0x00000400 /* Don't compress */
|
||||
#define F2FS_ENCRYPT_FL 0x00000800 /* encrypted file */
|
||||
/* End compression flags --- maybe not all used */
|
||||
#define F2FS_INDEX_FL 0x00001000 /* hash-indexed directory */
|
||||
#define F2FS_IMAGIC_FL 0x00002000 /* AFS directory */
|
||||
#define F2FS_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
|
||||
#define F2FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */
|
||||
#define F2FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
|
||||
#define F2FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
|
||||
#define F2FS_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
|
||||
#define F2FS_EXTENTS_FL 0x00080000 /* Inode uses extents */
|
||||
#define F2FS_EA_INODE_FL 0x00200000 /* Inode used for large EA */
|
||||
#define F2FS_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
|
||||
#define F2FS_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
|
||||
#define F2FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
|
||||
#define F2FS_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
|
||||
|
||||
#define F2FS_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
|
||||
#define F2FS_FL_USER_MODIFIABLE 0x204BC0FF /* User modifiable flags */
|
||||
|
||||
/* Flags we can manipulate with through F2FS_IOC_FSSETXATTR */
|
||||
#define F2FS_FL_XFLAG_VISIBLE (F2FS_SYNC_FL | \
|
||||
F2FS_IMMUTABLE_FL | \
|
||||
F2FS_APPEND_FL | \
|
||||
F2FS_NODUMP_FL | \
|
||||
F2FS_NOATIME_FL | \
|
||||
F2FS_PROJINHERIT_FL)
|
||||
|
||||
/* Flags that should be inherited by new inodes from their parent. */
|
||||
#define F2FS_FL_INHERITED (F2FS_SECRM_FL | F2FS_UNRM_FL | F2FS_COMPR_FL |\
|
||||
F2FS_SYNC_FL | F2FS_NODUMP_FL | F2FS_NOATIME_FL |\
|
||||
F2FS_NOCOMPR_FL | F2FS_JOURNAL_DATA_FL |\
|
||||
F2FS_NOTAIL_FL | F2FS_DIRSYNC_FL |\
|
||||
F2FS_PROJINHERIT_FL)
|
||||
|
||||
/* Flags that are appropriate for regular files (all but dir-specific ones). */
|
||||
#define F2FS_REG_FLMASK (~(F2FS_DIRSYNC_FL | F2FS_TOPDIR_FL))
|
||||
|
||||
/* Flags that are appropriate for non-directories/regular files. */
|
||||
#define F2FS_OTHER_FLMASK (F2FS_NODUMP_FL | F2FS_NOATIME_FL)
|
||||
|
||||
static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
|
||||
{
|
||||
@ -2214,6 +2271,7 @@ enum {
|
||||
FI_EXTRA_ATTR, /* indicate file has extra attribute */
|
||||
FI_PROJ_INHERIT, /* indicate file inherits projectid */
|
||||
FI_PIN_FILE, /* indicate file should not be gced */
|
||||
FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */
|
||||
};
|
||||
|
||||
static inline void __mark_inode_dirty_flag(struct inode *inode,
|
||||
@ -2312,7 +2370,7 @@ static inline void f2fs_i_depth_write(struct inode *inode, unsigned int depth)
|
||||
static inline void f2fs_i_gc_failures_write(struct inode *inode,
|
||||
unsigned int count)
|
||||
{
|
||||
F2FS_I(inode)->i_gc_failures = count;
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = count;
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
|
||||
@ -2590,7 +2648,7 @@ static inline int get_inline_xattr_addrs(struct inode *inode)
|
||||
return F2FS_I(inode)->i_inline_xattr_size;
|
||||
}
|
||||
|
||||
#define get_inode_mode(i) \
|
||||
#define f2fs_get_inode_mode(i) \
|
||||
((is_inode_flag_set(i, FI_ACL_MODE)) ? \
|
||||
(F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
|
||||
|
||||
@ -2666,14 +2724,14 @@ static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
|
||||
* file.c
|
||||
*/
|
||||
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
void truncate_data_blocks(struct dnode_of_data *dn);
|
||||
int truncate_blocks(struct inode *inode, u64 from, bool lock);
|
||||
void f2fs_truncate_data_blocks(struct dnode_of_data *dn);
|
||||
int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock);
|
||||
int f2fs_truncate(struct inode *inode);
|
||||
int f2fs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
int f2fs_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);
|
||||
void truncate_data_blocks_range(struct dnode_of_data *dn, int count);
|
||||
int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end);
|
||||
void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count);
|
||||
int f2fs_precache_extents(struct inode *inode);
|
||||
long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
@ -2687,38 +2745,37 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page);
|
||||
void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page);
|
||||
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino);
|
||||
struct inode *f2fs_iget_retry(struct super_block *sb, unsigned long ino);
|
||||
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
|
||||
void update_inode(struct inode *inode, struct page *node_page);
|
||||
void update_inode_page(struct inode *inode);
|
||||
int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink);
|
||||
void f2fs_update_inode(struct inode *inode, struct page *node_page);
|
||||
void f2fs_update_inode_page(struct inode *inode);
|
||||
int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc);
|
||||
void f2fs_evict_inode(struct inode *inode);
|
||||
void handle_failed_inode(struct inode *inode);
|
||||
void f2fs_handle_failed_inode(struct inode *inode);
|
||||
|
||||
/*
|
||||
* namei.c
|
||||
*/
|
||||
int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set);
|
||||
struct dentry *f2fs_get_parent(struct dentry *child);
|
||||
|
||||
/*
|
||||
* dir.c
|
||||
*/
|
||||
void set_de_type(struct f2fs_dir_entry *de, umode_t mode);
|
||||
unsigned char get_de_type(struct f2fs_dir_entry *de);
|
||||
struct f2fs_dir_entry *find_target_dentry(struct fscrypt_name *fname,
|
||||
unsigned char f2fs_get_de_type(struct f2fs_dir_entry *de);
|
||||
struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname,
|
||||
f2fs_hash_t namehash, int *max_slots,
|
||||
struct f2fs_dentry_ptr *d);
|
||||
int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
|
||||
unsigned int start_pos, struct fscrypt_str *fstr);
|
||||
void do_make_empty_dir(struct inode *inode, struct inode *parent,
|
||||
void f2fs_do_make_empty_dir(struct inode *inode, struct inode *parent,
|
||||
struct f2fs_dentry_ptr *d);
|
||||
struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
struct page *f2fs_init_inode_metadata(struct inode *inode, struct inode *dir,
|
||||
const struct qstr *new_name,
|
||||
const struct qstr *orig_name, struct page *dpage);
|
||||
void update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
void f2fs_update_parent_metadata(struct inode *dir, struct inode *inode,
|
||||
unsigned int current_depth);
|
||||
int room_for_filename(const void *bitmap, int slots, int max_slots);
|
||||
int f2fs_room_for_filename(const void *bitmap, int slots, int max_slots);
|
||||
void f2fs_drop_nlink(struct inode *dir, struct inode *inode);
|
||||
struct f2fs_dir_entry *__f2fs_find_entry(struct inode *dir,
|
||||
struct fscrypt_name *fname, struct page **res_page);
|
||||
@ -2735,9 +2792,9 @@ void f2fs_update_dentry(nid_t ino, umode_t mode, struct f2fs_dentry_ptr *d,
|
||||
int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
|
||||
const struct qstr *orig_name,
|
||||
struct inode *inode, nid_t ino, umode_t mode);
|
||||
int __f2fs_do_add_link(struct inode *dir, struct fscrypt_name *fname,
|
||||
int f2fs_add_dentry(struct inode *dir, struct fscrypt_name *fname,
|
||||
struct inode *inode, nid_t ino, umode_t mode);
|
||||
int __f2fs_add_link(struct inode *dir, const struct qstr *name,
|
||||
int f2fs_do_add_link(struct inode *dir, const struct qstr *name,
|
||||
struct inode *inode, nid_t ino, umode_t mode);
|
||||
void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
struct inode *dir, struct inode *inode);
|
||||
@ -2746,7 +2803,7 @@ bool f2fs_empty_dir(struct inode *dir);
|
||||
|
||||
static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
|
||||
{
|
||||
return __f2fs_add_link(d_inode(dentry->d_parent), &dentry->d_name,
|
||||
return f2fs_do_add_link(d_inode(dentry->d_parent), &dentry->d_name,
|
||||
inode, inode->i_ino, inode->i_mode);
|
||||
}
|
||||
|
||||
@ -2761,7 +2818,7 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover);
|
||||
int f2fs_sync_fs(struct super_block *sb, int sync);
|
||||
extern __printf(3, 4)
|
||||
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
|
||||
int sanity_check_ckpt(struct f2fs_sb_info *sbi);
|
||||
int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi);
|
||||
|
||||
/*
|
||||
* hash.c
|
||||
@ -2775,140 +2832,147 @@ f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info,
|
||||
struct dnode_of_data;
|
||||
struct node_info;
|
||||
|
||||
bool available_free_memory(struct f2fs_sb_info *sbi, int type);
|
||||
int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni);
|
||||
pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs);
|
||||
int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode);
|
||||
int truncate_inode_blocks(struct inode *inode, pgoff_t from);
|
||||
int truncate_xattr_node(struct inode *inode);
|
||||
int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int remove_inode_page(struct inode *inode);
|
||||
struct page *new_inode_page(struct inode *inode);
|
||||
struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs);
|
||||
void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid);
|
||||
struct page *get_node_page_ra(struct page *parent, int start);
|
||||
int move_node_page(struct page *node_page, int gc_type);
|
||||
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
int f2fs_check_nid_range(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type);
|
||||
int f2fs_need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool f2fs_is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||
struct node_info *ni);
|
||||
pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs);
|
||||
int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode);
|
||||
int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from);
|
||||
int f2fs_truncate_xattr_node(struct inode *inode);
|
||||
int f2fs_wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int f2fs_remove_inode_page(struct inode *inode);
|
||||
struct page *f2fs_new_inode_page(struct inode *inode);
|
||||
struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs);
|
||||
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid);
|
||||
struct page *f2fs_get_node_page_ra(struct page *parent, int start);
|
||||
int f2fs_move_node_page(struct page *node_page, int gc_type);
|
||||
int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
struct writeback_control *wbc, bool atomic);
|
||||
int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
|
||||
int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
|
||||
struct writeback_control *wbc,
|
||||
bool do_balance, enum iostat_type io_type);
|
||||
int build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount);
|
||||
bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid);
|
||||
void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink);
|
||||
void recover_inline_xattr(struct inode *inode, struct page *page);
|
||||
int recover_xattr_data(struct inode *inode, struct page *page);
|
||||
int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
|
||||
int restore_node_summary(struct f2fs_sb_info *sbi,
|
||||
int f2fs_build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount);
|
||||
bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid);
|
||||
void f2fs_alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
void f2fs_alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid);
|
||||
int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink);
|
||||
void f2fs_recover_inline_xattr(struct inode *inode, struct page *page);
|
||||
int f2fs_recover_xattr_data(struct inode *inode, struct page *page);
|
||||
int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
|
||||
int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
|
||||
unsigned int segno, struct f2fs_summary_block *sum);
|
||||
int flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
int build_node_manager(struct f2fs_sb_info *sbi);
|
||||
void destroy_node_manager(struct f2fs_sb_info *sbi);
|
||||
int __init create_node_manager_caches(void);
|
||||
void destroy_node_manager_caches(void);
|
||||
int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
int f2fs_build_node_manager(struct f2fs_sb_info *sbi);
|
||||
void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_node_manager_caches(void);
|
||||
void f2fs_destroy_node_manager_caches(void);
|
||||
|
||||
/*
|
||||
* segment.c
|
||||
*/
|
||||
bool need_SSR(struct f2fs_sb_info *sbi);
|
||||
void register_inmem_page(struct inode *inode, struct page *page);
|
||||
void drop_inmem_pages_all(struct f2fs_sb_info *sbi);
|
||||
void drop_inmem_pages(struct inode *inode);
|
||||
void drop_inmem_page(struct inode *inode, struct page *page);
|
||||
int commit_inmem_pages(struct inode *inode);
|
||||
bool f2fs_need_SSR(struct f2fs_sb_info *sbi);
|
||||
void f2fs_register_inmem_page(struct inode *inode, struct page *page);
|
||||
void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure);
|
||||
void f2fs_drop_inmem_pages(struct inode *inode);
|
||||
void f2fs_drop_inmem_page(struct inode *inode, struct page *page);
|
||||
int f2fs_commit_inmem_pages(struct inode *inode);
|
||||
void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need);
|
||||
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi);
|
||||
int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int create_flush_cmd_control(struct f2fs_sb_info *sbi);
|
||||
int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi);
|
||||
int f2fs_flush_device_cache(struct f2fs_sb_info *sbi);
|
||||
void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free);
|
||||
void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
|
||||
bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
|
||||
void drop_discard_cmd(struct f2fs_sb_info *sbi);
|
||||
void stop_discard_thread(struct f2fs_sb_info *sbi);
|
||||
void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free);
|
||||
void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr);
|
||||
bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr);
|
||||
void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi);
|
||||
void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi);
|
||||
bool f2fs_wait_discard_bios(struct f2fs_sb_info *sbi);
|
||||
void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
void release_discard_addrs(struct f2fs_sb_info *sbi);
|
||||
int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
|
||||
void allocate_new_segments(struct f2fs_sb_info *sbi);
|
||||
void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
|
||||
struct cp_control *cpc);
|
||||
void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi);
|
||||
int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra);
|
||||
void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi);
|
||||
int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range);
|
||||
bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno);
|
||||
void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr);
|
||||
void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
|
||||
struct cp_control *cpc);
|
||||
struct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno);
|
||||
void f2fs_update_meta_page(struct f2fs_sb_info *sbi, void *src,
|
||||
block_t blk_addr);
|
||||
void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
enum iostat_type io_type);
|
||||
void write_node_page(unsigned int nid, struct f2fs_io_info *fio);
|
||||
void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio);
|
||||
int rewrite_data_page(struct f2fs_io_info *fio);
|
||||
void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio);
|
||||
void f2fs_outplace_write_data(struct dnode_of_data *dn,
|
||||
struct f2fs_io_info *fio);
|
||||
int f2fs_inplace_write_data(struct f2fs_io_info *fio);
|
||||
void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
block_t old_blkaddr, block_t new_blkaddr,
|
||||
bool recover_curseg, bool recover_newaddr);
|
||||
void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
|
||||
block_t old_addr, block_t new_addr,
|
||||
unsigned char version, bool recover_curseg,
|
||||
bool recover_newaddr);
|
||||
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t old_blkaddr, block_t *new_blkaddr,
|
||||
struct f2fs_summary *sum, int type,
|
||||
struct f2fs_io_info *fio, bool add_list);
|
||||
void f2fs_wait_on_page_writeback(struct page *page,
|
||||
enum page_type type, bool ordered);
|
||||
void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr);
|
||||
void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
|
||||
void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
|
||||
int lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
|
||||
void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
|
||||
void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
|
||||
int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
|
||||
unsigned int val, int alloc);
|
||||
void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
int build_segment_manager(struct f2fs_sb_info *sbi);
|
||||
void destroy_segment_manager(struct f2fs_sb_info *sbi);
|
||||
int __init create_segment_manager_caches(void);
|
||||
void destroy_segment_manager_caches(void);
|
||||
int rw_hint_to_seg_type(enum rw_hint hint);
|
||||
enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
enum temp_type temp);
|
||||
void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
int f2fs_build_segment_manager(struct f2fs_sb_info *sbi);
|
||||
void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_segment_manager_caches(void);
|
||||
void f2fs_destroy_segment_manager_caches(void);
|
||||
int f2fs_rw_hint_to_seg_type(enum rw_hint hint);
|
||||
enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
|
||||
enum page_type type, enum temp_type temp);
|
||||
|
||||
/*
|
||||
* checkpoint.c
|
||||
*/
|
||||
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
|
||||
struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type);
|
||||
int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
block_t blkaddr, int type);
|
||||
int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int type, bool sync);
|
||||
void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
void f2fs_ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
long f2fs_sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
|
||||
long nr_to_write, enum iostat_type io_type);
|
||||
void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
|
||||
void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
|
||||
void release_ino_entry(struct f2fs_sb_info *sbi, bool all);
|
||||
bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode);
|
||||
void set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
void f2fs_add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
|
||||
void f2fs_remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type);
|
||||
void f2fs_release_ino_entry(struct f2fs_sb_info *sbi, bool all);
|
||||
bool f2fs_exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode);
|
||||
void f2fs_set_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
unsigned int devidx, int type);
|
||||
bool is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
bool f2fs_is_dirty_device(struct f2fs_sb_info *sbi, nid_t ino,
|
||||
unsigned int devidx, int type);
|
||||
int f2fs_sync_inode_meta(struct f2fs_sb_info *sbi);
|
||||
int acquire_orphan_inode(struct f2fs_sb_info *sbi);
|
||||
void release_orphan_inode(struct f2fs_sb_info *sbi);
|
||||
void add_orphan_inode(struct inode *inode);
|
||||
void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int recover_orphan_inodes(struct f2fs_sb_info *sbi);
|
||||
int get_valid_checkpoint(struct f2fs_sb_info *sbi);
|
||||
void update_dirty_page(struct inode *inode, struct page *page);
|
||||
void remove_dirty_inode(struct inode *inode);
|
||||
int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type);
|
||||
int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
void init_ino_entry_info(struct f2fs_sb_info *sbi);
|
||||
int __init create_checkpoint_caches(void);
|
||||
void destroy_checkpoint_caches(void);
|
||||
int f2fs_acquire_orphan_inode(struct f2fs_sb_info *sbi);
|
||||
void f2fs_release_orphan_inode(struct f2fs_sb_info *sbi);
|
||||
void f2fs_add_orphan_inode(struct inode *inode);
|
||||
void f2fs_remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino);
|
||||
int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi);
|
||||
int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi);
|
||||
void f2fs_update_dirty_page(struct inode *inode, struct page *page);
|
||||
void f2fs_remove_dirty_inode(struct inode *inode);
|
||||
int f2fs_sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type);
|
||||
int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc);
|
||||
void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_checkpoint_caches(void);
|
||||
void f2fs_destroy_checkpoint_caches(void);
|
||||
|
||||
/*
|
||||
* data.c
|
||||
@ -2921,34 +2985,31 @@ void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
|
||||
enum page_type type);
|
||||
void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi);
|
||||
int f2fs_submit_page_bio(struct f2fs_io_info *fio);
|
||||
int f2fs_submit_page_write(struct f2fs_io_info *fio);
|
||||
void f2fs_submit_page_write(struct f2fs_io_info *fio);
|
||||
struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi,
|
||||
block_t blk_addr, struct bio *bio);
|
||||
int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr);
|
||||
void set_data_blkaddr(struct dnode_of_data *dn);
|
||||
void f2fs_set_data_blkaddr(struct dnode_of_data *dn);
|
||||
void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr);
|
||||
int reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
|
||||
int reserve_new_block(struct dnode_of_data *dn);
|
||||
int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count);
|
||||
int f2fs_reserve_new_block(struct dnode_of_data *dn);
|
||||
int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index);
|
||||
int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from);
|
||||
int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index);
|
||||
struct page *get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
int op_flags, bool for_write);
|
||||
struct page *find_data_page(struct inode *inode, pgoff_t index);
|
||||
struct page *get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index);
|
||||
struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
bool for_write);
|
||||
struct page *get_new_data_page(struct inode *inode,
|
||||
struct page *f2fs_get_new_data_page(struct inode *inode,
|
||||
struct page *ipage, pgoff_t index, bool new_i_size);
|
||||
int do_write_data_page(struct f2fs_io_info *fio);
|
||||
int f2fs_do_write_data_page(struct f2fs_io_info *fio);
|
||||
int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
int create, int flag);
|
||||
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 len);
|
||||
bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
|
||||
bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
|
||||
int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc,
|
||||
enum iostat_type io_type);
|
||||
bool f2fs_should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
|
||||
bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
|
||||
void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
unsigned int length);
|
||||
int f2fs_release_page(struct page *page, gfp_t wait);
|
||||
@ -2957,22 +3018,23 @@ int f2fs_migrate_page(struct address_space *mapping, struct page *newpage,
|
||||
struct page *page, enum migrate_mode mode);
|
||||
#endif
|
||||
bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len);
|
||||
void f2fs_clear_radix_tree_dirty_tag(struct page *page);
|
||||
|
||||
/*
|
||||
* gc.c
|
||||
*/
|
||||
int start_gc_thread(struct f2fs_sb_info *sbi);
|
||||
void stop_gc_thread(struct f2fs_sb_info *sbi);
|
||||
block_t start_bidx_of_node(unsigned int node_ofs, struct inode *inode);
|
||||
int f2fs_start_gc_thread(struct f2fs_sb_info *sbi);
|
||||
void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi);
|
||||
block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode);
|
||||
int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background,
|
||||
unsigned int segno);
|
||||
void build_gc_manager(struct f2fs_sb_info *sbi);
|
||||
void f2fs_build_gc_manager(struct f2fs_sb_info *sbi);
|
||||
|
||||
/*
|
||||
* recovery.c
|
||||
*/
|
||||
int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
|
||||
bool space_for_roll_forward(struct f2fs_sb_info *sbi);
|
||||
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
|
||||
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi);
|
||||
|
||||
/*
|
||||
* debug.c
|
||||
@ -3010,6 +3072,7 @@ struct f2fs_stat_info {
|
||||
int bg_node_segs, bg_data_segs;
|
||||
int tot_blks, data_blks, node_blks;
|
||||
int bg_data_blks, bg_node_blks;
|
||||
unsigned long long skipped_atomic_files[2];
|
||||
int curseg[NR_CURSEG_TYPE];
|
||||
int cursec[NR_CURSEG_TYPE];
|
||||
int curzone[NR_CURSEG_TYPE];
|
||||
@ -3176,29 +3239,31 @@ extern const struct inode_operations f2fs_dir_inode_operations;
|
||||
extern const struct inode_operations f2fs_symlink_inode_operations;
|
||||
extern const struct inode_operations f2fs_encrypted_symlink_inode_operations;
|
||||
extern const struct inode_operations f2fs_special_inode_operations;
|
||||
extern struct kmem_cache *inode_entry_slab;
|
||||
extern struct kmem_cache *f2fs_inode_entry_slab;
|
||||
|
||||
/*
|
||||
* inline.c
|
||||
*/
|
||||
bool f2fs_may_inline_data(struct inode *inode);
|
||||
bool f2fs_may_inline_dentry(struct inode *inode);
|
||||
void read_inline_data(struct page *page, struct page *ipage);
|
||||
void truncate_inline_inode(struct inode *inode, struct page *ipage, u64 from);
|
||||
void f2fs_do_read_inline_data(struct page *page, struct page *ipage);
|
||||
void f2fs_truncate_inline_inode(struct inode *inode,
|
||||
struct page *ipage, u64 from);
|
||||
int f2fs_read_inline_data(struct inode *inode, struct page *page);
|
||||
int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page);
|
||||
int f2fs_convert_inline_inode(struct inode *inode);
|
||||
int f2fs_write_inline_data(struct inode *inode, struct page *page);
|
||||
bool recover_inline_data(struct inode *inode, struct page *npage);
|
||||
struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
bool f2fs_recover_inline_data(struct inode *inode, struct page *npage);
|
||||
struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
|
||||
struct fscrypt_name *fname, struct page **res_page);
|
||||
int make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
struct page *ipage);
|
||||
int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
|
||||
const struct qstr *orig_name,
|
||||
struct inode *inode, nid_t ino, umode_t mode);
|
||||
void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
struct inode *dir, struct inode *inode);
|
||||
void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry,
|
||||
struct page *page, struct inode *dir,
|
||||
struct inode *inode);
|
||||
bool f2fs_empty_inline_dir(struct inode *dir);
|
||||
int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
|
||||
struct fscrypt_str *fstr);
|
||||
@ -3219,17 +3284,17 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi);
|
||||
/*
|
||||
* extent_cache.c
|
||||
*/
|
||||
struct rb_entry *__lookup_rb_tree(struct rb_root *root,
|
||||
struct rb_entry *f2fs_lookup_rb_tree(struct rb_root *root,
|
||||
struct rb_entry *cached_re, unsigned int ofs);
|
||||
struct rb_node **__lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||
struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi,
|
||||
struct rb_root *root, struct rb_node **parent,
|
||||
unsigned int ofs);
|
||||
struct rb_entry *__lookup_rb_tree_ret(struct rb_root *root,
|
||||
struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root *root,
|
||||
struct rb_entry *cached_re, unsigned int ofs,
|
||||
struct rb_entry **prev_entry, struct rb_entry **next_entry,
|
||||
struct rb_node ***insert_p, struct rb_node **insert_parent,
|
||||
bool force);
|
||||
bool __check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
||||
bool f2fs_check_rb_tree_consistence(struct f2fs_sb_info *sbi,
|
||||
struct rb_root *root);
|
||||
unsigned int f2fs_shrink_extent_tree(struct f2fs_sb_info *sbi, int nr_shrink);
|
||||
unsigned long __count_extent_cache(struct f2fs_sb_info *sbi);
|
||||
@ -3242,9 +3307,9 @@ bool f2fs_lookup_extent_cache(struct inode *inode, pgoff_t pgofs,
|
||||
void f2fs_update_extent_cache(struct dnode_of_data *dn);
|
||||
void f2fs_update_extent_cache_range(struct dnode_of_data *dn,
|
||||
pgoff_t fofs, block_t blkaddr, unsigned int len);
|
||||
void init_extent_cache_info(struct f2fs_sb_info *sbi);
|
||||
int __init create_extent_cache(void);
|
||||
void destroy_extent_cache(void);
|
||||
void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_extent_cache(void);
|
||||
void f2fs_destroy_extent_cache(void);
|
||||
|
||||
/*
|
||||
* sysfs.c
|
||||
|
322
fs/f2fs/file.c
322
fs/f2fs/file.c
@ -95,7 +95,8 @@ static int f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
/* page is wholly or partially inside EOF */
|
||||
if (((loff_t)(page->index + 1) << PAGE_SHIFT) >
|
||||
i_size_read(inode)) {
|
||||
unsigned offset;
|
||||
loff_t offset;
|
||||
|
||||
offset = i_size_read(inode) & ~PAGE_MASK;
|
||||
zero_user_segment(page, offset, PAGE_SIZE);
|
||||
}
|
||||
@ -156,17 +157,18 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode)
|
||||
cp_reason = CP_SB_NEED_CP;
|
||||
else if (file_wrong_pino(inode))
|
||||
cp_reason = CP_WRONG_PINO;
|
||||
else if (!space_for_roll_forward(sbi))
|
||||
else if (!f2fs_space_for_roll_forward(sbi))
|
||||
cp_reason = CP_NO_SPC_ROLL;
|
||||
else if (!is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
|
||||
else if (!f2fs_is_checkpointed_node(sbi, F2FS_I(inode)->i_pino))
|
||||
cp_reason = CP_NODE_NEED_CP;
|
||||
else if (test_opt(sbi, FASTBOOT))
|
||||
cp_reason = CP_FASTBOOT_MODE;
|
||||
else if (F2FS_OPTION(sbi).active_logs == 2)
|
||||
cp_reason = CP_SPEC_LOG_NUM;
|
||||
else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
|
||||
need_dentry_mark(sbi, inode->i_ino) &&
|
||||
exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
|
||||
f2fs_need_dentry_mark(sbi, inode->i_ino) &&
|
||||
f2fs_exist_written_data(sbi, F2FS_I(inode)->i_pino,
|
||||
TRANS_DIR_INO))
|
||||
cp_reason = CP_RECOVER_DIR;
|
||||
|
||||
return cp_reason;
|
||||
@ -177,7 +179,7 @@ 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 */
|
||||
if ((i && PageDirty(i)) || need_inode_block_update(sbi, ino))
|
||||
if ((i && PageDirty(i)) || f2fs_need_inode_block_update(sbi, ino))
|
||||
ret = true;
|
||||
f2fs_put_page(i, 0);
|
||||
return ret;
|
||||
@ -240,14 +242,14 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
|
||||
* if there is no written data, don't waste time to write recovery info.
|
||||
*/
|
||||
if (!is_inode_flag_set(inode, FI_APPEND_WRITE) &&
|
||||
!exist_written_data(sbi, ino, APPEND_INO)) {
|
||||
!f2fs_exist_written_data(sbi, ino, APPEND_INO)) {
|
||||
|
||||
/* it may call write_inode just prior to fsync */
|
||||
if (need_inode_page_update(sbi, ino))
|
||||
goto go_write;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_UPDATE_WRITE) ||
|
||||
exist_written_data(sbi, ino, UPDATE_INO))
|
||||
f2fs_exist_written_data(sbi, ino, UPDATE_INO))
|
||||
goto flush_out;
|
||||
goto out;
|
||||
}
|
||||
@ -274,7 +276,9 @@ go_write:
|
||||
goto out;
|
||||
}
|
||||
sync_nodes:
|
||||
ret = fsync_node_pages(sbi, inode, &wbc, atomic);
|
||||
atomic_inc(&sbi->wb_sync_req[NODE]);
|
||||
ret = f2fs_fsync_node_pages(sbi, inode, &wbc, atomic);
|
||||
atomic_dec(&sbi->wb_sync_req[NODE]);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -284,7 +288,7 @@ sync_nodes:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (need_inode_block_update(sbi, ino)) {
|
||||
if (f2fs_need_inode_block_update(sbi, ino)) {
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
f2fs_write_inode(inode, NULL);
|
||||
goto sync_nodes;
|
||||
@ -299,21 +303,21 @@ sync_nodes:
|
||||
* given fsync mark.
|
||||
*/
|
||||
if (!atomic) {
|
||||
ret = wait_on_node_pages_writeback(sbi, ino);
|
||||
ret = f2fs_wait_on_node_pages_writeback(sbi, ino);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* once recovery info is written, don't need to tack this */
|
||||
remove_ino_entry(sbi, ino, APPEND_INO);
|
||||
f2fs_remove_ino_entry(sbi, ino, APPEND_INO);
|
||||
clear_inode_flag(inode, FI_APPEND_WRITE);
|
||||
flush_out:
|
||||
if (!atomic && F2FS_OPTION(sbi).fsync_mode != FSYNC_MODE_NOBARRIER)
|
||||
ret = f2fs_issue_flush(sbi, inode->i_ino);
|
||||
if (!ret) {
|
||||
remove_ino_entry(sbi, ino, UPDATE_INO);
|
||||
f2fs_remove_ino_entry(sbi, ino, UPDATE_INO);
|
||||
clear_inode_flag(inode, FI_UPDATE_WRITE);
|
||||
remove_ino_entry(sbi, ino, FLUSH_INO);
|
||||
f2fs_remove_ino_entry(sbi, ino, FLUSH_INO);
|
||||
}
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
out:
|
||||
@ -332,18 +336,19 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
static pgoff_t __get_first_dirty_index(struct address_space *mapping,
|
||||
pgoff_t pgofs, int whence)
|
||||
{
|
||||
struct pagevec pvec;
|
||||
struct page *page;
|
||||
int nr_pages;
|
||||
|
||||
if (whence != SEEK_DATA)
|
||||
return 0;
|
||||
|
||||
/* find first dirty page index */
|
||||
pagevec_init(&pvec, 0);
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &pgofs,
|
||||
PAGECACHE_TAG_DIRTY, 1);
|
||||
pgofs = nr_pages ? pvec.pages[0]->index : ULONG_MAX;
|
||||
pagevec_release(&pvec);
|
||||
nr_pages = find_get_pages_tag(mapping, &pgofs, PAGECACHE_TAG_DIRTY,
|
||||
1, &page);
|
||||
if (!nr_pages)
|
||||
return ULONG_MAX;
|
||||
pgofs = page->index;
|
||||
put_page(page);
|
||||
return pgofs;
|
||||
}
|
||||
|
||||
@ -393,13 +398,13 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
|
||||
|
||||
for (; data_ofs < isize; data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, pgofs, LOOKUP_NODE);
|
||||
if (err && err != -ENOENT) {
|
||||
goto fail;
|
||||
} else if (err == -ENOENT) {
|
||||
/* direct node does not exists */
|
||||
if (whence == SEEK_DATA) {
|
||||
pgofs = get_next_page_offset(&dn, pgofs);
|
||||
pgofs = f2fs_get_next_page_offset(&dn, pgofs);
|
||||
continue;
|
||||
} else {
|
||||
goto found;
|
||||
@ -413,6 +418,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
|
||||
dn.ofs_in_node++, pgofs++,
|
||||
data_ofs = (loff_t)pgofs << PAGE_SHIFT) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
|
||||
@ -495,7 +501,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)
|
||||
return dquot_file_open(inode, filp);
|
||||
}
|
||||
|
||||
void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
struct f2fs_node *raw_node;
|
||||
@ -511,17 +517,18 @@ void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
|
||||
for (; count > 0; count--, addr++, dn->ofs_in_node++) {
|
||||
block_t blkaddr = le32_to_cpu(*addr);
|
||||
|
||||
if (blkaddr == NULL_ADDR)
|
||||
continue;
|
||||
|
||||
dn->data_blkaddr = NULL_ADDR;
|
||||
set_data_blkaddr(dn);
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
|
||||
continue;
|
||||
|
||||
invalidate_blocks(sbi, blkaddr);
|
||||
f2fs_invalidate_blocks(sbi, blkaddr);
|
||||
if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
|
||||
clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
nr_free++;
|
||||
@ -533,7 +540,7 @@ void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
* once we invalidate valid blkaddr in range [ofs, ofs + count],
|
||||
* we will invalidate all blkaddr in the whole range.
|
||||
*/
|
||||
fofs = start_bidx_of_node(ofs_of_node(dn->node_page),
|
||||
fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
|
||||
dn->inode) + ofs;
|
||||
f2fs_update_extent_cache_range(dn, fofs, 0, len);
|
||||
dec_valid_block_count(sbi, dn->inode, nr_free);
|
||||
@ -545,15 +552,15 @@ void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
dn->ofs_in_node, nr_free);
|
||||
}
|
||||
|
||||
void truncate_data_blocks(struct dnode_of_data *dn)
|
||||
void f2fs_truncate_data_blocks(struct dnode_of_data *dn)
|
||||
{
|
||||
truncate_data_blocks_range(dn, ADDRS_PER_BLOCK);
|
||||
f2fs_truncate_data_blocks_range(dn, ADDRS_PER_BLOCK);
|
||||
}
|
||||
|
||||
static int truncate_partial_data_page(struct inode *inode, u64 from,
|
||||
bool cache_only)
|
||||
{
|
||||
unsigned offset = from & (PAGE_SIZE - 1);
|
||||
loff_t offset = from & (PAGE_SIZE - 1);
|
||||
pgoff_t index = from >> PAGE_SHIFT;
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
@ -569,7 +576,7 @@ static int truncate_partial_data_page(struct inode *inode, u64 from,
|
||||
return 0;
|
||||
}
|
||||
|
||||
page = get_lock_data_page(inode, index, true);
|
||||
page = f2fs_get_lock_data_page(inode, index, true);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page) == -ENOENT ? 0 : PTR_ERR(page);
|
||||
truncate_out:
|
||||
@ -584,7 +591,7 @@ truncate_out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int truncate_blocks(struct inode *inode, u64 from, bool lock)
|
||||
int f2fs_truncate_blocks(struct inode *inode, u64 from, bool lock)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct dnode_of_data dn;
|
||||
@ -603,21 +610,21 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
|
||||
if (lock)
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
err = PTR_ERR(ipage);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f2fs_has_inline_data(inode)) {
|
||||
truncate_inline_inode(inode, ipage, from);
|
||||
f2fs_truncate_inline_inode(inode, ipage, from);
|
||||
f2fs_put_page(ipage, 1);
|
||||
truncate_page = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
set_new_dnode(&dn, inode, ipage, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
|
||||
err = f2fs_get_dnode_of_data(&dn, free_from, LOOKUP_NODE_RA);
|
||||
if (err) {
|
||||
if (err == -ENOENT)
|
||||
goto free_next;
|
||||
@ -630,13 +637,13 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
|
||||
f2fs_bug_on(sbi, count < 0);
|
||||
|
||||
if (dn.ofs_in_node || IS_INODE(dn.node_page)) {
|
||||
truncate_data_blocks_range(&dn, count);
|
||||
f2fs_truncate_data_blocks_range(&dn, count);
|
||||
free_from += count;
|
||||
}
|
||||
|
||||
f2fs_put_dnode(&dn);
|
||||
free_next:
|
||||
err = truncate_inode_blocks(inode, free_from);
|
||||
err = f2fs_truncate_inode_blocks(inode, free_from);
|
||||
out:
|
||||
if (lock)
|
||||
f2fs_unlock_op(sbi);
|
||||
@ -675,7 +682,7 @@ int f2fs_truncate(struct inode *inode)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = truncate_blocks(inode, i_size_read(inode), true);
|
||||
err = f2fs_truncate_blocks(inode, i_size_read(inode), true);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -700,16 +707,16 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
|
||||
stat->btime.tv_nsec = fi->i_crtime.tv_nsec;
|
||||
}
|
||||
|
||||
flags = fi->i_flags & (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL);
|
||||
if (flags & FS_APPEND_FL)
|
||||
flags = fi->i_flags & F2FS_FL_USER_VISIBLE;
|
||||
if (flags & F2FS_APPEND_FL)
|
||||
stat->attributes |= STATX_ATTR_APPEND;
|
||||
if (flags & FS_COMPR_FL)
|
||||
if (flags & F2FS_COMPR_FL)
|
||||
stat->attributes |= STATX_ATTR_COMPRESSED;
|
||||
if (f2fs_encrypted_inode(inode))
|
||||
stat->attributes |= STATX_ATTR_ENCRYPTED;
|
||||
if (flags & FS_IMMUTABLE_FL)
|
||||
if (flags & F2FS_IMMUTABLE_FL)
|
||||
stat->attributes |= STATX_ATTR_IMMUTABLE;
|
||||
if (flags & FS_NODUMP_FL)
|
||||
if (flags & F2FS_NODUMP_FL)
|
||||
stat->attributes |= STATX_ATTR_NODUMP;
|
||||
|
||||
stat->attributes_mask |= (STATX_ATTR_APPEND |
|
||||
@ -825,7 +832,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
__setattr_copy(inode, attr);
|
||||
|
||||
if (attr->ia_valid & ATTR_MODE) {
|
||||
err = posix_acl_chmod(inode, get_inode_mode(inode));
|
||||
err = posix_acl_chmod(inode, f2fs_get_inode_mode(inode));
|
||||
if (err || is_inode_flag_set(inode, FI_ACL_MODE)) {
|
||||
inode->i_mode = F2FS_I(inode)->i_acl_mode;
|
||||
clear_inode_flag(inode, FI_ACL_MODE);
|
||||
@ -864,7 +871,7 @@ static int fill_zero(struct inode *inode, pgoff_t index,
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
page = get_new_data_page(inode, NULL, index, false);
|
||||
page = f2fs_get_new_data_page(inode, NULL, index, false);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (IS_ERR(page))
|
||||
@ -877,7 +884,7 @@ static int fill_zero(struct inode *inode, pgoff_t index,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
||||
int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -886,10 +893,11 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
||||
pgoff_t end_offset, count;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, pg_start, LOOKUP_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOENT) {
|
||||
pg_start = get_next_page_offset(&dn, pg_start);
|
||||
pg_start = f2fs_get_next_page_offset(&dn,
|
||||
pg_start);
|
||||
continue;
|
||||
}
|
||||
return err;
|
||||
@ -900,7 +908,7 @@ int truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end)
|
||||
|
||||
f2fs_bug_on(F2FS_I_SB(inode), count == 0 || count > end_offset);
|
||||
|
||||
truncate_data_blocks_range(&dn, count);
|
||||
f2fs_truncate_data_blocks_range(&dn, count);
|
||||
f2fs_put_dnode(&dn);
|
||||
|
||||
pg_start += count;
|
||||
@ -956,7 +964,7 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
||||
blk_end - 1);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
ret = truncate_hole(inode, pg_start, pg_end);
|
||||
ret = f2fs_truncate_hole(inode, pg_start, pg_end);
|
||||
f2fs_unlock_op(sbi);
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
}
|
||||
@ -974,7 +982,7 @@ static int __read_out_blkaddrs(struct inode *inode, block_t *blkaddr,
|
||||
|
||||
next_dnode:
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
|
||||
ret = f2fs_get_dnode_of_data(&dn, off, LOOKUP_NODE_RA);
|
||||
if (ret && ret != -ENOENT) {
|
||||
return ret;
|
||||
} else if (ret == -ENOENT) {
|
||||
@ -991,7 +999,7 @@ next_dnode:
|
||||
for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
|
||||
*blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
if (!is_checkpointed_data(sbi, *blkaddr)) {
|
||||
if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
|
||||
|
||||
if (test_opt(sbi, LFS)) {
|
||||
f2fs_put_dnode(&dn);
|
||||
@ -1024,10 +1032,10 @@ static int __roll_back_blkaddrs(struct inode *inode, block_t *blkaddr,
|
||||
continue;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
|
||||
ret = f2fs_get_dnode_of_data(&dn, off + i, LOOKUP_NODE_RA);
|
||||
if (ret) {
|
||||
dec_valid_block_count(sbi, inode, 1);
|
||||
invalidate_blocks(sbi, *blkaddr);
|
||||
f2fs_invalidate_blocks(sbi, *blkaddr);
|
||||
} else {
|
||||
f2fs_update_data_blkaddr(&dn, *blkaddr);
|
||||
}
|
||||
@ -1057,11 +1065,11 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
pgoff_t ilen;
|
||||
|
||||
set_new_dnode(&dn, dst_inode, NULL, NULL, 0);
|
||||
ret = get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
|
||||
ret = f2fs_get_dnode_of_data(&dn, dst + i, ALLOC_NODE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = get_node_info(sbi, dn.nid, &ni);
|
||||
ret = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
if (ret) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return ret;
|
||||
@ -1073,7 +1081,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
do {
|
||||
dn.data_blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
truncate_data_blocks_range(&dn, 1);
|
||||
f2fs_truncate_data_blocks_range(&dn, 1);
|
||||
|
||||
if (do_replace[i]) {
|
||||
f2fs_i_blocks_write(src_inode,
|
||||
@ -1096,10 +1104,11 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
} else {
|
||||
struct page *psrc, *pdst;
|
||||
|
||||
psrc = get_lock_data_page(src_inode, src + i, true);
|
||||
psrc = f2fs_get_lock_data_page(src_inode,
|
||||
src + i, true);
|
||||
if (IS_ERR(psrc))
|
||||
return PTR_ERR(psrc);
|
||||
pdst = get_new_data_page(dst_inode, NULL, dst + i,
|
||||
pdst = f2fs_get_new_data_page(dst_inode, NULL, dst + i,
|
||||
true);
|
||||
if (IS_ERR(pdst)) {
|
||||
f2fs_put_page(psrc, 1);
|
||||
@ -1110,7 +1119,8 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
f2fs_put_page(pdst, 1);
|
||||
f2fs_put_page(psrc, 1);
|
||||
|
||||
ret = truncate_hole(src_inode, src + i, src + i + 1);
|
||||
ret = f2fs_truncate_hole(src_inode,
|
||||
src + i, src + i + 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
i++;
|
||||
@ -1132,12 +1142,14 @@ static int __exchange_data_block(struct inode *src_inode,
|
||||
olen = min((pgoff_t)4 * ADDRS_PER_BLOCK, len);
|
||||
|
||||
src_blkaddr = f2fs_kvzalloc(F2FS_I_SB(src_inode),
|
||||
sizeof(block_t) * olen, GFP_KERNEL);
|
||||
array_size(olen, sizeof(block_t)),
|
||||
GFP_KERNEL);
|
||||
if (!src_blkaddr)
|
||||
return -ENOMEM;
|
||||
|
||||
do_replace = f2fs_kvzalloc(F2FS_I_SB(src_inode),
|
||||
sizeof(int) * olen, GFP_KERNEL);
|
||||
array_size(olen, sizeof(int)),
|
||||
GFP_KERNEL);
|
||||
if (!do_replace) {
|
||||
kvfree(src_blkaddr);
|
||||
return -ENOMEM;
|
||||
@ -1163,7 +1175,7 @@ static int __exchange_data_block(struct inode *src_inode,
|
||||
return 0;
|
||||
|
||||
roll_back:
|
||||
__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, len);
|
||||
__roll_back_blkaddrs(src_inode, src_blkaddr, do_replace, src, olen);
|
||||
kvfree(src_blkaddr);
|
||||
kvfree(do_replace);
|
||||
return ret;
|
||||
@ -1206,7 +1218,7 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
||||
pg_end = (offset + len) >> PAGE_SHIFT;
|
||||
|
||||
/* avoid gc operation during block exchange */
|
||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
|
||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
/* write out all dirty pages from offset */
|
||||
@ -1227,12 +1239,12 @@ static int f2fs_collapse_range(struct inode *inode, loff_t offset, loff_t len)
|
||||
new_size = i_size_read(inode) - len;
|
||||
truncate_pagecache(inode, new_size);
|
||||
|
||||
ret = truncate_blocks(inode, new_size, true);
|
||||
ret = f2fs_truncate_blocks(inode, new_size, true);
|
||||
if (!ret)
|
||||
f2fs_i_size_write(inode, new_size);
|
||||
out_unlock:
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1252,7 +1264,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
}
|
||||
|
||||
dn->ofs_in_node = ofs_in_node;
|
||||
ret = reserve_new_blocks(dn, count);
|
||||
ret = f2fs_reserve_new_blocks(dn, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1261,7 +1273,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
dn->data_blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
/*
|
||||
* reserve_new_blocks will not guarantee entire block
|
||||
* f2fs_reserve_new_blocks will not guarantee entire block
|
||||
* allocation.
|
||||
*/
|
||||
if (dn->data_blkaddr == NULL_ADDR) {
|
||||
@ -1269,9 +1281,9 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
break;
|
||||
}
|
||||
if (dn->data_blkaddr != NEW_ADDR) {
|
||||
invalidate_blocks(sbi, dn->data_blkaddr);
|
||||
f2fs_invalidate_blocks(sbi, dn->data_blkaddr);
|
||||
dn->data_blkaddr = NEW_ADDR;
|
||||
set_data_blkaddr(dn);
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1337,7 +1349,7 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len,
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = get_dnode_of_data(&dn, index, ALLOC_NODE);
|
||||
ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE);
|
||||
if (ret) {
|
||||
f2fs_unlock_op(sbi);
|
||||
goto out;
|
||||
@ -1408,10 +1420,10 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
/* avoid gc operation during block exchange */
|
||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
|
||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
ret = truncate_blocks(inode, i_size_read(inode), true);
|
||||
ret = f2fs_truncate_blocks(inode, i_size_read(inode), true);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -1449,7 +1461,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len)
|
||||
f2fs_i_size_write(inode, new_size);
|
||||
out:
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1492,7 +1504,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
||||
last_off = map.m_lblk + map.m_len - 1;
|
||||
|
||||
/* update new size to the failed position */
|
||||
new_size = (last_off == pg_end) ? offset + len:
|
||||
new_size = (last_off == pg_end) ? offset + len :
|
||||
(loff_t)(last_off + 1) << PAGE_SHIFT;
|
||||
} else {
|
||||
new_size = ((loff_t)pg_end << PAGE_SHIFT) + off_end;
|
||||
@ -1572,13 +1584,13 @@ static int f2fs_release_file(struct inode *inode, struct file *filp)
|
||||
|
||||
/* some remained atomic pages should discarded */
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
drop_inmem_pages(inode);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
if (f2fs_is_volatile_file(inode)) {
|
||||
clear_inode_flag(inode, FI_VOLATILE_FILE);
|
||||
stat_dec_volatile_write(inode);
|
||||
set_inode_flag(inode, FI_DROP_CACHE);
|
||||
filemap_fdatawrite(inode->i_mapping);
|
||||
clear_inode_flag(inode, FI_DROP_CACHE);
|
||||
clear_inode_flag(inode, FI_VOLATILE_FILE);
|
||||
stat_dec_volatile_write(inode);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1595,7 +1607,7 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id)
|
||||
*/
|
||||
if (f2fs_is_atomic_file(inode) &&
|
||||
F2FS_I(inode)->inmem_task == current)
|
||||
drop_inmem_pages(inode);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1603,8 +1615,15 @@ static int f2fs_ioc_getflags(struct file *filp, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
unsigned int flags = fi->i_flags &
|
||||
(FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL);
|
||||
unsigned int flags = fi->i_flags;
|
||||
|
||||
if (file_is_encrypt(inode))
|
||||
flags |= F2FS_ENCRYPT_FL;
|
||||
if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode))
|
||||
flags |= F2FS_INLINE_DATA_FL;
|
||||
|
||||
flags &= F2FS_FL_USER_VISIBLE;
|
||||
|
||||
return put_user(flags, (int __user *)arg);
|
||||
}
|
||||
|
||||
@ -1621,15 +1640,15 @@ static int __f2fs_ioc_setflags(struct inode *inode, unsigned int flags)
|
||||
|
||||
oldflags = fi->i_flags;
|
||||
|
||||
if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL))
|
||||
if ((flags ^ oldflags) & (F2FS_APPEND_FL | F2FS_IMMUTABLE_FL))
|
||||
if (!capable(CAP_LINUX_IMMUTABLE))
|
||||
return -EPERM;
|
||||
|
||||
flags = flags & (FS_FL_USER_MODIFIABLE | FS_PROJINHERIT_FL);
|
||||
flags |= oldflags & ~(FS_FL_USER_MODIFIABLE | FS_PROJINHERIT_FL);
|
||||
flags = flags & F2FS_FL_USER_MODIFIABLE;
|
||||
flags |= oldflags & ~F2FS_FL_USER_MODIFIABLE;
|
||||
fi->i_flags = flags;
|
||||
|
||||
if (fi->i_flags & FS_PROJINHERIT_FL)
|
||||
if (fi->i_flags & F2FS_PROJINHERIT_FL)
|
||||
set_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
else
|
||||
clear_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
@ -1689,7 +1708,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
goto out;
|
||||
@ -1698,29 +1717,25 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
set_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
set_inode_flag(inode, FI_HOT_DATA);
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
|
||||
if (!get_dirty_pages(inode))
|
||||
goto inc_stat;
|
||||
goto skip_flush;
|
||||
|
||||
f2fs_msg(F2FS_I_SB(inode)->sb, KERN_WARNING,
|
||||
"Unexpected flush for atomic writes: ino=%lu, npages=%u",
|
||||
inode->i_ino, get_dirty_pages(inode));
|
||||
ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX);
|
||||
if (ret) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_HOT_DATA);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
skip_flush:
|
||||
set_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
|
||||
inc_stat:
|
||||
F2FS_I(inode)->inmem_task = current;
|
||||
stat_inc_atomic_write(inode);
|
||||
stat_update_max_atomic_write(inode);
|
||||
out:
|
||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return ret;
|
||||
@ -1740,27 +1755,33 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
|
||||
if (f2fs_is_volatile_file(inode))
|
||||
if (f2fs_is_volatile_file(inode)) {
|
||||
ret = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
ret = commit_inmem_pages(inode);
|
||||
ret = f2fs_commit_inmem_pages(inode);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
if (!ret) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_HOT_DATA);
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC] = 0;
|
||||
stat_dec_atomic_write(inode);
|
||||
}
|
||||
} else {
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
|
||||
}
|
||||
err_out:
|
||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) {
|
||||
clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return ret;
|
||||
@ -1845,7 +1866,7 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
|
||||
inode_lock(inode);
|
||||
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
drop_inmem_pages(inode);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
if (f2fs_is_volatile_file(inode)) {
|
||||
clear_inode_flag(inode, FI_VOLATILE_FILE);
|
||||
stat_dec_volatile_write(inode);
|
||||
@ -1902,7 +1923,7 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
break;
|
||||
case F2FS_GOING_DOWN_METAFLUSH:
|
||||
sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_META_IO);
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
break;
|
||||
default:
|
||||
@ -1910,10 +1931,10 @@ static int f2fs_ioc_shutdown(struct file *filp, unsigned long arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
stop_gc_thread(sbi);
|
||||
stop_discard_thread(sbi);
|
||||
f2fs_stop_gc_thread(sbi);
|
||||
f2fs_stop_discard_thread(sbi);
|
||||
|
||||
drop_discard_cmd(sbi);
|
||||
f2fs_drop_discard_cmd(sbi);
|
||||
clear_opt(sbi, DISCARD);
|
||||
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
@ -2078,15 +2099,15 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg)
|
||||
if (f2fs_readonly(sbi->sb))
|
||||
return -EROFS;
|
||||
|
||||
end = range.start + range.len;
|
||||
if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mnt_want_write_file(filp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
end = range.start + range.len;
|
||||
if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
do_more:
|
||||
if (!range.sync) {
|
||||
if (!mutex_trylock(&sbi->gc_mutex)) {
|
||||
@ -2106,7 +2127,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
|
||||
static int f2fs_ioc_f2fs_write_checkpoint(struct file *filp, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
@ -2135,7 +2156,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct f2fs_map_blocks map = { .m_next_extent = NULL,
|
||||
.m_seg_type = NO_CHECK_TYPE };
|
||||
struct extent_info ei = {0,0,0};
|
||||
struct extent_info ei = {0, 0, 0};
|
||||
pgoff_t pg_start, pg_end, next_pgofs;
|
||||
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
||||
unsigned int total = 0, sec_num;
|
||||
@ -2144,7 +2165,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
int err;
|
||||
|
||||
/* if in-place-update policy is enabled, don't waste time here */
|
||||
if (should_update_inplace(inode, NULL))
|
||||
if (f2fs_should_update_inplace(inode, NULL))
|
||||
return -EINVAL;
|
||||
|
||||
pg_start = range->start >> PAGE_SHIFT;
|
||||
@ -2239,7 +2260,7 @@ do_map:
|
||||
while (idx < map.m_lblk + map.m_len && cnt < blk_per_seg) {
|
||||
struct page *page;
|
||||
|
||||
page = get_lock_data_page(inode, idx, true);
|
||||
page = f2fs_get_lock_data_page(inode, idx, true);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
goto clear_out;
|
||||
@ -2350,12 +2371,12 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
|
||||
}
|
||||
|
||||
inode_lock(src);
|
||||
down_write(&F2FS_I(src)->dio_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
|
||||
if (src != dst) {
|
||||
ret = -EBUSY;
|
||||
if (!inode_trylock(dst))
|
||||
goto out;
|
||||
if (!down_write_trylock(&F2FS_I(dst)->dio_rwsem[WRITE])) {
|
||||
if (!down_write_trylock(&F2FS_I(dst)->i_gc_rwsem[WRITE])) {
|
||||
inode_unlock(dst);
|
||||
goto out;
|
||||
}
|
||||
@ -2417,11 +2438,11 @@ static int f2fs_move_file_range(struct file *file_in, loff_t pos_in,
|
||||
f2fs_unlock_op(sbi);
|
||||
out_unlock:
|
||||
if (src != dst) {
|
||||
up_write(&F2FS_I(dst)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(dst)->i_gc_rwsem[WRITE]);
|
||||
inode_unlock(dst);
|
||||
}
|
||||
out:
|
||||
up_write(&F2FS_I(src)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(src)->i_gc_rwsem[WRITE]);
|
||||
inode_unlock(src);
|
||||
return ret;
|
||||
}
|
||||
@ -2579,7 +2600,7 @@ static int f2fs_ioc_setproject(struct file *filp, __u32 projid)
|
||||
if (IS_NOQUOTA(inode))
|
||||
goto out_unlock;
|
||||
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
err = PTR_ERR(ipage);
|
||||
goto out_unlock;
|
||||
@ -2628,17 +2649,17 @@ static inline __u32 f2fs_iflags_to_xflags(unsigned long iflags)
|
||||
{
|
||||
__u32 xflags = 0;
|
||||
|
||||
if (iflags & FS_SYNC_FL)
|
||||
if (iflags & F2FS_SYNC_FL)
|
||||
xflags |= FS_XFLAG_SYNC;
|
||||
if (iflags & FS_IMMUTABLE_FL)
|
||||
if (iflags & F2FS_IMMUTABLE_FL)
|
||||
xflags |= FS_XFLAG_IMMUTABLE;
|
||||
if (iflags & FS_APPEND_FL)
|
||||
if (iflags & F2FS_APPEND_FL)
|
||||
xflags |= FS_XFLAG_APPEND;
|
||||
if (iflags & FS_NODUMP_FL)
|
||||
if (iflags & F2FS_NODUMP_FL)
|
||||
xflags |= FS_XFLAG_NODUMP;
|
||||
if (iflags & FS_NOATIME_FL)
|
||||
if (iflags & F2FS_NOATIME_FL)
|
||||
xflags |= FS_XFLAG_NOATIME;
|
||||
if (iflags & FS_PROJINHERIT_FL)
|
||||
if (iflags & F2FS_PROJINHERIT_FL)
|
||||
xflags |= FS_XFLAG_PROJINHERIT;
|
||||
return xflags;
|
||||
}
|
||||
@ -2647,31 +2668,23 @@ static inline __u32 f2fs_iflags_to_xflags(unsigned long iflags)
|
||||
FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
|
||||
FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT)
|
||||
|
||||
/* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
|
||||
#define F2FS_FL_XFLAG_VISIBLE (FS_SYNC_FL | \
|
||||
FS_IMMUTABLE_FL | \
|
||||
FS_APPEND_FL | \
|
||||
FS_NODUMP_FL | \
|
||||
FS_NOATIME_FL | \
|
||||
FS_PROJINHERIT_FL)
|
||||
|
||||
/* Transfer xflags flags to internal */
|
||||
static inline unsigned long f2fs_xflags_to_iflags(__u32 xflags)
|
||||
{
|
||||
unsigned long iflags = 0;
|
||||
|
||||
if (xflags & FS_XFLAG_SYNC)
|
||||
iflags |= FS_SYNC_FL;
|
||||
iflags |= F2FS_SYNC_FL;
|
||||
if (xflags & FS_XFLAG_IMMUTABLE)
|
||||
iflags |= FS_IMMUTABLE_FL;
|
||||
iflags |= F2FS_IMMUTABLE_FL;
|
||||
if (xflags & FS_XFLAG_APPEND)
|
||||
iflags |= FS_APPEND_FL;
|
||||
iflags |= F2FS_APPEND_FL;
|
||||
if (xflags & FS_XFLAG_NODUMP)
|
||||
iflags |= FS_NODUMP_FL;
|
||||
iflags |= F2FS_NODUMP_FL;
|
||||
if (xflags & FS_XFLAG_NOATIME)
|
||||
iflags |= FS_NOATIME_FL;
|
||||
iflags |= F2FS_NOATIME_FL;
|
||||
if (xflags & FS_XFLAG_PROJINHERIT)
|
||||
iflags |= FS_PROJINHERIT_FL;
|
||||
iflags |= F2FS_PROJINHERIT_FL;
|
||||
|
||||
return iflags;
|
||||
}
|
||||
@ -2684,7 +2697,7 @@ static int f2fs_ioc_fsgetxattr(struct file *filp, unsigned long arg)
|
||||
|
||||
memset(&fa, 0, sizeof(struct fsxattr));
|
||||
fa.fsx_xflags = f2fs_iflags_to_xflags(fi->i_flags &
|
||||
(FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL));
|
||||
F2FS_FL_USER_VISIBLE);
|
||||
|
||||
if (f2fs_sb_has_project_quota(inode->i_sb))
|
||||
fa.fsx_projid = (__u32)from_kprojid(&init_user_ns,
|
||||
@ -2744,12 +2757,14 @@ int f2fs_pin_file_control(struct inode *inode, bool inc)
|
||||
|
||||
/* Use i_gc_failures for normal file as a risk signal. */
|
||||
if (inc)
|
||||
f2fs_i_gc_failures_write(inode, fi->i_gc_failures + 1);
|
||||
f2fs_i_gc_failures_write(inode,
|
||||
fi->i_gc_failures[GC_FAILURE_PIN] + 1);
|
||||
|
||||
if (fi->i_gc_failures > sbi->gc_pin_file_threshold) {
|
||||
if (fi->i_gc_failures[GC_FAILURE_PIN] > sbi->gc_pin_file_threshold) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: Enable GC = ino %lx after %x GC trials\n",
|
||||
__func__, inode->i_ino, fi->i_gc_failures);
|
||||
__func__, inode->i_ino,
|
||||
fi->i_gc_failures[GC_FAILURE_PIN]);
|
||||
clear_inode_flag(inode, FI_PIN_FILE);
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -2780,14 +2795,14 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
if (should_update_outplace(inode, NULL)) {
|
||||
if (f2fs_should_update_outplace(inode, NULL)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!pin) {
|
||||
clear_inode_flag(inode, FI_PIN_FILE);
|
||||
F2FS_I(inode)->i_gc_failures = 1;
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN] = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -2800,7 +2815,7 @@ static int f2fs_ioc_set_pin_file(struct file *filp, unsigned long arg)
|
||||
goto out;
|
||||
|
||||
set_inode_flag(inode, FI_PIN_FILE);
|
||||
ret = F2FS_I(inode)->i_gc_failures;
|
||||
ret = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
||||
done:
|
||||
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
|
||||
out:
|
||||
@ -2815,7 +2830,7 @@ static int f2fs_ioc_get_pin_file(struct file *filp, unsigned long arg)
|
||||
__u32 pin = 0;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_PIN_FILE))
|
||||
pin = F2FS_I(inode)->i_gc_failures;
|
||||
pin = F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN];
|
||||
return put_user(pin, (u32 __user *)arg);
|
||||
}
|
||||
|
||||
@ -2839,9 +2854,9 @@ int f2fs_precache_extents(struct inode *inode)
|
||||
while (map.m_lblk < end) {
|
||||
map.m_len = end - map.m_lblk;
|
||||
|
||||
down_write(&fi->dio_rwsem[WRITE]);
|
||||
down_write(&fi->i_gc_rwsem[WRITE]);
|
||||
err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE);
|
||||
up_write(&fi->dio_rwsem[WRITE]);
|
||||
up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2893,7 +2908,7 @@ long f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
case F2FS_IOC_GARBAGE_COLLECT_RANGE:
|
||||
return f2fs_ioc_gc_range(filp, arg);
|
||||
case F2FS_IOC_WRITE_CHECKPOINT:
|
||||
return f2fs_ioc_write_checkpoint(filp, arg);
|
||||
return f2fs_ioc_f2fs_write_checkpoint(filp, arg);
|
||||
case F2FS_IOC_DEFRAGMENT:
|
||||
return f2fs_ioc_defragment(filp, arg);
|
||||
case F2FS_IOC_MOVE_RANGE:
|
||||
@ -2921,7 +2936,6 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct blk_plug plug;
|
||||
ssize_t ret;
|
||||
|
||||
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
|
||||
@ -2951,6 +2965,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
iov_iter_count(from)) ||
|
||||
f2fs_has_inline_data(inode) ||
|
||||
f2fs_force_buffered_io(inode, WRITE)) {
|
||||
clear_inode_flag(inode,
|
||||
FI_NO_PREALLOC);
|
||||
inode_unlock(inode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
@ -2966,9 +2982,7 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
blk_start_plug(&plug);
|
||||
ret = __generic_file_write_iter(iocb, from);
|
||||
blk_finish_plug(&plug);
|
||||
clear_inode_flag(inode, FI_NO_PREALLOC);
|
||||
|
||||
/* if we couldn't write data, we should deallocate blocks. */
|
||||
|
159
fs/f2fs/gc.c
159
fs/f2fs/gc.c
@ -76,7 +76,7 @@ static int gc_thread_func(void *data)
|
||||
* invalidated soon after by user update or deletion.
|
||||
* So, I'd like to wait some time to collect dirty segments.
|
||||
*/
|
||||
if (gc_th->gc_urgent) {
|
||||
if (sbi->gc_mode == GC_URGENT) {
|
||||
wait_ms = gc_th->urgent_sleep_time;
|
||||
mutex_lock(&sbi->gc_mutex);
|
||||
goto do_gc;
|
||||
@ -114,7 +114,7 @@ next:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_th;
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
@ -131,8 +131,6 @@ int start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME;
|
||||
gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME;
|
||||
|
||||
gc_th->gc_idle = 0;
|
||||
gc_th->gc_urgent = 0;
|
||||
gc_th->gc_wake= 0;
|
||||
|
||||
sbi->gc_thread = gc_th;
|
||||
@ -148,7 +146,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void stop_gc_thread(struct f2fs_sb_info *sbi)
|
||||
void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_th = sbi->gc_thread;
|
||||
if (!gc_th)
|
||||
@ -158,21 +156,19 @@ void stop_gc_thread(struct f2fs_sb_info *sbi)
|
||||
sbi->gc_thread = NULL;
|
||||
}
|
||||
|
||||
static int select_gc_type(struct f2fs_gc_kthread *gc_th, int gc_type)
|
||||
static int select_gc_type(struct f2fs_sb_info *sbi, int gc_type)
|
||||
{
|
||||
int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY;
|
||||
|
||||
if (!gc_th)
|
||||
return gc_mode;
|
||||
|
||||
if (gc_th->gc_idle) {
|
||||
if (gc_th->gc_idle == 1)
|
||||
gc_mode = GC_CB;
|
||||
else if (gc_th->gc_idle == 2)
|
||||
gc_mode = GC_GREEDY;
|
||||
}
|
||||
if (gc_th->gc_urgent)
|
||||
switch (sbi->gc_mode) {
|
||||
case GC_IDLE_CB:
|
||||
gc_mode = GC_CB;
|
||||
break;
|
||||
case GC_IDLE_GREEDY:
|
||||
case GC_URGENT:
|
||||
gc_mode = GC_GREEDY;
|
||||
break;
|
||||
}
|
||||
return gc_mode;
|
||||
}
|
||||
|
||||
@ -187,7 +183,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
|
||||
p->max_search = dirty_i->nr_dirty[type];
|
||||
p->ofs_unit = 1;
|
||||
} else {
|
||||
p->gc_mode = select_gc_type(sbi->gc_thread, gc_type);
|
||||
p->gc_mode = select_gc_type(sbi, gc_type);
|
||||
p->dirty_segmap = dirty_i->dirty_segmap[DIRTY];
|
||||
p->max_search = dirty_i->nr_dirty[DIRTY];
|
||||
p->ofs_unit = sbi->segs_per_sec;
|
||||
@ -195,7 +191,7 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
|
||||
|
||||
/* we need to check every dirty segments in the FG_GC case */
|
||||
if (gc_type != FG_GC &&
|
||||
(sbi->gc_thread && !sbi->gc_thread->gc_urgent) &&
|
||||
(sbi->gc_mode != GC_URGENT) &&
|
||||
p->max_search > sbi->max_victim_search)
|
||||
p->max_search = sbi->max_victim_search;
|
||||
|
||||
@ -234,10 +230,6 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
|
||||
for_each_set_bit(secno, dirty_i->victim_secmap, MAIN_SECS(sbi)) {
|
||||
if (sec_usage_check(sbi, secno))
|
||||
continue;
|
||||
|
||||
if (no_fggc_candidate(sbi, secno))
|
||||
continue;
|
||||
|
||||
clear_bit(secno, dirty_i->victim_secmap);
|
||||
return GET_SEG_FROM_SEC(sbi, secno);
|
||||
}
|
||||
@ -377,9 +369,6 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
|
||||
goto next;
|
||||
if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
|
||||
goto next;
|
||||
if (gc_type == FG_GC && p.alloc_mode == LFS &&
|
||||
no_fggc_candidate(sbi, secno))
|
||||
goto next;
|
||||
|
||||
cost = get_gc_cost(sbi, segno, &p);
|
||||
|
||||
@ -440,7 +429,7 @@ static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode)
|
||||
iput(inode);
|
||||
return;
|
||||
}
|
||||
new_ie = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
|
||||
new_ie = f2fs_kmem_cache_alloc(f2fs_inode_entry_slab, GFP_NOFS);
|
||||
new_ie->inode = inode;
|
||||
|
||||
f2fs_radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie);
|
||||
@ -454,7 +443,7 @@ static void put_gc_inode(struct gc_inode_list *gc_list)
|
||||
radix_tree_delete(&gc_list->iroot, ie->inode->i_ino);
|
||||
iput(ie->inode);
|
||||
list_del(&ie->list);
|
||||
kmem_cache_free(inode_entry_slab, ie);
|
||||
kmem_cache_free(f2fs_inode_entry_slab, ie);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,12 +474,16 @@ static int gc_node_segment(struct f2fs_sb_info *sbi,
|
||||
int off;
|
||||
int phase = 0;
|
||||
int submitted = 0;
|
||||
bool fggc = (gc_type == FG_GC);
|
||||
|
||||
start_addr = START_BLOCK(sbi, segno);
|
||||
|
||||
next_step:
|
||||
entry = sum;
|
||||
|
||||
if (fggc && phase == 2)
|
||||
atomic_inc(&sbi->wb_sync_req[NODE]);
|
||||
|
||||
for (off = 0; off < sbi->blocks_per_seg; off++, entry++) {
|
||||
nid_t nid = le32_to_cpu(entry->nid);
|
||||
struct page *node_page;
|
||||
@ -505,28 +498,28 @@ next_step:
|
||||
continue;
|
||||
|
||||
if (phase == 0) {
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1,
|
||||
f2fs_ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1,
|
||||
META_NAT, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phase == 1) {
|
||||
ra_node_page(sbi, nid);
|
||||
f2fs_ra_node_page(sbi, nid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* phase == 2 */
|
||||
node_page = get_node_page(sbi, nid);
|
||||
node_page = f2fs_get_node_page(sbi, nid);
|
||||
if (IS_ERR(node_page))
|
||||
continue;
|
||||
|
||||
/* block may become invalid during get_node_page */
|
||||
/* block may become invalid during f2fs_get_node_page */
|
||||
if (check_valid_map(sbi, segno, off) == 0) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (get_node_info(sbi, nid, &ni)) {
|
||||
if (f2fs_get_node_info(sbi, nid, &ni)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
continue;
|
||||
}
|
||||
@ -536,7 +529,7 @@ next_step:
|
||||
continue;
|
||||
}
|
||||
|
||||
err = move_node_page(node_page, gc_type);
|
||||
err = f2fs_move_node_page(node_page, gc_type);
|
||||
if (!err && gc_type == FG_GC)
|
||||
submitted++;
|
||||
stat_inc_node_blk_count(sbi, 1, gc_type);
|
||||
@ -544,6 +537,9 @@ next_step:
|
||||
|
||||
if (++phase < 3)
|
||||
goto next_step;
|
||||
|
||||
if (fggc)
|
||||
atomic_dec(&sbi->wb_sync_req[NODE]);
|
||||
return submitted;
|
||||
}
|
||||
|
||||
@ -554,7 +550,7 @@ next_step:
|
||||
* as indirect or double indirect node blocks, are given, it must be a caller's
|
||||
* bug.
|
||||
*/
|
||||
block_t start_bidx_of_node(unsigned int node_ofs, struct inode *inode)
|
||||
block_t f2fs_start_bidx_of_node(unsigned int node_ofs, struct inode *inode)
|
||||
{
|
||||
unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4;
|
||||
unsigned int bidx;
|
||||
@ -585,11 +581,11 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
nid = le32_to_cpu(sum->nid);
|
||||
ofs_in_node = le16_to_cpu(sum->ofs_in_node);
|
||||
|
||||
node_page = get_node_page(sbi, nid);
|
||||
node_page = f2fs_get_node_page(sbi, nid);
|
||||
if (IS_ERR(node_page))
|
||||
return false;
|
||||
|
||||
if (get_node_info(sbi, nid, dni)) {
|
||||
if (f2fs_get_node_info(sbi, nid, dni)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
@ -615,7 +611,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
* This can be used to move blocks, aka LBAs, directly on disk.
|
||||
*/
|
||||
static int move_data_block(struct inode *inode, block_t bidx,
|
||||
unsigned int segno, int off)
|
||||
int gc_type, unsigned int segno, int off)
|
||||
{
|
||||
struct f2fs_io_info fio = {
|
||||
.sbi = F2FS_I_SB(inode),
|
||||
@ -626,6 +622,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
.op_flags = 0,
|
||||
.encrypted_page = NULL,
|
||||
.in_list = false,
|
||||
.retry = false,
|
||||
};
|
||||
struct dnode_of_data dn;
|
||||
struct f2fs_summary sum;
|
||||
@ -633,6 +630,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
struct page *page;
|
||||
block_t newaddr;
|
||||
int err = 0;
|
||||
bool lfs_mode = test_opt(fio.sbi, LFS);
|
||||
|
||||
/* do not read out */
|
||||
page = f2fs_grab_cache_page(inode->i_mapping, bidx, false);
|
||||
@ -646,6 +644,8 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
err = -EAGAIN;
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++;
|
||||
F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -656,7 +656,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
}
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, bidx, LOOKUP_NODE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -672,7 +672,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
*/
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
|
||||
err = get_node_info(fio.sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto put_out;
|
||||
|
||||
@ -683,7 +683,10 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
fio.page = page;
|
||||
fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
|
||||
|
||||
allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
|
||||
if (lfs_mode)
|
||||
down_write(&fio.sbi->io_order_lock);
|
||||
|
||||
f2fs_allocate_data_block(fio.sbi, NULL, fio.old_blkaddr, &newaddr,
|
||||
&sum, CURSEG_COLD_DATA, NULL, false);
|
||||
|
||||
fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
|
||||
@ -723,8 +726,8 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
fio.op = REQ_OP_WRITE;
|
||||
fio.op_flags = REQ_SYNC;
|
||||
fio.new_blkaddr = newaddr;
|
||||
err = f2fs_submit_page_write(&fio);
|
||||
if (err) {
|
||||
f2fs_submit_page_write(&fio);
|
||||
if (fio.retry) {
|
||||
if (PageWriteback(fio.encrypted_page))
|
||||
end_page_writeback(fio.encrypted_page);
|
||||
goto put_page_out;
|
||||
@ -739,8 +742,10 @@ static int move_data_block(struct inode *inode, block_t bidx,
|
||||
put_page_out:
|
||||
f2fs_put_page(fio.encrypted_page, 1);
|
||||
recover_block:
|
||||
if (lfs_mode)
|
||||
up_write(&fio.sbi->io_order_lock);
|
||||
if (err)
|
||||
__f2fs_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr,
|
||||
f2fs_do_replace_block(fio.sbi, &sum, newaddr, fio.old_blkaddr,
|
||||
true, true);
|
||||
put_out:
|
||||
f2fs_put_dnode(&dn);
|
||||
@ -755,7 +760,7 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
|
||||
struct page *page;
|
||||
int err = 0;
|
||||
|
||||
page = get_lock_data_page(inode, bidx, true);
|
||||
page = f2fs_get_lock_data_page(inode, bidx, true);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
@ -766,6 +771,8 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
err = -EAGAIN;
|
||||
F2FS_I(inode)->i_gc_failures[GC_FAILURE_ATOMIC]++;
|
||||
F2FS_I_SB(inode)->skipped_atomic_files[gc_type]++;
|
||||
goto out;
|
||||
}
|
||||
if (f2fs_is_pinned_file(inode)) {
|
||||
@ -803,12 +810,12 @@ retry:
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
if (clear_page_dirty_for_io(page)) {
|
||||
inode_dec_dirty_pages(inode);
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
}
|
||||
|
||||
set_cold_data(page);
|
||||
|
||||
err = do_write_data_page(&fio);
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
if (err) {
|
||||
clear_cold_data(page);
|
||||
if (err == -ENOMEM) {
|
||||
@ -862,13 +869,13 @@ next_step:
|
||||
continue;
|
||||
|
||||
if (phase == 0) {
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1,
|
||||
f2fs_ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), 1,
|
||||
META_NAT, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (phase == 1) {
|
||||
ra_node_page(sbi, nid);
|
||||
f2fs_ra_node_page(sbi, nid);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -877,7 +884,7 @@ next_step:
|
||||
continue;
|
||||
|
||||
if (phase == 2) {
|
||||
ra_node_page(sbi, dni.ino);
|
||||
f2fs_ra_node_page(sbi, dni.ino);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -895,16 +902,16 @@ next_step:
|
||||
}
|
||||
|
||||
if (!down_write_trylock(
|
||||
&F2FS_I(inode)->dio_rwsem[WRITE])) {
|
||||
&F2FS_I(inode)->i_gc_rwsem[WRITE])) {
|
||||
iput(inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
start_bidx = start_bidx_of_node(nofs, inode);
|
||||
data_page = get_read_data_page(inode,
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode);
|
||||
data_page = f2fs_get_read_data_page(inode,
|
||||
start_bidx + ofs_in_node, REQ_RAHEAD,
|
||||
true);
|
||||
up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
if (IS_ERR(data_page)) {
|
||||
iput(inode);
|
||||
continue;
|
||||
@ -923,11 +930,11 @@ next_step:
|
||||
int err;
|
||||
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (!down_write_trylock(&fi->dio_rwsem[READ]))
|
||||
if (!down_write_trylock(&fi->i_gc_rwsem[READ]))
|
||||
continue;
|
||||
if (!down_write_trylock(
|
||||
&fi->dio_rwsem[WRITE])) {
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
&fi->i_gc_rwsem[WRITE])) {
|
||||
up_write(&fi->i_gc_rwsem[READ]);
|
||||
continue;
|
||||
}
|
||||
locked = true;
|
||||
@ -936,10 +943,11 @@ next_step:
|
||||
inode_dio_wait(inode);
|
||||
}
|
||||
|
||||
start_bidx = start_bidx_of_node(nofs, inode)
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode)
|
||||
+ ofs_in_node;
|
||||
if (f2fs_post_read_required(inode))
|
||||
err = move_data_block(inode, start_bidx, segno, off);
|
||||
err = move_data_block(inode, start_bidx, gc_type,
|
||||
segno, off);
|
||||
else
|
||||
err = move_data_page(inode, start_bidx, gc_type,
|
||||
segno, off);
|
||||
@ -949,8 +957,8 @@ next_step:
|
||||
submitted++;
|
||||
|
||||
if (locked) {
|
||||
up_write(&fi->dio_rwsem[WRITE]);
|
||||
up_write(&fi->dio_rwsem[READ]);
|
||||
up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
up_write(&fi->i_gc_rwsem[READ]);
|
||||
}
|
||||
|
||||
stat_inc_data_blk_count(sbi, 1, gc_type);
|
||||
@ -992,12 +1000,12 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
||||
|
||||
/* readahead multi ssa blocks those have contiguous address */
|
||||
if (sbi->segs_per_sec > 1)
|
||||
ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
|
||||
f2fs_ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno),
|
||||
sbi->segs_per_sec, META_SSA, true);
|
||||
|
||||
/* reference all summary page */
|
||||
while (segno < end_segno) {
|
||||
sum_page = get_sum_page(sbi, segno++);
|
||||
sum_page = f2fs_get_sum_page(sbi, segno++);
|
||||
if (IS_ERR(sum_page)) {
|
||||
int err = PTR_ERR(sum_page);
|
||||
|
||||
@ -1082,6 +1090,8 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
|
||||
.ilist = LIST_HEAD_INIT(gc_list.ilist),
|
||||
.iroot = RADIX_TREE_INIT(GFP_NOFS),
|
||||
};
|
||||
unsigned long long last_skipped = sbi->skipped_atomic_files[FG_GC];
|
||||
unsigned int skipped_round = 0, round = 0;
|
||||
|
||||
trace_f2fs_gc_begin(sbi->sb, sync, background,
|
||||
get_pages(sbi, F2FS_DIRTY_NODES),
|
||||
@ -1110,7 +1120,7 @@ gc_more:
|
||||
* secure free segments which doesn't need fggc any more.
|
||||
*/
|
||||
if (prefree_segments(sbi)) {
|
||||
ret = write_checkpoint(sbi, &cpc);
|
||||
ret = f2fs_write_checkpoint(sbi, &cpc);
|
||||
if (ret)
|
||||
goto stop;
|
||||
}
|
||||
@ -1133,17 +1143,27 @@ gc_more:
|
||||
sec_freed++;
|
||||
total_freed += seg_freed;
|
||||
|
||||
if (gc_type == FG_GC) {
|
||||
if (sbi->skipped_atomic_files[FG_GC] > last_skipped)
|
||||
skipped_round++;
|
||||
last_skipped = sbi->skipped_atomic_files[FG_GC];
|
||||
round++;
|
||||
}
|
||||
|
||||
if (gc_type == FG_GC)
|
||||
sbi->cur_victim_sec = NULL_SEGNO;
|
||||
|
||||
if (!sync) {
|
||||
if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
|
||||
if (skipped_round > MAX_SKIP_ATOMIC_COUNT &&
|
||||
skipped_round * 2 >= round)
|
||||
f2fs_drop_inmem_pages_all(sbi, true);
|
||||
segno = NULL_SEGNO;
|
||||
goto gc_more;
|
||||
}
|
||||
|
||||
if (gc_type == FG_GC)
|
||||
ret = write_checkpoint(sbi, &cpc);
|
||||
ret = f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
stop:
|
||||
SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
|
||||
@ -1167,19 +1187,10 @@ stop:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void build_gc_manager(struct f2fs_sb_info *sbi)
|
||||
void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
u64 main_count, resv_count, ovp_count;
|
||||
|
||||
DIRTY_I(sbi)->v_ops = &default_v_ops;
|
||||
|
||||
/* threshold of # of valid blocks in a section for victims of FG_GC */
|
||||
main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg;
|
||||
resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg;
|
||||
ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
|
||||
|
||||
sbi->fggc_threshold = div64_u64((main_count - ovp_count) *
|
||||
BLKS_PER_SEC(sbi), (main_count - resv_count));
|
||||
sbi->gc_pin_file_threshold = DEF_GC_FAILED_PINNED_FILES;
|
||||
|
||||
/* give warm/cold data area from slower device */
|
||||
|
@ -36,8 +36,6 @@ struct f2fs_gc_kthread {
|
||||
unsigned int no_gc_sleep_time;
|
||||
|
||||
/* for changing gc mode */
|
||||
unsigned int gc_idle;
|
||||
unsigned int gc_urgent;
|
||||
unsigned int gc_wake;
|
||||
};
|
||||
|
||||
|
@ -43,7 +43,7 @@ bool f2fs_may_inline_dentry(struct inode *inode)
|
||||
return true;
|
||||
}
|
||||
|
||||
void read_inline_data(struct page *page, struct page *ipage)
|
||||
void f2fs_do_read_inline_data(struct page *page, struct page *ipage)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
void *src_addr, *dst_addr;
|
||||
@ -65,7 +65,8 @@ void read_inline_data(struct page *page, struct page *ipage)
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
|
||||
void truncate_inline_inode(struct inode *inode, struct page *ipage, u64 from)
|
||||
void f2fs_truncate_inline_inode(struct inode *inode,
|
||||
struct page *ipage, u64 from)
|
||||
{
|
||||
void *addr;
|
||||
|
||||
@ -97,7 +98,7 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
|
||||
path, current->comm);
|
||||
}
|
||||
|
||||
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
trace_android_fs_dataread_end(inode, page_offset(page),
|
||||
PAGE_SIZE);
|
||||
@ -115,7 +116,7 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
|
||||
if (page->index)
|
||||
zero_user_segment(page, 0, PAGE_SIZE);
|
||||
else
|
||||
read_inline_data(page, ipage);
|
||||
f2fs_do_read_inline_data(page, ipage);
|
||||
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
@ -147,7 +148,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
err = f2fs_reserve_block(dn, 0);
|
||||
if (err)
|
||||
return err;
|
||||
err = get_node_info(fio.sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn->nid, &ni);
|
||||
if (err) {
|
||||
f2fs_put_dnode(dn);
|
||||
return err;
|
||||
@ -167,7 +168,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
|
||||
f2fs_bug_on(F2FS_P_SB(page), PageWriteback(page));
|
||||
|
||||
read_inline_data(page, dn->inode_page);
|
||||
f2fs_do_read_inline_data(page, dn->inode_page);
|
||||
set_page_dirty(page);
|
||||
|
||||
/* clear dirty state */
|
||||
@ -178,18 +179,18 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
ClearPageError(page);
|
||||
fio.old_blkaddr = dn->data_blkaddr;
|
||||
set_inode_flag(dn->inode, FI_HOT_DATA);
|
||||
write_data_page(dn, &fio);
|
||||
f2fs_outplace_write_data(dn, &fio);
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
if (dirty) {
|
||||
inode_dec_dirty_pages(dn->inode);
|
||||
remove_dirty_inode(dn->inode);
|
||||
f2fs_remove_dirty_inode(dn->inode);
|
||||
}
|
||||
|
||||
/* this converted inline_data should be recovered. */
|
||||
set_inode_flag(dn->inode, FI_APPEND_WRITE);
|
||||
|
||||
/* clear inline data and flag after data writeback */
|
||||
truncate_inline_inode(dn->inode, dn->inode_page, 0);
|
||||
f2fs_truncate_inline_inode(dn->inode, dn->inode_page, 0);
|
||||
clear_inline_node(dn->inode_page);
|
||||
clear_out:
|
||||
stat_dec_inline_inode(dn->inode);
|
||||
@ -214,7 +215,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
err = PTR_ERR(ipage);
|
||||
goto out;
|
||||
@ -240,12 +241,10 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
{
|
||||
void *src_addr, *dst_addr;
|
||||
struct dnode_of_data dn;
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, 0, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, 0, LOOKUP_NODE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -263,10 +262,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
kunmap_atomic(src_addr);
|
||||
set_page_dirty(dn.inode_page);
|
||||
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree, page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
f2fs_clear_radix_tree_dirty_tag(page);
|
||||
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
@ -276,7 +272,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool recover_inline_data(struct inode *inode, struct page *npage)
|
||||
bool f2fs_recover_inline_data(struct inode *inode, struct page *npage)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode *ri = NULL;
|
||||
@ -297,7 +293,7 @@ bool recover_inline_data(struct inode *inode, struct page *npage)
|
||||
if (f2fs_has_inline_data(inode) &&
|
||||
ri && (ri->i_inline & F2FS_INLINE_DATA)) {
|
||||
process_inline:
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
f2fs_bug_on(sbi, IS_ERR(ipage));
|
||||
|
||||
f2fs_wait_on_page_writeback(ipage, NODE, true);
|
||||
@ -315,20 +311,20 @@ process_inline:
|
||||
}
|
||||
|
||||
if (f2fs_has_inline_data(inode)) {
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
f2fs_bug_on(sbi, IS_ERR(ipage));
|
||||
truncate_inline_inode(inode, ipage, 0);
|
||||
f2fs_truncate_inline_inode(inode, ipage, 0);
|
||||
clear_inode_flag(inode, FI_INLINE_DATA);
|
||||
f2fs_put_page(ipage, 1);
|
||||
} else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
|
||||
if (truncate_blocks(inode, 0, false))
|
||||
if (f2fs_truncate_blocks(inode, 0, false))
|
||||
return false;
|
||||
goto process_inline;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir,
|
||||
struct fscrypt_name *fname, struct page **res_page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
|
||||
@ -339,7 +335,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
void *inline_dentry;
|
||||
f2fs_hash_t namehash;
|
||||
|
||||
ipage = get_node_page(sbi, dir->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, dir->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
*res_page = ipage;
|
||||
return NULL;
|
||||
@ -350,7 +346,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
inline_dentry = inline_data_addr(dir, ipage);
|
||||
|
||||
make_dentry_ptr_inline(dir, &d, inline_dentry);
|
||||
de = find_target_dentry(fname, namehash, NULL, &d);
|
||||
de = f2fs_find_target_dentry(fname, namehash, NULL, &d);
|
||||
unlock_page(ipage);
|
||||
if (de)
|
||||
*res_page = ipage;
|
||||
@ -360,7 +356,7 @@ struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
|
||||
return de;
|
||||
}
|
||||
|
||||
int make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
int f2fs_make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
struct page *ipage)
|
||||
{
|
||||
struct f2fs_dentry_ptr d;
|
||||
@ -369,7 +365,7 @@ int make_empty_inline_dir(struct inode *inode, struct inode *parent,
|
||||
inline_dentry = inline_data_addr(inode, ipage);
|
||||
|
||||
make_dentry_ptr_inline(inode, &d, inline_dentry);
|
||||
do_make_empty_dir(inode, parent, &d);
|
||||
f2fs_do_make_empty_dir(inode, parent, &d);
|
||||
|
||||
set_page_dirty(ipage);
|
||||
|
||||
@ -415,7 +411,6 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
|
||||
}
|
||||
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
zero_user_segment(page, MAX_INLINE_DATA(dir), PAGE_SIZE);
|
||||
|
||||
dentry_blk = page_address(page);
|
||||
|
||||
@ -439,7 +434,7 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
|
||||
set_page_dirty(page);
|
||||
|
||||
/* clear inline dir and flag after data writeback */
|
||||
truncate_inline_inode(dir, ipage, 0);
|
||||
f2fs_truncate_inline_inode(dir, ipage, 0);
|
||||
|
||||
stat_dec_inline_dir(dir);
|
||||
clear_inode_flag(dir, FI_INLINE_DENTRY);
|
||||
@ -482,7 +477,7 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry)
|
||||
new_name.len = le16_to_cpu(de->name_len);
|
||||
|
||||
ino = le32_to_cpu(de->ino);
|
||||
fake_mode = get_de_type(de) << S_SHIFT;
|
||||
fake_mode = f2fs_get_de_type(de) << S_SHIFT;
|
||||
|
||||
err = f2fs_add_regular_entry(dir, &new_name, NULL, NULL,
|
||||
ino, fake_mode);
|
||||
@ -494,8 +489,8 @@ static int f2fs_add_inline_entries(struct inode *dir, void *inline_dentry)
|
||||
return 0;
|
||||
punch_dentry_pages:
|
||||
truncate_inode_pages(&dir->i_data, 0);
|
||||
truncate_blocks(dir, 0, false);
|
||||
remove_dirty_inode(dir);
|
||||
f2fs_truncate_blocks(dir, 0, false);
|
||||
f2fs_remove_dirty_inode(dir);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -513,7 +508,7 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
|
||||
}
|
||||
|
||||
memcpy(backup_dentry, inline_dentry, MAX_INLINE_DATA(dir));
|
||||
truncate_inline_inode(dir, ipage, 0);
|
||||
f2fs_truncate_inline_inode(dir, ipage, 0);
|
||||
|
||||
unlock_page(ipage);
|
||||
|
||||
@ -563,14 +558,14 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
|
||||
struct page *page = NULL;
|
||||
int err = 0;
|
||||
|
||||
ipage = get_node_page(sbi, dir->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, dir->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return PTR_ERR(ipage);
|
||||
|
||||
inline_dentry = inline_data_addr(dir, ipage);
|
||||
make_dentry_ptr_inline(dir, &d, inline_dentry);
|
||||
|
||||
bit_pos = room_for_filename(d.bitmap, slots, d.max);
|
||||
bit_pos = f2fs_room_for_filename(d.bitmap, slots, d.max);
|
||||
if (bit_pos >= d.max) {
|
||||
err = f2fs_convert_inline_dir(dir, ipage, inline_dentry);
|
||||
if (err)
|
||||
@ -581,7 +576,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
|
||||
|
||||
if (inode) {
|
||||
down_write(&F2FS_I(inode)->i_sem);
|
||||
page = init_inode_metadata(inode, dir, new_name,
|
||||
page = f2fs_init_inode_metadata(inode, dir, new_name,
|
||||
orig_name, ipage);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
@ -602,7 +597,7 @@ int f2fs_add_inline_entry(struct inode *dir, const struct qstr *new_name,
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
update_parent_metadata(dir, inode, 0);
|
||||
f2fs_update_parent_metadata(dir, inode, 0);
|
||||
fail:
|
||||
if (inode)
|
||||
up_write(&F2FS_I(inode)->i_sem);
|
||||
@ -648,7 +643,7 @@ bool f2fs_empty_inline_dir(struct inode *dir)
|
||||
void *inline_dentry;
|
||||
struct f2fs_dentry_ptr d;
|
||||
|
||||
ipage = get_node_page(sbi, dir->i_ino);
|
||||
ipage = f2fs_get_node_page(sbi, dir->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return false;
|
||||
|
||||
@ -679,7 +674,7 @@ int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx,
|
||||
if (ctx->pos == d.max)
|
||||
return 0;
|
||||
|
||||
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return PTR_ERR(ipage);
|
||||
|
||||
@ -705,7 +700,7 @@ int f2fs_inline_data_fiemap(struct inode *inode,
|
||||
struct page *ipage;
|
||||
int err = 0;
|
||||
|
||||
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
if (IS_ERR(ipage))
|
||||
return PTR_ERR(ipage);
|
||||
|
||||
@ -721,7 +716,7 @@ int f2fs_inline_data_fiemap(struct inode *inode,
|
||||
ilen = start + len;
|
||||
ilen -= start;
|
||||
|
||||
err = get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
103
fs/f2fs/inode.c
103
fs/f2fs/inode.c
@ -36,15 +36,15 @@ void f2fs_set_inode_flags(struct inode *inode)
|
||||
unsigned int flags = F2FS_I(inode)->i_flags;
|
||||
unsigned int new_fl = 0;
|
||||
|
||||
if (flags & FS_SYNC_FL)
|
||||
if (flags & F2FS_SYNC_FL)
|
||||
new_fl |= S_SYNC;
|
||||
if (flags & FS_APPEND_FL)
|
||||
if (flags & F2FS_APPEND_FL)
|
||||
new_fl |= S_APPEND;
|
||||
if (flags & FS_IMMUTABLE_FL)
|
||||
if (flags & F2FS_IMMUTABLE_FL)
|
||||
new_fl |= S_IMMUTABLE;
|
||||
if (flags & FS_NOATIME_FL)
|
||||
if (flags & F2FS_NOATIME_FL)
|
||||
new_fl |= S_NOATIME;
|
||||
if (flags & FS_DIRSYNC_FL)
|
||||
if (flags & F2FS_DIRSYNC_FL)
|
||||
new_fl |= S_DIRSYNC;
|
||||
if (f2fs_encrypted_inode(inode))
|
||||
new_fl |= S_ENCRYPTED;
|
||||
@ -120,7 +120,6 @@ static void __recover_inline_status(struct inode *inode, struct page *ipage)
|
||||
static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page)
|
||||
{
|
||||
struct f2fs_inode *ri = &F2FS_NODE(page)->i;
|
||||
int extra_isize = le32_to_cpu(ri->i_extra_isize);
|
||||
|
||||
if (!f2fs_sb_has_inode_chksum(sbi->sb))
|
||||
return false;
|
||||
@ -128,7 +127,8 @@ static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page
|
||||
if (!RAW_IS_INODE(F2FS_NODE(page)) || !(ri->i_inline & F2FS_EXTRA_ATTR))
|
||||
return false;
|
||||
|
||||
if (!F2FS_FITS_IN_INODE(ri, extra_isize, i_inode_checksum))
|
||||
if (!F2FS_FITS_IN_INODE(ri, le16_to_cpu(ri->i_extra_isize),
|
||||
i_inode_checksum))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -214,6 +214,15 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)
|
||||
&& !f2fs_has_extra_attr(inode)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: corrupted inode ino=%lx, run fsck to fix.",
|
||||
__func__, inode->i_ino);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f2fs_has_extra_attr(inode) &&
|
||||
!f2fs_sb_has_extra_attr(sbi->sb)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
@ -264,14 +273,10 @@ static int do_read_inode(struct inode *inode)
|
||||
int err;
|
||||
|
||||
/* Check if ino is within scope */
|
||||
if (check_nid_range(sbi, inode->i_ino)) {
|
||||
f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu",
|
||||
(unsigned long) inode->i_ino);
|
||||
WARN_ON(1);
|
||||
if (f2fs_check_nid_range(sbi, inode->i_ino))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
node_page = get_node_page(sbi, inode->i_ino);
|
||||
node_page = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(node_page))
|
||||
return PTR_ERR(node_page);
|
||||
|
||||
@ -291,8 +296,11 @@ static int do_read_inode(struct inode *inode)
|
||||
inode->i_ctime.tv_nsec = le32_to_cpu(ri->i_ctime_nsec);
|
||||
inode->i_mtime.tv_nsec = le32_to_cpu(ri->i_mtime_nsec);
|
||||
inode->i_generation = le32_to_cpu(ri->i_generation);
|
||||
|
||||
fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
fi->i_current_depth = le32_to_cpu(ri->i_current_depth);
|
||||
else if (S_ISREG(inode->i_mode))
|
||||
fi->i_gc_failures[GC_FAILURE_PIN] =
|
||||
le16_to_cpu(ri->i_gc_failures);
|
||||
fi->i_xattr_nid = le32_to_cpu(ri->i_xattr_nid);
|
||||
fi->i_flags = le32_to_cpu(ri->i_flags);
|
||||
fi->flags = 0;
|
||||
@ -309,7 +317,6 @@ static int do_read_inode(struct inode *inode)
|
||||
le16_to_cpu(ri->i_extra_isize) : 0;
|
||||
|
||||
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
|
||||
f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
|
||||
fi->i_inline_xattr_size = le16_to_cpu(ri->i_inline_xattr_size);
|
||||
} else if (f2fs_has_inline_xattr(inode) ||
|
||||
f2fs_has_inline_dentry(inode)) {
|
||||
@ -345,10 +352,10 @@ static int do_read_inode(struct inode *inode)
|
||||
if (!err)
|
||||
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
|
||||
if (!need_inode_block_update(sbi, inode->i_ino))
|
||||
if (!f2fs_need_inode_block_update(sbi, inode->i_ino))
|
||||
fi->last_disk_size = inode->i_size;
|
||||
|
||||
if (fi->i_flags & FS_PROJINHERIT_FL)
|
||||
if (fi->i_flags & F2FS_PROJINHERIT_FL)
|
||||
set_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
|
||||
if (f2fs_has_extra_attr(inode) && f2fs_sb_has_project_quota(sbi->sb) &&
|
||||
@ -400,10 +407,10 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
|
||||
make_now:
|
||||
if (ino == F2FS_NODE_INO(sbi)) {
|
||||
inode->i_mapping->a_ops = &f2fs_node_aops;
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
|
||||
} else if (ino == F2FS_META_INO(sbi)) {
|
||||
inode->i_mapping->a_ops = &f2fs_meta_aops;
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
|
||||
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
|
||||
} else if (S_ISREG(inode->i_mode)) {
|
||||
inode->i_op = &f2fs_file_inode_operations;
|
||||
inode->i_fop = &f2fs_file_operations;
|
||||
@ -453,7 +460,7 @@ retry:
|
||||
return inode;
|
||||
}
|
||||
|
||||
void update_inode(struct inode *inode, struct page *node_page)
|
||||
void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
{
|
||||
struct f2fs_inode *ri;
|
||||
struct extent_tree *et = F2FS_I(inode)->extent_tree;
|
||||
@ -488,7 +495,12 @@ void update_inode(struct inode *inode, struct page *node_page)
|
||||
ri->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec);
|
||||
ri->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
|
||||
ri->i_mtime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
|
||||
ri->i_current_depth = cpu_to_le32(F2FS_I(inode)->i_current_depth);
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
ri->i_current_depth =
|
||||
cpu_to_le32(F2FS_I(inode)->i_current_depth);
|
||||
else if (S_ISREG(inode->i_mode))
|
||||
ri->i_gc_failures =
|
||||
cpu_to_le16(F2FS_I(inode)->i_gc_failures[GC_FAILURE_PIN]);
|
||||
ri->i_xattr_nid = cpu_to_le32(F2FS_I(inode)->i_xattr_nid);
|
||||
ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags);
|
||||
ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
|
||||
@ -534,12 +546,12 @@ void update_inode(struct inode *inode, struct page *node_page)
|
||||
F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
|
||||
}
|
||||
|
||||
void update_inode_page(struct inode *inode)
|
||||
void f2fs_update_inode_page(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct page *node_page;
|
||||
retry:
|
||||
node_page = get_node_page(sbi, inode->i_ino);
|
||||
node_page = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(node_page)) {
|
||||
int err = PTR_ERR(node_page);
|
||||
if (err == -ENOMEM) {
|
||||
@ -550,7 +562,7 @@ retry:
|
||||
}
|
||||
return;
|
||||
}
|
||||
update_inode(inode, node_page);
|
||||
f2fs_update_inode(inode, node_page);
|
||||
f2fs_put_page(node_page, 1);
|
||||
}
|
||||
|
||||
@ -569,7 +581,7 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
* We need to balance fs here to prevent from producing dirty node pages
|
||||
* during the urgent cleaning time when runing out of free sections.
|
||||
*/
|
||||
update_inode_page(inode);
|
||||
f2fs_update_inode_page(inode);
|
||||
if (wbc && wbc->nr_to_write)
|
||||
f2fs_balance_fs(sbi, true);
|
||||
return 0;
|
||||
@ -586,7 +598,7 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
|
||||
/* some remained atomic pages should discarded */
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
drop_inmem_pages(inode);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
|
||||
trace_f2fs_evict_inode(inode);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
@ -596,7 +608,7 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
goto out_clear;
|
||||
|
||||
f2fs_bug_on(sbi, get_dirty_pages(inode));
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
|
||||
f2fs_destroy_extent_tree(inode);
|
||||
|
||||
@ -605,9 +617,9 @@ void f2fs_evict_inode(struct inode *inode)
|
||||
|
||||
dquot_initialize(inode);
|
||||
|
||||
remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
|
||||
remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
|
||||
f2fs_remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
|
||||
f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
f2fs_remove_ino_entry(sbi, inode->i_ino, FLUSH_INO);
|
||||
|
||||
sb_start_intwrite(inode->i_sb);
|
||||
set_inode_flag(inode, FI_NO_ALLOC);
|
||||
@ -624,7 +636,7 @@ retry:
|
||||
#endif
|
||||
if (!err) {
|
||||
f2fs_lock_op(sbi);
|
||||
err = remove_inode_page(inode);
|
||||
err = f2fs_remove_inode_page(inode);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (err == -ENOENT)
|
||||
err = 0;
|
||||
@ -637,7 +649,7 @@ retry:
|
||||
}
|
||||
|
||||
if (err)
|
||||
update_inode_page(inode);
|
||||
f2fs_update_inode_page(inode);
|
||||
dquot_free_inode(inode);
|
||||
sb_end_intwrite(inode->i_sb);
|
||||
no_delete:
|
||||
@ -664,16 +676,19 @@ no_delete:
|
||||
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
|
||||
if (inode->i_nlink) {
|
||||
if (is_inode_flag_set(inode, FI_APPEND_WRITE))
|
||||
add_ino_entry(sbi, inode->i_ino, APPEND_INO);
|
||||
f2fs_add_ino_entry(sbi, inode->i_ino, APPEND_INO);
|
||||
if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
|
||||
add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
f2fs_add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
|
||||
}
|
||||
if (is_inode_flag_set(inode, FI_FREE_NID)) {
|
||||
alloc_nid_failed(sbi, inode->i_ino);
|
||||
f2fs_alloc_nid_failed(sbi, inode->i_ino);
|
||||
clear_inode_flag(inode, FI_FREE_NID);
|
||||
} else {
|
||||
f2fs_bug_on(sbi, err &&
|
||||
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
|
||||
/*
|
||||
* If xattr nid is corrupted, we can reach out error condition,
|
||||
* err & !f2fs_exist_written_data(sbi, inode->i_ino, ORPHAN_INO)).
|
||||
* In that case, f2fs_check_nid_range() is enough to give a clue.
|
||||
*/
|
||||
}
|
||||
out_clear:
|
||||
fscrypt_put_encryption_info(inode);
|
||||
@ -681,7 +696,7 @@ out_clear:
|
||||
}
|
||||
|
||||
/* caller should call f2fs_lock_op() */
|
||||
void handle_failed_inode(struct inode *inode)
|
||||
void f2fs_handle_failed_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct node_info ni;
|
||||
@ -697,7 +712,7 @@ void handle_failed_inode(struct inode *inode)
|
||||
* we must call this to avoid inode being remained as dirty, resulting
|
||||
* in a panic when flushing dirty inodes in gdirty_list.
|
||||
*/
|
||||
update_inode_page(inode);
|
||||
f2fs_update_inode_page(inode);
|
||||
f2fs_inode_synced(inode);
|
||||
|
||||
/* don't make bad inode, since it becomes a regular file. */
|
||||
@ -708,7 +723,7 @@ void handle_failed_inode(struct inode *inode)
|
||||
* so we can prevent losing this orphan when encoutering checkpoint
|
||||
* and following suddenly power-off.
|
||||
*/
|
||||
err = get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
@ -717,15 +732,15 @@ void handle_failed_inode(struct inode *inode)
|
||||
}
|
||||
|
||||
if (ni.blk_addr != NULL_ADDR) {
|
||||
err = acquire_orphan_inode(sbi);
|
||||
err = f2fs_acquire_orphan_inode(sbi);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"Too many orphan inodes, run fsck to fix.");
|
||||
} else {
|
||||
add_orphan_inode(inode);
|
||||
f2fs_add_orphan_inode(inode);
|
||||
}
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
f2fs_alloc_nid_done(sbi, inode->i_ino);
|
||||
} else {
|
||||
set_inode_flag(inode, FI_FREE_NID);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
if (!alloc_nid(sbi, &ino)) {
|
||||
if (!f2fs_alloc_nid(sbi, &ino)) {
|
||||
f2fs_unlock_op(sbi);
|
||||
err = -ENOSPC;
|
||||
goto fail;
|
||||
@ -54,6 +54,9 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
F2FS_I(inode)->i_crtime = current_time(inode);
|
||||
inode->i_generation = sbi->s_next_generation++;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
F2FS_I(inode)->i_current_depth = 1;
|
||||
|
||||
err = insert_inode_locked(inode);
|
||||
if (err) {
|
||||
err = -EINVAL;
|
||||
@ -61,7 +64,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
}
|
||||
|
||||
if (f2fs_sb_has_project_quota(sbi->sb) &&
|
||||
(F2FS_I(dir)->i_flags & FS_PROJINHERIT_FL))
|
||||
(F2FS_I(dir)->i_flags & F2FS_PROJINHERIT_FL))
|
||||
F2FS_I(inode)->i_projid = F2FS_I(dir)->i_projid;
|
||||
else
|
||||
F2FS_I(inode)->i_projid = make_kprojid(&init_user_ns,
|
||||
@ -116,9 +119,9 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
F2FS_I(inode)->i_flags |= FS_INDEX_FL;
|
||||
F2FS_I(inode)->i_flags |= F2FS_INDEX_FL;
|
||||
|
||||
if (F2FS_I(inode)->i_flags & FS_PROJINHERIT_FL)
|
||||
if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
|
||||
set_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
|
||||
trace_f2fs_new_inode(inode, 0);
|
||||
@ -193,7 +196,7 @@ static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *
|
||||
up_read(&sbi->sb_lock);
|
||||
}
|
||||
|
||||
int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
@ -292,7 +295,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
goto out;
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
alloc_nid_done(sbi, ino);
|
||||
f2fs_alloc_nid_done(sbi, ino);
|
||||
|
||||
d_instantiate_new(dentry, inode);
|
||||
|
||||
@ -302,7 +305,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
f2fs_balance_fs(sbi, true);
|
||||
return 0;
|
||||
out:
|
||||
handle_failed_inode(inode);
|
||||
f2fs_handle_failed_inode(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -397,7 +400,7 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
err = PTR_ERR(page);
|
||||
goto out;
|
||||
} else {
|
||||
err = __f2fs_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR);
|
||||
err = f2fs_do_add_link(dir, &dot, NULL, dir->i_ino, S_IFDIR);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -408,7 +411,7 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
else if (IS_ERR(page))
|
||||
err = PTR_ERR(page);
|
||||
else
|
||||
err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
|
||||
err = f2fs_do_add_link(dir, &dotdot, NULL, pino, S_IFDIR);
|
||||
out:
|
||||
if (!err)
|
||||
clear_inode_flag(dir, FI_INLINE_DOTS);
|
||||
@ -520,7 +523,7 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
err = acquire_orphan_inode(sbi);
|
||||
err = f2fs_acquire_orphan_inode(sbi);
|
||||
if (err) {
|
||||
f2fs_unlock_op(sbi);
|
||||
f2fs_put_page(page, 0);
|
||||
@ -585,9 +588,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_add_link(dentry, inode);
|
||||
if (err)
|
||||
goto out_handle_failed_inode;
|
||||
goto out_f2fs_handle_failed_inode;
|
||||
f2fs_unlock_op(sbi);
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
f2fs_alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
|
||||
if (err)
|
||||
@ -620,8 +623,8 @@ err_out:
|
||||
f2fs_balance_fs(sbi, true);
|
||||
goto out_free_encrypted_link;
|
||||
|
||||
out_handle_failed_inode:
|
||||
handle_failed_inode(inode);
|
||||
out_f2fs_handle_failed_inode:
|
||||
f2fs_handle_failed_inode(inode);
|
||||
out_free_encrypted_link:
|
||||
if (disk_link.name != (unsigned char *)symname)
|
||||
kfree(disk_link.name);
|
||||
@ -657,7 +660,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
goto out_fail;
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
f2fs_alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
d_instantiate_new(dentry, inode);
|
||||
|
||||
@ -669,7 +672,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
|
||||
out_fail:
|
||||
clear_inode_flag(inode, FI_INC_LINK);
|
||||
handle_failed_inode(inode);
|
||||
f2fs_handle_failed_inode(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -708,7 +711,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
goto out;
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
f2fs_alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
d_instantiate_new(dentry, inode);
|
||||
|
||||
@ -718,7 +721,7 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
f2fs_balance_fs(sbi, true);
|
||||
return 0;
|
||||
out:
|
||||
handle_failed_inode(inode);
|
||||
f2fs_handle_failed_inode(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -747,7 +750,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
err = acquire_orphan_inode(sbi);
|
||||
err = f2fs_acquire_orphan_inode(sbi);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -759,8 +762,8 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
* add this non-linked tmpfile to orphan list, in this way we could
|
||||
* remove all unused data of tmpfile after abnormal power-off.
|
||||
*/
|
||||
add_orphan_inode(inode);
|
||||
alloc_nid_done(sbi, inode->i_ino);
|
||||
f2fs_add_orphan_inode(inode);
|
||||
f2fs_alloc_nid_done(sbi, inode->i_ino);
|
||||
|
||||
if (whiteout) {
|
||||
f2fs_i_links_write(inode, false);
|
||||
@ -776,9 +779,9 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
return 0;
|
||||
|
||||
release_out:
|
||||
release_orphan_inode(sbi);
|
||||
f2fs_release_orphan_inode(sbi);
|
||||
out:
|
||||
handle_failed_inode(inode);
|
||||
f2fs_handle_failed_inode(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -885,7 +888,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
err = acquire_orphan_inode(sbi);
|
||||
err = f2fs_acquire_orphan_inode(sbi);
|
||||
if (err)
|
||||
goto put_out_dir;
|
||||
|
||||
@ -899,9 +902,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
up_write(&F2FS_I(new_inode)->i_sem);
|
||||
|
||||
if (!new_inode->i_nlink)
|
||||
add_orphan_inode(new_inode);
|
||||
f2fs_add_orphan_inode(new_inode);
|
||||
else
|
||||
release_orphan_inode(sbi);
|
||||
f2fs_release_orphan_inode(sbi);
|
||||
} else {
|
||||
f2fs_balance_fs(sbi, true);
|
||||
|
||||
@ -969,8 +972,12 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
f2fs_put_page(old_dir_page, 0);
|
||||
f2fs_i_links_write(old_dir, false);
|
||||
}
|
||||
if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
|
||||
add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
|
||||
if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
|
||||
f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
|
||||
if (S_ISDIR(old_inode->i_mode))
|
||||
f2fs_add_ino_entry(sbi, old_inode->i_ino,
|
||||
TRANS_DIR_INO);
|
||||
}
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
@ -1121,8 +1128,8 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
f2fs_mark_inode_dirty_sync(new_dir, false);
|
||||
|
||||
if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
|
||||
add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
|
||||
add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
|
||||
f2fs_add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
|
||||
f2fs_add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
|
||||
}
|
||||
|
||||
f2fs_unlock_op(sbi);
|
||||
|
340
fs/f2fs/node.c
340
fs/f2fs/node.c
@ -23,13 +23,28 @@
|
||||
#include "trace.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
#define on_build_free_nids(nmi) mutex_is_locked(&(nm_i)->build_lock)
|
||||
#define on_f2fs_build_free_nids(nmi) mutex_is_locked(&(nm_i)->build_lock)
|
||||
|
||||
static struct kmem_cache *nat_entry_slab;
|
||||
static struct kmem_cache *free_nid_slab;
|
||||
static struct kmem_cache *nat_entry_set_slab;
|
||||
|
||||
bool available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
/*
|
||||
* Check whether the given nid is within node id range.
|
||||
*/
|
||||
int f2fs_check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
if (unlikely(nid < F2FS_ROOT_INO(sbi) || nid >= NM_I(sbi)->max_nid)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: out-of-range nid=%x, run fsck to fix.",
|
||||
__func__, nid);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct sysinfo val;
|
||||
@ -87,18 +102,10 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
|
||||
static void clear_node_page_dirty(struct page *page)
|
||||
{
|
||||
struct address_space *mapping = page->mapping;
|
||||
unsigned int long flags;
|
||||
|
||||
if (PageDirty(page)) {
|
||||
spin_lock_irqsave(&mapping->tree_lock, flags);
|
||||
radix_tree_tag_clear(&mapping->page_tree,
|
||||
page_index(page),
|
||||
PAGECACHE_TAG_DIRTY);
|
||||
spin_unlock_irqrestore(&mapping->tree_lock, flags);
|
||||
|
||||
f2fs_clear_radix_tree_dirty_tag(page);
|
||||
clear_page_dirty_for_io(page);
|
||||
dec_page_count(F2FS_M_SB(mapping), F2FS_DIRTY_NODES);
|
||||
dec_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
|
||||
}
|
||||
ClearPageUptodate(page);
|
||||
}
|
||||
@ -123,10 +130,10 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
dst_off = next_nat_addr(sbi, src_off);
|
||||
|
||||
/* get current nat block page with lock */
|
||||
src_page = get_meta_page(sbi, src_off);
|
||||
src_page = f2fs_get_meta_page(sbi, src_off);
|
||||
if (IS_ERR(src_page))
|
||||
return src_page;
|
||||
dst_page = grab_meta_page(sbi, dst_off);
|
||||
dst_page = f2fs_grab_meta_page(sbi, dst_off);
|
||||
f2fs_bug_on(sbi, PageDirty(src_page));
|
||||
|
||||
src_addr = page_address(src_page);
|
||||
@ -262,7 +269,7 @@ static unsigned int __gang_lookup_nat_set(struct f2fs_nm_info *nm_i,
|
||||
start, nr);
|
||||
}
|
||||
|
||||
int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
int f2fs_need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct nat_entry *e;
|
||||
@ -279,7 +286,7 @@ int need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
return need;
|
||||
}
|
||||
|
||||
bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
bool f2fs_is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct nat_entry *e;
|
||||
@ -293,7 +300,7 @@ bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
return is_cp;
|
||||
}
|
||||
|
||||
bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct nat_entry *e;
|
||||
@ -392,7 +399,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
up_write(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
int nr = nr_shrink;
|
||||
@ -414,7 +421,8 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
/*
|
||||
* This function always returns success
|
||||
*/
|
||||
int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
|
||||
int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||
struct node_info *ni)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
@ -444,7 +452,7 @@ int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
|
||||
|
||||
/* Check current segment summary */
|
||||
down_read(&curseg->journal_rwsem);
|
||||
i = lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);
|
||||
i = f2fs_lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);
|
||||
if (i >= 0) {
|
||||
ne = nat_in_journal(journal, i);
|
||||
node_info_from_raw_nat(ni, &ne);
|
||||
@ -459,7 +467,7 @@ int get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
|
||||
index = current_nat_addr(sbi, nid);
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
|
||||
page = get_meta_page(sbi, index);
|
||||
page = f2fs_get_meta_page(sbi, index);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
@ -476,7 +484,7 @@ cache:
|
||||
/*
|
||||
* readahead MAX_RA_NODE number of node pages.
|
||||
*/
|
||||
static void ra_node_pages(struct page *parent, int start, int n)
|
||||
static void f2fs_ra_node_pages(struct page *parent, int start, int n)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
|
||||
struct blk_plug plug;
|
||||
@ -490,13 +498,13 @@ static void ra_node_pages(struct page *parent, int start, int n)
|
||||
end = min(end, NIDS_PER_BLOCK);
|
||||
for (i = start; i < end; i++) {
|
||||
nid = get_nid(parent, i, false);
|
||||
ra_node_page(sbi, nid);
|
||||
f2fs_ra_node_page(sbi, nid);
|
||||
}
|
||||
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
pgoff_t get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
|
||||
pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs)
|
||||
{
|
||||
const long direct_index = ADDRS_PER_INODE(dn->inode);
|
||||
const long direct_blks = ADDRS_PER_BLOCK;
|
||||
@ -611,7 +619,7 @@ got:
|
||||
* f2fs_unlock_op() only if ro is not set RDONLY_NODE.
|
||||
* In the case of RDONLY_NODE, we don't need to care about mutex.
|
||||
*/
|
||||
int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
struct page *npage[4];
|
||||
@ -630,7 +638,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
npage[0] = dn->inode_page;
|
||||
|
||||
if (!npage[0]) {
|
||||
npage[0] = get_node_page(sbi, nids[0]);
|
||||
npage[0] = f2fs_get_node_page(sbi, nids[0]);
|
||||
if (IS_ERR(npage[0]))
|
||||
return PTR_ERR(npage[0]);
|
||||
}
|
||||
@ -654,24 +662,24 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
|
||||
if (!nids[i] && mode == ALLOC_NODE) {
|
||||
/* alloc new node */
|
||||
if (!alloc_nid(sbi, &(nids[i]))) {
|
||||
if (!f2fs_alloc_nid(sbi, &(nids[i]))) {
|
||||
err = -ENOSPC;
|
||||
goto release_pages;
|
||||
}
|
||||
|
||||
dn->nid = nids[i];
|
||||
npage[i] = new_node_page(dn, noffset[i]);
|
||||
npage[i] = f2fs_new_node_page(dn, noffset[i]);
|
||||
if (IS_ERR(npage[i])) {
|
||||
alloc_nid_failed(sbi, nids[i]);
|
||||
f2fs_alloc_nid_failed(sbi, nids[i]);
|
||||
err = PTR_ERR(npage[i]);
|
||||
goto release_pages;
|
||||
}
|
||||
|
||||
set_nid(parent, offset[i - 1], nids[i], i == 1);
|
||||
alloc_nid_done(sbi, nids[i]);
|
||||
f2fs_alloc_nid_done(sbi, nids[i]);
|
||||
done = true;
|
||||
} else if (mode == LOOKUP_NODE_RA && i == level && level > 1) {
|
||||
npage[i] = get_node_page_ra(parent, offset[i - 1]);
|
||||
npage[i] = f2fs_get_node_page_ra(parent, offset[i - 1]);
|
||||
if (IS_ERR(npage[i])) {
|
||||
err = PTR_ERR(npage[i]);
|
||||
goto release_pages;
|
||||
@ -686,7 +694,7 @@ int get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
npage[i] = get_node_page(sbi, nids[i]);
|
||||
npage[i] = f2fs_get_node_page(sbi, nids[i]);
|
||||
if (IS_ERR(npage[i])) {
|
||||
err = PTR_ERR(npage[i]);
|
||||
f2fs_put_page(npage[0], 0);
|
||||
@ -727,17 +735,17 @@ static int truncate_node(struct dnode_of_data *dn)
|
||||
int err;
|
||||
pgoff_t index;
|
||||
|
||||
err = get_node_info(sbi, dn->nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Deallocate node address */
|
||||
invalidate_blocks(sbi, ni.blk_addr);
|
||||
f2fs_invalidate_blocks(sbi, ni.blk_addr);
|
||||
dec_valid_node_count(sbi, dn->inode, dn->nid == dn->inode->i_ino);
|
||||
set_node_addr(sbi, &ni, NULL_ADDR, false);
|
||||
|
||||
if (dn->nid == dn->inode->i_ino) {
|
||||
remove_orphan_inode(sbi, dn->nid);
|
||||
f2fs_remove_orphan_inode(sbi, dn->nid);
|
||||
dec_valid_inode_count(sbi);
|
||||
f2fs_inode_synced(dn->inode);
|
||||
}
|
||||
@ -765,7 +773,7 @@ static int truncate_dnode(struct dnode_of_data *dn)
|
||||
return 1;
|
||||
|
||||
/* get direct node */
|
||||
page = get_node_page(F2FS_I_SB(dn->inode), dn->nid);
|
||||
page = f2fs_get_node_page(F2FS_I_SB(dn->inode), dn->nid);
|
||||
if (IS_ERR(page) && PTR_ERR(page) == -ENOENT)
|
||||
return 1;
|
||||
else if (IS_ERR(page))
|
||||
@ -774,7 +782,7 @@ static int truncate_dnode(struct dnode_of_data *dn)
|
||||
/* Make dnode_of_data for parameter */
|
||||
dn->node_page = page;
|
||||
dn->ofs_in_node = 0;
|
||||
truncate_data_blocks(dn);
|
||||
f2fs_truncate_data_blocks(dn);
|
||||
err = truncate_node(dn);
|
||||
if (err)
|
||||
return err;
|
||||
@ -797,13 +805,13 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
|
||||
|
||||
trace_f2fs_truncate_nodes_enter(dn->inode, dn->nid, dn->data_blkaddr);
|
||||
|
||||
page = get_node_page(F2FS_I_SB(dn->inode), dn->nid);
|
||||
page = f2fs_get_node_page(F2FS_I_SB(dn->inode), dn->nid);
|
||||
if (IS_ERR(page)) {
|
||||
trace_f2fs_truncate_nodes_exit(dn->inode, PTR_ERR(page));
|
||||
return PTR_ERR(page);
|
||||
}
|
||||
|
||||
ra_node_pages(page, ofs, NIDS_PER_BLOCK);
|
||||
f2fs_ra_node_pages(page, ofs, NIDS_PER_BLOCK);
|
||||
|
||||
rn = F2FS_NODE(page);
|
||||
if (depth < 3) {
|
||||
@ -875,7 +883,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
|
||||
/* get indirect nodes in the path */
|
||||
for (i = 0; i < idx + 1; i++) {
|
||||
/* reference count'll be increased */
|
||||
pages[i] = get_node_page(F2FS_I_SB(dn->inode), nid[i]);
|
||||
pages[i] = f2fs_get_node_page(F2FS_I_SB(dn->inode), nid[i]);
|
||||
if (IS_ERR(pages[i])) {
|
||||
err = PTR_ERR(pages[i]);
|
||||
idx = i - 1;
|
||||
@ -884,7 +892,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
|
||||
nid[i + 1] = get_nid(pages[i], offset[i + 1], false);
|
||||
}
|
||||
|
||||
ra_node_pages(pages[idx], offset[idx + 1], NIDS_PER_BLOCK);
|
||||
f2fs_ra_node_pages(pages[idx], offset[idx + 1], NIDS_PER_BLOCK);
|
||||
|
||||
/* free direct nodes linked to a partial indirect node */
|
||||
for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) {
|
||||
@ -923,7 +931,7 @@ fail:
|
||||
/*
|
||||
* All the block addresses of data and nodes should be nullified.
|
||||
*/
|
||||
int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||
int f2fs_truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
int err = 0, cont = 1;
|
||||
@ -939,7 +947,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
|
||||
if (level < 0)
|
||||
return level;
|
||||
|
||||
page = get_node_page(sbi, inode->i_ino);
|
||||
page = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(page)) {
|
||||
trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
|
||||
return PTR_ERR(page);
|
||||
@ -1019,7 +1027,7 @@ fail:
|
||||
}
|
||||
|
||||
/* caller must lock inode page */
|
||||
int truncate_xattr_node(struct inode *inode)
|
||||
int f2fs_truncate_xattr_node(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
nid_t nid = F2FS_I(inode)->i_xattr_nid;
|
||||
@ -1030,7 +1038,7 @@ int truncate_xattr_node(struct inode *inode)
|
||||
if (!nid)
|
||||
return 0;
|
||||
|
||||
npage = get_node_page(sbi, nid);
|
||||
npage = f2fs_get_node_page(sbi, nid);
|
||||
if (IS_ERR(npage))
|
||||
return PTR_ERR(npage);
|
||||
|
||||
@ -1050,17 +1058,17 @@ int truncate_xattr_node(struct inode *inode)
|
||||
* Caller should grab and release a rwsem by calling f2fs_lock_op() and
|
||||
* f2fs_unlock_op().
|
||||
*/
|
||||
int remove_inode_page(struct inode *inode)
|
||||
int f2fs_remove_inode_page(struct inode *inode)
|
||||
{
|
||||
struct dnode_of_data dn;
|
||||
int err;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
|
||||
err = get_dnode_of_data(&dn, 0, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, 0, LOOKUP_NODE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = truncate_xattr_node(inode);
|
||||
err = f2fs_truncate_xattr_node(inode);
|
||||
if (err) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return err;
|
||||
@ -1069,7 +1077,7 @@ int remove_inode_page(struct inode *inode)
|
||||
/* remove potential inline_data blocks */
|
||||
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
|
||||
S_ISLNK(inode->i_mode))
|
||||
truncate_data_blocks_range(&dn, 1);
|
||||
f2fs_truncate_data_blocks_range(&dn, 1);
|
||||
|
||||
/* 0 is possible, after f2fs_new_inode() has failed */
|
||||
f2fs_bug_on(F2FS_I_SB(inode),
|
||||
@ -1084,7 +1092,7 @@ int remove_inode_page(struct inode *inode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct page *new_inode_page(struct inode *inode)
|
||||
struct page *f2fs_new_inode_page(struct inode *inode)
|
||||
{
|
||||
struct dnode_of_data dn;
|
||||
|
||||
@ -1092,10 +1100,10 @@ struct page *new_inode_page(struct inode *inode)
|
||||
set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
|
||||
|
||||
/* caller should f2fs_put_page(page, 1); */
|
||||
return new_node_page(&dn, 0);
|
||||
return f2fs_new_node_page(&dn, 0);
|
||||
}
|
||||
|
||||
struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
|
||||
struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
struct node_info new_ni;
|
||||
@ -1113,7 +1121,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs)
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
err = get_node_info(sbi, dn->nid, &new_ni);
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &new_ni);
|
||||
if (err) {
|
||||
dec_valid_node_count(sbi, dn->inode, !ofs);
|
||||
goto fail;
|
||||
@ -1170,7 +1178,7 @@ static int read_node_page(struct page *page, int op_flags)
|
||||
if (PageUptodate(page))
|
||||
return LOCKED_PAGE;
|
||||
|
||||
err = get_node_info(sbi, page->index, &ni);
|
||||
err = f2fs_get_node_info(sbi, page->index, &ni);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1186,14 +1194,15 @@ static int read_node_page(struct page *page, int op_flags)
|
||||
/*
|
||||
* Readahead a node page
|
||||
*/
|
||||
void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
struct page *apage;
|
||||
int err;
|
||||
|
||||
if (!nid)
|
||||
return;
|
||||
f2fs_bug_on(sbi, check_nid_range(sbi, nid));
|
||||
if (f2fs_check_nid_range(sbi, nid))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
apage = radix_tree_lookup(&NODE_MAPPING(sbi)->page_tree, nid);
|
||||
@ -1217,7 +1226,8 @@ static struct page *__get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid,
|
||||
|
||||
if (!nid)
|
||||
return ERR_PTR(-ENOENT);
|
||||
f2fs_bug_on(sbi, check_nid_range(sbi, nid));
|
||||
if (f2fs_check_nid_range(sbi, nid))
|
||||
return ERR_PTR(-EINVAL);
|
||||
repeat:
|
||||
page = f2fs_grab_cache_page(NODE_MAPPING(sbi), nid, false);
|
||||
if (!page)
|
||||
@ -1233,7 +1243,7 @@ repeat:
|
||||
}
|
||||
|
||||
if (parent)
|
||||
ra_node_pages(parent, start + 1, MAX_RA_NODE);
|
||||
f2fs_ra_node_pages(parent, start + 1, MAX_RA_NODE);
|
||||
|
||||
lock_page(page);
|
||||
|
||||
@ -1267,12 +1277,12 @@ out_err:
|
||||
return page;
|
||||
}
|
||||
|
||||
struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
|
||||
struct page *f2fs_get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
|
||||
{
|
||||
return __get_node_page(sbi, nid, NULL, 0);
|
||||
}
|
||||
|
||||
struct page *get_node_page_ra(struct page *parent, int start)
|
||||
struct page *f2fs_get_node_page_ra(struct page *parent, int start)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_P_SB(parent);
|
||||
nid_t nid = get_nid(parent, start, false);
|
||||
@ -1307,7 +1317,7 @@ static void flush_inline_data(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
|
||||
ret = f2fs_write_inline_data(inode, page);
|
||||
inode_dec_dirty_pages(inode);
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
if (ret)
|
||||
set_page_dirty(page);
|
||||
page_out:
|
||||
@ -1318,21 +1328,17 @@ iput_out:
|
||||
|
||||
static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
pgoff_t index, end;
|
||||
pgoff_t index;
|
||||
struct pagevec pvec;
|
||||
struct page *last_page = NULL;
|
||||
int nr_pages;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
index = 0;
|
||||
end = ULONG_MAX;
|
||||
|
||||
while (index <= end) {
|
||||
int i, nr_pages;
|
||||
nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_DIRTY))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
@ -1398,11 +1404,8 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
||||
|
||||
trace_f2fs_writepage(page, NODE);
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
dec_page_count(sbi, F2FS_DIRTY_NODES);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
goto redirty_out;
|
||||
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
||||
goto redirty_out;
|
||||
@ -1411,7 +1414,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
||||
nid = nid_of_node(page);
|
||||
f2fs_bug_on(sbi, page->index != nid);
|
||||
|
||||
if (get_node_info(sbi, nid, &ni))
|
||||
if (f2fs_get_node_info(sbi, nid, &ni))
|
||||
goto redirty_out;
|
||||
|
||||
if (wbc->for_reclaim) {
|
||||
@ -1442,7 +1445,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
||||
set_page_writeback(page);
|
||||
ClearPageError(page);
|
||||
fio.old_blkaddr = ni.blk_addr;
|
||||
write_node_page(nid, &fio);
|
||||
f2fs_do_write_node_page(nid, &fio);
|
||||
set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page));
|
||||
dec_page_count(sbi, F2FS_DIRTY_NODES);
|
||||
up_read(&sbi->node_write);
|
||||
@ -1471,7 +1474,7 @@ redirty_out:
|
||||
return AOP_WRITEPAGE_ACTIVATE;
|
||||
}
|
||||
|
||||
int move_node_page(struct page *node_page, int gc_type)
|
||||
int f2fs_move_node_page(struct page *node_page, int gc_type)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
@ -1515,16 +1518,17 @@ static int f2fs_write_node_page(struct page *page,
|
||||
return __write_node_page(page, false, NULL, wbc, false, FS_NODE_IO);
|
||||
}
|
||||
|
||||
int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
int f2fs_fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
struct writeback_control *wbc, bool atomic)
|
||||
{
|
||||
pgoff_t index, end;
|
||||
pgoff_t index;
|
||||
pgoff_t last_idx = ULONG_MAX;
|
||||
struct pagevec pvec;
|
||||
int ret = 0;
|
||||
struct page *last_page = NULL;
|
||||
bool marked = false;
|
||||
nid_t ino = inode->i_ino;
|
||||
int nr_pages;
|
||||
|
||||
if (atomic) {
|
||||
last_page = last_fsync_dnode(sbi, ino);
|
||||
@ -1534,15 +1538,10 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
retry:
|
||||
pagevec_init(&pvec, 0);
|
||||
index = 0;
|
||||
end = ULONG_MAX;
|
||||
|
||||
while (index <= end) {
|
||||
int i, nr_pages;
|
||||
nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_DIRTY))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
@ -1586,9 +1585,9 @@ continue_unlock:
|
||||
if (IS_INODE(page)) {
|
||||
if (is_inode_flag_set(inode,
|
||||
FI_DIRTY_INODE))
|
||||
update_inode(inode, page);
|
||||
f2fs_update_inode(inode, page);
|
||||
set_dentry_mark(page,
|
||||
need_dentry_mark(sbi, ino));
|
||||
f2fs_need_dentry_mark(sbi, ino));
|
||||
}
|
||||
/* may be written by other thread */
|
||||
if (!PageDirty(page))
|
||||
@ -1638,33 +1637,37 @@ out:
|
||||
return ret ? -EIO: 0;
|
||||
}
|
||||
|
||||
int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,
|
||||
int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
|
||||
struct writeback_control *wbc,
|
||||
bool do_balance, enum iostat_type io_type)
|
||||
{
|
||||
pgoff_t index, end;
|
||||
pgoff_t index;
|
||||
struct pagevec pvec;
|
||||
int step = 0;
|
||||
int nwritten = 0;
|
||||
int ret = 0;
|
||||
int nr_pages, done = 0;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
|
||||
next_step:
|
||||
index = 0;
|
||||
end = ULONG_MAX;
|
||||
|
||||
while (index <= end) {
|
||||
int i, nr_pages;
|
||||
nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_DIRTY,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
while (!done && (nr_pages = pagevec_lookup_tag(&pvec,
|
||||
NODE_MAPPING(sbi), &index, PAGECACHE_TAG_DIRTY))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
bool submitted = false;
|
||||
|
||||
/* give a priority to WB_SYNC threads */
|
||||
if (atomic_read(&sbi->wb_sync_req[NODE]) &&
|
||||
wbc->sync_mode == WB_SYNC_NONE) {
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* flushing sequence with step:
|
||||
* 0. indirect nodes
|
||||
@ -1745,29 +1748,22 @@ continue_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
int f2fs_wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
pgoff_t index = 0, end = ULONG_MAX;
|
||||
pgoff_t index = 0;
|
||||
struct pagevec pvec;
|
||||
int ret2, ret = 0;
|
||||
int nr_pages;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
|
||||
while (index <= end) {
|
||||
int i, nr_pages;
|
||||
nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_WRITEBACK,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
while ((nr_pages = pagevec_lookup_tag(&pvec, NODE_MAPPING(sbi), &index,
|
||||
PAGECACHE_TAG_WRITEBACK))) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
/* until radix tree lookup accepts end_index */
|
||||
if (unlikely(page->index > end))
|
||||
continue;
|
||||
|
||||
if (ino && ino_of_node(page) == ino) {
|
||||
f2fs_wait_on_page_writeback(page, NODE, true);
|
||||
if (TestClearPageError(page))
|
||||
@ -1801,14 +1797,21 @@ static int f2fs_write_node_pages(struct address_space *mapping,
|
||||
if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE))
|
||||
goto skip_write;
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_inc(&sbi->wb_sync_req[NODE]);
|
||||
else if (atomic_read(&sbi->wb_sync_req[NODE]))
|
||||
goto skip_write;
|
||||
|
||||
trace_f2fs_writepages(mapping->host, wbc, NODE);
|
||||
|
||||
diff = nr_pages_to_write(sbi, NODE, wbc);
|
||||
wbc->sync_mode = WB_SYNC_NONE;
|
||||
blk_start_plug(&plug);
|
||||
sync_node_pages(sbi, wbc, true, FS_NODE_IO);
|
||||
f2fs_sync_node_pages(sbi, wbc, true, FS_NODE_IO);
|
||||
blk_finish_plug(&plug);
|
||||
wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_dec(&sbi->wb_sync_req[NODE]);
|
||||
return 0;
|
||||
|
||||
skip_write:
|
||||
@ -1954,20 +1957,20 @@ static bool add_free_nid(struct f2fs_sb_info *sbi,
|
||||
* Thread A Thread B
|
||||
* - f2fs_create
|
||||
* - f2fs_new_inode
|
||||
* - alloc_nid
|
||||
* - f2fs_alloc_nid
|
||||
* - __insert_nid_to_list(PREALLOC_NID)
|
||||
* - f2fs_balance_fs_bg
|
||||
* - build_free_nids
|
||||
* - __build_free_nids
|
||||
* - f2fs_build_free_nids
|
||||
* - __f2fs_build_free_nids
|
||||
* - scan_nat_page
|
||||
* - add_free_nid
|
||||
* - __lookup_nat_cache
|
||||
* - f2fs_add_link
|
||||
* - init_inode_metadata
|
||||
* - new_inode_page
|
||||
* - new_node_page
|
||||
* - f2fs_init_inode_metadata
|
||||
* - f2fs_new_inode_page
|
||||
* - f2fs_new_node_page
|
||||
* - set_node_addr
|
||||
* - alloc_nid_done
|
||||
* - f2fs_alloc_nid_done
|
||||
* - __remove_nid_from_list(PREALLOC_NID)
|
||||
* - __insert_nid_to_list(FREE_NID)
|
||||
*/
|
||||
@ -2102,7 +2105,8 @@ out:
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
}
|
||||
|
||||
static int __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi,
|
||||
bool sync, bool mount)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
int i = 0, ret;
|
||||
@ -2115,7 +2119,7 @@ static int __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
if (nm_i->nid_cnt[FREE_NID] >= NAT_ENTRY_PER_BLOCK)
|
||||
return 0;
|
||||
|
||||
if (!sync && !available_free_memory(sbi, FREE_NIDS))
|
||||
if (!sync && !f2fs_available_free_memory(sbi, FREE_NIDS))
|
||||
return 0;
|
||||
|
||||
if (!mount) {
|
||||
@ -2127,7 +2131,7 @@ static int __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
}
|
||||
|
||||
/* readahead nat pages to be scanned */
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
|
||||
f2fs_ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES,
|
||||
META_NAT, true);
|
||||
|
||||
down_read(&nm_i->nat_tree_lock);
|
||||
@ -2169,16 +2173,16 @@ static int __build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
|
||||
up_read(&nm_i->nat_tree_lock);
|
||||
|
||||
ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
|
||||
f2fs_ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nm_i->next_scan_nid),
|
||||
nm_i->ra_nid_pages, META_NAT, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
int f2fs_build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
{
|
||||
int ret;
|
||||
mutex_lock(&NM_I(sbi)->build_lock);
|
||||
ret = __build_free_nids(sbi, sync, mount);
|
||||
ret = __f2fs_build_free_nids(sbi, sync, mount);
|
||||
mutex_unlock(&NM_I(sbi)->build_lock);
|
||||
return ret;
|
||||
}
|
||||
@ -2188,7 +2192,7 @@ int build_free_nids(struct f2fs_sb_info *sbi, bool sync, bool mount)
|
||||
* from second parameter of this function.
|
||||
* The returned nid could be used ino as well as nid when inode is created.
|
||||
*/
|
||||
bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
|
||||
bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct free_nid *i = NULL;
|
||||
@ -2206,8 +2210,8 @@ retry:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We should not use stale free nids created by build_free_nids */
|
||||
if (nm_i->nid_cnt[FREE_NID] && !on_build_free_nids(nm_i)) {
|
||||
/* We should not use stale free nids created by f2fs_build_free_nids */
|
||||
if (nm_i->nid_cnt[FREE_NID] && !on_f2fs_build_free_nids(nm_i)) {
|
||||
f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list));
|
||||
i = list_first_entry(&nm_i->free_nid_list,
|
||||
struct free_nid, list);
|
||||
@ -2224,14 +2228,14 @@ retry:
|
||||
spin_unlock(&nm_i->nid_list_lock);
|
||||
|
||||
/* Let's scan nat pages and its caches to get free nids */
|
||||
build_free_nids(sbi, true, false);
|
||||
f2fs_build_free_nids(sbi, true, false);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* alloc_nid() should be called prior to this function.
|
||||
* f2fs_alloc_nid() should be called prior to this function.
|
||||
*/
|
||||
void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
void f2fs_alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct free_nid *i;
|
||||
@ -2246,9 +2250,9 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
}
|
||||
|
||||
/*
|
||||
* alloc_nid() should be called prior to this function.
|
||||
* f2fs_alloc_nid() should be called prior to this function.
|
||||
*/
|
||||
void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
void f2fs_alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct free_nid *i;
|
||||
@ -2261,7 +2265,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
i = __lookup_free_nid_list(nm_i, nid);
|
||||
f2fs_bug_on(sbi, !i);
|
||||
|
||||
if (!available_free_memory(sbi, FREE_NIDS)) {
|
||||
if (!f2fs_available_free_memory(sbi, FREE_NIDS)) {
|
||||
__remove_free_nid(sbi, i, PREALLOC_NID);
|
||||
need_free = true;
|
||||
} else {
|
||||
@ -2278,7 +2282,7 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
kmem_cache_free(free_nid_slab, i);
|
||||
}
|
||||
|
||||
int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct free_nid *i, *next;
|
||||
@ -2306,14 +2310,14 @@ int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
|
||||
return nr - nr_shrink;
|
||||
}
|
||||
|
||||
void recover_inline_xattr(struct inode *inode, struct page *page)
|
||||
void f2fs_recover_inline_xattr(struct inode *inode, struct page *page)
|
||||
{
|
||||
void *src_addr, *dst_addr;
|
||||
size_t inline_size;
|
||||
struct page *ipage;
|
||||
struct f2fs_inode *ri;
|
||||
|
||||
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
f2fs_bug_on(F2FS_I_SB(inode), IS_ERR(ipage));
|
||||
|
||||
ri = F2FS_INODE(page);
|
||||
@ -2331,11 +2335,11 @@ void recover_inline_xattr(struct inode *inode, struct page *page)
|
||||
f2fs_wait_on_page_writeback(ipage, NODE, true);
|
||||
memcpy(dst_addr, src_addr, inline_size);
|
||||
update_inode:
|
||||
update_inode(inode, ipage);
|
||||
f2fs_update_inode(inode, ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
}
|
||||
|
||||
int recover_xattr_data(struct inode *inode, struct page *page)
|
||||
int f2fs_recover_xattr_data(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid;
|
||||
@ -2349,27 +2353,27 @@ int recover_xattr_data(struct inode *inode, struct page *page)
|
||||
goto recover_xnid;
|
||||
|
||||
/* 1: invalidate the previous xattr nid */
|
||||
err = get_node_info(sbi, prev_xnid, &ni);
|
||||
err = f2fs_get_node_info(sbi, prev_xnid, &ni);
|
||||
if (err)
|
||||
return err;
|
||||
invalidate_blocks(sbi, ni.blk_addr);
|
||||
f2fs_invalidate_blocks(sbi, ni.blk_addr);
|
||||
dec_valid_node_count(sbi, inode, false);
|
||||
set_node_addr(sbi, &ni, NULL_ADDR, false);
|
||||
|
||||
recover_xnid:
|
||||
/* 2: update xattr nid in inode */
|
||||
if (!alloc_nid(sbi, &new_xnid))
|
||||
if (!f2fs_alloc_nid(sbi, &new_xnid))
|
||||
return -ENOSPC;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, new_xnid);
|
||||
xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
|
||||
xpage = f2fs_new_node_page(&dn, XATTR_NODE_OFFSET);
|
||||
if (IS_ERR(xpage)) {
|
||||
alloc_nid_failed(sbi, new_xnid);
|
||||
f2fs_alloc_nid_failed(sbi, new_xnid);
|
||||
return PTR_ERR(xpage);
|
||||
}
|
||||
|
||||
alloc_nid_done(sbi, new_xnid);
|
||||
update_inode_page(inode);
|
||||
f2fs_alloc_nid_done(sbi, new_xnid);
|
||||
f2fs_update_inode_page(inode);
|
||||
|
||||
/* 3: update and set xattr node page dirty */
|
||||
memcpy(F2FS_NODE(xpage), F2FS_NODE(page), VALID_XATTR_BLOCK_SIZE);
|
||||
@ -2380,7 +2384,7 @@ recover_xnid:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
{
|
||||
struct f2fs_inode *src, *dst;
|
||||
nid_t ino = ino_of_node(page);
|
||||
@ -2388,7 +2392,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
|
||||
struct page *ipage;
|
||||
int err;
|
||||
|
||||
err = get_node_info(sbi, ino, &old_ni);
|
||||
err = f2fs_get_node_info(sbi, ino, &old_ni);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2444,7 +2448,7 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int restore_node_summary(struct f2fs_sb_info *sbi,
|
||||
int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
|
||||
unsigned int segno, struct f2fs_summary_block *sum)
|
||||
{
|
||||
struct f2fs_node *rn;
|
||||
@ -2461,10 +2465,10 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
|
||||
nrpages = min(last_offset - i, BIO_MAX_PAGES);
|
||||
|
||||
/* readahead node pages */
|
||||
ra_meta_pages(sbi, addr, nrpages, META_POR, true);
|
||||
f2fs_ra_meta_pages(sbi, addr, nrpages, META_POR, true);
|
||||
|
||||
for (idx = addr; idx < addr + nrpages; idx++) {
|
||||
struct page *page = get_tmp_page(sbi, idx);
|
||||
struct page *page = f2fs_get_tmp_page(sbi, idx);
|
||||
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
@ -2612,7 +2616,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
|
||||
f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR);
|
||||
|
||||
if (to_journal) {
|
||||
offset = lookup_journal_in_cursum(journal,
|
||||
offset = f2fs_lookup_journal_in_cursum(journal,
|
||||
NAT_JOURNAL, nid, 1);
|
||||
f2fs_bug_on(sbi, offset < 0);
|
||||
raw_ne = &nat_in_journal(journal, offset);
|
||||
@ -2650,7 +2654,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
|
||||
/*
|
||||
* This function is called during the checkpointing process.
|
||||
*/
|
||||
int flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
@ -2721,7 +2725,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
|
||||
for (i = 0; i < nm_i->nat_bits_blocks; i++) {
|
||||
struct page *page;
|
||||
|
||||
page = get_meta_page(sbi, nat_bits_addr++);
|
||||
page = f2fs_get_meta_page(sbi, nat_bits_addr++);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
@ -2842,8 +2846,10 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi)
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
int i;
|
||||
|
||||
nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks *
|
||||
sizeof(unsigned char *), GFP_KERNEL);
|
||||
nm_i->free_nid_bitmap =
|
||||
f2fs_kzalloc(sbi, array_size(sizeof(unsigned char *),
|
||||
nm_i->nat_blocks),
|
||||
GFP_KERNEL);
|
||||
if (!nm_i->free_nid_bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2859,14 +2865,16 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi)
|
||||
if (!nm_i->nat_block_bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
nm_i->free_nid_count = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
|
||||
sizeof(unsigned short), GFP_KERNEL);
|
||||
nm_i->free_nid_count =
|
||||
f2fs_kvzalloc(sbi, array_size(sizeof(unsigned short),
|
||||
nm_i->nat_blocks),
|
||||
GFP_KERNEL);
|
||||
if (!nm_i->free_nid_count)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int build_node_manager(struct f2fs_sb_info *sbi)
|
||||
int f2fs_build_node_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -2886,10 +2894,10 @@ int build_node_manager(struct f2fs_sb_info *sbi)
|
||||
/* load free nid status from nat_bits table */
|
||||
load_free_nid_bitmap(sbi);
|
||||
|
||||
return build_free_nids(sbi, true, true);
|
||||
return f2fs_build_free_nids(sbi, true, true);
|
||||
}
|
||||
|
||||
void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_nm_info *nm_i = NM_I(sbi);
|
||||
struct free_nid *i, *next_i;
|
||||
@ -2961,7 +2969,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
|
||||
kfree(nm_i);
|
||||
}
|
||||
|
||||
int __init create_node_manager_caches(void)
|
||||
int __init f2fs_create_node_manager_caches(void)
|
||||
{
|
||||
nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
|
||||
sizeof(struct nat_entry));
|
||||
@ -2987,7 +2995,7 @@ fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void destroy_node_manager_caches(void)
|
||||
void f2fs_destroy_node_manager_caches(void)
|
||||
{
|
||||
kmem_cache_destroy(nat_entry_set_slab);
|
||||
kmem_cache_destroy(free_nid_slab);
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
static struct kmem_cache *fsync_entry_slab;
|
||||
|
||||
bool space_for_roll_forward(struct f2fs_sb_info *sbi)
|
||||
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
s64 nalloc = percpu_counter_sum_positive(&sbi->alloc_valid_block_count);
|
||||
|
||||
@ -162,7 +162,7 @@ retry:
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
err = acquire_orphan_inode(F2FS_I_SB(inode));
|
||||
err = f2fs_acquire_orphan_inode(F2FS_I_SB(inode));
|
||||
if (err) {
|
||||
iput(einode);
|
||||
goto out_put;
|
||||
@ -173,7 +173,7 @@ retry:
|
||||
} else if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
} else {
|
||||
err = __f2fs_do_add_link(dir, &fname, inode,
|
||||
err = f2fs_add_dentry(dir, &fname, inode,
|
||||
inode->i_ino, inode->i_mode);
|
||||
}
|
||||
if (err == -ENOMEM)
|
||||
@ -204,8 +204,6 @@ static void recover_inline_flags(struct inode *inode, struct f2fs_inode *ri)
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
else
|
||||
clear_inode_flag(inode, FI_DATA_EXIST);
|
||||
if (!(ri->i_inline & F2FS_INLINE_DOTS))
|
||||
clear_inode_flag(inode, FI_INLINE_DOTS);
|
||||
}
|
||||
|
||||
static void recover_inode(struct inode *inode, struct page *page)
|
||||
@ -258,7 +256,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
return 0;
|
||||
|
||||
page = get_tmp_page(sbi, blkaddr);
|
||||
page = f2fs_get_tmp_page(sbi, blkaddr);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
break;
|
||||
@ -276,7 +274,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
|
||||
if (!check_only &&
|
||||
IS_INODE(page) && is_dent_dnode(page)) {
|
||||
err = recover_inode_page(sbi, page);
|
||||
err = f2fs_recover_inode_page(sbi, page);
|
||||
if (err)
|
||||
break;
|
||||
quota_inode = true;
|
||||
@ -317,7 +315,7 @@ next:
|
||||
blkaddr = next_blkaddr_of_node(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
ra_meta_pages_cond(sbi, blkaddr);
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
}
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
@ -360,7 +358,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
}
|
||||
|
||||
sum_page = get_sum_page(sbi, segno);
|
||||
sum_page = f2fs_get_sum_page(sbi, segno);
|
||||
if (IS_ERR(sum_page))
|
||||
return PTR_ERR(sum_page);
|
||||
sum_node = (struct f2fs_summary_block *)page_address(sum_page);
|
||||
@ -382,7 +380,7 @@ got_it:
|
||||
}
|
||||
|
||||
/* Get the node page */
|
||||
node_page = get_node_page(sbi, nid);
|
||||
node_page = f2fs_get_node_page(sbi, nid);
|
||||
if (IS_ERR(node_page))
|
||||
return PTR_ERR(node_page);
|
||||
|
||||
@ -407,7 +405,8 @@ got_it:
|
||||
inode = dn->inode;
|
||||
}
|
||||
|
||||
bidx = start_bidx_of_node(offset, inode) + le16_to_cpu(sum.ofs_in_node);
|
||||
bidx = f2fs_start_bidx_of_node(offset, inode) +
|
||||
le16_to_cpu(sum.ofs_in_node);
|
||||
|
||||
/*
|
||||
* if inode page is locked, unlock temporarily, but its reference
|
||||
@ -417,11 +416,11 @@ got_it:
|
||||
unlock_page(dn->inode_page);
|
||||
|
||||
set_new_dnode(&tdn, inode, NULL, NULL, 0);
|
||||
if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE))
|
||||
if (f2fs_get_dnode_of_data(&tdn, bidx, LOOKUP_NODE))
|
||||
goto out;
|
||||
|
||||
if (tdn.data_blkaddr == blkaddr)
|
||||
truncate_data_blocks_range(&tdn, 1);
|
||||
f2fs_truncate_data_blocks_range(&tdn, 1);
|
||||
|
||||
f2fs_put_dnode(&tdn);
|
||||
out:
|
||||
@ -434,7 +433,7 @@ out:
|
||||
truncate_out:
|
||||
if (datablock_addr(tdn.inode, tdn.node_page,
|
||||
tdn.ofs_in_node) == blkaddr)
|
||||
truncate_data_blocks_range(&tdn, 1);
|
||||
f2fs_truncate_data_blocks_range(&tdn, 1);
|
||||
if (dn->inode->i_ino == nid && !dn->inode_page_locked)
|
||||
unlock_page(dn->inode_page);
|
||||
return 0;
|
||||
@ -450,25 +449,25 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
|
||||
/* step 1: recover xattr */
|
||||
if (IS_INODE(page)) {
|
||||
recover_inline_xattr(inode, page);
|
||||
f2fs_recover_inline_xattr(inode, page);
|
||||
} else if (f2fs_has_xattr_block(ofs_of_node(page))) {
|
||||
err = recover_xattr_data(inode, page);
|
||||
err = f2fs_recover_xattr_data(inode, page);
|
||||
if (!err)
|
||||
recovered++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* step 2: recover inline data */
|
||||
if (recover_inline_data(inode, page))
|
||||
if (f2fs_recover_inline_data(inode, page))
|
||||
goto out;
|
||||
|
||||
/* step 3: recover data indices */
|
||||
start = start_bidx_of_node(ofs_of_node(page), inode);
|
||||
start = f2fs_start_bidx_of_node(ofs_of_node(page), inode);
|
||||
end = start + ADDRS_PER_PAGE(page, inode);
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
retry_dn:
|
||||
err = get_dnode_of_data(&dn, start, ALLOC_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, start, ALLOC_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
@ -479,7 +478,7 @@ retry_dn:
|
||||
|
||||
f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
|
||||
|
||||
err = get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
@ -498,7 +497,7 @@ retry_dn:
|
||||
|
||||
/* dest is invalid, just invalidate src block */
|
||||
if (dest == NULL_ADDR) {
|
||||
truncate_data_blocks_range(&dn, 1);
|
||||
f2fs_truncate_data_blocks_range(&dn, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -512,8 +511,8 @@ retry_dn:
|
||||
* and then reserve one new block in dnode page.
|
||||
*/
|
||||
if (dest == NEW_ADDR) {
|
||||
truncate_data_blocks_range(&dn, 1);
|
||||
reserve_new_block(&dn);
|
||||
f2fs_truncate_data_blocks_range(&dn, 1);
|
||||
f2fs_reserve_new_block(&dn);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -521,10 +520,10 @@ retry_dn:
|
||||
if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
|
||||
|
||||
if (src == NULL_ADDR) {
|
||||
err = reserve_new_block(&dn);
|
||||
err = f2fs_reserve_new_block(&dn);
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
while (err)
|
||||
err = reserve_new_block(&dn);
|
||||
err = f2fs_reserve_new_block(&dn);
|
||||
#endif
|
||||
/* We should not get -ENOSPC */
|
||||
f2fs_bug_on(sbi, err);
|
||||
@ -582,9 +581,9 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
break;
|
||||
|
||||
ra_meta_pages_cond(sbi, blkaddr);
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
|
||||
page = get_tmp_page(sbi, blkaddr);
|
||||
page = f2fs_get_tmp_page(sbi, blkaddr);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
break;
|
||||
@ -626,11 +625,11 @@ next:
|
||||
f2fs_put_page(page, 1);
|
||||
}
|
||||
if (!err)
|
||||
allocate_new_segments(sbi);
|
||||
f2fs_allocate_new_segments(sbi);
|
||||
return err;
|
||||
}
|
||||
|
||||
int recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
{
|
||||
struct list_head inode_list;
|
||||
struct list_head dir_list;
|
||||
@ -705,7 +704,7 @@ skip:
|
||||
struct cp_control cpc = {
|
||||
.reason = CP_RECOVERY,
|
||||
};
|
||||
err = write_checkpoint(sbi, &cpc);
|
||||
err = f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
|
@ -169,7 +169,7 @@ found:
|
||||
return result - size + __reverse_ffz(tmp);
|
||||
}
|
||||
|
||||
bool need_SSR(struct f2fs_sb_info *sbi)
|
||||
bool f2fs_need_SSR(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES);
|
||||
int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS);
|
||||
@ -177,14 +177,14 @@ bool need_SSR(struct f2fs_sb_info *sbi)
|
||||
|
||||
if (test_opt(sbi, LFS))
|
||||
return false;
|
||||
if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
|
||||
if (sbi->gc_mode == GC_URGENT)
|
||||
return true;
|
||||
|
||||
return free_sections(sbi) <= (node_secs + 2 * dent_secs + imeta_secs +
|
||||
SM_I(sbi)->min_ssr_sections + reserved_sections(sbi));
|
||||
}
|
||||
|
||||
void register_inmem_page(struct inode *inode, struct page *page)
|
||||
void f2fs_register_inmem_page(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
@ -239,7 +239,8 @@ static int __revoke_inmem_pages(struct inode *inode,
|
||||
trace_f2fs_commit_inmem_page(page, INMEM_REVOKE);
|
||||
retry:
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
|
||||
err = f2fs_get_dnode_of_data(&dn, page->index,
|
||||
LOOKUP_NODE);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
@ -249,13 +250,13 @@ retry:
|
||||
err = -EAGAIN;
|
||||
goto next;
|
||||
}
|
||||
err = get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
if (err) {
|
||||
f2fs_put_dnode(&dn);
|
||||
return err;
|
||||
}
|
||||
if (cur->old_addr == NEW_ADDR) {
|
||||
invalidate_blocks(sbi, dn.data_blkaddr);
|
||||
f2fs_invalidate_blocks(sbi, dn.data_blkaddr);
|
||||
f2fs_update_data_blkaddr(&dn, NEW_ADDR);
|
||||
} else
|
||||
f2fs_replace_block(sbi, &dn, dn.data_blkaddr,
|
||||
@ -277,7 +278,7 @@ next:
|
||||
return err;
|
||||
}
|
||||
|
||||
void drop_inmem_pages_all(struct f2fs_sb_info *sbi)
|
||||
void f2fs_drop_inmem_pages_all(struct f2fs_sb_info *sbi, bool gc_failure)
|
||||
{
|
||||
struct list_head *head = &sbi->inode_list[ATOMIC_FILE];
|
||||
struct inode *inode;
|
||||
@ -293,15 +294,23 @@ next:
|
||||
spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
|
||||
|
||||
if (inode) {
|
||||
drop_inmem_pages(inode);
|
||||
if (gc_failure) {
|
||||
if (fi->i_gc_failures[GC_FAILURE_ATOMIC])
|
||||
goto drop;
|
||||
goto skip;
|
||||
}
|
||||
drop:
|
||||
set_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
iput(inode);
|
||||
}
|
||||
skip:
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
cond_resched();
|
||||
goto next;
|
||||
}
|
||||
|
||||
void drop_inmem_pages(struct inode *inode)
|
||||
void f2fs_drop_inmem_pages(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
@ -315,11 +324,11 @@ void drop_inmem_pages(struct inode *inode)
|
||||
mutex_unlock(&fi->inmem_lock);
|
||||
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
clear_inode_flag(inode, FI_HOT_DATA);
|
||||
fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0;
|
||||
stat_dec_atomic_write(inode);
|
||||
}
|
||||
|
||||
void drop_inmem_page(struct inode *inode, struct page *page)
|
||||
void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
@ -334,7 +343,7 @@ void drop_inmem_page(struct inode *inode, struct page *page)
|
||||
break;
|
||||
}
|
||||
|
||||
f2fs_bug_on(sbi, !cur || cur->page != page);
|
||||
f2fs_bug_on(sbi, list_empty(head) || cur->page != page);
|
||||
list_del(&cur->list);
|
||||
mutex_unlock(&fi->inmem_lock);
|
||||
|
||||
@ -349,8 +358,7 @@ void drop_inmem_page(struct inode *inode, struct page *page)
|
||||
trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE);
|
||||
}
|
||||
|
||||
static int __commit_inmem_pages(struct inode *inode,
|
||||
struct list_head *revoke_list)
|
||||
static int __f2fs_commit_inmem_pages(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
@ -363,9 +371,12 @@ static int __commit_inmem_pages(struct inode *inode,
|
||||
.op_flags = REQ_SYNC | REQ_PRIO,
|
||||
.io_type = FS_DATA_IO,
|
||||
};
|
||||
struct list_head revoke_list;
|
||||
pgoff_t last_idx = ULONG_MAX;
|
||||
int err = 0;
|
||||
|
||||
INIT_LIST_HEAD(&revoke_list);
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, &fi->inmem_pages, list) {
|
||||
struct page *page = cur->page;
|
||||
|
||||
@ -377,14 +388,14 @@ static int __commit_inmem_pages(struct inode *inode,
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
if (clear_page_dirty_for_io(page)) {
|
||||
inode_dec_dirty_pages(inode);
|
||||
remove_dirty_inode(inode);
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
}
|
||||
retry:
|
||||
fio.page = page;
|
||||
fio.old_blkaddr = NULL_ADDR;
|
||||
fio.encrypted_page = NULL;
|
||||
fio.need_lock = LOCK_DONE;
|
||||
err = do_write_data_page(&fio);
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
if (err) {
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
@ -399,35 +410,13 @@ retry:
|
||||
last_idx = page->index;
|
||||
}
|
||||
unlock_page(page);
|
||||
list_move_tail(&cur->list, revoke_list);
|
||||
list_move_tail(&cur->list, &revoke_list);
|
||||
}
|
||||
|
||||
if (last_idx != ULONG_MAX)
|
||||
f2fs_submit_merged_write_cond(sbi, inode, 0, last_idx, DATA);
|
||||
|
||||
if (!err)
|
||||
__revoke_inmem_pages(inode, revoke_list, false, false);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int commit_inmem_pages(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct list_head revoke_list;
|
||||
int err;
|
||||
|
||||
INIT_LIST_HEAD(&revoke_list);
|
||||
f2fs_balance_fs(sbi, true);
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
set_inode_flag(inode, FI_ATOMIC_COMMIT);
|
||||
|
||||
mutex_lock(&fi->inmem_lock);
|
||||
err = __commit_inmem_pages(inode, &revoke_list);
|
||||
if (err) {
|
||||
int ret;
|
||||
/*
|
||||
* try to revoke all committed pages, but still we could fail
|
||||
* due to no memory or other reason, if that happened, EAGAIN
|
||||
@ -436,13 +425,31 @@ int commit_inmem_pages(struct inode *inode)
|
||||
* recovery or rewrite & commit last transaction. For other
|
||||
* error number, revoking was done by filesystem itself.
|
||||
*/
|
||||
ret = __revoke_inmem_pages(inode, &revoke_list, false, true);
|
||||
if (ret)
|
||||
err = ret;
|
||||
err = __revoke_inmem_pages(inode, &revoke_list, false, true);
|
||||
|
||||
/* drop all uncommitted pages */
|
||||
__revoke_inmem_pages(inode, &fi->inmem_pages, true, false);
|
||||
} else {
|
||||
__revoke_inmem_pages(inode, &revoke_list, false, false);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int f2fs_commit_inmem_pages(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
int err;
|
||||
|
||||
f2fs_balance_fs(sbi, true);
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
set_inode_flag(inode, FI_ATOMIC_COMMIT);
|
||||
|
||||
mutex_lock(&fi->inmem_lock);
|
||||
err = __f2fs_commit_inmem_pages(inode);
|
||||
|
||||
spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
|
||||
if (!list_empty(&fi->inmem_ilist))
|
||||
list_del_init(&fi->inmem_ilist);
|
||||
@ -488,24 +495,24 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
return;
|
||||
|
||||
/* try to shrink extent cache when there is no enough memory */
|
||||
if (!available_free_memory(sbi, EXTENT_CACHE))
|
||||
if (!f2fs_available_free_memory(sbi, EXTENT_CACHE))
|
||||
f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER);
|
||||
|
||||
/* check the # of cached NAT entries */
|
||||
if (!available_free_memory(sbi, NAT_ENTRIES))
|
||||
try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);
|
||||
if (!f2fs_available_free_memory(sbi, NAT_ENTRIES))
|
||||
f2fs_try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK);
|
||||
|
||||
if (!available_free_memory(sbi, FREE_NIDS))
|
||||
try_to_free_nids(sbi, MAX_FREE_NIDS);
|
||||
if (!f2fs_available_free_memory(sbi, FREE_NIDS))
|
||||
f2fs_try_to_free_nids(sbi, MAX_FREE_NIDS);
|
||||
else
|
||||
build_free_nids(sbi, false, false);
|
||||
f2fs_build_free_nids(sbi, false, false);
|
||||
|
||||
if (!is_idle(sbi) && !excess_dirty_nats(sbi))
|
||||
return;
|
||||
|
||||
/* checkpoint is the only way to shrink partial cached entries */
|
||||
if (!available_free_memory(sbi, NAT_ENTRIES) ||
|
||||
!available_free_memory(sbi, INO_ENTRIES) ||
|
||||
if (!f2fs_available_free_memory(sbi, NAT_ENTRIES) ||
|
||||
!f2fs_available_free_memory(sbi, INO_ENTRIES) ||
|
||||
excess_prefree_segs(sbi) ||
|
||||
excess_dirty_nats(sbi) ||
|
||||
f2fs_time_over(sbi, CP_TIME)) {
|
||||
@ -513,7 +520,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
|
||||
struct blk_plug plug;
|
||||
|
||||
blk_start_plug(&plug);
|
||||
sync_dirty_inodes(sbi, FILE_INODE);
|
||||
f2fs_sync_dirty_inodes(sbi, FILE_INODE);
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
f2fs_sync_fs(sbi->sb, true);
|
||||
@ -546,7 +553,7 @@ static int submit_flush_wait(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
return __submit_flush_wait(sbi, sbi->sb->s_bdev);
|
||||
|
||||
for (i = 0; i < sbi->s_ndevs; i++) {
|
||||
if (!is_dirty_device(sbi, ino, i, FLUSH_INO))
|
||||
if (!f2fs_is_dirty_device(sbi, ino, i, FLUSH_INO))
|
||||
continue;
|
||||
ret = __submit_flush_wait(sbi, FDEV(i).bdev);
|
||||
if (ret)
|
||||
@ -657,7 +664,7 @@ int f2fs_issue_flush(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
return cmd.ret;
|
||||
}
|
||||
|
||||
int create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
struct flush_cmd_control *fcc;
|
||||
@ -694,7 +701,7 @@ init_thread:
|
||||
return err;
|
||||
}
|
||||
|
||||
void destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
|
||||
void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
|
||||
{
|
||||
struct flush_cmd_control *fcc = SM_I(sbi)->fcc_info;
|
||||
|
||||
@ -954,6 +961,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
} else if (discard_type == DPOLICY_FSTRIM) {
|
||||
dpolicy->io_aware = false;
|
||||
} else if (discard_type == DPOLICY_UMOUNT) {
|
||||
dpolicy->max_requests = UINT_MAX;
|
||||
dpolicy->io_aware = false;
|
||||
}
|
||||
}
|
||||
@ -973,6 +981,9 @@ static void __submit_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
if (dc->state != D_PREP)
|
||||
return;
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
|
||||
return;
|
||||
|
||||
trace_f2fs_issue_discard(dc->bdev, dc->start, dc->len);
|
||||
|
||||
dc->error = __blkdev_issue_discard(dc->bdev,
|
||||
@ -1016,7 +1027,7 @@ static struct discard_cmd *__insert_discard_tree(struct f2fs_sb_info *sbi,
|
||||
goto do_insert;
|
||||
}
|
||||
|
||||
p = __lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, lstart);
|
||||
p = f2fs_lookup_rb_tree_for_insert(sbi, &dcc->root, &parent, lstart);
|
||||
do_insert:
|
||||
dc = __attach_discard_cmd(sbi, bdev, lstart, start, len, parent, p);
|
||||
if (!dc)
|
||||
@ -1081,7 +1092,7 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
|
||||
|
||||
mutex_lock(&dcc->cmd_lock);
|
||||
|
||||
dc = (struct discard_cmd *)__lookup_rb_tree_ret(&dcc->root,
|
||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
||||
NULL, lstart,
|
||||
(struct rb_entry **)&prev_dc,
|
||||
(struct rb_entry **)&next_dc,
|
||||
@ -1192,7 +1203,8 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
mutex_lock(&dcc->cmd_lock);
|
||||
if (list_empty(pend_list))
|
||||
goto next;
|
||||
f2fs_bug_on(sbi, !__check_rb_tree_consistence(sbi, &dcc->root));
|
||||
f2fs_bug_on(sbi,
|
||||
!f2fs_check_rb_tree_consistence(sbi, &dcc->root));
|
||||
blk_start_plug(&plug);
|
||||
list_for_each_entry_safe(dc, tmp, pend_list, list) {
|
||||
f2fs_bug_on(sbi, dc->state != D_PREP);
|
||||
@ -1245,7 +1257,7 @@ static bool __drop_discard_cmd(struct f2fs_sb_info *sbi)
|
||||
return dropped;
|
||||
}
|
||||
|
||||
void drop_discard_cmd(struct f2fs_sb_info *sbi)
|
||||
void f2fs_drop_discard_cmd(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
__drop_discard_cmd(sbi);
|
||||
}
|
||||
@ -1336,7 +1348,8 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
bool need_wait = false;
|
||||
|
||||
mutex_lock(&dcc->cmd_lock);
|
||||
dc = (struct discard_cmd *)__lookup_rb_tree(&dcc->root, NULL, blkaddr);
|
||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree(&dcc->root,
|
||||
NULL, blkaddr);
|
||||
if (dc) {
|
||||
if (dc->state == D_PREP) {
|
||||
__punch_discard_cmd(sbi, dc, blkaddr);
|
||||
@ -1351,7 +1364,7 @@ static void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
__wait_one_discard_bio(sbi, dc);
|
||||
}
|
||||
|
||||
void stop_discard_thread(struct f2fs_sb_info *sbi)
|
||||
void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||
|
||||
@ -1401,17 +1414,22 @@ static int issue_discard_thread(void *data)
|
||||
kthread_should_stop() || freezing(current) ||
|
||||
dcc->discard_wake,
|
||||
msecs_to_jiffies(wait_ms));
|
||||
|
||||
if (dcc->discard_wake)
|
||||
dcc->discard_wake = 0;
|
||||
|
||||
if (try_to_freeze())
|
||||
continue;
|
||||
if (f2fs_readonly(sbi->sb))
|
||||
continue;
|
||||
if (kthread_should_stop())
|
||||
return 0;
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
|
||||
wait_ms = dpolicy.max_interval;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dcc->discard_wake)
|
||||
dcc->discard_wake = 0;
|
||||
|
||||
if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
|
||||
if (sbi->gc_mode == GC_URGENT)
|
||||
__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1);
|
||||
|
||||
sb_start_intwrite(sbi->sb);
|
||||
@ -1594,20 +1612,24 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
|
||||
return false;
|
||||
}
|
||||
|
||||
void release_discard_addrs(struct f2fs_sb_info *sbi)
|
||||
static void release_discard_addr(struct discard_entry *entry)
|
||||
{
|
||||
list_del(&entry->list);
|
||||
kmem_cache_free(discard_entry_slab, entry);
|
||||
}
|
||||
|
||||
void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct list_head *head = &(SM_I(sbi)->dcc_info->entry_list);
|
||||
struct discard_entry *entry, *this;
|
||||
|
||||
/* drop caches */
|
||||
list_for_each_entry_safe(entry, this, head, list) {
|
||||
list_del(&entry->list);
|
||||
kmem_cache_free(discard_entry_slab, entry);
|
||||
}
|
||||
list_for_each_entry_safe(entry, this, head, list)
|
||||
release_discard_addr(entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* Should call clear_prefree_segments after checkpoint is done.
|
||||
* Should call f2fs_clear_prefree_segments after checkpoint is done.
|
||||
*/
|
||||
static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
@ -1620,7 +1642,8 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
|
||||
mutex_unlock(&dirty_i->seglist_lock);
|
||||
}
|
||||
|
||||
void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
|
||||
struct cp_control *cpc)
|
||||
{
|
||||
struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
||||
struct list_head *head = &dcc->entry_list;
|
||||
@ -1703,9 +1726,8 @@ skip:
|
||||
if (cur_pos < sbi->blocks_per_seg)
|
||||
goto find_next;
|
||||
|
||||
list_del(&entry->list);
|
||||
release_discard_addr(entry);
|
||||
dcc->nr_discards -= total_len;
|
||||
kmem_cache_free(discard_entry_slab, entry);
|
||||
}
|
||||
|
||||
wake_up_discard_thread(sbi, false);
|
||||
@ -1763,7 +1785,7 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
if (!dcc)
|
||||
return;
|
||||
|
||||
stop_discard_thread(sbi);
|
||||
f2fs_stop_discard_thread(sbi);
|
||||
|
||||
kfree(dcc);
|
||||
SM_I(sbi)->dcc_info = NULL;
|
||||
@ -1810,8 +1832,9 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
|
||||
(new_vblocks > sbi->blocks_per_seg)));
|
||||
|
||||
se->valid_blocks = new_vblocks;
|
||||
se->mtime = get_mtime(sbi);
|
||||
SIT_I(sbi)->max_mtime = se->mtime;
|
||||
se->mtime = get_mtime(sbi, false);
|
||||
if (se->mtime > SIT_I(sbi)->max_mtime)
|
||||
SIT_I(sbi)->max_mtime = se->mtime;
|
||||
|
||||
/* Update valid block bitmap */
|
||||
if (del > 0) {
|
||||
@ -1879,7 +1902,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
|
||||
get_sec_entry(sbi, segno)->valid_blocks += del;
|
||||
}
|
||||
|
||||
void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
|
||||
void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
|
||||
{
|
||||
unsigned int segno = GET_SEGNO(sbi, addr);
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
@ -1899,7 +1922,7 @@ void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
|
||||
up_write(&sit_i->sentry_lock);
|
||||
}
|
||||
|
||||
bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
{
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
unsigned int segno, offset;
|
||||
@ -1938,7 +1961,7 @@ static void __add_sum_entry(struct f2fs_sb_info *sbi, int type,
|
||||
/*
|
||||
* Calculate the number of current summary pages for writing
|
||||
*/
|
||||
int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
|
||||
int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
|
||||
{
|
||||
int valid_sum_count = 0;
|
||||
int i, sum_in_page;
|
||||
@ -1968,14 +1991,15 @@ int npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
|
||||
/*
|
||||
* Caller should put this summary page
|
||||
*/
|
||||
struct page *get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
|
||||
struct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
|
||||
{
|
||||
return f2fs_get_meta_page_nofail(sbi, GET_SUM_BLOCK(sbi, segno));
|
||||
}
|
||||
|
||||
void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr)
|
||||
void f2fs_update_meta_page(struct f2fs_sb_info *sbi,
|
||||
void *src, block_t blk_addr)
|
||||
{
|
||||
struct page *page = grab_meta_page(sbi, blk_addr);
|
||||
struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
|
||||
|
||||
memcpy(page_address(page), src, PAGE_SIZE);
|
||||
set_page_dirty(page);
|
||||
@ -1985,18 +2009,19 @@ void update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr)
|
||||
static void write_sum_page(struct f2fs_sb_info *sbi,
|
||||
struct f2fs_summary_block *sum_blk, block_t blk_addr)
|
||||
{
|
||||
update_meta_page(sbi, (void *)sum_blk, blk_addr);
|
||||
f2fs_update_meta_page(sbi, (void *)sum_blk, blk_addr);
|
||||
}
|
||||
|
||||
static void write_current_sum_page(struct f2fs_sb_info *sbi,
|
||||
int type, block_t blk_addr)
|
||||
{
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, type);
|
||||
struct page *page = grab_meta_page(sbi, blk_addr);
|
||||
struct page *page = f2fs_grab_meta_page(sbi, blk_addr);
|
||||
struct f2fs_summary_block *src = curseg->sum_blk;
|
||||
struct f2fs_summary_block *dst;
|
||||
|
||||
dst = (struct f2fs_summary_block *)page_address(page);
|
||||
memset(dst, 0, PAGE_SIZE);
|
||||
|
||||
mutex_lock(&curseg->curseg_mutex);
|
||||
|
||||
@ -2236,7 +2261,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type)
|
||||
curseg->alloc_type = SSR;
|
||||
__next_free_blkoff(sbi, curseg, 0);
|
||||
|
||||
sum_page = get_sum_page(sbi, new_segno);
|
||||
sum_page = f2fs_get_sum_page(sbi, new_segno);
|
||||
f2fs_bug_on(sbi, IS_ERR(sum_page));
|
||||
sum_node = (struct f2fs_summary_block *)page_address(sum_page);
|
||||
memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
|
||||
@ -2251,7 +2276,7 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type)
|
||||
int i, cnt;
|
||||
bool reversed = false;
|
||||
|
||||
/* need_SSR() already forces to do this */
|
||||
/* f2fs_need_SSR() already forces to do this */
|
||||
if (v_ops->get_victim(sbi, &segno, BG_GC, type, SSR)) {
|
||||
curseg->next_segno = segno;
|
||||
return 1;
|
||||
@ -2303,7 +2328,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
|
||||
new_curseg(sbi, type, false);
|
||||
else if (curseg->alloc_type == LFS && is_next_segment_free(sbi, type))
|
||||
new_curseg(sbi, type, false);
|
||||
else if (need_SSR(sbi) && get_ssr_segment(sbi, type))
|
||||
else if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type))
|
||||
change_curseg(sbi, type);
|
||||
else
|
||||
new_curseg(sbi, type, false);
|
||||
@ -2311,7 +2336,7 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
}
|
||||
|
||||
void allocate_new_segments(struct f2fs_sb_info *sbi)
|
||||
void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct curseg_info *curseg;
|
||||
unsigned int old_segno;
|
||||
@ -2333,7 +2358,8 @@ static const struct segment_allocation default_salloc_ops = {
|
||||
.allocate_segment = allocate_segment_by_default,
|
||||
};
|
||||
|
||||
bool exist_trim_candidates(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
|
||||
struct cp_control *cpc)
|
||||
{
|
||||
__u64 trim_start = cpc->trim_start;
|
||||
bool has_candidate = false;
|
||||
@ -2366,9 +2392,9 @@ next:
|
||||
issued = 0;
|
||||
|
||||
mutex_lock(&dcc->cmd_lock);
|
||||
f2fs_bug_on(sbi, !__check_rb_tree_consistence(sbi, &dcc->root));
|
||||
f2fs_bug_on(sbi, !f2fs_check_rb_tree_consistence(sbi, &dcc->root));
|
||||
|
||||
dc = (struct discard_cmd *)__lookup_rb_tree_ret(&dcc->root,
|
||||
dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root,
|
||||
NULL, start,
|
||||
(struct rb_entry **)&prev_dc,
|
||||
(struct rb_entry **)&next_dc,
|
||||
@ -2427,12 +2453,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
|
||||
return -EINVAL;
|
||||
|
||||
if (end <= MAIN_BLKADDR(sbi))
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"Found FS corruption, run fsck to fix.");
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* start/end segment number in main_area */
|
||||
@ -2449,7 +2475,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&sbi->gc_mutex);
|
||||
err = write_checkpoint(sbi, &cpc);
|
||||
err = f2fs_write_checkpoint(sbi, &cpc);
|
||||
mutex_unlock(&sbi->gc_mutex);
|
||||
if (err)
|
||||
goto out;
|
||||
@ -2484,7 +2510,7 @@ static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
|
||||
return false;
|
||||
}
|
||||
|
||||
int rw_hint_to_seg_type(enum rw_hint hint)
|
||||
int f2fs_rw_hint_to_seg_type(enum rw_hint hint)
|
||||
{
|
||||
switch (hint) {
|
||||
case WRITE_LIFE_SHORT:
|
||||
@ -2557,7 +2583,7 @@ int rw_hint_to_seg_type(enum rw_hint hint)
|
||||
* WRITE_LIFE_LONG " WRITE_LIFE_LONG
|
||||
*/
|
||||
|
||||
enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi,
|
||||
enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
|
||||
enum page_type type, enum temp_type temp)
|
||||
{
|
||||
if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) {
|
||||
@ -2624,9 +2650,11 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
|
||||
if (is_cold_data(fio->page) || file_is_cold(inode))
|
||||
return CURSEG_COLD_DATA;
|
||||
if (file_is_hot(inode) ||
|
||||
is_inode_flag_set(inode, FI_HOT_DATA))
|
||||
is_inode_flag_set(inode, FI_HOT_DATA) ||
|
||||
is_inode_flag_set(inode, FI_ATOMIC_FILE) ||
|
||||
is_inode_flag_set(inode, FI_VOLATILE_FILE))
|
||||
return CURSEG_HOT_DATA;
|
||||
return rw_hint_to_seg_type(inode->i_write_hint);
|
||||
return f2fs_rw_hint_to_seg_type(inode->i_write_hint);
|
||||
} else {
|
||||
if (IS_DNODE(fio->page))
|
||||
return is_cold_node(fio->page) ? CURSEG_WARM_NODE :
|
||||
@ -2662,7 +2690,7 @@ static int __get_segment_type(struct f2fs_io_info *fio)
|
||||
return type;
|
||||
}
|
||||
|
||||
void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
block_t old_blkaddr, block_t *new_blkaddr,
|
||||
struct f2fs_summary *sum, int type,
|
||||
struct f2fs_io_info *fio, bool add_list)
|
||||
@ -2722,6 +2750,7 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
|
||||
INIT_LIST_HEAD(&fio->list);
|
||||
fio->in_list = true;
|
||||
fio->retry = false;
|
||||
io = sbi->write_io[fio->type] + fio->temp;
|
||||
spin_lock(&io->io_lock);
|
||||
list_add_tail(&fio->list, &io->io_list);
|
||||
@ -2744,7 +2773,7 @@ static void update_device_state(struct f2fs_io_info *fio)
|
||||
devidx = f2fs_target_device_index(sbi, fio->new_blkaddr);
|
||||
|
||||
/* update device state for fsync */
|
||||
set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
|
||||
f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
|
||||
|
||||
/* update device state for checkpoint */
|
||||
if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
|
||||
@ -2757,23 +2786,28 @@ static void update_device_state(struct f2fs_io_info *fio)
|
||||
static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
|
||||
{
|
||||
int type = __get_segment_type(fio);
|
||||
int err;
|
||||
bool keep_order = (test_opt(fio->sbi, LFS) && type == CURSEG_COLD_DATA);
|
||||
|
||||
if (keep_order)
|
||||
down_read(&fio->sbi->io_order_lock);
|
||||
reallocate:
|
||||
allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
|
||||
f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
|
||||
&fio->new_blkaddr, sum, type, fio, true);
|
||||
|
||||
/* writeout dirty page into bdev */
|
||||
err = f2fs_submit_page_write(fio);
|
||||
if (err == -EAGAIN) {
|
||||
f2fs_submit_page_write(fio);
|
||||
if (fio->retry) {
|
||||
fio->old_blkaddr = fio->new_blkaddr;
|
||||
goto reallocate;
|
||||
} else if (!err) {
|
||||
update_device_state(fio);
|
||||
}
|
||||
|
||||
update_device_state(fio);
|
||||
|
||||
if (keep_order)
|
||||
up_read(&fio->sbi->io_order_lock);
|
||||
}
|
||||
|
||||
void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
enum iostat_type io_type)
|
||||
{
|
||||
struct f2fs_io_info fio = {
|
||||
@ -2799,7 +2833,7 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page,
|
||||
f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE);
|
||||
}
|
||||
|
||||
void write_node_page(unsigned int nid, struct f2fs_io_info *fio)
|
||||
void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_summary sum;
|
||||
|
||||
@ -2809,7 +2843,8 @@ void write_node_page(unsigned int nid, struct f2fs_io_info *fio)
|
||||
f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
|
||||
}
|
||||
|
||||
void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
|
||||
void f2fs_outplace_write_data(struct dnode_of_data *dn,
|
||||
struct f2fs_io_info *fio)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
struct f2fs_summary sum;
|
||||
@ -2822,7 +2857,7 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio)
|
||||
f2fs_update_iostat(sbi, fio->io_type, F2FS_BLKSIZE);
|
||||
}
|
||||
|
||||
int rewrite_data_page(struct f2fs_io_info *fio)
|
||||
int f2fs_inplace_write_data(struct f2fs_io_info *fio)
|
||||
{
|
||||
int err;
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
@ -2857,7 +2892,7 @@ static inline int __f2fs_get_curseg(struct f2fs_sb_info *sbi,
|
||||
return i;
|
||||
}
|
||||
|
||||
void __f2fs_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
block_t old_blkaddr, block_t new_blkaddr,
|
||||
bool recover_curseg, bool recover_newaddr)
|
||||
{
|
||||
@ -2942,7 +2977,7 @@ void f2fs_replace_block(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
|
||||
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, version);
|
||||
|
||||
__f2fs_replace_block(sbi, &sum, old_addr, new_addr,
|
||||
f2fs_do_replace_block(sbi, &sum, old_addr, new_addr,
|
||||
recover_curseg, recover_newaddr);
|
||||
|
||||
f2fs_update_data_blkaddr(dn, new_addr);
|
||||
@ -2992,7 +3027,7 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
|
||||
|
||||
start = start_sum_block(sbi);
|
||||
|
||||
page = get_meta_page(sbi, start++);
|
||||
page = f2fs_get_meta_page(sbi, start++);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
kaddr = (unsigned char *)page_address(page);
|
||||
@ -3034,7 +3069,7 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi)
|
||||
f2fs_put_page(page, 1);
|
||||
page = NULL;
|
||||
|
||||
page = get_meta_page(sbi, start++);
|
||||
page = f2fs_get_meta_page(sbi, start++);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
kaddr = (unsigned char *)page_address(page);
|
||||
@ -3077,7 +3112,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
|
||||
blk_addr = GET_SUM_BLOCK(sbi, segno);
|
||||
}
|
||||
|
||||
new = get_meta_page(sbi, blk_addr);
|
||||
new = f2fs_get_meta_page(sbi, blk_addr);
|
||||
if (IS_ERR(new))
|
||||
return PTR_ERR(new);
|
||||
sum = (struct f2fs_summary_block *)page_address(new);
|
||||
@ -3091,7 +3126,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
|
||||
ns->ofs_in_node = 0;
|
||||
}
|
||||
} else {
|
||||
err = restore_node_summary(sbi, segno, sum);
|
||||
err = f2fs_restore_node_summary(sbi, segno, sum);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
@ -3126,10 +3161,10 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
|
||||
int err;
|
||||
|
||||
if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG)) {
|
||||
int npages = npages_for_summary_flush(sbi, true);
|
||||
int npages = f2fs_npages_for_summary_flush(sbi, true);
|
||||
|
||||
if (npages >= 2)
|
||||
ra_meta_pages(sbi, start_sum_block(sbi), npages,
|
||||
f2fs_ra_meta_pages(sbi, start_sum_block(sbi), npages,
|
||||
META_CP, true);
|
||||
|
||||
/* restore for compacted data summary */
|
||||
@ -3140,7 +3175,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
|
||||
if (__exist_node_summaries(sbi))
|
||||
ra_meta_pages(sbi, sum_blk_addr(sbi, NR_CURSEG_TYPE, type),
|
||||
f2fs_ra_meta_pages(sbi, sum_blk_addr(sbi, NR_CURSEG_TYPE, type),
|
||||
NR_CURSEG_TYPE - type, META_CP, true);
|
||||
|
||||
for (; type <= CURSEG_COLD_NODE; type++) {
|
||||
@ -3166,8 +3201,9 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
int written_size = 0;
|
||||
int i, j;
|
||||
|
||||
page = grab_meta_page(sbi, blkaddr++);
|
||||
page = f2fs_grab_meta_page(sbi, blkaddr++);
|
||||
kaddr = (unsigned char *)page_address(page);
|
||||
memset(kaddr, 0, PAGE_SIZE);
|
||||
|
||||
/* Step 1: write nat cache */
|
||||
seg_i = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
@ -3190,8 +3226,9 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
|
||||
for (j = 0; j < blkoff; j++) {
|
||||
if (!page) {
|
||||
page = grab_meta_page(sbi, blkaddr++);
|
||||
page = f2fs_grab_meta_page(sbi, blkaddr++);
|
||||
kaddr = (unsigned char *)page_address(page);
|
||||
memset(kaddr, 0, PAGE_SIZE);
|
||||
written_size = 0;
|
||||
}
|
||||
summary = (struct f2fs_summary *)(kaddr + written_size);
|
||||
@ -3226,7 +3263,7 @@ static void write_normal_summaries(struct f2fs_sb_info *sbi,
|
||||
write_current_sum_page(sbi, i, blkaddr + (i - type));
|
||||
}
|
||||
|
||||
void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
void f2fs_write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
{
|
||||
if (is_set_ckpt_flags(sbi, CP_COMPACT_SUM_FLAG))
|
||||
write_compacted_summaries(sbi, start_blk);
|
||||
@ -3234,12 +3271,12 @@ void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
write_normal_summaries(sbi, start_blk, CURSEG_HOT_DATA);
|
||||
}
|
||||
|
||||
void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
void f2fs_write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk)
|
||||
{
|
||||
write_normal_summaries(sbi, start_blk, CURSEG_HOT_NODE);
|
||||
}
|
||||
|
||||
int lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
|
||||
int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
|
||||
unsigned int val, int alloc)
|
||||
{
|
||||
int i;
|
||||
@ -3277,7 +3314,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
|
||||
src_off = current_sit_addr(sbi, start);
|
||||
dst_off = next_sit_addr(sbi, src_off);
|
||||
|
||||
page = grab_meta_page(sbi, dst_off);
|
||||
page = f2fs_grab_meta_page(sbi, dst_off);
|
||||
seg_info_to_sit_page(sbi, page, start);
|
||||
|
||||
set_page_dirty(page);
|
||||
@ -3373,7 +3410,7 @@ static void remove_sits_in_journal(struct f2fs_sb_info *sbi)
|
||||
* CP calls this function, which flushes SIT entries including sit_journal,
|
||||
* and moves prefree segs to free segs.
|
||||
*/
|
||||
void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
{
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
|
||||
@ -3432,6 +3469,11 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
int offset, sit_offset;
|
||||
|
||||
se = get_seg_entry(sbi, segno);
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
if (memcmp(se->cur_valid_map, se->cur_valid_map_mir,
|
||||
SIT_VBLOCK_MAP_SIZE))
|
||||
f2fs_bug_on(sbi, 1);
|
||||
#endif
|
||||
|
||||
/* add discard candidates */
|
||||
if (!(cpc->reason & CP_DISCARD)) {
|
||||
@ -3440,17 +3482,21 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
}
|
||||
|
||||
if (to_journal) {
|
||||
offset = lookup_journal_in_cursum(journal,
|
||||
offset = f2fs_lookup_journal_in_cursum(journal,
|
||||
SIT_JOURNAL, segno, 1);
|
||||
f2fs_bug_on(sbi, offset < 0);
|
||||
segno_in_journal(journal, offset) =
|
||||
cpu_to_le32(segno);
|
||||
seg_info_to_raw_sit(se,
|
||||
&sit_in_journal(journal, offset));
|
||||
check_block_count(sbi, segno,
|
||||
&sit_in_journal(journal, offset));
|
||||
} else {
|
||||
sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
|
||||
seg_info_to_raw_sit(se,
|
||||
&raw_sit->entries[sit_offset]);
|
||||
check_block_count(sbi, segno,
|
||||
&raw_sit->entries[sit_offset]);
|
||||
}
|
||||
|
||||
__clear_bit(segno, bitmap);
|
||||
@ -3498,8 +3544,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
|
||||
|
||||
SM_I(sbi)->sit_info = sit_i;
|
||||
|
||||
sit_i->sentries = f2fs_kvzalloc(sbi, MAIN_SEGS(sbi) *
|
||||
sizeof(struct seg_entry), GFP_KERNEL);
|
||||
sit_i->sentries =
|
||||
f2fs_kvzalloc(sbi, array_size(sizeof(struct seg_entry),
|
||||
MAIN_SEGS(sbi)),
|
||||
GFP_KERNEL);
|
||||
if (!sit_i->sentries)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -3539,8 +3587,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
|
||||
return -ENOMEM;
|
||||
|
||||
if (sbi->segs_per_sec > 1) {
|
||||
sit_i->sec_entries = f2fs_kvzalloc(sbi, MAIN_SECS(sbi) *
|
||||
sizeof(struct sec_entry), GFP_KERNEL);
|
||||
sit_i->sec_entries =
|
||||
f2fs_kvzalloc(sbi, array_size(sizeof(struct sec_entry),
|
||||
MAIN_SECS(sbi)),
|
||||
GFP_KERNEL);
|
||||
if (!sit_i->sec_entries)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -3616,7 +3666,8 @@ static int build_curseg(struct f2fs_sb_info *sbi)
|
||||
struct curseg_info *array;
|
||||
int i;
|
||||
|
||||
array = f2fs_kzalloc(sbi, sizeof(*array) * NR_CURSEG_TYPE, GFP_KERNEL);
|
||||
array = f2fs_kzalloc(sbi, array_size(NR_CURSEG_TYPE, sizeof(*array)),
|
||||
GFP_KERNEL);
|
||||
if (!array)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -3652,7 +3703,7 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
|
||||
block_t total_node_blocks = 0;
|
||||
|
||||
do {
|
||||
readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
|
||||
readed = f2fs_ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
|
||||
META_SIT, true);
|
||||
|
||||
start = start_blk * sit_i->sents_per_block;
|
||||
@ -3734,14 +3785,17 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
|
||||
} else {
|
||||
memcpy(se->discard_map, se->cur_valid_map,
|
||||
SIT_VBLOCK_MAP_SIZE);
|
||||
sbi->discard_blks += old_valid_blocks -
|
||||
se->valid_blocks;
|
||||
sbi->discard_blks += old_valid_blocks;
|
||||
sbi->discard_blks -= se->valid_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
if (sbi->segs_per_sec > 1)
|
||||
if (sbi->segs_per_sec > 1) {
|
||||
get_sec_entry(sbi, start)->valid_blocks +=
|
||||
se->valid_blocks - old_valid_blocks;
|
||||
se->valid_blocks;
|
||||
get_sec_entry(sbi, start)->valid_blocks -=
|
||||
old_valid_blocks;
|
||||
}
|
||||
}
|
||||
up_read(&curseg->journal_rwsem);
|
||||
|
||||
@ -3851,7 +3905,7 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi)
|
||||
|
||||
down_write(&sit_i->sentry_lock);
|
||||
|
||||
sit_i->min_mtime = LLONG_MAX;
|
||||
sit_i->min_mtime = ULLONG_MAX;
|
||||
|
||||
for (segno = 0; segno < MAIN_SEGS(sbi); segno += sbi->segs_per_sec) {
|
||||
unsigned int i;
|
||||
@ -3865,11 +3919,11 @@ static void init_min_max_mtime(struct f2fs_sb_info *sbi)
|
||||
if (sit_i->min_mtime > mtime)
|
||||
sit_i->min_mtime = mtime;
|
||||
}
|
||||
sit_i->max_mtime = get_mtime(sbi);
|
||||
sit_i->max_mtime = get_mtime(sbi, false);
|
||||
up_write(&sit_i->sentry_lock);
|
||||
}
|
||||
|
||||
int build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
||||
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
|
||||
@ -3907,7 +3961,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
init_rwsem(&sm_info->curseg_lock);
|
||||
|
||||
if (!f2fs_readonly(sbi->sb)) {
|
||||
err = create_flush_cmd_control(sbi);
|
||||
err = f2fs_create_flush_cmd_control(sbi);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -4032,13 +4086,13 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
|
||||
kfree(sit_i);
|
||||
}
|
||||
|
||||
void destroy_segment_manager(struct f2fs_sb_info *sbi)
|
||||
void f2fs_destroy_segment_manager(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_sm_info *sm_info = SM_I(sbi);
|
||||
|
||||
if (!sm_info)
|
||||
return;
|
||||
destroy_flush_cmd_control(sbi, true);
|
||||
f2fs_destroy_flush_cmd_control(sbi, true);
|
||||
destroy_discard_cmd_control(sbi);
|
||||
destroy_dirty_segmap(sbi);
|
||||
destroy_curseg(sbi);
|
||||
@ -4048,7 +4102,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi)
|
||||
kfree(sm_info);
|
||||
}
|
||||
|
||||
int __init create_segment_manager_caches(void)
|
||||
int __init f2fs_create_segment_manager_caches(void)
|
||||
{
|
||||
discard_entry_slab = f2fs_kmem_cache_create("discard_entry",
|
||||
sizeof(struct discard_entry));
|
||||
@ -4081,7 +4135,7 @@ fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void destroy_segment_manager_caches(void)
|
||||
void f2fs_destroy_segment_manager_caches(void)
|
||||
{
|
||||
kmem_cache_destroy(sit_entry_set_slab);
|
||||
kmem_cache_destroy(discard_cmd_slab);
|
||||
|
@ -215,6 +215,8 @@ struct segment_allocation {
|
||||
#define IS_DUMMY_WRITTEN_PAGE(page) \
|
||||
(page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE)
|
||||
|
||||
#define MAX_SKIP_ATOMIC_COUNT 16
|
||||
|
||||
struct inmem_pages {
|
||||
struct list_head list;
|
||||
struct page *page;
|
||||
@ -375,6 +377,7 @@ static inline void seg_info_to_sit_page(struct f2fs_sb_info *sbi,
|
||||
int i;
|
||||
|
||||
raw_sit = (struct f2fs_sit_block *)page_address(page);
|
||||
memset(raw_sit, 0, PAGE_SIZE);
|
||||
for (i = 0; i < end - start; i++) {
|
||||
rs = &raw_sit->entries[i];
|
||||
se = get_seg_entry(sbi, start + i);
|
||||
@ -742,12 +745,23 @@ static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi)
|
||||
static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi,
|
||||
bool base_time)
|
||||
{
|
||||
struct sit_info *sit_i = SIT_I(sbi);
|
||||
time64_t now = ktime_get_real_seconds();
|
||||
time64_t diff, now = ktime_get_real_seconds();
|
||||
|
||||
return sit_i->elapsed_time + now - sit_i->mounted_time;
|
||||
if (now >= sit_i->mounted_time)
|
||||
return sit_i->elapsed_time + now - sit_i->mounted_time;
|
||||
|
||||
/* system time is set to the past */
|
||||
if (!base_time) {
|
||||
diff = sit_i->mounted_time - now;
|
||||
if (sit_i->elapsed_time >= diff)
|
||||
return sit_i->elapsed_time - diff;
|
||||
return 0;
|
||||
}
|
||||
return sit_i->elapsed_time;
|
||||
}
|
||||
|
||||
static inline void set_summary(struct f2fs_summary *sum, nid_t nid,
|
||||
@ -771,15 +785,6 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
|
||||
- (base + 1) + type;
|
||||
}
|
||||
|
||||
static inline bool no_fggc_candidate(struct f2fs_sb_info *sbi,
|
||||
unsigned int secno)
|
||||
{
|
||||
if (get_valid_blocks(sbi, GET_SEG_FROM_SEC(sbi, secno), true) >
|
||||
sbi->fggc_threshold)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
|
||||
{
|
||||
if (IS_CURSEC(sbi, secno) || (sbi->cur_victim_sec == secno))
|
||||
|
@ -109,11 +109,11 @@ unsigned long f2fs_shrink_scan(struct shrinker *shrink,
|
||||
|
||||
/* shrink clean nat cache entries */
|
||||
if (freed < nr)
|
||||
freed += try_to_free_nats(sbi, nr - freed);
|
||||
freed += f2fs_try_to_free_nats(sbi, nr - freed);
|
||||
|
||||
/* shrink free nids cache entries */
|
||||
if (freed < nr)
|
||||
freed += try_to_free_nids(sbi, nr - freed);
|
||||
freed += f2fs_try_to_free_nids(sbi, nr - freed);
|
||||
|
||||
spin_lock(&f2fs_list_lock);
|
||||
p = p->next;
|
||||
|
149
fs/f2fs/super.c
149
fs/f2fs/super.c
@ -830,15 +830,14 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
|
||||
|
||||
/* Initialize f2fs-specific inode info */
|
||||
atomic_set(&fi->dirty_pages, 0);
|
||||
fi->i_current_depth = 1;
|
||||
init_rwsem(&fi->i_sem);
|
||||
INIT_LIST_HEAD(&fi->dirty_list);
|
||||
INIT_LIST_HEAD(&fi->gdirty_list);
|
||||
INIT_LIST_HEAD(&fi->inmem_ilist);
|
||||
INIT_LIST_HEAD(&fi->inmem_pages);
|
||||
mutex_init(&fi->inmem_lock);
|
||||
init_rwsem(&fi->dio_rwsem[READ]);
|
||||
init_rwsem(&fi->dio_rwsem[WRITE]);
|
||||
init_rwsem(&fi->i_gc_rwsem[READ]);
|
||||
init_rwsem(&fi->i_gc_rwsem[WRITE]);
|
||||
init_rwsem(&fi->i_mmap_sem);
|
||||
init_rwsem(&fi->i_xattr_sem);
|
||||
|
||||
@ -866,7 +865,7 @@ static int f2fs_drop_inode(struct inode *inode)
|
||||
|
||||
/* some remained atomic pages should discarded */
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
drop_inmem_pages(inode);
|
||||
f2fs_drop_inmem_pages(inode);
|
||||
|
||||
/* should remain fi->extent_tree for writepage */
|
||||
f2fs_destroy_extent_node(inode);
|
||||
@ -995,7 +994,7 @@ static void f2fs_umount_end(struct super_block *sb, int flags)
|
||||
struct cp_control cpc = {
|
||||
.reason = CP_UMOUNT,
|
||||
};
|
||||
write_checkpoint(F2FS_SB(sb), &cpc);
|
||||
f2fs_write_checkpoint(F2FS_SB(sb), &cpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1021,7 +1020,7 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
struct cp_control cpc = {
|
||||
.reason = CP_UMOUNT,
|
||||
};
|
||||
write_checkpoint(sbi, &cpc);
|
||||
f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
|
||||
/* be sure to wait for any on-going discard commands */
|
||||
@ -1031,14 +1030,14 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
struct cp_control cpc = {
|
||||
.reason = CP_UMOUNT | CP_TRIMMED,
|
||||
};
|
||||
write_checkpoint(sbi, &cpc);
|
||||
f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
|
||||
/*
|
||||
* normally superblock is clean, so we need to release this.
|
||||
* In addition, EIO will skip do checkpoint, we need this as well.
|
||||
*/
|
||||
release_ino_entry(sbi, true);
|
||||
f2fs_release_ino_entry(sbi, true);
|
||||
|
||||
f2fs_leave_shrinker(sbi);
|
||||
mutex_unlock(&sbi->umount_mutex);
|
||||
@ -1056,8 +1055,8 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
f2fs_destroy_stats(sbi);
|
||||
|
||||
/* destroy f2fs internal modules */
|
||||
destroy_node_manager(sbi);
|
||||
destroy_segment_manager(sbi);
|
||||
f2fs_destroy_node_manager(sbi);
|
||||
f2fs_destroy_segment_manager(sbi);
|
||||
|
||||
kfree(sbi->ckpt);
|
||||
|
||||
@ -1099,7 +1098,7 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
|
||||
cpc.reason = __get_cp_reason(sbi);
|
||||
|
||||
mutex_lock(&sbi->gc_mutex);
|
||||
err = write_checkpoint(sbi, &cpc);
|
||||
err = f2fs_write_checkpoint(sbi, &cpc);
|
||||
mutex_unlock(&sbi->gc_mutex);
|
||||
}
|
||||
f2fs_trace_ios(NULL, 1);
|
||||
@ -1504,11 +1503,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
|
||||
*/
|
||||
if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) {
|
||||
if (sbi->gc_thread) {
|
||||
stop_gc_thread(sbi);
|
||||
f2fs_stop_gc_thread(sbi);
|
||||
need_restart_gc = true;
|
||||
}
|
||||
} else if (!sbi->gc_thread) {
|
||||
err = start_gc_thread(sbi);
|
||||
err = f2fs_start_gc_thread(sbi);
|
||||
if (err)
|
||||
goto restore_opts;
|
||||
need_stop_gc = true;
|
||||
@ -1531,9 +1530,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
|
||||
*/
|
||||
if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
|
||||
clear_opt(sbi, FLUSH_MERGE);
|
||||
destroy_flush_cmd_control(sbi, false);
|
||||
f2fs_destroy_flush_cmd_control(sbi, false);
|
||||
} else {
|
||||
err = create_flush_cmd_control(sbi);
|
||||
err = f2fs_create_flush_cmd_control(sbi);
|
||||
if (err)
|
||||
goto restore_gc;
|
||||
}
|
||||
@ -1551,11 +1550,11 @@ skip:
|
||||
return 0;
|
||||
restore_gc:
|
||||
if (need_restart_gc) {
|
||||
if (start_gc_thread(sbi))
|
||||
if (f2fs_start_gc_thread(sbi))
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"background gc thread has stopped");
|
||||
} else if (need_stop_gc) {
|
||||
stop_gc_thread(sbi);
|
||||
f2fs_stop_gc_thread(sbi);
|
||||
}
|
||||
restore_opts:
|
||||
#ifdef CONFIG_QUOTA
|
||||
@ -1827,7 +1826,7 @@ static int f2fs_quota_on(struct super_block *sb, int type, int format_id,
|
||||
inode = d_inode(path->dentry);
|
||||
|
||||
inode_lock(inode);
|
||||
F2FS_I(inode)->i_flags |= FS_NOATIME_FL | FS_IMMUTABLE_FL;
|
||||
F2FS_I(inode)->i_flags |= F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL;
|
||||
inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
|
||||
S_NOATIME | S_IMMUTABLE);
|
||||
inode_unlock(inode);
|
||||
@ -1853,7 +1852,7 @@ static int f2fs_quota_off(struct super_block *sb, int type)
|
||||
goto out_put;
|
||||
|
||||
inode_lock(inode);
|
||||
F2FS_I(inode)->i_flags &= ~(FS_NOATIME_FL | FS_IMMUTABLE_FL);
|
||||
F2FS_I(inode)->i_flags &= ~(F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL);
|
||||
inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
|
||||
inode_unlock(inode);
|
||||
f2fs_mark_inode_dirty_sync(inode, false);
|
||||
@ -1971,25 +1970,13 @@ static bool f2fs_dummy_context(struct inode *inode)
|
||||
return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode));
|
||||
}
|
||||
|
||||
static unsigned f2fs_max_namelen(struct inode *inode)
|
||||
{
|
||||
return S_ISLNK(inode->i_mode) ?
|
||||
inode->i_sb->s_blocksize : F2FS_NAME_LEN;
|
||||
}
|
||||
|
||||
static inline bool f2fs_is_encrypted(struct inode *inode)
|
||||
{
|
||||
return f2fs_encrypted_file(inode);
|
||||
}
|
||||
|
||||
static const struct fscrypt_operations f2fs_cryptops = {
|
||||
.key_prefix = "f2fs:",
|
||||
.get_context = f2fs_get_context,
|
||||
.set_context = f2fs_set_context,
|
||||
.dummy_context = f2fs_dummy_context,
|
||||
.empty_dir = f2fs_empty_dir,
|
||||
.max_namelen = f2fs_max_namelen,
|
||||
.is_encrypted = f2fs_is_encrypted,
|
||||
.max_namelen = F2FS_NAME_LEN,
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -1999,7 +1986,7 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct inode *inode;
|
||||
|
||||
if (check_nid_range(sbi, ino))
|
||||
if (f2fs_check_nid_range(sbi, ino))
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
/*
|
||||
@ -2285,10 +2272,14 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
secs_per_zone, total_sections);
|
||||
return 1;
|
||||
}
|
||||
if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION) {
|
||||
if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION ||
|
||||
raw_super->hot_ext_count > F2FS_MAX_EXTENSION ||
|
||||
(le32_to_cpu(raw_super->extension_count) +
|
||||
raw_super->hot_ext_count) > F2FS_MAX_EXTENSION) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Corrupted extension count (%u > %u)",
|
||||
"Corrupted extension count (%u + %u > %u)",
|
||||
le32_to_cpu(raw_super->extension_count),
|
||||
raw_super->hot_ext_count,
|
||||
F2FS_MAX_EXTENSION);
|
||||
return 1;
|
||||
}
|
||||
@ -2321,7 +2312,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned int total, fsmeta;
|
||||
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
|
||||
@ -2442,13 +2433,15 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
|
||||
for (i = 0; i < NR_COUNT_TYPE; i++)
|
||||
atomic_set(&sbi->nr_pages[i], 0);
|
||||
|
||||
atomic_set(&sbi->wb_sync_req, 0);
|
||||
for (i = 0; i < META; i++)
|
||||
atomic_set(&sbi->wb_sync_req[i], 0);
|
||||
|
||||
INIT_LIST_HEAD(&sbi->s_list);
|
||||
mutex_init(&sbi->umount_mutex);
|
||||
for (i = 0; i < NR_PAGE_TYPE - 1; i++)
|
||||
for (j = HOT; j < NR_TEMP_TYPE; j++)
|
||||
mutex_init(&sbi->wio_mutex[i][j]);
|
||||
init_rwsem(&sbi->io_order_lock);
|
||||
spin_lock_init(&sbi->cp_lock);
|
||||
|
||||
sbi->dirty_device = 0;
|
||||
@ -2503,8 +2496,10 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
|
||||
|
||||
#define F2FS_REPORT_NR_ZONES 4096
|
||||
|
||||
zones = f2fs_kzalloc(sbi, sizeof(struct blk_zone) *
|
||||
F2FS_REPORT_NR_ZONES, GFP_KERNEL);
|
||||
zones = f2fs_kzalloc(sbi,
|
||||
array_size(F2FS_REPORT_NR_ZONES,
|
||||
sizeof(struct blk_zone)),
|
||||
GFP_KERNEL);
|
||||
if (!zones)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2644,8 +2639,10 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
|
||||
* Initialize multiple devices information, or single
|
||||
* zoned block device information.
|
||||
*/
|
||||
sbi->devs = f2fs_kzalloc(sbi, sizeof(struct f2fs_dev_info) *
|
||||
max_devices, GFP_KERNEL);
|
||||
sbi->devs = f2fs_kzalloc(sbi,
|
||||
array_size(max_devices,
|
||||
sizeof(struct f2fs_dev_info)),
|
||||
GFP_KERNEL);
|
||||
if (!sbi->devs)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -2878,9 +2875,11 @@ try_onemore:
|
||||
int n = (i == META) ? 1: NR_TEMP_TYPE;
|
||||
int j;
|
||||
|
||||
sbi->write_io[i] = f2fs_kmalloc(sbi,
|
||||
n * sizeof(struct f2fs_bio_info),
|
||||
GFP_KERNEL);
|
||||
sbi->write_io[i] =
|
||||
f2fs_kmalloc(sbi,
|
||||
array_size(n,
|
||||
sizeof(struct f2fs_bio_info)),
|
||||
GFP_KERNEL);
|
||||
if (!sbi->write_io[i]) {
|
||||
err = -ENOMEM;
|
||||
goto free_options;
|
||||
@ -2920,7 +2919,7 @@ try_onemore:
|
||||
goto free_io_dummy;
|
||||
}
|
||||
|
||||
err = get_valid_checkpoint(sbi);
|
||||
err = f2fs_get_valid_checkpoint(sbi);
|
||||
if (err) {
|
||||
f2fs_msg(sb, KERN_ERR, "Failed to get valid F2FS checkpoint");
|
||||
goto free_meta_inode;
|
||||
@ -2950,18 +2949,18 @@ try_onemore:
|
||||
spin_lock_init(&sbi->inode_lock[i]);
|
||||
}
|
||||
|
||||
init_extent_cache_info(sbi);
|
||||
f2fs_init_extent_cache_info(sbi);
|
||||
|
||||
init_ino_entry_info(sbi);
|
||||
f2fs_init_ino_entry_info(sbi);
|
||||
|
||||
/* setup f2fs internal modules */
|
||||
err = build_segment_manager(sbi);
|
||||
err = f2fs_build_segment_manager(sbi);
|
||||
if (err) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"Failed to initialize F2FS segment manager");
|
||||
goto free_sm;
|
||||
}
|
||||
err = build_node_manager(sbi);
|
||||
err = f2fs_build_node_manager(sbi);
|
||||
if (err) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"Failed to initialize F2FS node manager");
|
||||
@ -2979,7 +2978,7 @@ try_onemore:
|
||||
sbi->kbytes_written =
|
||||
le64_to_cpu(seg_i->journal->info.kbytes_written);
|
||||
|
||||
build_gc_manager(sbi);
|
||||
f2fs_build_gc_manager(sbi);
|
||||
|
||||
err = f2fs_build_stats(sbi);
|
||||
if (err)
|
||||
@ -3031,7 +3030,7 @@ try_onemore:
|
||||
}
|
||||
#endif
|
||||
/* if there are nt orphan nodes free them */
|
||||
err = recover_orphan_inodes(sbi);
|
||||
err = f2fs_recover_orphan_inodes(sbi);
|
||||
if (err)
|
||||
goto free_meta;
|
||||
|
||||
@ -3053,7 +3052,7 @@ try_onemore:
|
||||
if (!retry)
|
||||
goto skip_recovery;
|
||||
|
||||
err = recover_fsync_data(sbi, false);
|
||||
err = f2fs_recover_fsync_data(sbi, false);
|
||||
if (err < 0) {
|
||||
need_fsck = true;
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
@ -3061,7 +3060,7 @@ try_onemore:
|
||||
goto free_meta;
|
||||
}
|
||||
} else {
|
||||
err = recover_fsync_data(sbi, true);
|
||||
err = f2fs_recover_fsync_data(sbi, true);
|
||||
|
||||
if (!f2fs_readonly(sb) && err > 0) {
|
||||
err = -EINVAL;
|
||||
@ -3071,7 +3070,7 @@ try_onemore:
|
||||
}
|
||||
}
|
||||
skip_recovery:
|
||||
/* recover_fsync_data() cleared this already */
|
||||
/* f2fs_recover_fsync_data() cleared this already */
|
||||
clear_sbi_flag(sbi, SBI_POR_DOING);
|
||||
|
||||
/*
|
||||
@ -3080,7 +3079,7 @@ skip_recovery:
|
||||
*/
|
||||
if (test_opt(sbi, BG_GC) && !f2fs_readonly(sb)) {
|
||||
/* After POR, we can run background GC thread.*/
|
||||
err = start_gc_thread(sbi);
|
||||
err = f2fs_start_gc_thread(sbi);
|
||||
if (err)
|
||||
goto free_meta;
|
||||
}
|
||||
@ -3111,10 +3110,10 @@ free_meta:
|
||||
#endif
|
||||
f2fs_sync_inode_meta(sbi);
|
||||
/*
|
||||
* Some dirty meta pages can be produced by recover_orphan_inodes()
|
||||
* Some dirty meta pages can be produced by f2fs_recover_orphan_inodes()
|
||||
* failed by EIO. Then, iput(node_inode) can trigger balance_fs_bg()
|
||||
* followed by write_checkpoint() through f2fs_write_node_pages(), which
|
||||
* falls into an infinite loop in sync_meta_pages().
|
||||
* followed by f2fs_write_checkpoint() through f2fs_write_node_pages(), which
|
||||
* falls into an infinite loop in f2fs_sync_meta_pages().
|
||||
*/
|
||||
truncate_inode_pages_final(META_MAPPING(sbi));
|
||||
/* cleanup recovery and quota inodes */
|
||||
@ -3127,15 +3126,15 @@ free_root_inode:
|
||||
dput(sb->s_root);
|
||||
sb->s_root = NULL;
|
||||
free_node_inode:
|
||||
release_ino_entry(sbi, true);
|
||||
f2fs_release_ino_entry(sbi, true);
|
||||
truncate_inode_pages_final(NODE_MAPPING(sbi));
|
||||
iput(sbi->node_inode);
|
||||
free_stats:
|
||||
f2fs_destroy_stats(sbi);
|
||||
free_nm:
|
||||
destroy_node_manager(sbi);
|
||||
f2fs_destroy_node_manager(sbi);
|
||||
free_sm:
|
||||
destroy_segment_manager(sbi);
|
||||
f2fs_destroy_segment_manager(sbi);
|
||||
free_devices:
|
||||
destroy_device_list(sbi);
|
||||
kfree(sbi->ckpt);
|
||||
@ -3180,8 +3179,8 @@ static void kill_f2fs_super(struct super_block *sb)
|
||||
{
|
||||
if (sb->s_root) {
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE);
|
||||
stop_gc_thread(F2FS_SB(sb));
|
||||
stop_discard_thread(F2FS_SB(sb));
|
||||
f2fs_stop_gc_thread(F2FS_SB(sb));
|
||||
f2fs_stop_discard_thread(F2FS_SB(sb));
|
||||
}
|
||||
kill_block_super(sb);
|
||||
}
|
||||
@ -3230,16 +3229,16 @@ static int __init init_f2fs_fs(void)
|
||||
err = init_inodecache();
|
||||
if (err)
|
||||
goto fail;
|
||||
err = create_node_manager_caches();
|
||||
err = f2fs_create_node_manager_caches();
|
||||
if (err)
|
||||
goto free_inodecache;
|
||||
err = create_segment_manager_caches();
|
||||
err = f2fs_create_segment_manager_caches();
|
||||
if (err)
|
||||
goto free_node_manager_caches;
|
||||
err = create_checkpoint_caches();
|
||||
err = f2fs_create_checkpoint_caches();
|
||||
if (err)
|
||||
goto free_segment_manager_caches;
|
||||
err = create_extent_cache();
|
||||
err = f2fs_create_extent_cache();
|
||||
if (err)
|
||||
goto free_checkpoint_caches;
|
||||
err = f2fs_init_sysfs();
|
||||
@ -3268,13 +3267,13 @@ free_shrinker:
|
||||
free_sysfs:
|
||||
f2fs_exit_sysfs();
|
||||
free_extent_cache:
|
||||
destroy_extent_cache();
|
||||
f2fs_destroy_extent_cache();
|
||||
free_checkpoint_caches:
|
||||
destroy_checkpoint_caches();
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
free_segment_manager_caches:
|
||||
destroy_segment_manager_caches();
|
||||
f2fs_destroy_segment_manager_caches();
|
||||
free_node_manager_caches:
|
||||
destroy_node_manager_caches();
|
||||
f2fs_destroy_node_manager_caches();
|
||||
free_inodecache:
|
||||
destroy_inodecache();
|
||||
fail:
|
||||
@ -3288,10 +3287,10 @@ static void __exit exit_f2fs_fs(void)
|
||||
unregister_filesystem(&f2fs_fs_type);
|
||||
unregister_shrinker(&f2fs_shrinker_info);
|
||||
f2fs_exit_sysfs();
|
||||
destroy_extent_cache();
|
||||
destroy_checkpoint_caches();
|
||||
destroy_segment_manager_caches();
|
||||
destroy_node_manager_caches();
|
||||
f2fs_destroy_extent_cache();
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
f2fs_destroy_segment_manager_caches();
|
||||
f2fs_destroy_node_manager_caches();
|
||||
destroy_inodecache();
|
||||
f2fs_destroy_trace_ios();
|
||||
}
|
||||
|
@ -148,13 +148,13 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
int len = 0, i;
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"cold file extenstion:\n");
|
||||
"cold file extension:\n");
|
||||
for (i = 0; i < cold_count; i++)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
extlist[i]);
|
||||
|
||||
len += snprintf(buf + len, PAGE_SIZE - len,
|
||||
"hot file extenstion:\n");
|
||||
"hot file extension:\n");
|
||||
for (i = cold_count; i < cold_count + hot_count; i++)
|
||||
len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
|
||||
extlist[i]);
|
||||
@ -166,7 +166,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
|
||||
}
|
||||
|
||||
static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||
static ssize_t __sbi_store(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
@ -202,13 +202,13 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||
|
||||
down_write(&sbi->sb_lock);
|
||||
|
||||
ret = update_extension_list(sbi, name, hot, set);
|
||||
ret = f2fs_update_extension_list(sbi, name, hot, set);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = f2fs_commit_super(sbi, false);
|
||||
if (ret)
|
||||
update_extension_list(sbi, name, hot, !set);
|
||||
f2fs_update_extension_list(sbi, name, hot, !set);
|
||||
out:
|
||||
up_write(&sbi->sb_lock);
|
||||
return ret ? ret : count;
|
||||
@ -249,19 +249,53 @@ out:
|
||||
if (!strcmp(a->attr.name, "trim_sections"))
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcmp(a->attr.name, "gc_urgent")) {
|
||||
if (t >= 1) {
|
||||
sbi->gc_mode = GC_URGENT;
|
||||
if (sbi->gc_thread) {
|
||||
wake_up_interruptible_all(
|
||||
&sbi->gc_thread->gc_wait_queue_head);
|
||||
wake_up_discard_thread(sbi, true);
|
||||
}
|
||||
} else {
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
if (!strcmp(a->attr.name, "gc_idle")) {
|
||||
if (t == GC_IDLE_CB)
|
||||
sbi->gc_mode = GC_IDLE_CB;
|
||||
else if (t == GC_IDLE_GREEDY)
|
||||
sbi->gc_mode = GC_IDLE_GREEDY;
|
||||
else
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
return count;
|
||||
}
|
||||
|
||||
*ui = t;
|
||||
|
||||
if (!strcmp(a->attr.name, "iostat_enable") && *ui == 0)
|
||||
f2fs_reset_iostat(sbi);
|
||||
if (!strcmp(a->attr.name, "gc_urgent") && t == 1 && sbi->gc_thread) {
|
||||
sbi->gc_thread->gc_wake = 1;
|
||||
wake_up_interruptible_all(&sbi->gc_thread->gc_wait_queue_head);
|
||||
wake_up_discard_thread(sbi, true);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||
struct f2fs_sb_info *sbi,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
ssize_t ret;
|
||||
bool gc_entry = (!strcmp(a->attr.name, "gc_urgent") ||
|
||||
a->struct_type == GC_THREAD);
|
||||
|
||||
if (gc_entry)
|
||||
down_read(&sbi->sb->s_umount);
|
||||
ret = __sbi_store(a, sbi, buf, count);
|
||||
if (gc_entry)
|
||||
up_read(&sbi->sb->s_umount);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t f2fs_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf)
|
||||
{
|
||||
@ -350,8 +384,8 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent_sleep_time,
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_min_sleep_time, min_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
|
||||
F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_urgent, gc_urgent);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_idle, gc_mode);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_urgent, gc_mode);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
|
||||
F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity);
|
||||
|
@ -252,7 +252,7 @@ static int read_inline_xattr(struct inode *inode, struct page *ipage,
|
||||
if (ipage) {
|
||||
inline_addr = inline_xattr_addr(inode, ipage);
|
||||
} else {
|
||||
page = get_node_page(sbi, inode->i_ino);
|
||||
page = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(page))
|
||||
return PTR_ERR(page);
|
||||
|
||||
@ -273,7 +273,7 @@ static int read_xattr_block(struct inode *inode, void *txattr_addr)
|
||||
void *xattr_addr;
|
||||
|
||||
/* The inode already has an extended attribute block. */
|
||||
xpage = get_node_page(sbi, xnid);
|
||||
xpage = f2fs_get_node_page(sbi, xnid);
|
||||
if (IS_ERR(xpage))
|
||||
return PTR_ERR(xpage);
|
||||
|
||||
@ -397,7 +397,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
int err = 0;
|
||||
|
||||
if (hsize > inline_size && !F2FS_I(inode)->i_xattr_nid)
|
||||
if (!alloc_nid(sbi, &new_nid))
|
||||
if (!f2fs_alloc_nid(sbi, &new_nid))
|
||||
return -ENOSPC;
|
||||
|
||||
/* write to inline xattr */
|
||||
@ -405,9 +405,9 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
if (ipage) {
|
||||
inline_addr = inline_xattr_addr(inode, ipage);
|
||||
} else {
|
||||
in_page = get_node_page(sbi, inode->i_ino);
|
||||
in_page = f2fs_get_node_page(sbi, inode->i_ino);
|
||||
if (IS_ERR(in_page)) {
|
||||
alloc_nid_failed(sbi, new_nid);
|
||||
f2fs_alloc_nid_failed(sbi, new_nid);
|
||||
return PTR_ERR(in_page);
|
||||
}
|
||||
inline_addr = inline_xattr_addr(inode, in_page);
|
||||
@ -417,8 +417,8 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
NODE, true);
|
||||
/* no need to use xattr node block */
|
||||
if (hsize <= inline_size) {
|
||||
err = truncate_xattr_node(inode);
|
||||
alloc_nid_failed(sbi, new_nid);
|
||||
err = f2fs_truncate_xattr_node(inode);
|
||||
f2fs_alloc_nid_failed(sbi, new_nid);
|
||||
if (err) {
|
||||
f2fs_put_page(in_page, 1);
|
||||
return err;
|
||||
@ -431,10 +431,10 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
|
||||
/* write to xattr node block */
|
||||
if (F2FS_I(inode)->i_xattr_nid) {
|
||||
xpage = get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
|
||||
xpage = f2fs_get_node_page(sbi, F2FS_I(inode)->i_xattr_nid);
|
||||
if (IS_ERR(xpage)) {
|
||||
err = PTR_ERR(xpage);
|
||||
alloc_nid_failed(sbi, new_nid);
|
||||
f2fs_alloc_nid_failed(sbi, new_nid);
|
||||
goto in_page_out;
|
||||
}
|
||||
f2fs_bug_on(sbi, new_nid);
|
||||
@ -442,13 +442,13 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
|
||||
} else {
|
||||
struct dnode_of_data dn;
|
||||
set_new_dnode(&dn, inode, NULL, NULL, new_nid);
|
||||
xpage = new_node_page(&dn, XATTR_NODE_OFFSET);
|
||||
xpage = f2fs_new_node_page(&dn, XATTR_NODE_OFFSET);
|
||||
if (IS_ERR(xpage)) {
|
||||
err = PTR_ERR(xpage);
|
||||
alloc_nid_failed(sbi, new_nid);
|
||||
f2fs_alloc_nid_failed(sbi, new_nid);
|
||||
goto in_page_out;
|
||||
}
|
||||
alloc_nid_done(sbi, new_nid);
|
||||
f2fs_alloc_nid_done(sbi, new_nid);
|
||||
}
|
||||
xattr_addr = page_address(xpage);
|
||||
|
||||
@ -693,7 +693,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* this case is only from init_inode_metadata */
|
||||
/* this case is only from f2fs_init_inode_metadata */
|
||||
if (ipage)
|
||||
return __f2fs_setxattr(inode, index, name, value,
|
||||
size, ipage, flags);
|
||||
|
@ -280,22 +280,6 @@ static int gfs2_write_jdata_pagevec(struct address_space *mapping,
|
||||
for(i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec->pages[i];
|
||||
|
||||
/*
|
||||
* At this point, the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or
|
||||
* even swizzled back from swapper_space to tmpfs file
|
||||
* mapping. However, page->index will not change
|
||||
* because we have a reference on the page.
|
||||
*/
|
||||
if (page->index > end) {
|
||||
/*
|
||||
* can't be range_cyclic (1st pass) because
|
||||
* end == -1 in that case.
|
||||
*/
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
*done_index = page->index;
|
||||
|
||||
lock_page(page);
|
||||
@ -413,8 +397,8 @@ retry:
|
||||
tag_pages_for_writeback(mapping, index, end);
|
||||
done_index = index;
|
||||
while (!done && (index <= end)) {
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
|
||||
|
@ -2158,8 +2158,8 @@ static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *btree,
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
|
||||
while (pagevec_lookup_tag(&pvec, btcache, &index, PAGECACHE_TAG_DIRTY,
|
||||
PAGEVEC_SIZE)) {
|
||||
while (pagevec_lookup_tag(&pvec, btcache, &index,
|
||||
PAGECACHE_TAG_DIRTY)) {
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
bh = head = page_buffers(pvec.pages[i]);
|
||||
do {
|
||||
|
@ -257,8 +257,7 @@ int nilfs_copy_dirty_pages(struct address_space *dmap,
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
repeat:
|
||||
if (!pagevec_lookup_tag(&pvec, smap, &index, PAGECACHE_TAG_DIRTY,
|
||||
PAGEVEC_SIZE))
|
||||
if (!pagevec_lookup_tag(&pvec, smap, &index, PAGECACHE_TAG_DIRTY))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
@ -376,8 +375,8 @@ void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent)
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
|
||||
while (pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY,
|
||||
PAGEVEC_SIZE)) {
|
||||
while (pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY)) {
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
|
@ -711,18 +711,14 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode,
|
||||
pagevec_init(&pvec, 0);
|
||||
repeat:
|
||||
if (unlikely(index > last) ||
|
||||
!pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY,
|
||||
min_t(pgoff_t, last - index,
|
||||
PAGEVEC_SIZE - 1) + 1))
|
||||
!pagevec_lookup_range_tag(&pvec, mapping, &index, last,
|
||||
PAGECACHE_TAG_DIRTY))
|
||||
return ndirties;
|
||||
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
struct buffer_head *bh, *head;
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
if (unlikely(page->index > last))
|
||||
break;
|
||||
|
||||
lock_page(page);
|
||||
if (!page_has_buffers(page))
|
||||
create_empty_buffers(page, i_blocksize(inode), 0);
|
||||
@ -759,8 +755,8 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
|
||||
while (pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY,
|
||||
PAGEVEC_SIZE)) {
|
||||
while (pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_DIRTY)) {
|
||||
for (i = 0; i < pagevec_count(&pvec); i++) {
|
||||
bh = head = page_buffers(pvec.pages[i]);
|
||||
do {
|
||||
|
@ -24,14 +24,6 @@ static bool ubifs_crypt_empty_dir(struct inode *inode)
|
||||
return ubifs_check_dir_empty(inode) == 0;
|
||||
}
|
||||
|
||||
static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
|
||||
{
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return UBIFS_MAX_INO_DATA;
|
||||
else
|
||||
return UBIFS_MAX_NLEN;
|
||||
}
|
||||
|
||||
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len, int block)
|
||||
{
|
||||
@ -89,5 +81,5 @@ const struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.get_context = ubifs_crypt_get_context,
|
||||
.set_context = ubifs_crypt_set_context,
|
||||
.empty_dir = ubifs_crypt_empty_dir,
|
||||
.max_namelen = ubifs_crypt_max_namelen,
|
||||
.max_namelen = UBIFS_MAX_NLEN,
|
||||
};
|
||||
|
@ -220,20 +220,9 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
|
||||
/*
|
||||
* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
|
||||
* created while the directory was encrypted and we
|
||||
* have access to the key.
|
||||
*/
|
||||
if (fscrypt_has_encryption_key(dir))
|
||||
fscrypt_set_encrypted_dentry(dentry);
|
||||
fscrypt_set_d_op(dentry);
|
||||
if (err && err != -ENOKEY)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
err = fscrypt_prepare_lookup(dir, dentry, flags);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
|
||||
if (err)
|
||||
|
@ -68,16 +68,6 @@ static inline void fscrypt_restore_control_page(struct page *page)
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_d_op(struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* policy.c */
|
||||
static inline int fscrypt_ioctl_set_policy(struct file *filp,
|
||||
const void __user *arg)
|
||||
|
@ -29,7 +29,7 @@ struct fscrypt_operations {
|
||||
int (*set_context)(struct inode *, const void *, size_t, void *);
|
||||
bool (*dummy_context)(struct inode *);
|
||||
bool (*empty_dir)(struct inode *);
|
||||
unsigned (*max_namelen)(struct inode *);
|
||||
unsigned int max_namelen;
|
||||
bool (*is_encrypted)(struct inode *);
|
||||
};
|
||||
|
||||
@ -76,20 +76,6 @@ static inline struct page *fscrypt_control_page(struct page *page)
|
||||
|
||||
extern void fscrypt_restore_control_page(struct page *);
|
||||
|
||||
extern const struct dentry_operations fscrypt_d_ops;
|
||||
|
||||
static inline void fscrypt_set_d_op(struct dentry *dentry)
|
||||
{
|
||||
d_set_d_op(dentry, &fscrypt_d_ops);
|
||||
}
|
||||
|
||||
static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry)
|
||||
{
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
|
||||
/* policy.c */
|
||||
extern int fscrypt_ioctl_set_policy(struct file *, const void __user *);
|
||||
extern int fscrypt_ioctl_get_policy(struct file *, void __user *);
|
||||
|
@ -202,4 +202,77 @@
|
||||
|
||||
#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
|
||||
|
||||
/**
|
||||
* array_size() - Calculate size of 2-dimensional array.
|
||||
*
|
||||
* @a: dimension one
|
||||
* @b: dimension two
|
||||
*
|
||||
* Calculates size of 2-dimensional array: @a * @b.
|
||||
*
|
||||
* Returns: number of bytes needed to represent the array or SIZE_MAX on
|
||||
* overflow.
|
||||
*/
|
||||
static inline __must_check size_t array_size(size_t a, size_t b)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (check_mul_overflow(a, b, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* array3_size() - Calculate size of 3-dimensional array.
|
||||
*
|
||||
* @a: dimension one
|
||||
* @b: dimension two
|
||||
* @c: dimension three
|
||||
*
|
||||
* Calculates size of 3-dimensional array: @a * @b * @c.
|
||||
*
|
||||
* Returns: number of bytes needed to represent the array or SIZE_MAX on
|
||||
* overflow.
|
||||
*/
|
||||
static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (check_mul_overflow(a, b, &bytes))
|
||||
return SIZE_MAX;
|
||||
if (check_mul_overflow(bytes, c, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (check_mul_overflow(n, size, &bytes))
|
||||
return SIZE_MAX;
|
||||
if (check_add_overflow(bytes, c, &bytes))
|
||||
return SIZE_MAX;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct_size() - Calculate size of structure with trailing array.
|
||||
* @p: Pointer to the structure.
|
||||
* @member: Name of the array member.
|
||||
* @n: Number of elements in the array.
|
||||
*
|
||||
* Calculates size of memory needed for structure @p followed by an
|
||||
* array of @n @member elements.
|
||||
*
|
||||
* Return: number of bytes needed or SIZE_MAX on overflow.
|
||||
*/
|
||||
#define struct_size(p, member, n) \
|
||||
__ab_c_size(n, \
|
||||
sizeof(*(p)->member) + __must_be_array((p)->member),\
|
||||
sizeof(*(p)))
|
||||
|
||||
#endif /* __LINUX_OVERFLOW_H */
|
||||
|
@ -366,8 +366,16 @@ static inline unsigned find_get_pages(struct address_space *mapping,
|
||||
}
|
||||
unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t start,
|
||||
unsigned int nr_pages, struct page **pages);
|
||||
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
|
||||
int tag, unsigned int nr_pages, struct page **pages);
|
||||
unsigned find_get_pages_range_tag(struct address_space *mapping, pgoff_t *index,
|
||||
pgoff_t end, int tag, unsigned int nr_pages,
|
||||
struct page **pages);
|
||||
static inline unsigned find_get_pages_tag(struct address_space *mapping,
|
||||
pgoff_t *index, int tag, unsigned int nr_pages,
|
||||
struct page **pages)
|
||||
{
|
||||
return find_get_pages_range_tag(mapping, index, (pgoff_t)-1, tag,
|
||||
nr_pages, pages);
|
||||
}
|
||||
unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start,
|
||||
int tag, unsigned int nr_entries,
|
||||
struct page **entries, pgoff_t *indices);
|
||||
|
@ -38,9 +38,17 @@ static inline unsigned pagevec_lookup(struct pagevec *pvec,
|
||||
return pagevec_lookup_range(pvec, mapping, start, (pgoff_t)-1);
|
||||
}
|
||||
|
||||
unsigned pagevec_lookup_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, int tag,
|
||||
unsigned nr_pages);
|
||||
unsigned pagevec_lookup_range_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
||||
int tag);
|
||||
unsigned pagevec_lookup_range_nr_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
||||
int tag, unsigned max_pages);
|
||||
static inline unsigned pagevec_lookup_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, int tag)
|
||||
{
|
||||
return pagevec_lookup_range_tag(pvec, mapping, index, (pgoff_t)-1, tag);
|
||||
}
|
||||
|
||||
static inline void pagevec_init(struct pagevec *pvec, int cold)
|
||||
{
|
||||
|
47
mm/filemap.c
47
mm/filemap.c
@ -424,19 +424,17 @@ static void __filemap_fdatawait_range(struct address_space *mapping,
|
||||
return;
|
||||
|
||||
pagevec_init(&pvec, 0);
|
||||
while ((index <= end) &&
|
||||
(nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
|
||||
PAGECACHE_TAG_WRITEBACK,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) {
|
||||
while (index <= end) {
|
||||
unsigned i;
|
||||
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index,
|
||||
end, PAGECACHE_TAG_WRITEBACK);
|
||||
if (!nr_pages)
|
||||
break;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
/* until radix tree lookup accepts end_index */
|
||||
if (page->index > end)
|
||||
continue;
|
||||
|
||||
wait_on_page_writeback(page);
|
||||
ClearPageError(page);
|
||||
}
|
||||
@ -1757,9 +1755,10 @@ repeat:
|
||||
EXPORT_SYMBOL(find_get_pages_contig);
|
||||
|
||||
/**
|
||||
* find_get_pages_tag - find and return pages that match @tag
|
||||
* find_get_pages_range_tag - find and return pages in given range matching @tag
|
||||
* @mapping: the address_space to search
|
||||
* @index: the starting page index
|
||||
* @end: The final page index (inclusive)
|
||||
* @tag: the tag index
|
||||
* @nr_pages: the maximum number of pages
|
||||
* @pages: where the resulting pages are placed
|
||||
@ -1767,8 +1766,9 @@ EXPORT_SYMBOL(find_get_pages_contig);
|
||||
* Like find_get_pages, except we only return pages which are tagged with
|
||||
* @tag. We update @index to index the next page for the traversal.
|
||||
*/
|
||||
unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
|
||||
int tag, unsigned int nr_pages, struct page **pages)
|
||||
unsigned find_get_pages_range_tag(struct address_space *mapping, pgoff_t *index,
|
||||
pgoff_t end, int tag, unsigned int nr_pages,
|
||||
struct page **pages)
|
||||
{
|
||||
struct radix_tree_iter iter;
|
||||
void **slot;
|
||||
@ -1781,6 +1781,9 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
|
||||
radix_tree_for_each_tagged(slot, &mapping->page_tree,
|
||||
&iter, *index, tag) {
|
||||
struct page *head, *page;
|
||||
|
||||
if (iter.index > end)
|
||||
break;
|
||||
repeat:
|
||||
page = radix_tree_deref_slot(slot);
|
||||
if (unlikely(!page))
|
||||
@ -1822,18 +1825,28 @@ repeat:
|
||||
}
|
||||
|
||||
pages[ret] = page;
|
||||
if (++ret == nr_pages)
|
||||
break;
|
||||
if (++ret == nr_pages) {
|
||||
*index = pages[ret - 1]->index + 1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We come here when we got at @end. We take care to not overflow the
|
||||
* index @index as it confuses some of the callers. This breaks the
|
||||
* iteration when there is page at index -1 but that is already broken
|
||||
* anyway.
|
||||
*/
|
||||
if (end == (pgoff_t)-1)
|
||||
*index = (pgoff_t)-1;
|
||||
else
|
||||
*index = end + 1;
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret)
|
||||
*index = pages[ret - 1]->index + 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(find_get_pages_tag);
|
||||
EXPORT_SYMBOL(find_get_pages_range_tag);
|
||||
|
||||
/**
|
||||
* find_get_entries_tag - find and return entries that match @tag
|
||||
|
@ -2195,30 +2195,14 @@ retry:
|
||||
while (!done && (index <= end)) {
|
||||
int i;
|
||||
|
||||
nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag,
|
||||
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag);
|
||||
if (nr_pages == 0)
|
||||
break;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
|
||||
/*
|
||||
* At this point, the page may be truncated or
|
||||
* invalidated (changing page->mapping to NULL), or
|
||||
* even swizzled back from swapper_space to tmpfs file
|
||||
* mapping. However, page->index will not change
|
||||
* because we have a reference on the page.
|
||||
*/
|
||||
if (page->index > end) {
|
||||
/*
|
||||
* can't be range_cyclic (1st pass) because
|
||||
* end == -1 in that case.
|
||||
*/
|
||||
done = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
done_index = page->index;
|
||||
|
||||
lock_page(page);
|
||||
|
20
mm/swap.c
20
mm/swap.c
@ -986,15 +986,25 @@ unsigned pagevec_lookup_range(struct pagevec *pvec,
|
||||
}
|
||||
EXPORT_SYMBOL(pagevec_lookup_range);
|
||||
|
||||
unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping,
|
||||
pgoff_t *index, int tag, unsigned nr_pages)
|
||||
unsigned pagevec_lookup_range_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
||||
int tag)
|
||||
{
|
||||
pvec->nr = find_get_pages_tag(mapping, index, tag,
|
||||
nr_pages, pvec->pages);
|
||||
pvec->nr = find_get_pages_range_tag(mapping, index, end, tag,
|
||||
PAGEVEC_SIZE, pvec->pages);
|
||||
return pagevec_count(pvec);
|
||||
}
|
||||
EXPORT_SYMBOL(pagevec_lookup_tag);
|
||||
EXPORT_SYMBOL(pagevec_lookup_range_tag);
|
||||
|
||||
unsigned pagevec_lookup_range_nr_tag(struct pagevec *pvec,
|
||||
struct address_space *mapping, pgoff_t *index, pgoff_t end,
|
||||
int tag, unsigned max_pages)
|
||||
{
|
||||
pvec->nr = find_get_pages_range_tag(mapping, index, end, tag,
|
||||
min_t(unsigned int, max_pages, PAGEVEC_SIZE), pvec->pages);
|
||||
return pagevec_count(pvec);
|
||||
}
|
||||
EXPORT_SYMBOL(pagevec_lookup_range_nr_tag);
|
||||
/*
|
||||
* Perform any setup for the swap system
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user