diff --git a/drivers/char/misc.c b/drivers/char/misc.c index cba19bfdc44d..b9a494bc4228 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -100,49 +100,39 @@ static const struct seq_operations misc_seq_ops = { static int misc_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct miscdevice *c = NULL, *iter; + struct miscdevice *iter; int err = -ENODEV; const struct file_operations *new_fops = NULL; + bool retried = false; - mutex_lock(&misc_mtx); - + retry: + if (mutex_lock_killable(&misc_mtx)) + return -EINTR; list_for_each_entry(iter, &misc_list, list) { if (iter->minor != minor) continue; - c = iter; new_fops = fops_get(iter->fops); + if (!new_fops) + break; + /* + * Place the miscdevice in the file's + * private_data so it can be used by the + * file operations, including f_op->open below + */ + file->private_data = iter; + + err = 0; + replace_fops(file, new_fops); + if (file->f_op->open) + err = file->f_op->open(inode, file); break; } - - if (!new_fops) { - mutex_unlock(&misc_mtx); + mutex_unlock(&misc_mtx); + if (!new_fops && !retried) { request_module("char-major-%d-%d", MISC_MAJOR, minor); - mutex_lock(&misc_mtx); - - list_for_each_entry(iter, &misc_list, list) { - if (iter->minor != minor) - continue; - c = iter; - new_fops = fops_get(iter->fops); - break; - } - if (!new_fops) - goto fail; + retried = true; + goto retry; } - - /* - * Place the miscdevice in the file's - * private_data so it can be used by the - * file operations, including f_op->open below - */ - file->private_data = c; - - err = 0; - replace_fops(file, new_fops); - if (file->f_op->open) - err = file->f_op->open(inode, file); -fail: - mutex_unlock(&misc_mtx); return err; } @@ -180,7 +170,8 @@ int misc_register(struct miscdevice *misc) INIT_LIST_HEAD(&misc->list); - mutex_lock(&misc_mtx); + if (mutex_lock_killable(&misc_mtx)) + return -EINTR; if (is_dynamic) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);