lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20191016125019.157144-3-namhyung@kernel.org>
Date:   Wed, 16 Oct 2019 21:50:19 +0900
From:   Namhyung Kim <namhyung@...nel.org>
To:     Tejun Heo <tj@...nel.org>, Johannes Weiner <hannes@...xchg.org>,
        Li Zefan <lizefan@...wei.com>
Cc:     LKML <linux-kernel@...r.kernel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        "Rafael J. Wysocki" <rafael@...nel.org>,
        Song Liu <liu.song.a23@...il.com>,
        Fenghua Yu <fenghua.yu@...el.com>,
        Reinette Chatre <reinette.chatre@...el.com>
Subject: [PATCH 2/2] kernfs: Allow creation with external gen + ino numbers

Extend file and directory creation API to take external generation
number and inode number.  Passing 0 as inode number will keep original
behavior.

The cgroup id will be used as inode number from now on so allocate id
for each file as well.

Cc: Fenghua Yu <fenghua.yu@...el.com>
Cc: Reinette Chatre <reinette.chatre@...el.com>
Signed-off-by: Namhyung Kim <namhyung@...nel.org>
---
 arch/x86/kernel/cpu/resctrl/rdtgroup.c |  4 +-
 fs/kernfs/dir.c                        | 63 ++++++++++++++++++++------
 fs/kernfs/file.c                       |  9 ++--
 fs/kernfs/kernfs-internal.h            |  5 ++
 fs/sysfs/file.c                        |  2 +-
 include/linux/kernfs.h                 | 25 +++++++---
 kernel/cgroup/cgroup.c                 | 12 ++++-
 7 files changed, 90 insertions(+), 30 deletions(-)

diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
index a46dee8e78db..a2fbcab3189e 100644
--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
@@ -206,7 +206,7 @@ static int rdtgroup_add_file(struct kernfs_node *parent_kn, struct rftype *rft)
 
 	kn = __kernfs_create_file(parent_kn, rft->name, rft->mode,
 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
-				  0, rft->kf_ops, rft, NULL, NULL);
+				  0, rft->kf_ops, rft, NULL, NULL, 0, 0);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
 
@@ -2294,7 +2294,7 @@ static int mon_addfile(struct kernfs_node *parent_kn, const char *name,
 
 	kn = __kernfs_create_file(parent_kn, name, 0444,
 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0,
-				  &kf_mondata_ops, priv, NULL, NULL);
+				  &kf_mondata_ops, priv, NULL, NULL, 0, 0);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
 
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 6ebae6bbe6a5..f2e54532c110 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -618,10 +618,10 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 					     struct kernfs_node *parent,
 					     const char *name, umode_t mode,
 					     kuid_t uid, kgid_t gid,
