* [Ocfs2-devel] [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check
2016-02-29 5:17 [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature Gang He
@ 2016-02-29 5:17 ` Gang He
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces " Gang He
` (3 subsequent siblings)
4 siblings, 0 replies; 14+ 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] 14+ messages in thread* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
2016-02-29 5:17 [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature Gang He
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check Gang He
@ 2016-02-29 5:17 ` Gang He
2016-03-09 5:40 ` Eric Ren
2016-03-21 22:57 ` Mark Fasheh
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 3/5] ocfs2: create/remove sysfile " Gang He
` (2 subsequent siblings)
4 siblings, 2 replies; 14+ 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] 14+ messages in thread* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces " Gang He
@ 2016-03-09 5:40 ` Eric Ren
2016-03-21 22:57 ` Mark Fasheh
1 sibling, 0 replies; 14+ 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] 14+ messages in thread* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces " Gang He
2016-03-09 5:40 ` Eric Ren
@ 2016-03-21 22:57 ` Mark Fasheh
2016-03-21 23:05 ` Andrew Morton
1 sibling, 1 reply; 14+ 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] 14+ messages in thread
* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
2016-03-21 22:57 ` Mark Fasheh
@ 2016-03-21 23:05 ` Andrew Morton
2016-03-21 23:38 ` Mark Fasheh
0 siblings, 1 reply; 14+ 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] 14+ messages in thread
* [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces for online file check
2016-03-21 23:05 ` Andrew Morton
@ 2016-03-21 23:38 ` Mark Fasheh
2016-03-22 1:01 ` Andrew Morton
0 siblings, 1 reply; 14+ 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] 14+ messages in thread
* [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
2016-03-22 2:15 ` Gang He
0 siblings, 1 reply; 14+ 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] 14+ messages in thread
* [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
0 siblings, 0 replies; 14+ 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] 14+ messages in thread
* [Ocfs2-devel] [PATCH v4 3/5] ocfs2: create/remove sysfile for online file check
2016-02-29 5:17 [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature Gang He
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 1/5] ocfs2: export ocfs2_kset for online file check Gang He
2016-02-29 5:17 ` [Ocfs2-devel] [PATCH v4 2/5] ocfs2: sysfile interfaces " Gang He
@ 2016-02-29 5:18 ` Gang He
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block " Gang He
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 5/5] ocfs2: add feature document " Gang He
4 siblings, 0 replies; 14+ 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] 14+ messages in thread
* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
2016-02-29 5:17 [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature Gang He
` (2 preceding siblings ...)
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 3/5] ocfs2: create/remove sysfile " Gang He
@ 2016-02-29 5:18 ` Gang He
2016-03-09 5:41 ` Eric Ren
2016-03-21 22:16 ` Mark Fasheh
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 5/5] ocfs2: add feature document " Gang He
4 siblings, 2 replies; 14+ 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] 14+ messages in thread* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block " Gang He
@ 2016-03-09 5:41 ` Eric Ren
2016-03-21 22:16 ` Mark Fasheh
1 sibling, 0 replies; 14+ 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] 14+ messages in thread* [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block for online file check
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block " Gang He
2016-03-09 5:41 ` Eric Ren
@ 2016-03-21 22:16 ` Mark Fasheh
1 sibling, 0 replies; 14+ 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] 14+ messages in thread
* [Ocfs2-devel] [PATCH v4 5/5] ocfs2: add feature document for online file check
2016-02-29 5:17 [Ocfs2-devel] [PATCH v4 0/5] Add online file check feature Gang He
` (3 preceding siblings ...)
2016-02-29 5:18 ` [Ocfs2-devel] [PATCH v4 4/5] ocfs2: check/fix inode block " Gang He
@ 2016-02-29 5:18 ` Gang He
4 siblings, 0 replies; 14+ 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] 14+ messages in thread