Bug 8334 - smu_release() calls schedule while holding a spinlock
Summary: smu_release() calls schedule while holding a spinlock
Status: RESOLVED CODE_FIX
Alias: None
Product: Drivers
Classification: Unclassified
Component: Other (show other bugs)
Hardware: i386 Linux
: P2 normal
Assignee: drivers_other
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-04-16 01:49 UTC by Matthias Kaehlcke
Modified: 2007-04-16 09:27 UTC (History)
0 users

See Also:
Kernel Version: 2.6.20
Subsystem:
Regression: ---
Bisected commit-id:


Attachments

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.

Note You need to log in before you can comment on or make changes to this bug.