All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/5] Add online file check feature
@ 2016-02-29  5:17 ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

When there are errors in the ocfs2 filesystem,
they are usually accompanied by the inode number which caused the error.
This inode number would be the input to fixing the file.
One of these options could be considered:
A file in the sys filesytem which would accept inode numbers.
This could be used to communication back what has to be fixed or is fixed.
You could write:
$# echo "<inode>" > /sys/fs/ocfs2/devname/filecheck/check
or
$# echo "<inode>" > /sys/fs/ocfs2/devname/filecheck/fix

Compare with third version, I add buffer_jbd() check in inode block fix/writing
dirty buffer back, make unsigned short type to unsigned int type for members
in ocfs2_filecheck_entry struct, add feature document in this patch set.
Compare with second version, I re-design filecheck sysfs interfaces, there
are three sysfs files(check, fix and set) under filecheck directory(see above),
sysfs will accept only one argument <inode>. Second, I adjust some code in
ocfs2_filecheck_repair_inode_block() function according to upstream feedback,
we cannot just add VALID_FL flag back as a inode block fix, then we will not
fix this field corruption currently until having a complete solution.
Compare with first version, I use strncasecmp instead of double strncmp
functions. Second, update the source file contribution vendor.

Gang He (5):
  ocfs2: export ocfs2_kset for online file check
  ocfs2: sysfile interfaces for online file check
  ocfs2: create/remove sysfile for online file check
  ocfs2: check/fix inode block for online file check
  ocfs2: add feature document for online file check

 .../filesystems/ocfs2-online-filecheck.txt         |  94 ++++
 fs/ocfs2/Makefile                                  |   3 +-
 fs/ocfs2/filecheck.c                               | 606 +++++++++++++++++++++
 fs/ocfs2/filecheck.h                               |  49 ++
 fs/ocfs2/inode.c                                   | 225 +++++++-
 fs/ocfs2/inode.h                                   |   3 +
 fs/ocfs2/ocfs2_trace.h                             |   2 +
 fs/ocfs2/stackglue.c                               |   3 +-
 fs/ocfs2/stackglue.h                               |   2 +
 fs/ocfs2/super.c                                   |   5 +
 10 files changed, 981 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/filesystems/ocfs2-online-filecheck.txt
 create mode 100644 fs/ocfs2/filecheck.c
 create mode 100644 fs/ocfs2/filecheck.h

-- 
2.1.2

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature
@ 2016-02-29  5:17 ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

When there are errors in the ocfs2 filesystem,
they are usually accompanied by the inode number which caused the error.
This inode number would be the input to fixing the file.
One of these options could be considered:
A file in the sys filesytem which would accept inode numbers.
This could be used to communication back what has to be fixed or is fixed.
You could write:
$# echo "<inode>" > /sys/fs/ocfs2/devname/filecheck/check
or
$# echo "<inode>" > /sys/fs/ocfs2/devname/filecheck/fix

Compare with third version, I add buffer_jbd() check in inode block fix/writing
dirty buffer back, make unsigned short type to unsigned int type for members
in ocfs2_filecheck_entry struct, add feature document in this patch set.
Compare with second version, I re-design filecheck sysfs interfaces, there
are three sysfs files(check, fix and set) under filecheck directory(see above),
sysfs will accept only one argument <inode>. Second, I adjust some code in
ocfs2_filecheck_repair_inode_block() function according to upstream feedback,
we cannot just add VALID_FL flag back as a inode block fix, then we will not
fix this field corruption currently until having a complete solution.
Compare with first version, I use strncasecmp instead of double strncmp
functions. Second, update the source file contribution vendor.

Gang He (5):
  ocfs2: export ocfs2_kset for online file check
  ocfs2: sysfile interfaces for online file check
  ocfs2: create/remove sysfile for online file check
  ocfs2: check/fix inode block for online file check
  ocfs2: add feature document for online file check

 .../filesystems/ocfs2-online-filecheck.txt         |  94 ++++
 fs/ocfs2/Makefile                                  |   3 +-
 fs/ocfs2/filecheck.c                               | 606 +++++++++++++++++++++
 fs/ocfs2/filecheck.h                               |  49 ++
 fs/ocfs2/inode.c                                   | 225 +++++++-
 fs/ocfs2/inode.h                                   |   3 +
 fs/ocfs2/ocfs2_trace.h                             |   2 +
 fs/ocfs2/stackglue.c                               |   3 +-
 fs/ocfs2/stackglue.h                               |   2 +
 fs/ocfs2/super.c                                   |   5 +
 10 files changed, 981 insertions(+), 11 deletions(-)
 create mode 100644 Documentation/filesystems/ocfs2-online-filecheck.txt
 create mode 100644 fs/ocfs2/filecheck.c
 create mode 100644 fs/ocfs2/filecheck.h

-- 
2.1.2

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check
  2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
@ 2016-02-29  5:17   ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Export ocfs2_kset object from ocfs2_stackglue kernel module,
then online file check code will create the related sysfiles
under ocfs2_kset object.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 fs/ocfs2/stackglue.c | 3 ++-
 fs/ocfs2/stackglue.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 5d965e8..13219ed 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -629,7 +629,8 @@ static struct attribute_group ocfs2_attr_group = {
 	.attrs = ocfs2_attrs,
 };
 
-static struct kset *ocfs2_kset;
+struct kset *ocfs2_kset;
+EXPORT_SYMBOL_GPL(ocfs2_kset);
 
 static void ocfs2_sysfs_exit(void)
 {
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h
index 66334a3..f2dce10 100644
--- a/fs/ocfs2/stackglue.h
+++ b/fs/ocfs2/stackglue.h
@@ -298,4 +298,6 @@ void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_p
 int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
 void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);
 
+extern struct kset *ocfs2_kset;
+
 #endif  /* STACKGLUE_H */
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check
@ 2016-02-29  5:17   ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Export ocfs2_kset object from ocfs2_stackglue kernel module,
then online file check code will create the related sysfiles
under ocfs2_kset object.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 fs/ocfs2/stackglue.c | 3 ++-
 fs/ocfs2/stackglue.h | 2 ++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 5d965e8..13219ed 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -629,7 +629,8 @@ static struct attribute_group ocfs2_attr_group = {
 	.attrs = ocfs2_attrs,
 };
 
-static struct kset *ocfs2_kset;
+struct kset *ocfs2_kset;
+EXPORT_SYMBOL_GPL(ocfs2_kset);
 
 static void ocfs2_sysfs_exit(void)
 {
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h
index 66334a3..f2dce10 100644
--- a/fs/ocfs2/stackglue.h
+++ b/fs/ocfs2/stackglue.h
@@ -298,4 +298,6 @@ void ocfs2_stack_glue_set_max_proto_version(struct ocfs2_protocol_version *max_p
 int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
 void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);
 
+extern struct kset *ocfs2_kset;
+
 #endif  /* STACKGLUE_H */
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
@ 2016-02-29  5:17   ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Implement online file check sysfile interfaces, e.g.
how to create the related sysfile according to device name,
how to display/handle file check request from the sysfile.

Signed-off-by: Gang He <ghe@suse.com>
---
 fs/ocfs2/Makefile    |   3 +-
 fs/ocfs2/filecheck.c | 606 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/filecheck.h |  49 +++++
 fs/ocfs2/inode.h     |   3 +
 4 files changed, 660 insertions(+), 1 deletion(-)
 create mode 100644 fs/ocfs2/filecheck.c
 create mode 100644 fs/ocfs2/filecheck.h

diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
index ce210d4..e27e652 100644
--- a/fs/ocfs2/Makefile
+++ b/fs/ocfs2/Makefile
@@ -41,7 +41,8 @@ ocfs2-objs := \
 	quota_local.o		\
 	quota_global.o		\
 	xattr.o			\
-	acl.o
+	acl.o	\
+	filecheck.o
 
 ocfs2_stackglue-objs := stackglue.o
 ocfs2_stack_o2cb-objs := stack_o2cb.o
diff --git a/fs/ocfs2/filecheck.c b/fs/ocfs2/filecheck.c
new file mode 100644
index 0000000..2cabbcf
--- /dev/null
+++ b/fs/ocfs2/filecheck.c
@@ -0,0 +1,606 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * filecheck.c
+ *
+ * Code which implements online file check.
+ *
+ * Copyright (C) 2016 SuSE.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/sysctl.h>
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "ocfs2_fs.h"
+#include "stackglue.h"
+#include "inode.h"
+
+#include "filecheck.h"
+
+
+/* File check error strings,
+ * must correspond with error number in header file.
+ */
+static const char * const ocfs2_filecheck_errs[] = {
+	"SUCCESS",
+	"FAILED",
+	"INPROGRESS",
+	"READONLY",
+	"INJBD",
+	"INVALIDINO",
+	"BLOCKECC",
+	"BLOCKNO",
+	"VALIDFLAG",
+	"GENERATION",
+	"UNSUPPORTED"
+};
+
+static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
+static LIST_HEAD(ocfs2_filecheck_sysfs_list);
+
+struct ocfs2_filecheck {
+	struct list_head fc_head;	/* File check entry list head */
+	spinlock_t fc_lock;
+	unsigned int fc_max;	/* Maximum number of entry in list */
+	unsigned int fc_size;	/* Current entry count in list */
+	unsigned int fc_done;	/* Finished entry count in list */
+};
+
+struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per mounting */
+	struct list_head fs_list;
+	atomic_t fs_count;
+	struct super_block *fs_sb;
+	struct kset *fs_devicekset;
+	struct kset *fs_fcheckkset;
+	struct ocfs2_filecheck *fs_fcheck;
+};
+
+#define OCFS2_FILECHECK_MAXSIZE		100
+#define OCFS2_FILECHECK_MINSIZE		10
+
+/* File check operation type */
+enum {
+	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
+	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
+	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
+};
+
+struct ocfs2_filecheck_entry {
+	struct list_head fe_list;
+	unsigned long fe_ino;
+	unsigned int fe_type;
+	unsigned int fe_done:1;
+	unsigned int fe_status:31;
+};
+
+struct ocfs2_filecheck_args {
+	unsigned int fa_type;
+	union {
+		unsigned long fa_ino;
+		unsigned int fa_len;
+	};
+};
+
+static const char *
+ocfs2_filecheck_error(int errno)
+{
+	if (!errno)
+		return ocfs2_filecheck_errs[errno];
+
+	BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
+	       errno > OCFS2_FILECHECK_ERR_END);
+	return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
+}
+
+static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf);
+static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count);
+static struct kobj_attribute ocfs2_attr_filecheck_chk =
+					__ATTR(check, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+static struct kobj_attribute ocfs2_attr_filecheck_fix =
+					__ATTR(fix, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+static struct kobj_attribute ocfs2_attr_filecheck_set =
+					__ATTR(set, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+
+static int ocfs2_filecheck_sysfs_wait(atomic_t *p)
+{
+	schedule();
+	return 0;
+}
+
+static void
+ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	struct ocfs2_filecheck_entry *p;
+
+	if (!atomic_dec_and_test(&entry->fs_count))
+		wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait,
+				 TASK_UNINTERRUPTIBLE);
+
+	spin_lock(&entry->fs_fcheck->fc_lock);
+	while (!list_empty(&entry->fs_fcheck->fc_head)) {
+		p = list_first_entry(&entry->fs_fcheck->fc_head,
+				     struct ocfs2_filecheck_entry, fe_list);
+		list_del(&p->fe_list);
+		BUG_ON(!p->fe_done); /* To free a undone file check entry */
+		kfree(p);
+	}
+	spin_unlock(&entry->fs_fcheck->fc_lock);
+
+	kset_unregister(entry->fs_fcheckkset);
+	kset_unregister(entry->fs_devicekset);
+	kfree(entry->fs_fcheck);
+	kfree(entry);
+}
+
+static void
+ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list);
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+}
+
+static int ocfs2_filecheck_sysfs_del(const char *devname)
+{
+	struct ocfs2_filecheck_sysfs_entry *p;
+
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
+		if (!strcmp(p->fs_sb->s_id, devname)) {
+			list_del(&p->fs_list);
+			spin_unlock(&ocfs2_filecheck_sysfs_lock);
+			ocfs2_filecheck_sysfs_free(p);
+			return 0;
+		}
+	}
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+	return 1;
+}
+
+static void
+ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	if (atomic_dec_and_test(&entry->fs_count))
+		wake_up_atomic_t(&entry->fs_count);
+}
+
+static struct ocfs2_filecheck_sysfs_entry *
+ocfs2_filecheck_sysfs_get(const char *devname)
+{
+	struct ocfs2_filecheck_sysfs_entry *p = NULL;
+
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
+		if (!strcmp(p->fs_sb->s_id, devname)) {
+			atomic_inc(&p->fs_count);
+			spin_unlock(&ocfs2_filecheck_sysfs_lock);
+			return p;
+		}
+	}
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+	return NULL;
+}
+
+int ocfs2_filecheck_create_sysfs(struct super_block *sb)
+{
+	int ret = 0;
+	struct kset *device_kset = NULL;
+	struct kset *fcheck_kset = NULL;
+	struct ocfs2_filecheck *fcheck = NULL;
+	struct ocfs2_filecheck_sysfs_entry *entry = NULL;
+	struct attribute **attrs = NULL;
+	struct attribute_group attrgp;
+
+	if (!ocfs2_kset)
+		return -ENOMEM;
+
+	attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
+	if (!attrs) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		attrs[0] = &ocfs2_attr_filecheck_chk.attr;
+		attrs[1] = &ocfs2_attr_filecheck_fix.attr;
+		attrs[2] = &ocfs2_attr_filecheck_set.attr;
+		attrs[3] = NULL;
+		memset(&attrgp, 0, sizeof(attrgp));
+		attrgp.attrs = attrs;
+	}
+
+	fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
+	if (!fcheck) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		INIT_LIST_HEAD(&fcheck->fc_head);
+		spin_lock_init(&fcheck->fc_lock);
+		fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
+		fcheck->fc_size = 0;
+		fcheck->fc_done = 0;
+	}
+
+	if (strlen(sb->s_id) <= 0) {
+		mlog(ML_ERROR,
+		"Cannot get device basename when create filecheck sysfs\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
+	if (!device_kset) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	fcheck_kset = kset_create_and_add("filecheck", NULL,
+					  &device_kset->kobj);
+	if (!fcheck_kset) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
+	if (ret)
+		goto error;
+
+	entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
+	if (!entry) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		atomic_set(&entry->fs_count, 1);
+		entry->fs_sb = sb;
+		entry->fs_devicekset = device_kset;
+		entry->fs_fcheckkset = fcheck_kset;
+		entry->fs_fcheck = fcheck;
+		ocfs2_filecheck_sysfs_add(entry);
+	}
+
+	kfree(attrs);
+	return 0;
+
+error:
+	kfree(attrs);
+	kfree(entry);
+	kfree(fcheck);
+	kset_unregister(fcheck_kset);
+	kset_unregister(device_kset);
+	return ret;
+}
+
+int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
+{
+	return ocfs2_filecheck_sysfs_del(sb->s_id);
+}
+
+static int
+ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+			      unsigned int count);
+static int
+ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
+			   unsigned int len)
+{
+	int ret;
+
+	if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
+		return -EINVAL;
+
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
+		mlog(ML_ERROR,
+		"Cannot set online file check maximum entry number "
+		"to %u due to too many pending entries(%u)\n",
+		len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
+		ret = -EBUSY;
+	} else {
+		if (len < ent->fs_fcheck->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(ent,
+				ent->fs_fcheck->fc_size - len));
+
+		ent->fs_fcheck->fc_max = len;
+		ret = 0;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+	return ret;
+}
+
+#define OCFS2_FILECHECK_ARGS_LEN	24
+static int
+ocfs2_filecheck_args_get_long(const char *buf, size_t count,
+			      unsigned long *val)
+{
+	char buffer[OCFS2_FILECHECK_ARGS_LEN];
+
+	memcpy(buffer, buf, count);
+	buffer[count] = '\0';
+
+	if (kstrtoul(buffer, 0, val))
+		return 1;
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
+{
+	if (!strncmp(name, "fix", 4))
+		*type = OCFS2_FILECHECK_TYPE_FIX;
+	else if (!strncmp(name, "check", 6))
+		*type = OCFS2_FILECHECK_TYPE_CHK;
+	else if (!strncmp(name, "set", 4))
+		*type = OCFS2_FILECHECK_TYPE_SET;
+	else
+		return 1;
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
+			   struct ocfs2_filecheck_args *args)
+{
+	unsigned long val = 0;
+	unsigned int type;
+
+	/* too short/long args length */
+	if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
+		return 1;
+
+	if (ocfs2_filecheck_type_parse(name, &type))
+		return 1;
+	if (ocfs2_filecheck_args_get_long(buf, count, &val))
+		return 1;
+
+	if (val <= 0)
+		return 1;
+
+	args->fa_type = type;
+	if (type == OCFS2_FILECHECK_TYPE_SET)
+		args->fa_len = (unsigned int)val;
+	else
+		args->fa_ino = val;
+
+	return 0;
+}
+
+static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+
+	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
+	unsigned int type;
+	struct ocfs2_filecheck_entry *p;
+	struct ocfs2_filecheck_sysfs_entry *ent;
+
+	if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
+		return -EINVAL;
+
+	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
+	if (!ent) {
+		mlog(ML_ERROR,
+		"Cannot get the corresponding entry via device basename %s\n",
+		kobj->name);
+		return -ENODEV;
+	}
+
+	if (type == OCFS2_FILECHECK_TYPE_SET) {
+		spin_lock(&ent->fs_fcheck->fc_lock);
+		total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
+		spin_unlock(&ent->fs_fcheck->fc_lock);
+		goto exit;
+	}
+
+	ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
+	total += ret;
+	remain -= ret;
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+		if (p->fe_type != type)
+			continue;
+
+		ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
+			       p->fe_ino, p->fe_done,
+			       ocfs2_filecheck_error(p->fe_status));
+		if (ret < 0) {
+			total = ret;
+			break;
+		}
+		if (ret == remain) {
+			/* snprintf() didn't fit */
+			total = -E2BIG;
+			break;
+		}
+		total += ret;
+		remain -= ret;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+exit:
+	ocfs2_filecheck_sysfs_put(ent);
+	return total;
+}
+
+static int
+ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+{
+	struct ocfs2_filecheck_entry *p;
+
+	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+		if (p->fe_done) {
+			list_del(&p->fe_list);
+			kfree(p);
+			ent->fs_fcheck->fc_size--;
+			ent->fs_fcheck->fc_done--;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+			      unsigned int count)
+{
+	unsigned int i = 0;
+	unsigned int ret = 0;
+
+	while (i++ < count) {
+		if (ocfs2_filecheck_erase_entry(ent))
+			ret++;
+		else
+			break;
+	}
+
+	return (ret == count ? 1 : 0);
+}
+
+static void
+ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+			   struct ocfs2_filecheck_entry *entry)
+{
+	entry->fe_done = 1;
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	ent->fs_fcheck->fc_done++;
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+}
+
+static unsigned int
+ocfs2_filecheck_handle(struct super_block *sb,
+		       unsigned long ino, unsigned int flags)
+{
+	unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
+	struct inode *inode = NULL;
+	int rc;
+
+	inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
+	if (IS_ERR(inode)) {
+		rc = (int)(-(long)inode);
+		if (rc >= OCFS2_FILECHECK_ERR_START &&
+		    rc < OCFS2_FILECHECK_ERR_END)
+			ret = rc;
+		else
+			ret = OCFS2_FILECHECK_ERR_FAILED;
+	} else
+		iput(inode);
+
+	return ret;
+}
+
+static void
+ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+			     struct ocfs2_filecheck_entry *entry)
+{
+	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
+		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
+	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
+		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+	else
+		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
+
+	ocfs2_filecheck_done_entry(ent, entry);
+}
+
+static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ocfs2_filecheck_args args;
+	struct ocfs2_filecheck_entry *entry;
+	struct ocfs2_filecheck_sysfs_entry *ent;
+	ssize_t ret = 0;
+
+	if (count == 0)
+		return count;
+
+	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
+		mlog(ML_ERROR, "Invalid arguments for online file check\n");
+		return -EINVAL;
+	}
+
+	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
+	if (!ent) {
+		mlog(ML_ERROR,
+		"Cannot get the corresponding entry via device basename %s\n",
+		kobj->parent->name);
+		return -ENODEV;
+	}
+
+	if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
+		ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
+		goto exit;
+	}
+
+	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
+	if (!entry) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
+	    (ent->fs_fcheck->fc_done == 0)) {
+		mlog(ML_ERROR,
+		"Cannot do more file check "
+		"since file check queue(%u) is full now\n",
+		ent->fs_fcheck->fc_max);
+		ret = -EBUSY;
+		kfree(entry);
+	} else {
+		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
+		    (ent->fs_fcheck->fc_done > 0)) {
+			/* Delete the oldest entry which was done,
+			 * make sure the entry size in list does
+			 * not exceed maximum value
+			 */
+			BUG_ON(!ocfs2_filecheck_erase_entry(ent));
+		}
+
+		entry->fe_ino = args.fa_ino;
+		entry->fe_type = args.fa_type;
+		entry->fe_done = 0;
+		entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
+		list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
+		ent->fs_fcheck->fc_size++;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+	if (!ret)
+		ocfs2_filecheck_handle_entry(ent, entry);
+
+exit:
+	ocfs2_filecheck_sysfs_put(ent);
+	return (!ret ? count : ret);
+}
diff --git a/fs/ocfs2/filecheck.h b/fs/ocfs2/filecheck.h
new file mode 100644
index 0000000..e5cd002
--- /dev/null
+++ b/fs/ocfs2/filecheck.h
@@ -0,0 +1,49 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * filecheck.h
+ *
+ * Online file check.
+ *
+ * Copyright (C) 2016 SuSE.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+
+#ifndef FILECHECK_H
+#define FILECHECK_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+
+/* File check errno */
+enum {
+	OCFS2_FILECHECK_ERR_SUCCESS = 0,	/* Success */
+	OCFS2_FILECHECK_ERR_FAILED = 1000,	/* Other failure */
+	OCFS2_FILECHECK_ERR_INPROGRESS,		/* In progress */
+	OCFS2_FILECHECK_ERR_READONLY,		/* Read only */
+	OCFS2_FILECHECK_ERR_INJBD,		/* Buffer in jbd */
+	OCFS2_FILECHECK_ERR_INVALIDINO,		/* Invalid ino */
+	OCFS2_FILECHECK_ERR_BLOCKECC,		/* Block ecc */
+	OCFS2_FILECHECK_ERR_BLOCKNO,		/* Block number */
+	OCFS2_FILECHECK_ERR_VALIDFLAG,		/* Inode valid flag */
+	OCFS2_FILECHECK_ERR_GENERATION,		/* Inode generation */
+	OCFS2_FILECHECK_ERR_UNSUPPORTED		/* Unsupported */
+};
+
+#define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
+#define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+
+int ocfs2_filecheck_create_sysfs(struct super_block *sb);
+int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+
+#endif  /* FILECHECK_H */
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index aac8b86..01635e0 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -139,6 +139,9 @@ int ocfs2_drop_inode(struct inode *inode);
 /* Flags for ocfs2_iget() */
 #define OCFS2_FI_FLAG_SYSFILE		0x1
 #define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
