Skip to contentSkip to conversation

ocfs2: sysfs and cleanup

PATCH New Goldwyn Rodrigues 3 participants 27 messages May 26, 2016 – Jun 6, 2016 4 messages not in the archive OCFS2

lore
Share & tools
lore
#0 lore raw

v2 cover ocfs2: sysfs and cleanup

From: Goldwyn Rodrigues <[email protected]>

This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. All other files are added in this directory. This is done by:
1. Adding kobject in the ocfs2_super structure
2. Using ocfs2_sb_attr which encompass all the show() and store() functions

This also reduce code and does away with unnecessary data structure, but adds some in the ocfs2_super for house keeping.

Hopefully, this would be used to further add configurable parameters for the super block.

Suggestions/Criticism welcome.

Changes since v1:
- Corrected store() function check

Signature · 1 line
Goldwyn
#1 lore raw

PATCH v2 1/5 ocfs2: Provisions for sysfs entries

From: Goldwyn Rodrigues <[email protected]>

This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This is done by adding the kobj into the ocfs2_super. All other files are added in this directory.

Introduce ocfs2_sb_attr which encompasses the store() and show() functions. Move all the important data structures with respect to filechecks to ocfs2_super.

More superblock information should move in here.

---
 fs/ocfs2/Makefile |  3 +-
 fs/ocfs2/ocfs2.h  |  4 +++
 fs/ocfs2/super.c  |  7 +++--
 fs/ocfs2/sysfs.c  | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/sysfs.h  |  9 ++++++
 5 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 fs/ocfs2/sysfs.c
 create mode 100644 fs/ocfs2/sysfs.h
fs/ocfs2/Makefile +2 -1
index e27e652..716ed45 100644
@@ -41,7 +41,8 @@ ocfs2-objs := \
 	quota_local.o		\
 	quota_global.o		\
 	xattr.o			\
-	acl.o	\
+	acl.o			\
+	sysfs.o			\
 	filecheck.o
 
 ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/ocfs2.h +4 -0
index e63af7d..8e66cdf 100644
@@ -37,6 +37,7 @@
 #include <linux/mutex.h>
 #include <linux/lockdep.h>
 #include <linux/jbd2.h>
+#include <linux/kobject.h>
 
 /* For union ocfs2_dlm_lksb */
 #include "stackglue.h"
@@ -472,6 +473,9 @@ struct ocfs2_super
 	 * workqueue and schedule on our own.
 	 */
 	struct workqueue_struct *ocfs2_wq;
+
+	struct kobject kobj;
+	struct completion kobj_unregister;
 };
 
 #define OCFS2_SB(sb)	    ((struct ocfs2_super *)(sb)->s_fs_info)
fs/ocfs2/super.c +4 -3
index d7cae33..96b7a9f 100644
@@ -75,6 +75,7 @@
 
 #include "buffer_head_io.h"
 #include "filecheck.h"
+#include "sysfs.h"
 
 static struct kmem_cache *ocfs2_inode_cachep;
 struct kmem_cache *ocfs2_dquot_cachep;
@@ -1200,8 +1201,8 @@ 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);
+	/* Create sysfs entries */
+	ocfs2_sysfs_sb_init(sb);
 
 	return status;
 
@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb)
 {
 	trace_ocfs2_put_super(sb);
 
+	ocfs2_sysfs_sb_exit(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)
fs/ocfs2/sysfs.c new file +92 -0

92 lines not on this page · raw message

fs/ocfs2/sysfs.h new file +9 -0
new file mode 100644
index 0000000..d929ac1
@@ -0,0 +1,9 @@
+
+
+#ifndef _SYS_H
+#define _SYS_H
+
+int ocfs2_sysfs_sb_init(struct super_block *sb);
+void ocfs2_sysfs_sb_exit(struct super_block *sb);
+
+#endif
Signature · 1 line
2.6.6
#2 lore raw

PATCH 1/5 ocfs2: Provisions for sysfs entries

Hello Goldwyn,

Thanks for your code, my comments are inline.

Quoted 4 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This

Gang: My suggestion is to create a sysfs directory device_name under /sys/fs/ocfs2 per each file system, The file system generic attributes should be located under this top sub directory /sys/fs/ocfs2/<s_id>, but we should create a separate sub directory (e.g. filecheck) under this top sub directory for file check feature, then, all the file check related attributes should be located under that directory /sys/fs/ocfs2/<s_id>/filecheck. You know, in the future, we maybe add more attributes/sub directories under /sys/fs/ocfs2/<s_id>,
I should make sure the file check feature is not mixed with other things, it is easy to read/debug for the users/developers.

fs/ocfs2/sysfs.c

Quoted 97 lines

is done by adding the kobj into the ocfs2_super. All other files are added in this directory.

Introduce ocfs2_sb_attr which encompasses the store() and show() functions. Move all the important data structures with respect to filechecks to ocfs2_super.

More superblock information should move in here.

---
 fs/ocfs2/Makefile |  3 +-
 fs/ocfs2/ocfs2.h  |  4 +++
 fs/ocfs2/super.c  |  7 +++--
 fs/ocfs2/sysfs.c  | 92 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ocfs2/sysfs.h  |  9 ++++++
 5 files changed, 111 insertions(+), 4 deletions(-)
 create mode 100644 fs/ocfs2/sysfs.c
 create mode 100644 fs/ocfs2/sysfs.h
fs/ocfs2/Makefile +2 -1
index e27e652..716ed45 100644
@@ -41,7 +41,8 @@ ocfs2-objs := \
 	quota_local.o		\
 	quota_global.o		\
 	xattr.o			\
-	acl.o	\
+	acl.o			\
+	sysfs.o			\
 	filecheck.o
 
 ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/ocfs2.h +4 -0
index e63af7d..8e66cdf 100644
@@ -37,6 +37,7 @@
 #include <linux/mutex.h>
 #include <linux/lockdep.h>
 #include <linux/jbd2.h>
+#include <linux/kobject.h>
 
 /* For union ocfs2_dlm_lksb */
 #include "stackglue.h"
@@ -472,6 +473,9 @@ struct ocfs2_super
 	 * workqueue and schedule on our own.
 	 */
 	struct workqueue_struct *ocfs2_wq;
+
+	struct kobject kobj;
+	struct completion kobj_unregister;
 };
 
 #define OCFS2_SB(sb)	    ((struct ocfs2_super *)(sb)->s_fs_info)
fs/ocfs2/super.c +4 -3
index d7cae33..96b7a9f 100644
@@ -75,6 +75,7 @@
 
 #include "buffer_head_io.h"
 #include "filecheck.h"
+#include "sysfs.h"
 
 static struct kmem_cache *ocfs2_inode_cachep;
 struct kmem_cache *ocfs2_dquot_cachep;
@@ -1200,8 +1201,8 @@ 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);
+	/* Create sysfs entries */
+	ocfs2_sysfs_sb_init(sb);
 
 	return status;
@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb)
 {
 	trace_ocfs2_put_super(sb);
 
+	ocfs2_sysfs_sb_exit(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)
fs/ocfs2/sysfs.c new file +0 -0
new file mode 100644
index 0000000..e21e699

Gang: please add source file comments like other source files.

fs/ocfs2/sysfs.h

Quoted 98 lines
fs/ocfs2/sysfs.c new file +92 -0
@@ -0,0 +1,92 @@
+#include "ocfs2.h"
+#include "sysfs.h"
+
+struct ocfs2_sb_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			char *buf);
+	ssize_t (*store)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			const char *buf, size_t count);
+};
+
+#define OCFS2_SB_ATTR(_name, _mode) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+
+#define OCFS2_SB_ATTR_RO(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t ocfs2_sb_attr_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->show)
+		return -EIO;
+
+	return oa->show(osb, oa, buf);
+}
+
+static ssize_t ocfs2_sb_attr_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t count)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->store)
+		return -EIO;
+
+	return oa->store(osb, oa, buf, count);
+}
+
+static ssize_t slot_num_show(struct ocfs2_super *osb,
+			     struct ocfs2_sb_attr *attr,
+	  		     char *buf)
+{
+	return sprintf(buf, "%d\n", osb->slot_num);
+}
+
+static void sb_release(struct kobject *kobj)
+{
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	complete(&osb->kobj_unregister);
+}
+
+static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
+	.show = ocfs2_sb_attr_show,
+	.store = ocfs2_sb_attr_store,
+};
+
+static OCFS2_SB_ATTR_RO(slot_num);
+static struct attribute *ocfs2_sb_attrs[] = {
+	&sb_attr_slot_num.attr,
+	NULL
+};
+
+static struct kobj_type ocfs2_sb_ktype = {
+	.sysfs_ops 	= &ocfs2_sb_sysfs_ops,
+	.default_attrs 	= ocfs2_sb_attrs,
+	.release	= sb_release,
+};
+
+
+int ocfs2_sysfs_sb_init(struct super_block *sb)
+{
+	int err;
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	init_completion(&osb->kobj_unregister);
+	osb->kobj.kset = ocfs2_kset;
+	err = kobject_init_and_add(&osb->kobj, &ocfs2_sb_ktype, NULL, "%s", sb->s_id);
+	return err;
+
+}
+
+void ocfs2_sysfs_sb_exit(struct super_block *sb)
+{
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	kobject_del(&osb->kobj);
+	kobject_put(&osb->kobj);
+	wait_for_completion(&osb->kobj_unregister);
+}
+
+
fs/ocfs2/sysfs.h new file +0 -0
new file mode 100644
index 0000000..d929ac1

Gang: please add header file comments like other header files.

Quoted 18 lines
fs/ocfs2/sysfs.h new file +9 -0
@@ -0,0 +1,9 @@
+
+
+#ifndef _SYS_H
+#define _SYS_H
+
+int ocfs2_sysfs_sb_init(struct super_block *sb);
+void ocfs2_sysfs_sb_exit(struct super_block *sb);
+
+#endif
Signature · 7 lines
2.6.6


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com 
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw

PATCH 1/5 ocfs2: Provisions for sysfs entries

Quoted 8 lines · Gang He

Hello Goldwyn,

Thanks for your code, my comments are inline.

Quoted 3 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Quoted 8 lines
Quoted 1 line

This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This

Gang: My suggestion is to create a sysfs directory device_name under /sys/fs/ocfs2 per each file system, The file system generic attributes should be located under this top sub directory /sys/fs/ocfs2/<s_id>, but we should create a separate sub directory (e.g. filecheck) under this top sub directory for file check feature, then, all the file check related attributes should be located under that directory /sys/fs/ocfs2/<s_id>/filecheck. You know, in the future, we maybe add more attributes/sub directories under /sys/fs/ocfs2/<s_id>,
I should make sure the file check feature is not mixed with other things, it is easy to read/debug for the users/developers.

I don't think keeping it separate is important. We would need a separate kset for incorporating all of this. Besides, mulitple redirections will mess it up more than keep it simple. However, we should document what each portion is used for.

I don't see a point in using multiple structures when they would not be references at multiple points, at least in this case.

Quoted 190 lines

fs/ocfs2/sysfs.c

Quoted 97 lines

is done by adding the kobj into the ocfs2_super. All other files are added in this directory.

Introduce ocfs2_sb_attr which encompasses the store() and show() functions. Move all the important data structures with respect to filechecks to ocfs2_super.

More superblock information should move in here.

---
  fs/ocfs2/Makefile |  3 +-
  fs/ocfs2/ocfs2.h  |  4 +++
  fs/ocfs2/super.c  |  7 +++--
  fs/ocfs2/sysfs.c  | 92
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  fs/ocfs2/sysfs.h  |  9 ++++++
  5 files changed, 111 insertions(+), 4 deletions(-)

create mode 100644 fs/ocfs2/sysfs.c
create mode 100644 fs/ocfs2/sysfs.h

fs/ocfs2/Makefile +2 -1
index e27e652..716ed45 100644
@@ -41,7 +41,8 @@ ocfs2-objs := \
  	quota_local.o		\
  	quota_global.o		\
  	xattr.o			\
-	acl.o	\
+	acl.o			\
+	sysfs.o			\
  	filecheck.o
 
  ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/ocfs2.h +4 -0
index e63af7d..8e66cdf 100644
@@ -37,6 +37,7 @@
  #include <linux/mutex.h>
  #include <linux/lockdep.h>
  #include <linux/jbd2.h>
+#include <linux/kobject.h>
 
  /* For union ocfs2_dlm_lksb */
  #include "stackglue.h"
@@ -472,6 +473,9 @@ struct ocfs2_super
  	 * workqueue and schedule on our own.
  	 */
  	struct workqueue_struct *ocfs2_wq;
+
+	struct kobject kobj;
+	struct completion kobj_unregister;
  };
 
  #define OCFS2_SB(sb)	    ((struct ocfs2_super *)(sb)->s_fs_info)
fs/ocfs2/super.c +4 -3
index d7cae33..96b7a9f 100644
@@ -75,6 +75,7 @@
 
  #include "buffer_head_io.h"
  #include "filecheck.h"
+#include "sysfs.h"
 
  static struct kmem_cache *ocfs2_inode_cachep;
  struct kmem_cache *ocfs2_dquot_cachep;
@@ -1200,8 +1201,8 @@ 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);
+	/* Create sysfs entries */
+	ocfs2_sysfs_sb_init(sb);
 
  	return status;
@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb)
  {
  	trace_ocfs2_put_super(sb);
 
+	ocfs2_sysfs_sb_exit(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)
fs/ocfs2/sysfs.c new file +0 -0
new file mode 100644
index 0000000..e21e699

Gang: please add source file comments like other source files.

Quoted 91 lines
fs/ocfs2/sysfs.c new file +90 -0
@@ -0,0 +1,92 @@
+#include "ocfs2.h"
+#include "sysfs.h"
+
+struct ocfs2_sb_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			char *buf);
+	ssize_t (*store)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			const char *buf, size_t count);
+};
+
+#define OCFS2_SB_ATTR(_name, _mode) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+
+#define OCFS2_SB_ATTR_RO(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t ocfs2_sb_attr_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->show)
+		return -EIO;
+
+	return oa->show(osb, oa, buf);
+}
+
+static ssize_t ocfs2_sb_attr_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t count)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->store)
+		return -EIO;
+
+	return oa->store(osb, oa, buf, count);
+}
+
+static ssize_t slot_num_show(struct ocfs2_super *osb,
+			     struct ocfs2_sb_attr *attr,
+	  		     char *buf)
+{
+	return sprintf(buf, "%d\n", osb->slot_num);
+}
+
+static void sb_release(struct kobject *kobj)
+{
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	complete(&osb->kobj_unregister);
+}
+
+static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
+	.show = ocfs2_sb_attr_show,
+	.store = ocfs2_sb_attr_store,
+};
+
+static OCFS2_SB_ATTR_RO(slot_num);
+static struct attribute *ocfs2_sb_attrs[] = {
+	&sb_attr_slot_num.attr,
+	NULL
+};
+
+static struct kobj_type ocfs2_sb_ktype = {
+	.sysfs_ops 	= &ocfs2_sb_sysfs_ops,
+	.default_attrs 	= ocfs2_sb_attrs,
+	.release	= sb_release,
+};
+
+
+int ocfs2_sysfs_sb_init(struct super_block *sb)
+{
+	int err;
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	init_completion(&osb->kobj_unregister);
+	osb->kobj.kset = ocfs2_kset;
+	err = kobject_init_and_add(&osb->kobj, &ocfs2_sb_ktype, NULL, "%s", sb->s_id);
+	return err;
+
+}
+
+void ocfs2_sysfs_sb_exit(struct super_block *sb)
+{
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	kobject_del(&osb->kobj);
+	kobject_put(&osb->kobj);
+	wait_for_completion(&osb->kobj_unregister);
+}
Quoted 9 lines

fs/ocfs2/sysfs.h

Quoted 7 lines
fs/ocfs2/sysfs.c new file +2 -0
+
+
fs/ocfs2/sysfs.h new file +0 -0
new file mode 100644
index 0000000..d929ac1

Gang: please add header file comments like other header files.

Agree.

Quoted 18 lines
Quoted 18 lines
fs/ocfs2/sysfs.h new file +9 -1
@@ -0,0 +1,9 @@
+
+
+#ifndef _SYS_H
+#define _SYS_H
+
+int ocfs2_sysfs_sb_init(struct super_block *sb);
+void ocfs2_sysfs_sb_exit(struct super_block *sb);
+
+#endif
--

2.6.6

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

Signature · 1 line
Goldwyn
#5 lore raw

PATCH 1/5 ocfs2: Provisions for sysfs entries

Quoted 30 lines
Quoted 4 lines
Quoted 4 lines
Quoted 10 lines · Gang He

Hello Goldwyn,

Thanks for your code, my comments are inline.

