git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git]
/
drivers
/
md
/
kcopyd.c
diff --git
a/drivers/md/kcopyd.c
b/drivers/md/kcopyd.c
index
eb70364
..
b46f6c5
100644
(file)
--- a/
drivers/md/kcopyd.c
+++ b/
drivers/md/kcopyd.c
@@
-8,10
+8,10
@@
* completion notification.
*/
* completion notification.
*/
+#include <asm/types.h>
#include <asm/atomic.h>
#include <linux/blkdev.h>
#include <asm/atomic.h>
#include <linux/blkdev.h>
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/list.h>
@@
-21,6
+21,7
@@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include "kcopyd.h"
#include "kcopyd.h"
@@
-43,6
+44,9
@@
struct kcopyd_client {
struct page_list *pages;
unsigned int nr_pages;
unsigned int nr_free_pages;
struct page_list *pages;
unsigned int nr_pages;
unsigned int nr_free_pages;
+
+ wait_queue_head_t destroyq;
+ atomic_t nr_jobs;
};
static struct page_list *alloc_pl(void)
};
static struct page_list *alloc_pl(void)
@@
-199,7
+203,7
@@
struct kcopyd_job {
/* FIXME: this should scale with the number of pages */
#define MIN_JOBS 512
/* FIXME: this should scale with the number of pages */
#define MIN_JOBS 512
-static
kmem_cache_t
*_job_cache;
+static
struct kmem_cache
*_job_cache;
static mempool_t *_job_pool;
/*
static mempool_t *_job_pool;
/*
@@
-226,8
+230,7
@@
static int jobs_init(void)
if (!_job_cache)
return -ENOMEM;
if (!_job_cache)
return -ENOMEM;
- _job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab,
- mempool_free_slab, _job_cache);
+ _job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache);
if (!_job_pool) {
kmem_cache_destroy(_job_cache);
return -ENOMEM;
if (!_job_pool) {
kmem_cache_destroy(_job_cache);
return -ENOMEM;
@@
-292,10
+295,15
@@
static int run_complete_job(struct kcopyd_job *job)
int read_err = job->read_err;
unsigned int write_err = job->write_err;
kcopyd_notify_fn fn = job->fn;
int read_err = job->read_err;
unsigned int write_err = job->write_err;
kcopyd_notify_fn fn = job->fn;
+ struct kcopyd_client *kc = job->kc;
- kcopyd_put_pages(
job->
kc, job->pages);
+ kcopyd_put_pages(kc, job->pages);
mempool_free(job, _job_pool);
fn(read_err, write_err, context);
mempool_free(job, _job_pool);
fn(read_err, write_err, context);
+
+ if (atomic_dec_and_test(&kc->nr_jobs))
+ wake_up(&kc->destroyq);
+
return 0;
}
return 0;
}
@@
-305,7
+313,7
@@
static void complete_io(unsigned long error, void *context)
if (error) {
if (job->rw == WRITE)
if (error) {
if (job->rw == WRITE)
- job->write_err
&
= error;
+ job->write_err
|
= error;
else
job->read_err = 1;
else
job->read_err = 1;
@@
-409,7
+417,7
@@
static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
/*
* kcopyd does this every time it's woken up.
*/
/*
* kcopyd does this every time it's woken up.
*/
-static void do_work(
void
*ignored)
+static void do_work(
struct work_struct
*ignored)
{
/*
* The order that these are called is *very* important.
{
/*
* The order that these are called is *very* important.
@@
-430,6
+438,7
@@
static void do_work(void *ignored)
*/
static void dispatch_job(struct kcopyd_job *job)
{
*/
static void dispatch_job(struct kcopyd_job *job)
{
+ atomic_inc(&job->kc->nr_jobs);
push(&_pages_jobs, job);
wake();
}
push(&_pages_jobs, job);
wake();
}
@@
-450,7
+459,7
@@
static void segment_complete(int read_err,
job->read_err = 1;
if (write_err)
job->read_err = 1;
if (write_err)
- job->write_err
&
= write_err;
+ job->write_err
|
= write_err;
/*
* Only dispatch more work if there hasn't been an error.
/*
* Only dispatch more work if there hasn't been an error.
@@
-561,77
+570,79
@@
int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from,
* Cancels a kcopyd job, eg. someone might be deactivating a
* mirror.
*/
* Cancels a kcopyd job, eg. someone might be deactivating a
* mirror.
*/
+#if 0
int kcopyd_cancel(struct kcopyd_job *job, int block)
{
/* FIXME: finish */
return -1;
}
int kcopyd_cancel(struct kcopyd_job *job, int block)
{
/* FIXME: finish */
return -1;
}
+#endif /* 0 */
/*-----------------------------------------------------------------
* Unit setup
*---------------------------------------------------------------*/
/*-----------------------------------------------------------------
* Unit setup
*---------------------------------------------------------------*/
-static DE
CLAR
E_MUTEX(_client_lock);
+static DE
FIN
E_MUTEX(_client_lock);
static LIST_HEAD(_clients);
static void client_add(struct kcopyd_client *kc)
{
static LIST_HEAD(_clients);
static void client_add(struct kcopyd_client *kc)
{
-
down
(&_client_lock);
+
mutex_lock
(&_client_lock);
list_add(&kc->list, &_clients);
list_add(&kc->list, &_clients);
-
up
(&_client_lock);
+
mutex_unlock
(&_client_lock);
}
static void client_del(struct kcopyd_client *kc)
{
}
static void client_del(struct kcopyd_client *kc)
{
-
down
(&_client_lock);
+
mutex_lock
(&_client_lock);
list_del(&kc->list);
list_del(&kc->list);
-
up
(&_client_lock);
+
mutex_unlock
(&_client_lock);
}
}
-static DE
CLAR
E_MUTEX(kcopyd_init_lock);
+static DE
FIN
E_MUTEX(kcopyd_init_lock);
static int kcopyd_clients = 0;
static int kcopyd_init(void)
{
int r;
static int kcopyd_clients = 0;
static int kcopyd_init(void)
{
int r;
-
down
(&kcopyd_init_lock);
+
mutex_lock
(&kcopyd_init_lock);
if (kcopyd_clients) {
/* Already initialized. */
kcopyd_clients++;
if (kcopyd_clients) {
/* Already initialized. */
kcopyd_clients++;
-
up
(&kcopyd_init_lock);
+
mutex_unlock
(&kcopyd_init_lock);
return 0;
}
r = jobs_init();
if (r) {
return 0;
}
r = jobs_init();
if (r) {
-
up
(&kcopyd_init_lock);
+
mutex_unlock
(&kcopyd_init_lock);
return r;
}
_kcopyd_wq = create_singlethread_workqueue("kcopyd");
if (!_kcopyd_wq) {
jobs_exit();
return r;
}
_kcopyd_wq = create_singlethread_workqueue("kcopyd");
if (!_kcopyd_wq) {
jobs_exit();
-
up
(&kcopyd_init_lock);
+
mutex_unlock
(&kcopyd_init_lock);
return -ENOMEM;
}
kcopyd_clients++;
return -ENOMEM;
}
kcopyd_clients++;
- INIT_WORK(&_kcopyd_work, do_work
, NULL
);
-
up
(&kcopyd_init_lock);
+ INIT_WORK(&_kcopyd_work, do_work);
+
mutex_unlock
(&kcopyd_init_lock);
return 0;
}
static void kcopyd_exit(void)
{
return 0;
}
static void kcopyd_exit(void)
{
-
down
(&kcopyd_init_lock);
+
mutex_lock
(&kcopyd_init_lock);
kcopyd_clients--;
if (!kcopyd_clients) {
jobs_exit();
destroy_workqueue(_kcopyd_wq);
_kcopyd_wq = NULL;
}
kcopyd_clients--;
if (!kcopyd_clients) {
jobs_exit();
destroy_workqueue(_kcopyd_wq);
_kcopyd_wq = NULL;
}
-
up
(&kcopyd_init_lock);
+
mutex_unlock
(&kcopyd_init_lock);
}
int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
}
int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
@@
-667,6
+678,9
@@
int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
return r;
}
return r;
}
+ init_waitqueue_head(&kc->destroyq);
+ atomic_set(&kc->nr_jobs, 0);
+
client_add(kc);
*result = kc;
return 0;
client_add(kc);
*result = kc;
return 0;
@@
-674,6
+688,9
@@
int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
void kcopyd_client_destroy(struct kcopyd_client *kc)
{
void kcopyd_client_destroy(struct kcopyd_client *kc)
{
+ /* Wait for completion of all jobs submitted by this client. */
+ wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
+
dm_io_put(kc->nr_pages);
client_free_pages(kc);
client_del(kc);
dm_io_put(kc->nr_pages);
client_free_pages(kc);
client_del(kc);
@@
-684,4
+701,3
@@
void kcopyd_client_destroy(struct kcopyd_client *kc)
EXPORT_SYMBOL(kcopyd_client_create);
EXPORT_SYMBOL(kcopyd_client_destroy);
EXPORT_SYMBOL(kcopyd_copy);
EXPORT_SYMBOL(kcopyd_client_create);
EXPORT_SYMBOL(kcopyd_client_destroy);
EXPORT_SYMBOL(kcopyd_copy);
-EXPORT_SYMBOL(kcopyd_cancel);