+#define OCFS2_FI_FLAG_FILECHECK_CHK	0x4
+#define OCFS2_FI_FLAG_FILECHECK_FIX	0x8
+
 struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff);
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
 			 int sysfile_type);
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-02-29  5:17   ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:17 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Implement online file check sysfile interfaces, e.g.
how to create the related sysfile according to device name,
how to display/handle file check request from the sysfile.

Signed-off-by: Gang He <ghe@suse.com>
---
 fs/ocfs2/Makefile    |   3 +-
 fs/ocfs2/filecheck.c | 606 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/filecheck.h |  49 +++++
 fs/ocfs2/inode.h     |   3 +
 4 files changed, 660 insertions(+), 1 deletion(-)
 create mode 100644 fs/ocfs2/filecheck.c
 create mode 100644 fs/ocfs2/filecheck.h

diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
index ce210d4..e27e652 100644
--- a/fs/ocfs2/Makefile
+++ b/fs/ocfs2/Makefile
@@ -41,7 +41,8 @@ ocfs2-objs := \
 	quota_local.o		\
 	quota_global.o		\
 	xattr.o			\
-	acl.o
+	acl.o	\
+	filecheck.o
 
 ocfs2_stackglue-objs := stackglue.o
 ocfs2_stack_o2cb-objs := stack_o2cb.o
diff --git a/fs/ocfs2/filecheck.c b/fs/ocfs2/filecheck.c
new file mode 100644
index 0000000..2cabbcf
--- /dev/null
+++ b/fs/ocfs2/filecheck.c
@@ -0,0 +1,606 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * filecheck.c
+ *
+ * Code which implements online file check.
+ *
+ * Copyright (C) 2016 SuSE.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/sysctl.h>
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "ocfs2_fs.h"
+#include "stackglue.h"
+#include "inode.h"
+
+#include "filecheck.h"
+
+
+/* File check error strings,
+ * must correspond with error number in header file.
+ */
+static const char * const ocfs2_filecheck_errs[] = {
+	"SUCCESS",
+	"FAILED",
+	"INPROGRESS",
+	"READONLY",
+	"INJBD",
+	"INVALIDINO",
+	"BLOCKECC",
+	"BLOCKNO",
+	"VALIDFLAG",
+	"GENERATION",
+	"UNSUPPORTED"
+};
+
+static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
+static LIST_HEAD(ocfs2_filecheck_sysfs_list);
+
+struct ocfs2_filecheck {
+	struct list_head fc_head;	/* File check entry list head */
+	spinlock_t fc_lock;
+	unsigned int fc_max;	/* Maximum number of entry in list */
+	unsigned int fc_size;	/* Current entry count in list */
+	unsigned int fc_done;	/* Finished entry count in list */
+};
+
+struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per mounting */
+	struct list_head fs_list;
+	atomic_t fs_count;
+	struct super_block *fs_sb;
+	struct kset *fs_devicekset;
+	struct kset *fs_fcheckkset;
+	struct ocfs2_filecheck *fs_fcheck;
+};
+
+#define OCFS2_FILECHECK_MAXSIZE		100
+#define OCFS2_FILECHECK_MINSIZE		10
+
+/* File check operation type */
+enum {
+	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
+	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
+	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
+};
+
+struct ocfs2_filecheck_entry {
+	struct list_head fe_list;
+	unsigned long fe_ino;
+	unsigned int fe_type;
+	unsigned int fe_done:1;
+	unsigned int fe_status:31;
+};
+
+struct ocfs2_filecheck_args {
+	unsigned int fa_type;
+	union {
+		unsigned long fa_ino;
+		unsigned int fa_len;
+	};
+};
+
+static const char *
+ocfs2_filecheck_error(int errno)
+{
+	if (!errno)
+		return ocfs2_filecheck_errs[errno];
+
+	BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
+	       errno > OCFS2_FILECHECK_ERR_END);
+	return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
+}
+
+static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf);
+static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count);
+static struct kobj_attribute ocfs2_attr_filecheck_chk =
+					__ATTR(check, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+static struct kobj_attribute ocfs2_attr_filecheck_fix =
+					__ATTR(fix, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+static struct kobj_attribute ocfs2_attr_filecheck_set =
+					__ATTR(set, S_IRUSR | S_IWUSR,
+					ocfs2_filecheck_show,
+					ocfs2_filecheck_store);
+
+static int ocfs2_filecheck_sysfs_wait(atomic_t *p)
+{
+	schedule();
+	return 0;
+}
+
+static void
+ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	struct ocfs2_filecheck_entry *p;
+
+	if (!atomic_dec_and_test(&entry->fs_count))
+		wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait,
+				 TASK_UNINTERRUPTIBLE);
+
+	spin_lock(&entry->fs_fcheck->fc_lock);
+	while (!list_empty(&entry->fs_fcheck->fc_head)) {
+		p = list_first_entry(&entry->fs_fcheck->fc_head,
+				     struct ocfs2_filecheck_entry, fe_list);
+		list_del(&p->fe_list);
+		BUG_ON(!p->fe_done); /* To free a undone file check entry */
+		kfree(p);
+	}
+	spin_unlock(&entry->fs_fcheck->fc_lock);
+
+	kset_unregister(entry->fs_fcheckkset);
+	kset_unregister(entry->fs_devicekset);
+	kfree(entry->fs_fcheck);
+	kfree(entry);
+}
+
+static void
+ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list);
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+}
+
+static int ocfs2_filecheck_sysfs_del(const char *devname)
+{
+	struct ocfs2_filecheck_sysfs_entry *p;
+
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
+		if (!strcmp(p->fs_sb->s_id, devname)) {
+			list_del(&p->fs_list);
+			spin_unlock(&ocfs2_filecheck_sysfs_lock);
+			ocfs2_filecheck_sysfs_free(p);
+			return 0;
+		}
+	}
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+	return 1;
+}
+
+static void
+ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
+{
+	if (atomic_dec_and_test(&entry->fs_count))
+		wake_up_atomic_t(&entry->fs_count);
+}
+
+static struct ocfs2_filecheck_sysfs_entry *
+ocfs2_filecheck_sysfs_get(const char *devname)
+{
+	struct ocfs2_filecheck_sysfs_entry *p = NULL;
+
+	spin_lock(&ocfs2_filecheck_sysfs_lock);
+	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
+		if (!strcmp(p->fs_sb->s_id, devname)) {
+			atomic_inc(&p->fs_count);
+			spin_unlock(&ocfs2_filecheck_sysfs_lock);
+			return p;
+		}
+	}
+	spin_unlock(&ocfs2_filecheck_sysfs_lock);
+	return NULL;
+}
+
+int ocfs2_filecheck_create_sysfs(struct super_block *sb)
+{
+	int ret = 0;
+	struct kset *device_kset = NULL;
+	struct kset *fcheck_kset = NULL;
+	struct ocfs2_filecheck *fcheck = NULL;
+	struct ocfs2_filecheck_sysfs_entry *entry = NULL;
+	struct attribute **attrs = NULL;
+	struct attribute_group attrgp;
+
+	if (!ocfs2_kset)
+		return -ENOMEM;
+
+	attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
+	if (!attrs) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		attrs[0] = &ocfs2_attr_filecheck_chk.attr;
+		attrs[1] = &ocfs2_attr_filecheck_fix.attr;
+		attrs[2] = &ocfs2_attr_filecheck_set.attr;
+		attrs[3] = NULL;
+		memset(&attrgp, 0, sizeof(attrgp));
+		attrgp.attrs = attrs;
+	}
+
+	fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
+	if (!fcheck) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		INIT_LIST_HEAD(&fcheck->fc_head);
+		spin_lock_init(&fcheck->fc_lock);
+		fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
+		fcheck->fc_size = 0;
+		fcheck->fc_done = 0;
+	}
+
+	if (strlen(sb->s_id) <= 0) {
+		mlog(ML_ERROR,
+		"Cannot get device basename when create filecheck sysfs\n");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
+	if (!device_kset) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	fcheck_kset = kset_create_and_add("filecheck", NULL,
+					  &device_kset->kobj);
+	if (!fcheck_kset) {
+		ret = -ENOMEM;
+		goto error;
+	}
+
+	ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
+	if (ret)
+		goto error;
+
+	entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
+	if (!entry) {
+		ret = -ENOMEM;
+		goto error;
+	} else {
+		atomic_set(&entry->fs_count, 1);
+		entry->fs_sb = sb;
+		entry->fs_devicekset = device_kset;
+		entry->fs_fcheckkset = fcheck_kset;
+		entry->fs_fcheck = fcheck;
+		ocfs2_filecheck_sysfs_add(entry);
+	}
+
+	kfree(attrs);
+	return 0;
+
+error:
+	kfree(attrs);
+	kfree(entry);
+	kfree(fcheck);
+	kset_unregister(fcheck_kset);
+	kset_unregister(device_kset);
+	return ret;
+}
+
+int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
+{
+	return ocfs2_filecheck_sysfs_del(sb->s_id);
+}
+
+static int
+ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+			      unsigned int count);
+static int
+ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
+			   unsigned int len)
+{
+	int ret;
+
+	if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
+		return -EINVAL;
+
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
+		mlog(ML_ERROR,
+		"Cannot set online file check maximum entry number "
+		"to %u due to too many pending entries(%u)\n",
+		len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
+		ret = -EBUSY;
+	} else {
+		if (len < ent->fs_fcheck->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(ent,
+				ent->fs_fcheck->fc_size - len));
+
+		ent->fs_fcheck->fc_max = len;
+		ret = 0;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+	return ret;
+}
+
+#define OCFS2_FILECHECK_ARGS_LEN	24
+static int
+ocfs2_filecheck_args_get_long(const char *buf, size_t count,
+			      unsigned long *val)
+{
+	char buffer[OCFS2_FILECHECK_ARGS_LEN];
+
+	memcpy(buffer, buf, count);
+	buffer[count] = '\0';
+
+	if (kstrtoul(buffer, 0, val))
+		return 1;
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
+{
+	if (!strncmp(name, "fix", 4))
+		*type = OCFS2_FILECHECK_TYPE_FIX;
+	else if (!strncmp(name, "check", 6))
+		*type = OCFS2_FILECHECK_TYPE_CHK;
+	else if (!strncmp(name, "set", 4))
+		*type = OCFS2_FILECHECK_TYPE_SET;
+	else
+		return 1;
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
+			   struct ocfs2_filecheck_args *args)
+{
+	unsigned long val = 0;
+	unsigned int type;
+
+	/* too short/long args length */
+	if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
+		return 1;
+
+	if (ocfs2_filecheck_type_parse(name, &type))
+		return 1;
+	if (ocfs2_filecheck_args_get_long(buf, count, &val))
+		return 1;
+
+	if (val <= 0)
+		return 1;
+
+	args->fa_type = type;
+	if (type == OCFS2_FILECHECK_TYPE_SET)
+		args->fa_len = (unsigned int)val;
+	else
+		args->fa_ino = val;
+
+	return 0;
+}
+
+static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+
+	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
+	unsigned int type;
+	struct ocfs2_filecheck_entry *p;
+	struct ocfs2_filecheck_sysfs_entry *ent;
+
+	if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
+		return -EINVAL;
+
+	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
+	if (!ent) {
+		mlog(ML_ERROR,
+		"Cannot get the corresponding entry via device basename %s\n",
+		kobj->name);
+		return -ENODEV;
+	}
+
+	if (type == OCFS2_FILECHECK_TYPE_SET) {
+		spin_lock(&ent->fs_fcheck->fc_lock);
+		total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
+		spin_unlock(&ent->fs_fcheck->fc_lock);
+		goto exit;
+	}
+
+	ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
+	total += ret;
+	remain -= ret;
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+		if (p->fe_type != type)
+			continue;
+
+		ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
+			       p->fe_ino, p->fe_done,
+			       ocfs2_filecheck_error(p->fe_status));
+		if (ret < 0) {
+			total = ret;
+			break;
+		}
+		if (ret == remain) {
+			/* snprintf() didn't fit */
+			total = -E2BIG;
+			break;
+		}
+		total += ret;
+		remain -= ret;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+exit:
+	ocfs2_filecheck_sysfs_put(ent);
+	return total;
+}
+
+static int
+ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+{
+	struct ocfs2_filecheck_entry *p;
+
+	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+		if (p->fe_done) {
+			list_del(&p->fe_list);
+			kfree(p);
+			ent->fs_fcheck->fc_size--;
+			ent->fs_fcheck->fc_done--;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+			      unsigned int count)
+{
+	unsigned int i = 0;
+	unsigned int ret = 0;
+
+	while (i++ < count) {
+		if (ocfs2_filecheck_erase_entry(ent))
+			ret++;
+		else
+			break;
+	}
+
+	return (ret == count ? 1 : 0);
+}
+
+static void
+ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+			   struct ocfs2_filecheck_entry *entry)
+{
+	entry->fe_done = 1;
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	ent->fs_fcheck->fc_done++;
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+}
+
+static unsigned int
+ocfs2_filecheck_handle(struct super_block *sb,
+		       unsigned long ino, unsigned int flags)
+{
+	unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
+	struct inode *inode = NULL;
+	int rc;
+
+	inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
+	if (IS_ERR(inode)) {
+		rc = (int)(-(long)inode);
+		if (rc >= OCFS2_FILECHECK_ERR_START &&
+		    rc < OCFS2_FILECHECK_ERR_END)
+			ret = rc;
+		else
+			ret = OCFS2_FILECHECK_ERR_FAILED;
+	} else
+		iput(inode);
+
+	return ret;
+}
+
+static void
+ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+			     struct ocfs2_filecheck_entry *entry)
+{
+	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
+		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
+	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
+		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+	else
+		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
+
+	ocfs2_filecheck_done_entry(ent, entry);
+}
+
+static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct ocfs2_filecheck_args args;
+	struct ocfs2_filecheck_entry *entry;
+	struct ocfs2_filecheck_sysfs_entry *ent;
+	ssize_t ret = 0;
+
+	if (count == 0)
+		return count;
+
+	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
+		mlog(ML_ERROR, "Invalid arguments for online file check\n");
+		return -EINVAL;
+	}
+
+	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
+	if (!ent) {
+		mlog(ML_ERROR,
+		"Cannot get the corresponding entry via device basename %s\n",
+		kobj->parent->name);
+		return -ENODEV;
+	}
+
+	if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
+		ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
+		goto exit;
+	}
+
+	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
+	if (!entry) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	spin_lock(&ent->fs_fcheck->fc_lock);
+	if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
+	    (ent->fs_fcheck->fc_done == 0)) {
+		mlog(ML_ERROR,
+		"Cannot do more file check "
+		"since file check queue(%u) is full now\n",
+		ent->fs_fcheck->fc_max);
+		ret = -EBUSY;
+		kfree(entry);
+	} else {
+		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
+		    (ent->fs_fcheck->fc_done > 0)) {
+			/* Delete the oldest entry which was done,
+			 * make sure the entry size in list does
+			 * not exceed maximum value
+			 */
+			BUG_ON(!ocfs2_filecheck_erase_entry(ent));
+		}
+
+		entry->fe_ino = args.fa_ino;
+		entry->fe_type = args.fa_type;
+		entry->fe_done = 0;
+		entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
+		list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
+		ent->fs_fcheck->fc_size++;
+	}
+	spin_unlock(&ent->fs_fcheck->fc_lock);
+
+	if (!ret)
+		ocfs2_filecheck_handle_entry(ent, entry);
+
+exit:
+	ocfs2_filecheck_sysfs_put(ent);
+	return (!ret ? count : ret);
+}
diff --git a/fs/ocfs2/filecheck.h b/fs/ocfs2/filecheck.h
new file mode 100644
index 0000000..e5cd002
--- /dev/null
+++ b/fs/ocfs2/filecheck.h
@@ -0,0 +1,49 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * filecheck.h
+ *
+ * Online file check.
+ *
+ * Copyright (C) 2016 SuSE.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+
+#ifndef FILECHECK_H
+#define FILECHECK_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+
+/* File check errno */
+enum {
+	OCFS2_FILECHECK_ERR_SUCCESS = 0,	/* Success */
+	OCFS2_FILECHECK_ERR_FAILED = 1000,	/* Other failure */
+	OCFS2_FILECHECK_ERR_INPROGRESS,		/* In progress */
+	OCFS2_FILECHECK_ERR_READONLY,		/* Read only */
+	OCFS2_FILECHECK_ERR_INJBD,		/* Buffer in jbd */
+	OCFS2_FILECHECK_ERR_INVALIDINO,		/* Invalid ino */
+	OCFS2_FILECHECK_ERR_BLOCKECC,		/* Block ecc */
+	OCFS2_FILECHECK_ERR_BLOCKNO,		/* Block number */
+	OCFS2_FILECHECK_ERR_VALIDFLAG,		/* Inode valid flag */
+	OCFS2_FILECHECK_ERR_GENERATION,		/* Inode generation */
+	OCFS2_FILECHECK_ERR_UNSUPPORTED		/* Unsupported */
+};
+
+#define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
+#define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+
+int ocfs2_filecheck_create_sysfs(struct super_block *sb);
+int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+
+#endif  /* FILECHECK_H */
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index aac8b86..01635e0 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -139,6 +139,9 @@ int ocfs2_drop_inode(struct inode *inode);
 /* Flags for ocfs2_iget() */
 #define OCFS2_FI_FLAG_SYSFILE		0x1
 #define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