+					     u32 gen, int ino,
 					     unsigned flags)
 {
 	struct kernfs_node *kn;
-	u32 gen;
 	int cursor;
 	int ret;
 
@@ -635,11 +635,24 @@ static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
 
 	idr_preload(GFP_KERNEL);
 	spin_lock(&kernfs_idr_lock);
-	cursor = idr_get_cursor(&root->ino_idr);
-	ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
-	if (ret >= 0 && ret < cursor)
-		root->next_generation++;
-	gen = root->next_generation;
+
+	if (ino == 0) {
+		cursor = idr_get_cursor(&root->ino_idr);
+		ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
+		if (ret >= 0 && ret < cursor)
+			root->next_generation++;
+		gen = root->next_generation;
+	} else {
+		ret = idr_alloc(&root->ino_idr, kn, ino, ino + 1, GFP_ATOMIC);
+		if (ret != ino) {
+			WARN_ONCE(1, "kernfs ino was used: %d", ino);
+			ret = -EINVAL;
+		} else {
+			WARN_ON(root->next_generation > gen);
+			root->next_generation = gen;
+		}
+	}
+
 	spin_unlock(&kernfs_idr_lock);
 	idr_preload_end();
 	if (ret < 0)
@@ -696,7 +709,24 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 	struct kernfs_node *kn;
 
 	kn = __kernfs_new_node(kernfs_root(parent), parent,
-			       name, mode, uid, gid, flags);
+			       name, mode, uid, gid, 0, 0, flags);
+	if (kn) {
+		kernfs_get(parent);
+		kn->parent = parent;
+	}
+	return kn;
+}
+
+struct kernfs_node *kernfs_new_node_with_id(struct kernfs_node *parent,
+					    const char *name, umode_t mode,
+					    kuid_t uid, kgid_t gid,
+					    u32 gen, int ino,
+					    unsigned flags)
+{
+	struct kernfs_node *kn;
+
+	kn = __kernfs_new_node(kernfs_root(parent), parent,
+			       name, mode, uid, gid, gen, ino, flags);
 	if (kn) {
 		kernfs_get(parent);
 		kn->parent = parent;
@@ -965,7 +995,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 	root->next_generation = 1;
 
 	kn = __kernfs_new_node(root, NULL, "", S_IFDIR | S_IRUGO | S_IXUGO,
-			       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+			       GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, 0, 0,
 			       KERNFS_DIR);
 	if (!kn) {
 		idr_destroy(&root->ino_idr);
@@ -1000,7 +1030,7 @@ void kernfs_destroy_root(struct kernfs_root *root)
 }
 
 /**
- * kernfs_create_dir_ns - create a directory
+ * __kernfs_create_dir - create a directory
  * @parent: parent in which to create a new directory
  * @name: name of the new directory
  * @mode: mode of the new directory
@@ -1008,20 +1038,23 @@ void kernfs_destroy_root(struct kernfs_root *root)
  * @gid: gid of the new directory
  * @priv: opaque data associated with the new directory
  * @ns: optional namespace tag of the directory
+ * @gen: optional inode generation number
+ * @ino: optional inode number
  *
  * Returns the created node on success, ERR_PTR() value on failure.
  */
-struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
-					 const char *name, umode_t mode,
-					 kuid_t uid, kgid_t gid,
-					 void *priv, const void *ns)
+struct kernfs_node *__kernfs_create_dir(struct kernfs_node *parent,
+					const char *name, umode_t mode,
+					kuid_t uid, kgid_t gid,
+					void *priv, const void *ns,
+					u32 gen, int ino)
 {
 	struct kernfs_node *kn;
 	int rc;
 
 	/* allocate */
-	kn = kernfs_new_node(parent, name, mode | S_IFDIR,
-			     uid, gid, KERNFS_DIR);
+	kn = kernfs_new_node_with_id(parent, name, mode | S_IFDIR,
+				     uid, gid, gen, ino, KERNFS_DIR);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c
index e8c792b49616..8280b750b733 100644
--- a/fs/kernfs/file.c
+++ b/fs/kernfs/file.c
@@ -981,6 +981,8 @@ const struct file_operations kernfs_file_fops = {
  * @priv: private data for the file
  * @ns: optional namespace tag of the file
  * @key: lockdep key for the file's active_ref, %NULL to disable lockdep
+ * @gen: optional inode generation number
+ * @ino: optional inode number
  *
  * Returns the created node on success, ERR_PTR() value on error.
  */
@@ -990,7 +992,8 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 					 loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
-					 struct lock_class_key *key)
+					 struct lock_class_key *key,
+					 u32 gen, int ino)
 {
 	struct kernfs_node *kn;
 	unsigned flags;
@@ -998,8 +1001,8 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 
 	flags = KERNFS_FILE;
 
-	kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG,
-			     uid, gid, flags);
+	kn = kernfs_new_node_with_id(parent, name, (mode & S_IALLUGO) | S_IFREG,
+				     uid, gid, gen, ino, flags);
 	if (!kn)
 		return ERR_PTR(-ENOMEM);
 
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 02ce570a9a3c..42c787720a1f 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -109,6 +109,11 @@ struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
 				    const char *name, umode_t mode,
 				    kuid_t uid, kgid_t gid,
 				    unsigned flags);
+struct kernfs_node *kernfs_new_node_with_id(struct kernfs_node *parent,
+					    const char *name, umode_t mode,
+					    kuid_t uid, kgid_t gid,
+					    u32 gen, int ino,
+					    unsigned flags);
 struct kernfs_node *kernfs_find_and_get_node_by_ino(struct kernfs_root *root,
 						    unsigned int ino);
 
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 130fc6fbcc03..a21aa1aa2106 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -303,7 +303,7 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent,
 #endif
 
 	kn = __kernfs_create_file(parent, attr->name, mode & 0777, uid, gid,
-				  size, ops, (void *)attr, ns, key);
+				  size, ops, (void *)attr, ns, key, 0, 0);
 	if (IS_ERR(kn)) {
 		if (PTR_ERR(kn) == -EEXIST)
 			sysfs_warn_dup(parent, attr->name);
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 936b61bd504e..3764a870a279 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -340,10 +340,11 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
 				       unsigned int flags, void *priv);
 void kernfs_destroy_root(struct kernfs_root *root);
 
-struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
+struct kernfs_node *__kernfs_create_dir(struct kernfs_node *parent,
 					 const char *name, umode_t mode,
 					 kuid_t uid, kgid_t gid,
-					 void *priv, const void *ns);
+					 void *priv, const void *ns,
+					 u32 gen, int ino);
 struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
 					    const char *name);
 struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
@@ -352,7 +353,8 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent,
 					 loff_t size,
 					 const struct kernfs_ops *ops,
 					 void *priv, const void *ns,
-					 struct lock_class_key *key);
+					 struct lock_class_key *key,
+					 u32 gen, int ino);
 struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
 				       const char *name,
 				       struct kernfs_node *target);
@@ -438,16 +440,17 @@ kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags,
 static inline void kernfs_destroy_root(struct kernfs_root *root) { }
 
 static inline struct kernfs_node *
-kernfs_create_dir_ns(struct kernfs_node *parent, const char *name,
+__kernfs_create_dir(struct kernfs_node *parent, const char *name,
 		     umode_t mode, kuid_t uid, kgid_t gid,
-		     void *priv, const void *ns)
+		     void *priv, const void *ns, u32 gen, int ino)
 { return ERR_PTR(-ENOSYS); }
 
 static inline struct kernfs_node *
 __kernfs_create_file(struct kernfs_node *parent, const char *name,
 		     umode_t mode, kuid_t uid, kgid_t gid,
 		     loff_t size, const struct kernfs_ops *ops,
-		     void *priv, const void *ns, struct lock_class_key *key)
+		     void *priv, const void *ns, struct lock_class_key *key,
+		     u32 gen, int ino)
 { return ERR_PTR(-ENOSYS); }
 
 static inline struct kernfs_node *
@@ -528,6 +531,14 @@ kernfs_walk_and_get(struct kernfs_node *kn, const char *path)
 	return kernfs_walk_and_get_ns(kn, path, NULL);
 }
 
+static inline struct kernfs_node *
+kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, umode_t mode,
+		     kuid_t uid, kgid_t gid, void *priv, const void *ns)
+{
+	return __kernfs_create_dir(parent, name, mode,
+				   uid, gid, priv, ns, 0, 0);
+}
+
 static inline struct kernfs_node *
 kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode,
 		  void *priv)
@@ -549,7 +560,7 @@ kernfs_create_file_ns(struct kernfs_node *parent, const char *name,
 	key = (struct lock_class_key *)&ops->lockdep_key;
 #endif
 	return __kernfs_create_file(parent, name, mode, uid, gid,
-				    size, ops, priv, ns, key);
+				    size, ops, priv, ns, key, 0, 0);
 }
 
 static inline struct kernfs_node *
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 44c67d26c1fe..13d0d181a9f8 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3916,16 +3916,22 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
 	char name[CGROUP_FILE_NAME_MAX];
 	struct kernfs_node *kn;
 	struct lock_class_key *key = NULL;
+	struct cgroup_root *root = cgrp->root;
+	int ino, gen;
 	int ret;
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 	key = &cft->lockdep_key;
 #endif
+
+	ino = cgroup_idr_alloc(&root->cgroup_idr, NULL, false, GFP_KERNEL);
+	gen = root->cgroup_idr.generation;
+
 	kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
 				  cgroup_file_mode(cft),
 				  GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
 				  0, cft->kf_ops, cft,
-				  NULL, key);
+				  NULL, key, gen, ino);
 	if (IS_ERR(kn))
 		return PTR_ERR(kn);
 
@@ -5426,7 +5432,9 @@ int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name, umode_t mode)
 	}
 
 	/* create the directory */
-	kn = kernfs_create_dir(parent->kn, name, mode, cgrp);
+	kn = __kernfs_create_dir(parent->kn, name, mode,
+				 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+				 cgrp, NULL, cgrp->gen, cgrp->id);
 	if (IS_ERR(kn)) {
 		ret = PTR_ERR(kn);
 		goto out_destroy;
-- 
2.23.0.700.g56cf767bdb-goog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