Messages in this thread Patch in this message | | | From | (Eric W. Biederman) | Subject | [PATCH] sysfs: Optionally count subdirectories to support buggy applications | Date | Wed, 01 Feb 2012 14:21:59 -0800 |
| |
lm_sensors and possibly other applications get confused if all sysfs directories return nlink == 1. The lm_sensors code that got confused was just wrong and a fixed version of lm_sensors should be released shortly.
There may be other applications that have problems with sysfs return nlink == 1 for directories. To allow people to continue to use old versions of userspace with new kernels add to sysfs a compile time option to maintain mostly precise directory counts for those people who don't mind the cost.
I have moved where we keep nlink in sysfs_dirent as compared to previous versions of subdirectory counting to a location that packs better.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> --- fs/sysfs/Kconfig | 15 +++++++++++++++ fs/sysfs/dir.c | 8 ++++++++ fs/sysfs/inode.c | 2 ++ fs/sysfs/sysfs.h | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/fs/sysfs/Kconfig b/fs/sysfs/Kconfig index 8c41fea..9b403e9 100644 --- a/fs/sysfs/Kconfig +++ b/fs/sysfs/Kconfig @@ -21,3 +21,18 @@ config SYSFS example, "root=03:01" for /dev/hda1. Designers of embedded systems may wish to say N here to conserve space. + +config SYSFS_COUNT_LINKS + bool "sysfs count subdirectoires to support buggy applications" + default n + help + + Increase the memory and cpu untilization of sysfs by maintaining + by maintaining a count of how hard links from subdirectories a + directory has. This allows sysfs to report the directory nlink + as the number of subdirectories plus two. With out this enabled + sysfs will report the nlink of all directories as 1, which is + the standard way of indicating that the number of subdirectoires + is not tracked. + + Unless you know you need this say N here. diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index dd3779c..f30df7c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -91,6 +91,9 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd) struct rb_node **node = &sd->s_parent->s_dir.children.rb_node; struct rb_node *parent = NULL; + if (sysfs_type(sd) == SYSFS_DIR) + sysfs_inc_nlink(sd->s_parent); + while (*node) { struct sysfs_dirent *pos; int result; @@ -123,6 +126,9 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd) */ static void sysfs_unlink_sibling(struct sysfs_dirent *sd) { + if (sysfs_type(sd) == SYSFS_DIR) + sysfs_dec_nlink(sd->s_parent); + rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); } @@ -367,6 +373,8 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) sd->s_mode = mode; sd->s_flags = type; + sysfs_init_nlink(sd); + return sd; err_out2: diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 4291fd1..782c66a 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -216,6 +216,8 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) iattrs->ia_secdata, iattrs->ia_secdata_len); } + + set_nlink(inode, sysfs_read_nlink(sd)); } int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6289a00..4603506 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -69,6 +69,9 @@ struct sysfs_dirent { const void *s_ns; /* namespace tag */ unsigned int s_hash; /* ns + name hash */ +#ifdef CONFIG_SYSFS_COUNT_LINKS + unsigned int s_nlink; +#endif union { struct sysfs_elem_dir s_dir; struct sysfs_elem_symlink s_symlink; @@ -127,6 +130,41 @@ do { \ #define sysfs_dirent_init_lockdep(sd) do {} while(0) #endif +#ifdef CONFIG_SYSFS_COUNT_LINKS +static inline void sysfs_init_nlink(struct sysfs_dirent *sd) +{ + if (sysfs_type(sd) == SYSFS_DIR) + sd->s_nlink = 2; + else + sd->s_nlink = 1; +} +static inline void sysfs_inc_nlink(struct sysfs_dirent *sd) +{ + sd->s_nlink++; +} +static inline void sysfs_dec_nlink(struct sysfs_dirent *sd) +{ + sd->s_nlink++; +} +static inline unsigned int sysfs_read_nlink(struct sysfs_dirent *sd) +{ + return sd->s_nlink; +} +#else +static inline void sysfs_init_nlink(struct sysfs_dirent *sd) +{ +} +static inline void sysfs_inc_nlink(struct sysfs_dirent *sd) +{ +} +static inline void sysfs_dec_nlink(struct sysfs_dirent *sd) +{ +} +static inline unsigned int sysfs_read_nlink(struct sysfs_dirent *sd) +{ + return 1; +} +#endif /* * Context structure to be used while adding/removing nodes. */ -- 1.7.2.5
| |