+#define OCFS2_FI_FLAG_FILECHECK_CHK	0x4
+#define OCFS2_FI_FLAG_FILECHECK_FIX	0x8
+
 struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff);
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
 			 int sysfile_type);
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v4 3/5] ocfs2: create/remove sysfile for online file check
  2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
@ 2016-02-29  5:18   ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Create online file check sysfile when ocfs2 mount,
remove the related sysfile when ocfs2 umount.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 fs/ocfs2/super.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 2de4c8a..5ef88b8 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -74,6 +74,7 @@
 #include "suballoc.h"
 
 #include "buffer_head_io.h"
+#include "filecheck.h"
 
 static struct kmem_cache *ocfs2_inode_cachep;
 struct kmem_cache *ocfs2_dquot_cachep;
@@ -1204,6 +1205,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	/* Start this when the mount is almost sure of being successful */
 	ocfs2_orphan_scan_start(osb);
 
+	/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */
+	ocfs2_filecheck_create_sysfs(sb);
+
 	return status;
 
 read_super_error:
@@ -1671,6 +1675,7 @@ static void ocfs2_put_super(struct super_block *sb)
 
 	ocfs2_sync_blockdev(sb);
 	ocfs2_dismount_volume(sb, 0);
+	ocfs2_filecheck_remove_sysfs(sb);
 }
 
 static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 3/5] ocfs2: create/remove sysfile for online file check
@ 2016-02-29  5:18   ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Create online file check sysfile when ocfs2 mount,
remove the related sysfile when ocfs2 umount.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 fs/ocfs2/super.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 2de4c8a..5ef88b8 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -74,6 +74,7 @@
 #include "suballoc.h"
 
 #include "buffer_head_io.h"
+#include "filecheck.h"
 
 static struct kmem_cache *ocfs2_inode_cachep;
 struct kmem_cache *ocfs2_dquot_cachep;
@@ -1204,6 +1205,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	/* Start this when the mount is almost sure of being successful */
 	ocfs2_orphan_scan_start(osb);
 
+	/* Create filecheck sysfile /sys/fs/ocfs2/<devname>/filecheck */
+	ocfs2_filecheck_create_sysfs(sb);
+
 	return status;
 
 read_super_error:
@@ -1671,6 +1675,7 @@ static void ocfs2_put_super(struct super_block *sb)
 
 	ocfs2_sync_blockdev(sb);
 	ocfs2_dismount_volume(sb, 0);
+	ocfs2_filecheck_remove_sysfs(sb);
 }
 
 static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
  2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
@ 2016-02-29  5:18   ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Implement online check or fix inode block during
reading a inode block to memory.

Signed-off-by: Gang He <ghe@suse.com>
---
 fs/ocfs2/inode.c       | 225 +++++++++++++++++++++++++++++++++++++++++++++++--
 fs/ocfs2/ocfs2_trace.h |   2 +
 2 files changed, 218 insertions(+), 9 deletions(-)

diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 8f87e05..6ce531e 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -53,6 +53,7 @@
 #include "xattr.h"
 #include "refcounttree.h"
 #include "ocfs2_trace.h"
+#include "filecheck.h"
 
 #include "buffer_head_io.h"
 
@@ -74,6 +75,14 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
 				    struct inode *inode,
 				    struct buffer_head *fe_bh);
 
+static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
+						 struct buffer_head **bh,
+						 int flags, int type);
+static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
+						struct buffer_head *bh);
+static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
+					      struct buffer_head *bh);
+
 void ocfs2_set_inode_flags(struct inode *inode)
 {
 	unsigned int flags = OCFS2_I(inode)->ip_attr;
@@ -127,6 +136,7 @@ struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno)
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
 			 int sysfile_type)
 {
+	int rc = 0;
 	struct inode *inode = NULL;
 	struct super_block *sb = osb->sb;
 	struct ocfs2_find_inode_args args;
@@ -161,12 +171,17 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
 	}
 	trace_ocfs2_iget5_locked(inode->i_state);
 	if (inode->i_state & I_NEW) {
-		ocfs2_read_locked_inode(inode, &args);
+		rc = ocfs2_read_locked_inode(inode, &args);
 		unlock_new_inode(inode);
 	}
 	if (is_bad_inode(inode)) {
 		iput(inode);
-		inode = ERR_PTR(-ESTALE);
+		if ((flags & OCFS2_FI_FLAG_FILECHECK_CHK) ||
+		    (flags & OCFS2_FI_FLAG_FILECHECK_FIX))
+			/* Return OCFS2_FILECHECK_ERR_XXX related errno */
+			inode = ERR_PTR(rc);
+		else
+			inode = ERR_PTR(-ESTALE);
 		goto bail;
 	}
 
@@ -409,7 +424,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 	struct ocfs2_super *osb;
 	struct ocfs2_dinode *fe;
 	struct buffer_head *bh = NULL;
-	int status, can_lock;
+	int status, can_lock, lock_level = 0;
 	u32 generation = 0;
 
 	status = -EINVAL;
@@ -477,7 +492,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 			mlog_errno(status);
 			return status;
 		}
-		status = ocfs2_inode_lock(inode, NULL, 0);
+		status = ocfs2_inode_lock(inode, NULL, lock_level);
 		if (status) {
 			make_bad_inode(inode);
 			mlog_errno(status);
@@ -494,16 +509,32 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 	}
 
 	if (can_lock) {
-		status = ocfs2_read_inode_block_full(inode, &bh,
-						     OCFS2_BH_IGNORE_CACHE);
+		if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
+			status = ocfs2_filecheck_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE, 0);
+		else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
+			status = ocfs2_filecheck_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE, 1);
+		else
+			status = ocfs2_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE);
 	} else {
 		status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
 		/*
 		 * If buffer is in jbd, then its checksum may not have been
 		 * computed as yet.
 		 */
-		if (!status && !buffer_jbd(bh))
-			status = ocfs2_validate_inode_block(osb->sb, bh);
+		if (!status && !buffer_jbd(bh)) {
+			if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
+				status = ocfs2_filecheck_validate_inode_block(
+								osb->sb, bh);
+			else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
+				status = ocfs2_filecheck_repair_inode_block(
+								osb->sb, bh);
+			else
+				status = ocfs2_validate_inode_block(
+								osb->sb, bh);
+		}
 	}
 	if (status < 0) {
 		mlog_errno(status);
@@ -531,11 +562,24 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 
 	BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
 
+	if (buffer_dirty(bh) && !buffer_jbd(bh)) {
+		if (can_lock) {
+			ocfs2_inode_unlock(inode, lock_level);
+			lock_level = 1;
+			ocfs2_inode_lock(inode, NULL, lock_level);
+		}
+		status = ocfs2_write_block(osb, bh, INODE_CACHE(inode));
+		if (status < 0) {
+			mlog_errno(status);
+			goto bail;
+		}
+	}
+
 	status = 0;
 
 bail:
 	if (can_lock)
-		ocfs2_inode_unlock(inode, 0);
+		ocfs2_inode_unlock(inode, lock_level);
 
 	if (status < 0)
 		make_bad_inode(inode);
@@ -1396,6 +1440,169 @@ bail:
 	return rc;
 }
 
+static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
+						struct buffer_head *bh)
+{
+	int rc = 0;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
+
+	trace_ocfs2_filecheck_validate_inode_block(
+		(unsigned long long)bh->b_blocknr);
+
+	BUG_ON(!buffer_uptodate(bh));
+
+	/*
+	 * Call ocfs2_validate_meta_ecc() first since it has ecc repair
+	 * function, but we should not return error immediately when ecc
+	 * validation fails, because the reason is quite likely the invalid
+	 * inode number inputed.
+	 */
+	rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check);
+	if (rc) {
+		mlog(ML_ERROR,
+		     "Filecheck: checksum failed for dinode %llu\n",
+		     (unsigned long long)bh->b_blocknr);
+		rc = -OCFS2_FILECHECK_ERR_BLOCKECC;
+	}
+
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: signature = %.*s\n",
+		     (unsigned long long)bh->b_blocknr, 7, di->i_signature);
+		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+		goto bail;
+	} else if (rc)
+		goto bail;
+
+	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: i_blkno is %llu\n",
+		     (unsigned long long)bh->b_blocknr,
+		     (unsigned long long)le64_to_cpu(di->i_blkno));
+		rc = -OCFS2_FILECHECK_ERR_BLOCKNO;
+		goto bail;
+	}
+
+	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL "
+		     "not set\n",
+		     (unsigned long long)bh->b_blocknr);
+		rc = -OCFS2_FILECHECK_ERR_VALIDFLAG;
+		goto bail;
+	}
+
+	if (le32_to_cpu(di->i_fs_generation) !=
+	    OCFS2_SB(sb)->fs_generation) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: fs_generation is %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le32_to_cpu(di->i_fs_generation));
+		rc = -OCFS2_FILECHECK_ERR_GENERATION;
+		goto bail;
+	}
+
+bail:
+	return rc;
+}
+
+static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
+					      struct buffer_head *bh)
+{
+	int changed = 0;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
+
+	if (!ocfs2_filecheck_validate_inode_block(sb, bh))
+		return 0;
+
+	trace_ocfs2_filecheck_repair_inode_block(
+		(unsigned long long)bh->b_blocknr);
+
+	if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) ||
+	    ocfs2_is_soft_readonly(OCFS2_SB(sb))) {
+		mlog(ML_ERROR,
+		     "Filecheck: cannot repair dinode #%llu "
+		     "on readonly filesystem\n",
+		     (unsigned long long)bh->b_blocknr);
+		return -OCFS2_FILECHECK_ERR_READONLY;
+	}
+
+	if (buffer_jbd(bh)) {
+		mlog(ML_ERROR,
+		     "Filecheck: cannot repair dinode #%llu, "
+		     "its buffer is in jbd\n",
+		     (unsigned long long)bh->b_blocknr);
+		return -OCFS2_FILECHECK_ERR_INJBD;
+	}
+
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		/* Cannot fix invalid inode block */
+		return -OCFS2_FILECHECK_ERR_INVALIDINO;
+	}
+
+	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
+		/* Cannot just add VALID_FL flag back as a fix,
+		 * need more things to check here.
+		 */
+		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
+	}
+
+	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
+		di->i_blkno = cpu_to_le64(bh->b_blocknr);
+		changed = 1;
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: i_blkno to %llu\n",
+		     (unsigned long long)bh->b_blocknr,
+		     (unsigned long long)le64_to_cpu(di->i_blkno));
+	}
+
+	if (le32_to_cpu(di->i_fs_generation) !=
+	    OCFS2_SB(sb)->fs_generation) {
+		di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);
+		changed = 1;
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: fs_generation to %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le32_to_cpu(di->i_fs_generation));
+	}
+
+	if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) {
+		ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check);
+		mark_buffer_dirty(bh);
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: compute meta ecc\n",
+		     (unsigned long long)bh->b_blocknr);
+	}
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_read_inode_block_full(struct inode *inode,
+				      struct buffer_head **bh,
+				      int flags, int type)
+{
+	int rc;
+	struct buffer_head *tmp = *bh;
+
+	if (!type) /* Check inode block */
+		rc = ocfs2_read_blocks(INODE_CACHE(inode),
+				OCFS2_I(inode)->ip_blkno,
+				1, &tmp, flags,
+				ocfs2_filecheck_validate_inode_block);
+	else /* Repair inode block */
+		rc = ocfs2_read_blocks(INODE_CACHE(inode),
+				OCFS2_I(inode)->ip_blkno,
+				1, &tmp, flags,
+				ocfs2_filecheck_repair_inode_block);
+
+	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
+	if (!rc && !*bh)
+		*bh = tmp;
+
+	return rc;
+}
+
 int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
 				int flags)
 {
diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
index 6cb019b..d9205e0 100644
--- a/fs/ocfs2/ocfs2_trace.h
+++ b/fs/ocfs2/ocfs2_trace.h
@@ -1540,6 +1540,8 @@ DEFINE_OCFS2_ULL_INT_EVENT(ocfs2_read_locked_inode);
 DEFINE_OCFS2_INT_INT_EVENT(ocfs2_check_orphan_recovery_state);
 
 DEFINE_OCFS2_ULL_EVENT(ocfs2_validate_inode_block);
+DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_validate_inode_block);
+DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_repair_inode_block);
 
 TRACE_EVENT(ocfs2_inode_is_valid_to_delete,
 	TP_PROTO(void *task, void *dc_task, unsigned long long ino,
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
@ 2016-02-29  5:18   ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

Implement online check or fix inode block during
reading a inode block to memory.

Signed-off-by: Gang He <ghe@suse.com>
---
 fs/ocfs2/inode.c       | 225 +++++++++++++++++++++++++++++++++++++++++++++++--
 fs/ocfs2/ocfs2_trace.h |   2 +
 2 files changed, 218 insertions(+), 9 deletions(-)

diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 8f87e05..6ce531e 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -53,6 +53,7 @@
 #include "xattr.h"
 #include "refcounttree.h"
 #include "ocfs2_trace.h"
+#include "filecheck.h"
 
 #include "buffer_head_io.h"
 
@@ -74,6 +75,14 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
 				    struct inode *inode,
 				    struct buffer_head *fe_bh);
 
+static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
+						 struct buffer_head **bh,
+						 int flags, int type);
+static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
+						struct buffer_head *bh);
+static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
+					      struct buffer_head *bh);
+
 void ocfs2_set_inode_flags(struct inode *inode)
 {
 	unsigned int flags = OCFS2_I(inode)->ip_attr;
@@ -127,6 +136,7 @@ struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno)
 struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
 			 int sysfile_type)
 {
+	int rc = 0;
 	struct inode *inode = NULL;
 	struct super_block *sb = osb->sb;
 	struct ocfs2_find_inode_args args;
@@ -161,12 +171,17 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
 	}
 	trace_ocfs2_iget5_locked(inode->i_state);
 	if (inode->i_state & I_NEW) {
-		ocfs2_read_locked_inode(inode, &args);
+		rc = ocfs2_read_locked_inode(inode, &args);
 		unlock_new_inode(inode);
 	}
 	if (is_bad_inode(inode)) {
 		iput(inode);
-		inode = ERR_PTR(-ESTALE);
+		if ((flags & OCFS2_FI_FLAG_FILECHECK_CHK) ||
+		    (flags & OCFS2_FI_FLAG_FILECHECK_FIX))
+			/* Return OCFS2_FILECHECK_ERR_XXX related errno */
+			inode = ERR_PTR(rc);
+		else
+			inode = ERR_PTR(-ESTALE);
 		goto bail;
 	}
 
@@ -409,7 +424,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 	struct ocfs2_super *osb;
 	struct ocfs2_dinode *fe;
 	struct buffer_head *bh = NULL;
-	int status, can_lock;
+	int status, can_lock, lock_level = 0;
 	u32 generation = 0;
 
 	status = -EINVAL;
@@ -477,7 +492,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 			mlog_errno(status);
 			return status;
 		}
