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 <[email protected]>
Cc: Reinette Chatre <[email protected]>
Signed-off-by: Namhyung Kim <[email protected]>
---
 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

Reply via email to