Quoted 4 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This adds /sys/fs/ocfs2/<s_id> to the sys filesystem. This

Gang: My suggestion is to create a sysfs directory device_name under

/sys/fs/ocfs2 per each file system,

Quoted 1 line

The file system generic attributes should be located under this top sub

directory /sys/fs/ocfs2/<s_id>,

Quoted 1 line

but we should create a separate sub directory (e.g. filecheck) under this

top sub directory for file check feature,

Quoted 1 line

then, all the file check related attributes should be located under that

directory /sys/fs/ocfs2/<s_id>/filecheck.

Quoted 1 line

You know, in the future, we maybe add more attributes/sub directories under

/sys/fs/ocfs2/<s_id>,

Quoted 1 line

I should make sure the file check feature is not mixed with other things, it

is easy to read/debug for the users/developers.

Quoted 1 line
Quoted 7 lines

I don't think keeping it separate is important. We would need a separate kset for incorporating all of this. Besides, mulitple redirections will mess it up more than keep it simple. However, we should document what each portion is used for.

I don't see a point in using multiple structures when they would not be references at multiple points, at least in this case.

Gang: I prefer to use a separate sysfs directory for file check things, you know, maybe in the future
there will be more and more generic attributes under <device_name> sysfs directory for each file system. this will make the thing complicated, but actually the existing code have done like that, just re-use the code. But anyway, it is not too important for using/not using a separate sysfs directory for file check, I just worry about the future.

Quoted 225 lines
Quoted 192 lines

fs/ocfs2/sysfs.c

Quoted 99 lines

is done by adding the kobj into the ocfs2_super. All other files are added in this directory.

Introduce ocfs2_sb_attr which encompasses the store() and show() functions. Move all the important data structures with respect to filechecks to ocfs2_super.

More superblock information should move in here.

---
  fs/ocfs2/Makefile |  3 +-
  fs/ocfs2/ocfs2.h  |  4 +++
  fs/ocfs2/super.c  |  7 +++--
  fs/ocfs2/sysfs.c  | 92
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
  fs/ocfs2/sysfs.h  |  9 ++++++
  5 files changed, 111 insertions(+), 4 deletions(-)

create mode 100644 fs/ocfs2/sysfs.c
create mode 100644 fs/ocfs2/sysfs.h

fs/ocfs2/Makefile +2 -1
index e27e652..716ed45 100644
@@ -41,7 +41,8 @@ ocfs2-objs := \
  	quota_local.o		\
  	quota_global.o		\
  	xattr.o			\
-	acl.o	\
+	acl.o			\
+	sysfs.o			\
  	filecheck.o
 
  ocfs2_stackglue-objs := stackglue.o
fs/ocfs2/ocfs2.h +4 -0
index e63af7d..8e66cdf 100644
@@ -37,6 +37,7 @@
  #include <linux/mutex.h>
  #include <linux/lockdep.h>
  #include <linux/jbd2.h>
+#include <linux/kobject.h>
 
  /* For union ocfs2_dlm_lksb */
  #include "stackglue.h"
@@ -472,6 +473,9 @@ struct ocfs2_super
  	 * workqueue and schedule on our own.
  	 */
  	struct workqueue_struct *ocfs2_wq;
+
+	struct kobject kobj;
+	struct completion kobj_unregister;
  };
 
  #define OCFS2_SB(sb)	    ((struct ocfs2_super *)(sb)->s_fs_info)
fs/ocfs2/super.c +4 -3
index d7cae33..96b7a9f 100644
@@ -75,6 +75,7 @@
 
  #include "buffer_head_io.h"
  #include "filecheck.h"
+#include "sysfs.h"
 
  static struct kmem_cache *ocfs2_inode_cachep;
  struct kmem_cache *ocfs2_dquot_cachep;
@@ -1200,8 +1201,8 @@ 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);
+	/* Create sysfs entries */
+	ocfs2_sysfs_sb_init(sb);
 
  	return status;
@@ -1651,9 +1652,9 @@ static void ocfs2_put_super(struct super_block *sb)
  {
  	trace_ocfs2_put_super(sb);
 
+	ocfs2_sysfs_sb_exit(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)
fs/ocfs2/sysfs.c new file +0 -0
new file mode 100644
index 0000000..e21e699

Gang: please add source file comments like other source files.

Quoted 91 lines
fs/ocfs2/sysfs.c new file +90 -0
@@ -0,0 +1,92 @@
+#include "ocfs2.h"
+#include "sysfs.h"
+
+struct ocfs2_sb_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			char *buf);
+	ssize_t (*store)(struct ocfs2_super *, struct ocfs2_sb_attr *,
+			const char *buf, size_t count);
+};
+
+#define OCFS2_SB_ATTR(_name, _mode) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+
+#define OCFS2_SB_ATTR_RO(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
+
+static ssize_t ocfs2_sb_attr_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->show)
+		return -EIO;
+
+	return oa->show(osb, oa, buf);
+}
+
+static ssize_t ocfs2_sb_attr_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t count)
+{
+	struct ocfs2_sb_attr *oa =
+		container_of(attr, struct ocfs2_sb_attr, attr);
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	if (!oa->store)
+		return -EIO;
+
+	return oa->store(osb, oa, buf, count);
+}
+
+static ssize_t slot_num_show(struct ocfs2_super *osb,
+			     struct ocfs2_sb_attr *attr,
+	  		     char *buf)
+{
+	return sprintf(buf, "%d\n", osb->slot_num);
+}
+
+static void sb_release(struct kobject *kobj)
+{
+	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
+	complete(&osb->kobj_unregister);
+}
+
+static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
+	.show = ocfs2_sb_attr_show,
+	.store = ocfs2_sb_attr_store,
+};
+
+static OCFS2_SB_ATTR_RO(slot_num);
+static struct attribute *ocfs2_sb_attrs[] = {
+	&sb_attr_slot_num.attr,
+	NULL
+};
+
+static struct kobj_type ocfs2_sb_ktype = {
+	.sysfs_ops 	= &ocfs2_sb_sysfs_ops,
+	.default_attrs 	= ocfs2_sb_attrs,
+	.release	= sb_release,
+};
+
+
+int ocfs2_sysfs_sb_init(struct super_block *sb)
+{
+	int err;
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	init_completion(&osb->kobj_unregister);
+	osb->kobj.kset = ocfs2_kset;
+	err = kobject_init_and_add(&osb->kobj, &ocfs2_sb_ktype, NULL, "%s", sb->s_id);
+	return err;
+
+}
+
+void ocfs2_sysfs_sb_exit(struct super_block *sb)
+{
+	struct ocfs2_super *osb = OCFS2_SB(sb);
+	kobject_del(&osb->kobj);
+	kobject_put(&osb->kobj);
+	wait_for_completion(&osb->kobj_unregister);
+}
Quoted 9 lines

fs/ocfs2/sysfs.h

Quoted 7 lines
fs/ocfs2/sysfs.c new file +2 -0
+
+
fs/ocfs2/sysfs.h new file +0 -0
new file mode 100644
index 0000000..d929ac1

Gang: please add header file comments like other header files.

Agree.

Quoted 18 lines
Quoted 18 lines
fs/ocfs2/sysfs.h new file +9 -1
@@ -0,0 +1,9 @@
+
+
+#ifndef _SYS_H
+#define _SYS_H
+
+int ocfs2_sysfs_sb_init(struct super_block *sb);
+void ocfs2_sysfs_sb_exit(struct super_block *sb);
+
+#endif
--

2.6.6

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

Signature · 1 line
Goldwyn
#6 lore raw

PATCH v2 2/5 Use the sysfs interface for creating filecheck files

In reply to Goldwyn Rodrigues

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
 fs/ocfs2/filecheck.c | 440 ++++++---------------------------------------------
 fs/ocfs2/filecheck.h |  10 ++
 fs/ocfs2/ocfs2.h     |   7 +
 fs/ocfs2/super.c     |   7 +
 fs/ocfs2/sysfs.c     |  91 ++++++++++-
 5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +48 -392
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
  * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
 	"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;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
 	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)
 {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
 	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,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
 			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
 		ret = 0;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
 				    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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
 		if (p->fe_type != type)
 			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
 		total += ret;
 		remain -= ret;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
 	return total;
 }
 
 static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
 {
 	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
 		if (p->fe_done) {
 			list_del(&p->fe_list);
 			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
 			return 1;
 		}
 	}
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
 }
 
 static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
 			      unsigned int count)
 {
 	unsigned int i = 0;
 	unsigned int ret = 0;
 
 	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
 			ret++;
 		else
 			break;
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
 }
 
 static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
 			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
 }
 
 static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
 		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
 	if (IS_ERR(inode)) {
 		rc = (int)(-(long)inode);
 		if (rc >= OCFS2_FILECHECK_ERR_START &&
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
 }
 
 static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
 			     struct ocfs2_filecheck_entry *entry)
 {
 	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
 				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_status = ocfs2_filecheck_handle(osb,
 				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
 	else
 		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
 }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
 {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
 		ret = -EBUSY;
 		kfree(entry);
 	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
 		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
 		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
 	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
 exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
 }
fs/ocfs2/filecheck.h +10 -0
index e5cd002..b1a0d8c 100644
@@ -42,8 +42,18 @@ enum {
 
 #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
 #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */
 
 int ocfs2_filecheck_create_sysfs(struct super_block *sb);
 int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char *buf);
 
 #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +7 -0
index 8e66cdf..9ced543 100644
@@ -474,6 +474,13 @@ struct ocfs2_super
 	 */
 	struct workqueue_struct *ocfs2_wq;
 
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+
 	struct kobject kobj;
 	struct completion kobj_unregister;
 };
fs/ocfs2/super.c +7 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
 
 	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+
 	/* FIXME
 	 * This should be done in ocfs2_journal_init(), but unknown
 	 * ordering issues will cause the filesystem to crash.
fs/ocfs2/sysfs.c +89 -2

116 lines not on this page · raw message

Signature · 1 line
2.6.6
#7 lore raw

PATCH 2/5 Use the sysfs interface for creating filecheck files

Hello Goldwyn,

Please see my comments inline.
I just suggest to re-use the existing code as most as possible, since the code was tested by us.

Thanks
Gang

Quoted 41 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
 fs/ocfs2/filecheck.c | 440 ++++++---------------------------------------------
 fs/ocfs2/filecheck.h |  10 ++
 fs/ocfs2/ocfs2.h     |   7 +
 fs/ocfs2/super.c     |   7 +
 fs/ocfs2/sysfs.c     |  91 ++++++++++-
 5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +0 -9
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
  * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
 	"UNSUPPORTED"
 };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 66

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -9
-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 */
-};

Gang: we can reuse this structure, please move this structure into struct ocfs2_super, instead of defining a few members in struct ocfs2_super. We should use a separate structure to handle all the file check related thing, make the code simple and easy to maintain.

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 74

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -9
-
-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;
-};

Gang: I think that we can not delete this structure directly, some members are still useful.
e.g. fs_count, which is used to track if there are any pending file check entries, can be moved into struct ocfs2_filecheck. kset members maybe be kept in struct ocfs2_filecheck.

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 77

Quoted 3 lines
fs/ocfs2/filecheck.c +0 -3
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10

Gang: any file will reference these two macro?
if not, that means these are not interfaces, should be kept in source file.

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 84

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-
-/* 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 */
-};

Gang: delete the member OCFS2_FILECHECK_TYPE_SET,
Move this enum to the header file if any other source file will use, otherwise should be kept in source file.

Quoted 62 lines
fs/ocfs2/filecheck.c +0 -1
-
 struct ocfs2_filecheck_entry {
 	struct list_head fe_list;
fs/ocfs2/filecheck.c +0 -47
 	unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
 	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)
 {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
 	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);

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 161

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -10
-		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);
-}

Gang: we cannot delete the function ocfs2_filecheck_sysfs_free() directly, this will be used to free the file check entries. Please keep the code, otherwise, it will lead to memory leak.

Quoted 39 lines
fs/ocfs2/filecheck.c +0 -39
-
-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);

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 210

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -10
-	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;
-}

Gang: We can't delete these code directly, fs_count variable is used to track if there is any process to use file check related data. Please consider this variable before delete this part code.

Quoted 81 lines
fs/ocfs2/filecheck.c +0 -81
-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);

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 302

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -10
-	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);
-}

Gang: this part code can be re-used after a little modification.

Quoted 94 lines
fs/ocfs2/filecheck.c +12 -62
-
 static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
 			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
 		ret = 0;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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;

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 394

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -9
 
-	args->fa_type = type;
-	if (type == OCFS2_FILECHECK_TYPE_SET)
-		args->fa_len = (unsigned int)val;
-	else
-		args->fa_ino = val;
-
-	return 0;
-}
-

Gang: please keep the ocfs2_filecheck_args_parse function, or write a similar argument checking function since the arguments are from user-space, must be check strictly. Otherwise, this will be a way for malicious users to panic the kernel.

Quoted 5 lines
fs/ocfs2/filecheck.c +1 -2
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
 				    char *buf)
 {

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 408

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -7
 
 	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);

Gang: if delete file check data reference count mechanism, how to make sure the resource race condition (e.g. list the check results during the file system umounting.) Please consider this race condition problem.

Quoted 220 lines
fs/ocfs2/filecheck.c +7 -23
-	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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
 		if (p->fe_type != type)
 			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject 
 *kobj,
 		total += ret;
 		remain -= ret;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
 	return total;
 }
 
 static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
 {
 	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
 		if (p->fe_done) {
 			list_del(&p->fe_list);
 			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
 			return 1;
 		}
fs/ocfs2/filecheck.c +2 -2
 	}
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct 
 ocfs2_filecheck_sysfs_entry *ent)
 }
 
 static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
 			      unsigned int count)
 {
 	unsigned int i = 0;
 	unsigned int ret = 0;
 
 	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
 			ret++;
 		else
fs/ocfs2/filecheck.c +6 -6
 			break;
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct 
 ocfs2_filecheck_sysfs_entry *ent,
 }
 
 static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
 			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
 }
 
 static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
 		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
 	if (IS_ERR(inode)) {
 		rc = (int)(-(long)inode);
fs/ocfs2/filecheck.c +20 -45
 		if (rc >= OCFS2_FILECHECK_ERR_START &&
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
 }
 
 static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
 			     struct ocfs2_filecheck_entry *entry)
 {
 	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
 				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_status = ocfs2_filecheck_handle(osb,
 				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
 	else
 		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
 }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
 {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
 		ret = -EBUSY;
 		kfree(entry);
 	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
 		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
 		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
 	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
 	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
 exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
 }
fs/ocfs2/filecheck.h +0 -0
index e5cd002..b1a0d8c 100644

fs/ocfs2/filecheck.h enum { · line 50

Quoted 9 lines
fs/ocfs2/filecheck.h +6 -0
@@ -42,8 +42,18 @@ enum {
 
 #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
 #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */

Please use enum, not use macro definitions, maybe there will be more type. OCFS2_FILECHECK_TYPE_CHK should be zero, otherwise this macro is different with previous enum definitions.

Quoted 15 lines
fs/ocfs2/filecheck.h +4 -0
 int ocfs2_filecheck_create_sysfs(struct super_block *sb);
 int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char 
 *buf);
 
 #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +0 -0
index 8e66cdf..9ced543 100644

fs/ocfs2/ocfs2.h struct ocfs2_super · line 483

Quoted 10 lines
fs/ocfs2/ocfs2.h +7 -0
@@ -474,6 +474,13 @@ struct ocfs2_super
 	 */
 	struct workqueue_struct *ocfs2_wq;
 
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+

Gang: please use a separate structure to include all the file check members, easy to read/maintain.

Quoted 9 lines
fs/ocfs2/ocfs2.h +0 -0
 	struct kobject kobj;
 	struct completion kobj_unregister;
 };
fs/ocfs2/super.c +0 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block 
 *sb,

fs/ocfs2/super.c static int ocfs2_initialize_super(struct super_block · line 2225

Quoted 10 lines
fs/ocfs2/super.c +7 -0
 
 	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+

Gang: write a separate funtion in filecheck.c to include these line code, easy to read/maintain.

Quoted 90 lines
fs/ocfs2/super.c +0 -0
 	/* FIXME
 	 * This should be done in ocfs2_journal_init(), but unknown
fs/ocfs2/super.c +0 -0
 	 * ordering issues will cause the filesystem to crash.
fs/ocfs2/sysfs.c +64 -2
index e21e699..81e3dd4 100644
@@ -1,5 +1,6 @@
 #include "ocfs2.h"
 #include "sysfs.h"
+#include "filecheck.h"
 
 struct ocfs2_sb_attr {
 	struct attribute attr;
@@ -9,8 +10,12 @@ struct ocfs2_sb_attr {
 			const char *buf, size_t count);
 };
 
-#define OCFS2_SB_ATTR(_name, _mode) \
-struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+#define OCFS2_SB_ATTR(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = (S_IWUSR | S_IRUGO)},  \
+	.show = _name##_show, \
+	.store = _name##_store \
+}
 
 #define OCFS2_SB_ATTR_RO(_name) \
 struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
@@ -46,6 +51,81 @@ static ssize_t slot_num_show(struct ocfs2_super *osb,
 	return sprintf(buf, "%d\n", osb->slot_num);
 }
 
+static ssize_t file_check_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_CHK, buf);
+}
+
+static ssize_t file_check_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_fix_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_FIX, buf);
+}
+
+static ssize_t file_fix_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_check_max_entries_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	int len = 0;
+	spin_lock(&osb->fc_lock);
+	/* Show done, current size and max */
+	len += sprintf(buf, "%d\t%d\t%d\n", osb->fc_done, osb->fc_size,
+			osb->fc_max);
+	spin_unlock(&osb->fc_lock);
+	return len;

fs/ocfs2/sysfs.c static ssize_t slot_num_show(struct ocfs2_super *osb, · line 120

Quoted 10 lines
fs/ocfs2/sysfs.c +10 -0
+}
+
+static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr, const char *buf, size_t count)
+{
+
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);

Gang: please make sure the function kstrtoul does work well since the inputed buf has not terminating null character. This is why I write a wrapper function ocfs2_filecheck_args_get_long().

Quoted 16 lines
fs/ocfs2/sysfs.c +9 -0
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_set_max_entries(osb, (int)t);
+	if (ret)
+		return ret;
+	return count;
+}
+
 static void sb_release(struct kobject *kobj)
 {
 	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
@@ -58,8 +138,15 @@ static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
 };
 
 static OCFS2_SB_ATTR_RO(slot_num);
+static OCFS2_SB_ATTR(file_check);

fs/ocfs2/sysfs.c static const struct sysfs_ops ocfs2_sb_sysfs_ops = { · line 151

Quoted 10 lines
fs/ocfs2/sysfs.c +6 -0
+static OCFS2_SB_ATTR(file_fix);
+static OCFS2_SB_ATTR(file_check_max_entries);
+
 static struct attribute *ocfs2_sb_attrs[] = {
 	&sb_attr_slot_num.attr,
+	&sb_attr_file_check.attr,
+	&sb_attr_file_fix.attr,
+	&sb_attr_file_check_max_entries.attr,
 	NULL
 };

Gang: as I said in the first patch, please make all the file check related attributes in a separate sub directory. It will let us to be easy to read/debug, especially if there is any reference count leaking problem.

Quoted 9 lines
Signature · 8 lines
-- 
2.6.6


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com 
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#9 lore raw

PATCH 2/5 Use the sysfs interface for creating filecheck files

Quoted 53 lines · Gang He

Hello Goldwyn,

Please see my comments inline.
I just suggest to re-use the existing code as most as possible, since the code was tested by us.

Thanks
Gang

Quoted 43 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
  fs/ocfs2/filecheck.c | 440 ++++++---------------------------------------------
  fs/ocfs2/filecheck.h |  10 ++
  fs/ocfs2/ocfs2.h     |   7 +
  fs/ocfs2/super.c     |   7 +
  fs/ocfs2/sysfs.c     |  91 ++++++++++-
  5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +0 -11
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
   * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
  	"UNSUPPORTED"
  };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
-static LIST_HEAD(ocfs2_filecheck_sysfs_list);
-
Quoted 9 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 65

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-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 */
-};

Gang: we can reuse this structure, please move this structure into struct ocfs2_super, instead of defining a few members in struct ocfs2_super. We should use a separate structure to handle all the file check related thing, make the code simple and easy to maintain.

Not sure why you are insistent on keeping a separate structure when it would not be references from different structures. Keeping a prefix of fc will make sure it is for filecheck attributes.

Quoted 14 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 74

Quoted 11 lines
fs/ocfs2/filecheck.c +0 -9
-
-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;
-};

Gang: I think that we can not delete this structure directly, some members are still useful.
e.g. fs_count, which is used to track if there are any pending file check entries, can be moved into struct ocfs2_filecheck. kset members maybe be kept in struct ocfs2_filecheck.

Okay, I will fix that.

Quoted 6 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 77

Quoted 4 lines
fs/ocfs2/filecheck.c +0 -3
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10

Gang: any file will reference these two macro?
if not, that means these are not interfaces, should be kept in source file.

Yes, they are referenced by multiple files.

Quoted 10 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 84

Quoted 8 lines
fs/ocfs2/filecheck.c +0 -7
-
-/* 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 */
-};

Gang: delete the member OCFS2_FILECHECK_TYPE_SET,
Move this enum to the header file if any other source file will use, otherwise should be kept in source file.

The idea of removing this structures was to simplify the code. More structures make more complicated code.

Quoted 67 lines
Quoted 67 lines
fs/ocfs2/filecheck.c +0 -52
-
  struct ocfs2_filecheck_entry {
  	struct list_head fe_list;
  	unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
  	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)
  {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
  	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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 161

Quoted 6 lines
fs/ocfs2/filecheck.c +0 -6
-
-	kset_unregister(entry->fs_fcheckkset);
-	kset_unregister(entry->fs_devicekset);
-	kfree(entry->fs_fcheck);
-	kfree(entry);
-}

Gang: we cannot delete the function ocfs2_filecheck_sysfs_free() directly, this will be used to free the file check entries. Please keep the code, otherwise, it will lead to memory leak.

Yes, there should a cleanup routine.

Quoted 138 lines
Quoted 40 lines
fs/ocfs2/filecheck.c +0 -39
-
-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);

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 210

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -10
-	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;
-}

Gang: We can't delete these code directly, fs_count variable is used to track if there is any process to use file check related data. Please consider this variable before delete this part code.

Quoted 84 lines
fs/ocfs2/filecheck.c +0 -84
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 302

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	return ret;
-}
-
-int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
-{
-	return ocfs2_filecheck_sysfs_del(sb->s_id);
-}

Gang: this part code can be re-used after a little modification.

For what?

Quoted 96 lines
Quoted 96 lines
fs/ocfs2/filecheck.c +12 -62
-
  static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
  			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
  		ret = 0;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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;
 
Quoted 11 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 394

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -9
-	args->fa_type = type;
-	if (type == OCFS2_FILECHECK_TYPE_SET)
-		args->fa_len = (unsigned int)val;
-	else
-		args->fa_ino = val;
-
-	return 0;
-}
-

Gang: please keep the ocfs2_filecheck_args_parse function, or write a similar argument checking function since the arguments are from user-space, must be check strictly. Otherwise, this will be a way for malicious users to panic the kernel.

How? Do you have an example?

Quoted 7 lines
Quoted 7 lines
fs/ocfs2/filecheck.c +1 -2
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
  				    char *buf)
  {
 
Quoted 11 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 408

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -7
  	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);

Gang: if delete file check data reference count mechanism, how to make sure the resource race condition (e.g. list the check results during the file system umounting.) Please consider this race condition problem.

Isn't spinlock enough? What is the race?

Quoted 251 lines
Quoted 221 lines
fs/ocfs2/filecheck.c +7 -23
-	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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
  		if (p->fe_type != type)
  			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject
 *kobj,
  		total += ret;
  		remain -= ret;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
  	return total;
  }
 
  static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
  {
  	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
  		if (p->fe_done) {
  			list_del(&p->fe_list);
  			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
  			return 1;
  		}
  	}
fs/ocfs2/filecheck.c +2 -2
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct
 ocfs2_filecheck_sysfs_entry *ent)
  }
 
  static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
  			      unsigned int count)
  {
  	unsigned int i = 0;
  	unsigned int ret = 0;
 
  	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
  			ret++;
  		else

break;

fs/ocfs2/filecheck.c +6 -6
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct
 ocfs2_filecheck_sysfs_entry *ent,
  }
 
  static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
  			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
  }
 
  static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
  		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
  	if (IS_ERR(inode)) {
  		rc = (int)(-(long)inode);

if (rc >= OCFS2_FILECHECK_ERR_START &&

fs/ocfs2/filecheck.c +20 -45
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
  }
 
  static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
  			     struct ocfs2_filecheck_entry *entry)
  {
  	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
  				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_status = ocfs2_filecheck_handle(osb,
  				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
  	else
  		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
  }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
  {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
  		ret = -EBUSY;
  		kfree(entry);
  	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
  		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
  		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
  	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
  exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
  }
fs/ocfs2/filecheck.h +0 -0
index e5cd002..b1a0d8c 100644

fs/ocfs2/filecheck.h enum { · line 50

Quoted 9 lines
fs/ocfs2/filecheck.h +6 -0
@@ -42,8 +42,18 @@ enum {
 
  #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
  #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */

Please use enum, not use macro definitions, maybe there will be more type. OCFS2_FILECHECK_TYPE_CHK should be zero, otherwise this macro is different with previous enum definitions.

Quoted 18 lines
fs/ocfs2/filecheck.h +4 -0
  int ocfs2_filecheck_create_sysfs(struct super_block *sb);
  int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
 
  #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +0 -0
index 8e66cdf..9ced543 100644
@@ -474,6 +474,13 @@ struct ocfs2_super
  	 */
  	struct workqueue_struct *ocfs2_wq;
 
Quoted 8 lines

fs/ocfs2/ocfs2.h struct ocfs2_super · line 483

Quoted 7 lines
fs/ocfs2/ocfs2.h +7 -0
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+

Gang: please use a separate structure to include all the file check members, easy to read/maintain.

I would prefer it to be a part of ocfs2_super. It is easier to maintain and read.

Quoted 13 lines
Quoted 13 lines
fs/ocfs2/ocfs2.h +0 -0
  	struct kobject kobj;
  	struct completion kobj_unregister;
  };
fs/ocfs2/super.c +0 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block
 *sb,
 
  	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
Quoted 8 lines

fs/ocfs2/super.c static int ocfs2_initialize_super(struct super_block *sb, · line 2224

Quoted 7 lines
fs/ocfs2/super.c +7 -0
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+

Gang: write a separate funtion in filecheck.c to include these line code, easy to read/maintain.

Why? Unless we are starting something specific to filecheck, I don't see any need.

Quoted 95 lines
Quoted 95 lines
fs/ocfs2/super.c +0 -0
  	/* FIXME
  	 * This should be done in ocfs2_journal_init(), but unknown

* ordering issues will cause the filesystem to crash.

fs/ocfs2/sysfs.c +68 -2
index e21e699..81e3dd4 100644
@@ -1,5 +1,6 @@
  #include "ocfs2.h"
  #include "sysfs.h"
+#include "filecheck.h"
 
  struct ocfs2_sb_attr {
  	struct attribute attr;
@@ -9,8 +10,12 @@ struct ocfs2_sb_attr {
  			const char *buf, size_t count);
  };
 
-#define OCFS2_SB_ATTR(_name, _mode) \
-struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+#define OCFS2_SB_ATTR(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = (S_IWUSR | S_IRUGO)},  \
+	.show = _name##_show, \
+	.store = _name##_store \
+}
 
  #define OCFS2_SB_ATTR_RO(_name) \
  struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
@@ -46,6 +51,81 @@ static ssize_t slot_num_show(struct ocfs2_super *osb,
  	return sprintf(buf, "%d\n", osb->slot_num);
  }
 
+static ssize_t file_check_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_CHK, buf);
+}
+
+static ssize_t file_check_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_fix_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_FIX, buf);
+}
+
+static ssize_t file_fix_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_check_max_entries_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	int len = 0;
+	spin_lock(&osb->fc_lock);
+	/* Show done, current size and max */
+	len += sprintf(buf, "%d\t%d\t%d\n", osb->fc_done, osb->fc_size,
+			osb->fc_max);
+	spin_unlock(&osb->fc_lock);
+	return len;
+}
+
+static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr, const char *buf, size_t count)
Quoted 8 lines

fs/ocfs2/sysfs.c static ssize_t slot_num_show(struct ocfs2_super *osb, · line 68

Quoted 6 lines
fs/ocfs2/sysfs.c +6 -0
+{
+
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);

Gang: please make sure the function kstrtoul does work well since the inputed buf has not terminating null character. This is why I write a wrapper function ocfs2_filecheck_args_get_long().

Can you give an example on how this can be activated? Maybe a check on value < 0 may make sense.

Quoted 15 lines
Quoted 15 lines
fs/ocfs2/sysfs.c +8 -0
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_set_max_entries(osb, (int)t);
+	if (ret)
+		return ret;
+	return count;
+}
+
  static void sb_release(struct kobject *kobj)
  {
  	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
@@ -58,8 +138,15 @@ static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
  };
 
Quoted 14 lines

fs/ocfs2/sysfs.c static const struct sysfs_ops ocfs2_sb_sysfs_ops = { · line 151

Quoted 12 lines
fs/ocfs2/sysfs.c +7 -0
  static OCFS2_SB_ATTR_RO(slot_num);
+static OCFS2_SB_ATTR(file_check);
+static OCFS2_SB_ATTR(file_fix);
+static OCFS2_SB_ATTR(file_check_max_entries);
+
  static struct attribute *ocfs2_sb_attrs[] = {
  	&sb_attr_slot_num.attr,
+	&sb_attr_file_check.attr,
+	&sb_attr_file_fix.attr,
+	&sb_attr_file_check_max_entries.attr,
  	NULL
  };

Gang: as I said in the first patch, please make all the file check related attributes in a separate sub directory. It will let us to be easy to read/debug, especially if there is any reference count leaking problem.

The main reason of the code is to remove unnecessary data structures which is making the code hard to understand. I don't see a point in keeping them in a separate structure besides adding more indirections.

Signature · 1 line
Goldwyn
#10 lore raw

PATCH 2/5 Use the sysfs interface for creating filecheck files

Quoted 70 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines · Gang He

Hello Goldwyn,

Please see my comments inline.
I just suggest to re-use the existing code as most as possible, since the

code was tested by us.

Quoted 15 lines

Thanks
Gang

Quoted 10 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
  fs/ocfs2/filecheck.c | 440 

++++++---------------------------------------------

Quoted 34 lines
Quoted 33 lines
  fs/ocfs2/filecheck.h |  10 ++
  fs/ocfs2/ocfs2.h     |   7 +
  fs/ocfs2/super.c     |   7 +
  fs/ocfs2/sysfs.c     |  91 ++++++++++-
  5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +0 -11
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
   * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
  	"UNSUPPORTED"
  };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
-static LIST_HEAD(ocfs2_filecheck_sysfs_list);
-
Quoted 8 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 65

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-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 */
-};

Gang: we can reuse this structure, please move this structure into struct

Quoted 8 lines

ocfs2_super, instead of defining a few members in struct ocfs2_super.

Quoted 1 line

We should use a separate structure to handle all the file check related

thing, make the code simple and easy to maintain.

Not sure why you are insistent on keeping a separate structure when it would not be references from different structures. Keeping a prefix of fc will make sure it is for filecheck attributes.

Gang: I just want to make the feature code more independent in other source files, define a separate data structure to make the file check code more easily read for the developer, and keep the code change more less in other source file. Actually, the existing struct ocfs2_filecheck can be re-used here.

Quoted 39 lines
Quoted 13 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 74

Quoted 12 lines
fs/ocfs2/filecheck.c +0 -9
-
-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;
-};

Gang: I think that we can not delete this structure directly, some members

are still useful.

Quoted 1 line

e.g. fs_count, which is used to track if there are any pending file check

entries, can be moved into struct ocfs2_filecheck.

Quoted 1 line

kset members maybe be kept in struct ocfs2_filecheck.

Okay, I will fix that.

Quoted 6 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 77

Quoted 4 lines
fs/ocfs2/filecheck.c +0 -3
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10

Gang: any file will reference these two macro?
if not, that means these are not interfaces, should be kept in source file.

Yes, they are referenced by multiple files.

Quoted 10 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 84

Quoted 8 lines
fs/ocfs2/filecheck.c +0 -7
-
-/* 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 */
-};

Gang: delete the member OCFS2_FILECHECK_TYPE_SET,
Move this enum to the header file if any other source file will use,

Quoted 4 lines

otherwise should be kept in source file.

The idea of removing this structures was to simplify the code. More structures make more complicated code.

Gang: that is OK, but please define the OCFS2_FILECHECK_TYPE_CHK to 0, otherwise this replacing is not equivalent.

Quoted 228 lines
Quoted 67 lines
Quoted 67 lines
fs/ocfs2/filecheck.c +0 -51
-
  struct ocfs2_filecheck_entry {
  	struct list_head fe_list;
  	unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
  	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)
  {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
  	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);
