From b8441ed279bff09a0a5ddeacf8f4087d2fb424ca Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 24 Nov 2013 09:54:58 -0500 Subject: sysfs, kernfs: add skeletons for kernfs Core sysfs implementation will be separated into kernfs so that it can be used by other non-kobject users. This patch creates fs/kernfs/ directory and makes boilerplate changes. kernfs interface will be directly based on sysfs_dirent and its forward declaration is moved to include/linux/kernfs.h which is included from include/linux/sysfs.h. sysfs core implementation will be gradually separated out and moved to kernfs. This patch doesn't introduce any functional changes. v2: mount.c added. Signed-off-by: Tejun Heo Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 include/linux/kernfs.h (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h new file mode 100644 index 000000000000..254b9e872b09 --- /dev/null +++ b/include/linux/kernfs.h @@ -0,0 +1,12 @@ +/* + * kernfs.h - pseudo filesystem decoupled from vfs locking + * + * This file is released under the GPLv2. + */ + +#ifndef __LINUX_KERNFS_H +#define __LINUX_KERNFS_H + +struct sysfs_dirent; + +#endif /* __LINUX_KERNFS_H */ -- cgit v1.2.2 From 879f40d193bb3c6c13930e88e3e9d5d7baf84d19 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:49 -0500 Subject: sysfs, kernfs: introduce kernfs_remove[_by_name[_ns]]() Introduce kernfs removal interfaces - kernfs_remove() and kernfs_remove_by_name[_ns](). These are just renames of sysfs_remove() and sysfs_hash_and_remove(). No functional changes. v2: Dummy kernfs_remove_by_name_ns() for !CONFIG_SYSFS updated to return -ENOSYS instead of 0. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 254b9e872b09..83e151ad0619 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -7,6 +7,30 @@ #ifndef __LINUX_KERNFS_H #define __LINUX_KERNFS_H +#include + struct sysfs_dirent; +#ifdef CONFIG_SYSFS + +void kernfs_remove(struct sysfs_dirent *sd); +int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, + const void *ns); + +#else /* CONFIG_SYSFS */ + +static inline void kernfs_remove(struct sysfs_dirent *sd) { } + +static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, + const char *name, const void *ns) +{ return -ENOSYS; } + +#endif /* CONFIG_SYSFS */ + +static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, + const char *name) +{ + return kernfs_remove_by_name_ns(parent, name, NULL); +} + #endif /* __LINUX_KERNFS_H */ -- cgit v1.2.2 From 5d0e26bb59a680a5d97db5b6629941603e8de229 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:50 -0500 Subject: sysfs, kernfs: introduce kernfs_create_link() Separate out kernfs symlink interface - kernfs_create_link() - which takes and returns sysfs_dirents, from sysfs_do_create_link_sd(). sysfs_do_create_link_sd() now just determines the parent and target sysfs_dirents and invokes the new interface and handles dup warning. This patch doesn't introduce behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 83e151ad0619..fe6290d41776 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -8,17 +8,26 @@ #define __LINUX_KERNFS_H #include +#include struct sysfs_dirent; #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, + const char *name, + struct sysfs_dirent *target); void kernfs_remove(struct sysfs_dirent *sd); int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_link(struct sysfs_dirent *parent, const char *name, + struct sysfs_dirent *target) +{ return ERR_PTR(-ENOSYS); } + static inline void kernfs_remove(struct sysfs_dirent *sd) { } static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, -- cgit v1.2.2 From 890ece160c6465b49c42975d529c3481d89da8f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:51 -0500 Subject: sysfs, kernfs: introduce kernfs_rename[_ns]() Introduce kernfs rename interface, krenfs_rename[_ns](). This is just rename of sysfs_rename(). No functional changes. Function comment is added to kernfs_rename_ns() and @new_parent_sd is renamed to @new_parent for consistency with other kernfs interfaces. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fe6290d41776..803d9600cf72 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -20,6 +20,8 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, void kernfs_remove(struct sysfs_dirent *sd); int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); +int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, + const char *new_name, const void *new_ns); #else /* CONFIG_SYSFS */ @@ -34,6 +36,11 @@ static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns) { return -ENOSYS; } +static inline int kernfs_rename_ns(struct sysfs_dirent *sd, + struct sysfs_dirent *new_parent, + const char *new_name, const void *new_ns) +{ return -ENOSYS; } + #endif /* CONFIG_SYSFS */ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, -- cgit v1.2.2 From 5d60418e54751c856f5aecc308620fde9572e481 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:52 -0500 Subject: sysfs, kernfs: introduce kernfs_setattr() Introduce kernfs setattr interface - kernfs_setattr(). sysfs_sd_setattr() is renamed to __kernfs_setattr() and kernfs_setattr() is a simple wrapper around it with sysfs_mutex locking. sysfs_chmod_file() is updated to get an explicit ref on kobj->sd and then invoke kernfs_setattr() so that it doesn't have to use internal interface. This patch doesn't introduce any behavior differences. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 803d9600cf72..8cb673875715 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -10,6 +10,9 @@ #include #include +struct file; +struct iattr; + struct sysfs_dirent; #ifdef CONFIG_SYSFS @@ -22,6 +25,7 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); +int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); #else /* CONFIG_SYSFS */ @@ -41,6 +45,10 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } +static inline int kernfs_setattr(struct sysfs_dirent *sd, + const struct iattr *iattr) +{ return -ENOSYS; } + #endif /* CONFIG_SYSFS */ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, -- cgit v1.2.2 From 93b2b8e4aa4317e3fe6414d117deb5f3c362e8bb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:15 -0500 Subject: sysfs, kernfs: introduce kernfs_create_dir[_ns]() Introduce kernfs interface to manipulate a directory which takes and returns sysfs_dirents. create_dir() is renamed to kernfs_create_dir_ns() and its argumantes and return value are updated. create_dir() usages are replaced with kernfs_create_dir_ns() and sysfs_create_subdir() usages are replaced with kernfs_create_dir(). Dup warnings are handled explicitly by sysfs users of the kernfs interface. sysfs_enable_ns() is renamed to kernfs_enable_ns(). This patch doesn't introduce any behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. v3: kernfs_enable_ns() added. v4: Refreshed on top of "sysfs: drop kobj_ns_type handling, take #2" so that this patch removes sysfs_enable_ns(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 8cb673875715..e8b73d4a08d2 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -17,6 +17,9 @@ struct sysfs_dirent; #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, + const char *name, void *priv, + const void *ns); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -25,10 +28,16 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); +void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, + const void *ns) +{ return ERR_PTR(-ENOSYS); } + static inline struct sysfs_dirent * kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target) @@ -45,12 +54,20 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } + static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } #endif /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) +{ + return kernfs_create_dir_ns(parent, name, priv, NULL); +} + static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, const char *name) { -- cgit v1.2.2 From dd8a5b036b6e8d50854e130555f90f062c5eacec Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:20 -0500 Subject: sysfs, kernfs: move sysfs_open_file to include/linux/kernfs.h sysfs_open_file will be used as the primary handle for kernfs methods. Move its definition from fs/sysfs/file.c to include/linux/kernfs.h and mark the public and private fields. This is pure relocation. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e8b73d4a08d2..b923052c29d0 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -9,12 +9,30 @@ #include #include +#include +#include struct file; struct iattr; +struct seq_file; +struct vm_area_struct; struct sysfs_dirent; +struct sysfs_open_file { + /* published fields */ + struct sysfs_dirent *sd; + struct file *file; + + /* private fields, do not use outside kernfs proper */ + struct mutex mutex; + int event; + struct list_head list; + + bool mmapped; + const struct vm_operations_struct *vm_ops; +}; + #ifdef CONFIG_SYSFS struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, -- cgit v1.2.2 From f6acf8bb6a40ba3bfcf542e4c4c9e8968c8cb57a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:21 -0500 Subject: sysfs, kernfs: introduce kernfs_ops We're in the process of separating out core sysfs functionality into kernfs which will deal with sysfs_dirents directly. This patch introduces kernfs_ops which hosts methods kernfs users implement and updates fs/sysfs/file.c such that sysfs_kf_*() functions populate kernfs_ops and kernfs_file_*() functions call the matching entries from kernfs_ops. kernfs_ops contains the following groups of methods. * seq_show() - for kernfs files which use seq_file for reads. * read() - for direct read implementations. Used iff seq_show() is not implemented. * write() - for writes. * mmap() - for mmaps. Notes: * sysfs_elem_attr->ops is added so that kernfs_ops can be accessed from sysfs_dirent. kernfs_ops() helper is added to verify locking and access the field. * SYSFS_FLAG_HAS_(SEQ_SHOW|MMAP) added. sd->s_attr->ops is accessible only while holding active_ref and there are cases where we want to take different actions depending on which ops are implemented. These two flags cache whether the two ops are implemented for those. * kernfs_file_*() no longer test sysfs type but chooses different behaviors depending on which methods in kernfs_ops are implemented. The conversions are trivial except for the open path. As kernfs_file_open() now decides whether to allow read/write accesses depending on the kernfs_ops implemented, the presence of methods in kobjs and attribute_bin should be propagated to kernfs_ops. sysfs_add_file_mode_ns() is updated so that it propagates presence / absence of the callbacks through _empty, _ro, _wo, _rw kernfs_ops. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index b923052c29d0..97c6c0f91325 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -33,6 +33,32 @@ struct sysfs_open_file { const struct vm_operations_struct *vm_ops; }; +struct kernfs_ops { + /* + * Read is handled by either seq_file or raw_read(). + * + * If seq_show() is present, seq_file path is active. The behavior + * is equivalent to single_open(). @sf->private points to the + * associated sysfs_open_file. + * + * read() is bounced through kernel buffer and a read larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + int (*seq_show)(struct seq_file *sf, void *v); + + ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + /* + * write() is bounced through kernel buffer and a write larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + ssize_t (*write)(struct sysfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); +}; + #ifdef CONFIG_SYSFS struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, -- cgit v1.2.2 From 496f73944a4a974f89d48920bf368aec8841b195 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:24 -0500 Subject: sysfs, kernfs: introduce kernfs_create_file[_ns]() Introduce kernfs interface to create a file which takes and returns sysfs_dirents. The actual file creation part is separated out from sysfs_add_file_mode_ns() into kernfs_create_file_ns(). The former now only decides the kernfs_ops to use and the file's size and invokes the latter. This patch doesn't introduce behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 97c6c0f91325..d0912cf02087 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -64,6 +64,11 @@ struct kernfs_ops { struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); +struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -82,6 +87,12 @@ kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } +static inline struct sysfs_dirent * +kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns) +{ return ERR_PTR(-ENOSYS); } + static inline struct sysfs_dirent * kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target) @@ -112,6 +123,13 @@ kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) return kernfs_create_dir_ns(parent, name, priv, NULL); } +static inline struct sysfs_dirent * +kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, + loff_t size, const struct kernfs_ops *ops, void *priv) +{ + return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); +} + static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, const char *name) { -- cgit v1.2.2 From d19b9846df64d8845be682b6318bd1aee246cf60 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:26 -0500 Subject: sysfs, kernfs: add kernfs_ops->seq_{start|next|stop}() kernfs_ops currently only supports single_open() behavior which is pretty restrictive. Add optional callbacks ->seq_{start|next|stop}() which, when implemented, are invoked for seq_file traversal. This allows full seq_file functionality for kernfs users. This currently doesn't have any user and doesn't change any behavior. v2: Refreshed on top of the updated "sysfs, kernfs: prepare read path for kernfs". Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d0912cf02087..ba993ebcd81e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,8 +37,9 @@ struct kernfs_ops { /* * Read is handled by either seq_file or raw_read(). * - * If seq_show() is present, seq_file path is active. The behavior - * is equivalent to single_open(). @sf->private points to the + * If seq_show() is present, seq_file path is active. Other seq + * operations are optional and if not implemented, the behavior is + * equivalent to single_open(). @sf->private points to the * associated sysfs_open_file. * * read() is bounced through kernel buffer and a read larger than @@ -46,6 +47,10 @@ struct kernfs_ops { */ int (*seq_show)(struct seq_file *sf, void *v); + void *(*seq_start)(struct seq_file *sf, loff_t *ppos); + void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); + void (*seq_stop)(struct seq_file *sf, void *v); + ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, loff_t off); -- cgit v1.2.2 From 024f647117d697165aaadf3f1af1343b7000149a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:27 -0500 Subject: sysfs, kernfs: introduce kernfs_notify() Introduce kernfs interface to wake up poll(2) which takes and returns sysfs_dirents. sysfs_notify_dirent() is renamed to kernfs_notify() and sysfs_notify() is updated so that it doesn't directly grab sysfs_mutex but acquires the target sysfs_dirents using sysfs_get_dirent(). sysfs_notify_dirent() is reimplemented as a dumb inline wrapper around kernfs_notify(). This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index ba993ebcd81e..f20796ecc76e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -84,6 +84,7 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); +void kernfs_notify(struct sysfs_dirent *sd); #else /* CONFIG_SYSFS */ @@ -120,6 +121,8 @@ static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } +static inline void kernfs_notify(struct sysfs_dirent *sd) { } + #endif /* CONFIG_SYSFS */ static inline struct sysfs_dirent * -- cgit v1.2.2 From 517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:29 -0500 Subject: sysfs, kernfs: revamp sysfs_dirent active_ref lockdep annotation Currently, sysfs_dirent active_ref lockdep annotation uses attribute->[s]key as the lockdep key, which forces kernfs_create_file_ns() to assume that sysfs_dirent->priv is pointing to a struct attribute which may not be true for non-sysfs users. This patch restructures the lockdep annotation such that * kernfs_ops contains lockdep_key which is used by default for files created kernfs_create_file_ns(). * kernfs_create_file_ns_key() is introduced which takes an extra @key argument. The created file will use the specified key for active_ref lockdep annotation. If NULL is specified, lockdep for the file is disabled. * sysfs_add_file_mode_ns() is updated to use kernfs_create_file_ns_key() with the appropriate key from the attribute or NULL if ignore_lockdep is set. This makes the lockdep annotation properly contained in kernfs while allowing sysfs to cleanly keep its current behavior. This patch doesn't introduce any behavior differences. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index f20796ecc76e..105d09dcb064 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -11,6 +11,7 @@ #include #include #include +#include struct file; struct iattr; @@ -62,6 +63,10 @@ struct kernfs_ops { loff_t off); int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lock_class_key lockdep_key; +#endif }; #ifdef CONFIG_SYSFS @@ -69,11 +74,12 @@ struct kernfs_ops { struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); -struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns); +struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -94,9 +100,10 @@ kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, { return ERR_PTR(-ENOSYS); } static inline struct sysfs_dirent * -kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, - umode_t mode, loff_t size, const struct kernfs_ops *ops, - void *priv, const void *ns) +kernfs_create_file_ns_key(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, void *priv, + const void *ns, struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } static inline struct sysfs_dirent * @@ -131,6 +138,20 @@ kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) return kernfs_create_dir_ns(parent, name, priv, NULL); } +static inline struct sysfs_dirent * +kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns) +{ + struct lock_class_key *key = NULL; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + key = (struct lock_class_key *)&ops->lockdep_key; +#endif + return kernfs_create_file_ns_key(parent, name, mode, size, ops, priv, + ns, key); +} + static inline struct sysfs_dirent * kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv) -- cgit v1.2.2 From ccf73cf336dc55bc52748205dee998d2fd4a8808 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:30 -0500 Subject: sysfs, kernfs: introduce kernfs[_find_and]_get() and kernfs_put() Introduce kernfs interface for finding, getting and putting sysfs_dirents. * sysfs_find_dirent() is renamed to kernfs_find_ns() and lockdep assertion for sysfs_mutex is added. * sysfs_get_dirent_ns() is renamed to kernfs_find_and_get(). * Macro inline dancing around __sysfs_get/put() are removed and kernfs_get/put() are made proper functions implemented in fs/sysfs/dir.c. While the conversions are mostly equivalent, there's one difference - kernfs_get() doesn't return the input param as its return value. This change is intentional. While passing through the input increases writability in some areas, it is unnecessary and has been shown to cause confusion regarding how the last ref is handled. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 105d09dcb064..fd8f574ef2fe 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -71,6 +71,11 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, + const char *name, const void *ns); +void kernfs_get(struct sysfs_dirent *sd); +void kernfs_put(struct sysfs_dirent *sd); + struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); @@ -94,6 +99,14 @@ void kernfs_notify(struct sysfs_dirent *sd); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, + const void *ns) +{ return NULL; } + +static inline void kernfs_get(struct sysfs_dirent *sd) { } +static inline void kernfs_put(struct sysfs_dirent *sd) { } + static inline struct sysfs_dirent * kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) @@ -132,6 +145,12 @@ static inline void kernfs_notify(struct sysfs_dirent *sd) { } #endif /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_find_and_get(struct sysfs_dirent *sd, const char *name) +{ + return kernfs_find_and_get_ns(sd, name, NULL); +} + static inline struct sysfs_dirent * kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) { -- cgit v1.2.2 From ba7443bc656e5236c316b2acacc8b551f872910f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:40 -0500 Subject: sysfs, kernfs: implement kernfs_create/destroy_root() There currently is single kernfs hierarchy in the whole system which is used for sysfs. kernfs needs to support multiple hierarchies to allow other users. This patch introduces struct kernfs_root which serves as the root of each kernfs hierarchy and implements kernfs_create/destroy_root(). * Each kernfs_root is associated with a root sd (sysfs_dentry). The root is freed when the root sd is released and kernfs_destory_root() simply invokes kernfs_remove() on the root sd. sysfs_remove_one() is updated to handle release of the root sd. Note that ps_iattr update in sysfs_remove_one() is trivially updated for readability. * Root sd's are now dynamically allocated using sysfs_new_dirent(). Update sysfs_alloc_ino() so that it gives out ino from 1 so that the root sd still gets ino 1. * While kernfs currently only points to the root sd, it'll soon grow fields which are specific to each hierarchy. As determining a given sd's root will be necessary, sd->s_dir.root is added. This backlink fits better as a separate field in sd; however, sd->s_dir is inside union with space to spare, so use it to save space and provide kernfs_root() accessor to determine the root sd. * As hierarchies may be destroyed now, each mount needs to hold onto the hierarchy it's attached to. Update sysfs_fill_super() and sysfs_kill_sb() so that they get and put the kernfs_root respectively. * sysfs_root is replaced with kernfs_root which is dynamically created by invoking kernfs_create_root() from sysfs_init(). This patch doesn't introduce any visible behavior changes. v2: kernfs_create_root() forgot to set @sd->priv. Fixed. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fd8f574ef2fe..f75548b8ed7a 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -20,6 +20,11 @@ struct vm_area_struct; struct sysfs_dirent; +struct kernfs_root { + /* published fields */ + struct sysfs_dirent *sd; +}; + struct sysfs_open_file { /* published fields */ struct sysfs_dirent *sd; @@ -76,6 +81,9 @@ struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, void kernfs_get(struct sysfs_dirent *sd); void kernfs_put(struct sysfs_dirent *sd); +struct kernfs_root *kernfs_create_root(void *priv); +void kernfs_destroy_root(struct kernfs_root *root); + struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); @@ -107,6 +115,11 @@ kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, static inline void kernfs_get(struct sysfs_dirent *sd) { } static inline void kernfs_put(struct sysfs_dirent *sd) { } +static inline struct kernfs_root *kernfs_create_root(void *priv) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_destroy_root(struct kernfs_root *root) { } + static inline struct sysfs_dirent * kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) -- cgit v1.2.2 From bc755553df9ab33f389c1a0a8bd0b4f4646e80ef Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:41 -0500 Subject: sysfs, kernfs: make inode number ida per kernfs_root kernfs is being updated to allow multiple sysfs_dirent hierarchies so that it can also be used by other users. Currently, inode number is allocated using a global ida, sysfs_ino_ida; however, inos for different hierarchies should be handled separately. This patch makes ino allocation per kernfs_root. sysfs_ino_ida is replaced by kernfs_root->ino_ida and sysfs_new_dirent() is updated to take @root and allocate ino from it. ida_simple_get/remove() are used instead of sysfs_ino_lock and sysfs_alloc/free_ino(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index f75548b8ed7a..fad8b986800f 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -11,6 +11,7 @@ #include #include #include +#include #include struct file; @@ -23,6 +24,9 @@ struct sysfs_dirent; struct kernfs_root { /* published fields */ struct sysfs_dirent *sd; + + /* private fields, do not use outside kernfs proper */ + struct ida ino_ida; }; struct sysfs_open_file { -- cgit v1.2.2 From 4b93dc9b1c684d0587fe44d36bbfdf45bd3bea9d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:43 -0500 Subject: sysfs, kernfs: prepare mount path for kernfs We're in the process of separating out core sysfs functionality into kernfs which will deal with sysfs_dirents directly. This patch rearranges mount path so that the kernfs and sysfs parts are separate. * As sysfs_super_info won't be visible outside kernfs proper, kernfs_super_ns() is added to allow kernfs users to access a super_block's namespace tag. * Generic mount operation is separated out into kernfs_mount_ns(). sysfs_mount() now just performs sysfs-specific permission check, acquires namespace tag, and invokes kernfs_mount_ns(). * Generic superblock release is separated out into kernfs_kill_sb() which can be used directly as file_system_type->kill_sb(). As sysfs needs to put the namespace tag, sysfs_kill_sb() wraps kernfs_kill_sb() with ns tag put. * sysfs_dir_cachep init and sysfs_inode_init() are separated out into kernfs_init(). kernfs_init() uses only small amount of memory and trying to handle and propagate kernfs_init() failure doesn't make much sense. Use SLAB_PANIC for sysfs_dir_cachep and make sysfs_inode_init() panic on failure. After this change, kernfs_init() should be called before sysfs_init(), fs/namespace.c::mnt_init() modified accordingly. Signed-off-by: Tejun Heo Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fad8b986800f..75fcbe5c9d65 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -18,6 +18,8 @@ struct file; struct iattr; struct seq_file; struct vm_area_struct; +struct super_block; +struct file_system_type; struct sysfs_dirent; @@ -109,6 +111,13 @@ void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); void kernfs_notify(struct sysfs_dirent *sd); +const void *kernfs_super_ns(struct super_block *sb); +struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns); +void kernfs_kill_sb(struct super_block *sb); + +void kernfs_init(void); + #else /* CONFIG_SYSFS */ static inline struct sysfs_dirent * @@ -160,6 +169,18 @@ static inline int kernfs_setattr(struct sysfs_dirent *sd, static inline void kernfs_notify(struct sysfs_dirent *sd) { } +static inline const void *kernfs_super_ns(struct super_block *sb) +{ return NULL; } + +static inline struct dentry * +kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_kill_sb(struct super_block *sb) { } + +static inline void kernfs_init(void) { } + #endif /* CONFIG_SYSFS */ static inline struct sysfs_dirent * @@ -201,4 +222,11 @@ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, return kernfs_remove_by_name_ns(parent, name, NULL); } +static inline struct dentry * +kernfs_mount(struct file_system_type *fs_type, int flags, + struct kernfs_root *root) +{ + return kernfs_mount_ns(fs_type, flags, root, NULL); +} + #endif /* __LINUX_KERNFS_H */ -- cgit v1.2.2 From cf9e5a73aaff0204801dd19cb4bd91d32f32026a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 17:18:32 -0500 Subject: sysfs, kernfs: make sysfs_dirent definition public sysfs_dirent includes some information which should be available to kernfs users - the type, flags, name and parent pointer. This patch moves sysfs_dirent definition from kernfs/kernfs-internal.h to include/linux/kernfs.h so that kernfs users can access them. The type part of flags is exported as enum kernfs_node_type, the flags kernfs_node_flag, sysfs_type() and kernfs_enable_ns() are moved to include/linux/kernfs.h and the former is updated to return the enum type. sysfs_dirent->s_parent and ->s_name are marked explicitly as public. This patch doesn't introduce any functional changes. v2: Flags exported too and kernfs_enable_ns() definition moved. v3: While moving kernfs_enable_ns() to include/linux/kernfs.h, v1 and v2 put the definition outside CONFIG_SYSFS replacing the dummy implementation with the actual implementation too. Unfortunately, this can lead to oops when !CONFIG_SYSFS because kernfs_enable_ns() may be called on a NULL @sd and now tries to dereference @sd instead of not doing anything. This issue was reported by Yuanhan Liu. Signed-off-by: Tejun Heo Reported-by: Yuanhan Liu Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 4 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 75fcbe5c9d65..faaf4f29e33d 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include struct file; struct iattr; @@ -21,7 +24,92 @@ struct vm_area_struct; struct super_block; struct file_system_type; -struct sysfs_dirent; +struct sysfs_open_dirent; +struct sysfs_inode_attrs; + +enum kernfs_node_type { + SYSFS_DIR = 0x0001, + SYSFS_KOBJ_ATTR = 0x0002, + SYSFS_KOBJ_LINK = 0x0004, +}; + +#define SYSFS_TYPE_MASK 0x000f +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) +#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK + +enum kernfs_node_flag { + SYSFS_FLAG_REMOVED = 0x0010, + SYSFS_FLAG_NS = 0x0020, + SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040, + SYSFS_FLAG_HAS_MMAP = 0x0080, + SYSFS_FLAG_LOCKDEP = 0x0100, +}; + +/* type-specific structures for sysfs_dirent->s_* union members */ +struct sysfs_elem_dir { + unsigned long subdirs; + /* children rbtree starts here and goes through sd->s_rb */ + struct rb_root children; + + /* + * The kernfs hierarchy this directory belongs to. This fits + * better directly in sysfs_dirent but is here to save space. + */ + struct kernfs_root *root; +}; + +struct sysfs_elem_symlink { + struct sysfs_dirent *target_sd; +}; + +struct sysfs_elem_attr { + const struct kernfs_ops *ops; + struct sysfs_open_dirent *open; + loff_t size; +}; + +/* + * sysfs_dirent - the building block of sysfs hierarchy. Each and every + * sysfs node is represented by single sysfs_dirent. Most fields are + * private to kernfs and shouldn't be accessed directly by kernfs users. + * + * As long as s_count reference is held, the sysfs_dirent itself is + * accessible. Dereferencing s_elem or any other outer entity + * requires s_active reference. + */ +struct sysfs_dirent { + atomic_t s_count; + atomic_t s_active; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif + /* the following two fields are published */ + struct sysfs_dirent *s_parent; + const char *s_name; + + struct rb_node s_rb; + + union { + struct completion *completion; + struct sysfs_dirent *removed_list; + } u; + + const void *s_ns; /* namespace tag */ + unsigned int s_hash; /* ns + name hash */ + union { + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + }; + + void *priv; + + unsigned short s_flags; + umode_t s_mode; + unsigned int s_ino; + struct sysfs_inode_attrs *s_iattr; +}; struct kernfs_root { /* published fields */ @@ -82,6 +170,26 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS +static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_TYPE_MASK; +} + +/** + * kernfs_enable_ns - enable namespace under a directory + * @sd: directory of interest, should be empty + * + * This is to be called right after @sd is created to enable namespace + * under it. All children of @sd must have non-NULL namespace tags and + * only the ones which match the super_block's tag will be visible. + */ +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) +{ + WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); + sd->s_flags |= SYSFS_FLAG_NS; +} + struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns); void kernfs_get(struct sysfs_dirent *sd); @@ -107,7 +215,6 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); -void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); void kernfs_notify(struct sysfs_dirent *sd); @@ -120,6 +227,11 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ +static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +{ return 0; } /* whatever */ + +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } + static inline struct sysfs_dirent * kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns) @@ -161,8 +273,6 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } - static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } -- cgit v1.2.2 From ac9bba031001704a2339713cc12148857eccc5e5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 17:19:09 -0500 Subject: sysfs, kernfs: implement kernfs_ns_enabled() fs/sysfs/symlink.c::sysfs_delete_link() tests @sd->s_flags for SYSFS_FLAG_NS. Let's add kernfs_ns_enabled() so that sysfs doesn't have to test sysfs_dirent flag directly. This makes things tidier for kernfs proper too. This is purely cosmetic. v2: To avoid possible NULL deref, use noop dummy implementation which always returns false when !CONFIG_SYSFS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index faaf4f29e33d..d65541308419 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -190,6 +190,17 @@ static inline void kernfs_enable_ns(struct sysfs_dirent *sd) sd->s_flags |= SYSFS_FLAG_NS; } +/** + * kernfs_ns_enabled - test whether namespace is enabled + * @sd: the node to test + * + * Test whether namespace filtering is enabled for the children of @ns. + */ +static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_FLAG_NS; +} + struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns); void kernfs_get(struct sysfs_dirent *sd); @@ -232,6 +243,9 @@ static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } +static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +{ return false; } + static inline struct sysfs_dirent * kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns) -- cgit v1.2.2 From 324a56e16e44baecac3ca799fd216154145c14bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:53 -0500 Subject: kernfs: s/sysfs_dirent/kernfs_node/ and rename its friends accordingly kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_elem_dir/kernfs_elem_dir/ * s/sysfs_elem_symlink/kernfs_elem_symlink/ * s/sysfs_elem_attr/kernfs_elem_file/ * s/sysfs_dirent/kernfs_node/ * s/sd/kn/ in kernfs proper * s/parent_sd/parent/ * s/target_sd/target/ * s/dir_sd/parent/ * s/to_sysfs_dirent()/rb_to_kn()/ * misc renames of local vars when they conflict with the above Because md, mic and gpio dig into sysfs details, this patch ends up modifying them. All are sysfs_dirent renames and trivial. While we can avoid these by introducing a dummy wrapping struct sysfs_dirent around kernfs_node, given the limited usage outside kernfs and sysfs proper, I don't think such workaround is called for. This patch is strictly rename only and doesn't introduce any functional difference. - mic / gpio renames were missing. Spotted by kbuild test robot. Signed-off-by: Tejun Heo Cc: Neil Brown Cc: Linus Walleij Cc: Ashutosh Dixit Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 166 ++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 83 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d65541308419..195d1c6a8b0c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -46,61 +46,61 @@ enum kernfs_node_flag { SYSFS_FLAG_LOCKDEP = 0x0100, }; -/* type-specific structures for sysfs_dirent->s_* union members */ -struct sysfs_elem_dir { +/* type-specific structures for kernfs_node union members */ +struct kernfs_elem_dir { unsigned long subdirs; - /* children rbtree starts here and goes through sd->s_rb */ + /* children rbtree starts here and goes through kn->s_rb */ struct rb_root children; /* * The kernfs hierarchy this directory belongs to. This fits - * better directly in sysfs_dirent but is here to save space. + * better directly in kernfs_node but is here to save space. */ struct kernfs_root *root; }; -struct sysfs_elem_symlink { - struct sysfs_dirent *target_sd; +struct kernfs_elem_symlink { + struct kernfs_node *target_kn; }; -struct sysfs_elem_attr { +struct kernfs_elem_attr { const struct kernfs_ops *ops; struct sysfs_open_dirent *open; loff_t size; }; /* - * sysfs_dirent - the building block of sysfs hierarchy. Each and every - * sysfs node is represented by single sysfs_dirent. Most fields are + * kernfs_node - the building block of kernfs hierarchy. Each and every + * kernfs node is represented by single kernfs_node. Most fields are * private to kernfs and shouldn't be accessed directly by kernfs users. * - * As long as s_count reference is held, the sysfs_dirent itself is - * accessible. Dereferencing s_elem or any other outer entity - * requires s_active reference. + * As long as s_count reference is held, the kernfs_node itself is + * accessible. Dereferencing elem or any other outer entity requires + * active reference. */ -struct sysfs_dirent { +struct kernfs_node { atomic_t s_count; atomic_t s_active; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif /* the following two fields are published */ - struct sysfs_dirent *s_parent; + struct kernfs_node *s_parent; const char *s_name; struct rb_node s_rb; union { struct completion *completion; - struct sysfs_dirent *removed_list; + struct kernfs_node *removed_list; } u; const void *s_ns; /* namespace tag */ unsigned int s_hash; /* ns + name hash */ union { - struct sysfs_elem_dir s_dir; - struct sysfs_elem_symlink s_symlink; - struct sysfs_elem_attr s_attr; + struct kernfs_elem_dir s_dir; + struct kernfs_elem_symlink s_symlink; + struct kernfs_elem_attr s_attr; }; void *priv; @@ -113,7 +113,7 @@ struct sysfs_dirent { struct kernfs_root { /* published fields */ - struct sysfs_dirent *sd; + struct kernfs_node *kn; /* private fields, do not use outside kernfs proper */ struct ida ino_ida; @@ -121,7 +121,7 @@ struct kernfs_root { struct sysfs_open_file { /* published fields */ - struct sysfs_dirent *sd; + struct kernfs_node *kn; struct file *file; /* private fields, do not use outside kernfs proper */ @@ -170,64 +170,64 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS -static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { - return sd->s_flags & SYSFS_TYPE_MASK; + return kn->s_flags & SYSFS_TYPE_MASK; } /** * kernfs_enable_ns - enable namespace under a directory - * @sd: directory of interest, should be empty + * @kn: directory of interest, should be empty * - * This is to be called right after @sd is created to enable namespace - * under it. All children of @sd must have non-NULL namespace tags and + * This is to be called right after @kn is created to enable namespace + * under it. All children of @kn must have non-NULL namespace tags and * only the ones which match the super_block's tag will be visible. */ -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) +static inline void kernfs_enable_ns(struct kernfs_node *kn) { - WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); - sd->s_flags |= SYSFS_FLAG_NS; + WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->s_dir.children)); + kn->s_flags |= SYSFS_FLAG_NS; } /** * kernfs_ns_enabled - test whether namespace is enabled - * @sd: the node to test + * @kn: the node to test * * Test whether namespace filtering is enabled for the children of @ns. */ -static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return sd->s_flags & SYSFS_FLAG_NS; + return kn->s_flags & SYSFS_FLAG_NS; } -struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, - const char *name, const void *ns); -void kernfs_get(struct sysfs_dirent *sd); -void kernfs_put(struct sysfs_dirent *sd); +struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, + const char *name, const void *ns); +void kernfs_get(struct kernfs_node *kn); +void kernfs_put(struct kernfs_node *kn); struct kernfs_root *kernfs_create_root(void *priv); void kernfs_destroy_root(struct kernfs_root *root); -struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, - const char *name, void *priv, - const void *ns); -struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key); -struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, - const char *name, - struct sysfs_dirent *target); -void kernfs_remove(struct sysfs_dirent *sd); -int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, +struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, + const char *name, void *priv, + const void *ns); +struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key); +struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, + const char *name, + struct kernfs_node *target); +void kernfs_remove(struct kernfs_node *kn); +int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); -int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, +int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, const char *new_name, const void *new_ns); -int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); -void kernfs_notify(struct sysfs_dirent *sd); +int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); +void kernfs_notify(struct kernfs_node *kn); const void *kernfs_super_ns(struct super_block *sb); struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, @@ -238,60 +238,60 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ -static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { return 0; } /* whatever */ -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } +static inline void kernfs_enable_ns(struct kernfs_node *kn) { } -static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { return false; } -static inline struct sysfs_dirent * -kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, const void *ns) { return NULL; } -static inline void kernfs_get(struct sysfs_dirent *sd) { } -static inline void kernfs_put(struct sysfs_dirent *sd) { } +static inline void kernfs_get(struct kernfs_node *kn) { } +static inline void kernfs_put(struct kernfs_node *kn) { } static inline struct kernfs_root *kernfs_create_root(void *priv) { return ERR_PTR(-ENOSYS); } static inline void kernfs_destroy_root(struct kernfs_root *root) { } -static inline struct sysfs_dirent * -kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, +static inline struct kernfs_node * +kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } -static inline struct sysfs_dirent * -kernfs_create_file_ns_key(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv, const void *ns, struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } -static inline struct sysfs_dirent * -kernfs_create_link(struct sysfs_dirent *parent, const char *name, - struct sysfs_dirent *target) +static inline struct kernfs_node * +kernfs_create_link(struct kernfs_node *parent, const char *name, + struct kernfs_node *target) { return ERR_PTR(-ENOSYS); } -static inline void kernfs_remove(struct sysfs_dirent *sd) { } +static inline void kernfs_remove(struct kernfs_node *kn) { } -static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, +static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, const char *name, const void *ns) { return -ENOSYS; } -static inline int kernfs_rename_ns(struct sysfs_dirent *sd, - struct sysfs_dirent *new_parent, +static inline int kernfs_rename_ns(struct kernfs_node *kn, + struct kernfs_node *new_parent, const char *new_name, const void *new_ns) { return -ENOSYS; } -static inline int kernfs_setattr(struct sysfs_dirent *sd, +static inline int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { return -ENOSYS; } -static inline void kernfs_notify(struct sysfs_dirent *sd) { } +static inline void kernfs_notify(struct kernfs_node *kn) { } static inline const void *kernfs_super_ns(struct super_block *sb) { return NULL; } @@ -307,20 +307,20 @@ static inline void kernfs_init(void) { } #endif /* CONFIG_SYSFS */ -static inline struct sysfs_dirent * -kernfs_find_and_get(struct sysfs_dirent *sd, const char *name) +static inline struct kernfs_node * +kernfs_find_and_get(struct kernfs_node *kn, const char *name) { - return kernfs_find_and_get_ns(sd, name, NULL); + return kernfs_find_and_get_ns(kn, name, NULL); } -static inline struct sysfs_dirent * -kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) +static inline struct kernfs_node * +kernfs_create_dir(struct kernfs_node *parent, const char *name, void *priv) { return kernfs_create_dir_ns(parent, name, priv, NULL); } -static inline struct sysfs_dirent * -kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_create_file_ns(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv, const void *ns) { @@ -333,14 +333,14 @@ kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, ns, key); } -static inline struct sysfs_dirent * -kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, +static inline struct kernfs_node * +kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv) { return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); } -static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, +static inline int kernfs_remove_by_name(struct kernfs_node *parent, const char *name) { return kernfs_remove_by_name_ns(parent, name, NULL); -- cgit v1.2.2 From adc5e8b58f4886d45f79f4ff41a09001a76a6b12 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:54 -0500 Subject: kernfs: drop s_ prefix from kernfs_node members kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. s_ prefix for kernfs members is used inconsistently and a misnomer now. It's not like kernfs_node is used widely across the kernel making the ability to grep for the members particularly useful. Let's just drop the prefix. This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 195d1c6a8b0c..092469f60e3e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -49,7 +49,7 @@ enum kernfs_node_flag { /* type-specific structures for kernfs_node union members */ struct kernfs_elem_dir { unsigned long subdirs; - /* children rbtree starts here and goes through kn->s_rb */ + /* children rbtree starts here and goes through kn->rb */ struct rb_root children; /* @@ -79,36 +79,36 @@ struct kernfs_elem_attr { * active reference. */ struct kernfs_node { - atomic_t s_count; - atomic_t s_active; + atomic_t count; + atomic_t active; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif /* the following two fields are published */ - struct kernfs_node *s_parent; - const char *s_name; + struct kernfs_node *parent; + const char *name; - struct rb_node s_rb; + struct rb_node rb; union { struct completion *completion; struct kernfs_node *removed_list; } u; - const void *s_ns; /* namespace tag */ - unsigned int s_hash; /* ns + name hash */ + const void *ns; /* namespace tag */ + unsigned int hash; /* ns + name hash */ union { - struct kernfs_elem_dir s_dir; - struct kernfs_elem_symlink s_symlink; - struct kernfs_elem_attr s_attr; + struct kernfs_elem_dir dir; + struct kernfs_elem_symlink symlink; + struct kernfs_elem_attr attr; }; void *priv; - unsigned short s_flags; - umode_t s_mode; - unsigned int s_ino; - struct sysfs_inode_attrs *s_iattr; + unsigned short flags; + umode_t mode; + unsigned int ino; + struct sysfs_inode_attrs *iattr; }; struct kernfs_root { @@ -172,7 +172,7 @@ struct kernfs_ops { static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { - return kn->s_flags & SYSFS_TYPE_MASK; + return kn->flags & SYSFS_TYPE_MASK; } /** @@ -186,8 +186,8 @@ static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) static inline void kernfs_enable_ns(struct kernfs_node *kn) { WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->s_dir.children)); - kn->s_flags |= SYSFS_FLAG_NS; + WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); + kn->flags |= SYSFS_FLAG_NS; } /** @@ -198,7 +198,7 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) */ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return kn->s_flags & SYSFS_FLAG_NS; + return kn->flags & SYSFS_FLAG_NS; } struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, -- cgit v1.2.2 From c525aaddc366df23eb095d58a2bdf11cce62a98b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:55 -0500 Subject: kernfs: s/sysfs/kernfs/ in various data structures kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_open_dirent/kernfs_open_node/ * s/sysfs_open_file/kernfs_open_file/ * s/sysfs_inode_attrs/kernfs_iattrs/ * s/sysfs_addrm_cxt/kernfs_addrm_cxt/ * s/sysfs_super_info/kernfs_super_info/ * s/sysfs_info()/kernfs_info()/ * s/sysfs_open_dirent_lock/kernfs_open_node_lock/ * s/sysfs_open_file_mutex/kernfs_open_file_mutex/ * s/sysfs_of()/kernfs_of()/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 092469f60e3e..757647c4cb3b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -24,8 +24,8 @@ struct vm_area_struct; struct super_block; struct file_system_type; -struct sysfs_open_dirent; -struct sysfs_inode_attrs; +struct kernfs_open_node; +struct kernfs_iattrs; enum kernfs_node_type { SYSFS_DIR = 0x0001, @@ -65,7 +65,7 @@ struct kernfs_elem_symlink { struct kernfs_elem_attr { const struct kernfs_ops *ops; - struct sysfs_open_dirent *open; + struct kernfs_open_node *open; loff_t size; }; @@ -108,7 +108,7 @@ struct kernfs_node { unsigned short flags; umode_t mode; unsigned int ino; - struct sysfs_inode_attrs *iattr; + struct kernfs_iattrs *iattr; }; struct kernfs_root { @@ -119,7 +119,7 @@ struct kernfs_root { struct ida ino_ida; }; -struct sysfs_open_file { +struct kernfs_open_file { /* published fields */ struct kernfs_node *kn; struct file *file; @@ -140,7 +140,7 @@ struct kernfs_ops { * If seq_show() is present, seq_file path is active. Other seq * operations are optional and if not implemented, the behavior is * equivalent to single_open(). @sf->private points to the - * associated sysfs_open_file. + * associated kernfs_open_file. * * read() is bounced through kernel buffer and a read larger than * PAGE_SIZE results in partial operation of PAGE_SIZE. @@ -151,17 +151,17 @@ struct kernfs_ops { void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); void (*seq_stop)(struct seq_file *sf, void *v); - ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, + ssize_t (*read)(struct kernfs_open_file *of, char *buf, size_t bytes, loff_t off); /* * write() is bounced through kernel buffer and a write larger than * PAGE_SIZE results in partial operation of PAGE_SIZE. */ - ssize_t (*write)(struct sysfs_open_file *of, char *buf, size_t bytes, + ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes, loff_t off); - int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); + int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma); #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lock_class_key lockdep_key; -- cgit v1.2.2 From df23fc39bce03bb26e63bea57fc5f5bf6882d74b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:56 -0500 Subject: kernfs: s/sysfs/kernfs/ in constants kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/SYSFS_DIR/KERNFS_DIR/ * s/SYSFS_KOBJ_ATTR/KERNFS_FILE/ * s/SYSFS_KOBJ_LINK/KERNFS_LINK/ * s/SYSFS_{TYPE_FLAGS}/KERNFS_{TYPE_FLAGS}/ * s/SYSFS_FLAG_{FLAG}/KERNFS_{FLAG}/ * s/sysfs_type()/kernfs_type()/ * s/SD_DEACTIVATED_BIAS/KN_DEACTIVATED_BIAS/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 757647c4cb3b..e9c4e3a03960 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -28,22 +28,22 @@ struct kernfs_open_node; struct kernfs_iattrs; enum kernfs_node_type { - SYSFS_DIR = 0x0001, - SYSFS_KOBJ_ATTR = 0x0002, - SYSFS_KOBJ_LINK = 0x0004, + KERNFS_DIR = 0x0001, + KERNFS_FILE = 0x0002, + KERNFS_LINK = 0x0004, }; -#define SYSFS_TYPE_MASK 0x000f -#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) -#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define KERNFS_TYPE_MASK 0x000f +#define KERNFS_COPY_NAME (KERNFS_DIR | KERNFS_LINK) +#define KERNFS_ACTIVE_REF KERNFS_FILE +#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { - SYSFS_FLAG_REMOVED = 0x0010, - SYSFS_FLAG_NS = 0x0020, - SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040, - SYSFS_FLAG_HAS_MMAP = 0x0080, - SYSFS_FLAG_LOCKDEP = 0x0100, + KERNFS_REMOVED = 0x0010, + KERNFS_NS = 0x0020, + KERNFS_HAS_SEQ_SHOW = 0x0040, + KERNFS_HAS_MMAP = 0x0080, + KERNFS_LOCKDEP = 0x0100, }; /* type-specific structures for kernfs_node union members */ @@ -170,9 +170,9 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS -static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) { - return kn->flags & SYSFS_TYPE_MASK; + return kn->flags & KERNFS_TYPE_MASK; } /** @@ -185,9 +185,9 @@ static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) */ static inline void kernfs_enable_ns(struct kernfs_node *kn) { - WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); - kn->flags |= SYSFS_FLAG_NS; + kn->flags |= KERNFS_NS; } /** @@ -198,7 +198,7 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) */ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return kn->flags & SYSFS_FLAG_NS; + return kn->flags & KERNFS_NS; } struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, @@ -238,7 +238,7 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ -static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) { return 0; } /* whatever */ static inline void kernfs_enable_ns(struct kernfs_node *kn) { } -- cgit v1.2.2 From bb8b9d095c5c56cce99576cfef0cf9b989f7120d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:02:55 -0500 Subject: kernfs: add @mode to kernfs_create_dir[_ns]() sysfs assumed 0755 for all newly created directories and kernfs inherited it. This assumption is unnecessarily restrictive and inconsistent with kernfs_create_file[_ns](). This patch adds @mode parameter to kernfs_create_dir[_ns]() and update uses in sysfs accordingly. Among others, this will be useful for implementations of the planned ->mkdir() method. This patch doesn't introduce any behavior differences. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e9c4e3a03960..0ca2aedfd31b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -210,8 +210,8 @@ struct kernfs_root *kernfs_create_root(void *priv); void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, void *priv, - const void *ns); + const char *name, umode_t mode, + void *priv, const void *ns); struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, @@ -260,8 +260,8 @@ static inline struct kernfs_root *kernfs_create_root(void *priv) 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, void *priv, - const void *ns) +kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, + umode_t mode, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * @@ -314,9 +314,10 @@ kernfs_find_and_get(struct kernfs_node *kn, const char *name) } static inline struct kernfs_node * -kernfs_create_dir(struct kernfs_node *parent, const char *name, void *priv) +kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, + void *priv) { - return kernfs_create_dir_ns(parent, name, priv, NULL); + return kernfs_create_dir_ns(parent, name, mode, priv, NULL); } static inline struct kernfs_node * -- cgit v1.2.2 From 2063d608f5110d120db60e896ec2c70c95bb7978 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:02:57 -0500 Subject: kernfs: mark static names with KERNFS_STATIC_NAME Because sysfs used struct attribute which are supposed to stay constant, sysfs didn't copy names when creating regular files. The specified string for name was supposed to stay constant. Such distinction isn't inherent for kernfs. kernfs_create_file[_ns]() should be able to take the same @name as kernfs_create_dir[_ns]() As there can be huge number of sysfs attributes, we still want to be able to use static names for sysfs attributes. This patch renames kernfs_create_file_ns_key() to __kernfs_create_file() and adds @name_is_static parameter so that the caller can explicitly indicate that @name can be used without copying. kernfs is updated to use KERNFS_STATIC_NAME to distinguish static and copied names. This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 0ca2aedfd31b..321ed84ad4ce 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -34,7 +34,6 @@ enum kernfs_node_type { }; #define KERNFS_TYPE_MASK 0x000f -#define KERNFS_COPY_NAME (KERNFS_DIR | KERNFS_LINK) #define KERNFS_ACTIVE_REF KERNFS_FILE #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK @@ -44,6 +43,7 @@ enum kernfs_node_flag { KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, KERNFS_LOCKDEP = 0x0100, + KERNFS_STATIC_NAME = 0x0200, }; /* type-specific structures for kernfs_node union members */ @@ -212,12 +212,13 @@ void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, umode_t mode, void *priv, const void *ns); -struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key); +struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + bool name_is_static, + struct lock_class_key *key); struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target); @@ -265,10 +266,10 @@ kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * -kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, void *priv, - const void *ns, struct lock_class_key *key) +__kernfs_create_file(struct kernfs_node *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns, bool name_is_static, + struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * @@ -330,8 +331,8 @@ kernfs_create_file_ns(struct kernfs_node *parent, const char *name, #ifdef CONFIG_DEBUG_LOCK_ALLOC key = (struct lock_class_key *)&ops->lockdep_key; #endif - return kernfs_create_file_ns_key(parent, name, mode, size, ops, priv, - ns, key); + return __kernfs_create_file(parent, name, mode, size, ops, priv, ns, + false, key); } static inline struct kernfs_node * -- cgit v1.2.2 From 80b9bbefc345079bddc4959de016ba4074b0c8d6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:03:00 -0500 Subject: kernfs: add kernfs_dir_ops Add support for mkdir(2), rmdir(2) and rename(2) syscalls. This is implemented through optional kernfs_dir_ops callback table which can be specified on kernfs_create_root(). An implemented callback is invoked when the matching syscall is invoked. As kernfs keep dcache syncs with internal representation and revalidates dentries on each access, the implementation of these methods is extremely simple. Each just discovers the relevant kernfs_node(s) and invokes the requested callback which is allowed to do any kernfs operations and the end result doesn't necessarily have to match the expected semantics of the syscall. This will be used to convert cgroup to use kernfs instead of its own filesystem implementation. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 321ed84ad4ce..d2c439db4efa 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -111,12 +111,27 @@ struct kernfs_node { struct kernfs_iattrs *iattr; }; +/* + * kernfs_dir_ops may be specified on kernfs_create_root() to support + * directory manipulation syscalls. These optional callbacks are invoked + * on the matching syscalls and can perform any kernfs operations which + * don't necessarily have to be the exact operation requested. + */ +struct kernfs_dir_ops { + int (*mkdir)(struct kernfs_node *parent, const char *name, + umode_t mode); + int (*rmdir)(struct kernfs_node *kn); + int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, + const char *new_name); +}; + struct kernfs_root { /* published fields */ struct kernfs_node *kn; /* private fields, do not use outside kernfs proper */ struct ida ino_ida; + struct kernfs_dir_ops *dir_ops; }; struct kernfs_open_file { @@ -206,7 +221,8 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, void kernfs_get(struct kernfs_node *kn); void kernfs_put(struct kernfs_node *kn); -struct kernfs_root *kernfs_create_root(void *priv); +struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, + void *priv); void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, @@ -255,7 +271,8 @@ kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, static inline void kernfs_get(struct kernfs_node *kn) { } static inline void kernfs_put(struct kernfs_node *kn) { } -static inline struct kernfs_root *kernfs_create_root(void *priv) +static inline struct kernfs_root * +kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) { return ERR_PTR(-ENOSYS); } static inline void kernfs_destroy_root(struct kernfs_root *root) { } -- cgit v1.2.2 From ea1c472dfeada211a0100daa7976e8e8e779b858 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:19 -0500 Subject: kernfs: replace kernfs_node->u.completion with kernfs_root->deactivate_waitq kernfs_node->u.completion is used to notify deactivation completion from kernfs_put_active() to kernfs_deactivate(). We now allow multiple racing removals of the same node and the current removal scheme is no longer correct - kernfs_remove() invocation may return before the node is properly deactivated if it races against another removal. The removal path will be restructured to address the issue. To help such restructure which requires supporting multiple waiters, this patch replaces kernfs_node->u.completion with kernfs_root->deactivate_waitq. This makes deactivation event notifications share a per-root waitqueue_head; however, the wait path is quite cold and this will also allow shaving one pointer off kernfs_node. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d2c439db4efa..232f1a632383 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include struct file; struct iattr; @@ -91,7 +91,6 @@ struct kernfs_node { struct rb_node rb; union { - struct completion *completion; struct kernfs_node *removed_list; } u; @@ -132,6 +131,7 @@ struct kernfs_root { /* private fields, do not use outside kernfs proper */ struct ida ino_ida; struct kernfs_dir_ops *dir_ops; + wait_queue_head_t deactivate_waitq; }; struct kernfs_open_file { -- cgit v1.2.2 From a69d001cfc712b96ec9d7ba44d6285702a38dabf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:20 -0500 Subject: kernfs: remove KERNFS_ACTIVE_REF and add kernfs_lockdep() There currently are two mechanisms gating active ref lockdep annotations - KERNFS_LOCKDEP flag and KERNFS_ACTIVE_REF type mask. The former disables lockdep annotations in kernfs_get/put_active() while the latter disables all of kernfs_deactivate(). While KERNFS_ACTIVE_REF also behaves as an optimization to skip the deactivation step for non-file nodes, the benefit is marginal and it needlessly diverges code paths. Let's drop KERNFS_ACTIVE_REF and use KERNFS_LOCKDEP in kernfs_deactivate() too. While at it, add a test helper kernfs_lockdep() to test KERNFS_LOCKDEP flag so that it's more convenient and the related code can be compiled out when not enabled. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 232f1a632383..42ad32ff22f8 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -34,7 +34,6 @@ enum kernfs_node_type { }; #define KERNFS_TYPE_MASK 0x000f -#define KERNFS_ACTIVE_REF KERNFS_FILE #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { -- cgit v1.2.2 From ae34372eb8408b3d07e870f1939f99007a730d28 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:21 -0500 Subject: kernfs: remove KERNFS_REMOVED KERNFS_REMOVED is used to mark half-initialized and dying nodes so that they don't show up in lookups and deny adding new nodes under or renaming it; however, its role overlaps those of deactivation and removal from rbtree. It's necessary to deny addition of new children while removal is in progress; however, this role considerably intersects with deactivation - KERNFS_REMOVED prevents new children while deactivation prevents new file operations. There's no reason to have them separate making things more complex than necessary. KERNFS_REMOVED is also used to decide whether a node is still visible to vfs layer, which is rather redundant as equivalent determination can be made by testing whether the node is on its parent's children rbtree or not. This patch removes KERNFS_REMOVED. * Instead of KERNFS_REMOVED, each node now starts its life deactivated. This means that we now use both atomic_add() and atomic_sub() on KN_DEACTIVATED_BIAS, which is INT_MIN. The compiler generates an overflow warnings when negating INT_MIN as the negation can't be represented as a positive number. Nothing is actually broken but let's bump BIAS by one to avoid the warnings for archs which negates the subtrahend.. * KERNFS_REMOVED tests in add and rename paths are replaced with kernfs_get/put_active() of the target nodes. Due to the way the add path is structured now, active ref handling is done in the callers of kernfs_add_one(). This will be consolidated up later. * kernfs_remove_one() is updated to deactivate instead of setting KERNFS_REMOVED. This removes deactivation from kernfs_deactivate(), which is now renamed to kernfs_drain(). * kernfs_dop_revalidate() now tests RB_EMPTY_NODE(&kn->rb) instead of KERNFS_REMOVED and KERNFS_REMOVED test in kernfs_dir_pos() is dropped. A node which is removed from the children rbtree is not included in the iteration in the first place. This means that a node may be visible through vfs a bit longer - it's now also visible after deactivation until the actual removal. This slightly enlarged window difference doesn't make any difference to the userland. * Sanity check on KERNFS_REMOVED in kernfs_put() is replaced with checks on the active ref. * Some comment style updates in the affected area. v2: Reordered before removal path restructuring. kernfs_active() dropped and kernfs_get/put_active() used instead. RB_EMPTY_NODE() used in the lookup paths. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 42ad32ff22f8..289d4f639ade 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,7 +37,6 @@ enum kernfs_node_type { #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { - KERNFS_REMOVED = 0x0010, KERNFS_NS = 0x0020, KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, -- cgit v1.2.2 From 45a140e587f3d32d8d424ed940dffb61e1739047 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:22 -0500 Subject: kernfs: restructure removal path to fix possible premature return The recursive nature of kernfs_remove() means that, even if kernfs_remove() is not allowed to be called multiple times on the same node, there may be race conditions between removal of parent and its descendants. While we can claim that kernfs_remove() shouldn't be called on one of the descendants while the removal of an ancestor is in progress, such rule is unnecessarily restrictive and very difficult to enforce. It's better to simply allow invoking kernfs_remove() as the caller sees fit as long as the caller ensures that the node is accessible. The current behavior in such situations is broken. Whoever enters removal path first takes the node off the hierarchy and then deactivates. Following removers either return as soon as it notices that it's not the first one or can't even find the target node as it has already been removed from the hierarchy. In both cases, the following removers may finish prematurely while the nodes which should be removed and drained are still being processed by the first one. This patch restructures so that multiple removers, whether through recursion or direction invocation, always follow the following rules. * When there are multiple concurrent removers, only one puts the base ref. * Regardless of which one puts the base ref, all removers are blocked until the target node is fully deactivated and removed. To achieve the above, removal path now first deactivates the subtree, drains it and then unlinks one-by-one. __kernfs_deactivate() is called directly from __kernfs_removal() and drops and regrabs kernfs_mutex for each descendant to drain active refs. As this means that multiple removers can enter __kernfs_deactivate() for the same node, the function is updated so that it can handle multiple deactivators of the same node - only one actually deactivates but all wait till drain completion. The restructured removal path guarantees that a removed node gets unlinked only after the node is deactivated and drained. Combined with proper multiple deactivator handling, this guarantees that any invocation of kernfs_remove() returns only after the node itself and all its descendants are deactivated, drained and removed. v2: Draining separated into a separate loop (used to be in the same loop as unlink) and done from __kernfs_deactivate(). This is to allow exposing deactivation as a separate interface later. Root node removal was broken in v1 patch. Fixed. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 289d4f639ade..61bd7ae6b8e0 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,6 +37,7 @@ enum kernfs_node_type { #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { + KERNFS_JUST_DEACTIVATED = 0x0010, /* used to aid lockdep annotation */ KERNFS_NS = 0x0020, KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, -- cgit v1.2.2 From 99177a34110889a8f2c36420c34e3bcc9bfd8a70 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:24 -0500 Subject: kernfs: remove kernfs_addrm_cxt kernfs_addrm_cxt and the accompanying kernfs_addrm_start/finish() were added because there were operations which should be performed outside kernfs_mutex after adding and removing kernfs_nodes. The necessary operations were recorded in kernfs_addrm_cxt and performed by kernfs_addrm_finish(); however, after the recent changes which relocated deactivation and unmapping so that they're performed directly during removal, the only operation kernfs_addrm_finish() performs is kernfs_put(), which can be moved inside the removal path too. This patch moves the kernfs_put() of the base ref to __kernfs_remove() and remove kernfs_addrm_cxt and kernfs_addrm_start/finish(). * kernfs_add_one() is updated to grab and release the parent's active ref and kernfs_mutex itself. kernfs_get/put_active() and kernfs_addrm_start/finish() invocations around it are removed from all users. * __kernfs_remove() puts an unlinked node directly instead of chaining it to kernfs_addrm_cxt. Its callers are updated to grab and release kernfs_mutex instead of calling kernfs_addrm_start/finish() around it. v2: Updated to fit the v2 restructuring of removal path. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 61bd7ae6b8e0..9b5a4bb88c64 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -89,10 +89,6 @@ struct kernfs_node { struct rb_node rb; - union { - struct kernfs_node *removed_list; - } u; - const void *ns; /* namespace tag */ unsigned int hash; /* ns + name hash */ union { -- cgit v1.2.2 From 9f010c2ad5194a4b682e747984477850fabd03be Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:26 -0500 Subject: kernfs: implement kernfs_{de|re}activate[_self]() This patch implements four functions to manipulate deactivation state - deactivate, reactivate and the _self suffixed pair. A new fields kernfs_node->deact_depth is added so that concurrent and nested deactivations are handled properly. kernfs_node->hash is moved so that it's paired with the new field so that it doesn't increase the size of kernfs_node. A kernfs user's lock would normally nest inside active ref but during removal the user may want to perform kernfs_remove() while holding the said lock, which would introduce a reverse locking dependency. This function can be used to break such reverse dependency by allowing deactivation step to performed separately outside user's critical section. This will also be used implement kernfs_remove_self(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 9b5a4bb88c64..ac8693027058 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -80,6 +80,8 @@ struct kernfs_elem_attr { struct kernfs_node { atomic_t count; atomic_t active; + int deact_depth; + unsigned int hash; /* ns + name hash */ #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif @@ -90,7 +92,6 @@ struct kernfs_node { struct rb_node rb; const void *ns; /* namespace tag */ - unsigned int hash; /* ns + name hash */ union { struct kernfs_elem_dir dir; struct kernfs_elem_symlink symlink; @@ -233,6 +234,10 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target); +void kernfs_deactivate(struct kernfs_node *kn); +void kernfs_reactivate(struct kernfs_node *kn); +void kernfs_deactivate_self(struct kernfs_node *kn); +void kernfs_reactivate_self(struct kernfs_node *kn); void kernfs_remove(struct kernfs_node *kn); int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); -- cgit v1.2.2 From 1ae06819c77cff1ea2833c94f8c093fe8a5c79db Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:27 -0500 Subject: kernfs, sysfs, driver-core: implement kernfs_remove_self() and its wrappers Sometimes it's necessary to implement a node which wants to delete nodes including itself. This isn't straightforward because of kernfs active reference. While a file operation is in progress, an active reference is held and kernfs_remove() waits for all such references to drain before completing. For a self-deleting node, this is a deadlock as kernfs_remove() ends up waiting for an active reference that itself is sitting on top of. This currently is worked around in the sysfs layer using sysfs_schedule_callback() which makes such removals asynchronous. While it works, it's rather cumbersome and inherently breaks synchronicity of the operation - the file operation which triggered the operation may complete before the removal is finished (or even started) and the removal may fail asynchronously. If a removal operation is immmediately followed by another operation which expects the specific name to be available (e.g. removal followed by rename onto the same name), there's no way to make the latter operation reliable. The thing is there's no inherent reason for this to be asynchrnous. All that's necessary to do this synchronous is a dedicated operation which drops its own active ref and deactivates self. This patch implements kernfs_remove_self() and its wrappers in sysfs and driver core. kernfs_remove_self() is to be called from one of the file operations, drops the active ref and deactivates using __kernfs_deactivate_self(), removes the self node, and restores active ref to the dead node using __kernfs_reactivate_self() so that the ref is balanced afterwards. __kernfs_remove() is updated so that it takes an early exit if the target node is already fully removed so that the active ref restored by kernfs_remove_self() after removal doesn't confuse the deactivation path. This makes implementing self-deleting nodes very easy. The normal removal path doesn't even need to be changed to use kernfs_remove_self() for the self-deleting node. The method can invoke kernfs_remove_self() on itself before proceeding the normal removal path. kernfs_remove() invoked on the node by the normal deletion path will simply be ignored. This will replace sysfs_schedule_callback(). A subtle feature of sysfs_schedule_callback() is that it collapses multiple invocations - even if multiple removals are triggered, the removal callback is run only once. An equivalent effect can be achieved by testing the return value of kernfs_remove_self() - only the one which gets %true return value should proceed with actual deletion. All other instances of kernfs_remove_self() will wait till the enclosing kernfs operation which invoked the winning instance of kernfs_remove_self() finishes and then return %false. This trivially makes all users of kernfs_remove_self() automatically show correct synchronous behavior even when there are multiple concurrent operations - all "echo 1 > delete" instances will finish only after the whole operation is completed by one of the instances. v2: For !CONFIG_SYSFS, dummy version kernfs_remove_self() was missing and sysfs_remove_file_self() had incorrect return type. Fix it. Reported by kbuild test bot. v3: Updated to use __kernfs_{de|re}activate_self(). Signed-off-by: Tejun Heo Cc: Alan Stern Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index ac8693027058..0b7b7cc352eb 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -43,6 +43,8 @@ enum kernfs_node_flag { KERNFS_HAS_MMAP = 0x0080, KERNFS_LOCKDEP = 0x0100, KERNFS_STATIC_NAME = 0x0200, + KERNFS_SUICIDAL = 0x0400, + KERNFS_SUICIDED = 0x0800, }; /* type-specific structures for kernfs_node union members */ @@ -239,6 +241,7 @@ void kernfs_reactivate(struct kernfs_node *kn); void kernfs_deactivate_self(struct kernfs_node *kn); void kernfs_reactivate_self(struct kernfs_node *kn); void kernfs_remove(struct kernfs_node *kn); +bool kernfs_remove_self(struct kernfs_node *kn); int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, @@ -296,6 +299,9 @@ kernfs_create_link(struct kernfs_node *parent, const char *name, static inline void kernfs_remove(struct kernfs_node *kn) { } +static inline bool kernfs_remove_self(struct kernfs_node *kn) +{ return false; } + static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, const char *name, const void *ns) { return -ENOSYS; } -- cgit v1.2.2 From a9f138b0e537de55933335d580ebd38c2bc53c47 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:05:13 -0800 Subject: Revert "kernfs, sysfs, driver-core: implement kernfs_remove_self() and its wrappers" This reverts commit 1ae06819c77cff1ea2833c94f8c093fe8a5c79db. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Cc: Alan Stern Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 0b7b7cc352eb..ac8693027058 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -43,8 +43,6 @@ enum kernfs_node_flag { KERNFS_HAS_MMAP = 0x0080, KERNFS_LOCKDEP = 0x0100, KERNFS_STATIC_NAME = 0x0200, - KERNFS_SUICIDAL = 0x0400, - KERNFS_SUICIDED = 0x0800, }; /* type-specific structures for kernfs_node union members */ @@ -241,7 +239,6 @@ void kernfs_reactivate(struct kernfs_node *kn); void kernfs_deactivate_self(struct kernfs_node *kn); void kernfs_reactivate_self(struct kernfs_node *kn); void kernfs_remove(struct kernfs_node *kn); -bool kernfs_remove_self(struct kernfs_node *kn); int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, @@ -299,9 +296,6 @@ kernfs_create_link(struct kernfs_node *parent, const char *name, static inline void kernfs_remove(struct kernfs_node *kn) { } -static inline bool kernfs_remove_self(struct kernfs_node *kn) -{ return false; } - static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, const char *name, const void *ns) { return -ENOSYS; } -- cgit v1.2.2 From 9b0925a6ff64a33be45497e3c798bfee8790b102 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:09:38 -0800 Subject: Revert "kernfs: implement kernfs_{de|re}activate[_self]()" This reverts commit 9f010c2ad5194a4b682e747984477850fabd03be. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index ac8693027058..9b5a4bb88c64 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -80,8 +80,6 @@ struct kernfs_elem_attr { struct kernfs_node { atomic_t count; atomic_t active; - int deact_depth; - unsigned int hash; /* ns + name hash */ #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif @@ -92,6 +90,7 @@ struct kernfs_node { struct rb_node rb; const void *ns; /* namespace tag */ + unsigned int hash; /* ns + name hash */ union { struct kernfs_elem_dir dir; struct kernfs_elem_symlink symlink; @@ -234,10 +233,6 @@ struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target); -void kernfs_deactivate(struct kernfs_node *kn); -void kernfs_reactivate(struct kernfs_node *kn); -void kernfs_deactivate_self(struct kernfs_node *kn); -void kernfs_reactivate_self(struct kernfs_node *kn); void kernfs_remove(struct kernfs_node *kn); int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); -- cgit v1.2.2 From 7653fe9d6cddc3fc5e4220608079006d8ac0054c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:20:56 -0800 Subject: Revert "kernfs: remove kernfs_addrm_cxt" This reverts commit 99177a34110889a8f2c36420c34e3bcc9bfd8a70. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 9b5a4bb88c64..61bd7ae6b8e0 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -89,6 +89,10 @@ struct kernfs_node { struct rb_node rb; + union { + struct kernfs_node *removed_list; + } u; + const void *ns; /* namespace tag */ unsigned int hash; /* ns + name hash */ union { -- cgit v1.2.2 From 4f4b1b6471cf219d136776f9ff9631a07c4e92b5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:30:47 -0800 Subject: Revert "kernfs: restructure removal path to fix possible premature return" This reverts commit 45a140e587f3d32d8d424ed940dffb61e1739047. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 61bd7ae6b8e0..289d4f639ade 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,7 +37,6 @@ enum kernfs_node_type { #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { - KERNFS_JUST_DEACTIVATED = 0x0010, /* used to aid lockdep annotation */ KERNFS_NS = 0x0020, KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, -- cgit v1.2.2 From 798c75a0d44cdbd6e3d82a6a676e6de38525b3bb Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:36:03 -0800 Subject: Revert "kernfs: remove KERNFS_REMOVED" This reverts commit ae34372eb8408b3d07e870f1939f99007a730d28. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 289d4f639ade..42ad32ff22f8 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,6 +37,7 @@ enum kernfs_node_type { #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { + KERNFS_REMOVED = 0x0010, KERNFS_NS = 0x0020, KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, -- cgit v1.2.2 From 0890147fe09ff7e8275a162b1ab76ab5e3158c6d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:39:52 -0800 Subject: Revert "kernfs: remove KERNFS_ACTIVE_REF and add kernfs_lockdep()" This reverts commit a69d001cfc712b96ec9d7ba44d6285702a38dabf. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 42ad32ff22f8..232f1a632383 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -34,6 +34,7 @@ enum kernfs_node_type { }; #define KERNFS_TYPE_MASK 0x000f +#define KERNFS_ACTIVE_REF KERNFS_FILE #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { -- cgit v1.2.2 From 87da149343c8c93f6984c0f4b9da7651709624f7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Jan 2014 14:43:11 -0800 Subject: Revert "kernfs: replace kernfs_node->u.completion with kernfs_root->deactivate_waitq" This reverts commit ea1c472dfeada211a0100daa7976e8e8e779b858. Tejun writes: I'm sorry but can you please revert the whole series? get_active() waiting while a node is deactivated has potential to lead to deadlock and that deactivate/reactivate interface is something fundamentally flawed and that cgroup will have to work with the remove_self() like everybody else. IOW, I think the first posting was correct. Cc: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 232f1a632383..d2c439db4efa 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include struct file; struct iattr; @@ -91,6 +91,7 @@ struct kernfs_node { struct rb_node rb; union { + struct completion *completion; struct kernfs_node *removed_list; } u; @@ -131,7 +132,6 @@ struct kernfs_root { /* private fields, do not use outside kernfs proper */ struct ida ino_ida; struct kernfs_dir_ops *dir_ops; - wait_queue_head_t deactivate_waitq; }; struct kernfs_open_file { -- cgit v1.2.2 From 917f56caaabc215f9658006dad28a9665ec0ce19 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 17 Jan 2014 09:57:49 -0500 Subject: kernfs: add struct dentry declaration in kernfs.h Hello, Greg. Two misc fixes for kernfs. Thanks. ------- 8< ------- struct dentry is used in kernfs.h but its declaration was missing, leading to compilation errors unless its declaration gets pulled in in some other way. Add the declaration. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/kernfs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux/kernfs.h') diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d2c439db4efa..5be9f0228a3b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -18,6 +18,7 @@ #include struct file; +struct dentry; struct iattr; struct seq_file; struct vm_area_struct; -- cgit v1.2.2