[RFC PATCH 05/14] driver core: add struct device_sysfs_entry and walker

Pavol Sakac <[email protected]>
Newsgroups org.infradead.lists.kexec,dev.linux.lists.driver-core,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <[email protected]>
Introduce the primitive for declaring per-device sysfs content as
table rows and a single walker that dispatches across eager,
lazy-populate, and teardown paths.

struct device_sysfs_entry { name, applies_to, create, remove }

  - name == NULL: wildcard row (create() does internal name
    dispatch; used for attribute_group-source rows).
  - applies_to: NULL or a pure, cheap, non-sleeping predicate.
  - create: implements ADD_ONE (name != NULL) and ADD_ALL
    (name == NULL) semantics; absorbs -EEXIST from concurrent
    racers to 0.
  - remove: reverse-order teardown.

device_sysfs_apply(dev, entries, action, name) dispatches
DEV_SYSFS_ADD_ONE / DEV_SYSFS_ADD_ALL / DEV_SYSFS_REMOVE_ALL across
the table. -ENOENT from a wildcard row's create() is treated as
"not my name" and the walker continues; any other error propagates
to the caller on ADD_ONE and is absorbed on ADD_ALL (best-effort).
REMOVE_ALL reverses the table and never aborts. The full contract
is documented in Documentation/driver-api/sysfs-lazy.rst (added
later in this series).

Shape follows cftype + cgroup_addrm_files (kernel/cgroup/cgroup.c)
as the in-tree precedent for table-driven attribute creation.
struct kobj_type grows a trailing .entries pointer; ktypes opt in
by setting it and wiring their populate / populate_all callbacks
to the walker. The field is at end of struct for source-
compatibility with positional initialisers of out-of-tree ktypes.

sysfs_add_file_mode_ns() and sysfs_add_bin_file_mode_ns() are
exported (kerneldoc added) so the walker can absorb -EEXIST from
concurrent create racers without going through sysfs_warn_dup().

Two static helpers - create_attr_in_groups() and
create_all_in_groups() - are added for use by attribute-group
source rows that the migration commit later wires up; they search
@groups by @name and walk every visible attribute respectively.

Cc: Greg Kroah-Hartman <[email protected]>
Cc: Rafael J. Wysocki <[email protected]>
Cc: Tejun Heo <[email protected]>
Cc: Jonathan Corbet <[email protected]>
Cc: Bjorn Helgaas <[email protected]>
Cc: Danilo Krummrich <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Assisted-by: Claude:claude-opus-4.7
Signed-off-by: Pavol Sakac <[email protected]>
---
 drivers/base/core.c     | 319 ++++++++++++++++++++++++++++++++++++++++
 fs/sysfs/file.c         |  41 +++++-
 fs/sysfs/sysfs.h        |   6 -
 include/linux/device.h  |  56 +++++++
 include/linux/kobject.h |   5 +
 include/linux/sysfs.h   |  24 +++
 6 files changed, 443 insertions(+), 8 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index 6d0d917d4b1ff..aeb4985eb8838 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2574,6 +2574,325 @@ static void device_release(struct kobject *kobj)
 	kfree(p);
 }
 