-	}
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 161

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	spin_unlock(&entry->fs_fcheck->fc_lock);
-
-	kset_unregister(entry->fs_fcheckkset);
-	kset_unregister(entry->fs_devicekset);
-	kfree(entry->fs_fcheck);
-	kfree(entry);
-}

Gang: we cannot delete the function ocfs2_filecheck_sysfs_free() directly,

this will be used to free the file check entries.

Quoted 1 line

Please keep the code, otherwise, it will lead to memory leak.

Yes, there should a cleanup routine.

Quoted 43 lines
Quoted 43 lines
fs/ocfs2/filecheck.c +0 -42
-
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 210

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-			spin_unlock(&ocfs2_filecheck_sysfs_lock);
-			return p;
-		}
-	}
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
-	return NULL;
-}

Gang: We can't delete these code directly, fs_count variable is used to

track if there is any process to use file check related data.

Quoted 87 lines

Please consider this variable before delete this part code.

Quoted 84 lines
fs/ocfs2/filecheck.c +0 -84
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 302

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	return ret;
-}
-
-int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
-{
-	return ocfs2_filecheck_sysfs_del(sb->s_id);
-}

Gang: this part code can be re-used after a little modification.

Quoted 1 line

For what?

Gang: this part code have a complete creating/releasing kset code, have been tested, it will not bring any memory leak.

Quoted 107 lines
Quoted 97 lines
Quoted 97 lines
fs/ocfs2/filecheck.c +12 -62
-
  static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
  			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
  		ret = 0;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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;
 
Quoted 10 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 394

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -9
-	args->fa_type = type;
-	if (type == OCFS2_FILECHECK_TYPE_SET)
-		args->fa_len = (unsigned int)val;
-	else
-		args->fa_ino = val;
-
-	return 0;
-}
-

Gang: please keep the ocfs2_filecheck_args_parse function, or write a

Quoted 5 lines

similar argument checking function since the arguments are from user-space, must be check strictly.

Quoted 1 line

Otherwise, this will be a way for malicious users to panic the kernel.

How? Do you have an example?

Gang: for example, user input a too long number string, we should return a invalid error directly, not do the further file check operation. We need a ocfs2_filecheck_args_parse function, add some argument checking rules for now and future (when we find more limitations), return the error to the user process directly, to avoid bringing the further IO checking efforts.

Quoted 18 lines
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/filecheck.c +1 -2
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
  				    char *buf)
  {
 
Quoted 10 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 408

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -7
  	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);

Gang: if delete file check data reference count mechanism, how to make sure

Quoted 5 lines

the resource race condition (e.g. list the check results during the file system umounting.)

Quoted 1 line

Please consider this race condition problem.

Isn't spinlock enough? What is the race?

Gang: No, since file check operation is executed without spinlock, we need a reference count to keep the related data, until the last usage is finished.

Quoted 288 lines
Quoted 223 lines
Quoted 223 lines
fs/ocfs2/filecheck.c +7 -23
-	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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
  		if (p->fe_type != type)
  			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject
 *kobj,
  		total += ret;
  		remain -= ret;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
  	return total;
  }
 
  static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
  {
  	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
  		if (p->fe_done) {
  			list_del(&p->fe_list);
  			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
  			return 1;
  		}
  	}
fs/ocfs2/filecheck.c +2 -2
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct
 ocfs2_filecheck_sysfs_entry *ent)
  }
 
  static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
  			      unsigned int count)
  {
  	unsigned int i = 0;
  	unsigned int ret = 0;
 
  	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
  			ret++;
  		else

break;

fs/ocfs2/filecheck.c +6 -6
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct
 ocfs2_filecheck_sysfs_entry *ent,
  }
 
  static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
  			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
  }
 
  static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
  		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
  	if (IS_ERR(inode)) {
  		rc = (int)(-(long)inode);

if (rc >= OCFS2_FILECHECK_ERR_START &&

fs/ocfs2/filecheck.c +20 -45
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
  }
 
  static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
  			     struct ocfs2_filecheck_entry *entry)
  {
  	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
  				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_status = ocfs2_filecheck_handle(osb,
  				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
  	else
  		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
  }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
  {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
  		ret = -EBUSY;
  		kfree(entry);
  	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
  		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
  		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
  	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
  	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
  exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
  }
fs/ocfs2/filecheck.h +0 -0
index e5cd002..b1a0d8c 100644
@@ -42,8 +42,18 @@ enum {
 
Quoted 10 lines

fs/ocfs2/filecheck.h enum { · line 50

Quoted 8 lines
fs/ocfs2/filecheck.h +6 -0
  #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
  #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */

Please use enum, not use macro definitions, maybe there will be more type. OCFS2_FILECHECK_TYPE_CHK should be zero, otherwise this macro is different

with previous enum definitions.

Quoted 19 lines
Quoted 19 lines
fs/ocfs2/filecheck.h +4 -0
  int ocfs2_filecheck_create_sysfs(struct super_block *sb);
  int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
 
  #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +0 -0
index 8e66cdf..9ced543 100644
@@ -474,6 +474,13 @@ struct ocfs2_super
  	 */
  	struct workqueue_struct *ocfs2_wq;
 
Quoted 8 lines

fs/ocfs2/ocfs2.h struct ocfs2_super · line 483

Quoted 7 lines
fs/ocfs2/ocfs2.h +7 -0
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+

Gang: please use a separate structure to include all the file check members,

easy to read/maintain.

I would prefer it to be a part of ocfs2_super. It is easier to maintain and read.

Quoted 13 lines
Quoted 13 lines
fs/ocfs2/ocfs2.h +0 -0
  	struct kobject kobj;
  	struct completion kobj_unregister;
  };
fs/ocfs2/super.c +0 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block
 *sb,
 
  	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
Quoted 8 lines

fs/ocfs2/super.c static int ocfs2_initialize_super(struct super_block *sb, · line 2224

Quoted 7 lines
fs/ocfs2/super.c +7 -0
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+

Gang: write a separate funtion in filecheck.c to include these line code,

Quoted 4 lines

easy to read/maintain.

Why? Unless we are starting something specific to filecheck, I don't see any need.

Gang: I just want to make the file check thing is done in filecheck source file, the other module just call some functions. Let the code more clear.

Quoted 103 lines
Quoted 95 lines
Quoted 95 lines
fs/ocfs2/super.c +0 -0
  	/* FIXME
  	 * This should be done in ocfs2_journal_init(), but unknown

* ordering issues will cause the filesystem to crash.

fs/ocfs2/sysfs.c +67 -2
index e21e699..81e3dd4 100644
@@ -1,5 +1,6 @@
  #include "ocfs2.h"
  #include "sysfs.h"
+#include "filecheck.h"
 
  struct ocfs2_sb_attr {
  	struct attribute attr;
@@ -9,8 +10,12 @@ struct ocfs2_sb_attr {
  			const char *buf, size_t count);
  };
 
-#define OCFS2_SB_ATTR(_name, _mode) \
-struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+#define OCFS2_SB_ATTR(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = (S_IWUSR | S_IRUGO)},  \
+	.show = _name##_show, \
+	.store = _name##_store \
+}
 
  #define OCFS2_SB_ATTR_RO(_name) \
  struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
@@ -46,6 +51,81 @@ static ssize_t slot_num_show(struct ocfs2_super *osb,
  	return sprintf(buf, "%d\n", osb->slot_num);
  }
 
+static ssize_t file_check_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_CHK, buf);
+}
+
+static ssize_t file_check_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_fix_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_FIX, buf);
+}
+
+static ssize_t file_fix_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_check_max_entries_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	int len = 0;
+	spin_lock(&osb->fc_lock);
+	/* Show done, current size and max */
+	len += sprintf(buf, "%d\t%d\t%d\n", osb->fc_done, osb->fc_size,
+			osb->fc_max);
+	spin_unlock(&osb->fc_lock);
+	return len;
+}
+
+static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
Quoted 8 lines

fs/ocfs2/sysfs.c static ssize_t slot_num_show(struct ocfs2_super *osb, · line 120

Quoted 7 lines
fs/ocfs2/sysfs.c +7 -0
+		struct ocfs2_sb_attr *attr, const char *buf, size_t count)
+{
+
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);

Gang: please make sure the function kstrtoul does work well since the

Quoted 5 lines

inputed buf has not terminating null character.

Quoted 1 line

This is why I write a wrapper function ocfs2_filecheck_args_get_long().

Can you give an example on how this can be activated? Maybe a check on value < 0 may make sense.

Gang: I am not sure if this function works well when the string is inputed without a terminating null character. need to test all the case if using the function directly. But we test all the case with a terminating null character.

Quoted 40 lines
Quoted 16 lines
Quoted 16 lines
fs/ocfs2/sysfs.c +8 -0
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_set_max_entries(osb, (int)t);
+	if (ret)
+		return ret;
+	return count;
+}
+
  static void sb_release(struct kobject *kobj)
  {
  	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
@@ -58,8 +138,15 @@ static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
  };
 
Quoted 13 lines

fs/ocfs2/sysfs.c static const struct sysfs_ops ocfs2_sb_sysfs_ops = { · line 151

Quoted 12 lines
fs/ocfs2/sysfs.c +7 -0
  static OCFS2_SB_ATTR_RO(slot_num);
+static OCFS2_SB_ATTR(file_check);
+static OCFS2_SB_ATTR(file_fix);
+static OCFS2_SB_ATTR(file_check_max_entries);
+
  static struct attribute *ocfs2_sb_attrs[] = {
  	&sb_attr_slot_num.attr,
+	&sb_attr_file_check.attr,
+	&sb_attr_file_fix.attr,
+	&sb_attr_file_check_max_entries.attr,
  	NULL
  };

Gang: as I said in the first patch, please make all the file check related

attributes in a separate sub directory.

Quoted 1 line

It will let us to be easy to read/debug, especially if there is any

reference count leaking problem.

The main reason of the code is to remove unnecessary data structures which is making the code hard to understand. I don't see a point in keeping them in a separate structure besides adding more indirections.

Signature · 1 line
Goldwyn
#11 lore raw

PATCH v2 2/5 Use the sysfs interface for creating filecheck files

Quoted 75 lines · Gang He
Quoted 75 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines · Gang He

Hello Goldwyn,

Please see my comments inline.
I just suggest to re-use the existing code as most as possible, since the

code was tested by us.

Quoted 15 lines

Thanks
Gang

Quoted 10 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
   fs/ocfs2/filecheck.c | 440

++++++---------------------------------------------

Quoted 34 lines
Quoted 33 lines
   fs/ocfs2/filecheck.h |  10 ++
   fs/ocfs2/ocfs2.h     |   7 +
   fs/ocfs2/super.c     |   7 +
   fs/ocfs2/sysfs.c     |  91 ++++++++++-
   5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +0 -11
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
    * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
   	"UNSUPPORTED"
   };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
-static LIST_HEAD(ocfs2_filecheck_sysfs_list);
-
Quoted 8 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 65

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-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 */
-};

Gang: we can reuse this structure, please move this structure into struct

ocfs2_super, instead of defining a few members in struct ocfs2_super.

Quoted 1 line

We should use a separate structure to handle all the file check related

thing, make the code simple and easy to maintain.

Quoted 6 lines
Quoted 3 lines

Not sure why you are insistent on keeping a separate structure when it would not be references from different structures. Keeping a prefix of fc will make sure it is for filecheck attributes.

Gang: I just want to make the feature code more independent in other source files, define a separate data structure to make the file check code more easily read for the developer, and keep the code change more less in other source file. Actually, the existing struct ocfs2_filecheck can be re-used here.

Yes, but it is just initialization of the fields. I understand if you are doing something more..

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 74

Quoted 12 lines
fs/ocfs2/filecheck.c +0 -9
-
-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;
-};

Gang: I think that we can not delete this structure directly, some members

Quoted 6 lines
Quoted 6 lines

are still useful.

Quoted 1 line

e.g. fs_count, which is used to track if there are any pending file check

entries, can be moved into struct ocfs2_filecheck.

Quoted 1 line

kset members maybe be kept in struct ocfs2_filecheck.

Okay, I will fix that.

On second though, this may not be required.

Quoted 20 lines
Quoted 20 lines
Quoted 7 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 77

Quoted 5 lines
fs/ocfs2/filecheck.c +0 -3
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10

Gang: any file will reference these two macro?
if not, that means these are not interfaces, should be kept in source file.

Yes, they are referenced by multiple files.

Quoted 10 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 84

Quoted 8 lines
fs/ocfs2/filecheck.c +0 -7
-
-/* 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 */
-};

Gang: delete the member OCFS2_FILECHECK_TYPE_SET,
Move this enum to the header file if any other source file will use,

Quoted 6 lines
Quoted 4 lines

otherwise should be kept in source file.

The idea of removing this structures was to simplify the code. More structures make more complicated code.

Gang: that is OK, but please define the OCFS2_FILECHECK_TYPE_CHK to 0, otherwise this replacing is not equivalent.

I am doing away with this in the future posts.

Quoted 367 lines
Quoted 228 lines
Quoted 67 lines
Quoted 67 lines
fs/ocfs2/filecheck.c +0 -51
-
   struct ocfs2_filecheck_entry {
   	struct list_head fe_list;
   	unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
   	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)
   {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
   	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);
-	}
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 161

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	spin_unlock(&entry->fs_fcheck->fc_lock);
-
-	kset_unregister(entry->fs_fcheckkset);
-	kset_unregister(entry->fs_devicekset);
-	kfree(entry->fs_fcheck);
-	kfree(entry);
-}

Gang: we cannot delete the function ocfs2_filecheck_sysfs_free() directly,

this will be used to free the file check entries.

Quoted 1 line

Please keep the code, otherwise, it will lead to memory leak.

Yes, there should a cleanup routine.

Quoted 43 lines
Quoted 43 lines
fs/ocfs2/filecheck.c +0 -42
-
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 210

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-			spin_unlock(&ocfs2_filecheck_sysfs_lock);
-			return p;
-		}
-	}
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
-	return NULL;
-}

Gang: We can't delete these code directly, fs_count variable is used to

track if there is any process to use file check related data.

Quoted 87 lines

Please consider this variable before delete this part code.

Quoted 84 lines
fs/ocfs2/filecheck.c +0 -84
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 302

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	return ret;
-}
-
-int ocfs2_filecheck_remove_sysfs(struct super_block *sb)
-{
-	return ocfs2_filecheck_sysfs_del(sb->s_id);
-}

Gang: this part code can be re-used after a little modification.

Quoted 1 line

For what?

Gang: this part code have a complete creating/releasing kset code, have been tested, it will not bring any memory leak.

Quoted 107 lines
Quoted 97 lines
Quoted 97 lines
fs/ocfs2/filecheck.c +12 -62
-
   static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
   			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
   		ret = 0;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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;
 
Quoted 10 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 394

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -9
-	args->fa_type = type;
-	if (type == OCFS2_FILECHECK_TYPE_SET)
-		args->fa_len = (unsigned int)val;
-	else
-		args->fa_ino = val;
-
-	return 0;
-}
-

Gang: please keep the ocfs2_filecheck_args_parse function, or write a

Quoted 5 lines

similar argument checking function since the arguments are from user-space, must be check strictly.

Quoted 1 line

Otherwise, this will be a way for malicious users to panic the kernel.

How? Do you have an example?

Gang: for example, user input a too long number string, we should return a invalid error directly, not do the further file check operation. We need a ocfs2_filecheck_args_parse function, add some argument checking rules for now and future (when we find more limitations), return the error to the user process directly, to avoid bringing the further IO checking efforts.

Quoted 20 lines
Quoted 8 lines
Quoted 8 lines
fs/ocfs2/filecheck.c +1 -2
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
   				    char *buf)
   {
 
Quoted 10 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 408

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -7
   	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);

Gang: if delete file check data reference count mechanism, how to make sure

the resource race condition (e.g. list the check results during the file system umounting.)

Quoted 7 lines
Quoted 6 lines
Quoted 1 line

Please consider this race condition problem.

Isn't spinlock enough? What is the race?

Gang: No, since file check operation is executed without spinlock, we need a reference count to keep the related data, until the last usage is finished.

Filesystem unmonting is a different game. It evicts inodes. Could you clarify more?

Anyways, doing away with fe_done and using the status instead should help.

Quoted 399 lines
Quoted 289 lines
Quoted 224 lines
Quoted 224 lines
fs/ocfs2/filecheck.c +7 -23
-	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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
   		if (p->fe_type != type)
   			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject
 *kobj,
   		total += ret;
   		remain -= ret;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
   	return total;
   }
 
   static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
   {
   	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
   		if (p->fe_done) {
   			list_del(&p->fe_list);
   			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
   			return 1;
   		}
   	}