-		status = ocfs2_inode_lock(inode, NULL, 0);
+		status = ocfs2_inode_lock(inode, NULL, lock_level);
 		if (status) {
 			make_bad_inode(inode);
 			mlog_errno(status);
@@ -494,16 +509,32 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 	}
 
 	if (can_lock) {
-		status = ocfs2_read_inode_block_full(inode, &bh,
-						     OCFS2_BH_IGNORE_CACHE);
+		if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
+			status = ocfs2_filecheck_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE, 0);
+		else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
+			status = ocfs2_filecheck_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE, 1);
+		else
+			status = ocfs2_read_inode_block_full(inode,
+						&bh, OCFS2_BH_IGNORE_CACHE);
 	} else {
 		status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
 		/*
 		 * If buffer is in jbd, then its checksum may not have been
 		 * computed as yet.
 		 */
-		if (!status && !buffer_jbd(bh))
-			status = ocfs2_validate_inode_block(osb->sb, bh);
+		if (!status && !buffer_jbd(bh)) {
+			if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
+				status = ocfs2_filecheck_validate_inode_block(
+								osb->sb, bh);
+			else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
+				status = ocfs2_filecheck_repair_inode_block(
+								osb->sb, bh);
+			else
+				status = ocfs2_validate_inode_block(
+								osb->sb, bh);
+		}
 	}
 	if (status < 0) {
 		mlog_errno(status);
@@ -531,11 +562,24 @@ static int ocfs2_read_locked_inode(struct inode *inode,
 
 	BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
 
+	if (buffer_dirty(bh) && !buffer_jbd(bh)) {
+		if (can_lock) {
+			ocfs2_inode_unlock(inode, lock_level);
+			lock_level = 1;
+			ocfs2_inode_lock(inode, NULL, lock_level);
+		}
+		status = ocfs2_write_block(osb, bh, INODE_CACHE(inode));
+		if (status < 0) {
+			mlog_errno(status);
+			goto bail;
+		}
+	}
+
 	status = 0;
 
 bail:
 	if (can_lock)
-		ocfs2_inode_unlock(inode, 0);
+		ocfs2_inode_unlock(inode, lock_level);
 
 	if (status < 0)
 		make_bad_inode(inode);
@@ -1396,6 +1440,169 @@ bail:
 	return rc;
 }
 
+static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
+						struct buffer_head *bh)
+{
+	int rc = 0;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
+
+	trace_ocfs2_filecheck_validate_inode_block(
+		(unsigned long long)bh->b_blocknr);
+
+	BUG_ON(!buffer_uptodate(bh));
+
+	/*
+	 * Call ocfs2_validate_meta_ecc() first since it has ecc repair
+	 * function, but we should not return error immediately when ecc
+	 * validation fails, because the reason is quite likely the invalid
+	 * inode number inputed.
+	 */
+	rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check);
+	if (rc) {
+		mlog(ML_ERROR,
+		     "Filecheck: checksum failed for dinode %llu\n",
+		     (unsigned long long)bh->b_blocknr);
+		rc = -OCFS2_FILECHECK_ERR_BLOCKECC;
+	}
+
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: signature = %.*s\n",
+		     (unsigned long long)bh->b_blocknr, 7, di->i_signature);
+		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
+		goto bail;
+	} else if (rc)
+		goto bail;
+
+	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: i_blkno is %llu\n",
+		     (unsigned long long)bh->b_blocknr,
+		     (unsigned long long)le64_to_cpu(di->i_blkno));
+		rc = -OCFS2_FILECHECK_ERR_BLOCKNO;
+		goto bail;
+	}
+
+	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL "
+		     "not set\n",
+		     (unsigned long long)bh->b_blocknr);
+		rc = -OCFS2_FILECHECK_ERR_VALIDFLAG;
+		goto bail;
+	}
+
+	if (le32_to_cpu(di->i_fs_generation) !=
+	    OCFS2_SB(sb)->fs_generation) {
+		mlog(ML_ERROR,
+		     "Filecheck: invalid dinode #%llu: fs_generation is %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le32_to_cpu(di->i_fs_generation));
+		rc = -OCFS2_FILECHECK_ERR_GENERATION;
+		goto bail;
+	}
+
+bail:
+	return rc;
+}
+
+static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
+					      struct buffer_head *bh)
+{
+	int changed = 0;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
+
+	if (!ocfs2_filecheck_validate_inode_block(sb, bh))
+		return 0;
+
+	trace_ocfs2_filecheck_repair_inode_block(
+		(unsigned long long)bh->b_blocknr);
+
+	if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) ||
+	    ocfs2_is_soft_readonly(OCFS2_SB(sb))) {
+		mlog(ML_ERROR,
+		     "Filecheck: cannot repair dinode #%llu "
+		     "on readonly filesystem\n",
+		     (unsigned long long)bh->b_blocknr);
+		return -OCFS2_FILECHECK_ERR_READONLY;
+	}
+
+	if (buffer_jbd(bh)) {
+		mlog(ML_ERROR,
+		     "Filecheck: cannot repair dinode #%llu, "
+		     "its buffer is in jbd\n",
+		     (unsigned long long)bh->b_blocknr);
+		return -OCFS2_FILECHECK_ERR_INJBD;
+	}
+
+	if (!OCFS2_IS_VALID_DINODE(di)) {
+		/* Cannot fix invalid inode block */
+		return -OCFS2_FILECHECK_ERR_INVALIDINO;
+	}
+
+	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
+		/* Cannot just add VALID_FL flag back as a fix,
+		 * need more things to check here.
+		 */
+		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
+	}
+
+	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
+		di->i_blkno = cpu_to_le64(bh->b_blocknr);
+		changed = 1;
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: i_blkno to %llu\n",
+		     (unsigned long long)bh->b_blocknr,
+		     (unsigned long long)le64_to_cpu(di->i_blkno));
+	}
+
+	if (le32_to_cpu(di->i_fs_generation) !=
+	    OCFS2_SB(sb)->fs_generation) {
+		di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);
+		changed = 1;
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: fs_generation to %u\n",
+		     (unsigned long long)bh->b_blocknr,
+		     le32_to_cpu(di->i_fs_generation));
+	}
+
+	if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) {
+		ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check);
+		mark_buffer_dirty(bh);
+		mlog(ML_ERROR,
+		     "Filecheck: reset dinode #%llu: compute meta ecc\n",
+		     (unsigned long long)bh->b_blocknr);
+	}
+
+	return 0;
+}
+
+static int
+ocfs2_filecheck_read_inode_block_full(struct inode *inode,
+				      struct buffer_head **bh,
+				      int flags, int type)
+{
+	int rc;
+	struct buffer_head *tmp = *bh;
+
+	if (!type) /* Check inode block */
+		rc = ocfs2_read_blocks(INODE_CACHE(inode),
+				OCFS2_I(inode)->ip_blkno,
+				1, &tmp, flags,
+				ocfs2_filecheck_validate_inode_block);
+	else /* Repair inode block */
+		rc = ocfs2_read_blocks(INODE_CACHE(inode),
+				OCFS2_I(inode)->ip_blkno,
+				1, &tmp, flags,
+				ocfs2_filecheck_repair_inode_block);
+
+	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
+	if (!rc && !*bh)
+		*bh = tmp;
+
+	return rc;
+}
+
 int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
 				int flags)
 {
diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
index 6cb019b..d9205e0 100644
--- a/fs/ocfs2/ocfs2_trace.h
+++ b/fs/ocfs2/ocfs2_trace.h
@@ -1540,6 +1540,8 @@ DEFINE_OCFS2_ULL_INT_EVENT(ocfs2_read_locked_inode);
 DEFINE_OCFS2_INT_INT_EVENT(ocfs2_check_orphan_recovery_state);
 
 DEFINE_OCFS2_ULL_EVENT(ocfs2_validate_inode_block);
+DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_validate_inode_block);
+DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_repair_inode_block);
 
 TRACE_EVENT(ocfs2_inode_is_valid_to_delete,
 	TP_PROTO(void *task, void *dc_task, unsigned long long ino,
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH v4 5/5] ocfs2: add feature document for online file check
  2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
@ 2016-02-29  5:18   ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

This document will describe OCFS2 online file check feature.
OCFS2 is often used in high-availaibility systems. However, OCFS2 usually
converts the filesystem to read-only when encounters an error. This may not be
necessary, since turning the filesystem read-only would affect other running
processes as well, decreasing availability.
Then, a mount option (errors=continue) is introduced, which would return the
-EIO errno to the calling process and terminate furhter processing so that the
filesystem is not corrupted further. The filesystem is not converted to
read-only, and the problematic file's inode number is reported in the kernel
log. The user can try to check/fix this file via online filecheck feature.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 .../filesystems/ocfs2-online-filecheck.txt         | 94 ++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 Documentation/filesystems/ocfs2-online-filecheck.txt

diff --git a/Documentation/filesystems/ocfs2-online-filecheck.txt b/Documentation/filesystems/ocfs2-online-filecheck.txt
new file mode 100644
index 0000000..1ab0786
--- /dev/null
+++ b/Documentation/filesystems/ocfs2-online-filecheck.txt
@@ -0,0 +1,94 @@
+		    OCFS2 online file check
+		    -----------------------
+
+This document will describe OCFS2 online file check feature.
+
+Introduction
+============
+OCFS2 is often used in high-availaibility systems. However, OCFS2 usually
+converts the filesystem to read-only when encounters an error. This may not be
+necessary, since turning the filesystem read-only would affect other running
+processes as well, decreasing availability.
+Then, a mount option (errors=continue) is introduced, which would return the
+-EIO errno to the calling process and terminate furhter processing so that the
+filesystem is not corrupted further. The filesystem is not converted to
+read-only, and the problematic file's inode number is reported in the kernel
+log. The user can try to check/fix this file via online filecheck feature.
+
+Scope
+=====
+This effort is to check/fix small issues which may hinder day-to-day operations
+of a cluster filesystem by turning the filesystem read-only. The scope of
+checking/fixing is at the file level, initially for regular files and eventually
+to all files (including system files) of the filesystem.
+
+In case of directory to file links is incorrect, the directory inode is
+reported as erroneous.
+
+This feature is not suited for extravagant checks which involve dependency of
+other components of the filesystem, such as but not limited to, checking if the
+bits for file blocks in the allocation has been set. In case of such an error,
+the offline fsck should/would be recommended.
+
+Finally, such an operation/feature should not be automated lest the filesystem
+may end up with more damage than before the repair attempt. So, this has to
+be performed using user interaction and consent.
+
+User interface
+==============
+When there are errors in the OCFS2 filesystem, they are usually accompanied
+by the inode number which caused the error. This inode number would be the
+input to check/fix the file.
+
+There is a sysfs directory for each OCFS2 file system mounting:
+
+  /sys/fs/ocfs2/<devname>/filecheck
+
+Here, <devname> indicates the name of OCFS2 volumn device which has been already
+mounted. The file above would accept inode numbers. This could be used to
+communicate with kernel space, tell which file(inode number) will be checked or
+fixed. Currently, three operations are supported, which includes checking
+inode, fixing inode and setting the size of result record history.
+
+1. If you want to know what error exactly happened to <inode> before fixing, do
+
+  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/check
+  # cat /sys/fs/ocfs2/<devname>/filecheck/check
+
+The output is like this:
+  INO		DONE	ERROR
+39502		1	GENERATION
+
+<INO> lists the inode numbers.
+<DONE> indicates whether the operation has been finished.
+<ERROR> says what kind of errors was found. For the detailed error numbers,
+please refer to the file linux/fs/ocfs2/filecheck.h.
+
+2. If you determine to fix this inode, do
+
+  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/fix
+  # cat /sys/fs/ocfs2/<devname>/filecheck/fix
+
+The output is like this:
+  INO		DONE	ERROR
+39502		1	SUCCESS
+
+This time, the <ERROR> column indicates whether this fix is successful or not.
+
+3. The record cache is used to store the history of check/fix results. It's
+defalut size is 10, and can be adjust between the range of 10 ~ 100. You can
+adjust the size like this:
+
+  # echo "<size>" > /sys/fs/ocfs2/<devname>/filecheck/set
+
+Fixing stuff
+============
+On receivng the inode, the filesystem would read the inode and the
+file metadata. In case of errors, the filesystem would fix the errors
+and report the problems it fixed in the kernel log. As a precautionary measure,
+the inode must first be checked for errors before performing a final fix.
+
+The inode and the result history will be maintained temporarily in a
+small linked list buffer which would contain the last (N) inodes
+fixed/checked, the detailed errors which were fixed/checked are printed in the
+kernel log.
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 5/5] ocfs2: add feature document for online file check
@ 2016-02-29  5:18   ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-02-29  5:18 UTC (permalink / raw)
  To: mfasheh, rgoldwyn, ghe; +Cc: linux-kernel, ocfs2-devel, akpm

This document will describe OCFS2 online file check feature.
OCFS2 is often used in high-availaibility systems. However, OCFS2 usually
converts the filesystem to read-only when encounters an error. This may not be
necessary, since turning the filesystem read-only would affect other running
processes as well, decreasing availability.
Then, a mount option (errors=continue) is introduced, which would return the
-EIO errno to the calling process and terminate furhter processing so that the
filesystem is not corrupted further. The filesystem is not converted to
read-only, and the problematic file's inode number is reported in the kernel
log. The user can try to check/fix this file via online filecheck feature.

Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>
---
 .../filesystems/ocfs2-online-filecheck.txt         | 94 ++++++++++++++++++++++
 1 file changed, 94 insertions(+)
 create mode 100644 Documentation/filesystems/ocfs2-online-filecheck.txt

diff --git a/Documentation/filesystems/ocfs2-online-filecheck.txt b/Documentation/filesystems/ocfs2-online-filecheck.txt
new file mode 100644
index 0000000..1ab0786
--- /dev/null
+++ b/Documentation/filesystems/ocfs2-online-filecheck.txt
@@ -0,0 +1,94 @@
+		    OCFS2 online file check
+		    -----------------------
+
+This document will describe OCFS2 online file check feature.
+
+Introduction
+============
+OCFS2 is often used in high-availaibility systems. However, OCFS2 usually
+converts the filesystem to read-only when encounters an error. This may not be
+necessary, since turning the filesystem read-only would affect other running
+processes as well, decreasing availability.
+Then, a mount option (errors=continue) is introduced, which would return the
+-EIO errno to the calling process and terminate furhter processing so that the
+filesystem is not corrupted further. The filesystem is not converted to
+read-only, and the problematic file's inode number is reported in the kernel
+log. The user can try to check/fix this file via online filecheck feature.
+
+Scope
+=====
+This effort is to check/fix small issues which may hinder day-to-day operations
+of a cluster filesystem by turning the filesystem read-only. The scope of
+checking/fixing is at the file level, initially for regular files and eventually
+to all files (including system files) of the filesystem.
+
+In case of directory to file links is incorrect, the directory inode is
+reported as erroneous.
+
+This feature is not suited for extravagant checks which involve dependency of
+other components of the filesystem, such as but not limited to, checking if the
+bits for file blocks in the allocation has been set. In case of such an error,
+the offline fsck should/would be recommended.
+
+Finally, such an operation/feature should not be automated lest the filesystem
+may end up with more damage than before the repair attempt. So, this has to
+be performed using user interaction and consent.
+
+User interface
+==============
+When there are errors in the OCFS2 filesystem, they are usually accompanied
+by the inode number which caused the error. This inode number would be the
+input to check/fix the file.
+
+There is a sysfs directory for each OCFS2 file system mounting:
+
+  /sys/fs/ocfs2/<devname>/filecheck
+
+Here, <devname> indicates the name of OCFS2 volumn device which has been already
+mounted. The file above would accept inode numbers. This could be used to
+communicate with kernel space, tell which file(inode number) will be checked or
+fixed. Currently, three operations are supported, which includes checking
+inode, fixing inode and setting the size of result record history.
+
+1. If you want to know what error exactly happened to <inode> before fixing, do
+
+  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/check
+  # cat /sys/fs/ocfs2/<devname>/filecheck/check
+
+The output is like this:
+  INO		DONE	ERROR
+39502		1	GENERATION
+
+<INO> lists the inode numbers.
+<DONE> indicates whether the operation has been finished.
+<ERROR> says what kind of errors was found. For the detailed error numbers,
+please refer to the file linux/fs/ocfs2/filecheck.h.
+
+2. If you determine to fix this inode, do
+
+  # echo "<inode>" > /sys/fs/ocfs2/<devname>/filecheck/fix
+  # cat /sys/fs/ocfs2/<devname>/filecheck/fix
+
+The output is like this:
+  INO		DONE	ERROR
+39502		1	SUCCESS
+
+This time, the <ERROR> column indicates whether this fix is successful or not.
+
+3. The record cache is used to store the history of check/fix results. It's
+defalut size is 10, and can be adjust between the range of 10 ~ 100. You can
+adjust the size like this:
+
+  # echo "<size>" > /sys/fs/ocfs2/<devname>/filecheck/set
+
+Fixing stuff
+============
+On receivng the inode, the filesystem would read the inode and the
+file metadata. In case of errors, the filesystem would fix the errors
+and report the problems it fixed in the kernel log. As a precautionary measure,
+the inode must first be checked for errors before performing a final fix.
+
+The inode and the result history will be maintained temporarily in a
+small linked list buffer which would contain the last (N) inodes
+fixed/checked, the detailed errors which were fixed/checked are printed in the
+kernel log.
-- 
2.1.2

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-02-29  5:17   ` [Ocfs2-devel] " Gang He
@ 2016-03-09  5:40     ` Eric Ren
  -1 siblings, 0 replies; 28+ messages in thread
From: Eric Ren @ 2016-03-09  5:40 UTC (permalink / raw)
  To: Gang He, mfasheh, rgoldwyn; +Cc: linux-kernel, ocfs2-devel