+/*
+ * device_sysfs_apply() - declarative per-device sysfs dispatch
+ *
+ * Single walker over a sentinel-terminated struct device_sysfs_entry
+ * table. Intended to be invoked on every dispatch path (device_add
+ * eager, lazy populate_one, lazy populate_all, device_del teardown)
+ * so adding a new per-device file is one row, not four open-coded
+ * branches. Shape follows cftype + cgroup_addrm_files
+ * (kernel/cgroup/cgroup.c) and pci_sysfs_entries[]
+ * (drivers/pci/pci-sysfs.c).
+ *
+ * ADD_ONE:  first row whose applies_to passes and whose name matches
+ *	     (or a wildcard row whose create() does not return
+ *	     -ENOENT) terminates the walk. -ENOENT from a wildcard
+ *	     row's create() signals "not my name"; the walker
+ *	     continues. Realize callbacks MUST check existence (via
+ *	     sysfs_*_exists()) before calling sysfs_create_*() and
+ *	     return 0 if the entry already exists. Reaching
+ *	     __kernfs_create_*() for a name that another lazy path
+ *	     just created is forbidden under lock
+ *	     serialization. If sysfs_warn_dup() ever fires from a
+ *	     lazy path, it indicates a lock invariant
+ *	     violation or a non-lazy path creating lazy attrs (bug).
+ * ADD_ALL:  every applicable row's create() fires with name = NULL;
+ *	     per-row errors are best-effort - the walker discards
+ *	     return values and rows log via their own diagnostics.
+ * REMOVE_ALL: reverse row order; remove() fires for every row whose
+ *	     applies_to passes. Teardown never aborts.
+ *
+ * The full walker contract (error-absorption matrix, interaction
+ * with negative-dentry caching, lifecycle caveats) is documented in
+ * Documentation/driver-api/sysfs-lazy.rst, added later in this
+ * series.
+ */
+/*
+ * Create one named attr inside @grp; honours grp->is_visible.
+ * Returns 0 on success/hidden/already-present, -ENOENT on no-match.
+ */
+static int create_attr_in_group(struct device *dev,
+				 const struct attribute_group *grp,
+				 const char *name)
+{
+	struct attribute **a;
+	const struct bin_attribute *const *ba;
+	kuid_t uid;
+	kgid_t gid;
+	umode_t mode;
+	int i;
+
+	if (device_is_sysfs_lazy(dev))
+		lockdep_assert_held(&dev->sysfs_lazy->lock);
+
+	kobject_get_ownership(&dev->kobj, &uid, &gid);
+
+	if (grp->name) {
+		if (!strcmp(grp->name, name)) {
+			if (sysfs_group_exists(&dev->kobj, grp))
+				return 0;
+			return sysfs_create_group(&dev->kobj, grp);
+		}
+		return -ENOENT;
+	}
+
+	if (grp->attrs) {
+		for (i = 0, a = grp->attrs; *a; i++, a++) {
+			if (strcmp((*a)->name, name))
+				continue;
+
+			mode = (*a)->mode;
+			if (grp->is_visible || grp->is_visible_const) {
+				if (grp->is_visible)
+					mode = grp->is_visible(&dev->kobj, *a, i);
+				else
+					mode = grp->is_visible_const(&dev->kobj, *a, i);
+				mode &= ~SYSFS_GROUP_INVISIBLE;
+				if (!mode)
+					return 0;	/* hidden */
+			}
+			mode &= SYSFS_PREALLOC | 0664;
+
+			if (sysfs_kn_exists(&dev->kobj, (*a)->name))
+				return 0;
+
+			return sysfs_add_file_mode_ns(dev->kobj.sd, *a,
+						      mode, uid, gid, NULL);
+		}
+	}
+	if (grp->bin_attrs) {
+		for (i = 0, ba = grp->bin_attrs; *ba; i++, ba++) {
+			if (strcmp((*ba)->attr.name, name))
+				continue;
+			mode = (*ba)->attr.mode;
+			if (grp->is_bin_visible) {
+				mode = grp->is_bin_visible(&dev->kobj, *ba, i);
+				mode &= ~SYSFS_GROUP_INVISIBLE;
+				if (!mode)
+					return 0;
+			}
+			mode &= SYSFS_PREALLOC | 0664;
+
+			if (sysfs_kn_exists(&dev->kobj, (*ba)->attr.name))
+				return 0;
+
+			return sysfs_add_bin_file_mode_ns(dev->kobj.sd,
+							  *ba, mode,
+							  (*ba)->size,
+							  uid, gid, NULL);
+		}
+	}
+	return -ENOENT;
+}
+
+/*
+ * Per-group incremental creation. Tolerates partial state from
+ * concurrent populate_one. Best-effort: absorbs per-attr failures.
+ */
+static int create_group_incremental(struct device *dev,
+				     const struct attribute_group *grp)
+{
+	struct attribute **a;
+	const struct bin_attribute *const *ba;
+	int ret;
+
+	if (device_is_sysfs_lazy(dev))
+		lockdep_assert_held(&dev->sysfs_lazy->lock);
+
+	if (grp->name) {
+		struct kernfs_node *subdir;
+		kuid_t uid;
+		kgid_t gid;
+		umode_t mode;
+		int i;
+
+		subdir = kernfs_find_and_get(dev->kobj.sd, grp->name);
+		if (!subdir)
+			return sysfs_create_group(&dev->kobj, grp);
+
+		kobject_get_ownership(&dev->kobj, &uid, &gid);
+
+		if (grp->attrs) {
+			for (i = 0, a = grp->attrs; *a; i++, a++) {
+				struct kernfs_node *kn;
+
+				mode = (*a)->mode;
+				if (grp->is_visible || grp->is_visible_const) {
+					if (grp->is_visible)
+						mode = grp->is_visible(&dev->kobj,
+								       *a, i);
+					else
+						mode = grp->is_visible_const(&dev->kobj,
+									     *a, i);
+					mode &= ~SYSFS_GROUP_INVISIBLE;
+					if (!mode)
+						continue;
+				}
+				mode &= SYSFS_PREALLOC | 0664;
+
+				/* Existence check inside named @subdir (not a kobject). */
+				kn = kernfs_find_and_get(subdir, (*a)->name);
+				if (kn) {
+					kernfs_put(kn);
+					continue;
+				}
+
+				ret = sysfs_add_file_mode_ns(subdir, *a,
+							     mode, uid,
+							     gid, NULL);
+				if (ret)
+					dev_dbg(dev,
+						"lazy %s/%s: %d\n",
+						grp->name, (*a)->name, ret);
+			}
+		}
+		if (grp->bin_attrs) {
+			for (i = 0, ba = grp->bin_attrs; *ba; i++, ba++) {
+				struct kernfs_node *kn;
+
+				mode = (*ba)->attr.mode;
+				if (grp->is_bin_visible) {
+					mode = grp->is_bin_visible(&dev->kobj,
+								   *ba, i);
+					mode &= ~SYSFS_GROUP_INVISIBLE;
+					if (!mode)
+						continue;
+				}
+				mode &= SYSFS_PREALLOC | 0664;
+
+				kn = kernfs_find_and_get(subdir, (*ba)->attr.name);
+				if (kn) {
+					kernfs_put(kn);
+					continue;
+				}
+
+				ret = sysfs_add_bin_file_mode_ns(subdir,
+								 *ba,
+								 mode,
+								 (*ba)->size,
+								 uid,
+								 gid,
+								 NULL);
+				if (ret)
+					dev_dbg(dev,
+						"lazy %s/%s: %d\n",
+						grp->name,
+						(*ba)->attr.name, ret);
+			}
+		}
+
+		kernfs_put(subdir);
+		return 0;
+	}
+
+	if (grp->attrs) {
+		for (a = grp->attrs; *a; a++)
+			(void)create_attr_in_group(dev, grp, (*a)->name);
+	}
+	if (grp->bin_attrs) {
+		for (ba = grp->bin_attrs; *ba; ba++)
+			(void)create_attr_in_group(dev, grp,
+						    (*ba)->attr.name);
+	}
+	return 0;
+}
+
+/* Search @groups for @name. -ENOENT = not in this source. */
+static int __maybe_unused create_attr_in_groups(struct device *dev,
+				  const struct attribute_group *const *groups,
+				  const char *name)
+{
+	const struct attribute_group *const *g;
+	int ret;
+
+	if (!groups)
+		return -ENOENT;
+
+	for (g = groups; *g; g++) {
+		ret = create_attr_in_group(dev, *g, name);
+		if (ret != -ENOENT)
+			return ret;
+	}
+	return -ENOENT;
+}
+
+/* Walk @groups creating every visible attribute. Best-effort. */
+static int __maybe_unused create_all_in_groups(struct device *dev,
+				 const struct attribute_group *const *groups)
+{
+	const struct attribute_group *const *g;
+
+	if (!groups)
+		return 0;
+
+	for (g = groups; *g; g++)
+		(void)create_group_incremental(dev, *g);
+	return 0;
+}
+
+static const struct device_sysfs_entry *
+device_sysfs_entries_end(const struct device_sysfs_entry *entries)
+{
+	const struct device_sysfs_entry *e = entries;
+
+	while (e->create)
+		e++;
+	return e;
+}
+
+static __maybe_unused int
+device_sysfs_apply(struct device *dev,
+		  const struct device_sysfs_entry *entries,
+		  enum dev_sysfs_action action, const char *name)
+{
+	const struct device_sysfs_entry *e;
+
+	if (!entries)
+		return action == DEV_SYSFS_ADD_ONE ? -ENOENT : 0;
+
+	if (action == DEV_SYSFS_REMOVE_ALL) {
+		for (e = device_sysfs_entries_end(entries) - 1;
+		     e >= entries; e--) {
+			if (e->applies_to && !e->applies_to(dev))
+				continue;
+			if (e->remove)
+				e->remove(dev);
+		}
+		return 0;
+	}
+
+	for (e = entries; e->create; e++) {
+		int ret;
+
+		if (e->applies_to && !e->applies_to(dev))
+			continue;
+		if (action == DEV_SYSFS_ADD_ONE && e->name &&
+		    strcmp(e->name, name))
+			continue;
+
+		ret = e->create(dev, action == DEV_SYSFS_ADD_ONE
+					      ? name : NULL);
+		if (action == DEV_SYSFS_ADD_ONE) {
+			/*
+			 * A named row is the authoritative handler for its
+			 * name: return its result even on -ENOENT. A wildcard
+			 * row (e->name == NULL) may decline with -ENOENT, so
+			 * keep scanning for another handler in that case.
+			 */
+			if (e->name || ret != -ENOENT)
+				return ret;
+		}
+		/*
+		 * FIXME: ADD_ALL is best-effort and never returns the first create() failure to
+		 * the caller, so device_ktype_populate_all() latches populated=true after a
+		 * transient failure - the missing attribute is negative-cached forever (a later
+		 * lookup returns -ENOENT and never retries), contradicting the sysfs-lazy ABI.
+		 */
+	}
+	return action == DEV_SYSFS_ADD_ONE ? -ENOENT : 0;
+}
+
 static const struct ns_common *device_namespace(const struct kobject *kobj)
 {
 	const struct device *dev = kobj_to_dev(kobj);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 5f3144e52ab72..8d0b8c2c2ee4d 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -270,6 +270,25 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = {
 	.llseek		= sysfs_kf_bin_llseek,
 };
 
+/**
+ * sysfs_add_file_mode_ns - create a sysfs attribute file under @parent
+ * @parent: kernfs node for the parent directory (typically @kobj->sd)
+ * @attr:   attribute descriptor; @attr->name is the file name
+ * @mode:   file mode (low bits) optionally OR'd with %SYSFS_PREALLOC
+ * @uid: file owner UID
+ * @gid: file owner GID
+ * @ns:  namespace tag (may be %NULL)
+ *
+ * Picks a kernfs_ops dispatch row from (prealloc?, has show, has store)
+ * routing read()/write() through @parent->priv->ktype->sysfs_ops.
+ *
+ * Return: 0 on success, or -errno. -EEXIST means the name already
+ * exists and is treated as a caller error (it triggers sysfs_warn_dup()).
+ * The lazy populate path must not reach this: it checks sysfs_kn_exists()/
+ * sysfs_group_exists() under the populate lock before creating, so a
+ * concurrent ADD_ONE/ADD_ALL race resolves to a no-op rather than a
+ * duplicate create.
+ */
 int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 		const struct attribute *attr, umode_t mode, kuid_t uid,
 		kgid_t gid, const struct ns_common *ns)
