Commit 95904475 authored by Russell King's avatar Russell King

[MMC] Fix mmc_block suspend/resume handling (again).

The previous change is not the whole story - the mmc queue
thread may be handling a request.  We must wait for outstanding
requests to complete before allowing the suspend to proceed,
otherwise we may suffer loss of data.
parent e7f10a52
...@@ -428,11 +428,7 @@ static int mmc_blk_suspend(struct mmc_card *card, u32 state) ...@@ -428,11 +428,7 @@ static int mmc_blk_suspend(struct mmc_card *card, u32 state)
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) { if (md) {
unsigned long flags; mmc_queue_suspend(&md->queue);
spin_lock_irqsave(&md->lock, flags);
blk_stop_queue(md->queue.queue);
spin_unlock_irqrestore(&md->lock, flags);
} }
return 0; return 0;
} }
...@@ -442,12 +438,8 @@ static int mmc_blk_resume(struct mmc_card *card) ...@@ -442,12 +438,8 @@ static int mmc_blk_resume(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) { if (md) {
unsigned long flags;
mmc_blk_set_blksize(md, card); mmc_blk_set_blksize(md, card);
spin_lock_irqsave(&md->lock, flags); mmc_queue_resume(&md->queue);
blk_start_queue(md->queue.queue);
spin_unlock_irqrestore(&md->lock, flags);
} }
return 0; return 0;
} }
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include "mmc_queue.h" #include "mmc_queue.h"
#define MMC_QUEUE_EXIT (1 << 0)
#define MMC_QUEUE_SUSPENDED (1 << 1)
/* /*
* Prepare a MMC request. Essentially, this means passing the * Prepare a MMC request. Essentially, this means passing the
* preparation off to the media driver. The media driver will * preparation off to the media driver. The media driver will
...@@ -66,14 +69,9 @@ static int mmc_queue_thread(void *d) ...@@ -66,14 +69,9 @@ static int mmc_queue_thread(void *d)
daemonize("mmcqd"); daemonize("mmcqd");
spin_lock_irq(&current->sighand->siglock);
sigfillset(&current->blocked);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
mq->thread = current;
complete(&mq->thread_complete); complete(&mq->thread_complete);
down(&mq->thread_sem);
add_wait_queue(&mq->thread_wq, &wait); add_wait_queue(&mq->thread_wq, &wait);
do { do {
struct request *req = NULL; struct request *req = NULL;
...@@ -85,9 +83,11 @@ static int mmc_queue_thread(void *d) ...@@ -85,9 +83,11 @@ static int mmc_queue_thread(void *d)
spin_unlock(q->queue_lock); spin_unlock(q->queue_lock);
if (!req) { if (!req) {
if (!mq->thread) if (mq->flags & MMC_QUEUE_EXIT)
break; break;
up(&mq->thread_sem);
schedule(); schedule();
down(&mq->thread_sem);
continue; continue;
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
...@@ -95,6 +95,7 @@ static int mmc_queue_thread(void *d) ...@@ -95,6 +95,7 @@ static int mmc_queue_thread(void *d)
mq->issue_fn(mq, req); mq->issue_fn(mq, req);
} while (1); } while (1);
remove_wait_queue(&mq->thread_wq, &wait); remove_wait_queue(&mq->thread_wq, &wait);
up(&mq->thread_sem);
complete_and_exit(&mq->thread_complete, 0); complete_and_exit(&mq->thread_complete, 0);
return 0; return 0;
...@@ -160,17 +161,61 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock ...@@ -160,17 +161,61 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
return ret; return ret;
} }
EXPORT_SYMBOL(mmc_init_queue); EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq) void mmc_cleanup_queue(struct mmc_queue *mq)
{ {
mq->thread = NULL; mq->flags |= MMC_QUEUE_EXIT;
wake_up(&mq->thread_wq); wake_up(&mq->thread_wq);
wait_for_completion(&mq->thread_complete); wait_for_completion(&mq->thread_complete);
blk_cleanup_queue(mq->queue); blk_cleanup_queue(mq->queue);
mq->card = NULL; mq->card = NULL;
} }
EXPORT_SYMBOL(mmc_cleanup_queue); EXPORT_SYMBOL(mmc_cleanup_queue);
/**
* mmc_queue_suspend - suspend a MMC request queue
* @mq: MMC queue to suspend
*
* Stop the block request queue, and wait for our thread to
* complete any outstanding requests. This ensures that we
* won't suspend while a request is being processed.
*/
void mmc_queue_suspend(struct mmc_queue *mq)
{
request_queue_t *q = mq->queue;
unsigned long flags;
if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
mq->flags |= MMC_QUEUE_SUSPENDED;
spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
down(&mq->thread_sem);
}
}
EXPORT_SYMBOL(mmc_queue_suspend);
/**
* mmc_queue_resume - resume a previously suspended MMC request queue
* @mq: MMC queue to resume
*/
void mmc_queue_resume(struct mmc_queue *mq)
{
request_queue_t *q = mq->queue;
unsigned long flags;
if (mq->flags & MMC_QUEUE_SUSPENDED) {
mq->flags &= ~MMC_QUEUE_SUSPENDED;
up(&mq->thread_sem);
spin_lock_irqsave(q->queue_lock, flags);
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
}
EXPORT_SYMBOL(mmc_queue_resume);
...@@ -8,7 +8,8 @@ struct mmc_queue { ...@@ -8,7 +8,8 @@ struct mmc_queue {
struct mmc_card *card; struct mmc_card *card;
struct completion thread_complete; struct completion thread_complete;
wait_queue_head_t thread_wq; wait_queue_head_t thread_wq;
struct task_struct *thread; struct semaphore thread_sem;
unsigned int flags;
struct request *req; struct request *req;
int (*prep_fn)(struct mmc_queue *, struct request *); int (*prep_fn)(struct mmc_queue *, struct request *);
int (*issue_fn)(struct mmc_queue *, struct request *); int (*issue_fn)(struct mmc_queue *, struct request *);
...@@ -25,5 +26,7 @@ struct mmc_io_request { ...@@ -25,5 +26,7 @@ struct mmc_io_request {
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *); extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
extern void mmc_cleanup_queue(struct mmc_queue *); extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment