[RHEL7,COMMIT] ext4: add a new ioctl EXT4_IOC_CLEAR_ES_CACHE

Submitted by Vasily Averin on Aug. 17, 2020, 6:52 a.m.

Details

Message ID 202008170652.07H6qbFv006395@vz7build.vvs.sw.ru
State New
Series "ext4: add a new ioctl EXT4_IOC_CLEAR_ES_CACHE"
Headers show

Commit Message

Vasily Averin Aug. 17, 2020, 6:52 a.m.
The commit is pushed to "branch-rh7-3.10.0-1127.18.2.vz7.163.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.18.2.vz7.163.2
------>
commit ea05de712cfc226de2a0f75bc18c1879871f08f2
Author: Theodore Ts'o <tytso@mit.edu>
Date:   Mon Aug 17 09:52:37 2020 +0300

    ext4: add a new ioctl EXT4_IOC_CLEAR_ES_CACHE
    
    ms commit b0c013e2928d
    
    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.
    
    https://jira.sw.ru/browse/PSBM-105347
    
    Signed-off-by: Theodore Ts'o <tytso@mit.edu>
    
    ext4_fiemap() on 3.10 uses information from cached extent tree
    only for checks of delayed extent status, while every of
    the checks waste much time iterating over all extents in tree
    (many rb_next). We will use this ioctl before filefrag (which
    populates the tree from start to end of file, so every iteration
    rb_next() path is rather short).
    
    Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 fs/ext4/ext4.h           |  2 ++
 fs/ext4/extents_status.c | 28 ++++++++++++++++++++++++++++
 fs/ext4/extents_status.h |  2 ++
 fs/ext4/ioctl.c          |  9 +++++++++
 4 files changed, 41 insertions(+)

Patch hide | download patch | download mbox

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7eda9c3..9202c5e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -624,6 +624,8 @@  enum {
 #define EXT4_IOC_RESIZE_FS		_IOW('f', 16, __u64)
 #define EXT4_IOC_SWAP_BOOT		_IO('f', 17)
 #define EXT4_IOC_PRECACHE_EXTENTS	_IO('f', 18)
+/* ioctl codes 19--39 are reserved for fscrypt */
+#define EXT4_IOC_CLEAR_ES_CACHE		_IO('f', 40)
 #define EXT4_IOC_OPEN_BALLOON		_IO('f', 42)
 #define EXT4_IOC_MFSYNC			_IO('f', 43)
 #define EXT4_IOC_SET_RSV_BLOCKS		_IOW('f', 44, __u64)
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index d8dcc42..d78546e 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -1166,3 +1166,31 @@  static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan)
 	ei->i_es_tree.cache_es = NULL;
 	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);
+}
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
index 0b85145..2b08c4c 100644
--- a/fs/ext4/extents_status.h
+++ b/fs/ext4/extents_status.h
@@ -168,4 +168,6 @@  static inline void ext4_es_store_pblock_status(struct extent_status *es,
 extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi);
 extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi);
 
+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 a50016a..3356a5e 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -754,6 +754,14 @@  resize_out:
 	case EXT4_IOC_PRECACHE_EXTENTS:
 		return ext4_ext_precache(inode);
 
+	case EXT4_IOC_CLEAR_ES_CACHE:
+	{
+		if (!inode_owner_or_capable(inode))
+			return -EACCES;
+		ext4_clear_inode_es(inode);
+		return 0;
+	}
+
 	case EXT4_IOC_OPEN_BALLOON:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
@@ -912,6 +920,7 @@  long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case FITRIM:
 	case EXT4_IOC_RESIZE_FS:
 	case EXT4_IOC_PRECACHE_EXTENTS:
+	case EXT4_IOC_CLEAR_ES_CACHE:
 		break;
 	case FS_IOC_PFCACHE_OPEN:
 	case FS_IOC_PFCACHE_CLOSE: