Bug 8334

Summary: smu_release() calls schedule while holding a spinlock
Product: Drivers Reporter: Matthias Kaehlcke (matthias.kaehlcke)
Component: OtherAssignee: drivers_other
Status: RESOLVED CODE_FIX    
Severity: normal    
Priority: P2    
Hardware: i386   
OS: Linux   
Kernel Version: 2.6.20 Subsystem:
Regression: --- Bisected commit-id:

Description Matthias Kaehlcke 2007-04-16 01:49:37 UTC
Problem Description:

smu_release() in drivers/macintosh/smu.c calls schedule() while holding the
spinlock pp->lock. AFAIK this should not be done as schedule() might sleep.

further the code might produce a deadlock, in certain conditions pp->lock is
acquired recursivly, first at the beginning of the function, then inside the for
(;;) loop

static int smu_release(struct inode *inode, struct file *file)
{
        struct smu_private *pp = file->private_data;
        unsigned long flags;
        unsigned int busy;

        if (pp == 0)
                return 0;

        file->private_data = NULL;

        /* Mark file as closing to avoid races with new request */
        spin_lock_irqsave(&pp->lock, flags);
        pp->mode = smu_file_closing;
        busy = pp->busy;

        /* Wait for any pending request to complete */
        if (busy && pp->cmd.status == 1) {
                DECLARE_WAITQUEUE(wait, current);

                add_wait_queue(&pp->wait, &wait);
                for (;;) {
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        if (pp->cmd.status != 1)
                                break;
                       spin_lock_irqsave(&pp->lock, flags);
                        schedule();
                        spin_unlock_irqrestore(&pp->lock, flags);
                }
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&pp->wait, &wait);
        }
        spin_unlock_irqrestore(&pp->lock, flags);

        spin_lock_irqsave(&smu_clist_lock, flags);
        list_del(&pp->list);
        spin_unlock_irqrestore(&smu_clist_lock, flags);
        kfree(pp);

        return 0;
}
Comment 1 Andrew Morton 2007-04-16 09:27:16 UTC
I queued a fix, thanks.