Index: usb-devel/drivers/media/usb/usbvision/usbvision-video.c =================================================================== --- usb-devel.orig/drivers/media/usb/usbvision/usbvision-video.c +++ usb-devel/drivers/media/usb/usbvision/usbvision-video.c @@ -131,6 +131,33 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(USBVISION_VERSION_STRING); MODULE_ALIAS(DRIVER_ALIAS); +#include +#include + +extern void ASadd(struct kernfs_node *parent); +extern void ASremove(struct kernfs_node *parent); + +static int usbvision_check(struct usb_usbvision *usbvision, char *msg) +{ + struct kernfs_node *kn; + + if (!video_is_registered(&usbvision->rdev)) { + dev_info(&usbvision->rdev.dev, "AS Not registered: %s\n", msg); + } else if (!usbvision->rdev.dev.kobj.sd->dir.children.rb_node) { + dev_info(&usbvision->rdev.dev, "AS Node erased: %s\n", msg); + } else { + kn = kernfs_find_and_get(usbvision->rdev.dev.kobj.sd, "power"); + if (kn) { + kernfs_put(kn); + dev_info(&usbvision->rdev.dev, "AS Power ok: %s\n", msg); + } else { + dev_err(&usbvision->rdev.dev, "AS Power gone: %s\n", msg); + return 1; + } + } + return 0; +} + /*****************************************************************************/ /* SYSFS Code - Copied from the stv680.c usb module. */ @@ -314,6 +341,10 @@ static int usbvision_v4l2_open(struct fi if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto unlock; + } if (usbvision->user) { err_code = -EBUSY; } else { @@ -377,6 +408,7 @@ unlock: static int usbvision_v4l2_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, "close"); @@ -391,9 +423,10 @@ static int usbvision_v4l2_close(struct f usbvision_scratch_free(usbvision); usbvision->user--; + r = usbvision->remove_pending; mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); return 0; @@ -453,6 +486,9 @@ static int vidioc_querycap(struct file * { struct usb_usbvision *usbvision = video_drvdata(file); + if (!usbvision->dev) + return -ENODEV; + strscpy(vc->driver, "USBVision", sizeof(vc->driver)); strscpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, @@ -1073,6 +1109,11 @@ static int usbvision_radio_open(struct f if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto out; + } err_code = v4l2_fh_open(file); if (err_code) goto out; @@ -1105,21 +1146,28 @@ out: static int usbvision_radio_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, ""); + usbvision_check(usbvision, "radio close 1"); mutex_lock(&usbvision->v4l2_lock); + usbvision_check(usbvision, "radio close 2"); /* Set packet size to 0 */ usbvision->iface_alt = 0; - usb_set_interface(usbvision->dev, usbvision->iface, + if (usbvision->dev) + usb_set_interface(usbvision->dev, usbvision->iface, usbvision->iface_alt); + usbvision_check(usbvision, "radio close 3"); usbvision_audio_off(usbvision); usbvision->radio = 0; usbvision->user--; + r = usbvision->remove_pending; + usbvision_check(usbvision, "radio close 4"); mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); v4l2_fh_release(file); usbvision_release(usbvision); @@ -1236,6 +1284,8 @@ static void usbvision_unregister_video(s if (video_is_registered(&usbvision->rdev)) { PDEBUG(DBG_PROBE, "unregister %s [v4l2]", video_device_node_name(&usbvision->rdev)); + usbvision_check(usbvision, "unregister_video"); + ASremove(usbvision->rdev.dev.kobj.sd); video_unregister_device(&usbvision->rdev); } @@ -1283,6 +1333,7 @@ static int usbvision_register_video(stru usbvision->nr, video_device_node_name(&usbvision->rdev)); } /* all done */ + ASadd(usbvision->rdev.dev.kobj.sd); return 0; err_exit: @@ -1551,6 +1602,7 @@ err_usb: static void usbvision_disconnect(struct usb_interface *intf) { struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf)); + int u; PDEBUG(DBG_PROBE, ""); @@ -1567,13 +1619,14 @@ static void usbvision_disconnect(struct v4l2_device_disconnect(&usbvision->v4l2_dev); usbvision_i2c_unregister(usbvision); usbvision->remove_pending = 1; /* Now all ISO data will be ignored */ + u = usbvision->user; usb_put_dev(usbvision->dev); usbvision->dev = NULL; /* USB device is no more */ mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->user) { + if (u) { printk(KERN_INFO "%s: In use, disconnect pending\n", __func__); wake_up_interruptible(&usbvision->wait_frame); Index: usb-devel/fs/kernfs/dir.c =================================================================== --- usb-devel.orig/fs/kernfs/dir.c +++ usb-devel/fs/kernfs/dir.c @@ -25,6 +25,64 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) +#define ASMAX 100 +static struct rb_node **ASlist[ASMAX]; +static int ASnum; + +static DEFINE_MUTEX(ASmutex); + +void ASadd(struct kernfs_node *parent) +{ + int i; + + mutex_lock(&ASmutex); + for (i = 0; i < ASnum; ++i) { + if (!ASlist[i]) + break; + } + if (i == ASnum && ASnum < ASMAX) + ++ASnum; + if (i < ASnum) { + ASlist[i] = &parent->dir.children.rb_node; + printk(KERN_INFO "AS Adding %s: %px %px\n", + parent->name, ASlist[i], *ASlist[i]); + } + mutex_unlock(&ASmutex); +} +EXPORT_SYMBOL_GPL(ASadd); + +void ASremove(struct kernfs_node *parent) +{ + int i; + struct rb_node **r = &parent->dir.children.rb_node; + + mutex_lock(&ASmutex); + for (i = 0; i < ASnum; ++i) { + if (ASlist[i] == r) { + ASlist[i] = NULL; + break; + } + } + mutex_unlock(&ASmutex); +} +EXPORT_SYMBOL_GPL(ASremove); + +void AScheck(void) +{ + int i; + + mutex_lock(&ASmutex); + for (i = 0; i < ASnum; ++i) { + if (ASlist[i] && !*ASlist[i]) { + printk(KERN_INFO "AS rb_mode erased at %px\n", + ASlist[i]); + dump_stack(); + ASlist[i] = NULL; + } + } + mutex_unlock(&ASmutex); +} + static bool kernfs_active(struct kernfs_node *kn) { lockdep_assert_held(&kernfs_mutex); @@ -462,6 +520,7 @@ static void kernfs_drain(struct kernfs_n lockdep_assert_held(&kernfs_mutex); WARN_ON_ONCE(kernfs_active(kn)); + AScheck(); mutex_unlock(&kernfs_mutex); if (kernfs_lockdep(kn)) { @@ -586,9 +645,11 @@ static int kernfs_dop_revalidate(struct kernfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; + AScheck(); mutex_unlock(&kernfs_mutex); return 1; out_bad: + AScheck(); mutex_unlock(&kernfs_mutex); out_bad_unlocked: return 0; @@ -800,6 +861,7 @@ int kernfs_add_one(struct kernfs_node *k ps_iattrs->ia_mtime = ps_iattrs->ia_ctime; } + AScheck(); mutex_unlock(&kernfs_mutex); /* @@ -814,6 +876,7 @@ int kernfs_add_one(struct kernfs_node *k return 0; out_unlock: + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -910,6 +973,7 @@ struct kernfs_node *kernfs_find_and_get_ mutex_lock(&kernfs_mutex); kn = kernfs_find_ns(parent, name, ns); kernfs_get(kn); + AScheck(); mutex_unlock(&kernfs_mutex); return kn; @@ -934,6 +998,7 @@ struct kernfs_node *kernfs_walk_and_get_ mutex_lock(&kernfs_mutex); kn = kernfs_walk_ns(parent, path, ns); kernfs_get(kn); + AScheck(); mutex_unlock(&kernfs_mutex); return kn; @@ -1102,6 +1167,7 @@ static struct dentry *kernfs_iop_lookup( /* instantiate and hash dentry */ ret = d_splice_alias(inode, dentry); out_unlock: + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -1271,6 +1337,7 @@ void kernfs_activate(struct kernfs_node pos->flags |= KERNFS_ACTIVATED; } + AScheck(); mutex_unlock(&kernfs_mutex); } @@ -1351,6 +1418,7 @@ void kernfs_remove(struct kernfs_node *k { mutex_lock(&kernfs_mutex); __kernfs_remove(kn); + AScheck(); mutex_unlock(&kernfs_mutex); } @@ -1466,6 +1534,7 @@ bool kernfs_remove_self(struct kernfs_no atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) break; + AScheck(); mutex_unlock(&kernfs_mutex); schedule(); mutex_lock(&kernfs_mutex); @@ -1481,6 +1550,7 @@ bool kernfs_remove_self(struct kernfs_no */ kernfs_unbreak_active_protection(kn); + AScheck(); mutex_unlock(&kernfs_mutex); return ret; } @@ -1511,6 +1581,7 @@ int kernfs_remove_by_name_ns(struct kern if (kn) __kernfs_remove(kn); + AScheck(); mutex_unlock(&kernfs_mutex); if (kn) @@ -1591,6 +1662,7 @@ int kernfs_rename_ns(struct kernfs_node error = 0; out: + AScheck(); mutex_unlock(&kernfs_mutex); return error; } @@ -1683,11 +1755,13 @@ static int kernfs_fop_readdir(struct fil file->private_data = pos; kernfs_get(pos); + AScheck(); mutex_unlock(&kernfs_mutex); if (!dir_emit(ctx, name, len, ino, type)) return 0; mutex_lock(&kernfs_mutex); } + AScheck(); mutex_unlock(&kernfs_mutex); file->private_data = NULL; ctx->pos = INT_MAX; Index: usb-devel/fs/kernfs/kernfs-internal.h =================================================================== --- usb-devel.orig/fs/kernfs/kernfs-internal.h +++ usb-devel/fs/kernfs/kernfs-internal.h @@ -19,6 +19,8 @@ #include #include +extern void AScheck(void); + struct kernfs_iattrs { struct iattr ia_iattr; void *ia_secdata; Index: usb-devel/fs/kernfs/mount.c =================================================================== --- usb-devel.orig/fs/kernfs/mount.c +++ usb-devel/fs/kernfs/mount.c @@ -235,6 +235,7 @@ static int kernfs_fill_super(struct supe /* get root inode, initialize and unlock it */ mutex_lock(&kernfs_mutex); inode = kernfs_get_inode(sb, info->root->kn); + AScheck(); mutex_unlock(&kernfs_mutex); if (!inode) { pr_debug("kernfs: could not get root inode\n"); @@ -324,6 +325,7 @@ int kernfs_get_tree(struct fs_context *f mutex_lock(&kernfs_mutex); list_add(&info->node, &info->root->supers); + AScheck(); mutex_unlock(&kernfs_mutex); } @@ -352,6 +354,7 @@ void kernfs_kill_sb(struct super_block * mutex_lock(&kernfs_mutex); list_del(&info->node); + AScheck(); mutex_unlock(&kernfs_mutex); /* Index: usb-devel/fs/kernfs/symlink.c =================================================================== --- usb-devel.orig/fs/kernfs/symlink.c +++ usb-devel/fs/kernfs/symlink.c @@ -119,6 +119,7 @@ static int kernfs_getlink(struct inode * mutex_lock(&kernfs_mutex); error = kernfs_get_target_path(parent, target, path); + AScheck(); mutex_unlock(&kernfs_mutex); return error;