From a1a4234b3ae94ab29e50aaf7e8b3a8de171ef966 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 11 Aug 2019 17:40:33 -0400 Subject: [PATCH] Add debugging ioctls that allow querying and flushing the extent status cache Signed-off-by: Theodore Ts'o --- add-clear_es_cache-ioctl | 104 +++++++++++ add-getstate-ioctl | 75 ++++++++ return-extent-cache-info-via-fiemap | 364 ++++++++++++++++++++++++++++++++++++ series | 3 + timestamps | 9 +- 5 files changed, 552 insertions(+), 3 deletions(-) create mode 100644 add-clear_es_cache-ioctl create mode 100644 add-getstate-ioctl create mode 100644 return-extent-cache-info-via-fiemap diff --git a/add-clear_es_cache-ioctl b/add-clear_es_cache-ioctl new file mode 100644 index 00000000..490b065c --- /dev/null +++ b/add-clear_es_cache-ioctl @@ -0,0 +1,104 @@ +ext4: add a new ioctl EXT4_IOC_CLEAR_ES_CACHE + +The new ioctl EXT4_IOC_CLEAR_ES_CACHE will force an inode's extent +status cache to be cleared out. This is intended for use for +debugging. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/ext4.h | 2 ++ + fs/ext4/extents_status.c | 28 ++++++++++++++++++++++++++++ + fs/ext4/extents_status.h | 1 + + fs/ext4/ioctl.c | 9 +++++++++ + 4 files changed, 40 insertions(+) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index bf660aa7a9e0..b22f24f1d365 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -649,6 +649,8 @@ enum { + #define EXT4_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY + #define EXT4_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT + #define EXT4_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY ++/* ioctl codes 19--39 are reserved for fscrypt */ ++#define EXT4_IOC_CLEAR_ES_CACHE _IO('f', 40) + + #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR + #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR +diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c +index 7521de2dcf3a..02cc8eb3eb0e 100644 +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -1374,6 +1374,34 @@ static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan) + return nr_shrunk; + } + ++/* ++ * Called to support EXT4_IOC_CLEAR_ES_CACHE. We can only remove ++ * discretionary entries from the extent status cache. (Some entries ++ * must be present for proper operations.) ++ */ ++void ext4_clear_inode_es(struct inode *inode) ++{ ++ struct ext4_inode_info *ei = EXT4_I(inode); ++ struct extent_status *es; ++ struct ext4_es_tree *tree; ++ struct rb_node *node; ++ ++ write_lock(&ei->i_es_lock); ++ tree = &EXT4_I(inode)->i_es_tree; ++ tree->cache_es = NULL; ++ node = rb_first(&tree->root); ++ while (node) { ++ es = rb_entry(node, struct extent_status, rb_node); ++ node = rb_next(node); ++ if (!ext4_es_is_delayed(es)) { ++ rb_erase(&es->rb_node, &tree->root); ++ ext4_es_free_extent(inode, es); ++ } ++ } ++ ext4_clear_inode_state(inode, EXT4_STATE_EXT_PRECACHED); ++ write_unlock(&ei->i_es_lock); ++} ++ + #ifdef ES_DEBUG__ + static void ext4_print_pending_tree(struct inode *inode) + { +diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h +index 131a8b7df265..e16785f431e7 100644 +--- a/fs/ext4/extents_status.h ++++ b/fs/ext4/extents_status.h +@@ -248,5 +248,6 @@ extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len); + extern void ext4_es_remove_blks(struct inode *inode, ext4_lblk_t lblk, + ext4_lblk_t len); ++extern void ext4_clear_inode_es(struct inode *inode); + + #endif /* _EXT4_EXTENTS_STATUS_H */ +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index 442f7ef873fc..15b1047878ab 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -1115,6 +1115,14 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + case EXT4_IOC_GET_ENCRYPTION_POLICY: + return fscrypt_ioctl_get_policy(filp, (void __user *)arg); + ++ case EXT4_IOC_CLEAR_ES_CACHE: ++ { ++ if (!inode_owner_or_capable(inode)) ++ return -EACCES; ++ ext4_clear_inode_es(inode); ++ return 0; ++ } ++ + case EXT4_IOC_FSGETXATTR: + { + struct fsxattr fa; +@@ -1233,6 +1241,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case EXT4_IOC_GET_ENCRYPTION_POLICY: + case EXT4_IOC_SHUTDOWN: + case FS_IOC_GETFSMAP: ++ case EXT4_IOC_CLEAR_ES_CACHE: + break; + default: + return -ENOIOCTLCMD; diff --git a/add-getstate-ioctl b/add-getstate-ioctl new file mode 100644 index 00000000..8ba4aad2 --- /dev/null +++ b/add-getstate-ioctl @@ -0,0 +1,75 @@ +ext4: add a new ioctl EXT4_IOC_GETSTATE + +The new ioctl EXT4_IOC_GETSTATE returns some of the dynamic state of +an ext4 inode for debugging purposes. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/ext4.h | 11 +++++++++++ + fs/ext4/ioctl.c | 17 +++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index b22f24f1d365..ee296797bcd2 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -651,6 +651,7 @@ enum { + #define EXT4_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY + /* ioctl codes 19--39 are reserved for fscrypt */ + #define EXT4_IOC_CLEAR_ES_CACHE _IO('f', 40) ++#define EXT4_IOC_GETSTATE _IOW('f', 41, __u32) + + #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR + #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR +@@ -664,6 +665,16 @@ enum { + #define EXT4_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ + #define EXT4_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ + ++/* ++ * Flags returned by EXT4_IOC_GETSTATE ++ * ++ * We only expose to userspace a subset of the state flags in ++ * i_state_flags ++ */ ++#define EXT4_STATE_FLAG_EXT_PRECACHED 0x00000001 ++#define EXT4_STATE_FLAG_NEW 0x00000002 ++#define EXT4_STATE_FLAG_NEWENTRY 0x00000004 ++#define EXT4_STATE_FLAG_DA_ALLOC_CLOSE 0x00000008 + + #if defined(__KERNEL__) && defined(CONFIG_COMPAT) + /* +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index 15b1047878ab..ffb7bde4900d 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -1123,6 +1123,22 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + return 0; + } + ++ case EXT4_IOC_GETSTATE: ++ { ++ __u32 state = 0; ++ ++ if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED)) ++ state |= EXT4_STATE_FLAG_EXT_PRECACHED; ++ if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) ++ state |= EXT4_STATE_FLAG_NEW; ++ if (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) ++ state |= EXT4_STATE_FLAG_NEWENTRY; ++ if (ext4_test_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE)) ++ state |= EXT4_STATE_FLAG_DA_ALLOC_CLOSE; ++ ++ return put_user(state, (__u32 __user *) arg); ++ } ++ + case EXT4_IOC_FSGETXATTR: + { + struct fsxattr fa; +@@ -1242,6 +1258,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case EXT4_IOC_SHUTDOWN: + case FS_IOC_GETFSMAP: + case EXT4_IOC_CLEAR_ES_CACHE: ++ case EXT4_IOC_GETSTATE: + break; + default: + return -ENOIOCTLCMD; diff --git a/return-extent-cache-info-via-fiemap b/return-extent-cache-info-via-fiemap new file mode 100644 index 00000000..07bf24cf --- /dev/null +++ b/return-extent-cache-info-via-fiemap @@ -0,0 +1,364 @@ +ext4: add new ioctl EXT4_IOC_GET_ES_CACHE + +For debugging reasons, it's useful to know the contents of the extent +cache. Since the extent cache contains much of what is in the fiemap +ioctl, use an fiemap-style interface to return this information. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/ext4.h | 10 ++++++++ + fs/ext4/extents.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- + fs/ext4/extents_status.c | 10 ++++++++ + fs/ext4/extents_status.h | 1 + + fs/ext4/inode.c | 6 ++--- + fs/ext4/ioctl.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 6 files changed, 182 insertions(+), 11 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index ee296797bcd2..e2d8ad27f4d1 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -652,6 +652,7 @@ enum { + /* ioctl codes 19--39 are reserved for fscrypt */ + #define EXT4_IOC_CLEAR_ES_CACHE _IO('f', 40) + #define EXT4_IOC_GETSTATE _IOW('f', 41, __u32) ++#define EXT4_IOC_GET_ES_CACHE _IOWR('f', 42, struct fiemap) + + #define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR + #define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR +@@ -692,6 +693,12 @@ enum { + #define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION + #endif + ++/* ++ * Returned by EXT4_IOC_GET_ES_CACHE as an additional possible flag. ++ * It indicates that the entry in extent status cache is for a hole. ++ */ ++#define EXT4_FIEMAP_EXTENT_HOLE 0x08000000 ++ + /* Max physical block we can address w/o extents */ + #define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF + +@@ -3258,6 +3265,9 @@ extern int ext4_ext_check_inode(struct inode *inode); + extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path); + extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + __u64 start, __u64 len); ++extern int ext4_get_es_cache(struct inode *inode, ++ struct fiemap_extent_info *fieinfo, ++ __u64 start, __u64 len); + extern int ext4_ext_precache(struct inode *inode); + extern int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len); + extern int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len); +diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c +index 92266a2da7d6..0620d495fd8a 100644 +--- a/fs/ext4/extents.c ++++ b/fs/ext4/extents.c +@@ -2315,6 +2315,52 @@ static int ext4_fill_fiemap_extents(struct inode *inode, + return err; + } + ++static int ext4_fill_es_cache_info(struct inode *inode, ++ ext4_lblk_t block, ext4_lblk_t num, ++ struct fiemap_extent_info *fieinfo) ++{ ++ ext4_lblk_t next, end = block + num - 1; ++ struct extent_status es; ++ unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; ++ unsigned int flags; ++ int err; ++ ++ while (block <= end) { ++ next = 0; ++ flags = 0; ++ if (!ext4_es_lookup_extent(inode, block, &next, &es)) ++ break; ++ if (ext4_es_is_unwritten(&es)) ++ flags |= FIEMAP_EXTENT_UNWRITTEN; ++ if (ext4_es_is_delayed(&es)) ++ flags |= (FIEMAP_EXTENT_DELALLOC | ++ FIEMAP_EXTENT_UNKNOWN); ++ if (ext4_es_is_hole(&es)) ++ flags |= EXT4_FIEMAP_EXTENT_HOLE; ++ if (next == 0) ++ flags |= FIEMAP_EXTENT_LAST; ++ if (flags & (FIEMAP_EXTENT_DELALLOC| ++ EXT4_FIEMAP_EXTENT_HOLE)) ++ es.es_pblk = 0; ++ else ++ es.es_pblk = ext4_es_pblock(&es); ++ err = fiemap_fill_next_extent(fieinfo, ++ (__u64)es.es_lblk << blksize_bits, ++ (__u64)es.es_pblk << blksize_bits, ++ (__u64)es.es_len << blksize_bits, ++ flags); ++ if (next == 0) ++ break; ++ block = next; ++ if (err < 0) ++ return err; ++ if (err == 1) ++ return 0; ++ } ++ return 0; ++} ++ ++ + /* + * ext4_ext_determine_hole - determine hole around given block + * @inode: inode we lookup in +@@ -5017,8 +5063,6 @@ static int ext4_find_delayed_extent(struct inode *inode, + + return next_del; + } +-/* fiemap flags we can handle specified here */ +-#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) + + static int ext4_xattr_fiemap(struct inode *inode, + struct fiemap_extent_info *fieinfo) +@@ -5055,10 +5099,16 @@ static int ext4_xattr_fiemap(struct inode *inode, + return (error < 0 ? error : 0); + } + +-int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, +- __u64 start, __u64 len) ++static int _ext4_fiemap(struct inode *inode, ++ struct fiemap_extent_info *fieinfo, ++ __u64 start, __u64 len, ++ int (*fill)(struct inode *, ext4_lblk_t, ++ ext4_lblk_t, ++ struct fiemap_extent_info *)) + { + ext4_lblk_t start_blk; ++ u32 ext4_fiemap_flags = FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR; ++ + int error = 0; + + if (ext4_has_inline_data(inode)) { +@@ -5075,14 +5125,18 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + error = ext4_ext_precache(inode); + if (error) + return error; ++ fieinfo->fi_flags &= ~FIEMAP_FLAG_CACHE; + } + + /* fallback to generic here if not in extents fmt */ +- if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) ++ if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) && ++ fill == ext4_fill_fiemap_extents) + return generic_block_fiemap(inode, fieinfo, start, len, + ext4_get_block); + +- if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS)) ++ if (fill == ext4_fill_es_cache_info) ++ ext4_fiemap_flags &= FIEMAP_FLAG_XATTR; ++ if (fiemap_check_flags(fieinfo, ext4_fiemap_flags)) + return -EBADR; + + if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { +@@ -5101,12 +5155,36 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, + * Walk the extent tree gathering extent information + * and pushing extents back to the user. + */ +- error = ext4_fill_fiemap_extents(inode, start_blk, +- len_blks, fieinfo); ++ error = fill(inode, start_blk, len_blks, fieinfo); + } + return error; + } + ++int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, ++ __u64 start, __u64 len) ++{ ++ return _ext4_fiemap(inode, fieinfo, start, len, ++ ext4_fill_fiemap_extents); ++} ++ ++int ext4_get_es_cache(struct inode *inode, struct fiemap_extent_info *fieinfo, ++ __u64 start, __u64 len) ++{ ++ if (ext4_has_inline_data(inode)) { ++ int has_inline; ++ ++ down_read(&EXT4_I(inode)->xattr_sem); ++ has_inline = ext4_has_inline_data(inode); ++ up_read(&EXT4_I(inode)->xattr_sem); ++ if (has_inline) ++ return 0; ++ } ++ ++ return _ext4_fiemap(inode, fieinfo, start, len, ++ ext4_fill_es_cache_info); ++} ++ ++ + /* + * ext4_access_path: + * Function to access the path buffer for marking it dirty. +diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c +index 02cc8eb3eb0e..a959adc59bcd 100644 +--- a/fs/ext4/extents_status.c ++++ b/fs/ext4/extents_status.c +@@ -899,6 +899,7 @@ void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, + * Return: 1 on found, 0 on not + */ + int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, ++ ext4_lblk_t *next_lblk, + struct extent_status *es) + { + struct ext4_es_tree *tree; +@@ -948,6 +949,15 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, + if (!ext4_es_is_referenced(es1)) + ext4_es_set_referenced(es1); + stats->es_stats_cache_hits++; ++ if (next_lblk) { ++ node = rb_next(&es1->rb_node); ++ if (node) { ++ es1 = rb_entry(node, struct extent_status, ++ rb_node); ++ *next_lblk = es1->es_lblk; ++ } else ++ *next_lblk = 0; ++ } + } else { + stats->es_stats_cache_misses++; + } +diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h +index e16785f431e7..eb56a1289031 100644 +--- a/fs/ext4/extents_status.h ++++ b/fs/ext4/extents_status.h +@@ -140,6 +140,7 @@ extern void ext4_es_find_extent_range(struct inode *inode, + ext4_lblk_t lblk, ext4_lblk_t end, + struct extent_status *es); + extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, ++ ext4_lblk_t *next_lblk, + struct extent_status *es); + extern bool ext4_es_scan_range(struct inode *inode, + int (*matching_fn)(struct extent_status *es), +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index a6523516d681..4b92c7603907 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -527,7 +527,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, + return -EFSCORRUPTED; + + /* Lookup extent status tree firstly */ +- if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { ++ if (ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) { + if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { + map->m_pblk = ext4_es_pblock(&es) + + map->m_lblk - es.es_lblk; +@@ -695,7 +695,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, + * extent status tree. + */ + if ((flags & EXT4_GET_BLOCKS_PRE_IO) && +- ext4_es_lookup_extent(inode, map->m_lblk, &es)) { ++ ext4_es_lookup_extent(inode, map->m_lblk, NULL, &es)) { + if (ext4_es_is_written(&es)) + goto out_sem; + } +@@ -1868,7 +1868,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, + (unsigned long) map->m_lblk); + + /* Lookup extent status tree firstly */ +- if (ext4_es_lookup_extent(inode, iblock, &es)) { ++ if (ext4_es_lookup_extent(inode, iblock, NULL, &es)) { + if (ext4_es_is_hole(&es)) { + retval = 0; + down_read(&EXT4_I(inode)->i_data_sem); +diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c +index ffb7bde4900d..d6242b7b8718 100644 +--- a/fs/ext4/ioctl.c ++++ b/fs/ext4/ioctl.c +@@ -745,6 +745,74 @@ static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa) + fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid); + } + ++/* copied from fs/ioctl.c */ ++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) ++ 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; ++ ++ return 0; ++} ++ ++/* So that the fiemap access checks can't overflow on 32 bit machines. */ ++#define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) ++ ++static int ext4_ioctl_get_es_cache(struct file *filp, unsigned long arg) ++{ ++ struct fiemap fiemap; ++ struct fiemap __user *ufiemap = (struct fiemap __user *) arg; ++ struct fiemap_extent_info fieinfo = { 0, }; ++ struct inode *inode = file_inode(filp); ++ struct super_block *sb = inode->i_sb; ++ u64 len; ++ int error; ++ ++ if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap))) ++ return -EFAULT; ++ ++ 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; ++ ++ if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) ++ filemap_write_and_wait(inode->i_mapping); ++ ++ error = ext4_get_es_cache(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))) ++ error = -EFAULT; ++ ++ return error; ++} ++ + long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + { + struct inode *inode = file_inode(filp); +@@ -1139,6 +1207,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + return put_user(state, (__u32 __user *) arg); + } + ++ case EXT4_IOC_GET_ES_CACHE: ++ return ext4_ioctl_get_es_cache(filp, arg); ++ + case EXT4_IOC_FSGETXATTR: + { + struct fsxattr fa; +@@ -1259,6 +1330,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) + case FS_IOC_GETFSMAP: + case EXT4_IOC_CLEAR_ES_CACHE: + case EXT4_IOC_GETSTATE: ++ case EXT4_IOC_GET_ES_CACHE: + break; + default: + return -ENOIOCTLCMD; diff --git a/series b/series index e70e5605..92300fa4 100644 --- a/series +++ b/series @@ -3,6 +3,9 @@ fix-warning-when-turn-on-dioread_nolock-and-inline_data remove-unnecessary-error-check do-not-descrease-bufferheads-refcount +add-clear_es_cache-ioctl +add-getstate-ioctl +return-extent-cache-info-via-fiemap #################################################### # unstable patches diff --git a/timestamps b/timestamps index 4213692e..5925963a 100755 --- a/timestamps +++ b/timestamps @@ -14,7 +14,10 @@ touch -d @1558930766 save-patch touch -d @1561168680 stable-boundary touch -d @1565015214 fix-warning-when-turn-on-dioread_nolock-and-inline_data touch -d @1565016977 remove-unnecessary-error-check -touch -d @1565279325 series touch -d @1565279410 do-not-descrease-bufferheads-refcount -touch -d @1565279416 status -touch -d @1565279424 timestamps +touch -d @1565538957 series +touch -d @1565539144 add-clear_es_cache-ioctl +touch -d @1565539237 add-getstate-ioctl +touch -d @1565546306 return-extent-cache-info-via-fiemap +touch -d @1565553008 status +touch -d @1565559606 timestamps -- 2.11.4.GIT