From fe06b494f652029c10210a4caafb5796202b8513 Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Thu, 20 Nov 2003 19:02:15 +0000 Subject: [PATCH] Sync with ejt 2.4.23-pre7-umd1 (excl. vfs lock move (7); with incl bitops & GFP_KERNEL repl NOIO) --- kernel/common/dm-io.c | 1 + kernel/common/dm-log.c | 11 +- kernel/common/dm-table.c | 103 +++++++------------ kernel/common/kcopyd.c | 30 ++++-- kernel/ioctl/dm-ioctl.c | 214 +++++++++++++++++++-------------------- kernel/ioctl/dm-ioctl.h | 4 +- 6 files changed, 175 insertions(+), 188 deletions(-) diff --git a/kernel/common/dm-io.c b/kernel/common/dm-io.c index 43d3482..cd766f5 100644 --- a/kernel/common/dm-io.c +++ b/kernel/common/dm-io.c @@ -10,6 +10,7 @@ #include #include #include +#include /* FIXME: can we shrink this ? */ struct io_context { diff --git a/kernel/common/dm-log.c b/kernel/common/dm-log.c index f3f8c9b..a58777b 100644 --- a/kernel/common/dm-log.c +++ b/kernel/common/dm-log.c @@ -124,6 +124,8 @@ struct core_log { int sync_search; }; +#define BYTE_SHIFT 3 + static int core_ctr(struct dirty_log *log, sector_t dev_size, unsigned int argc, char **argv) { @@ -153,8 +155,13 @@ static int core_ctr(struct dirty_log *log, sector_t dev_size, clog->region_size = region_size; clog->region_count = region_count; - bitset_size = dm_round_up((region_count + 7) >> 3, - sizeof(*clog->clean_bits)); + /* + * Work out how many words we need to hold the bitset. + */ + bitset_size = dm_round_up(region_count, + sizeof(*clog->clean_bits) << BYTE_SHIFT); + bitset_size >>= BYTE_SHIFT; + clog->clean_bits = vmalloc(bitset_size); if (!clog->clean_bits) { DMWARN("couldn't allocate clean bitset"); diff --git a/kernel/common/dm-table.c b/kernel/common/dm-table.c index bbf7d3c..a3d8642 100644 --- a/kernel/common/dm-table.c +++ b/kernel/common/dm-table.c @@ -17,7 +17,6 @@ #define NODE_SIZE L1_CACHE_BYTES #define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t)) #define CHILDREN_PER_NODE (KEYS_PER_NODE + 1) -#define MAX_TARGET_ARGS 64 struct dm_table { atomic_t holders; @@ -113,40 +112,7 @@ static int setup_btree_index(unsigned int l, struct dm_table *t) return 0; } -/* - * highs, and targets are managed as dynamic arrays during a - * table load. - */ -static int alloc_targets(struct dm_table *t, unsigned int num) -{ - sector_t *n_highs; - struct dm_target *n_targets; - int n = t->num_targets; - - /* - * Allocate both the target array and offset array at once. - */ - n_highs = (sector_t *) vcalloc(sizeof(struct dm_target) + - sizeof(sector_t), num); - if (!n_highs) - return -ENOMEM; - n_targets = (struct dm_target *) (n_highs + num); - - if (n) { - memcpy(n_highs, t->highs, sizeof(*n_highs) * n); - memcpy(n_targets, t->targets, sizeof(*n_targets) * n); - } - - memset(n_highs + n, -1, sizeof(*n_highs) * (num - n)); - vfree(t->highs); - - t->num_allocated = num; - t->highs = n_highs; - t->targets = n_targets; - - return 0; -} int dm_table_create(struct dm_table **result, int mode, unsigned num_targets) { @@ -159,15 +125,20 @@ int dm_table_create(struct dm_table **result, int mode, unsigned num_targets) INIT_LIST_HEAD(&t->devices); atomic_set(&t->holders, 1); - if (!num_targets) - num_targets = KEYS_PER_NODE; + num_targets = dm_round_up(num_targets, KEYS_PER_NODE); - if (alloc_targets(t, num_targets)) { + /* Allocate both the target array and offset array at once. */ + t->highs = (sector_t *) vcalloc(sizeof(struct dm_target) + + sizeof(sector_t), num_targets); + if (!t->highs) { kfree(t); - t = NULL; return -ENOMEM; } + memset(t->highs, -1, sizeof(*t->highs) * num_targets); + + t->targets = (struct dm_target *) (t->highs + num_targets); + t->num_allocated = num_targets; t->mode = mode; *result = t; return 0; @@ -226,17 +197,6 @@ void dm_table_put(struct dm_table *t) table_destroy(t); } -/* - * Checks to see if we need to extend highs or targets. - */ -static inline int check_space(struct dm_table *t) -{ - if (t->num_targets >= t->num_allocated) - return alloc_targets(t, t->num_allocated * 2); - - return 0; -} - /* * Convert a device path to a dev_t. */ @@ -443,17 +403,35 @@ static int adjoin(struct dm_table *table, struct dm_target *ti) return (ti->begin == (prev->begin + prev->len)); } +/* + * Used to dynamically allocate the arg array. + */ +static char **realloc_argv(unsigned *array_size, char **old_argv) +{ + char **argv; + unsigned new_size; + + new_size = *array_size ? *array_size * 2 : 64; + argv = kmalloc(new_size * sizeof(*argv), GFP_NOIO); + if (argv) { + memcpy(argv, old_argv, *array_size * sizeof(*argv)); + *array_size = new_size; + } + + kfree(old_argv); + return argv; +} + /* * Destructively splits up the argument list to pass to ctr. */ static int split_args(int *argc, char ***argvp, char *input) { - char *start, *end = input, *out; - char **argv; - int max_args = MAX_TARGET_ARGS; + char *start, *end = input, *out, **argv = NULL; + unsigned array_size = 0; *argc = 0; - argv = kmalloc(sizeof(*argv) * max_args, GFP_NOIO); + argv = realloc_argv(&array_size, argv); if (!argv) return -ENOMEM; @@ -484,19 +462,10 @@ static int split_args(int *argc, char ***argvp, char *input) } /* have we already filled the array ? */ - if ((*argc + 1) > max_args) { - char **argv2; - - max_args *= 2; - argv2 = kmalloc(sizeof(*argv2) * max_args, GFP_NOIO); - if (!argv2) { - kfree(argv); + if ((*argc + 1) > array_size) { + argv = realloc_argv(&array_size, argv); + if (!argv) return -ENOMEM; - } - - memcpy(argv2, argv, sizeof(*argv) * *argc); - kfree(argv); - argv = argv2; } /* we know this is whitespace */ @@ -520,8 +489,8 @@ int dm_table_add_target(struct dm_table *t, const char *type, char **argv; struct dm_target *tgt; - if ((r = check_space(t))) - return r; + if (t->num_targets >= t->num_allocated) + return -ENOMEM; tgt = t->targets + t->num_targets; memset(tgt, 0, sizeof(*tgt)); diff --git a/kernel/common/kcopyd.c b/kernel/common/kcopyd.c index bcbfb8e..5b7653f 100644 --- a/kernel/common/kcopyd.c +++ b/kernel/common/kcopyd.c @@ -27,6 +27,11 @@ static struct dm_daemon _kcopyd; +#define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE) +#define SUB_JOB_SIZE 128 +#define PAGES_PER_SUB_JOB (SUB_JOB_SIZE / SECTORS_PER_PAGE) +#define SUB_JOB_COUNT 8 + /*----------------------------------------------------------------- * Each kcopyd client has its own little pool of preallocated * pages for kcopyd io. @@ -38,6 +43,7 @@ struct kcopyd_client { struct list_head pages; unsigned int nr_pages; unsigned int nr_free_pages; + unsigned int max_split; }; static inline void __push_page(struct kcopyd_client *kc, struct page *p) @@ -122,6 +128,10 @@ static int client_alloc_pages(struct kcopyd_client *kc, unsigned int nr) kcopyd_put_pages(kc, &new); kc->nr_pages += nr; + kc->max_split = kc->nr_pages / PAGES_PER_SUB_JOB; + if (kc->max_split > SUB_JOB_COUNT) + kc->max_split = SUB_JOB_COUNT; + return 0; } @@ -334,7 +344,6 @@ static int run_io_job(struct kcopyd_job *job) return r; } -#define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE) static int run_pages_job(struct kcopyd_job *job) { int r; @@ -422,7 +431,6 @@ static void dispatch_job(struct kcopyd_job *job) dm_daemon_wake(&_kcopyd); } -#define SUB_JOB_SIZE 128 static void segment_complete(int read_err, unsigned int write_err, void *context) { @@ -491,17 +499,19 @@ static void segment_complete(int read_err, * Create some little jobs that will do the move between * them. */ -#define SPLIT_COUNT 8 static void split_job(struct kcopyd_job *job) { - int i; + int nr; + + nr = dm_div_up(job->source.count, SUB_JOB_SIZE); + if (nr > job->kc->max_split) + nr = job->kc->max_split; - atomic_set(&job->sub_jobs, SPLIT_COUNT); - for (i = 0; i < SPLIT_COUNT; i++) + atomic_set(&job->sub_jobs, nr); + while (nr--) segment_complete(0, 0u, job); } -#define SUB_JOB_THRESHOLD (SPLIT_COUNT * SUB_JOB_SIZE) int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, unsigned int num_dests, struct io_region *dests, unsigned int flags, kcopyd_notify_fn fn, void *context) @@ -534,7 +544,7 @@ int kcopyd_copy(struct kcopyd_client *kc, struct io_region *from, job->fn = fn; job->context = context; - if (job->source.count < SUB_JOB_THRESHOLD) + if (job->source.count < SUB_JOB_SIZE) dispatch_job(job); else { @@ -582,9 +592,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result) int r = 0; struct kcopyd_client *kc; - if (nr_pages * SECTORS_PER_PAGE < SUB_JOB_SIZE * SPLIT_COUNT) { + if (nr_pages * SECTORS_PER_PAGE < SUB_JOB_SIZE) { DMERR("kcopyd client requested %u pages: minimum is %lu", - nr_pages, SUB_JOB_SIZE * SPLIT_COUNT / SECTORS_PER_PAGE); + nr_pages, SUB_JOB_SIZE / SECTORS_PER_PAGE); return -ENOMEM; } diff --git a/kernel/ioctl/dm-ioctl.c b/kernel/ioctl/dm-ioctl.c index 42d26df..9f1ea41 100644 --- a/kernel/ioctl/dm-ioctl.c +++ b/kernel/ioctl/dm-ioctl.c @@ -698,6 +698,113 @@ static int dev_status(struct dm_ioctl *param, size_t param_size) return r; } +/* + * Build up the status struct for each target + */ +static void retrieve_status(struct dm_table *table, struct dm_ioctl *param, + size_t param_size) +{ + unsigned int i, num_targets; + struct dm_target_spec *spec; + char *outbuf, *outptr; + status_type_t type; + size_t remaining, len, used = 0; + + outptr = outbuf = get_result_buffer(param, param_size, &len); + + if (param->flags & DM_STATUS_TABLE_FLAG) + type = STATUSTYPE_TABLE; + else + type = STATUSTYPE_INFO; + + /* Get all the target info */ + num_targets = dm_table_get_num_targets(table); + for (i = 0; i < num_targets; i++) { + struct dm_target *ti = dm_table_get_target(table, i); + + remaining = len - (outptr - outbuf); + if (remaining < sizeof(struct dm_target_spec)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + + spec = (struct dm_target_spec *) outptr; + + spec->status = 0; + spec->sector_start = ti->begin; + spec->length = ti->len; + strncpy(spec->target_type, ti->type->name, + sizeof(spec->target_type)); + + outptr += sizeof(struct dm_target_spec); + remaining = len - (outptr - outbuf); + + /* Get the status/table string from the target driver */ + if (ti->type->status) { + if (ti->type->status(ti, type, outptr, remaining)) { + param->flags |= DM_BUFFER_FULL_FLAG; + break; + } + } else + outptr[0] = '\0'; + + outptr += strlen(outptr) + 1; + used = param->data_start + (outptr - outbuf); + + align_ptr(outptr); + spec->next = outptr - outbuf; + } + + if (used) + param->data_size = used; + + param->target_count = num_targets; +} + +/* + * Wait for a device to report an event + */ +static int dev_wait(struct dm_ioctl *param, size_t param_size) +{ + int r; + struct mapped_device *md; + struct dm_table *table; + DECLARE_WAITQUEUE(wq, current); + + md = find_device(param); + if (!md) + return -ENXIO; + + /* + * Wait for a notification event + */ + set_current_state(TASK_INTERRUPTIBLE); + if (!dm_add_wait_queue(md, &wq, param->event_nr)) { + schedule(); + dm_remove_wait_queue(md, &wq); + } + set_current_state(TASK_RUNNING); + + /* + * The userland program is going to want to know what + * changed to trigger the event, so we may as well tell + * him and save an ioctl. + */ + r = __dev_status(md, param); + if (r) + goto out; + + table = dm_get_table(md); + if (table) { + retrieve_status(table, param, param_size); + dm_table_put(table); + } + + out: + dm_put(md); + return r; +} + static inline int get_mode(struct dm_ioctl *param) { int mode = FMODE_READ | FMODE_WRITE; @@ -884,69 +991,6 @@ static int table_deps(struct dm_ioctl *param, size_t param_size) return r; } -/* - * Build up the status struct for each target - */ -static void retrieve_status(struct dm_table *table, struct dm_ioctl *param, - size_t param_size) -{ - unsigned int i, num_targets; - struct dm_target_spec *spec; - char *outbuf, *outptr; - status_type_t type; - size_t remaining, len, used = 0; - - outptr = outbuf = get_result_buffer(param, param_size, &len); - - if (param->flags & DM_STATUS_TABLE_FLAG) - type = STATUSTYPE_TABLE; - else - type = STATUSTYPE_INFO; - - /* Get all the target info */ - num_targets = dm_table_get_num_targets(table); - for (i = 0; i < num_targets; i++) { - struct dm_target *ti = dm_table_get_target(table, i); - - remaining = len - (outptr - outbuf); - if (remaining < sizeof(struct dm_target_spec)) { - param->flags |= DM_BUFFER_FULL_FLAG; - break; - } - - spec = (struct dm_target_spec *) outptr; - - spec->status = 0; - spec->sector_start = ti->begin; - spec->length = ti->len; - strncpy(spec->target_type, ti->type->name, - sizeof(spec->target_type)); - - outptr += sizeof(struct dm_target_spec); - remaining = len - (outptr - outbuf); - - /* Get the status/table string from the target driver */ - if (ti->type->status) { - if (ti->type->status(ti, type, outptr, remaining)) { - param->flags |= DM_BUFFER_FULL_FLAG; - break; - } - } else - outptr[0] = '\0'; - - outptr += strlen(outptr) + 1; - used = param->data_start + (outptr - outbuf); - - align_ptr(outptr); - spec->next = outptr - outbuf; - } - - if (used) - param->data_size = used; - - param->target_count = num_targets; -} - /* * Return the status of a device as a text string for each * target. @@ -976,50 +1020,6 @@ static int table_status(struct dm_ioctl *param, size_t param_size) return r; } -/* - * Wait for a device to report an event - */ -static int dev_wait(struct dm_ioctl *param, size_t param_size) -{ - int r; - struct mapped_device *md; - struct dm_table *table; - DECLARE_WAITQUEUE(wq, current); - - md = find_device(param); - if (!md) - return -ENXIO; - - /* - * Wait for a notification event - */ - set_current_state(TASK_INTERRUPTIBLE); - if (!dm_add_wait_queue(md, &wq, param->event_nr)) { - schedule(); - dm_remove_wait_queue(md, &wq); - } - set_current_state(TASK_RUNNING); - - /* - * The userland program is going to want to know what - * changed to trigger the event, so we may as well tell - * him and save an ioctl. - */ - r = __dev_status(md, param); - if (r) - goto out; - - table = dm_get_table(md); - if (table) { - retrieve_status(table, param, param_size); - dm_table_put(table); - } - - out: - dm_put(md); - return r; -} - /*----------------------------------------------------------------- * Implementation of open/close/ioctl on the special char * device. diff --git a/kernel/ioctl/dm-ioctl.h b/kernel/ioctl/dm-ioctl.h index 552c554..7487d36 100644 --- a/kernel/ioctl/dm-ioctl.h +++ b/kernel/ioctl/dm-ioctl.h @@ -207,8 +207,8 @@ enum { #define DM_VERSION_MAJOR 4 #define DM_VERSION_MINOR 0 -#define DM_VERSION_PATCHLEVEL 4 -#define DM_VERSION_EXTRA "-ioctl-cvs (2003-08-30)" +#define DM_VERSION_PATCHLEVEL 5 +#define DM_VERSION_EXTRA "-ioctl-cvs (2003-11-18)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ -- 2.43.5