diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 14:20:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 14:20:48 -0400 |
| commit | b11b06d90a41766c2d31f0acb8a87aa0f2a7188f (patch) | |
| tree | be326cde997bcc38b2a9e0a6d6bc7d7ee7b4cbed | |
| parent | f1d1c9fa8f360990e263bdcb73e35ab6fbdc41fe (diff) | |
| parent | fa34ce73072f90ecd90dcc43f29d82e70e5f8676 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
* git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm:
dm kcopyd: return client directly and not through a pointer
dm kcopyd: reserve fewer pages
dm io: use fixed initial mempool size
dm kcopyd: alloc pages from the main page allocator
dm kcopyd: add gfp parm to alloc_pl
dm kcopyd: remove superfluous page allocation spinlock
dm kcopyd: preallocate sub jobs to avoid deadlock
dm kcopyd: avoid pointless job splitting
dm mpath: do not fail paths after integrity errors
dm table: reject devices without request fns
dm table: allow targets to support discards internally
| -rw-r--r-- | drivers/md/dm-io.c | 27 | ||||
| -rw-r--r-- | drivers/md/dm-kcopyd.c | 168 | ||||
| -rw-r--r-- | drivers/md/dm-log.c | 3 | ||||
| -rw-r--r-- | drivers/md/dm-mpath.c | 2 | ||||
| -rw-r--r-- | drivers/md/dm-raid1.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-snap-persistent.c | 13 | ||||
| -rw-r--r-- | drivers/md/dm-snap.c | 10 | ||||
| -rw-r--r-- | drivers/md/dm-table.c | 23 | ||||
| -rw-r--r-- | include/linux/device-mapper.h | 6 | ||||
| -rw-r--r-- | include/linux/dm-io.h | 3 | ||||
| -rw-r--r-- | include/linux/dm-kcopyd.h | 3 |
11 files changed, 144 insertions, 124 deletions
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 76a5af00a26..2067288f61f 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #define DM_MSG_PREFIX "io" | 19 | #define DM_MSG_PREFIX "io" |
| 20 | 20 | ||
| 21 | #define DM_IO_MAX_REGIONS BITS_PER_LONG | 21 | #define DM_IO_MAX_REGIONS BITS_PER_LONG |
| 22 | #define MIN_IOS 16 | ||
| 23 | #define MIN_BIOS 16 | ||
| 22 | 24 | ||
| 23 | struct dm_io_client { | 25 | struct dm_io_client { |
| 24 | mempool_t *pool; | 26 | mempool_t *pool; |
| @@ -41,33 +43,21 @@ struct io { | |||
| 41 | static struct kmem_cache *_dm_io_cache; | 43 | static struct kmem_cache *_dm_io_cache; |
| 42 | 44 | ||
| 43 | /* | 45 | /* |
| 44 | * io contexts are only dynamically allocated for asynchronous | ||
| 45 | * io. Since async io is likely to be the majority of io we'll | ||
| 46 | * have the same number of io contexts as bios! (FIXME: must reduce this). | ||
| 47 | */ | ||
| 48 | |||
| 49 | static unsigned int pages_to_ios(unsigned int pages) | ||
| 50 | { | ||
| 51 | return 4 * pages; /* too many ? */ | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Create a client with mempool and bioset. | 46 | * Create a client with mempool and bioset. |
| 56 | */ | 47 | */ |
| 57 | struct dm_io_client *dm_io_client_create(unsigned num_pages) | 48 | struct dm_io_client *dm_io_client_create(void) |
| 58 | { | 49 | { |
| 59 | unsigned ios = pages_to_ios(num_pages); | ||
| 60 | struct dm_io_client *client; | 50 | struct dm_io_client *client; |
| 61 | 51 | ||
| 62 | client = kmalloc(sizeof(*client), GFP_KERNEL); | 52 | client = kmalloc(sizeof(*client), GFP_KERNEL); |
| 63 | if (!client) | 53 | if (!client) |
| 64 | return ERR_PTR(-ENOMEM); | 54 | return ERR_PTR(-ENOMEM); |
| 65 | 55 | ||
| 66 | client->pool = mempool_create_slab_pool(ios, _dm_io_cache); | 56 | client->pool = mempool_create_slab_pool(MIN_IOS, _dm_io_cache); |
| 67 | if (!client->pool) | 57 | if (!client->pool) |
| 68 | goto bad; | 58 | goto bad; |
| 69 | 59 | ||
| 70 | client->bios = bioset_create(16, 0); | 60 | client->bios = bioset_create(MIN_BIOS, 0); |
| 71 | if (!client->bios) | 61 | if (!client->bios) |
| 72 | goto bad; | 62 | goto bad; |
| 73 | 63 | ||
| @@ -81,13 +71,6 @@ struct dm_io_client *dm_io_client_create(unsigned num_pages) | |||
| 81 | } | 71 | } |
| 82 | EXPORT_SYMBOL(dm_io_client_create); | 72 | EXPORT_SYMBOL(dm_io_client_create); |
| 83 | 73 | ||
| 84 | int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client) | ||
| 85 | { | ||
| 86 | return mempool_resize(client->pool, pages_to_ios(num_pages), | ||
| 87 | GFP_KERNEL); | ||
| 88 | } | ||
| 89 | EXPORT_SYMBOL(dm_io_client_resize); | ||
| 90 | |||
| 91 | void dm_io_client_destroy(struct dm_io_client *client) | 74 | void dm_io_client_destroy(struct dm_io_client *client) |
| 92 | { | 75 | { |
| 93 | mempool_destroy(client->pool); | 76 | mempool_destroy(client->pool); |
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 1bb73a13ca4..819e37eaaeb 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c | |||
| @@ -27,15 +27,19 @@ | |||
| 27 | 27 | ||
| 28 | #include "dm.h" | 28 | #include "dm.h" |
| 29 | 29 | ||
| 30 | #define SUB_JOB_SIZE 128 | ||
| 31 | #define SPLIT_COUNT 8 | ||
| 32 | #define MIN_JOBS 8 | ||
| 33 | #define RESERVE_PAGES (DIV_ROUND_UP(SUB_JOB_SIZE << SECTOR_SHIFT, PAGE_SIZE)) | ||
| 34 | |||
| 30 | /*----------------------------------------------------------------- | 35 | /*----------------------------------------------------------------- |
| 31 | * Each kcopyd client has its own little pool of preallocated | 36 | * Each kcopyd client has its own little pool of preallocated |
| 32 | * pages for kcopyd io. | 37 | * pages for kcopyd io. |
| 33 | *---------------------------------------------------------------*/ | 38 | *---------------------------------------------------------------*/ |
| 34 | struct dm_kcopyd_client { | 39 | struct dm_kcopyd_client { |
| 35 | spinlock_t lock; | ||
| 36 | struct page_list *pages; | 40 | struct page_list *pages; |
| 37 | unsigned int nr_pages; | 41 | unsigned nr_reserved_pages; |
| 38 | unsigned int nr_free_pages; | 42 | unsigned nr_free_pages; |
| 39 | 43 | ||
| 40 | struct dm_io_client *io_client; | 44 | struct dm_io_client *io_client; |
| 41 | 45 | ||
| @@ -67,15 +71,18 @@ static void wake(struct dm_kcopyd_client *kc) | |||
| 67 | queue_work(kc->kcopyd_wq, &kc->kcopyd_work); | 71 | queue_work(kc->kcopyd_wq, &kc->kcopyd_work); |
| 68 | } | 72 | } |
| 69 | 73 | ||
| 70 | static struct page_list *alloc_pl(void) | 74 | /* |
| 75 | * Obtain one page for the use of kcopyd. | ||
| 76 | */ | ||
| 77 | static struct page_list *alloc_pl(gfp_t gfp) | ||
| 71 | { | 78 | { |
| 72 | struct page_list *pl; | 79 | struct page_list *pl; |
| 73 | 80 | ||
| 74 | pl = kmalloc(sizeof(*pl), GFP_KERNEL); | 81 | pl = kmalloc(sizeof(*pl), gfp); |
| 75 | if (!pl) | 82 | if (!pl) |
| 76 | return NULL; | 83 | return NULL; |
| 77 | 84 | ||
| 78 | pl->page = alloc_page(GFP_KERNEL); | 85 | pl->page = alloc_page(gfp); |
| 79 | if (!pl->page) { | 86 | if (!pl->page) { |
| 80 | kfree(pl); | 87 | kfree(pl); |
| 81 | return NULL; | 88 | return NULL; |
| @@ -90,41 +97,56 @@ static void free_pl(struct page_list *pl) | |||
| 90 | kfree(pl); | 97 | kfree(pl); |
| 91 | } | 98 | } |
| 92 | 99 | ||
| 93 | static int kcopyd_get_pages(struct dm_kcopyd_client *kc, | 100 | /* |
| 94 | unsigned int nr, struct page_list **pages) | 101 | * Add the provided pages to a client's free page list, releasing |
| 102 | * back to the system any beyond the reserved_pages limit. | ||
| 103 | */ | ||
| 104 | static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl) | ||
| 95 | { | 105 | { |
| 96 | struct page_list *pl; | 106 | struct page_list *next; |
| 97 | |||
| 98 | spin_lock(&kc->lock); | ||
| 99 | if (kc->nr_free_pages < nr) { | ||
| 100 | spin_unlock(&kc->lock); | ||
| 101 | return -ENOMEM; | ||
| 102 | } | ||
| 103 | |||
| 104 | kc->nr_free_pages -= nr; | ||
| 105 | for (*pages = pl = kc->pages; --nr; pl = pl->next) | ||
| 106 | ; | ||
| 107 | 107 | ||
| 108 | kc->pages = pl->next; | 108 | do { |
| 109 | pl->next = NULL; | 109 | next = pl->next; |
| 110 | 110 | ||
| 111 | spin_unlock(&kc->lock); | 111 | if (kc->nr_free_pages >= kc->nr_reserved_pages) |
| 112 | free_pl(pl); | ||
| 113 | else { | ||
| 114 | pl->next = kc->pages; | ||
| 115 | kc->pages = pl; | ||
| 116 | kc->nr_free_pages++; | ||
| 117 | } | ||
| 112 | 118 | ||
| 113 | return 0; | 119 | pl = next; |
| 120 | } while (pl); | ||
| 114 | } | 121 | } |
| 115 | 122 | ||
| 116 | static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl) | 123 | static int kcopyd_get_pages(struct dm_kcopyd_client *kc, |
| 124 | unsigned int nr, struct page_list **pages) | ||
| 117 | { | 125 | { |
| 118 | struct page_list *cursor; | 126 | struct page_list *pl; |
| 127 | |||
| 128 | *pages = NULL; | ||
| 129 | |||
| 130 | do { | ||
| 131 | pl = alloc_pl(__GFP_NOWARN | __GFP_NORETRY); | ||
| 132 | if (unlikely(!pl)) { | ||
| 133 | /* Use reserved pages */ | ||
| 134 | pl = kc->pages; | ||
| 135 | if (unlikely(!pl)) | ||
| 136 | goto out_of_memory; | ||
| 137 | kc->pages = pl->next; | ||
| 138 | kc->nr_free_pages--; | ||
| 139 | } | ||
| 140 | pl->next = *pages; | ||
| 141 | *pages = pl; | ||
| 142 | } while (--nr); | ||
| 119 | 143 | ||
| 120 | spin_lock(&kc->lock); | 144 | return 0; |
| 121 | for (cursor = pl; cursor->next; cursor = cursor->next) | ||