On 02/29/2016 01:17 PM, Gang He wrote:
> Implement online file check sysfile interfaces, e.g.
> how to create the related sysfile according to device name,
> how to display/handle file check request from the sysfile.
>
> Signed-off-by: Gang He <ghe@suse.com>
Tested-by: Eric Ren <zren@suse.com>
> ---
>   fs/ocfs2/Makefile    |   3 +-
>   fs/ocfs2/filecheck.c | 606 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   fs/ocfs2/filecheck.h |  49 +++++
>   fs/ocfs2/inode.h     |   3 +
>   4 files changed, 660 insertions(+), 1 deletion(-)
>   create mode 100644 fs/ocfs2/filecheck.c
>   create mode 100644 fs/ocfs2/filecheck.h
>
> diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
> index ce210d4..e27e652 100644
> --- a/fs/ocfs2/Makefile
> +++ b/fs/ocfs2/Makefile
> @@ -41,7 +41,8 @@ ocfs2-objs := \
>   	quota_local.o		\
>   	quota_global.o		\
>   	xattr.o			\
> -	acl.o
> +	acl.o	\
> +	filecheck.o
>   
>   ocfs2_stackglue-objs := stackglue.o
>   ocfs2_stack_o2cb-objs := stack_o2cb.o
> diff --git a/fs/ocfs2/filecheck.c b/fs/ocfs2/filecheck.c
> new file mode 100644
> index 0000000..2cabbcf
> --- /dev/null
> +++ b/fs/ocfs2/filecheck.c
> @@ -0,0 +1,606 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * filecheck.c
> + *
> + * Code which implements online file check.
> + *
> + * Copyright (C) 2016 SuSE.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation, version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/kmod.h>
> +#include <linux/fs.h>
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
> +#include <linux/sysctl.h>
> +#include <cluster/masklog.h>
> +
> +#include "ocfs2.h"
> +#include "ocfs2_fs.h"
> +#include "stackglue.h"
> +#include "inode.h"
> +
> +#include "filecheck.h"
> +
> +
> +/* File check error strings,
> + * must correspond with error number in header file.
> + */
> +static const char * const ocfs2_filecheck_errs[] = {
> +	"SUCCESS",
> +	"FAILED",
> +	"INPROGRESS",
> +	"READONLY",
> +	"INJBD",
> +	"INVALIDINO",
> +	"BLOCKECC",
> +	"BLOCKNO",
> +	"VALIDFLAG",
> +	"GENERATION",
> +	"UNSUPPORTED"
> +};
> +
> +static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
> +static LIST_HEAD(ocfs2_filecheck_sysfs_list);
> +
> +struct ocfs2_filecheck {
> +	struct list_head fc_head;	/* File check entry list head */
> +	spinlock_t fc_lock;
> +	unsigned int fc_max;	/* Maximum number of entry in list */
> +	unsigned int fc_size;	/* Current entry count in list */
> +	unsigned int fc_done;	/* Finished entry count in list */
> +};
> +
> +struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per mounting */
> +	struct list_head fs_list;
> +	atomic_t fs_count;
> +	struct super_block *fs_sb;
> +	struct kset *fs_devicekset;
> +	struct kset *fs_fcheckkset;
> +	struct ocfs2_filecheck *fs_fcheck;
> +};
> +
> +#define OCFS2_FILECHECK_MAXSIZE		100
> +#define OCFS2_FILECHECK_MINSIZE		10
> +
> +/* File check operation type */
> +enum {
> +	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
> +	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
> +	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
> +};
> +
> +struct ocfs2_filecheck_entry {
> +	struct list_head fe_list;
> +	unsigned long fe_ino;
> +	unsigned int fe_type;
> +	unsigned int fe_done:1;
> +	unsigned int fe_status:31;
> +};
> +
> +struct ocfs2_filecheck_args {
> +	unsigned int fa_type;
> +	union {
> +		unsigned long fa_ino;
> +		unsigned int fa_len;
> +	};
> +};
> +
> +static const char *
> +ocfs2_filecheck_error(int errno)
> +{
> +	if (!errno)
> +		return ocfs2_filecheck_errs[errno];
> +
> +	BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
> +	       errno > OCFS2_FILECHECK_ERR_END);
> +	return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
> +}
> +
> +static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
> +				    struct kobj_attribute *attr,
> +				    char *buf);
> +static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
> +				     struct kobj_attribute *attr,
> +				     const char *buf, size_t count);
> +static struct kobj_attribute ocfs2_attr_filecheck_chk =
> +					__ATTR(check, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +static struct kobj_attribute ocfs2_attr_filecheck_fix =
> +					__ATTR(fix, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +static struct kobj_attribute ocfs2_attr_filecheck_set =
> +					__ATTR(set, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +
> +static int ocfs2_filecheck_sysfs_wait(atomic_t *p)
> +{
> +	schedule();
> +	return 0;
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	struct ocfs2_filecheck_entry *p;
> +
> +	if (!atomic_dec_and_test(&entry->fs_count))
> +		wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait,
> +				 TASK_UNINTERRUPTIBLE);
> +
> +	spin_lock(&entry->fs_fcheck->fc_lock);
> +	while (!list_empty(&entry->fs_fcheck->fc_head)) {
> +		p = list_first_entry(&entry->fs_fcheck->fc_head,
> +				     struct ocfs2_filecheck_entry, fe_list);
> +		list_del(&p->fe_list);
> +		BUG_ON(!p->fe_done); /* To free a undone file check entry */
> +		kfree(p);
> +	}
> +	spin_unlock(&entry->fs_fcheck->fc_lock);
> +
> +	kset_unregister(entry->fs_fcheckkset);
> +	kset_unregister(entry->fs_devicekset);
> +	kfree(entry->fs_fcheck);
> +	kfree(entry);
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list);
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +}
> +
> +static int ocfs2_filecheck_sysfs_del(const char *devname)
> +{
> +	struct ocfs2_filecheck_sysfs_entry *p;
> +
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
> +		if (!strcmp(p->fs_sb->s_id, devname)) {
> +			list_del(&p->fs_list);
> +			spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +			ocfs2_filecheck_sysfs_free(p);
> +			return 0;
> +		}
> +	}
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +	return 1;
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	if (atomic_dec_and_test(&entry->fs_count))
> +		wake_up_atomic_t(&entry->fs_count);
> +}
> +
> +static struct ocfs2_filecheck_sysfs_entry *
> +ocfs2_filecheck_sysfs_get(const char *devname)
> +{
> +	struct ocfs2_filecheck_sysfs_entry *p = NULL;
> +
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
> +		if (!strcmp(p->fs_sb->s_id, devname)) {
> +			atomic_inc(&p->fs_count);
> +			spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +			return p;
> +		}
> +	}
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +	return NULL;
> +}
> +
> +int ocfs2_filecheck_create_sysfs(struct super_block *sb)
> +{
> +	int ret = 0;
> +	struct kset *device_kset = NULL;
> +	struct kset *fcheck_kset = NULL;
> +	struct ocfs2_filecheck *fcheck = NULL;
> +	struct ocfs2_filecheck_sysfs_entry *entry = NULL;
> +	struct attribute **attrs = NULL;
> +	struct attribute_group attrgp;
> +
> +	if (!ocfs2_kset)
> +		return -ENOMEM;
> +
> +	attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
> +	if (!attrs) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		attrs[0] = &ocfs2_attr_filecheck_chk.attr;
> +		attrs[1] = &ocfs2_attr_filecheck_fix.attr;
> +		attrs[2] = &ocfs2_attr_filecheck_set.attr;
> +		attrs[3] = NULL;
> +		memset(&attrgp, 0, sizeof(attrgp));
> +		attrgp.attrs = attrs;
> +	}
> +
> +	fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
> +	if (!fcheck) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		INIT_LIST_HEAD(&fcheck->fc_head);
> +		spin_lock_init(&fcheck->fc_lock);
> +		fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
> +		fcheck->fc_size = 0;
> +		fcheck->fc_done = 0;
> +	}
> +
> +	if (strlen(sb->s_id) <= 0) {
> +		mlog(ML_ERROR,
> +		"Cannot get device basename when create filecheck sysfs\n");
> +		ret = -ENODEV;
> +		goto error;
> +	}
> +
> +	device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
> +	if (!device_kset) {
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	fcheck_kset = kset_create_and_add("filecheck", NULL,
> +					  &device_kset->kobj);
> +	if (!fcheck_kset) {
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
> +	if (ret)
> +		goto error;
> +
> +	entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
> +	if (!entry) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		atomic_set(&entry->fs_count, 1);
> +		entry->fs_sb = sb;
> +		entry->fs_devicekset = device_kset;
> +		entry->fs_fcheckkset = fcheck_kset;
> +		entry->fs_fcheck = fcheck;
> +		ocfs2_filecheck_sysfs_add(entry);
> +	}
> +
> +	kfree(attrs);
> +	return 0;
> +
> +error:
> +	kfree(attrs);
> +	kfree(entry);
> +	kfree(fcheck);
> +	kset_unregister(fcheck_kset);
> +	kset_unregister(device_kset);
> +	return ret;
> +}
> +
> +int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
> +{
> +	return ocfs2_filecheck_sysfs_del(sb->s_id);
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
> +			      unsigned int count);
> +static int
> +ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
> +			   unsigned int len)
> +{
> +	int ret;
> +
> +	if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
> +		return -EINVAL;
> +
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
> +		mlog(ML_ERROR,
> +		"Cannot set online file check maximum entry number "
> +		"to %u due to too many pending entries(%u)\n",
> +		len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
> +		ret = -EBUSY;
> +	} else {
> +		if (len < ent->fs_fcheck->fc_size)
> +			BUG_ON(!ocfs2_filecheck_erase_entries(ent,
> +				ent->fs_fcheck->fc_size - len));
> +
> +		ent->fs_fcheck->fc_max = len;
> +		ret = 0;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +	return ret;
> +}
> +
> +#define OCFS2_FILECHECK_ARGS_LEN	24
> +static int
> +ocfs2_filecheck_args_get_long(const char *buf, size_t count,
> +			      unsigned long *val)
> +{
> +	char buffer[OCFS2_FILECHECK_ARGS_LEN];
> +
> +	memcpy(buffer, buf, count);
> +	buffer[count] = '\0';
> +
> +	if (kstrtoul(buffer, 0, val))
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
> +{
> +	if (!strncmp(name, "fix", 4))
> +		*type = OCFS2_FILECHECK_TYPE_FIX;
> +	else if (!strncmp(name, "check", 6))
> +		*type = OCFS2_FILECHECK_TYPE_CHK;
> +	else if (!strncmp(name, "set", 4))
> +		*type = OCFS2_FILECHECK_TYPE_SET;
> +	else
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
> +			   struct ocfs2_filecheck_args *args)
> +{
> +	unsigned long val = 0;
> +	unsigned int type;
> +
> +	/* too short/long args length */
> +	if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
> +		return 1;
> +
> +	if (ocfs2_filecheck_type_parse(name, &type))
> +		return 1;
> +	if (ocfs2_filecheck_args_get_long(buf, count, &val))
> +		return 1;
> +
> +	if (val <= 0)
> +		return 1;
> +
> +	args->fa_type = type;
> +	if (type == OCFS2_FILECHECK_TYPE_SET)
> +		args->fa_len = (unsigned int)val;
> +	else
> +		args->fa_ino = val;
> +
> +	return 0;
> +}
> +
> +static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
> +				    struct kobj_attribute *attr,
> +				    char *buf)
> +{
> +
> +	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
> +	unsigned int type;
> +	struct ocfs2_filecheck_entry *p;
> +	struct ocfs2_filecheck_sysfs_entry *ent;
> +
> +	if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
> +		return -EINVAL;
> +
> +	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
> +	if (!ent) {
> +		mlog(ML_ERROR,
> +		"Cannot get the corresponding entry via device basename %s\n",
> +		kobj->name);
> +		return -ENODEV;
> +	}
> +
> +	if (type == OCFS2_FILECHECK_TYPE_SET) {
> +		spin_lock(&ent->fs_fcheck->fc_lock);
> +		total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
> +		spin_unlock(&ent->fs_fcheck->fc_lock);
> +		goto exit;
> +	}
> +
> +	ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
> +	total += ret;
> +	remain -= ret;
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
> +		if (p->fe_type != type)
> +			continue;
> +
> +		ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
> +			       p->fe_ino, p->fe_done,
> +			       ocfs2_filecheck_error(p->fe_status));
> +		if (ret < 0) {
> +			total = ret;
> +			break;
> +		}
> +		if (ret == remain) {
> +			/* snprintf() didn't fit */
> +			total = -E2BIG;
> +			break;
> +		}
> +		total += ret;
> +		remain -= ret;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +exit:
> +	ocfs2_filecheck_sysfs_put(ent);
> +	return total;
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
> +{
> +	struct ocfs2_filecheck_entry *p;
> +
> +	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
> +		if (p->fe_done) {
> +			list_del(&p->fe_list);
> +			kfree(p);
> +			ent->fs_fcheck->fc_size--;
> +			ent->fs_fcheck->fc_done--;
> +			return 1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
> +			      unsigned int count)
> +{
> +	unsigned int i = 0;
> +	unsigned int ret = 0;
> +
> +	while (i++ < count) {
> +		if (ocfs2_filecheck_erase_entry(ent))
> +			ret++;
> +		else
> +			break;
> +	}
> +
> +	return (ret == count ? 1 : 0);
> +}
> +
> +static void
> +ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
> +			   struct ocfs2_filecheck_entry *entry)
> +{
> +	entry->fe_done = 1;
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	ent->fs_fcheck->fc_done++;
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +}
> +
> +static unsigned int
> +ocfs2_filecheck_handle(struct super_block *sb,
> +		       unsigned long ino, unsigned int flags)
> +{
> +	unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
> +	struct inode *inode = NULL;
> +	int rc;
> +
> +	inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
> +	if (IS_ERR(inode)) {
> +		rc = (int)(-(long)inode);
> +		if (rc >= OCFS2_FILECHECK_ERR_START &&
> +		    rc < OCFS2_FILECHECK_ERR_END)
> +			ret = rc;
> +		else
> +			ret = OCFS2_FILECHECK_ERR_FAILED;
> +	} else
> +		iput(inode);
> +
> +	return ret;
> +}
> +
> +static void
> +ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
> +			     struct ocfs2_filecheck_entry *entry)
> +{
> +	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
> +		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
> +				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
> +	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
> +		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
> +				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
> +	else
> +		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
> +
> +	ocfs2_filecheck_done_entry(ent, entry);
> +}
> +
> +static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
> +				     struct kobj_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct ocfs2_filecheck_args args;
> +	struct ocfs2_filecheck_entry *entry;
> +	struct ocfs2_filecheck_sysfs_entry *ent;
> +	ssize_t ret = 0;
> +
> +	if (count == 0)
> +		return count;
> +
> +	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
> +		mlog(ML_ERROR, "Invalid arguments for online file check\n");
> +		return -EINVAL;
> +	}
> +
> +	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
> +	if (!ent) {
> +		mlog(ML_ERROR,
> +		"Cannot get the corresponding entry via device basename %s\n",
> +		kobj->parent->name);
> +		return -ENODEV;
> +	}
> +
> +	if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
> +		ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
> +		goto exit;
> +	}
> +
> +	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
> +	if (!entry) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
> +	    (ent->fs_fcheck->fc_done == 0)) {
> +		mlog(ML_ERROR,
> +		"Cannot do more file check "
> +		"since file check queue(%u) is full now\n",
> +		ent->fs_fcheck->fc_max);
> +		ret = -EBUSY;
> +		kfree(entry);
> +	} else {
> +		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
> +		    (ent->fs_fcheck->fc_done > 0)) {
> +			/* Delete the oldest entry which was done,
> +			 * make sure the entry size in list does
> +			 * not exceed maximum value
> +			 */
> +			BUG_ON(!ocfs2_filecheck_erase_entry(ent));
> +		}
> +
> +		entry->fe_ino = args.fa_ino;
> +		entry->fe_type = args.fa_type;
> +		entry->fe_done = 0;
> +		entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
> +		list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
> +		ent->fs_fcheck->fc_size++;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +	if (!ret)
> +		ocfs2_filecheck_handle_entry(ent, entry);
> +
> +exit:
> +	ocfs2_filecheck_sysfs_put(ent);
> +	return (!ret ? count : ret);
> +}
> diff --git a/fs/ocfs2/filecheck.h b/fs/ocfs2/filecheck.h
> new file mode 100644
> index 0000000..e5cd002
> --- /dev/null
> +++ b/fs/ocfs2/filecheck.h
> @@ -0,0 +1,49 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * filecheck.h
> + *
> + * Online file check.
> + *
> + * Copyright (C) 2016 SuSE.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation, version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +
> +#ifndef FILECHECK_H
> +#define FILECHECK_H
> +
> +#include <linux/types.h>
> +#include <linux/list.h>
> +
> +
> +/* File check errno */
> +enum {
> +	OCFS2_FILECHECK_ERR_SUCCESS = 0,	/* Success */
> +	OCFS2_FILECHECK_ERR_FAILED = 1000,	/* Other failure */
> +	OCFS2_FILECHECK_ERR_INPROGRESS,		/* In progress */
> +	OCFS2_FILECHECK_ERR_READONLY,		/* Read only */
> +	OCFS2_FILECHECK_ERR_INJBD,		/* Buffer in jbd */
> +	OCFS2_FILECHECK_ERR_INVALIDINO,		/* Invalid ino */
> +	OCFS2_FILECHECK_ERR_BLOCKECC,		/* Block ecc */
> +	OCFS2_FILECHECK_ERR_BLOCKNO,		/* Block number */
> +	OCFS2_FILECHECK_ERR_VALIDFLAG,		/* Inode valid flag */
> +	OCFS2_FILECHECK_ERR_GENERATION,		/* Inode generation */
> +	OCFS2_FILECHECK_ERR_UNSUPPORTED		/* Unsupported */
> +};
> +
> +#define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
> +#define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
> +
> +int ocfs2_filecheck_create_sysfs(struct super_block *sb);
> +int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
> +
> +#endif  /* FILECHECK_H */
> diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
> index aac8b86..01635e0 100644
> --- a/fs/ocfs2/inode.h
> +++ b/fs/ocfs2/inode.h
> @@ -139,6 +139,9 @@ int ocfs2_drop_inode(struct inode *inode);
>   /* Flags for ocfs2_iget() */
>   #define OCFS2_FI_FLAG_SYSFILE		0x1
>   #define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
> +#define OCFS2_FI_FLAG_FILECHECK_CHK	0x4
> +#define OCFS2_FI_FLAG_FILECHECK_FIX	0x8
> +
>   struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff);
>   struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
>   			 int sysfile_type);

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-09  5:40     ` Eric Ren
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Ren @ 2016-03-09  5:40 UTC (permalink / raw)
  To: Gang He, mfasheh, rgoldwyn; +Cc: linux-kernel, ocfs2-devel



On 02/29/2016 01:17 PM, Gang He wrote:
> Implement online file check sysfile interfaces, e.g.
> how to create the related sysfile according to device name,
> how to display/handle file check request from the sysfile.
>
> Signed-off-by: Gang He <ghe@suse.com>
Tested-by: Eric Ren <zren@suse.com>
> ---
>   fs/ocfs2/Makefile    |   3 +-
>   fs/ocfs2/filecheck.c | 606 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   fs/ocfs2/filecheck.h |  49 +++++
>   fs/ocfs2/inode.h     |   3 +
>   4 files changed, 660 insertions(+), 1 deletion(-)
>   create mode 100644 fs/ocfs2/filecheck.c
>   create mode 100644 fs/ocfs2/filecheck.h
>
> diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
> index ce210d4..e27e652 100644
> --- a/fs/ocfs2/Makefile
> +++ b/fs/ocfs2/Makefile
> @@ -41,7 +41,8 @@ ocfs2-objs := \
>   	quota_local.o		\
>   	quota_global.o		\
>   	xattr.o			\
> -	acl.o
> +	acl.o	\
> +	filecheck.o
>   
>   ocfs2_stackglue-objs := stackglue.o
>   ocfs2_stack_o2cb-objs := stack_o2cb.o
> diff --git a/fs/ocfs2/filecheck.c b/fs/ocfs2/filecheck.c
> new file mode 100644
> index 0000000..2cabbcf
> --- /dev/null
> +++ b/fs/ocfs2/filecheck.c
> @@ -0,0 +1,606 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * filecheck.c
> + *
> + * Code which implements online file check.
> + *
> + * Copyright (C) 2016 SuSE.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation, version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/kmod.h>
> +#include <linux/fs.h>
> +#include <linux/kobject.h>
> +#include <linux/sysfs.h>
> +#include <linux/sysctl.h>
> +#include <cluster/masklog.h>
> +
> +#include "ocfs2.h"
> +#include "ocfs2_fs.h"
> +#include "stackglue.h"
> +#include "inode.h"
> +
> +#include "filecheck.h"
> +
> +
> +/* File check error strings,
> + * must correspond with error number in header file.
> + */
> +static const char * const ocfs2_filecheck_errs[] = {
> +	"SUCCESS",
> +	"FAILED",
> +	"INPROGRESS",
> +	"READONLY",
> +	"INJBD",
> +	"INVALIDINO",
> +	"BLOCKECC",
> +	"BLOCKNO",
> +	"VALIDFLAG",
> +	"GENERATION",
> +	"UNSUPPORTED"
> +};
> +
> +static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
> +static LIST_HEAD(ocfs2_filecheck_sysfs_list);
> +
> +struct ocfs2_filecheck {
> +	struct list_head fc_head;	/* File check entry list head */
> +	spinlock_t fc_lock;
> +	unsigned int fc_max;	/* Maximum number of entry in list */
> +	unsigned int fc_size;	/* Current entry count in list */
> +	unsigned int fc_done;	/* Finished entry count in list */
> +};
> +
> +struct ocfs2_filecheck_sysfs_entry {	/* sysfs entry per mounting */
> +	struct list_head fs_list;
> +	atomic_t fs_count;
> +	struct super_block *fs_sb;
> +	struct kset *fs_devicekset;
> +	struct kset *fs_fcheckkset;
> +	struct ocfs2_filecheck *fs_fcheck;
> +};
> +
> +#define OCFS2_FILECHECK_MAXSIZE		100
> +#define OCFS2_FILECHECK_MINSIZE		10
> +
> +/* File check operation type */
> +enum {
> +	OCFS2_FILECHECK_TYPE_CHK = 0,	/* Check a file(inode) */
> +	OCFS2_FILECHECK_TYPE_FIX,	/* Fix a file(inode) */
> +	OCFS2_FILECHECK_TYPE_SET = 100	/* Set entry list maximum size */
> +};
> +
> +struct ocfs2_filecheck_entry {
> +	struct list_head fe_list;
> +	unsigned long fe_ino;
> +	unsigned int fe_type;
> +	unsigned int fe_done:1;
> +	unsigned int fe_status:31;
> +};
> +
> +struct ocfs2_filecheck_args {
> +	unsigned int fa_type;
> +	union {
> +		unsigned long fa_ino;
> +		unsigned int fa_len;
> +	};
> +};
> +
> +static const char *
> +ocfs2_filecheck_error(int errno)
> +{
> +	if (!errno)
> +		return ocfs2_filecheck_errs[errno];
> +
> +	BUG_ON(errno < OCFS2_FILECHECK_ERR_START ||
> +	       errno > OCFS2_FILECHECK_ERR_END);
> +	return ocfs2_filecheck_errs[errno - OCFS2_FILECHECK_ERR_START + 1];
> +}
> +
> +static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
> +				    struct kobj_attribute *attr,
> +				    char *buf);
> +static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
> +				     struct kobj_attribute *attr,
> +				     const char *buf, size_t count);
> +static struct kobj_attribute ocfs2_attr_filecheck_chk =
> +					__ATTR(check, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +static struct kobj_attribute ocfs2_attr_filecheck_fix =
> +					__ATTR(fix, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +static struct kobj_attribute ocfs2_attr_filecheck_set =
> +					__ATTR(set, S_IRUSR | S_IWUSR,
> +					ocfs2_filecheck_show,
> +					ocfs2_filecheck_store);
> +
> +static int ocfs2_filecheck_sysfs_wait(atomic_t *p)
> +{
> +	schedule();
> +	return 0;
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_free(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	struct ocfs2_filecheck_entry *p;
> +
> +	if (!atomic_dec_and_test(&entry->fs_count))
> +		wait_on_atomic_t(&entry->fs_count, ocfs2_filecheck_sysfs_wait,
> +				 TASK_UNINTERRUPTIBLE);
> +
> +	spin_lock(&entry->fs_fcheck->fc_lock);
> +	while (!list_empty(&entry->fs_fcheck->fc_head)) {
> +		p = list_first_entry(&entry->fs_fcheck->fc_head,
> +				     struct ocfs2_filecheck_entry, fe_list);
> +		list_del(&p->fe_list);
> +		BUG_ON(!p->fe_done); /* To free a undone file check entry */
> +		kfree(p);
> +	}
> +	spin_unlock(&entry->fs_fcheck->fc_lock);
> +
> +	kset_unregister(entry->fs_fcheckkset);
> +	kset_unregister(entry->fs_devicekset);
> +	kfree(entry->fs_fcheck);
> +	kfree(entry);
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_add(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_add_tail(&entry->fs_list, &ocfs2_filecheck_sysfs_list);
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +}
> +
> +static int ocfs2_filecheck_sysfs_del(const char *devname)
> +{
> +	struct ocfs2_filecheck_sysfs_entry *p;
> +
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
> +		if (!strcmp(p->fs_sb->s_id, devname)) {
> +			list_del(&p->fs_list);
> +			spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +			ocfs2_filecheck_sysfs_free(p);
> +			return 0;
> +		}
> +	}
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +	return 1;
> +}
> +
> +static void
> +ocfs2_filecheck_sysfs_put(struct ocfs2_filecheck_sysfs_entry *entry)
> +{
> +	if (atomic_dec_and_test(&entry->fs_count))
> +		wake_up_atomic_t(&entry->fs_count);
> +}
> +
> +static struct ocfs2_filecheck_sysfs_entry *
> +ocfs2_filecheck_sysfs_get(const char *devname)
> +{
> +	struct ocfs2_filecheck_sysfs_entry *p = NULL;
> +
> +	spin_lock(&ocfs2_filecheck_sysfs_lock);
> +	list_for_each_entry(p, &ocfs2_filecheck_sysfs_list, fs_list) {
> +		if (!strcmp(p->fs_sb->s_id, devname)) {
> +			atomic_inc(&p->fs_count);
> +			spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +			return p;
> +		}
> +	}
> +	spin_unlock(&ocfs2_filecheck_sysfs_lock);
> +	return NULL;
> +}
> +
> +int ocfs2_filecheck_create_sysfs(struct super_block *sb)
> +{
> +	int ret = 0;
> +	struct kset *device_kset = NULL;
> +	struct kset *fcheck_kset = NULL;
> +	struct ocfs2_filecheck *fcheck = NULL;
> +	struct ocfs2_filecheck_sysfs_entry *entry = NULL;
> +	struct attribute **attrs = NULL;
> +	struct attribute_group attrgp;
> +
> +	if (!ocfs2_kset)
> +		return -ENOMEM;
> +
> +	attrs = kmalloc(sizeof(struct attribute *) * 4, GFP_NOFS);
> +	if (!attrs) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		attrs[0] = &ocfs2_attr_filecheck_chk.attr;
> +		attrs[1] = &ocfs2_attr_filecheck_fix.attr;
> +		attrs[2] = &ocfs2_attr_filecheck_set.attr;
> +		attrs[3] = NULL;
> +		memset(&attrgp, 0, sizeof(attrgp));
> +		attrgp.attrs = attrs;
> +	}
> +
> +	fcheck = kmalloc(sizeof(struct ocfs2_filecheck), GFP_NOFS);
> +	if (!fcheck) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		INIT_LIST_HEAD(&fcheck->fc_head);
> +		spin_lock_init(&fcheck->fc_lock);
> +		fcheck->fc_max = OCFS2_FILECHECK_MINSIZE;
> +		fcheck->fc_size = 0;
> +		fcheck->fc_done = 0;
> +	}
> +
> +	if (strlen(sb->s_id) <= 0) {
> +		mlog(ML_ERROR,
> +		"Cannot get device basename when create filecheck sysfs\n");
> +		ret = -ENODEV;
> +		goto error;
> +	}
> +
> +	device_kset = kset_create_and_add(sb->s_id, NULL, &ocfs2_kset->kobj);
> +	if (!device_kset) {
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	fcheck_kset = kset_create_and_add("filecheck", NULL,
> +					  &device_kset->kobj);
> +	if (!fcheck_kset) {
> +		ret = -ENOMEM;
> +		goto error;
> +	}
> +
> +	ret = sysfs_create_group(&fcheck_kset->kobj, &attrgp);
> +	if (ret)
> +		goto error;
> +
> +	entry = kmalloc(sizeof(struct ocfs2_filecheck_sysfs_entry), GFP_NOFS);
> +	if (!entry) {
> +		ret = -ENOMEM;
> +		goto error;
> +	} else {
> +		atomic_set(&entry->fs_count, 1);
> +		entry->fs_sb = sb;
> +		entry->fs_devicekset = device_kset;
> +		entry->fs_fcheckkset = fcheck_kset;
> +		entry->fs_fcheck = fcheck;
> +		ocfs2_filecheck_sysfs_add(entry);
> +	}
> +
> +	kfree(attrs);
> +	return 0;
> +
> +error:
> +	kfree(attrs);
> +	kfree(entry);
> +	kfree(fcheck);
> +	kset_unregister(fcheck_kset);
> +	kset_unregister(device_kset);
> +	return ret;
> +}
> +
> +int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
> +{
> +	return ocfs2_filecheck_sysfs_del(sb->s_id);
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
> +			      unsigned int count);
> +static int
> +ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
> +			   unsigned int len)
> +{
> +	int ret;
> +
> +	if ((len < OCFS2_FILECHECK_MINSIZE) || (len > OCFS2_FILECHECK_MAXSIZE))
> +		return -EINVAL;
> +
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	if (len < (ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done)) {
> +		mlog(ML_ERROR,
> +		"Cannot set online file check maximum entry number "
> +		"to %u due to too many pending entries(%u)\n",
> +		len, ent->fs_fcheck->fc_size - ent->fs_fcheck->fc_done);
> +		ret = -EBUSY;
> +	} else {
> +		if (len < ent->fs_fcheck->fc_size)
> +			BUG_ON(!ocfs2_filecheck_erase_entries(ent,
> +				ent->fs_fcheck->fc_size - len));
> +
> +		ent->fs_fcheck->fc_max = len;
> +		ret = 0;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +	return ret;
> +}
> +
> +#define OCFS2_FILECHECK_ARGS_LEN	24
> +static int
> +ocfs2_filecheck_args_get_long(const char *buf, size_t count,
> +			      unsigned long *val)
> +{
> +	char buffer[OCFS2_FILECHECK_ARGS_LEN];
> +
> +	memcpy(buffer, buf, count);
> +	buffer[count] = '\0';
> +
> +	if (kstrtoul(buffer, 0, val))
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_type_parse(const char *name, unsigned int *type)
> +{
> +	if (!strncmp(name, "fix", 4))
> +		*type = OCFS2_FILECHECK_TYPE_FIX;
> +	else if (!strncmp(name, "check", 6))
> +		*type = OCFS2_FILECHECK_TYPE_CHK;
> +	else if (!strncmp(name, "set", 4))
> +		*type = OCFS2_FILECHECK_TYPE_SET;
> +	else
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_args_parse(const char *name, const char *buf, size_t count,
> +			   struct ocfs2_filecheck_args *args)
> +{
> +	unsigned long val = 0;
> +	unsigned int type;
> +
> +	/* too short/long args length */
> +	if ((count < 1) || (count >= OCFS2_FILECHECK_ARGS_LEN))
> +		return 1;
> +
> +	if (ocfs2_filecheck_type_parse(name, &type))
> +		return 1;
> +	if (ocfs2_filecheck_args_get_long(buf, count, &val))
> +		return 1;
> +
> +	if (val <= 0)
> +		return 1;
> +
> +	args->fa_type = type;
> +	if (type == OCFS2_FILECHECK_TYPE_SET)
> +		args->fa_len = (unsigned int)val;
> +	else
> +		args->fa_ino = val;
> +
> +	return 0;
> +}
> +
> +static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
> +				    struct kobj_attribute *attr,
> +				    char *buf)
> +{
> +
> +	ssize_t ret = 0, total = 0, remain = PAGE_SIZE;
> +	unsigned int type;
> +	struct ocfs2_filecheck_entry *p;
> +	struct ocfs2_filecheck_sysfs_entry *ent;
> +
> +	if (ocfs2_filecheck_type_parse(attr->attr.name, &type))
> +		return -EINVAL;
> +
> +	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
> +	if (!ent) {
> +		mlog(ML_ERROR,
> +		"Cannot get the corresponding entry via device basename %s\n",
> +		kobj->name);
> +		return -ENODEV;
> +	}
> +
> +	if (type == OCFS2_FILECHECK_TYPE_SET) {
> +		spin_lock(&ent->fs_fcheck->fc_lock);
> +		total = snprintf(buf, remain, "%u\n", ent->fs_fcheck->fc_max);
> +		spin_unlock(&ent->fs_fcheck->fc_lock);
> +		goto exit;
> +	}
> +
> +	ret = snprintf(buf, remain, "INO\t\tDONE\tERROR\n");
> +	total += ret;
> +	remain -= ret;
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
> +		if (p->fe_type != type)
> +			continue;
> +
> +		ret = snprintf(buf + total, remain, "%lu\t\t%u\t%s\n",
> +			       p->fe_ino, p->fe_done,
> +			       ocfs2_filecheck_error(p->fe_status));
> +		if (ret < 0) {
> +			total = ret;
> +			break;
> +		}
> +		if (ret == remain) {
> +			/* snprintf() didn't fit */
> +			total = -E2BIG;
> +			break;
> +		}
> +		total += ret;
> +		remain -= ret;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +exit:
> +	ocfs2_filecheck_sysfs_put(ent);
> +	return total;
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
> +{
> +	struct ocfs2_filecheck_entry *p;
> +
> +	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
> +		if (p->fe_done) {
> +			list_del(&p->fe_list);
> +			kfree(p);
> +			ent->fs_fcheck->fc_size--;
> +			ent->fs_fcheck->fc_done--;
> +			return 1;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
> +			      unsigned int count)
> +{
> +	unsigned int i = 0;
> +	unsigned int ret = 0;
> +
> +	while (i++ < count) {
> +		if (ocfs2_filecheck_erase_entry(ent))
> +			ret++;
> +		else
> +			break;
> +	}
> +
> +	return (ret == count ? 1 : 0);
> +}
> +
> +static void
> +ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
> +			   struct ocfs2_filecheck_entry *entry)
> +{
> +	entry->fe_done = 1;
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	ent->fs_fcheck->fc_done++;
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +}
> +
> +static unsigned int
> +ocfs2_filecheck_handle(struct super_block *sb,
> +		       unsigned long ino, unsigned int flags)
> +{
> +	unsigned int ret = OCFS2_FILECHECK_ERR_SUCCESS;
> +	struct inode *inode = NULL;
> +	int rc;
> +
> +	inode = ocfs2_iget(OCFS2_SB(sb), ino, flags, 0);
> +	if (IS_ERR(inode)) {
> +		rc = (int)(-(long)inode);
> +		if (rc >= OCFS2_FILECHECK_ERR_START &&
> +		    rc < OCFS2_FILECHECK_ERR_END)
> +			ret = rc;
> +		else
> +			ret = OCFS2_FILECHECK_ERR_FAILED;
> +	} else
> +		iput(inode);
> +
> +	return ret;
> +}
> +
> +static void
> +ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
> +			     struct ocfs2_filecheck_entry *entry)
> +{
> +	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
> +		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
> +				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
> +	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
> +		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
> +				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
> +	else
> +		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
> +
> +	ocfs2_filecheck_done_entry(ent, entry);
> +}
> +
> +static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
> +				     struct kobj_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct ocfs2_filecheck_args args;
> +	struct ocfs2_filecheck_entry *entry;
> +	struct ocfs2_filecheck_sysfs_entry *ent;
> +	ssize_t ret = 0;
> +
> +	if (count == 0)
> +		return count;
> +
> +	if (ocfs2_filecheck_args_parse(attr->attr.name, buf, count, &args)) {
> +		mlog(ML_ERROR, "Invalid arguments for online file check\n");
> +		return -EINVAL;
> +	}
> +
> +	ent = ocfs2_filecheck_sysfs_get(kobj->parent->name);
> +	if (!ent) {
> +		mlog(ML_ERROR,
> +		"Cannot get the corresponding entry via device basename %s\n",
> +		kobj->parent->name);
> +		return -ENODEV;
> +	}
> +
> +	if (args.fa_type == OCFS2_FILECHECK_TYPE_SET) {
> +		ret = ocfs2_filecheck_adjust_max(ent, args.fa_len);
> +		goto exit;
> +	}
> +
> +	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
> +	if (!entry) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	spin_lock(&ent->fs_fcheck->fc_lock);
> +	if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
> +	    (ent->fs_fcheck->fc_done == 0)) {
> +		mlog(ML_ERROR,
> +		"Cannot do more file check "
> +		"since file check queue(%u) is full now\n",
> +		ent->fs_fcheck->fc_max);
> +		ret = -EBUSY;
> +		kfree(entry);
> +	} else {
> +		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
> +		    (ent->fs_fcheck->fc_done > 0)) {
> +			/* Delete the oldest entry which was done,
> +			 * make sure the entry size in list does
> +			 * not exceed maximum value
> +			 */
> +			BUG_ON(!ocfs2_filecheck_erase_entry(ent));
> +		}
> +
> +		entry->fe_ino = args.fa_ino;
> +		entry->fe_type = args.fa_type;
> +		entry->fe_done = 0;
> +		entry->fe_status = OCFS2_FILECHECK_ERR_INPROGRESS;
> +		list_add_tail(&entry->fe_list, &ent->fs_fcheck->fc_head);
> +		ent->fs_fcheck->fc_size++;
> +	}
> +	spin_unlock(&ent->fs_fcheck->fc_lock);
> +
> +	if (!ret)
> +		ocfs2_filecheck_handle_entry(ent, entry);
> +
> +exit:
> +	ocfs2_filecheck_sysfs_put(ent);
> +	return (!ret ? count : ret);
> +}
> diff --git a/fs/ocfs2/filecheck.h b/fs/ocfs2/filecheck.h
> new file mode 100644
> index 0000000..e5cd002
> --- /dev/null
> +++ b/fs/ocfs2/filecheck.h
> @@ -0,0 +1,49 @@
> +/* -*- mode: c; c-basic-offset: 8; -*-
> + * vim: noexpandtab sw=8 ts=8 sts=0:
> + *
> + * filecheck.h
> + *
> + * Online file check.
> + *
> + * Copyright (C) 2016 SuSE.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public
> + * License as published by the Free Software Foundation, version 2.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details.
> + */
> +
> +
> +#ifndef FILECHECK_H
> +#define FILECHECK_H
> +
> +#include <linux/types.h>
> +#include <linux/list.h>
> +
> +
> +/* File check errno */
> +enum {
> +	OCFS2_FILECHECK_ERR_SUCCESS = 0,	/* Success */
> +	OCFS2_FILECHECK_ERR_FAILED = 1000,	/* Other failure */
> +	OCFS2_FILECHECK_ERR_INPROGRESS,		/* In progress */
> +	OCFS2_FILECHECK_ERR_READONLY,		/* Read only */
> +	OCFS2_FILECHECK_ERR_INJBD,		/* Buffer in jbd */
> +	OCFS2_FILECHECK_ERR_INVALIDINO,		/* Invalid ino */
> +	OCFS2_FILECHECK_ERR_BLOCKECC,		/* Block ecc */
> +	OCFS2_FILECHECK_ERR_BLOCKNO,		/* Block number */
> +	OCFS2_FILECHECK_ERR_VALIDFLAG,		/* Inode valid flag */
> +	OCFS2_FILECHECK_ERR_GENERATION,		/* Inode generation */
> +	OCFS2_FILECHECK_ERR_UNSUPPORTED		/* Unsupported */
> +};
> +
> +#define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
> +#define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
> +
> +int ocfs2_filecheck_create_sysfs(struct super_block *sb);
> +int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
> +
> +#endif  /* FILECHECK_H */
> diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
> index aac8b86..01635e0 100644
> --- a/fs/ocfs2/inode.h
> +++ b/fs/ocfs2/inode.h
> @@ -139,6 +139,9 @@ int ocfs2_drop_inode(struct inode *inode);
>   /* Flags for ocfs2_iget() */
>   #define OCFS2_FI_FLAG_SYSFILE		0x1
>   #define OCFS2_FI_FLAG_ORPHAN_RECOVERY	0x2
> +#define OCFS2_FI_FLAG_FILECHECK_CHK	0x4
> +#define OCFS2_FI_FLAG_FILECHECK_FIX	0x8
> +
>   struct inode *ocfs2_ilookup(struct super_block *sb, u64 feoff);
>   struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 feoff, unsigned flags,
>   			 int sysfile_type);

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
  2016-02-29  5:18   ` [Ocfs2-devel] " Gang He