@@ -320,6 +339,26 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 	return 0;
 }
 
+/**
+ * sysfs_add_bin_file_mode_ns - create a sysfs binary-attribute file
+ * @parent: kernfs node for the parent directory
+ * @battr:  binary attribute descriptor
+ * @mode:   file mode (low bits)
+ * @size:   in-core size of the binary attribute (passed to __kernfs_create_file())
+ * @uid: file owner UID
+ * @gid: file owner GID
+ * @ns:  namespace tag (may be %NULL)
+ *
+ * Picks a kernfs_ops dispatch row from a 5-row matrix on @battr's
+ * callbacks (mmap > rw > read > write > empty).
+ *
+ * Return: 0 on success, or -errno. -EEXIST means the name already
+ * exists and is treated as a caller error (it triggers sysfs_warn_dup()).
+ * The lazy populate path must not reach this: it checks sysfs_kn_exists()/
+ * sysfs_group_exists() under the populate lock before creating, so a
+ * concurrent ADD_ONE/ADD_ALL race resolves to a no-op rather than a
+ * duplicate create.
+ */
 int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
 		const struct bin_attribute *battr, umode_t mode, size_t size,
 		kuid_t uid, kgid_t gid, const struct ns_common *ns)
@@ -816,5 +855,3 @@ ssize_t sysfs_bin_attr_simple_read(struct file *file, struct kobject *kobj,
 	return count;
 }
 EXPORT_SYMBOL_GPL(sysfs_bin_attr_simple_read);
-
-
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index f4583dcafcd1e..94b8aca20bffc 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -27,12 +27,6 @@ void sysfs_warn_dup(struct kernfs_node *parent, const char *name);
 /*
  * file.c
  */
-int sysfs_add_file_mode_ns(struct kernfs_node *parent,
-		const struct attribute *attr, umode_t amode, kuid_t uid,
-		kgid_t gid, const struct ns_common *ns);
-int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
-		const struct bin_attribute *battr, umode_t mode, size_t size,
-		kuid_t uid, kgid_t gid, const struct ns_common *ns);
 
 /*
  * symlink.c
diff --git a/include/linux/device.h b/include/linux/device.h
index 39e08e8c950c6..e5485bfbc6c84 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -88,6 +88,62 @@ int subsys_system_register(const struct bus_type *subsys,
 int subsys_virtual_register(const struct bus_type *subsys,
 			    const struct attribute_group **groups);
 
+/**
+ * enum dev_sysfs_action - verb selector for device_sysfs_apply()
+ * @DEV_SYSFS_ADD_ONE: realize a single named entry (lazy populate_one
+ *		       miss path); walker stops at the first row whose
+ *		       @applies_to passes and whose create() returns
+ *		       anything other than -ENOENT.
+ * @DEV_SYSFS_ADD_ALL: realize every applicable entry (eager device_add
+ *		       or lazy populate_all); best-effort, per-row errors
+ *		       do not abort the walk.
+ * @DEV_SYSFS_REMOVE_ALL: tear down every applicable entry in reverse
+ *		       row order (device_del teardown).
+ */
+enum dev_sysfs_action {
+	DEV_SYSFS_ADD_ONE,
+	DEV_SYSFS_ADD_ALL,
+	DEV_SYSFS_REMOVE_ALL,
+};
+
+/**
+ * struct device_sysfs_entry - declarative per-device sysfs content row
+ * @name:	Attribute or symlink name at the top level of the device's
+ *		sysfs directory, or %NULL for a wildcard row whose
+ *		create() performs internal name dispatch (typically a
+ *		group-source row iterating an attribute_group array).
+ * @applies_to: Optional predicate gating row eligibility for this
+ *		device. Must be cheap, non-sleeping, side-effect-free, and
+ *		monotonic for a given device state. MUST NOT acquire any
+ *		lock the walker's caller may already hold (notably
+ *		device_lock()). %NULL means unconditional.
+ * @create:	Required. Creates the row's sysfs content. For a named
+ *		row (@name != NULL) the @name argument equals @e->name on
+ *		ADD_ONE and %NULL on ADD_ALL. For a wildcard row the @name
+ *		argument is the ADD_ONE target (or %NULL on ADD_ALL) and
+ *		the row's create() matches internally, returning -ENOENT
+ *		to signal "not my name" so the walker continues. Must
+ *		convert -EEXIST from concurrent racers to 0.
+ * @remove:	Optional reverse-of-realize teardown. Called on
+ *		REMOVE_ALL in reverse row order. MUST NOT fail the walk.
+ *
+ * Rows are declared in file-static, sentinel-terminated tables whose
+ * base pointer is published to the walker via struct kobj_type.entries
+ * (device ktype shares a single driver_core table and dispatches to
+ * dev->type->entries as well). The row shape mirrors cftype +
+ * cgroup_addrm_files (kernel/cgroup/cgroup.c) and the
+ * pci_sysfs_entries[] at drivers/pci/pci-sysfs.c (added later in
+ * the series); see Documentation/driver-api/sysfs-lazy.rst (also
+ * added later in the series) for the full walker contract and
+ * error-handling matrix.
+ */
+struct device_sysfs_entry {
+	const char *name;
+	bool (*applies_to)(struct device *dev);
+	int  (*create)(struct device *dev, const char *name);
+	void (*remove)(struct device *dev);
+};
+
 /*
  * The type of device, "struct device" is embedded in. A class
  * or bus can contain devices of different types
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index cec6de1720076..c724d86e1a049 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -61,6 +61,8 @@ enum kobject_action {
 	KOBJ_UNBIND,
 };
 
+struct device_sysfs_entry;
+
 struct kobject {
 	const char		*name;
 	struct list_head	entry;
@@ -130,6 +132,9 @@ struct kobj_type {
 	 */
 	int (*populate)(struct kobject *kobj, const char *name);
 	void (*populate_all)(struct kobject *kobj);
