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.verwo...@alliedtelesis.co.nz>
---
 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

Reply via email to