@ 2016-03-09  5:41     ` Eric Ren
  -1 siblings, 0 replies; 28+ messages in thread
From: Eric Ren @ 2016-03-09  5:41 UTC (permalink / raw)
  To: Gang He, mfasheh, rgoldwyn; +Cc: linux-kernel, ocfs2-devel



On 02/29/2016 01:18 PM, Gang He wrote:
> Implement online check or fix inode block during
> reading a inode block to memory.
>
> Signed-off-by: Gang He <ghe@suse.com>
Tested-by: Eric Ren <zren@suse.com>
> ---
>   fs/ocfs2/inode.c       | 225 +++++++++++++++++++++++++++++++++++++++++++++++--
>   fs/ocfs2/ocfs2_trace.h |   2 +
>   2 files changed, 218 insertions(+), 9 deletions(-)
>
> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> index 8f87e05..6ce531e 100644
> --- a/fs/ocfs2/inode.c
> +++ b/fs/ocfs2/inode.c
> @@ -53,6 +53,7 @@
>   #include "xattr.h"
>   #include "refcounttree.h"
>   #include "ocfs2_trace.h"
> +#include "filecheck.h"
>   
>   #include "buffer_head_io.h"
>   
> @@ -74,6 +75,14 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
>   				    struct inode *inode,
>   				    struct buffer_head *fe_bh);
>   
> +static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
> +						 struct buffer_head **bh,
> +						 int flags, int type);
> +static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> +						struct buffer_head *bh);
> +static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> +					      struct buffer_head *bh);
> +
>   void ocfs2_set_inode_flags(struct inode *inode)
>   {
>   	unsigned int flags = OCFS2_I(inode)->ip_attr;
> @@ -127,6 +136,7 @@ struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno)
>   struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
>   			 int sysfile_type)
>   {
> +	int rc = 0;
>   	struct inode *inode = NULL;
>   	struct super_block *sb = osb->sb;
>   	struct ocfs2_find_inode_args args;
> @@ -161,12 +171,17 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
>   	}
>   	trace_ocfs2_iget5_locked(inode->i_state);
>   	if (inode->i_state & I_NEW) {
> -		ocfs2_read_locked_inode(inode, &args);
> +		rc = ocfs2_read_locked_inode(inode, &args);
>   		unlock_new_inode(inode);
>   	}
>   	if (is_bad_inode(inode)) {
>   		iput(inode);
> -		inode = ERR_PTR(-ESTALE);
> +		if ((flags & OCFS2_FI_FLAG_FILECHECK_CHK) ||
> +		    (flags & OCFS2_FI_FLAG_FILECHECK_FIX))
> +			/* Return OCFS2_FILECHECK_ERR_XXX related errno */
> +			inode = ERR_PTR(rc);
> +		else
> +			inode = ERR_PTR(-ESTALE);
>   		goto bail;
>   	}
>   
> @@ -409,7 +424,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   	struct ocfs2_super *osb;
>   	struct ocfs2_dinode *fe;
>   	struct buffer_head *bh = NULL;
> -	int status, can_lock;
> +	int status, can_lock, lock_level = 0;
>   	u32 generation = 0;
>   
>   	status = -EINVAL;
> @@ -477,7 +492,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   			mlog_errno(status);
>   			return status;
>   		}
> -		status = ocfs2_inode_lock(inode, NULL, 0);
> +		status = ocfs2_inode_lock(inode, NULL, lock_level);
>   		if (status) {
>   			make_bad_inode(inode);
>   			mlog_errno(status);
> @@ -494,16 +509,32 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   	}
>   
>   	if (can_lock) {
> -		status = ocfs2_read_inode_block_full(inode, &bh,
> -						     OCFS2_BH_IGNORE_CACHE);
> +		if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
> +			status = ocfs2_filecheck_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE, 0);
> +		else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
> +			status = ocfs2_filecheck_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE, 1);
> +		else
> +			status = ocfs2_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE);
>   	} else {
>   		status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
>   		/*
>   		 * If buffer is in jbd, then its checksum may not have been
>   		 * computed as yet.
>   		 */
> -		if (!status && !buffer_jbd(bh))
> -			status = ocfs2_validate_inode_block(osb->sb, bh);
> +		if (!status && !buffer_jbd(bh)) {
> +			if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
> +				status = ocfs2_filecheck_validate_inode_block(
> +								osb->sb, bh);
> +			else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
> +				status = ocfs2_filecheck_repair_inode_block(
> +								osb->sb, bh);
> +			else
> +				status = ocfs2_validate_inode_block(
> +								osb->sb, bh);
> +		}
>   	}
>   	if (status < 0) {
>   		mlog_errno(status);
> @@ -531,11 +562,24 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   
>   	BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
>   
> +	if (buffer_dirty(bh) && !buffer_jbd(bh)) {
> +		if (can_lock) {
> +			ocfs2_inode_unlock(inode, lock_level);
> +			lock_level = 1;
> +			ocfs2_inode_lock(inode, NULL, lock_level);
> +		}
> +		status = ocfs2_write_block(osb, bh, INODE_CACHE(inode));
> +		if (status < 0) {
> +			mlog_errno(status);
> +			goto bail;
> +		}
> +	}
> +
>   	status = 0;
>   
>   bail:
>   	if (can_lock)
> -		ocfs2_inode_unlock(inode, 0);
> +		ocfs2_inode_unlock(inode, lock_level);
>   
>   	if (status < 0)
>   		make_bad_inode(inode);
> @@ -1396,6 +1440,169 @@ bail:
>   	return rc;
>   }
>   
> +static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> +						struct buffer_head *bh)
> +{
> +	int rc = 0;
> +	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
> +
> +	trace_ocfs2_filecheck_validate_inode_block(
> +		(unsigned long long)bh->b_blocknr);
> +
> +	BUG_ON(!buffer_uptodate(bh));
> +
> +	/*
> +	 * Call ocfs2_validate_meta_ecc() first since it has ecc repair
> +	 * function, but we should not return error immediately when ecc
> +	 * validation fails, because the reason is quite likely the invalid
> +	 * inode number inputed.
> +	 */
> +	rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check);
> +	if (rc) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: checksum failed for dinode %llu\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		rc = -OCFS2_FILECHECK_ERR_BLOCKECC;
> +	}
> +
> +	if (!OCFS2_IS_VALID_DINODE(di)) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: signature = %.*s\n",
> +		     (unsigned long long)bh->b_blocknr, 7, di->i_signature);
> +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> +		goto bail;
> +	} else if (rc)
> +		goto bail;
> +
> +	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: i_blkno is %llu\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     (unsigned long long)le64_to_cpu(di->i_blkno));
> +		rc = -OCFS2_FILECHECK_ERR_BLOCKNO;
> +		goto bail;
> +	}
> +
> +	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL "
> +		     "not set\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		rc = -OCFS2_FILECHECK_ERR_VALIDFLAG;
> +		goto bail;
> +	}
> +
> +	if (le32_to_cpu(di->i_fs_generation) !=
> +	    OCFS2_SB(sb)->fs_generation) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: fs_generation is %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le32_to_cpu(di->i_fs_generation));
> +		rc = -OCFS2_FILECHECK_ERR_GENERATION;
> +		goto bail;
> +	}
> +
> +bail:
> +	return rc;
> +}
> +
> +static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> +					      struct buffer_head *bh)
> +{
> +	int changed = 0;
> +	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
> +
> +	if (!ocfs2_filecheck_validate_inode_block(sb, bh))
> +		return 0;
> +
> +	trace_ocfs2_filecheck_repair_inode_block(
> +		(unsigned long long)bh->b_blocknr);
> +
> +	if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) ||
> +	    ocfs2_is_soft_readonly(OCFS2_SB(sb))) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: cannot repair dinode #%llu "
> +		     "on readonly filesystem\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		return -OCFS2_FILECHECK_ERR_READONLY;
> +	}
> +
> +	if (buffer_jbd(bh)) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: cannot repair dinode #%llu, "
> +		     "its buffer is in jbd\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		return -OCFS2_FILECHECK_ERR_INJBD;
> +	}
> +
> +	if (!OCFS2_IS_VALID_DINODE(di)) {
> +		/* Cannot fix invalid inode block */
> +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
> +	}
> +
> +	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
> +		/* Cannot just add VALID_FL flag back as a fix,
> +		 * need more things to check here.
> +		 */
> +		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
> +	}
> +
> +	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> +		di->i_blkno = cpu_to_le64(bh->b_blocknr);
> +		changed = 1;
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: i_blkno to %llu\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     (unsigned long long)le64_to_cpu(di->i_blkno));
> +	}
> +
> +	if (le32_to_cpu(di->i_fs_generation) !=
> +	    OCFS2_SB(sb)->fs_generation) {
> +		di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);
> +		changed = 1;
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: fs_generation to %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le32_to_cpu(di->i_fs_generation));
> +	}
> +
> +	if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) {
> +		ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check);
> +		mark_buffer_dirty(bh);
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: compute meta ecc\n",
> +		     (unsigned long long)bh->b_blocknr);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_read_inode_block_full(struct inode *inode,
> +				      struct buffer_head **bh,
> +				      int flags, int type)
> +{
> +	int rc;
> +	struct buffer_head *tmp = *bh;
> +
> +	if (!type) /* Check inode block */
> +		rc = ocfs2_read_blocks(INODE_CACHE(inode),
> +				OCFS2_I(inode)->ip_blkno,
> +				1, &tmp, flags,
> +				ocfs2_filecheck_validate_inode_block);
> +	else /* Repair inode block */
> +		rc = ocfs2_read_blocks(INODE_CACHE(inode),
> +				OCFS2_I(inode)->ip_blkno,
> +				1, &tmp, flags,
> +				ocfs2_filecheck_repair_inode_block);
> +
> +	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
> +	if (!rc && !*bh)
> +		*bh = tmp;
> +
> +	return rc;
> +}
> +
>   int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
>   				int flags)
>   {
> diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
> index 6cb019b..d9205e0 100644
> --- a/fs/ocfs2/ocfs2_trace.h
> +++ b/fs/ocfs2/ocfs2_trace.h
> @@ -1540,6 +1540,8 @@ DEFINE_OCFS2_ULL_INT_EVENT(ocfs2_read_locked_inode);
>   DEFINE_OCFS2_INT_INT_EVENT(ocfs2_check_orphan_recovery_state);
>   
>   DEFINE_OCFS2_ULL_EVENT(ocfs2_validate_inode_block);
> +DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_validate_inode_block);
> +DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_repair_inode_block);
>   
>   TRACE_EVENT(ocfs2_inode_is_valid_to_delete,
>   	TP_PROTO(void *task, void *dc_task, unsigned long long ino,

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
@ 2016-03-09  5:41     ` Eric Ren
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Ren @ 2016-03-09  5:41 UTC (permalink / raw)
  To: Gang He, mfasheh, rgoldwyn; +Cc: linux-kernel, ocfs2-devel



