A lot of bug fixes and cleanups for ext4, including:
* Fix performance problems found in dioread_nolock now that it is the default, caused by transaction leaks. * Clean up fiemap handling in ext4 * Clean up and refactor multiple block allocator (mballoc) code * Fix a problem with mballoc with a smaller file systems running out of blocks because they couldn't properly use blocks that had been reserved by inode preallocation. * Fixed a race in ext4_sync_parent() versus rename() * Simplify the error handling in the extent manipulation code * Make sure all metadata I/O errors are felected to ext4_ext_dirty()'s and ext4_make_inode_dirty()'s callers. * Avoid passing an error pointer to brelse in ext4_xattr_set() * Fix race which could result to freeing an inode on the dirty last in data=journal mode. * Fix refcount handling if ext4_iget() fails * Fix a crash in generic/019 caused by a corrupted extent node -----BEGIN PGP SIGNATURE----- iQEyBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAl7Ze8kACgkQ8vlZVpUN gaNChAf4xn0ytFSrweI/S2Sp05G/2L/ocZ2TZZk2ZdGeN1E+ABdSIv/zIF9zuFgZ /pY/C+fyEZWt4E3FlNO8gJzoEedkzMCMnUhSIfI+wZbcclyTOSNMJtnrnJKAEtVH HOvGZJmg357jy407RCGhZpJ773nwU2xhBTr5OFxvSf9mt/vzebxIOnw5D7HPlC1V Fgm6Du8q+tRrPsyjv1Yu4pUEVXMJ7qUcvt326AXVM3kCZO1Aa5GrURX0w3J4mzW1 tc1tKmtbLcVVYTo9CwHXhk/edbxrhAydSP2iACand3tK6IJuI6j9x+bBJnxXitnr vsxsfTYMG18+2SxrJ9LwmagqmrRq =HMTs -----END PGP SIGNATURE----- Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4 Pull ext4 updates from Ted Ts'o: "A lot of bug fixes and cleanups for ext4, including: - Fix performance problems found in dioread_nolock now that it is the default, caused by transaction leaks. - Clean up fiemap handling in ext4 - Clean up and refactor multiple block allocator (mballoc) code - Fix a problem with mballoc with a smaller file systems running out of blocks because they couldn't properly use blocks that had been reserved by inode preallocation. - Fixed a race in ext4_sync_parent() versus rename() - Simplify the error handling in the extent manipulation code - Make sure all metadata I/O errors are felected to ext4_ext_dirty()'s and ext4_make_inode_dirty()'s callers. - Avoid passing an error pointer to brelse in ext4_xattr_set() - Fix race which could result to freeing an inode on the dirty last in data=journal mode. - Fix refcount handling if ext4_iget() fails - Fix a crash in generic/019 caused by a corrupted extent node" * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (58 commits) ext4: avoid unnecessary transaction starts during writeback ext4: don't block for O_DIRECT if IOCB_NOWAIT is set ext4: remove the access_ok() check in ext4_ioctl_get_es_cache fs: remove the access_ok() check in ioctl_fiemap fs: handle FIEMAP_FLAG_SYNC in fiemap_prep fs: move fiemap range validation into the file systems instances iomap: fix the iomap_fiemap prototype fs: move the fiemap definitions out of fs.h fs: mark __generic_block_fiemap static ext4: remove the call to fiemap_check_flags in ext4_fiemap ext4: split _ext4_fiemap ext4: fix fiemap size checks for bitmap files ext4: fix EXT4_MAX_LOGICAL_BLOCK macro add comment for ext4_dir_entry_2 file_type member jbd2: avoid leaking transaction credits when unreserving handle ext4: drop ext4_journal_free_reserved() ext4: mballoc: use lock for checking free blocks while retrying ext4: mballoc: refactor ext4_mb_good_group() ext4: mballoc: introduce pcpu seqcnt for freeing PA to improve ENOSPC handling ext4: mballoc: refactor ext4_mb_discard_preallocations() ...
This commit is contained in:
commit
0b166a57e6
@ -206,16 +206,18 @@ EINTR once fatal signal received.
|
||||
|
||||
|
||||
Flag checking should be done at the beginning of the ->fiemap callback via the
|
||||
fiemap_check_flags() helper::
|
||||
fiemap_prep() helper::
|
||||
|
||||
int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
|
||||
int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 *len, u32 supported_flags);
|
||||
|
||||
The struct fieinfo should be passed in as received from ioctl_fiemap(). The
|
||||
set of fiemap flags which the fs understands should be passed via fs_flags. If
|
||||
fiemap_check_flags finds invalid user flags, it will place the bad values in
|
||||
fiemap_prep finds invalid user flags, it will place the bad values in
|
||||
fieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, from
|
||||
fiemap_check_flags(), it should immediately exit, returning that error back to
|
||||
ioctl_fiemap().
|
||||
fiemap_prep(), it should immediately exit, returning that error back to
|
||||
ioctl_fiemap(). Additionally the range is validate against the supported
|
||||
maximum file size.
|
||||
|
||||
|
||||
For each extent in the request range, the file system should call
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
static int bad_file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include "ulist.h"
|
||||
|
||||
/*
|
||||
|
@ -7828,14 +7828,12 @@ const struct iomap_dio_ops btrfs_dops = {
|
||||
.submit_io = btrfs_submit_direct,
|
||||
};
|
||||
|
||||
#define BTRFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC)
|
||||
|
||||
static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, BTRFS_FIEMAP_FLAGS);
|
||||
ret = fiemap_prep(inode, fieinfo, start, &len, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/wait_bit.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include "cifsfs.h"
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/sort.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include "cifsfs.h"
|
||||
#include "cifsglob.h"
|
||||
#include "smb2pdu.h"
|
||||
@ -3407,8 +3408,9 @@ static int smb3_fiemap(struct cifs_tcon *tcon,
|
||||
int i, num, rc, flags, last_blob;
|
||||
u64 next;
|
||||
|
||||
if (fiemap_check_flags(fei, FIEMAP_FLAG_SYNC))
|
||||
return -EBADR;
|
||||
rc = fiemap_prep(d_inode(cfile->dentry), fei, start, &len, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
xid = get_xid();
|
||||
again:
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/iomap.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include "ext2.h"
|
||||
#include "acl.h"
|
||||
#include "xattr.h"
|
||||
|
@ -99,8 +99,7 @@ config EXT4_DEBUG
|
||||
Enables run-time debugging support for the ext4 filesystem.
|
||||
|
||||
If you select Y here, then you will be able to turn on debugging
|
||||
with a command such as:
|
||||
echo 1 > /sys/module/ext4/parameters/mballoc_debug
|
||||
using dynamic debug control for mb_debug() / ext_debug() msgs.
|
||||
|
||||
config EXT4_KUNIT_TESTS
|
||||
tristate "KUnit tests for ext4"
|
||||
|
@ -215,9 +215,8 @@ __ext4_set_acl(handle_t *handle, struct inode *inode, int type,
|
||||
value, size, xattr_flags);
|
||||
|
||||
kfree(value);
|
||||
if (!error) {
|
||||
if (!error)
|
||||
set_cached_acl(inode, type, acl);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
@ -256,7 +255,7 @@ retry:
|
||||
if (!error && update_mode) {
|
||||
inode->i_mode = mode;
|
||||
inode->i_ctime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
error = ext4_mark_inode_dirty(handle, inode);
|
||||
}
|
||||
out_stop:
|
||||
ext4_journal_stop(handle);
|
||||
|
@ -903,10 +903,11 @@ ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode)
|
||||
return bg_start;
|
||||
|
||||
if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block)
|
||||
colour = (current->pid % 16) *
|
||||
colour = (task_pid_nr(current) % 16) *
|
||||
(EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
|
||||
else
|
||||
colour = (current->pid % 16) * ((last_block - bg_start) / 16);
|
||||
colour = (task_pid_nr(current) % 16) *
|
||||
((last_block - bg_start) / 16);
|
||||
return bg_start + colour;
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/percpu-rwsem.h>
|
||||
#include <linux/fiemap.h>
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
@ -80,14 +81,22 @@
|
||||
#define ext4_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Turn on EXT_DEBUG to get lots of info about extents operations.
|
||||
*/
|
||||
/*
|
||||
* Turn on EXT_DEBUG to enable ext4_ext_show_path/leaf/move in extents.c
|
||||
*/
|
||||
#define EXT_DEBUG__
|
||||
#ifdef EXT_DEBUG
|
||||
#define ext_debug(fmt, ...) printk(fmt, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Dynamic printk for controlled extents debugging.
|
||||
*/
|
||||
#ifdef CONFIG_EXT4_DEBUG
|
||||
#define ext_debug(ino, fmt, ...) \
|
||||
pr_debug("[%s/%d] EXT4-fs (%s): ino %lu: (%s, %d): %s:" fmt, \
|
||||
current->comm, task_pid_nr(current), \
|
||||
ino->i_sb->s_id, ino->i_ino, __FILE__, __LINE__, \
|
||||
__func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ext_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#define ext_debug(ino, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* data type for block offset of block group */
|
||||
@ -142,6 +151,8 @@ enum SHIFT_DIRECTION {
|
||||
#define EXT4_MB_USE_ROOT_BLOCKS 0x1000
|
||||
/* Use blocks from reserved pool */
|
||||
#define EXT4_MB_USE_RESERVED 0x2000
|
||||
/* Do strict check for free blocks while retrying block allocation */
|
||||
#define EXT4_MB_STRICT_CHECK 0x4000
|
||||
|
||||
struct ext4_allocation_request {
|
||||
/* target inode for block we're allocating */
|
||||
@ -171,10 +182,10 @@ struct ext4_allocation_request {
|
||||
* well as to store the information returned by ext4_map_blocks(). It
|
||||
* takes less room on the stack than a struct buffer_head.
|
||||
*/
|
||||
#define EXT4_MAP_NEW (1 << BH_New)
|
||||
#define EXT4_MAP_MAPPED (1 << BH_Mapped)
|
||||
#define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten)
|
||||
#define EXT4_MAP_BOUNDARY (1 << BH_Boundary)
|
||||
#define EXT4_MAP_NEW BIT(BH_New)
|
||||
#define EXT4_MAP_MAPPED BIT(BH_Mapped)
|
||||
#define EXT4_MAP_UNWRITTEN BIT(BH_Unwritten)
|
||||
#define EXT4_MAP_BOUNDARY BIT(BH_Boundary)
|
||||
#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
|
||||
EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
|
||||
|
||||
@ -417,7 +428,7 @@ struct flex_groups {
|
||||
/* 0x00400000 was formerly EXT4_EOFBLOCKS_FL */
|
||||
#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
|
||||
#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
|
||||
#define EXT4_CASEFOLD_FL 0x40000000 /* Casefolded file */
|
||||
#define EXT4_CASEFOLD_FL 0x40000000 /* Casefolded directory */
|
||||
#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
|
||||
|
||||
#define EXT4_FL_USER_VISIBLE 0x705BDFFF /* User visible flags */
|
||||
@ -490,6 +501,7 @@ enum {
|
||||
/* 22 was formerly EXT4_INODE_EOFBLOCKS */
|
||||
EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */
|
||||
EXT4_INODE_PROJINHERIT = 29, /* Create with parents projid */
|
||||
EXT4_INODE_CASEFOLD = 30, /* Casefolded directory */
|
||||
EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */
|
||||
};
|
||||
|
||||
@ -535,6 +547,7 @@ static inline void ext4_check_flag_values(void)
|
||||
CHECK_FLAG_VALUE(EA_INODE);
|
||||
CHECK_FLAG_VALUE(INLINE_DATA);
|
||||
CHECK_FLAG_VALUE(PROJINHERIT);
|
||||
CHECK_FLAG_VALUE(CASEFOLD);
|
||||
CHECK_FLAG_VALUE(RESERVED);
|
||||
}
|
||||
|
||||
@ -609,8 +622,6 @@ enum {
|
||||
#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020
|
||||
/* Don't normalize allocation size (used for fallocate) */
|
||||
#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
|
||||
/* Request will not result in inode size update (user for fallocate) */
|
||||
#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
|
||||
/* Convert written extents to unwritten */
|
||||
#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100
|
||||
/* Write zeros to newly created written extents */
|
||||
@ -632,6 +643,7 @@ enum {
|
||||
*/
|
||||
#define EXT4_EX_NOCACHE 0x40000000
|
||||
#define EXT4_EX_FORCE_CACHE 0x20000000
|
||||
#define EXT4_EX_NOFAIL 0x10000000
|
||||
|
||||
/*
|
||||
* Flags used by ext4_free_blocks
|
||||
@ -2051,7 +2063,7 @@ struct ext4_dir_entry_2 {
|
||||
__le32 inode; /* Inode number */
|
||||
__le16 rec_len; /* Directory entry length */
|
||||
__u8 name_len; /* Name length */
|
||||
__u8 file_type;
|
||||
__u8 file_type; /* See file type macros EXT4_FT_* below */
|
||||
char name[EXT4_NAME_LEN]; /* File name */
|
||||
};
|
||||
|
||||
@ -3354,7 +3366,7 @@ struct ext4_extent;
|
||||
*/
|
||||
#define EXT_MAX_BLOCKS 0xffffffff
|
||||
|
||||
extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
|
||||
extern void ext4_ext_tree_init(handle_t *handle, struct inode *inode);
|
||||
extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents);
|
||||
extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
|
||||
struct ext4_map_blocks *map, int flags);
|
||||
|
@ -170,10 +170,13 @@ struct partial_cluster {
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
|
||||
#define EXT_LAST_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
|
||||
#define EXT_MAX_EXTENT(__hdr__) \
|
||||
(EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
|
||||
#define EXT_MAX_EXTENT(__hdr__) \
|
||||
((le16_to_cpu((__hdr__)->eh_max)) ? \
|
||||
((EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) \
|
||||
: 0)
|
||||
#define EXT_MAX_INDEX(__hdr__) \
|
||||
(EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
|
||||
((le16_to_cpu((__hdr__)->eh_max)) ? \
|
||||
((EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) : 0)
|
||||
|
||||
static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
|
||||
{
|
||||
|
@ -222,7 +222,10 @@ ext4_mark_iloc_dirty(handle_t *handle,
|
||||
int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
|
||||
struct ext4_iloc *iloc);
|
||||
|
||||
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
|
||||
#define ext4_mark_inode_dirty(__h, __i) \
|
||||
__ext4_mark_inode_dirty((__h), (__i), __func__, __LINE__)
|
||||
int __ext4_mark_inode_dirty(handle_t *handle, struct inode *inode,
|
||||
const char *func, unsigned int line);
|
||||
|
||||
int ext4_expand_extra_isize(struct inode *inode,
|
||||
unsigned int new_extra_isize,
|
||||
@ -335,12 +338,6 @@ static inline handle_t *__ext4_journal_start(struct inode *inode,
|
||||
handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line,
|
||||
int type);
|
||||
|
||||
static inline void ext4_journal_free_reserved(handle_t *handle)
|
||||
{
|
||||
if (ext4_handle_valid(handle))
|
||||
jbd2_journal_free_reserved(handle);
|
||||
}
|
||||
|
||||
static inline handle_t *ext4_journal_current_handle(void)
|
||||
{
|
||||
return journal_current_handle();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1054,7 +1054,7 @@ static void count_rsvd(struct inode *inode, ext4_lblk_t lblk, long len,
|
||||
end = (end > ext4_es_end(es)) ? ext4_es_end(es) : end;
|
||||
|
||||
/* record the first block of the first delonly extent seen */
|
||||
if (rc->first_do_lblk_found == false) {
|
||||
if (!rc->first_do_lblk_found) {
|
||||
rc->first_do_lblk = i;
|
||||
rc->first_do_lblk_found = true;
|
||||
}
|
||||
|
@ -287,6 +287,7 @@ static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset,
|
||||
bool truncate = false;
|
||||
u8 blkbits = inode->i_blkbits;
|
||||
ext4_lblk_t written_blk, end_blk;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note that EXT4_I(inode)->i_disksize can get extended up to
|
||||
@ -327,8 +328,14 @@ static ssize_t ext4_handle_inode_extension(struct inode *inode, loff_t offset,
|
||||
goto truncate;
|
||||
}
|
||||
|
||||
if (ext4_update_inode_size(inode, offset + written))
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
if (ext4_update_inode_size(inode, offset + written)) {
|
||||
ret = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(ret)) {
|
||||
written = ret;
|
||||
ext4_journal_stop(handle);
|
||||
goto truncate;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We may need to truncate allocated but not written blocks beyond EOF.
|
||||
@ -495,6 +502,12 @@ static ssize_t ext4_dio_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
/* if we're going to block and IOCB_NOWAIT is set, return -EAGAIN */
|
||||
if ((iocb->ki_flags & IOCB_NOWAIT) && (unaligned_io || extend)) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset = iocb->ki_pos;
|
||||
count = ret;
|
||||
|
||||
|
@ -44,30 +44,28 @@
|
||||
*/
|
||||
static int ext4_sync_parent(struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry = NULL;
|
||||
struct inode *next;
|
||||
struct dentry *dentry, *next;
|
||||
int ret = 0;
|
||||
|
||||
if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY))
|
||||
return 0;
|
||||
inode = igrab(inode);
|
||||
dentry = d_find_any_alias(inode);
|
||||
if (!dentry)
|
||||
return 0;
|
||||
while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
|
||||
ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
|
||||
dentry = d_find_any_alias(inode);
|
||||
if (!dentry)
|
||||
break;
|
||||
next = igrab(d_inode(dentry->d_parent));
|
||||
|
||||
next = dget_parent(dentry);
|
||||
dput(dentry);
|
||||
if (!next)
|
||||
break;
|
||||
iput(inode);
|
||||
inode = next;
|
||||
dentry = next;
|
||||
inode = dentry->d_inode;
|
||||
|
||||
/*
|
||||
* The directory inode may have gone through rmdir by now. But
|
||||
* the inode itself and its blocks are still allocated (we hold
|
||||
* a reference to the inode so it didn't go through
|
||||
* ext4_evict_inode()) and so we are safe to flush metadata
|
||||
* blocks and the inode.
|
||||
* a reference to the inode via its dentry), so it didn't go
|
||||
* through ext4_evict_inode()) and so we are safe to flush
|
||||
* metadata blocks and the inode.
|
||||
*/
|
||||
ret = sync_mapping_buffers(inode->i_mapping);
|
||||
if (ret)
|
||||
@ -76,7 +74,7 @@ static int ext4_sync_parent(struct inode *inode)
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
iput(inode);
|
||||
dput(dentry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1246,6 +1246,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
|
||||
ext4_error_err(sb, -err,
|
||||
"couldn't read orphan inode %lu (err %d)",
|
||||
ino, err);
|
||||
brelse(bitmap_bh);
|
||||
return inode;
|
||||
}
|
||||
|
||||
|
@ -467,7 +467,9 @@ static int ext4_splice_branch(handle_t *handle,
|
||||
/*
|
||||
* OK, we spliced it into the inode itself on a direct block.
|
||||
*/
|
||||
ext4_mark_inode_dirty(handle, ar->inode);
|
||||
err = ext4_mark_inode_dirty(handle, ar->inode);
|
||||
if (unlikely(err))
|
||||
goto err_out;
|
||||
jbd_debug(5, "splicing direct\n");
|
||||
}
|
||||
return err;
|
||||
|
@ -1260,7 +1260,7 @@ out:
|
||||
int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
|
||||
struct inode *dir, struct inode *inode)
|
||||
{
|
||||
int ret, inline_size, no_expand;
|
||||
int ret, ret2, inline_size, no_expand;
|
||||
void *inline_start;
|
||||
struct ext4_iloc iloc;
|
||||
|
||||
@ -1314,7 +1314,9 @@ int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname,
|
||||
|
||||
out:
|
||||
ext4_write_unlock_xattr(dir, &no_expand);
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
ret2 = ext4_mark_inode_dirty(handle, dir);
|
||||
if (unlikely(ret2 && !ret))
|
||||
ret = ret2;
|
||||
brelse(iloc.bh);
|
||||
return ret;
|
||||
}
|
||||
|
108
fs/ext4/inode.c
108
fs/ext4/inode.c
@ -220,6 +220,16 @@ void ext4_evict_inode(struct inode *inode)
|
||||
ext4_begin_ordered_truncate(inode, 0);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
|
||||
/*
|
||||
* For inodes with journalled data, transaction commit could have
|
||||
* dirtied the inode. Flush worker is ignoring it because of I_FREEING
|
||||
* flag but we still need to remove the inode from the writeback lists.
|
||||
*/
|
||||
if (!list_empty_careful(&inode->i_io_list)) {
|
||||
WARN_ON_ONCE(!ext4_should_journal_data(inode));
|
||||
inode_io_list_del(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Protect us against freezing - iput() caller didn't have to have any
|
||||
* protection against it
|
||||
@ -432,11 +442,9 @@ static void ext4_map_blocks_es_recheck(handle_t *handle,
|
||||
*/
|
||||
down_read(&EXT4_I(inode)->i_data_sem);
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
||||
EXT4_GET_BLOCKS_KEEP_SIZE);
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, 0);
|
||||
} else {
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, flags &
|
||||
EXT4_GET_BLOCKS_KEEP_SIZE);
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, 0);
|
||||
}
|
||||
up_read((&EXT4_I(inode)->i_data_sem));
|
||||
|
||||
@ -493,9 +501,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
#endif
|
||||
|
||||
map->m_flags = 0;
|
||||
ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
|
||||
"logical block %lu\n", inode->i_ino, flags, map->m_len,
|
||||
(unsigned long) map->m_lblk);
|
||||
ext_debug(inode, "flag 0x%x, max_blocks %u, logical block %lu\n",
|
||||
flags, map->m_len, (unsigned long) map->m_lblk);
|
||||
|
||||
/*
|
||||
* ext4_map_blocks returns an int, and m_len is an unsigned int
|
||||
@ -541,11 +548,9 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
|
||||
*/
|
||||
down_read(&EXT4_I(inode)->i_data_sem);
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, flags &
|
||||
EXT4_GET_BLOCKS_KEEP_SIZE);
|
||||
retval = ext4_ext_map_blocks(handle, inode, map, 0);
|
||||
} else {
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, flags &
|
||||
EXT4_GET_BLOCKS_KEEP_SIZE);
|
||||
retval = ext4_ind_map_blocks(handle, inode, map, 0);
|
||||
}
|
||||
if (retval > 0) {
|
||||
unsigned int status;
|
||||
@ -726,6 +731,9 @@ out_sem:
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (retval < 0)
|
||||
ext_debug(inode, "failed with err %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -1296,7 +1304,7 @@ static int ext4_write_end(struct file *file,
|
||||
* filesystems.
|
||||
*/
|
||||
if (i_size_changed || inline_data)
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret = ext4_mark_inode_dirty(handle, inode);
|
||||
|
||||
if (pos + len > inode->i_size && !verity && ext4_can_truncate(inode))
|
||||
/* if we have allocated more blocks and copied
|
||||
@ -1526,6 +1534,7 @@ struct mpage_da_data {
|
||||
struct ext4_map_blocks map;
|
||||
struct ext4_io_submit io_submit; /* IO submission data */
|
||||
unsigned int do_map:1;
|
||||
unsigned int scanned_until_end:1;
|
||||
};
|
||||
|
||||
static void mpage_release_unused_pages(struct mpage_da_data *mpd,
|
||||
@ -1541,6 +1550,7 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd,
|
||||
if (mpd->first_page >= mpd->next_page)
|
||||
return;
|
||||
|
||||
mpd->scanned_until_end = 0;
|
||||
index = mpd->first_page;
|
||||
end = mpd->next_page - 1;
|
||||
if (invalidate) {
|
||||
@ -1681,8 +1691,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
|
||||
invalid_block = ~0;
|
||||
|
||||
map->m_flags = 0;
|
||||
ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u,"
|
||||
"logical block %lu\n", inode->i_ino, map->m_len,
|
||||
ext_debug(inode, "max_blocks %u, logical block %lu\n", map->m_len,
|
||||
(unsigned long) map->m_lblk);
|
||||
|
||||
/* Lookup extent status tree firstly */
|
||||
@ -2078,7 +2087,7 @@ static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page)
|
||||
return err;
|
||||
}
|
||||
|
||||
#define BH_FLAGS ((1 << BH_Unwritten) | (1 << BH_Delay))
|
||||
#define BH_FLAGS (BIT(BH_Unwritten) | BIT(BH_Delay))
|
||||
|
||||
/*
|
||||
* mballoc gives us at most this number of blocks...
|
||||
@ -2188,7 +2197,11 @@ static int mpage_process_page_bufs(struct mpage_da_data *mpd,
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
return lblk < blocks;
|
||||
if (lblk >= blocks) {
|
||||
mpd->scanned_until_end = 1;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2311,7 +2324,7 @@ static int mpage_map_and_submit_buffers(struct mpage_da_data *mpd)
|
||||
* mapping, or maybe the page was submitted for IO.
|
||||
* So we return to call further extent mapping.
|
||||
*/
|
||||
if (err < 0 || map_bh == true)
|
||||
if (err < 0 || map_bh)
|
||||
goto out;
|
||||
/* Page fully mapped - let IO run! */
|
||||
err = mpage_submit_page(mpd, page);
|
||||
@ -2358,7 +2371,7 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
|
||||
dioread_nolock = ext4_should_dioread_nolock(inode);
|
||||
if (dioread_nolock)
|
||||
get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT;
|
||||
if (map->m_flags & (1 << BH_Delay))
|
||||
if (map->m_flags & BIT(BH_Delay))
|
||||
get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE;
|
||||
|
||||
err = ext4_map_blocks(handle, inode, map, get_blocks_flags);
|
||||
@ -2546,7 +2559,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
|
||||
nr_pages = pagevec_lookup_range_tag(&pvec, mapping, &index, end,
|
||||
tag);
|
||||
if (nr_pages == 0)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
for (i = 0; i < nr_pages; i++) {
|
||||
struct page *page = pvec.pages[i];
|
||||
@ -2601,6 +2614,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)
|
||||
pagevec_release(&pvec);
|
||||
cond_resched();
|
||||
}
|
||||
mpd->scanned_until_end = 1;
|
||||
return 0;
|
||||
out:
|
||||
pagevec_release(&pvec);
|
||||
@ -2619,7 +2633,6 @@ static int ext4_writepages(struct address_space *mapping,
|
||||
struct inode *inode = mapping->host;
|
||||
int needed_blocks, rsv_blocks = 0, ret = 0;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
|
||||
bool done;
|
||||
struct blk_plug plug;
|
||||
bool give_up_on_write = false;
|
||||
|
||||
@ -2705,7 +2718,6 @@ static int ext4_writepages(struct address_space *mapping,
|
||||
retry:
|
||||
if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)
|
||||
tag_pages_for_writeback(mapping, mpd.first_page, mpd.last_page);
|
||||
done = false;
|
||||
blk_start_plug(&plug);
|
||||
|
||||
/*
|
||||
@ -2715,6 +2727,7 @@ retry:
|
||||
* started.
|
||||
*/
|
||||
mpd.do_map = 0;
|
||||
mpd.scanned_until_end = 0;
|
||||
mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
|
||||
if (!mpd.io_submit.io_end) {
|
||||
ret = -ENOMEM;
|
||||
@ -2730,7 +2743,7 @@ retry:
|
||||
if (ret < 0)
|
||||
goto unplug;
|
||||
|
||||
while (!done && mpd.first_page <= mpd.last_page) {
|
||||
while (!mpd.scanned_until_end && wbc->nr_to_write > 0) {
|
||||
/* For each extent of pages we use new io_end */
|
||||
mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL);
|
||||
if (!mpd.io_submit.io_end) {
|
||||
@ -2765,20 +2778,9 @@ retry:
|
||||
|
||||
trace_ext4_da_write_pages(inode, mpd.first_page, mpd.wbc);
|
||||
ret = mpage_prepare_extent_to_map(&mpd);
|
||||
if (!ret) {
|
||||
if (mpd.map.m_len)
|
||||
ret = mpage_map_and_submit_extent(handle, &mpd,
|
||||
if (!ret && mpd.map.m_len)
|
||||
ret = mpage_map_and_submit_extent(handle, &mpd,
|
||||
&give_up_on_write);
|
||||
else {
|
||||
/*
|
||||
* We scanned the whole range (or exhausted
|
||||
* nr_to_write), submitted what was mapped and
|
||||
* didn't find anything needing mapping. We are
|
||||
* done.
|
||||
*/
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Caution: If the handle is synchronous,
|
||||
* ext4_journal_stop() can wait for transaction commit
|
||||
@ -3077,7 +3079,7 @@ static int ext4_da_write_end(struct file *file,
|
||||
* new_i_size is less that inode->i_size
|
||||
* bu greater than i_disksize.(hint delalloc)
|
||||
*/
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret = ext4_mark_inode_dirty(handle, inode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3094,7 +3096,7 @@ static int ext4_da_write_end(struct file *file,
|
||||
if (ret2 < 0)
|
||||
ret = ret2;
|
||||
ret2 = ext4_journal_stop(handle);
|
||||
if (!ret)
|
||||
if (unlikely(ret2 && !ret))
|
||||
ret = ret2;
|
||||
|
||||
return ret ? ret : copied;
|
||||
@ -3883,6 +3885,8 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
|
||||
loff_t len)
|
||||
{
|
||||
handle_t *handle;
|
||||
int ret;
|
||||
|
||||
loff_t size = i_size_read(inode);
|
||||
|
||||
WARN_ON(!inode_is_locked(inode));
|
||||
@ -3896,10 +3900,10 @@ int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
ext4_update_i_disksize(inode, size);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret = ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ext4_wait_dax_page(struct ext4_inode_info *ei)
|
||||
@ -3951,7 +3955,7 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
|
||||
loff_t first_block_offset, last_block_offset;
|
||||
handle_t *handle;
|
||||
unsigned int credits;
|
||||
int ret = 0;
|
||||
int ret = 0, ret2 = 0;
|
||||
|
||||
trace_ext4_punch_hole(inode, offset, length, 0);
|
||||
|
||||
@ -4074,7 +4078,9 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
|
||||
ext4_handle_sync(handle);
|
||||
|
||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(ret2))
|
||||
ret = ret2;
|
||||
if (ret >= 0)
|
||||
ext4_update_inode_fsync_trans(handle, inode, 1);
|
||||
out_stop:
|
||||
@ -4143,7 +4149,7 @@ int ext4_truncate(struct inode *inode)
|
||||
{
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
unsigned int credits;
|
||||
int err = 0;
|
||||
int err = 0, err2;
|
||||
handle_t *handle;
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
|
||||
@ -4231,7 +4237,9 @@ out_stop:
|
||||
ext4_orphan_del(handle, inode);
|
||||
|
||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(err2 && !err))
|
||||
err = err2;
|
||||
ext4_journal_stop(handle);
|
||||
|
||||
trace_ext4_truncate_exit(inode);
|
||||
@ -5289,6 +5297,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
|
||||
inode->i_gid = attr->ia_gid;
|
||||
error = ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
if (unlikely(error))
|
||||
return error;
|
||||
}
|
||||
|
||||
if (attr->ia_valid & ATTR_SIZE) {
|
||||
@ -5774,7 +5784,8 @@ out_unlock:
|
||||
* Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
|
||||
* we start and wait on commits.
|
||||
*/
|
||||
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
|
||||
int __ext4_mark_inode_dirty(handle_t *handle, struct inode *inode,
|
||||
const char *func, unsigned int line)
|
||||
{
|
||||
struct ext4_iloc iloc;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
||||
@ -5784,13 +5795,18 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
|
||||
trace_ext4_mark_inode_dirty(inode, _RET_IP_);
|
||||
err = ext4_reserve_inode_write(handle, inode, &iloc);
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize)
|
||||
ext4_try_to_expand_extra_isize(inode, sbi->s_want_extra_isize,
|
||||
iloc, handle);
|
||||
|
||||
return ext4_mark_iloc_dirty(handle, inode, &iloc);
|
||||
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
|
||||
out:
|
||||
if (unlikely(err))
|
||||
ext4_error_inode_err(inode, func, line, 0, err,
|
||||
"mark_inode_dirty error");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -754,14 +754,6 @@ static int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg)
|
||||
fieinfo.fi_extents_max = fiemap.fm_extent_count;
|
||||
fieinfo.fi_extents_start = ufiemap->fm_extents;
|
||||
|
||||
if (fiemap.fm_extent_count != 0 &&
|
||||
!access_ok(fieinfo.fi_extents_start,
|
||||
fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))
|
||||
return -EFAULT;
|
||||
|
||||
if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
|
||||
error = ext4_get_es_cache(inode, &fieinfo, fiemap.fm_start,
|
||||
fiemap.fm_length);
|
||||
fiemap.fm_flags = fieinfo.fi_flags;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,19 +24,15 @@
|
||||
#include "ext4.h"
|
||||
|
||||
/*
|
||||
* mb_debug() dynamic printk msgs could be used to debug mballoc code.
|
||||
*/
|
||||
#ifdef CONFIG_EXT4_DEBUG
|
||||
extern ushort ext4_mballoc_debug;
|
||||
|
||||
#define mb_debug(n, fmt, ...) \
|
||||
do { \
|
||||
if ((n) <= ext4_mballoc_debug) { \
|
||||
printk(KERN_DEBUG "(%s, %d): %s: " fmt, \
|
||||
__FILE__, __LINE__, __func__, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
#define mb_debug(sb, fmt, ...) \
|
||||
pr_debug("[%s/%d] EXT4-fs (%s): (%s, %d): %s: " fmt, \
|
||||
current->comm, task_pid_nr(current), sb->s_id, \
|
||||
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define mb_debug(n, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#define mb_debug(sb, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */
|
||||
|
@ -287,7 +287,7 @@ static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data)
|
||||
static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
||||
struct inode *tmp_inode)
|
||||
{
|
||||
int retval;
|
||||
int retval, retval2 = 0;
|
||||
__le32 i_data[3];
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
struct ext4_inode_info *tmp_ei = EXT4_I(tmp_inode);
|
||||
@ -342,7 +342,9 @@ static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
|
||||
* i_blocks when freeing the indirect meta-data blocks
|
||||
*/
|
||||
retval = free_ind_block(handle, inode, i_data);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
retval2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(retval2 && !retval))
|
||||
retval = retval2;
|
||||
|
||||
err_out:
|
||||
return retval;
|
||||
@ -601,7 +603,7 @@ int ext4_ind_migrate(struct inode *inode)
|
||||
ext4_lblk_t start, end;
|
||||
ext4_fsblk_t blk;
|
||||
handle_t *handle;
|
||||
int ret;
|
||||
int ret, ret2 = 0;
|
||||
|
||||
if (!ext4_has_feature_extents(inode->i_sb) ||
|
||||
(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
|
||||
@ -655,7 +657,9 @@ int ext4_ind_migrate(struct inode *inode)
|
||||
memset(ei->i_data, 0, sizeof(ei->i_data));
|
||||
for (i = start; i <= end; i++)
|
||||
ei->i_data[i] = cpu_to_le32(blk++);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ret2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(ret2 && !ret))
|
||||
ret = ret2;
|
||||
errout:
|
||||
ext4_journal_stop(handle);
|
||||
up_write(&EXT4_I(inode)->i_data_sem);
|
||||
|
@ -1993,7 +1993,7 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
|
||||
{
|
||||
unsigned int blocksize = dir->i_sb->s_blocksize;
|
||||
int csum_size = 0;
|
||||
int err;
|
||||
int err, err2;
|
||||
|
||||
if (ext4_has_metadata_csum(inode->i_sb))
|
||||
csum_size = sizeof(struct ext4_dir_entry_tail);
|
||||
@ -2028,12 +2028,12 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname,
|
||||
dir->i_mtime = dir->i_ctime = current_time(dir);
|
||||
ext4_update_dx_flag(dir);
|
||||
inode_inc_iversion(dir);
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
err2 = ext4_mark_inode_dirty(handle, dir);
|
||||
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
|
||||
err = ext4_handle_dirty_dirblock(handle, dir, bh);
|
||||
if (err)
|
||||
ext4_std_error(dir->i_sb, err);
|
||||
return 0;
|
||||
return err ? err : err2;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2223,7 +2223,9 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
}
|
||||
ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
|
||||
dx_fallback++;
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
retval = ext4_mark_inode_dirty(handle, dir);
|
||||
if (unlikely(retval))
|
||||
goto out;
|
||||
}
|
||||
blocks = dir->i_size >> sb->s_blocksize_bits;
|
||||
for (block = 0; block < blocks; block++) {
|
||||
@ -2576,12 +2578,12 @@ static int ext4_add_nondir(handle_t *handle,
|
||||
struct inode *inode = *inodep;
|
||||
int err = ext4_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
if (IS_DIRSYNC(dir))
|
||||
ext4_handle_sync(handle);
|
||||
d_instantiate_new(dentry, inode);
|
||||
*inodep = NULL;
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
drop_nlink(inode);
|
||||
ext4_orphan_add(handle, inode);
|
||||
@ -2775,7 +2777,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
handle_t *handle;
|
||||
struct inode *inode;
|
||||
int err, credits, retries = 0;
|
||||
int err, err2 = 0, credits, retries = 0;
|
||||
|
||||
if (EXT4_DIR_LINK_MAX(dir))
|
||||
return -EMLINK;
|
||||
@ -2808,7 +2810,9 @@ out_clear_inode:
|
||||
clear_nlink(inode);
|
||||
ext4_orphan_add(handle, inode);
|
||||
unlock_new_inode(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(err2))
|
||||
err = err2;
|
||||
ext4_journal_stop(handle);
|
||||
iput(inode);
|
||||
goto out_retry;
|
||||
@ -3148,10 +3152,12 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
inode->i_size = 0;
|
||||
ext4_orphan_add(handle, inode);
|
||||
inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
retval = ext4_mark_inode_dirty(handle, inode);
|
||||
if (retval)
|
||||
goto end_rmdir;
|
||||
ext4_dec_count(handle, dir);
|
||||
ext4_update_dx_flag(dir);
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
retval = ext4_mark_inode_dirty(handle, dir);
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
/* VFS negative dentries are incompatible with Encoding and
|
||||
@ -3221,7 +3227,9 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
|
||||
goto end_unlink;
|
||||
dir->i_ctime = dir->i_mtime = current_time(dir);
|
||||
ext4_update_dx_flag(dir);
|
||||
ext4_mark_inode_dirty(handle, dir);
|
||||
retval = ext4_mark_inode_dirty(handle, dir);
|
||||
if (retval)
|
||||
goto end_unlink;
|
||||
if (inode->i_nlink == 0)
|
||||
ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
|
||||
dentry->d_name.len, dentry->d_name.name);
|
||||
@ -3230,7 +3238,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (!inode->i_nlink)
|
||||
ext4_orphan_add(handle, inode);
|
||||
inode->i_ctime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
retval = ext4_mark_inode_dirty(handle, inode);
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
/* VFS negative dentries are incompatible with Encoding and
|
||||
@ -3419,7 +3427,7 @@ retry:
|
||||
|
||||
err = ext4_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
/* this can happen only for tmpfile being
|
||||
* linked the first time
|
||||
*/
|
||||
@ -3531,7 +3539,7 @@ static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent,
|
||||
static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
|
||||
unsigned ino, unsigned file_type)
|
||||
{
|
||||
int retval;
|
||||
int retval, retval2;
|
||||
|
||||
BUFFER_TRACE(ent->bh, "get write access");
|
||||
retval = ext4_journal_get_write_access(handle, ent->bh);
|
||||
@ -3543,19 +3551,19 @@ static int ext4_setent(handle_t *handle, struct ext4_renament *ent,
|
||||
inode_inc_iversion(ent->dir);
|
||||
ent->dir->i_ctime = ent->dir->i_mtime =
|
||||
current_time(ent->dir);
|
||||
ext4_mark_inode_dirty(handle, ent->dir);
|
||||
retval = ext4_mark_inode_dirty(handle, ent->dir);
|
||||
BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata");
|
||||
if (!ent->inlined) {
|
||||
retval = ext4_handle_dirty_dirblock(handle, ent->dir, ent->bh);
|
||||
if (unlikely(retval)) {
|
||||
ext4_std_error(ent->dir->i_sb, retval);
|
||||
return retval;
|
||||
retval2 = ext4_handle_dirty_dirblock(handle, ent->dir, ent->bh);
|
||||
if (unlikely(retval2)) {
|
||||
ext4_std_error(ent->dir->i_sb, retval2);
|
||||
return retval2;
|
||||
}
|
||||
}
|
||||
brelse(ent->bh);
|
||||
ent->bh = NULL;
|
||||
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
|
||||
@ -3790,7 +3798,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
EXT4_FT_CHRDEV);
|
||||
if (retval)
|
||||
goto end_rename;
|
||||
ext4_mark_inode_dirty(handle, whiteout);
|
||||
retval = ext4_mark_inode_dirty(handle, whiteout);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
}
|
||||
if (!new.bh) {
|
||||
retval = ext4_add_entry(handle, new.dentry, old.inode);
|
||||
@ -3811,7 +3821,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
* rename.
|
||||
*/
|
||||
old.inode->i_ctime = current_time(old.inode);
|
||||
ext4_mark_inode_dirty(handle, old.inode);
|
||||
retval = ext4_mark_inode_dirty(handle, old.inode);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
|
||||
if (!whiteout) {
|
||||
/*
|
||||
@ -3840,12 +3852,18 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
} else {
|
||||
ext4_inc_count(handle, new.dir);
|
||||
ext4_update_dx_flag(new.dir);
|
||||
ext4_mark_inode_dirty(handle, new.dir);
|
||||
retval = ext4_mark_inode_dirty(handle, new.dir);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
}
|
||||
}
|
||||
ext4_mark_inode_dirty(handle, old.dir);
|
||||
retval = ext4_mark_inode_dirty(handle, old.dir);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
if (new.inode) {
|
||||
ext4_mark_inode_dirty(handle, new.inode);
|
||||
retval = ext4_mark_inode_dirty(handle, new.inode);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
if (!new.inode->i_nlink)
|
||||
ext4_orphan_add(handle, new.inode);
|
||||
}
|
||||
@ -3979,8 +3997,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
ctime = current_time(old.inode);
|
||||
old.inode->i_ctime = ctime;
|
||||
new.inode->i_ctime = ctime;
|
||||
ext4_mark_inode_dirty(handle, old.inode);
|
||||
ext4_mark_inode_dirty(handle, new.inode);
|
||||
retval = ext4_mark_inode_dirty(handle, old.inode);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
retval = ext4_mark_inode_dirty(handle, new.inode);
|
||||
if (unlikely(retval))
|
||||
goto end_rename;
|
||||
|
||||
if (old.dir_bh) {
|
||||
retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
|
||||
|
@ -3718,7 +3718,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
int blocksize, clustersize;
|
||||
unsigned int db_count;
|
||||
unsigned int i;
|
||||
int needs_recovery, has_huge_files, has_bigalloc;
|
||||
int needs_recovery, has_huge_files;
|
||||
__u64 blocks_count;
|
||||
int err = 0;
|
||||
unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
|
||||
@ -4010,17 +4010,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
|
||||
printk_once(KERN_WARNING "EXT4-fs: Warning: mounting with data=journal disables delayed allocation, dioread_nolock, and O_DIRECT support!\n");
|
||||
/* can't mount with both data=journal and dioread_nolock. */
|
||||
clear_opt(sb, DIOREAD_NOLOCK);
|
||||
if (test_opt2(sb, EXPLICIT_DELALLOC)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and delalloc");
|
||||
goto failed_mount;
|
||||
}
|
||||
if (test_opt(sb, DIOREAD_NOLOCK)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and dioread_nolock");
|
||||
goto failed_mount;
|
||||
}
|
||||
if (test_opt(sb, DAX)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and dax");
|
||||
@ -4237,8 +4233,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
/* Handle clustersize */
|
||||
clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size);
|
||||
has_bigalloc = ext4_has_feature_bigalloc(sb);
|
||||
if (has_bigalloc) {
|
||||
if (ext4_has_feature_bigalloc(sb)) {
|
||||
if (clustersize < blocksize) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"cluster size (%d) smaller than "
|
||||
@ -5925,7 +5920,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
|
||||
EXT4_I(inode)->i_flags |= EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL;
|
||||
inode_set_flags(inode, S_NOATIME | S_IMMUTABLE,
|
||||
S_NOATIME | S_IMMUTABLE);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
unlock_inode:
|
||||
inode_unlock(inode);
|
||||
@ -6027,12 +6022,14 @@ static int ext4_quota_off(struct super_block *sb, int type)
|
||||
* this is not a hard failure and quotas are already disabled.
|
||||
*/
|
||||
handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
|
||||
if (IS_ERR(handle))
|
||||
if (IS_ERR(handle)) {
|
||||
err = PTR_ERR(handle);
|
||||
goto out_unlock;
|
||||
}
|
||||
EXT4_I(inode)->i_flags &= ~(EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL);
|
||||
inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
|
||||
inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_journal_stop(handle);
|
||||
out_unlock:
|
||||
inode_unlock(inode);
|
||||
@ -6090,7 +6087,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
|
||||
{
|
||||
struct inode *inode = sb_dqopt(sb)->files[type];
|
||||
ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
|
||||
int err, offset = off & (sb->s_blocksize - 1);
|
||||
int err = 0, err2 = 0, offset = off & (sb->s_blocksize - 1);
|
||||
int retries = 0;
|
||||
struct buffer_head *bh;
|
||||
handle_t *handle = journal_current_handle();
|
||||
@ -6138,9 +6135,11 @@ out:
|
||||
if (inode->i_size < off + len) {
|
||||
i_size_write(inode, off + len);
|
||||
EXT4_I(inode)->i_disksize = inode->i_size;
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
err2 = ext4_mark_inode_dirty(handle, inode);
|
||||
if (unlikely(err2 && !err))
|
||||
err = err2;
|
||||
}
|
||||
return len;
|
||||
return err ? err : len;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1327,7 +1327,7 @@ static int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode,
|
||||
int blocksize = ea_inode->i_sb->s_blocksize;
|
||||
int max_blocks = (bufsize + blocksize - 1) >> ea_inode->i_blkbits;
|
||||
int csize, wsize = 0;
|
||||
int ret = 0;
|
||||
int ret = 0, ret2 = 0;
|
||||
int retries = 0;
|
||||
|
||||
retry:
|
||||
@ -1385,7 +1385,9 @@ retry:
|
||||
ext4_update_i_disksize(ea_inode, wsize);
|
||||
inode_unlock(ea_inode);
|
||||
|
||||
ext4_mark_inode_dirty(handle, ea_inode);
|
||||
ret2 = ext4_mark_inode_dirty(handle, ea_inode);
|
||||
if (unlikely(ret2 && !ret))
|
||||
ret = ret2;
|
||||
|
||||
out:
|
||||
brelse(bh);
|
||||
@ -1800,8 +1802,11 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
|
||||
if (EXT4_I(inode)->i_file_acl) {
|
||||
/* The inode already has an extended attribute block. */
|
||||
bs->bh = ext4_sb_bread(sb, EXT4_I(inode)->i_file_acl, REQ_PRIO);
|
||||
if (IS_ERR(bs->bh))
|
||||
return PTR_ERR(bs->bh);
|
||||
if (IS_ERR(bs->bh)) {
|
||||
error = PTR_ERR(bs->bh);
|
||||
bs->bh = NULL;
|
||||
return error;
|
||||
}
|
||||
ea_bdebug(bs->bh, "b_count=%d, refcount=%d",
|
||||
atomic_read(&(bs->bh->b_count)),
|
||||
le32_to_cpu(BHDR(bs->bh)->h_refcount));
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/uio.h>
|
||||
#include <linux/cleancache.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
#include "f2fs.h"
|
||||
#include "node.h"
|
||||
@ -1824,7 +1825,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR);
|
||||
ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_XATTR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/f2fs_fs.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
#include "f2fs.h"
|
||||
#include "node.h"
|
||||
|
@ -1125,6 +1125,7 @@ void inode_io_list_del(struct inode *inode)
|
||||
inode_io_list_del_locked(inode, wb);
|
||||
spin_unlock(&wb->list_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(inode_io_list_del);
|
||||
|
||||
/*
|
||||
* mark an inode as under writeback on the sb
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/iomap.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "gfs2.h"
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "hpfs_fn.h"
|
||||
#include <linux/mpage.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
#define BLOCKS(size) (((size) + 511) >> 9)
|
||||
|
||||
|
@ -142,8 +142,6 @@ extern int dentry_needs_remove_privs(struct dentry *dentry);
|
||||
/*
|
||||
* fs-writeback.c
|
||||
*/
|
||||
extern void inode_io_list_del(struct inode *inode);
|
||||
|
||||
extern long get_nr_dirty_inodes(void);
|
||||
extern int invalidate_inodes(struct super_block *, bool);
|
||||
|
||||
|
82
fs/ioctl.c
82
fs/ioctl.c
@ -18,6 +18,7 @@
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -148,61 +149,55 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical,
|
||||
EXPORT_SYMBOL(fiemap_fill_next_extent);
|
||||
|
||||
/**
|
||||
* fiemap_check_flags - check validity of requested flags for fiemap
|
||||
* fiemap_prep - check validity of requested flags for fiemap
|
||||
* @inode: Inode to operate on
|
||||
* @fieinfo: Fiemap context passed into ->fiemap
|
||||
* @fs_flags: Set of fiemap flags that the file system understands
|
||||
* @start: Start of the mapped range
|
||||
* @len: Length of the mapped range, can be truncated by this function.
|
||||
* @supported_flags: Set of fiemap flags that the file system understands
|
||||
*
|
||||
* Called from file system ->fiemap callback. This will compute the
|
||||
* intersection of valid fiemap flags and those that the fs supports. That
|
||||
* value is then compared against the user supplied flags. In case of bad user
|
||||
* flags, the invalid values will be written into the fieinfo structure, and
|
||||
* -EBADR is returned, which tells ioctl_fiemap() to return those values to
|
||||
* userspace. For this reason, a return code of -EBADR should be preserved.
|
||||
* This function must be called from each ->fiemap instance to validate the
|
||||
* fiemap request against the file system parameters.
|
||||
*
|
||||
* Returns 0 on success, -EBADR on bad flags.
|
||||
* Returns 0 on success, or a negative error on failure.
|
||||
*/
|
||||
int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags)
|
||||
int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 *len, u32 supported_flags)
|
||||
{
|
||||
u64 maxbytes = inode->i_sb->s_maxbytes;
|
||||
u32 incompat_flags;
|
||||
int ret = 0;
|
||||
|
||||
incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags);
|
||||
if (incompat_flags) {
|
||||
fieinfo->fi_flags = incompat_flags;
|
||||
return -EBADR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fiemap_check_flags);
|
||||
|
||||
static int fiemap_check_ranges(struct super_block *sb,
|
||||
u64 start, u64 len, u64 *new_len)
|
||||
{
|
||||
u64 maxbytes = (u64) sb->s_maxbytes;
|
||||
|
||||
*new_len = len;
|
||||
|
||||
if (len == 0)
|
||||
if (*len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (start > maxbytes)
|
||||
return -EFBIG;
|
||||
|
||||
/*
|
||||
* Shrink request scope to what the fs can actually handle.
|
||||
*/
|
||||
if (len > maxbytes || (maxbytes - len) < start)
|
||||
*new_len = maxbytes - start;
|
||||
if (*len > maxbytes || (maxbytes - *len) < start)
|
||||
*len = maxbytes - start;
|
||||
|
||||
return 0;
|
||||
supported_flags |= FIEMAP_FLAG_SYNC;
|
||||
supported_flags &= FIEMAP_FLAGS_COMPAT;
|
||||
incompat_flags = fieinfo->fi_flags & ~supported_flags;
|
||||
if (incompat_flags) {
|
||||
fieinfo->fi_flags = incompat_flags;
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC)
|
||||
ret = filemap_write_and_wait(inode->i_mapping);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(fiemap_prep);
|
||||
|
||||
static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
|
||||
{
|
||||
struct fiemap fiemap;
|
||||
struct fiemap_extent_info fieinfo = { 0, };
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
u64 len;
|
||||
int error;
|
||||
|
||||
if (!inode->i_op->fiemap)
|
||||
@ -214,24 +209,13 @@ static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
|
||||
if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS)
|
||||
return -EINVAL;
|
||||
|
||||
error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length,
|
||||
&len);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
fieinfo.fi_flags = fiemap.fm_flags;
|
||||
fieinfo.fi_extents_max = fiemap.fm_extent_count;
|
||||
fieinfo.fi_extents_start = ufiemap->fm_extents;
|
||||
|
||||
if (fiemap.fm_extent_count != 0 &&
|
||||
!access_ok(fieinfo.fi_extents_start,
|
||||
fieinfo.fi_extents_max * sizeof(struct fiemap_extent)))
|
||||
return -EFAULT;
|
||||
error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start,
|
||||
fiemap.fm_length);
|
||||
|
||||
if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC)
|
||||
filemap_write_and_wait(inode->i_mapping);
|
||||
|
||||
error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len);
|
||||
fiemap.fm_flags = fieinfo.fi_flags;
|
||||
fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped;
|
||||
if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap)))
|
||||
@ -307,8 +291,7 @@ static inline loff_t blk_to_logical(struct inode *inode, sector_t blk)
|
||||
* If you use this function directly, you need to do your own locking. Use
|
||||
* generic_block_fiemap if you want the locking done for you.
|
||||
*/
|
||||
|
||||
int __generic_block_fiemap(struct inode *inode,
|
||||
static int __generic_block_fiemap(struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo, loff_t start,
|
||||
loff_t len, get_block_t *get_block)
|
||||
{
|
||||
@ -320,7 +303,7 @@ int __generic_block_fiemap(struct inode *inode,
|
||||
bool past_eof = false, whole_file = false;
|
||||
int ret = 0;
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
|
||||
ret = fiemap_prep(inode, fieinfo, start, &len, FIEMAP_FLAG_SYNC);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -453,7 +436,6 @@ int __generic_block_fiemap(struct inode *inode,
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(__generic_block_fiemap);
|
||||
|
||||
/**
|
||||
* generic_block_fiemap - FIEMAP for block based inodes
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/iomap.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
struct fiemap_ctx {
|
||||
struct fiemap_extent_info *fi;
|
||||
@ -65,7 +66,7 @@ iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
|
||||
}
|
||||
|
||||
int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
|
||||
loff_t start, loff_t len, const struct iomap_ops *ops)
|
||||
u64 start, u64 len, const struct iomap_ops *ops)
|
||||
{
|
||||
struct fiemap_ctx ctx;
|
||||
loff_t ret;
|
||||
@ -74,16 +75,10 @@ int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi,
|
||||
ctx.fi = fi;
|
||||
ctx.prev.type = IOMAP_HOLE;
|
||||
|
||||
ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC);
|
||||
ret = fiemap_prep(inode, fi, start, &len, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (fi->fi_flags & FIEMAP_FLAG_SYNC) {
|
||||
ret = filemap_write_and_wait(inode->i_mapping);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx,
|
||||
iomap_fiemap_actor);
|
||||
|
@ -541,17 +541,24 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
|
||||
}
|
||||
EXPORT_SYMBOL(jbd2_journal_start);
|
||||
|
||||
static void __jbd2_journal_unreserve_handle(handle_t *handle)
|
||||
static void __jbd2_journal_unreserve_handle(handle_t *handle, transaction_t *t)
|
||||
{
|
||||
journal_t *journal = handle->h_journal;
|
||||
|
||||
WARN_ON(!handle->h_reserved);
|
||||
sub_reserved_credits(journal, handle->h_total_credits);
|
||||
if (t)
|
||||
atomic_sub(handle->h_total_credits, &t->t_outstanding_credits);
|
||||
}
|
||||
|
||||
void jbd2_journal_free_reserved(handle_t *handle)
|
||||
{
|
||||
__jbd2_journal_unreserve_handle(handle);
|
||||
journal_t *journal = handle->h_journal;
|
||||
|
||||
/* Get j_state_lock to pin running transaction if it exists */
|
||||
read_lock(&journal->j_state_lock);
|
||||
__jbd2_journal_unreserve_handle(handle, journal->j_running_transaction);
|
||||
read_unlock(&journal->j_state_lock);
|
||||
jbd2_free_handle(handle);
|
||||
}
|
||||
EXPORT_SYMBOL(jbd2_journal_free_reserved);
|
||||
@ -722,7 +729,8 @@ static void stop_this_handle(handle_t *handle)
|
||||
atomic_sub(handle->h_total_credits,
|
||||
&transaction->t_outstanding_credits);
|
||||
if (handle->h_rsv_handle)
|
||||
__jbd2_journal_unreserve_handle(handle->h_rsv_handle);
|
||||
__jbd2_journal_unreserve_handle(handle->h_rsv_handle,
|
||||
transaction);
|
||||
if (atomic_dec_and_test(&transaction->t_updates))
|
||||
wake_up(&journal->j_wait_updates);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include "nilfs.h"
|
||||
#include "btnode.h"
|
||||
#include "segment.h"
|
||||
@ -996,7 +997,7 @@ int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
unsigned int blkbits = inode->i_blkbits;
|
||||
int ret, n;
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
|
||||
ret = fiemap_prep(inode, fieinfo, start, &len, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -733,8 +733,6 @@ static int ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OCFS2_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC)
|
||||
|
||||
int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 map_start, u64 map_len)
|
||||
{
|
||||
@ -746,7 +744,7 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
struct buffer_head *di_bh = NULL;
|
||||
struct ocfs2_extent_rec rec;
|
||||
|
||||
ret = fiemap_check_flags(fieinfo, OCFS2_FIEMAP_FLAGS);
|
||||
ret = fiemap_prep(inode, fieinfo, map_start, &map_len, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include "overlayfs.h"
|
||||
|
||||
|
||||
@ -479,10 +480,6 @@ static int ovl_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
old_cred = ovl_override_creds(inode->i_sb);
|
||||
|
||||
if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC)
|
||||
filemap_write_and_wait(realinode->i_mapping);
|
||||
|
||||
err = realinode->i_op->fiemap(realinode, fieinfo, start, len);
|
||||
revert_creds(old_cred);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fiemap.h>
|
||||
|
||||
/*
|
||||
* Directories have different lock order w.r.t. mmap_sem compared to regular
|
||||
|
25
include/linux/fiemap.h
Normal file
25
include/linux/fiemap.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_FIEMAP_H
|
||||
#define _LINUX_FIEMAP_H 1
|
||||
|
||||
#include <uapi/linux/fiemap.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
struct fiemap_extent_info {
|
||||
unsigned int fi_flags; /* Flags as passed from user */
|
||||
unsigned int fi_extents_mapped; /* Number of mapped extents */
|
||||
unsigned int fi_extents_max; /* Size of fiemap_extent array */
|
||||
struct fiemap_extent __user *fi_extents_start; /* Start of
|
||||
fiemap_extent array */
|
||||
};
|
||||
|
||||
int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 *len, u32 supported_flags);
|
||||
int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
|
||||
u64 phys, u64 len, u32 flags);
|
||||
|
||||
int generic_block_fiemap(struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo, u64 start, u64 len,
|
||||
get_block_t *get_block);
|
||||
|
||||
#endif /* _LINUX_FIEMAP_H 1 */
|
@ -24,7 +24,6 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/fiemap.h>
|
||||
#include <linux/rculist_bl.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/shrinker.h>
|
||||
@ -48,6 +47,7 @@ struct backing_dev_info;
|
||||
struct bdi_writeback;
|
||||
struct bio;
|
||||
struct export_operations;
|
||||
struct fiemap_extent_info;
|
||||
struct hd_geometry;
|
||||
struct iovec;
|
||||
struct kiocb;
|
||||
@ -1755,19 +1755,6 @@ extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
|
||||
extern void inode_init_owner(struct inode *inode, const struct inode *dir,
|
||||
umode_t mode);
|
||||
extern bool may_open_dev(const struct path *path);
|
||||
/*
|
||||
* VFS FS_IOC_FIEMAP helper definitions.
|
||||
*/
|
||||
struct fiemap_extent_info {
|
||||
unsigned int fi_flags; /* Flags as passed from user */
|
||||
unsigned int fi_extents_mapped; /* Number of mapped extents */
|
||||
unsigned int fi_extents_max; /* Size of fiemap_extent array */
|
||||
struct fiemap_extent __user *fi_extents_start; /* Start of
|
||||
fiemap_extent array */
|
||||
};
|
||||
int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
|
||||
u64 phys, u64 len, u32 flags);
|
||||
int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
|
||||
|
||||
/*
|
||||
* This is the "filldir" function type, used by readdir() to let
|
||||
@ -3323,14 +3310,6 @@ static inline int vfs_fstat(int fd, struct kstat *stat)
|
||||
extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
|
||||
extern int vfs_readlink(struct dentry *, char __user *, int);
|
||||
|
||||
extern int __generic_block_fiemap(struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo,
|
||||
loff_t start, loff_t len,
|
||||
get_block_t *get_block);
|
||||
extern int generic_block_fiemap(struct inode *inode,
|
||||
struct fiemap_extent_info *fieinfo, u64 start,
|
||||
u64 len, get_block_t *get_block);
|
||||
|
||||
extern struct file_system_type *get_filesystem(struct file_system_type *fs);
|
||||
extern void put_filesystem(struct file_system_type *fs);
|
||||
extern struct file_system_type *get_fs_type(const char *name);
|
||||
|
@ -177,7 +177,7 @@ int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero,
|
||||
vm_fault_t iomap_page_mkwrite(struct vm_fault *vmf,
|
||||
const struct iomap_ops *ops);
|
||||
int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
loff_t start, loff_t len, const struct iomap_ops *ops);
|
||||
u64 start, u64 len, const struct iomap_ops *ops);
|
||||
loff_t iomap_seek_hole(struct inode *inode, loff_t offset,
|
||||
const struct iomap_ops *ops);
|
||||
loff_t iomap_seek_data(struct inode *inode, loff_t offset,
|
||||
|
@ -197,6 +197,7 @@ void wakeup_flusher_threads(enum wb_reason reason);
|
||||
void wakeup_flusher_threads_bdi(struct backing_dev_info *bdi,
|
||||
enum wb_reason reason);
|
||||
void inode_wait_for_writeback(struct inode *inode);
|
||||
void inode_io_list_del(struct inode *inode);
|
||||
|
||||
/* writeback.h requires fs.h; it, too, is not included from here. */
|
||||
static inline void wait_on_inode(struct inode *inode)
|
||||
|
@ -35,7 +35,8 @@ struct partial_cluster;
|
||||
{ EXT4_MB_DELALLOC_RESERVED, "DELALLOC_RESV" }, \
|
||||
{ EXT4_MB_STREAM_ALLOC, "STREAM_ALLOC" }, \
|
||||
{ EXT4_MB_USE_ROOT_BLOCKS, "USE_ROOT_BLKS" }, \
|
||||
{ EXT4_MB_USE_RESERVED, "USE_RESV" })
|
||||
{ EXT4_MB_USE_RESERVED, "USE_RESV" }, \
|
||||
{ EXT4_MB_STRICT_CHECK, "STRICT_CHECK" })
|
||||
|
||||
#define show_map_flags(flags) __print_flags(flags, "|", \
|
||||
{ EXT4_GET_BLOCKS_CREATE, "CREATE" }, \
|
||||
@ -45,8 +46,10 @@ struct partial_cluster;
|
||||
{ EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \
|
||||
{ EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \
|
||||
{ EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \
|
||||
{ EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \
|
||||
{ EXT4_GET_BLOCKS_ZERO, "ZERO" })
|
||||
{ EXT4_GET_BLOCKS_CONVERT_UNWRITTEN, "CONVERT_UNWRITTEN" }, \
|
||||
{ EXT4_GET_BLOCKS_ZERO, "ZERO" }, \
|
||||
{ EXT4_GET_BLOCKS_IO_SUBMIT, "IO_SUBMIT" }, \
|
||||
{ EXT4_EX_NOCACHE, "EX_NOCACHE" })
|
||||
|
||||
/*
|
||||
* __print_flags() requires that all enum values be wrapped in the
|
||||
|
@ -9,8 +9,8 @@
|
||||
* Andreas Dilger <adilger@sun.com>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FIEMAP_H
|
||||
#define _LINUX_FIEMAP_H
|
||||
#ifndef _UAPI_LINUX_FIEMAP_H
|
||||
#define _UAPI_LINUX_FIEMAP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
@ -67,4 +67,4 @@ struct fiemap {
|
||||
#define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other
|
||||
* files. */
|
||||
|
||||
#endif /* _LINUX_FIEMAP_H */
|
||||
#endif /* _UAPI_LINUX_FIEMAP_H */
|
||||
|
Loading…
Reference in New Issue
Block a user