fs/ocfs2/filecheck.c +2 -2
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct
 ocfs2_filecheck_sysfs_entry *ent)
   }
 
   static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
   			      unsigned int count)
   {
   	unsigned int i = 0;
   	unsigned int ret = 0;
 
   	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
   			ret++;
   		else
   			break;
fs/ocfs2/filecheck.c +6 -6
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct
 ocfs2_filecheck_sysfs_entry *ent,
   }
 
   static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
   			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
   }
 
   static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
   		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
   	if (IS_ERR(inode)) {
   		rc = (int)(-(long)inode);
   		if (rc >= OCFS2_FILECHECK_ERR_START &&
fs/ocfs2/filecheck.c +20 -45
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
   }
 
   static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
   			     struct ocfs2_filecheck_entry *entry)
   {
   	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
   				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_status = ocfs2_filecheck_handle(osb,
   				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
   	else
   		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
   }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
   {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
   		ret = -EBUSY;
   		kfree(entry);
   	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
   		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
   		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
   	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
   exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
   }
fs/ocfs2/filecheck.h +0 -0
index e5cd002..b1a0d8c 100644
@@ -42,8 +42,18 @@ enum {
 
Quoted 10 lines

fs/ocfs2/filecheck.h enum { · line 50

Quoted 8 lines
fs/ocfs2/filecheck.h +6 -0
   #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
   #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */

Please use enum, not use macro definitions, maybe there will be more type. OCFS2_FILECHECK_TYPE_CHK should be zero, otherwise this macro is different

with previous enum definitions.

Quoted 19 lines
Quoted 19 lines
fs/ocfs2/filecheck.h +4 -0
   int ocfs2_filecheck_create_sysfs(struct super_block *sb);
   int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
 
   #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +0 -0
index 8e66cdf..9ced543 100644
@@ -474,6 +474,13 @@ struct ocfs2_super
   	 */
   	struct workqueue_struct *ocfs2_wq;
 
Quoted 8 lines

fs/ocfs2/ocfs2.h struct ocfs2_super · line 483

Quoted 7 lines
fs/ocfs2/ocfs2.h +7 -0
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+

Gang: please use a separate structure to include all the file check members,

easy to read/maintain.

I would prefer it to be a part of ocfs2_super. It is easier to maintain and read.

Quoted 13 lines
Quoted 13 lines
fs/ocfs2/ocfs2.h +0 -0
   	struct kobject kobj;
   	struct completion kobj_unregister;
   };
fs/ocfs2/super.c +0 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block
 *sb,
 
   	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
Quoted 8 lines

fs/ocfs2/super.c static int ocfs2_initialize_super(struct super_block *sb, · line 2224

Quoted 7 lines
fs/ocfs2/super.c +7 -0
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+

Gang: write a separate funtion in filecheck.c to include these line code,

Quoted 4 lines

easy to read/maintain.

Why? Unless we are starting something specific to filecheck, I don't see any need.

Gang: I just want to make the file check thing is done in filecheck source file, the other module just call some functions. Let the code more clear.

Quoted 103 lines
Quoted 103 lines
Quoted 92 lines
fs/ocfs2/super.c +0 -0
   	/* FIXME
   	 * This should be done in ocfs2_journal_init(), but unknown

* ordering issues will cause the filesystem to crash.

fs/ocfs2/sysfs.c +64 -2
index e21e699..81e3dd4 100644
@@ -1,5 +1,6 @@
   #include "ocfs2.h"
   #include "sysfs.h"
+#include "filecheck.h"
 
   struct ocfs2_sb_attr {
   	struct attribute attr;
@@ -9,8 +10,12 @@ struct ocfs2_sb_attr {
   			const char *buf, size_t count);
   };
 
-#define OCFS2_SB_ATTR(_name, _mode) \
-struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+#define OCFS2_SB_ATTR(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = (S_IWUSR | S_IRUGO)},  \
+	.show = _name##_show, \
+	.store = _name##_store \
+}
 
   #define OCFS2_SB_ATTR_RO(_name) \
   struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
@@ -46,6 +51,81 @@ static ssize_t slot_num_show(struct ocfs2_super *osb,
   	return sprintf(buf, "%d\n", osb->slot_num);
   }
 
+static ssize_t file_check_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_CHK, buf);
+}
+
+static ssize_t file_check_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_fix_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_FIX, buf);
+}
+
+static ssize_t file_fix_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_check_max_entries_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	int len = 0;
+	spin_lock(&osb->fc_lock);
+	/* Show done, current size and max */
+	len += sprintf(buf, "%d\t%d\t%d\n", osb->fc_done, osb->fc_size,
+			osb->fc_max);
+	spin_unlock(&osb->fc_lock);
+	return len;

fs/ocfs2/sysfs.c static ssize_t slot_num_show(struct ocfs2_super *osb, · line 120

Quoted 10 lines
fs/ocfs2/sysfs.c +10 -0
+}
+
+static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr, const char *buf, size_t count)
+{
+
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);

Gang: please make sure the function kstrtoul does work well since the

Quoted 8 lines
Quoted 5 lines

inputed buf has not terminating null character.

Quoted 1 line

This is why I write a wrapper function ocfs2_filecheck_args_get_long().

Can you give an example on how this can be activated? Maybe a check on value < 0 may make sense.

Gang: I am not sure if this function works well when the string is inputed without a terminating null character. need to test all the case if using the function directly. But we test all the case with a terminating null character.

So, do you have a testcase?

Quoted 41 lines
Quoted 41 lines
Quoted 17 lines
Quoted 17 lines
fs/ocfs2/sysfs.c +8 -0
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_set_max_entries(osb, (int)t);
+	if (ret)
+		return ret;
+	return count;
+}
+
   static void sb_release(struct kobject *kobj)
   {
   	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
@@ -58,8 +138,15 @@ static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
   };
 
Quoted 13 lines

fs/ocfs2/sysfs.c static const struct sysfs_ops ocfs2_sb_sysfs_ops = { · line 151

Quoted 12 lines
fs/ocfs2/sysfs.c +7 -0
   static OCFS2_SB_ATTR_RO(slot_num);
+static OCFS2_SB_ATTR(file_check);
+static OCFS2_SB_ATTR(file_fix);
+static OCFS2_SB_ATTR(file_check_max_entries);
+
   static struct attribute *ocfs2_sb_attrs[] = {
   	&sb_attr_slot_num.attr,
+	&sb_attr_file_check.attr,
+	&sb_attr_file_fix.attr,
+	&sb_attr_file_check_max_entries.attr,
   	NULL
   };

Gang: as I said in the first patch, please make all the file check related

attributes in a separate sub directory.

Quoted 1 line

It will let us to be easy to read/debug, especially if there is any

reference count leaking problem.

The main reason of the code is to remove unnecessary data structures which is making the code hard to understand. I don't see a point in keeping them in a separate structure besides adding more indirections.

--
Goldwyn

Signature · 1 line
Goldwyn
#12 lore raw

PATCH 2/5 Use the sysfs interface for creating filecheck files

Quoted 107 lines
Quoted 4 lines
Quoted 4 lines
Quoted 71 lines · Gang He
Quoted 71 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines · Gang He

Hello Goldwyn,

Please see my comments inline.
I just suggest to re-use the existing code as most as possible, since the

code was tested by us.

Quoted 15 lines

Thanks
Gang

Quoted 10 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

This reduces the code base and removes unnecessary data structures for filecheck information since all information is stored in ocfs2_super now.

---
   fs/ocfs2/filecheck.c | 440

++++++---------------------------------------------

Quoted 34 lines
Quoted 33 lines
   fs/ocfs2/filecheck.h |  10 ++
   fs/ocfs2/ocfs2.h     |   7 +
   fs/ocfs2/super.c     |   7 +
   fs/ocfs2/sysfs.c     |  91 ++++++++++-
   5 files changed, 161 insertions(+), 394 deletions(-)
fs/ocfs2/filecheck.c +0 -11
index 2cabbcf..0b41967 100644
@@ -17,15 +17,7 @@
    * 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"
@@ -53,36 +45,6 @@ static const char * const ocfs2_filecheck_errs[] = {
   	"UNSUPPORTED"
   };
 
-static DEFINE_SPINLOCK(ocfs2_filecheck_sysfs_lock);
-static LIST_HEAD(ocfs2_filecheck_sysfs_list);
-
Quoted 8 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 65

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-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 */
-};

Gang: we can reuse this structure, please move this structure into struct

ocfs2_super, instead of defining a few members in struct ocfs2_super.

Quoted 8 lines
Quoted 7 lines
Quoted 1 line

We should use a separate structure to handle all the file check related

thing, make the code simple and easy to maintain.

Not sure why you are insistent on keeping a separate structure when it would not be references from different structures. Keeping a prefix of fc will make sure it is for filecheck attributes.

Gang: I just want to make the feature code more independent in other source

files, define a separate data structure to

Quoted 1 line

make the file check code more easily read for the developer, and keep the

code change more less in other source file.

Quoted 1 line

Actually, the existing struct ocfs2_filecheck can be re-used here.

Yes, but it is just initialization of the fields. I understand if you are doing something more..

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 74

Quoted 12 lines
fs/ocfs2/filecheck.c +0 -9
-
-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;
-};

Gang: I think that we can not delete this structure directly, some members

Quoted 8 lines
Quoted 6 lines
Quoted 6 lines

are still useful.

Quoted 1 line

e.g. fs_count, which is used to track if there are any pending file check

entries, can be moved into struct ocfs2_filecheck.

Quoted 1 line

kset members maybe be kept in struct ocfs2_filecheck.

Okay, I will fix that.

On second though, this may not be required.

Gang: This should need a reference count to track if the related data is still needed by others before we delete in the umount stage. You know, file check entry operation is running in the kernel without holding the list spin_lock (actually can not hold), if we try to release the list during umounting, how to make sure all the filecheck IO operation is done?

Quoted 409 lines
Quoted 22 lines
Quoted 22 lines
Quoted 9 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 77

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -3
-
-#define OCFS2_FILECHECK_MAXSIZE		100
-#define OCFS2_FILECHECK_MINSIZE		10

Gang: any file will reference these two macro?
if not, that means these are not interfaces, should be kept in source file.

Yes, they are referenced by multiple files.

Quoted 10 lines

fs/ocfs2/filecheck.c static const char * const ocfs2_filecheck_errs[] = { · line 84

Quoted 8 lines
fs/ocfs2/filecheck.c +0 -7
-
-/* 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 */
-};

Gang: delete the member OCFS2_FILECHECK_TYPE_SET,
Move this enum to the header file if any other source file will use,

Quoted 5 lines
Quoted 4 lines

otherwise should be kept in source file.

The idea of removing this structures was to simplify the code. More structures make more complicated code.

Gang: that is OK, but please define the OCFS2_FILECHECK_TYPE_CHK to 0,

otherwise this replacing is not equivalent.

Quoted 1 line

I am doing away with this in the future posts.

Quoted 228 lines
Quoted 228 lines
Quoted 67 lines
Quoted 67 lines
fs/ocfs2/filecheck.c +0 -51
-
   struct ocfs2_filecheck_entry {
   	struct list_head fe_list;
   	unsigned long fe_ino;
@@ -91,14 +53,6 @@ struct ocfs2_filecheck_entry {
   	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)
   {
@@ -110,321 +64,51 @@ ocfs2_filecheck_error(int errno)
   	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);
-	}
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 161

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-	spin_unlock(&entry->fs_fcheck->fc_lock);
-
-	kset_unregister(entry->fs_fcheckkset);
-	kset_unregister(entry->fs_devicekset);
-	kfree(entry->fs_fcheck);
-	kfree(entry);
-}

Gang: we cannot delete the function ocfs2_filecheck_sysfs_free() directly,

this will be used to free the file check entries.

Quoted 1 line

Please keep the code, otherwise, it will lead to memory leak.

Yes, there should a cleanup routine.

Quoted 43 lines
Quoted 43 lines
fs/ocfs2/filecheck.c +0 -42
-
-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);
Quoted 8 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 210

Quoted 7 lines
fs/ocfs2/filecheck.c +0 -7
-			spin_unlock(&ocfs2_filecheck_sysfs_lock);
-			return p;
-		}
-	}
-	spin_unlock(&ocfs2_filecheck_sysfs_lock);
-	return NULL;
-}

Gang: We can't delete these code directly, fs_count variable is used to

track if there is any process to use file check related data.

Quoted 95 lines

Please consider this variable before delete this part code.

Quoted 81 lines
fs/ocfs2/filecheck.c +0 -81
-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);

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 302

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -10
-	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);
-}

Gang: this part code can be re-used after a little modification.

Quoted 2 lines
Quoted 1 line

For what?

Gang: this part code have a complete creating/releasing kset code, have been

tested, it will not bring any memory leak.

Quoted 108 lines
Quoted 108 lines
Quoted 108 lines
Quoted 97 lines
fs/ocfs2/filecheck.c +12 -62
-
   static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *,
   			      unsigned int count);
-static int
-ocfs2_filecheck_adjust_max(struct ocfs2_filecheck_sysfs_entry *ent,
-			   unsigned int len)
+
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb,
+				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)) {
+	spin_lock(&osb->fc_lock);
+	if (len < (osb->fc_size - osb->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);
+		len, osb->fc_size - osb->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));
+		if (len < osb->fc_size)
+			BUG_ON(!ocfs2_filecheck_erase_entries(osb,
+				osb->fc_size - len));
 
-		ent->fs_fcheck->fc_max = len;
+		osb->fc_max = len;
   		ret = 0;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->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;

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 394

Quoted 10 lines
fs/ocfs2/filecheck.c +0 -9
 
-	args->fa_type = type;
-	if (type == OCFS2_FILECHECK_TYPE_SET)
-		args->fa_len = (unsigned int)val;
-	else
-		args->fa_ino = val;
-
-	return 0;
-}
-

Gang: please keep the ocfs2_filecheck_args_parse function, or write a

Quoted 6 lines
Quoted 5 lines

similar argument checking function since the arguments are from user-space, must be check strictly.

Quoted 1 line

Otherwise, this will be a way for malicious users to panic the kernel.

How? Do you have an example?

Gang: for example, user input a too long number string, we should return a

invalid error directly, not do the further file check operation.

Quoted 1 line

We need a ocfs2_filecheck_args_parse function, add some argument checking

rules for now and future (when we find more limitations),

Quoted 1 line

return the error to the user process directly, to avoid bringing the further

IO checking efforts.

Quoted 27 lines
Quoted 27 lines
Quoted 9 lines
Quoted 9 lines
fs/ocfs2/filecheck.c +1 -2
-static ssize_t ocfs2_filecheck_show(struct kobject *kobj,
-				    struct kobj_attribute *attr,
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type,
   				    char *buf)
   {
 
Quoted 10 lines

fs/ocfs2/filecheck.c ocfs2_filecheck_error(int errno) · line 408

Quoted 9 lines
fs/ocfs2/filecheck.c +0 -7
   	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);

Gang: if delete file check data reference count mechanism, how to make sure

the resource race condition (e.g. list the check results during the file system umounting.)

Quoted 1 line

Please consider this race condition problem.

Isn't spinlock enough? What is the race?

Quoted 8 lines
Quoted 1 line

Gang: No, since file check operation is executed without spinlock, we need a

reference count to keep the related data, until the last usage is finished.

Filesystem unmonting is a different game. It evicts inodes. Could you clarify more?

Anyways, doing away with fe_done and using the status instead should help.

Gang: the file check entry is on behalf of one file check user trigger, is not related with inode object in the kernel. When we get to handle one inode object, we need to follow all the locks of inode.

