Hello, Miles Lane wrote: > XXX sysfs_deactivate: sd=c36ba6c0 s_sibling=6b6b6b6b s_flags=0x6b6b6b6b > ------------[ cut here ]------------ > kernel BUG at fs/sysfs/dir.c:274! OIC, ref counter is too low by one. The sysfs_dirent is probably getting freed on sysfs_drop_dentry(). Hmmm... Where did I screw up? Can you apply the attached patch and report the log after oops? It shouldn't generate too much output. Thanks. -- tejun
--- fs/sysfs/dir.c | 43 +++++++++++++++++++++++++++++++++++++++++++ fs/sysfs/sysfs.h | 16 ++-------------- include/linux/sysfs.h | 3 +++ net/core/net-sysfs.c | 6 +++++- 4 files changed, 53 insertions(+), 15 deletions(-) Index: tree0/fs/sysfs/dir.c =================================================================== --- tree0.orig/fs/sysfs/dir.c +++ tree0/fs/sysfs/dir.c @@ -11,15 +11,52 @@ #include <linux/namei.h> #include <linux/idr.h> #include <linux/completion.h> +#include <linux/kallsyms.h> #include <asm/semaphore.h> #include "sysfs.h" +struct kobject *sysfs_debug_me; + DEFINE_MUTEX(sysfs_mutex); spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED; static DEFINE_IDA(sysfs_ino_ida); +struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) +{ + if (sd) { + if (sd->s_flags & SYSFS_FLAG_XXX) { + char c0[KSYM_NAME_LEN], c1[KSYM_NAME_LEN]; + + lookup_symbol_name((unsigned long)__builtin_return_address(0), c0); + lookup_symbol_name((unsigned long)__builtin_return_address(1), c1); + + printk("sysfs_get(%s): cnt=%d++ called from %s:%s\n", + sd->s_name, atomic_read(&sd->s_count), c0, c1); + } + WARN_ON(!atomic_read(&sd->s_count)); + atomic_inc(&sd->s_count); + } + return sd; +} + +void sysfs_put(struct sysfs_dirent * sd) +{ + if (sd && sd->s_flags & SYSFS_FLAG_XXX) { + char c0[KSYM_NAME_LEN], c1[KSYM_NAME_LEN]; + + lookup_symbol_name((unsigned long)__builtin_return_address(0), c0); + lookup_symbol_name((unsigned long)__builtin_return_address(1), c1); + + printk("sysfs_put(%s): cnt=%d-- called from %s:%s\n", + sd->s_name, atomic_read(&sd->s_count), c0, c1); + } + + if (sd && atomic_dec_and_test(&sd->s_count)) + release_sysfs_dirent(sd); +} + /** * sysfs_link_sibling - link sysfs_dirent into sibling list * @sd: sysfs_dirent of interest @@ -317,6 +354,10 @@ void release_sysfs_dirent(struct sysfs_d * sd->s_parent won't change beneath us. */ parent_sd = sd->s_parent; + if (parent_sd->s_flags & SYSFS_FLAG_XXX) + printk("put from release(%s): cnt=%d-- (rel=%s)\n", + parent_sd->s_name, atomic_read(&parent_sd->s_count), + sd->s_name); if (sysfs_type(sd) == SYSFS_KOBJ_LINK) sysfs_put(sd->s_elem.symlink.target_sd); @@ -695,6 +736,8 @@ static int create_dir(struct kobject *ko if (!sd) return -ENOMEM; sd->s_elem.dir.kobj = kobj; + if (sysfs_debug_me && sysfs_debug_me == kobj) + sd->s_flags |= SYSFS_FLAG_XXX; /* link in */ sysfs_addrm_start(&acxt, parent_sd); Index: tree0/fs/sysfs/sysfs.h =================================================================== --- tree0.orig/fs/sysfs/sysfs.h +++ tree0/fs/sysfs/sysfs.h @@ -108,20 +108,8 @@ static inline unsigned int sysfs_type(st return sd->s_flags & SYSFS_TYPE_MASK; } -static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd) -{ - if (sd) { - WARN_ON(!atomic_read(&sd->s_count)); - atomic_inc(&sd->s_count); - } - return sd; -} - -static inline void sysfs_put(struct sysfs_dirent * sd) -{ - if (sd && atomic_dec_and_test(&sd->s_count)) - release_sysfs_dirent(sd); -} +struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd); +void sysfs_put(struct sysfs_dirent * sd); static inline int sysfs_is_shadowed_inode(struct inode *inode) { Index: tree0/include/linux/sysfs.h =================================================================== --- tree0.orig/include/linux/sysfs.h +++ tree0/include/linux/sysfs.h @@ -87,9 +87,12 @@ struct sysfs_ops { #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK #define SYSFS_FLAG_REMOVED 0x0100 +#define SYSFS_FLAG_XXX 0x0200 #ifdef CONFIG_SYSFS +extern struct kobject *sysfs_debug_me; + extern int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), void *data, struct module *owner); Index: tree0/net/core/net-sysfs.c =================================================================== --- tree0.orig/net/core/net-sysfs.c +++ tree0/net/core/net-sysfs.c @@ -472,6 +472,7 @@ int netdev_register_sysfs(struct net_dev { struct device *dev = &(net->dev); struct attribute_group **groups = net->sysfs_groups; + int rc; device_initialize(dev); dev->class = &net_class; @@ -489,7 +490,10 @@ int netdev_register_sysfs(struct net_dev *groups++ = &wireless_group; #endif - return device_add(dev); + sysfs_debug_me = &dev->kobj; + rc = device_add(dev); + sysfs_debug_me = NULL; + return rc; } int netdev_sysfs_init(void)