On 02/29/2016 01:18 PM, Gang He wrote:
> Implement online check or fix inode block during
> reading a inode block to memory.
>
> Signed-off-by: Gang He <ghe@suse.com>
Tested-by: Eric Ren <zren@suse.com>
> ---
>   fs/ocfs2/inode.c       | 225 +++++++++++++++++++++++++++++++++++++++++++++++--
>   fs/ocfs2/ocfs2_trace.h |   2 +
>   2 files changed, 218 insertions(+), 9 deletions(-)
>
> diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
> index 8f87e05..6ce531e 100644
> --- a/fs/ocfs2/inode.c
> +++ b/fs/ocfs2/inode.c
> @@ -53,6 +53,7 @@
>   #include "xattr.h"
>   #include "refcounttree.h"
>   #include "ocfs2_trace.h"
> +#include "filecheck.h"
>   
>   #include "buffer_head_io.h"
>   
> @@ -74,6 +75,14 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
>   				    struct inode *inode,
>   				    struct buffer_head *fe_bh);
>   
> +static int ocfs2_filecheck_read_inode_block_full(struct inode *inode,
> +						 struct buffer_head **bh,
> +						 int flags, int type);
> +static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> +						struct buffer_head *bh);
> +static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> +					      struct buffer_head *bh);
> +
>   void ocfs2_set_inode_flags(struct inode *inode)
>   {
>   	unsigned int flags = OCFS2_I(inode)->ip_attr;
> @@ -127,6 +136,7 @@ struct inode *ocfs2_ilookup(struct super_block *sb, u64 blkno)
>   struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
>   			 int sysfile_type)
>   {
> +	int rc = 0;
>   	struct inode *inode = NULL;
>   	struct super_block *sb = osb->sb;
>   	struct ocfs2_find_inode_args args;
> @@ -161,12 +171,17 @@ struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags,
>   	}
>   	trace_ocfs2_iget5_locked(inode->i_state);
>   	if (inode->i_state & I_NEW) {
> -		ocfs2_read_locked_inode(inode, &args);
> +		rc = ocfs2_read_locked_inode(inode, &args);
>   		unlock_new_inode(inode);
>   	}
>   	if (is_bad_inode(inode)) {
>   		iput(inode);
> -		inode = ERR_PTR(-ESTALE);
> +		if ((flags & OCFS2_FI_FLAG_FILECHECK_CHK) ||
> +		    (flags & OCFS2_FI_FLAG_FILECHECK_FIX))
> +			/* Return OCFS2_FILECHECK_ERR_XXX related errno */
> +			inode = ERR_PTR(rc);
> +		else
> +			inode = ERR_PTR(-ESTALE);
>   		goto bail;
>   	}
>   
> @@ -409,7 +424,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   	struct ocfs2_super *osb;
>   	struct ocfs2_dinode *fe;
>   	struct buffer_head *bh = NULL;
> -	int status, can_lock;
> +	int status, can_lock, lock_level = 0;
>   	u32 generation = 0;
>   
>   	status = -EINVAL;
> @@ -477,7 +492,7 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   			mlog_errno(status);
>   			return status;
>   		}
> -		status = ocfs2_inode_lock(inode, NULL, 0);
> +		status = ocfs2_inode_lock(inode, NULL, lock_level);
>   		if (status) {
>   			make_bad_inode(inode);
>   			mlog_errno(status);
> @@ -494,16 +509,32 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   	}
>   
>   	if (can_lock) {
> -		status = ocfs2_read_inode_block_full(inode, &bh,
> -						     OCFS2_BH_IGNORE_CACHE);
> +		if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
> +			status = ocfs2_filecheck_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE, 0);
> +		else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
> +			status = ocfs2_filecheck_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE, 1);
> +		else
> +			status = ocfs2_read_inode_block_full(inode,
> +						&bh, OCFS2_BH_IGNORE_CACHE);
>   	} else {
>   		status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
>   		/*
>   		 * If buffer is in jbd, then its checksum may not have been
>   		 * computed as yet.
>   		 */
> -		if (!status && !buffer_jbd(bh))
> -			status = ocfs2_validate_inode_block(osb->sb, bh);
> +		if (!status && !buffer_jbd(bh)) {
> +			if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_CHK)
> +				status = ocfs2_filecheck_validate_inode_block(
> +								osb->sb, bh);
> +			else if (args->fi_flags & OCFS2_FI_FLAG_FILECHECK_FIX)
> +				status = ocfs2_filecheck_repair_inode_block(
> +								osb->sb, bh);
> +			else
> +				status = ocfs2_validate_inode_block(
> +								osb->sb, bh);
> +		}
>   	}
>   	if (status < 0) {
>   		mlog_errno(status);
> @@ -531,11 +562,24 @@ static int ocfs2_read_locked_inode(struct inode *inode,
>   
>   	BUG_ON(args->fi_blkno != le64_to_cpu(fe->i_blkno));
>   
> +	if (buffer_dirty(bh) && !buffer_jbd(bh)) {
> +		if (can_lock) {
> +			ocfs2_inode_unlock(inode, lock_level);
> +			lock_level = 1;
> +			ocfs2_inode_lock(inode, NULL, lock_level);
> +		}
> +		status = ocfs2_write_block(osb, bh, INODE_CACHE(inode));
> +		if (status < 0) {
> +			mlog_errno(status);
> +			goto bail;
> +		}
> +	}
> +
>   	status = 0;
>   
>   bail:
>   	if (can_lock)
> -		ocfs2_inode_unlock(inode, 0);
> +		ocfs2_inode_unlock(inode, lock_level);
>   
>   	if (status < 0)
>   		make_bad_inode(inode);
> @@ -1396,6 +1440,169 @@ bail:
>   	return rc;
>   }
>   
> +static int ocfs2_filecheck_validate_inode_block(struct super_block *sb,
> +						struct buffer_head *bh)
> +{
> +	int rc = 0;
> +	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
> +
> +	trace_ocfs2_filecheck_validate_inode_block(
> +		(unsigned long long)bh->b_blocknr);
> +
> +	BUG_ON(!buffer_uptodate(bh));
> +
> +	/*
> +	 * Call ocfs2_validate_meta_ecc() first since it has ecc repair
> +	 * function, but we should not return error immediately when ecc
> +	 * validation fails, because the reason is quite likely the invalid
> +	 * inode number inputed.
> +	 */
> +	rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check);
> +	if (rc) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: checksum failed for dinode %llu\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		rc = -OCFS2_FILECHECK_ERR_BLOCKECC;
> +	}
> +
> +	if (!OCFS2_IS_VALID_DINODE(di)) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: signature = %.*s\n",
> +		     (unsigned long long)bh->b_blocknr, 7, di->i_signature);
> +		rc = -OCFS2_FILECHECK_ERR_INVALIDINO;
> +		goto bail;
> +	} else if (rc)
> +		goto bail;
> +
> +	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: i_blkno is %llu\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     (unsigned long long)le64_to_cpu(di->i_blkno));
> +		rc = -OCFS2_FILECHECK_ERR_BLOCKNO;
> +		goto bail;
> +	}
> +
> +	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: OCFS2_VALID_FL "
> +		     "not set\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		rc = -OCFS2_FILECHECK_ERR_VALIDFLAG;
> +		goto bail;
> +	}
> +
> +	if (le32_to_cpu(di->i_fs_generation) !=
> +	    OCFS2_SB(sb)->fs_generation) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: invalid dinode #%llu: fs_generation is %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le32_to_cpu(di->i_fs_generation));
> +		rc = -OCFS2_FILECHECK_ERR_GENERATION;
> +		goto bail;
> +	}
> +
> +bail:
> +	return rc;
> +}
> +
> +static int ocfs2_filecheck_repair_inode_block(struct super_block *sb,
> +					      struct buffer_head *bh)
> +{
> +	int changed = 0;
> +	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
> +
> +	if (!ocfs2_filecheck_validate_inode_block(sb, bh))
> +		return 0;
> +
> +	trace_ocfs2_filecheck_repair_inode_block(
> +		(unsigned long long)bh->b_blocknr);
> +
> +	if (ocfs2_is_hard_readonly(OCFS2_SB(sb)) ||
> +	    ocfs2_is_soft_readonly(OCFS2_SB(sb))) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: cannot repair dinode #%llu "
> +		     "on readonly filesystem\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		return -OCFS2_FILECHECK_ERR_READONLY;
> +	}
> +
> +	if (buffer_jbd(bh)) {
> +		mlog(ML_ERROR,
> +		     "Filecheck: cannot repair dinode #%llu, "
> +		     "its buffer is in jbd\n",
> +		     (unsigned long long)bh->b_blocknr);
> +		return -OCFS2_FILECHECK_ERR_INJBD;
> +	}
> +
> +	if (!OCFS2_IS_VALID_DINODE(di)) {
> +		/* Cannot fix invalid inode block */
> +		return -OCFS2_FILECHECK_ERR_INVALIDINO;
> +	}
> +
> +	if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) {
> +		/* Cannot just add VALID_FL flag back as a fix,
> +		 * need more things to check here.
> +		 */
> +		return -OCFS2_FILECHECK_ERR_VALIDFLAG;
> +	}
> +
> +	if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) {
> +		di->i_blkno = cpu_to_le64(bh->b_blocknr);
> +		changed = 1;
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: i_blkno to %llu\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     (unsigned long long)le64_to_cpu(di->i_blkno));
> +	}
> +
> +	if (le32_to_cpu(di->i_fs_generation) !=
> +	    OCFS2_SB(sb)->fs_generation) {
> +		di->i_fs_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);
> +		changed = 1;
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: fs_generation to %u\n",
> +		     (unsigned long long)bh->b_blocknr,
> +		     le32_to_cpu(di->i_fs_generation));
> +	}
> +
> +	if (changed || ocfs2_validate_meta_ecc(sb, bh->b_data, &di->i_check)) {
> +		ocfs2_compute_meta_ecc(sb, bh->b_data, &di->i_check);
> +		mark_buffer_dirty(bh);
> +		mlog(ML_ERROR,
> +		     "Filecheck: reset dinode #%llu: compute meta ecc\n",
> +		     (unsigned long long)bh->b_blocknr);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +ocfs2_filecheck_read_inode_block_full(struct inode *inode,
> +				      struct buffer_head **bh,
> +				      int flags, int type)
> +{
> +	int rc;
> +	struct buffer_head *tmp = *bh;
> +
> +	if (!type) /* Check inode block */
> +		rc = ocfs2_read_blocks(INODE_CACHE(inode),
> +				OCFS2_I(inode)->ip_blkno,
> +				1, &tmp, flags,
> +				ocfs2_filecheck_validate_inode_block);
> +	else /* Repair inode block */
> +		rc = ocfs2_read_blocks(INODE_CACHE(inode),
> +				OCFS2_I(inode)->ip_blkno,
> +				1, &tmp, flags,
> +				ocfs2_filecheck_repair_inode_block);
> +
> +	/* If ocfs2_read_blocks() got us a new bh, pass it up. */
> +	if (!rc && !*bh)
> +		*bh = tmp;
> +
> +	return rc;
> +}
> +
>   int ocfs2_read_inode_block_full(struct inode *inode, struct buffer_head **bh,
>   				int flags)
>   {
> diff --git a/fs/ocfs2/ocfs2_trace.h b/fs/ocfs2/ocfs2_trace.h
> index 6cb019b..d9205e0 100644
> --- a/fs/ocfs2/ocfs2_trace.h
> +++ b/fs/ocfs2/ocfs2_trace.h
> @@ -1540,6 +1540,8 @@ DEFINE_OCFS2_ULL_INT_EVENT(ocfs2_read_locked_inode);
>   DEFINE_OCFS2_INT_INT_EVENT(ocfs2_check_orphan_recovery_state);
>   
>   DEFINE_OCFS2_ULL_EVENT(ocfs2_validate_inode_block);
> +DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_validate_inode_block);
> +DEFINE_OCFS2_ULL_EVENT(ocfs2_filecheck_repair_inode_block);
>   
>   TRACE_EVENT(ocfs2_inode_is_valid_to_delete,
>   	TP_PROTO(void *task, void *dc_task, unsigned long long ino,

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
  2016-02-29  5:18   ` [Ocfs2-devel] " Gang He
@ 2016-03-21 22:16     ` Mark Fasheh
  -1 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 22:16 UTC (permalink / raw)
  To: Gang He; +Cc: rgoldwyn, linux-kernel, ocfs2-devel

On Mon, Feb 29, 2016 at 01:18:01PM +0800, Gang He wrote:
> Implement online check or fix inode block during
> reading a inode block to memory.
> 
> Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
@ 2016-03-21 22:16     ` Mark Fasheh
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 22:16 UTC (permalink / raw)
  To: Gang He; +Cc: rgoldwyn, linux-kernel, ocfs2-devel

On Mon, Feb 29, 2016 at 01:18:01PM +0800, Gang He wrote:
> Implement online check or fix inode block during
> reading a inode block to memory.
> 
> Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-02-29  5:17   ` [Ocfs2-devel] " Gang He
@ 2016-03-21 22:57     ` Mark Fasheh
  -1 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 22:57 UTC (permalink / raw)
  To: Gang He; +Cc: rgoldwyn, linux-kernel, ocfs2-devel, akpm

On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> Implement online file check sysfile interfaces, e.g.
> how to create the related sysfile according to device name,
> how to display/handle file check request from the sysfile.
> 
> Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-21 22:57     ` Mark Fasheh
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 22:57 UTC (permalink / raw)
  To: Gang He; +Cc: rgoldwyn, linux-kernel, ocfs2-devel, akpm

On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> Implement online file check sysfile interfaces, e.g.
> how to create the related sysfile according to device name,
> how to display/handle file check request from the sysfile.
> 
> Signed-off-by: Gang He <ghe@suse.com>
Reviewed-by: Mark Fasheh <mfasheh@suse.de>

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-03-21 22:57     ` [Ocfs2-devel] " Mark Fasheh
@ 2016-03-21 23:05       ` Andrew Morton
  -1 siblings, 0 replies; 28+ messages in thread
From: Andrew Morton @ 2016-03-21 23:05 UTC (permalink / raw)
  To: Mark Fasheh; +Cc: Gang He, rgoldwyn, linux-kernel, ocfs2-devel

On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:

> On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > Implement online file check sysfile interfaces, e.g.
> > how to create the related sysfile according to device name,
> > how to display/handle file check request from the sysfile.
> > 
> > Signed-off-by: Gang He <ghe@suse.com>
> Reviewed-by: Mark Fasheh <mfasheh@suse.de>

Thanks.  So all of

ocfs2-export-ocfs2_kset-for-online-file-check.patch
ocfs2-sysfile-interfaces-for-online-file-check.patch
ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
ocfs2-create-remove-sysfile-for-online-file-check.patch
ocfs2-check-fix-inode-block-for-online-file-check.patch
ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
ocfs2-add-feature-document-for-online-file-check.patch

have your reviewed-by.  I'll send them on to Linus.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-21 23:05       ` Andrew Morton
  0 siblings, 0 replies; 28+ messages in thread
From: Andrew Morton @ 2016-03-21 23:05 UTC (permalink / raw)
  To: Mark Fasheh; +Cc: Gang He, rgoldwyn, linux-kernel, ocfs2-devel

On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:

> On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > Implement online file check sysfile interfaces, e.g.
> > how to create the related sysfile according to device name,
> > how to display/handle file check request from the sysfile.
> > 
> > Signed-off-by: Gang He <ghe@suse.com>
> Reviewed-by: Mark Fasheh <mfasheh@suse.de>

Thanks.  So all of

ocfs2-export-ocfs2_kset-for-online-file-check.patch
ocfs2-sysfile-interfaces-for-online-file-check.patch
ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
ocfs2-create-remove-sysfile-for-online-file-check.patch
ocfs2-check-fix-inode-block-for-online-file-check.patch
ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
ocfs2-add-feature-document-for-online-file-check.patch

have your reviewed-by.  I'll send them on to Linus.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-03-21 23:05       ` [Ocfs2-devel] " Andrew Morton
@ 2016-03-21 23:38         ` Mark Fasheh
  -1 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 23:38 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, ocfs2-devel

On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
> On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> 
> > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > > Implement online file check sysfile interfaces, e.g.
> > > how to create the related sysfile according to device name,
> > > how to display/handle file check request from the sysfile.
> > > 
> > > Signed-off-by: Gang He <ghe@suse.com>
> > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
> 
> Thanks.  So all of
> 
> ocfs2-export-ocfs2_kset-for-online-file-check.patch
> ocfs2-sysfile-interfaces-for-online-file-check.patch
> ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
> ocfs2-create-remove-sysfile-for-online-file-check.patch
> ocfs2-check-fix-inode-block-for-online-file-check.patch
> ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
> ocfs2-add-feature-document-for-online-file-check.patch
> 
> have your reviewed-by.  I'll send them on to Linus.

I'm curious, are the '-V4' patches built on top of the non '-V4' versions?

Otherwise though this generally sounds good to me - I have reviewed the
entire online fsck patch series.
	--Mark

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-21 23:38         ` Mark Fasheh
  0 siblings, 0 replies; 28+ messages in thread
From: Mark Fasheh @ 2016-03-21 23:38 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, ocfs2-devel

On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
> On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> 
> > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > > Implement online file check sysfile interfaces, e.g.
> > > how to create the related sysfile according to device name,
> > > how to display/handle file check request from the sysfile.
> > > 
> > > Signed-off-by: Gang He <ghe@suse.com>
> > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
> 
> Thanks.  So all of
> 
> ocfs2-export-ocfs2_kset-for-online-file-check.patch
> ocfs2-sysfile-interfaces-for-online-file-check.patch
> ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
> ocfs2-create-remove-sysfile-for-online-file-check.patch
> ocfs2-check-fix-inode-block-for-online-file-check.patch
> ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
> ocfs2-add-feature-document-for-online-file-check.patch
> 
> have your reviewed-by.  I'll send them on to Linus.

I'm curious, are the '-V4' patches built on top of the non '-V4' versions?

Otherwise though this generally sounds good to me - I have reviewed the
entire online fsck patch series.
	--Mark

--
Mark Fasheh

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-03-21 23:38         ` Mark Fasheh
@ 2016-03-22  1:01           ` Andrew Morton
  -1 siblings, 0 replies; 28+ messages in thread
From: Andrew Morton @ 2016-03-22  1:01 UTC (permalink / raw)
  To: Mark Fasheh; +Cc: linux-kernel, ocfs2-devel

On Mon, 21 Mar 2016 16:38:02 -0700 Mark Fasheh <mfasheh@suse.de> wrote:

> On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
> > On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> > 
> > > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > > > Implement online file check sysfile interfaces, e.g.
> > > > how to create the related sysfile according to device name,
> > > > how to display/handle file check request from the sysfile.
> > > > 
> > > > Signed-off-by: Gang He <ghe@suse.com>
> > > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
> > 
> > Thanks.  So all of
> > 
> > ocfs2-export-ocfs2_kset-for-online-file-check.patch
> > ocfs2-sysfile-interfaces-for-online-file-check.patch
> > ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
> > ocfs2-create-remove-sysfile-for-online-file-check.patch
> > ocfs2-check-fix-inode-block-for-online-file-check.patch
> > ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
> > ocfs2-add-feature-document-for-online-file-check.patch
> > 
> > have your reviewed-by.  I'll send them on to Linus.
> 
> I'm curious, are the '-V4' patches built on top of the non '-V4' versions?

yes, the -v4 patches bring the base patch from
whatever-version-i-originally-merged up to v4.

> Otherwise though this generally sounds good to me - I have reviewed the
> entire online fsck patch series.

Cool.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-22  1:01           ` Andrew Morton
  0 siblings, 0 replies; 28+ messages in thread
From: Andrew Morton @ 2016-03-22  1:01 UTC (permalink / raw)
  To: Mark Fasheh; +Cc: linux-kernel, ocfs2-devel

On Mon, 21 Mar 2016 16:38:02 -0700 Mark Fasheh <mfasheh@suse.de> wrote:

> On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
> > On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> > 
> > > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
> > > > Implement online file check sysfile interfaces, e.g.
> > > > how to create the related sysfile according to device name,
> > > > how to display/handle file check request from the sysfile.
> > > > 
> > > > Signed-off-by: Gang He <ghe@suse.com>
> > > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
> > 
> > Thanks.  So all of
> > 
> > ocfs2-export-ocfs2_kset-for-online-file-check.patch
> > ocfs2-sysfile-interfaces-for-online-file-check.patch
> > ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
> > ocfs2-create-remove-sysfile-for-online-file-check.patch
> > ocfs2-check-fix-inode-block-for-online-file-check.patch
> > ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
> > ocfs2-add-feature-document-for-online-file-check.patch
> > 
> > have your reviewed-by.  I'll send them on to Linus.
> 
> I'm curious, are the '-V4' patches built on top of the non '-V4' versions?

yes, the -v4 patches bring the base patch from
whatever-version-i-originally-merged up to v4.

> Otherwise though this generally sounds good to me - I have reviewed the
> entire online fsck patch series.

Cool.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
  2016-03-22  1:01           ` Andrew Morton
@ 2016-03-22  2:15             ` Gang He
  -1 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-03-22  2:15 UTC (permalink / raw)
  To: akpm, Mark Fasheh; +Cc: ocfs2-devel, linux-kernel

Hello Mark and Andrew,

Thank for taking the time in reviewing the patches, move the thing forward.


Thanks
Gang




>>> 
> On Mon, 21 Mar 2016 16:38:02 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> 
>> On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
>> > On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
>> > 
>> > > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
>> > > > Implement online file check sysfile interfaces, e.g.
>> > > > how to create the related sysfile according to device name,
>> > > > how to display/handle file check request from the sysfile.
>> > > > 
>> > > > Signed-off-by: Gang He <ghe@suse.com>
>> > > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
>> > 
>> > Thanks.  So all of
>> > 
>> > ocfs2-export-ocfs2_kset-for-online-file-check.patch
>> > ocfs2-sysfile-interfaces-for-online-file-check.patch
>> > ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
>> > ocfs2-create-remove-sysfile-for-online-file-check.patch
>> > ocfs2-check-fix-inode-block-for-online-file-check.patch
>> > ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
>> > ocfs2-add-feature-document-for-online-file-check.patch
>> > 
>> > have your reviewed-by.  I'll send them on to Linus.
>> 
>> I'm curious, are the '-V4' patches built on top of the non '-V4' versions?
> 
> yes, the -v4 patches bring the base patch from
> whatever-version-i-originally-merged up to v4.
> 
>> Otherwise though this generally sounds good to me - I have reviewed the
>> entire online fsck patch series.
> 
> Cool.
> 
> _______________________________________________
> Ocfs2-devel mailing list
> Ocfs2-devel@oss.oracle.com 
> https://oss.oracle.com/mailman/listinfo/ocfs2-devel

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
@ 2016-03-22  2:15             ` Gang He
  0 siblings, 0 replies; 28+ messages in thread
From: Gang He @ 2016-03-22  2:15 UTC (permalink / raw)
  To: akpm, Mark Fasheh; +Cc: ocfs2-devel, linux-kernel

Hello Mark and Andrew,

Thank for taking the time in reviewing the patches, move the thing forward.


Thanks
Gang




>>> 
> On Mon, 21 Mar 2016 16:38:02 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
> 
>> On Mon, Mar 21, 2016 at 04:05:47PM -0700, Andrew Morton wrote:
>> > On Mon, 21 Mar 2016 15:57:23 -0700 Mark Fasheh <mfasheh@suse.de> wrote:
>> > 
>> > > On Mon, Feb 29, 2016 at 01:17:59PM +0800, Gang He wrote:
>> > > > Implement online file check sysfile interfaces, e.g.
>> > > > how to create the related sysfile according to device name,
>> > > > how to display/handle file check request from the sysfile.
>> > > > 
>> > > > Signed-off-by: Gang He <ghe@suse.com>
>> > > Reviewed-by: Mark Fasheh <mfasheh@suse.de>
>> > 
>> > Thanks.  So all of
>> > 
>> > ocfs2-export-ocfs2_kset-for-online-file-check.patch
>> > ocfs2-sysfile-interfaces-for-online-file-check.patch
>> > ocfs2-sysfile-interfaces-for-online-file-check-v4.patch
>> > ocfs2-create-remove-sysfile-for-online-file-check.patch
>> > ocfs2-check-fix-inode-block-for-online-file-check.patch
>> > ocfs2-check-fix-inode-block-for-online-file-check-v4.patch
>> > ocfs2-add-feature-document-for-online-file-check.patch
>> > 
>> > have your reviewed-by.  I'll send them on to Linus.
>> 
>> I'm curious, are the '-V4' patches built on top of the non '-V4' versions?
> 
> yes, the -v4 patches bring the base patch from
> whatever-version-i-originally-merged up to v4.
> 
>> Otherwise though this generally sounds good to me - I have reviewed the
>> entire online fsck patch series.
> 
> Cool.
> 
> _______________________________________________
> Ocfs2-devel mailing list
> Ocfs2-devel at oss.oracle.com 
> https://oss.oracle.com/mailman/listinfo/ocfs2-devel

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2016-03-22  2:15 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-29  5:17 [PATCH v4 0/5] Add online file check feature Gang He
2016-02-29  5:17 ` [Ocfs2-devel] " Gang He
2016-02-29  5:17 ` [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check Gang He
2016-02-29  5:17   ` [Ocfs2-devel] " Gang He
2016-02-29  5:17 ` [PATCH v4 2/5] ocfs2: sysfile interfaces " Gang He
2016-02-29  5:17   ` [Ocfs2-devel] " Gang He
2016-03-09  5:40   ` Eric Ren
2016-03-09  5:40     ` Eric Ren
2016-03-21 22:57   ` Mark Fasheh
2016-03-21 22:57     ` [Ocfs2-devel] " Mark Fasheh
2016-03-21 23:05     ` Andrew Morton
2016-03-21 23:05       ` [Ocfs2-devel] " Andrew Morton
2016-03-21 23:38       ` Mark Fasheh
2016-03-21 23:38         ` Mark Fasheh
2016-03-22  1:01         ` Andrew Morton
2016-03-22  1:01           ` Andrew Morton
2016-03-22  2:15           ` Gang He
2016-03-22  2:15             ` Gang He
2016-02-29  5:18 ` [PATCH v4 3/5] ocfs2: create/remove sysfile " Gang He
2016-02-29  5:18   ` [Ocfs2-devel] " Gang He
2016-02-29  5:18 ` [PATCH v4 4/5] ocfs2: check/fix inode block " Gang He
2016-02-29  5:18   ` [Ocfs2-devel] " Gang He
2016-03-09  5:41   ` Eric Ren
2016-03-09  5:41     ` Eric Ren
2016-03-21 22:16   ` Mark Fasheh
2016-03-21 22:16     ` Mark Fasheh
2016-02-29  5:18 ` [PATCH v4 5/5] ocfs2: add feature document " Gang He
2016-02-29  5:18   ` [Ocfs2-devel] " Gang He

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.