Quoted 406 lines
Quoted 290 lines
Quoted 290 lines
Quoted 225 lines
Quoted 225 lines
fs/ocfs2/filecheck.c +7 -23
-	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) {
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
   		if (p->fe_type != type)
   			continue;
 
@@ -443,24 +127,21 @@ static ssize_t ocfs2_filecheck_show(struct kobject
 *kobj,
   		total += ret;
   		remain -= ret;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
-
-exit:
-	ocfs2_filecheck_sysfs_put(ent);
+	spin_unlock(&osb->fc_lock);
   	return total;
   }
 
   static int
-ocfs2_filecheck_erase_entry(struct ocfs2_filecheck_sysfs_entry *ent)
+ocfs2_filecheck_erase_entry(struct ocfs2_super *osb)
   {
   	struct ocfs2_filecheck_entry *p;
 
-	list_for_each_entry(p, &ent->fs_fcheck->fc_head, fe_list) {
+	list_for_each_entry(p, &osb->file_check_entries, fe_list) {
   		if (p->fe_done) {
   			list_del(&p->fe_list);
   			kfree(p);
-			ent->fs_fcheck->fc_size--;
-			ent->fs_fcheck->fc_done--;
+			osb->fc_size--;
+			osb->fc_done--;
   			return 1;
   		}
   	}
fs/ocfs2/filecheck.c +2 -2
@@ -469,14 +150,14 @@ ocfs2_filecheck_erase_entry(struct
 ocfs2_filecheck_sysfs_entry *ent)
   }
 
   static int
-ocfs2_filecheck_erase_entries(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_erase_entries(struct ocfs2_super *osb,
   			      unsigned int count)
   {
   	unsigned int i = 0;
   	unsigned int ret = 0;
 
   	while (i++ < count) {
-		if (ocfs2_filecheck_erase_entry(ent))
+		if (ocfs2_filecheck_erase_entry(osb))
   			ret++;
   		else
   			break;
fs/ocfs2/filecheck.c +6 -6
@@ -486,24 +167,24 @@ ocfs2_filecheck_erase_entries(struct
 ocfs2_filecheck_sysfs_entry *ent,
   }
 
   static void
-ocfs2_filecheck_done_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_done_entry(struct ocfs2_super *osb,
   			   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);
+	spin_lock(&osb->fc_lock);
+	osb->fc_done++;
+	spin_unlock(&osb->fc_lock);
   }
 
   static unsigned int
-ocfs2_filecheck_handle(struct super_block *sb,
+ocfs2_filecheck_handle(struct ocfs2_super *osb,
   		       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);
+	inode = ocfs2_iget(osb, ino, flags, 0);
   	if (IS_ERR(inode)) {
   		rc = (int)(-(long)inode);
   		if (rc >= OCFS2_FILECHECK_ERR_START &&
fs/ocfs2/filecheck.c +20 -45
@@ -518,89 +199,64 @@ ocfs2_filecheck_handle(struct super_block *sb,
   }
 
   static void
-ocfs2_filecheck_handle_entry(struct ocfs2_filecheck_sysfs_entry *ent,
+ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
   			     struct ocfs2_filecheck_entry *entry)
   {
   	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(ent->fs_sb,
+		entry->fe_status = ocfs2_filecheck_handle(osb,
   				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_status = ocfs2_filecheck_handle(osb,
   				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
   	else
   		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
 
-	ocfs2_filecheck_done_entry(ent, entry);
+	ocfs2_filecheck_done_entry(osb, entry);
   }
 
-static ssize_t ocfs2_filecheck_store(struct kobject *kobj,
-				     struct kobj_attribute *attr,
-				     const char *buf, size_t count)
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
   {
-	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)) {
+	spin_lock(&osb->fc_lock);
+	if ((osb->fc_size >= osb->fc_max) &&
+	    (osb->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);
+		osb->fc_max);
   		ret = -EBUSY;
   		kfree(entry);
   	} else {
-		if ((ent->fs_fcheck->fc_size >= ent->fs_fcheck->fc_max) &&
-		    (ent->fs_fcheck->fc_done > 0)) {
+		if ((osb->fc_size >= osb->fc_max) &&
+		    (osb->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));
+			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
   		}
 
-		entry->fe_ino = args.fa_ino;
-		entry->fe_type = args.fa_type;
+		entry->fe_ino = ino;
+		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
   		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++;
+		list_add_tail(&entry->fe_list, &osb->file_check_entries);
+		osb->fc_size++;
   	}
-	spin_unlock(&ent->fs_fcheck->fc_lock);
+	spin_unlock(&osb->fc_lock);
 
   	if (!ret)
-		ocfs2_filecheck_handle_entry(ent, entry);
+		ocfs2_filecheck_handle_entry(osb, entry);
 
   exit:
-	ocfs2_filecheck_sysfs_put(ent);
-	return (!ret ? count : ret);
+	return ret;
   }
fs/ocfs2/filecheck.h +0 -0
index e5cd002..b1a0d8c 100644
@@ -42,8 +42,18 @@ enum {
 
Quoted 10 lines

fs/ocfs2/filecheck.h enum { · line 50

Quoted 8 lines
fs/ocfs2/filecheck.h +6 -0
   #define OCFS2_FILECHECK_ERR_START	OCFS2_FILECHECK_ERR_FAILED
   #define OCFS2_FILECHECK_ERR_END		OCFS2_FILECHECK_ERR_UNSUPPORTED
+#define OCFS2_FILECHECK_MAXSIZE         100
+#define OCFS2_FILECHECK_MINSIZE         10
+
+/* File check operation type */
+#define OCFS2_FILECHECK_TYPE_CHK  	1   /* Check a file(inode) */
+#define OCFS2_FILECHECK_TYPE_FIX  	2   /* Fix a file(inode) */

Please use enum, not use macro definitions, maybe there will be more type. OCFS2_FILECHECK_TYPE_CHK should be zero, otherwise this macro is different

with previous enum definitions.

Quoted 19 lines
Quoted 19 lines
fs/ocfs2/filecheck.h +4 -0
   int ocfs2_filecheck_create_sysfs(struct super_block *sb);
   int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
+int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
+int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
 
   #endif  /* FILECHECK_H */
fs/ocfs2/ocfs2.h +0 -0
index 8e66cdf..9ced543 100644
@@ -474,6 +474,13 @@ struct ocfs2_super
   	 */
   	struct workqueue_struct *ocfs2_wq;
 
Quoted 8 lines

fs/ocfs2/ocfs2.h struct ocfs2_super · line 483

Quoted 7 lines
fs/ocfs2/ocfs2.h +7 -0
+	/* file check */
+	struct list_head file_check_entries;
+	unsigned int fc_size;
+	unsigned int fc_max;
+	unsigned int fc_done;
+	spinlock_t fc_lock;
+

Gang: please use a separate structure to include all the file check members,

easy to read/maintain.

I would prefer it to be a part of ocfs2_super. It is easier to maintain and read.

Quoted 21 lines
Quoted 10 lines
fs/ocfs2/ocfs2.h +0 -0
   	struct kobject kobj;
   	struct completion kobj_unregister;
   };
fs/ocfs2/super.c +0 -0
index 96b7a9f..a7791fa 100644
@@ -2215,6 +2215,13 @@ static int ocfs2_initialize_super(struct super_block
 *sb,

fs/ocfs2/super.c static int ocfs2_initialize_super(struct super_block · line 2225

Quoted 10 lines
fs/ocfs2/super.c +7 -0
 
   	get_random_bytes(&osb->s_next_generation, sizeof(u32));
 
+	/* file check information */
+	INIT_LIST_HEAD(&osb->file_check_entries);
+	osb->fc_max = OCFS2_FILECHECK_MINSIZE;
+	osb->fc_size = 0;
+	osb->fc_done = 0;
+	spin_lock_init(&osb->fc_lock);
+

Gang: write a separate funtion in filecheck.c to include these line code,

Quoted 5 lines
Quoted 4 lines

easy to read/maintain.

Why? Unless we are starting something specific to filecheck, I don't see any need.

Gang: I just want to make the file check thing is done in filecheck source

file, the other module just call some functions.

Quoted 110 lines

Let the code more clear.

Quoted 108 lines
Quoted 95 lines
Quoted 95 lines
fs/ocfs2/super.c +0 -0
   	/* FIXME
   	 * This should be done in ocfs2_journal_init(), but unknown

* ordering issues will cause the filesystem to crash.

fs/ocfs2/sysfs.c +67 -2
index e21e699..81e3dd4 100644
@@ -1,5 +1,6 @@
   #include "ocfs2.h"
   #include "sysfs.h"
+#include "filecheck.h"
 
   struct ocfs2_sb_attr {
   	struct attribute attr;
@@ -9,8 +10,12 @@ struct ocfs2_sb_attr {
   			const char *buf, size_t count);
   };
 
-#define OCFS2_SB_ATTR(_name, _mode) \
-struct ocfs2_sb_attr sb_attr_##_name = __ATTR(name, _mode, _show, _store)
+#define OCFS2_SB_ATTR(_name) \
+struct ocfs2_sb_attr sb_attr_##_name = { \
+	.attr = {.name = __stringify(_name), .mode = (S_IWUSR | S_IRUGO)},  \
+	.show = _name##_show, \
+	.store = _name##_store \
+}
 
   #define OCFS2_SB_ATTR_RO(_name) \
   struct ocfs2_sb_attr sb_attr_##_name = __ATTR_RO(_name)
@@ -46,6 +51,81 @@ static ssize_t slot_num_show(struct ocfs2_super *osb,
   	return sprintf(buf, "%d\n", osb->slot_num);
   }
 
+static ssize_t file_check_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_CHK, buf);
+}
+
+static ssize_t file_check_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_fix_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	return ocfs2_filecheck_show(osb, OCFS2_FILECHECK_TYPE_FIX, buf);
+}
+
+static ssize_t file_fix_store(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		const char *buf, size_t count)
+{
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_add_inode(osb, t);
+	if (ret)
+		return ret;
+	return count;
+}
+
+static ssize_t file_check_max_entries_show(struct ocfs2_super *osb,
+		struct ocfs2_sb_attr *attr,
+		char *buf)
+{
+	int len = 0;
+	spin_lock(&osb->fc_lock);
+	/* Show done, current size and max */
+	len += sprintf(buf, "%d\t%d\t%d\n", osb->fc_done, osb->fc_size,
+			osb->fc_max);
+	spin_unlock(&osb->fc_lock);
+	return len;
+}
+
+static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
Quoted 8 lines

fs/ocfs2/sysfs.c static ssize_t slot_num_show(struct ocfs2_super *osb, · line 120

Quoted 7 lines
fs/ocfs2/sysfs.c +7 -0
+		struct ocfs2_sb_attr *attr, const char *buf, size_t count)
+{
+
+	unsigned long t;
+	int ret;
+
+	ret = kstrtoul(skip_spaces(buf), 0, &t);

Gang: please make sure the function kstrtoul does work well since the

inputed buf has not terminating null character.

Quoted 1 line

This is why I write a wrapper function ocfs2_filecheck_args_get_long().

Can you give an example on how this can be activated? Maybe a check on value < 0 may make sense.

Quoted 7 lines
Quoted 1 line

Gang: I am not sure if this function works well when the string is inputed

without a terminating null character.

Quoted 1 line

need to test all the case if using the function directly. But we test all

the case with a terminating null character.

Quoted 1 line

So, do you have a testcase?

Gang: Eric tested this manually in various possible cases, not sure if he wrote these cases in the scripts.

Quoted 45 lines
Quoted 42 lines
Quoted 42 lines
Quoted 18 lines
Quoted 18 lines
fs/ocfs2/sysfs.c +8 -0
+	if (ret)
+		return ret;
+	ret = ocfs2_filecheck_set_max_entries(osb, (int)t);
+	if (ret)
+		return ret;
+	return count;
+}
+
   static void sb_release(struct kobject *kobj)
   {
   	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
@@ -58,8 +138,15 @@ static const struct sysfs_ops ocfs2_sb_sysfs_ops = {
   };
 
Quoted 13 lines

fs/ocfs2/sysfs.c static const struct sysfs_ops ocfs2_sb_sysfs_ops = { · line 151

Quoted 12 lines
fs/ocfs2/sysfs.c +7 -0
   static OCFS2_SB_ATTR_RO(slot_num);
+static OCFS2_SB_ATTR(file_check);
+static OCFS2_SB_ATTR(file_fix);
+static OCFS2_SB_ATTR(file_check_max_entries);
+
   static struct attribute *ocfs2_sb_attrs[] = {
   	&sb_attr_slot_num.attr,
+	&sb_attr_file_check.attr,
+	&sb_attr_file_fix.attr,
+	&sb_attr_file_check_max_entries.attr,
   	NULL
   };

Gang: as I said in the first patch, please make all the file check related

attributes in a separate sub directory.

Quoted 1 line

It will let us to be easy to read/debug, especially if there is any

reference count leaking problem.

The main reason of the code is to remove unnecessary data structures which is making the code hard to understand. I don't see a point in keeping them in a separate structure besides adding more indirections.

--
Goldwyn

Signature · 1 line
Goldwyn
#13 lore raw

PATCH v2 3/5 Generate uevents for errors

In reply to Goldwyn Rodrigues

From: Goldwyn Rodrigues <[email protected]>

---
 fs/ocfs2/inode.c | 13 +++++++++++++
 fs/ocfs2/sysfs.c | 17 +++++++++++++++++
 fs/ocfs2/sysfs.h |  2 ++
 3 files changed, 32 insertions(+)
fs/ocfs2/inode.c +13 -0
index 12f4a9e..a6cfe5d 100644
@@ -54,6 +54,7 @@
 #include "refcounttree.h"
 #include "ocfs2_trace.h"
 #include "filecheck.h"
+#include "sysfs.h"
 
 #include "buffer_head_io.h"
 
@@ -1412,6 +1413,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n",
 				 (unsigned long long)bh->b_blocknr, 7,
 				 di->i_signature);
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1419,6 +1423,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n",
 				 (unsigned long long)bh->b_blocknr,
 				 (unsigned long long)le64_to_cpu(di->i_blkno));
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1426,6 +1433,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb,
 				 "Invalid dinode #%llu: OCFS2_VALID_FL not set\n",
 				 (unsigned long long)bh->b_blocknr);
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1435,6 +1445,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 				 "Invalid dinode #%llu: fs_generation is %u\n",
 				 (unsigned long long)bh->b_blocknr,
 				 le32_to_cpu(di->i_fs_generation));
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
fs/ocfs2/sysfs.c +17 -0
index 81e3dd4..acc4834 100644
@@ -126,6 +126,23 @@ static ssize_t file_check_max_entries_store(struct ocfs2_super *osb,
 	return count;
 }
 
+void ocfs2_report_error(struct ocfs2_super *osb, unsigned long long ino,
+			unsigned long long blkno, int errno)
+{
+	char event_name[] = "EVENT=FS_ERROR";
+	char device[16];
+	char inode_number[16];
+	char error_number[16];
+	char block_number[16];
+	char *envp[] = {event_name, inode_number, error_number, block_number,
+		NULL};
+	snprintf(device, 16, "DEVICE=%s", osb->sb->s_id);
+	snprintf(error_number, 16, "ERROR=%d", errno);
+	snprintf(inode_number, 16, "INODE=%llu", ino);
+	snprintf(block_number, 16, "BLOCK=%llu", blkno);
+	kobject_uevent_env(&osb->kobj, KOBJ_CHANGE, envp);
+}
+
 static void sb_release(struct kobject *kobj)
 {
 	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
fs/ocfs2/sysfs.h +2 -0
index d929ac1..0383ee3 100644
@@ -3,6 +3,8 @@
 #ifndef _SYS_H
 #define _SYS_H
 
+void ocfs2_report_error(struct ocfs2_super *osb, unsigned long long ino,
+		unsigned long long blkno, int error);
 int ocfs2_sysfs_sb_init(struct super_block *sb);
 void ocfs2_sysfs_sb_exit(struct super_block *sb);
 
Signature · 1 line
2.6.6
#14 lore raw

PATCH 3/5 Generate uevents for errors

Looks good for me.

Thanks
Gang

Quoted 112 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

---
 fs/ocfs2/inode.c | 13 +++++++++++++
 fs/ocfs2/sysfs.c | 17 +++++++++++++++++
 fs/ocfs2/sysfs.h |  2 ++
 3 files changed, 32 insertions(+)
fs/ocfs2/inode.c +13 -0
index 12f4a9e..a6cfe5d 100644
@@ -54,6 +54,7 @@
 #include "refcounttree.h"
 #include "ocfs2_trace.h"
 #include "filecheck.h"
+#include "sysfs.h"
 
 #include "buffer_head_io.h"
 
@@ -1412,6 +1413,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n",
 				 (unsigned long long)bh->b_blocknr, 7,
 				 di->i_signature);
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1419,6 +1423,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n",
 				 (unsigned long long)bh->b_blocknr,
 				 (unsigned long long)le64_to_cpu(di->i_blkno));
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1426,6 +1433,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 		rc = ocfs2_error(sb,
 				 "Invalid dinode #%llu: OCFS2_VALID_FL not set\n",
 				 (unsigned long long)bh->b_blocknr);
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
@@ -1435,6 +1445,9 @@ int ocfs2_validate_inode_block(struct super_block *sb,
 				 "Invalid dinode #%llu: fs_generation is %u\n",
 				 (unsigned long long)bh->b_blocknr,
 				 le32_to_cpu(di->i_fs_generation));
+		ocfs2_report_error(OCFS2_SB(sb), (unsigned long long)bh->b_blocknr,
+				(unsigned long long)bh->b_blocknr,
+				rc);
 		goto bail;
 	}
 
fs/ocfs2/sysfs.c +17 -0
index 81e3dd4..acc4834 100644
@@ -126,6 +126,23 @@ static ssize_t file_check_max_entries_store(struct 
 ocfs2_super *osb,
 	return count;
 }
 
+void ocfs2_report_error(struct ocfs2_super *osb, unsigned long long ino,
+			unsigned long long blkno, int errno)
+{
+	char event_name[] = "EVENT=FS_ERROR";
+	char device[16];
+	char inode_number[16];
+	char error_number[16];
+	char block_number[16];
+	char *envp[] = {event_name, inode_number, error_number, block_number,
+		NULL};
+	snprintf(device, 16, "DEVICE=%s", osb->sb->s_id);
+	snprintf(error_number, 16, "ERROR=%d", errno);
+	snprintf(inode_number, 16, "INODE=%llu", ino);
+	snprintf(block_number, 16, "BLOCK=%llu", blkno);
+	kobject_uevent_env(&osb->kobj, KOBJ_CHANGE, envp);
+}
+
 static void sb_release(struct kobject *kobj)
 {
fs/ocfs2/sysfs.c +0 -0
 	struct ocfs2_super *osb = container_of(kobj, struct ocfs2_super, kobj);
fs/ocfs2/sysfs.h +2 -0
index d929ac1..0383ee3 100644
@@ -3,6 +3,8 @@
 #ifndef _SYS_H
 #define _SYS_H
 
+void ocfs2_report_error(struct ocfs2_super *osb, unsigned long long ino,
+		unsigned long long blkno, int error);
 int ocfs2_sysfs_sb_init(struct super_block *sb);
 void ocfs2_sysfs_sb_exit(struct super_block *sb);
 
Signature · 7 lines
2.6.6


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com 
https://oss.oracle.com/mailman/listinfo/ocfs2-devel
#15 lore raw

PATCH v2 4/5 ocfs2: Disallow duplicate entries in the list

In reply to Goldwyn Rodrigues

From: Goldwyn Rodrigues <[email protected]>

---
 fs/ocfs2/filecheck.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)
fs/ocfs2/filecheck.c +17 -9
index 0b41967..006d521 100644
@@ -217,14 +217,12 @@ ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 				     unsigned long ino)
 {
-	struct ocfs2_filecheck_entry *entry;
+	struct ocfs2_filecheck_entry *entry, *p;
 	ssize_t ret = 0;
 
 	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
-	if (!entry) {
-		ret = -ENOMEM;
-		goto exit;
-	}
+	if (!entry)
+		return -ENOMEM;
 
 	spin_lock(&osb->fc_lock);
 	if ((osb->fc_size >= osb->fc_max) &&
@@ -244,6 +242,12 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 			 */
 			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
 		}
+		list_for_each_entry(p, &osb->file_check_entries, fe_list)
+			if (p->fe_ino == ino) {
+				ret = -EEXIST;
+				kfree(entry);
+				goto unlock;
+			}
 
 		entry->fe_ino = ino;
 		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
@@ -252,11 +256,15 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 		list_add_tail(&entry->fe_list, &osb->file_check_entries);
 		osb->fc_size++;
 	}
+unlock:
 	spin_unlock(&osb->fc_lock);
 
-	if (!ret)
-		ocfs2_filecheck_handle_entry(osb, entry);
+	if (ret)
+		return ret;
 
-exit:
-	return ret;
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
 }
Signature · 1 line
2.6.6
#16 lore raw

PATCH 4/5 ocfs2: Disallow duplicate entries in the list

Looks good to me.

Thanks
Gang

Quoted 71 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

---
 fs/ocfs2/filecheck.c | 26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)
fs/ocfs2/filecheck.c +17 -9
index 0b41967..006d521 100644
@@ -217,14 +217,12 @@ ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 				     unsigned long ino)
 {
-	struct ocfs2_filecheck_entry *entry;
+	struct ocfs2_filecheck_entry *entry, *p;
 	ssize_t ret = 0;
 
 	entry = kmalloc(sizeof(struct ocfs2_filecheck_entry), GFP_NOFS);
-	if (!entry) {
-		ret = -ENOMEM;
-		goto exit;
-	}
+	if (!entry)
+		return -ENOMEM;
 
 	spin_lock(&osb->fc_lock);
 	if ((osb->fc_size >= osb->fc_max) &&
@@ -244,6 +242,12 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 			 */
 			BUG_ON(!ocfs2_filecheck_erase_entry(osb));
 		}
+		list_for_each_entry(p, &osb->file_check_entries, fe_list)
+			if (p->fe_ino == ino) {
+				ret = -EEXIST;
+				kfree(entry);
+				goto unlock;
+			}
 
 		entry->fe_ino = ino;
 		entry->fe_type = OCFS2_FILECHECK_TYPE_CHK;
@@ -252,11 +256,15 @@ int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 		list_add_tail(&entry->fe_list, &osb->file_check_entries);
 		osb->fc_size++;
 	}
+unlock:
 	spin_unlock(&osb->fc_lock);
 
-	if (!ret)
-		ocfs2_filecheck_handle_entry(osb, entry);
+	if (ret)
+		return ret;
 
-exit:
-	return ret;
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
 }
Signature · 7 lines
2.6.6


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com 
https://oss.oracle.com/mailman/listinfo/ocfs2-devel
#17 lore raw

PATCH v2 5/5 Fix files when an inode is written in file_fix

In reply to Goldwyn Rodrigues

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
 fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
 fs/ocfs2/filecheck.h |  1 +
 fs/ocfs2/sysfs.c     |  2 +-
 3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +25 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
 	return ret;
 }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 				     unsigned long ino)
 {
@@ -268,3 +252,28 @@ unlock:
 	ocfs2_filecheck_done_entry(osb, entry);
 	return 0;
 }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
