[Devel] [PATCH RH7] ext4: add a new ioctl EXT4_IOC_CLEAR_ES_CACHE

Kirill Tkhai ktkhai at virtuozzo.com
Wed Aug 12 16:22:10 MSK 2020


From: Theodore Ts'o <tytso at mit.edu>

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 at 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 at 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(+)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7eda9c35b869..9202c5e1c078 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 d8dcc4201797..d78546e86d8c 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 0b85145043ca..2b08c4c9df97 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 a50016a75149..3356a5e9837a 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -754,6 +754,14 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	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:




More information about the Devel mailing list