Messages in this thread Patch in this message | | | From | Namhyung Kim <> | Subject | [PATCH 2/2] kernfs: Allow creation with external gen + ino numbers | Date | Wed, 16 Oct 2019 21:50:19 +0900 |
| |
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@intel.com> Cc: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Namhyung Kim <namhyung@kernel.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
| |