fs/ocfs2/filecheck.h +1 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
 int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
 int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
 int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
 int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char *buf);
 
fs/ocfs2/sysfs.c +1 -1
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
 	ret = kstrtoul(skip_spaces(buf), 0, &t);
 	if (ret)
 		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
 	if (ret)
 		return ret;
 	return count;
Signature · 1 line
2.6.6
#18 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 45 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
 fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
 fs/ocfs2/filecheck.h |  1 +
 fs/ocfs2/sysfs.c     |  2 +-
 3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +1 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
 	return ret;
 }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
 				     unsigned long ino)
 {
@@ -268,3 +252,28 @@ unlock:
 	ocfs2_filecheck_done_entry(osb, entry);
 	return 0;
 }
+

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 10 lines
fs/ocfs2/filecheck.c +10 -0
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry pointer can be freed by the function ocfs2_filecheck_erase_entries().
We can not use the same entry pointer within two user processes.
The simple solution is to return -EBUSY error in case there is the same ino number entry in the list, then the user can try again after the previous user process is returned.

Quoted 48 lines
fs/ocfs2/filecheck.c +14 -0
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
fs/ocfs2/filecheck.h +1 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
 int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
 int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
 int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
 int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
 int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char 
 *buf);
fs/ocfs2/sysfs.c +1 -1
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
 	ret = kstrtoul(skip_spaces(buf), 0, &t);
 	if (ret)
 		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
 	if (ret)
 		return ret;
 	return count;
Signature · 7 lines
2.6.6


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com 
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#20 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Quoted 59 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 50 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
  fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
  fs/ocfs2/filecheck.h |  1 +
  fs/ocfs2/sysfs.c     |  2 +-
  3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +6 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
  	return ret;
  }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
  int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
  				     unsigned long ino)
  {
@@ -268,3 +252,28 @@ unlock:
  	ocfs2_filecheck_done_entry(osb, entry);
  	return 0;
  }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 5 lines
fs/ocfs2/filecheck.c +5 -0
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry pointer can be freed by the function ocfs2_filecheck_erase_entries().
We can not use the same entry pointer within two user processes.
The simple solution is to return -EBUSY error in case there is the same ino number entry in the list, then the user can try again after the previous user process is returned.

How? is it not protected under spinlock?
Anyways, I plan to make a separate list for this so we can do away with more macros.

Besides, any I/O and check operation should be done in a separate thread/work queue.

Quoted 49 lines
Quoted 49 lines
fs/ocfs2/filecheck.c +14 -0
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
fs/ocfs2/filecheck.h +1 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
  int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
  int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
  int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
  int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
  int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
fs/ocfs2/sysfs.c +1 -2
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
  	ret = kstrtoul(skip_spaces(buf), 0, &t);
  	if (ret)
  		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
  	if (ret)
  		return ret;
  	return count;
--

2.6.6

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

Signature · 1 line
Goldwyn
#21 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Hello Goldwyn,

Quoted 69 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
  fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
  fs/ocfs2/filecheck.h |  1 +
  fs/ocfs2/sysfs.c     |  2 +-
  3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
  	return ret;
  }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
  int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
  				     unsigned long ino)
  {
@@ -268,3 +252,28 @@ unlock:
  	ocfs2_filecheck_done_entry(osb, entry);
  	return 0;
  }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

Quoted 7 lines

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous user process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list (adding entry/deleting entry), not protect entry itself.
The first user process will mark the entry's status to done after the file check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry. You know, the spinlock can not protect the file check operation (too long time IO operation).

Quoted 2 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the thing simple.
Just return a -EBUSY error when the same inode is on the progress, then the user can try again after that file check process returns.

Quoted 3 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check operation, each user trigger process is used to execute its file check operation.
Why? first, keep the thing simple, avoid to involve more logic/thread. second, if we involved a thread/work queue to run the file check operations,
that means the user trigger process will return directly and need not to wait for the actual file check operation, there will be a risk that the user can
not see the result from the result history record (via cat check/fix), since the new submits result will make the oldest result records to be released,
we have a fixed length list to keep these status records. If we use the user trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 53 lines
Quoted 50 lines
Quoted 50 lines
fs/ocfs2/filecheck.c +14 -0
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
fs/ocfs2/filecheck.h +1 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
  int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
  int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
  int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
  int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
  int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
fs/ocfs2/sysfs.c +1 -2
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
  	ret = kstrtoul(skip_spaces(buf), 0, &t);
  	if (ret)
  		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
  	if (ret)
  		return ret;
  	return count;
--

2.6.6

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

Signature · 1 line
Goldwyn
#22 lore raw

PATCH v2 5/5 Fix files when an inode is written in file_fix

Quoted 75 lines · Gang He

Hello Goldwyn,

Quoted 72 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
   fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
   fs/ocfs2/filecheck.h |  1 +
   fs/ocfs2/sysfs.c     |  2 +-
   3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
   	return ret;
   }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
   int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
   				     unsigned long ino)
   {
@@ -268,3 +252,28 @@ unlock:
   	ocfs2_filecheck_done_entry(osb, entry);
   	return 0;
   }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

Quoted 7 lines
Quoted 4 lines

number entry in the list, then the user can try again after the previous user process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list (adding entry/deleting entry), not protect entry itself.
The first user process will mark the entry's status to done after the file check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry. You know, the spinlock can not protect the file check operation (too long time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Quoted 5 lines
Quoted 3 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the thing simple.
Just return a -EBUSY error when the same inode is on the progress, then the user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 10 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check operation, each user trigger process is used to execute its file check operation.
Why? first, keep the thing simple, avoid to involve more logic/thread. second, if we involved a thread/work queue to run the file check operations,
that means the user trigger process will return directly and need not to wait for the actual file check operation, there will be a risk that the user can
not see the result from the result history record (via cat check/fix), since the new submits result will make the oldest result records to be released,
we have a fixed length list to keep these status records. If we use the user trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Quoted 54 lines
Quoted 54 lines
Quoted 47 lines
Quoted 47 lines
fs/ocfs2/filecheck.c +14 -0
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
fs/ocfs2/filecheck.h +1 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
   int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
   int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
   int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long ino);
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
   int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
   int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
fs/ocfs2/sysfs.c +1 -2
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
   	ret = kstrtoul(skip_spaces(buf), 0, &t);
   	if (ret)
   		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
   	if (ret)
   		return ret;
   	return count;
--

2.6.6

Quoted 4 lines
Quoted 4 lines

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

--
Goldwyn

Signature · 1 line
Goldwyn
#23 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Quoted 94 lines
Quoted 4 lines
Quoted 4 lines
Quoted 76 lines · Gang He

Hello Goldwyn,

Quoted 73 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
   fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
   fs/ocfs2/filecheck.h |  1 +
   fs/ocfs2/sysfs.c     |  2 +-
   3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
   	return ret;
   }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
   int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
   				     unsigned long ino)
   {
@@ -268,3 +252,28 @@ unlock:
   	ocfs2_filecheck_done_entry(osb, entry);
   	return 0;
   }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done, since we need to keep them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only occupied by one user process. we only need to get the lock when adding/deleting the entry from the list, this operation is very short.

Quoted 28 lines
Quoted 6 lines
Quoted 5 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

Quoted 8 lines

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just like a system call. If we want to check multiple files (inode), we can use a batch to call this interface one by one (of course, you can use multiple threads/processes), this is why I did not use a work queue/thread in the kernel module to do this asynchronously, because in the user space, we can do the same thing. let's keep the kernel module logic simple.

Quoted 59 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
fs/ocfs2/filecheck.c +14 -0
+			ret = 0;
+			break;
+		}
+	spin_unlock(&osb->fc_lock);
+	if (ret)
+		return ret;
+
+	entry->fe_status = ocfs2_filecheck_handle(osb,
+			entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
+
+	ocfs2_filecheck_done_entry(osb, entry);
+	return 0;
+}
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

fs/ocfs2/filecheck.h int ocfs2_filecheck_create_sysfs(struct super_block *sb); · line 55

Quoted 8 lines
fs/ocfs2/filecheck.h +0 -0
index b1a0d8c..d5f81a7 100644
@@ -53,6 +53,7 @@ int ocfs2_filecheck_create_sysfs(struct super_block *sb);
   int ocfs2_filecheck_remove_sysfs(struct super_block *sb);
   int ocfs2_filefix_inode(struct ocfs2_super *osb, unsigned long ino);
   int ocfs2_filecheck_add_inode(struct ocfs2_super *osb, unsigned long 

ino);

Quoted 29 lines
Quoted 29 lines
Quoted 22 lines
Quoted 22 lines
fs/ocfs2/filecheck.h +1 -0
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb, unsigned long ino);
   int ocfs2_filecheck_set_max_entries(struct ocfs2_super *osb, int num);
   int ocfs2_filecheck_show(struct ocfs2_super *osb, unsigned int type, char
 *buf);
fs/ocfs2/sysfs.c +1 -2
index acc4834..ac149fb 100644
@@ -91,7 +91,7 @@ static ssize_t file_fix_store(struct ocfs2_super *osb,
   	ret = kstrtoul(skip_spaces(buf), 0, &t);
   	if (ret)
   		return ret;
-	ret = ocfs2_filecheck_add_inode(osb, t);
+	ret = ocfs2_filefix_add_inode(osb, t);
   	if (ret)
   		return ret;
   	return count;
--

2.6.6

Quoted 4 lines
Quoted 4 lines

_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel at oss.oracle.com
https://oss.oracle.com/mailman/listinfo/ocfs2-devel

--
Goldwyn

Signature · 1 line
Goldwyn
#24 lore raw

PATCH v2 5/5 Fix files when an inode is written in file_fix

Quoted 141 lines · Gang He
Quoted 94 lines
Quoted 4 lines
Quoted 4 lines
Quoted 76 lines · Gang He

Hello Goldwyn,

Quoted 73 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
    fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
    fs/ocfs2/filecheck.h |  1 +
    fs/ocfs2/sysfs.c     |  2 +-
    3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
    	return ret;
    }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
    int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
    				     unsigned long ino)
    {
@@ -268,3 +252,28 @@ unlock:
    	ocfs2_filecheck_done_entry(osb, entry);
    	return 0;
    }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done, since we need to keep them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only occupied by one user process. we only need to get the lock when adding/deleting the entry from the list, this operation is very short.

Quoted 33 lines
Quoted 6 lines
Quoted 5 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 8 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just like a system call. If we want to check multiple files (inode), we can use a batch to call this interface one by one (of course, you can use multiple threads/processes), this is why I did not use a work queue/thread in the kernel module to do this asynchronously, because in the user space, we can do the same thing. let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

Signature · 1 line
Goldwyn
#25 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Quoted 160 lines
Quoted 4 lines
Quoted 4 lines
Quoted 94 lines · Gang He
Quoted 94 lines
Quoted 4 lines
Quoted 4 lines
Quoted 76 lines · Gang He

Hello Goldwyn,

Quoted 73 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
    fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
    fs/ocfs2/filecheck.h |  1 +
    fs/ocfs2/sysfs.c     |  2 +-
    3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
    	return ret;
    }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
    int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
    				     unsigned long ino)
    {
@@ -268,3 +252,28 @@ unlock:
    	ocfs2_filecheck_done_entry(osb, entry);
    	return 0;
    }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done,

since we need to keep

Quoted 6 lines

them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only

occupied by one user process.

Quoted 1 line

