[PATCH 2/2] jffs2: Provide jffs2_sync files to track gc POLL progress

From: Theuns Verwoerd
Date: Thu Jul 19 2018 - 19:50:28 EST


When executing secure deletion under JFFS2 via the -POLL forced cleanup
option, userspace may need to know when the process has safely completed.
Provide debugfs files per mount that, when read, blocks while cleanup
is in progress: once the read completes it is safe to assume that all
obsoleted sensitive information has been erased.

If CONFIG_JFFS2_FS_SYNC is configured, create
/sys/kernel/debug/jffs2_sync_<fs name> files that block on read
while forced gc is in progress.

Signed-off-by: Theuns Verwoerd <theuns.verwoerd@xxxxxxxxxxxxxxxxxxx>
---
fs/jffs2/Kconfig | 8 ++++++++
fs/jffs2/super.c | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)

diff --git a/fs/jffs2/Kconfig b/fs/jffs2/Kconfig
index ad850c5bf2ca..191272729f06 100644
--- a/fs/jffs2/Kconfig
+++ b/fs/jffs2/Kconfig
@@ -96,6 +96,14 @@ config JFFS2_FS_SECURITY
If you are not using a security module that requires using
extended attributes for file security labels, say N.

+config JFFS2_FS_SYNC
+ bool "JFFS2 jffs2_sync file support"
+ depends on JFFS2_FS
+ help
+ This enables creation of jffs2_sync files for tracking
+ POLL forced garbage collection. It is used as part of FIPS
+ secure deletion support.
+
config JFFS2_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2"
depends on JFFS2_FS
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 87bdf0f4cba1..264f68ab2e91 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -27,6 +27,7 @@
#include <linux/namei.h>
#include <linux/seq_file.h>
#include <linux/exportfs.h>
+#include <linux/debugfs.h>
#include "compr.h"
#include "nodelist.h"

@@ -34,6 +35,26 @@ static void jffs2_put_super(struct super_block *);

static struct kmem_cache *jffs2_inode_cachep;

+#ifdef CONFIG_JFFS2_FS_SYNC
+#define JFFS2_FS_SYNC_NAME "jffs2_sync"
+static struct dentry *jffs2_debugfs_dir;
+
+ssize_t jffs2_sync_file_read(struct file *f,
+ char __user *b, size_t len, loff_t *ofs)
+{
+ struct jffs2_sb_info *c = file_inode(f)->i_private;
+
+ while (c->tidemark)
+ schedule();
+
+ return 0;
+}
+const struct file_operations jffs2_sync_ops = {
+ .owner = THIS_MODULE,
+ .read = jffs2_sync_file_read,
+};
+#endif
+
static struct inode *jffs2_alloc_inode(struct super_block *sb)
{
struct jffs2_inode_info *f;
@@ -307,6 +328,17 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
sb->s_flags |= SB_POSIXACL;
#endif
ret = jffs2_do_fill_super(sb, data, silent);
+
+#ifdef CONFIG_JFFS2_FS_SYNC
+ if (jffs2_debugfs_dir) {
+ char fname[128];
+
+ snprintf(fname, sizeof(fname), "%s_%s",
+ JFFS2_FS_SYNC_NAME, sb->s_mtd->name);
+ debugfs_create_file(fname, 0444,
+ jffs2_debugfs_dir, c, &jffs2_sync_ops);
+ }
+#endif
return ret;
}

@@ -405,6 +437,11 @@ static int __init init_jffs2_fs(void)
pr_err("error: Failed to register filesystem\n");
goto out_slab;
}
+
+#ifdef CONFIG_JFFS2_FS_SYNC
+ jffs2_debugfs_dir = debugfs_create_dir("jffs2", NULL);
+#endif
+
return 0;

out_slab:
@@ -419,6 +456,9 @@ static int __init init_jffs2_fs(void)
static void __exit exit_jffs2_fs(void)
{
unregister_filesystem(&jffs2_fs_type);
+#ifdef CONFIG_JFFS2_FS_SYNC
+ debugfs_remove_recursive(jffs2_debugfs_dir);
+#endif
jffs2_destroy_slab_caches();
jffs2_compressors_exit();

--
2.18.0