+
+	/* Optional table of per-attribute entries (see device_sysfs_apply()). */
+	const struct device_sysfs_entry *entries;
 };
 
 struct kobj_uevent_env {
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index de211563f3dec..aac2f773d5378 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -415,6 +415,12 @@ int __must_check sysfs_create_files(struct kobject *kobj,
 				   const struct attribute * const *attr);
 int __must_check sysfs_chmod_file(struct kobject *kobj,
 				  const struct attribute *attr, umode_t mode);
+int __must_check sysfs_add_file_mode_ns(struct kernfs_node *parent,
+		const struct attribute *attr, umode_t amode, kuid_t uid,
+		kgid_t gid, const struct ns_common *ns);
+int __must_check sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
+		const struct bin_attribute *battr, umode_t mode, size_t size,
+		kuid_t uid, kgid_t gid, const struct ns_common *ns);
 struct kernfs_node *sysfs_break_active_protection(struct kobject *kobj,
 						  const struct attribute *attr);
 void sysfs_unbreak_active_protection(struct kernfs_node *kn);
@@ -558,6 +564,24 @@ static inline int sysfs_chmod_file(struct kobject *kobj,
 	return 0;
 }
 
+static inline int sysfs_add_file_mode_ns(struct kernfs_node *parent,
+					 const struct attribute *attr,
+					 umode_t amode, kuid_t uid,
+					 kgid_t gid,
+					 const struct ns_common *ns)
+{
+	return 0;
+}
+
+static inline int sysfs_add_bin_file_mode_ns(struct kernfs_node *parent,
+					     const struct bin_attribute *battr,
+					     umode_t mode, size_t size,
+					     kuid_t uid, kgid_t gid,
+					     const struct ns_common *ns)
+{
+	return 0;
+}
+
 static inline struct kernfs_node *
 sysfs_break_active_protection(struct kobject *kobj,
 			      const struct attribute *attr)
-- 
2.47.3




Amazon Web Services Development Center Germany GmbH
Tamara-Danz-Str. 13
10243 Berlin
Geschaeftsfuehrung: Christof Hellmis, Andreas Stieger
Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B
Sitz: Berlin
Ust-ID: DE 365 538 597
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.