we only need to get the lock when adding/deleting the entry from the list,

this operation is very short.

Quoted 34 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 4 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just

like a system call.

Quoted 1 line

If we want to check multiple files (inode), we can use a batch to call this

interface one by one

Quoted 1 line

(of course, you can use multiple threads/processes), this is why I did not

use a work queue/thread

Quoted 8 lines
Quoted 1 line

in the kernel module to do this asynchronously, because in the user space,

we can do the same thing.

Quoted 1 line

let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

The list be used for file check entry history status, and for supporting to multiple user threads/processes to trigger a check/fix request parallelly.

Quoted 4 lines
Signature · 2 lines
-- 
Goldwyn
#26 lore raw

PATCH v2 5/5 Fix files when an inode is written in file_fix

Quoted 161 lines · Gang He
Quoted 161 lines
Quoted 4 lines
Quoted 4 lines
Quoted 94 lines · Gang He
Quoted 94 lines
Quoted 4 lines
Quoted 4 lines
Quoted 76 lines · Gang He

Hello Goldwyn,

Quoted 73 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
     fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
     fs/ocfs2/filecheck.h |  1 +
     fs/ocfs2/sysfs.c     |  2 +-
     3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
     	return ret;
     }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
     int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
     				     unsigned long ino)
     {
@@ -268,3 +252,28 @@ unlock:
     	ocfs2_filecheck_done_entry(osb, entry);
     	return 0;
     }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done,

since we need to keep

Quoted 6 lines

them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only

occupied by one user process.

Quoted 1 line

we only need to get the lock when adding/deleting the entry from the list,

this operation is very short.

Quoted 34 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 4 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just

like a system call.

Quoted 1 line

If we want to check multiple files (inode), we can use a batch to call this

interface one by one

Quoted 1 line

(of course, you can use multiple threads/processes), this is why I did not

use a work queue/thread

Quoted 1 line

in the kernel module to do this asynchronously, because in the user space,

Quoted 9 lines
Quoted 7 lines

we can do the same thing.

Quoted 1 line

let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

The list be used for file check entry history status, and for supporting to multiple user threads/processes to trigger a check/fix request parallelly.

Why do you need history in a synchronous process. The error is received as soon as the process ends. Besides, in multiple threads each thread will have his context so you don't need to store in a global location. Why did you need to use sysfs for this? Why couldn't you use something else for synchronous processing, say an ioctl()?

Signature · 1 line
Goldwyn
#27 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Quoted 175 lines
Quoted 4 lines
Quoted 4 lines
Quoted 168 lines · Gang He
Quoted 168 lines
Quoted 4 lines
Quoted 4 lines
Quoted 94 lines · Gang He
Quoted 94 lines
Quoted 4 lines
Quoted 4 lines
Quoted 76 lines · Gang He

Hello Goldwyn,

Quoted 73 lines
Quoted 1 line
Quoted 1 line
Quoted 57 lines · Gang He

Hello Goldwyn,

Please see my comments inline.

Thanks
Gang

Quoted 48 lines
Quoted 1 line
Quoted 1 line

From: Goldwyn Rodrigues <[email protected]>

Check that the entriy exists and has been filed for check. Also perform some code cleanup

---
     fs/ocfs2/filecheck.c | 41 +++++++++++++++++++++++++----------------
     fs/ocfs2/filecheck.h |  1 +
     fs/ocfs2/sysfs.c     |  2 +-
     3 files changed, 27 insertions(+), 17 deletions(-)
fs/ocfs2/filecheck.c +4 -16
index 006d521..fc6e183 100644
@@ -198,22 +198,6 @@ ocfs2_filecheck_handle(struct ocfs2_super *osb,
     	return ret;
     }
 
-static void
-ocfs2_filecheck_handle_entry(struct ocfs2_super *osb,
-			     struct ocfs2_filecheck_entry *entry)
-{
-	if (entry->fe_type == OCFS2_FILECHECK_TYPE_CHK)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_CHK);
-	else if (entry->fe_type == OCFS2_FILECHECK_TYPE_FIX)
-		entry->fe_status = ocfs2_filecheck_handle(osb,
-				entry->fe_ino, OCFS2_FI_FLAG_FILECHECK_FIX);
-	else
-		entry->fe_status = OCFS2_FILECHECK_ERR_UNSUPPORTED;
-
-	ocfs2_filecheck_done_entry(osb, entry);
-}
-
     int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
     				     unsigned long ino)
     {
@@ -268,3 +252,28 @@ unlock:
     	ocfs2_filecheck_done_entry(osb, entry);
     	return 0;
     }
+
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
Quoted 8 lines

fs/ocfs2/filecheck.c unlock: · line 265

Quoted 7 lines
fs/ocfs2/filecheck.c +7 -0
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done,

since we need to keep

Quoted 6 lines

them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only

occupied by one user process.

Quoted 1 line

we only need to get the lock when adding/deleting the entry from the list,

this operation is very short.

Quoted 34 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 4 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just

like a system call.

Quoted 1 line

If we want to check multiple files (inode), we can use a batch to call this

interface one by one

Quoted 1 line

(of course, you can use multiple threads/processes), this is why I did not

use a work queue/thread

Quoted 1 line

in the kernel module to do this asynchronously, because in the user space,

we can do the same thing.

Quoted 1 line

let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

Quoted 6 lines
Quoted 1 line

The list be used for file check entry history status, and for supporting to

multiple user threads/processes to trigger a check/fix request parallelly.

Quoted 1 line

Why do you need history in a synchronous process. The error is received as soon as the process ends.

How do you return a file check specific error number to the trigger user process? then I use a list to save these file check entries (running/done).
The user maybe want to see the file check result again after the file check was done, this just give an chance for user to inquire the result again, but will not occupy too much memory.

Besides, in multiple threads each thread

Quoted 1 line

will have his context so you don't need to store in a global location.

Gang: I prefer to do the thing with independent design, do not depend some other data structures/mechanism, since these data structures/mechanism will be changed according kernel versions possibly. we should try to implement our functions in our module code, then export some interfaces(extern functions) to be invoked by some kernel sensitive data structures/mechanism (e.g. Kobject, ioctl, etc). Why I user a global location, at that moment, I did not aware that we can embed kobject in super block structure like ext4, now we can embed kobject in the super, the idea
is better.

Quoted 2 lines

Why did you need to use sysfs for this? Why couldn't you use something else for synchronous processing, say an ioctl()?

Gang: Yes, this is a way to reach user process, as you said in a RFC one year ago.
Of course, we also can use ioctl to commutation, but this will means that we have to add some code to implement a user tool.

Anyway, I think it is not too important about if we use synchronous/asynchronous to handle a file check operation, if you like, please create a dedicated kernel thread to execute these file check entries in the list. It is OK for both ways.

Thanks
Gang

Quoted 4 lines
Signature · 2 lines
-- 
Goldwyn

A message that is not in the archive (sent off-list or not yet received): [email protected]

#29 lore raw

PATCH v2 5/5 Fix files when an inode is written in file_fix

Quoted 103 lines · Gang He
Quoted 103 lines
Quoted 103 lines
Quoted 103 lines
Quoted 36 lines
Quoted 36 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 10 lines

int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
unsigned long ino)
{

(quoted diff) +1 -0
@@ -268,3 +252,28 @@ unlock:
      	ocfs2_filecheck_done_entry(osb, entry);
      	return 0;
      }
+

Review unlock: · line 265

Quoted 10 lines
(quoted diff) +10 -0
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

Quoted 4 lines
Quoted 4 lines

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done,

since we need to keep

Quoted 6 lines

them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only

occupied by one user process.

Quoted 1 line

we only need to get the lock when adding/deleting the entry from the list,

this operation is very short.

Quoted 34 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 4 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just

like a system call.

Quoted 1 line

If we want to check multiple files (inode), we can use a batch to call this

interface one by one

Quoted 1 line

(of course, you can use multiple threads/processes), this is why I did not

use a work queue/thread

Quoted 1 line

in the kernel module to do this asynchronously, because in the user space,

we can do the same thing.

Quoted 1 line

let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

Quoted 8 lines
Quoted 6 lines
Quoted 1 line

The list be used for file check entry history status, and for supporting to

multiple user threads/processes to trigger a check/fix request parallelly.

Quoted 1 line

Why do you need history in a synchronous process. The error is received as soon as the process ends.

How do you return a file check specific error number to the trigger user process? then I use a list to save these file check entries (running/done).
The user maybe want to see the file check result again after the file check was done, this just give an chance for user to inquire the result again, but will not occupy too much memory.

There are quite a few ways, one of them being ioctl()s.
In synchronous processing, you don't need to check error values again and again. It is returned when you execute the request. Just like synchronous system calls such as read() and write() receive errors

Quoted 6 lines

Besides, in multiple threads each thread

Quoted 1 line

will have his context so you don't need to store in a global location.

Gang: I prefer to do the thing with independent design, do not depend some other data structures/mechanism, since these data structures/mechanism will be changed according kernel versions possibly. we should try to implement our functions in our module code, then export some interfaces(extern functions) to be invoked by some kernel sensitive data structures/mechanism (e.g. Kobject, ioctl, etc). Why I user a global location, at that moment, I did not aware that we can embed kobject in super block structure like ext4, now we can embed kobject in the super, the idea
is better.

But how will you code in the kernel if you don't use the kernel data structures?

Quoted 6 lines
Quoted 4 lines

Why did you need to use sysfs for this? Why couldn't you use something else for synchronous processing, say an ioctl()?

Gang: Yes, this is a way to reach user process, as you said in a RFC one year ago.
Of course, we also can use ioctl to commutation, but this will means that we have to add some code to implement a user tool.

Yes, the main reason I suggested to maintain a history in the RFC was to keep it asynchronous.

Quoted 3 lines

Anyway, I think it is not too important about if we use synchronous/asynchronous to handle a file check operation, if you like, please create a dedicated kernel thread to execute these file check entries in the list. It is OK for both ways.

It is not as complicated as you think. I will send it once I finish the code.

Signature · 1 line
Goldwyn
#30 lore raw

PATCH 5/5 Fix files when an inode is written in file_fix

Hi Goldwyn,

I have no more comments, let's discuss when your update code is finished.

Thanks
Gang

Quoted 165 lines
Quoted 1 line
Quoted 1 line
Quoted 103 lines · Gang He
Quoted 103 lines
Quoted 103 lines
Quoted 103 lines
Quoted 36 lines
Quoted 36 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 10 lines

int ocfs2_filecheck_add_inode(struct ocfs2_super *osb,
unsigned long ino)
{

(quoted diff) +1 -0
@@ -268,3 +252,28 @@ unlock:
      	ocfs2_filecheck_done_entry(osb, entry);
      	return 0;
      }
+

Review unlock: · line 265

Quoted 10 lines
(quoted diff) +10 -0
+int ocfs2_filefix_add_inode(struct ocfs2_super *osb,
+				     unsigned long ino)
+{
+	struct ocfs2_filecheck_entry *entry;
+	int ret = -ENOENT;
+
+	spin_lock(&osb->fc_lock);
+	list_for_each_entry(entry, &osb->file_check_entries, fe_list)
+		if (entry->fe_ino == ino) {
+			entry->fe_type = OCFS2_FILECHECK_TYPE_FIX;

Gang: It looks that we can not do it directly, why? because the entry

Quoted 4 lines
Quoted 4 lines

pointer can be freed by the function ocfs2_filecheck_erase_entries().

Quoted 2 lines

We can not use the same entry pointer within two user processes. The simple solution is to return -EBUSY error in case there is the same ino

number entry in the list, then the user can try again after the previous

user

Quoted 4 lines
Quoted 3 lines

process is returned.

How? is it not protected under spinlock?

Gang: please aware that this spinlock fc_lock is used to protect entry list

(adding entry/deleting entry), not protect entry itself.

Quoted 1 line

The first user process will mark the entry's status to done after the file

check operation is finished, then the function ocfs2_filecheck_erase_entries() will possibly delete this entry from the list, to free the entry memory during the second user process is referencing on this entry.

Quoted 6 lines
Quoted 5 lines
Quoted 1 line

You know, the spinlock can not protect the file check operation (too long

time IO operation).

Yes, a possible reason for separating the lists too. The entries will be deleted after a check, and the user will not be able to perform a fix on it.

Gang: we can not delete the file check entry after it's operation is done,

since we need to keep

Quoted 6 lines

them to provide the result history records.

Quoted 3 lines

In any case, if we check on status, we can do away with it. We may require filecheck_entry spinlocks later on, but for now it is not required.

Gang: Why we need a spinlock for each filecheck entry? the entry is only

occupied by one user process.

Quoted 1 line

we only need to get the lock when adding/deleting the entry from the list,

this operation is very short.

Quoted 34 lines
Quoted 34 lines
Quoted 7 lines
Quoted 6 lines

Anyways, I plan to make a separate list for this so we can do away with more macros.

Gang: you can use two lists, but I think that one list is also OK, keep the

thing simple.

Quoted 1 line

Just return a -EBUSY error when the same inode is on the progress, then the

user can try again after that file check process returns.

Thanks for the suggestions, I have incorporated that, with the two lists, of course.

Quoted 5 lines
Quoted 4 lines

Besides, any I/O and check operation should be done in a separate thread/work queue.

Gang: current design is no a separated thread is used to run file check

operation, each user trigger process is used to execute its file check operation.

Quoted 1 line

Why? first, keep the thing simple, avoid to involve more logic/thread.

second, if we involved a thread/work queue to run the file check operations,

Quoted 1 line

that means the user trigger process will return directly and need not to

wait for the actual file check operation, there will be a risk that the user can

Quoted 1 line

not see the result from the result history record (via cat check/fix), since

the new submits result will make the oldest result records to be released,

Quoted 1 line

we have a fixed length list to keep these status records. If we use the user

trigger process to do the file check operation, the user can surely see the result after this user process returns (since this file check operation is done in the kernel space).

Quoted 1 line
Quoted 4 lines
Quoted 3 lines

In the future, how do you plan to extend this? How would you check for extent_blocks? Or worse, system files? Would you keep the system waiting until all I/O has completed?

Gang: Yes, the trigger user process can wait for this I/O operation, just

like a system call.

Quoted 1 line

If we want to check multiple files (inode), we can use a batch to call this

interface one by one

Quoted 1 line

(of course, you can use multiple threads/processes), this is why I did not

use a work queue/thread

Quoted 1 line

in the kernel module to do this asynchronously, because in the user space,

we can do the same thing.

Quoted 1 line

let's keep the kernel module logic simple.

If you were planning to keep the process synchronous, why keep multiple entries. Just one would have been enough. This way the check/fix cycle would have a better probability of finding stuff in the cache as well.

Quoted 7 lines
Quoted 6 lines
Quoted 1 line

The list be used for file check entry history status, and for supporting to

multiple user threads/processes to trigger a check/fix request parallelly.

Quoted 1 line

Why do you need history in a synchronous process. The error is received as soon as the process ends.

How do you return a file check specific error number to the trigger user

process? then I use a list to save these file check entries (running/done).

Quoted 1 line

The user maybe want to see the file check result again after the file check

was done, this just give an chance for user to inquire the result again, but will not occupy too much memory.

There are quite a few ways, one of them being ioctl()s.
In synchronous processing, you don't need to check error values again and again. It is returned when you execute the request. Just like synchronous system calls such as read() and write() receive errors

Quoted 4 lines

Besides, in multiple threads each thread

Quoted 1 line

will have his context so you don't need to store in a global location.

Gang: I prefer to do the thing with independent design, do not depend some

other data structures/mechanism, since these data structures/mechanism will be changed according kernel versions possibly. we should try to implement our functions in our module code, then export some interfaces(extern functions) to be invoked by some kernel sensitive data structures/mechanism (e.g.

Quoted 1 line

Kobject, ioctl, etc). Why I user a global location, at that moment, I did

not aware that we can embed kobject in super block structure like ext4, now we can embed kobject in the super, the idea

Quoted 1 line

is better.

But how will you code in the kernel if you don't use the kernel data structures?

Quoted 5 lines
Quoted 4 lines

Why did you need to use sysfs for this? Why couldn't you use something else for synchronous processing, say an ioctl()?

Gang: Yes, this is a way to reach user process, as you said in a RFC one

year ago.

Quoted 1 line

Of course, we also can use ioctl to commutation, but this will means that we

have to add some code to implement a user tool.

Yes, the main reason I suggested to maintain a history in the RFC was to keep it asynchronous.

Quoted 2 lines

Anyway, I think it is not too important about if we use

synchronous/asynchronous to handle a file check operation, if you like, please create a dedicated kernel thread to execute these file check entries in the list. It is OK for both ways.

Quoted 1 line

It is not as complicated as you think. I will send it once I finish the code.

Signature · 1 line
Goldwyn