aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-05-29 14:20:48 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-29 14:20:48 -0400
commitb11b06d90a41766c2d31f0acb8a87aa0f2a7188f (patch)
treebe326cde997bcc38b2a9e0a6d6bc7d7ee7b4cbed
parentf1d1c9fa8f360990e263bdcb73e35ab6fbdc41fe (diff)
parentfa34ce73072f90ecd90dcc43f29d82e70e5f8676 (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.c27
-rw-r--r--drivers/md/dm-kcopyd.c168
-rw-r--r--drivers/md/dm-log.c3
-rw-r--r--drivers/md/dm-mpath.c2
-rw-r--r--drivers/md/dm-raid1.c10
-rw-r--r--drivers/md/dm-snap-persistent.c13
-rw-r--r--drivers/md/dm-snap.c10
-rw-r--r--drivers/md/dm-table.c23
-rw-r--r--include/linux/device-mapper.h6
-rw-r--r--include/linux/dm-io.h3
-rw-r--r--include/linux/dm-kcopyd.h3
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
23struct dm_io_client { 25struct dm_io_client {
24 mempool_t *pool; 26 mempool_t *pool;
@@ -41,33 +43,21 @@ struct io {
41static struct kmem_cache *_dm_io_cache; 43static 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
49static 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 */
57struct dm_io_client *dm_io_client_create(unsigned num_pages) 48struct 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}
82EXPORT_SYMBOL(dm_io_client_create); 72EXPORT_SYMBOL(dm_io_client_create);
83 73
84int 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}
89EXPORT_SYMBOL(dm_io_client_resize);
90
91void dm_io_client_destroy(struct dm_io_client *client) 74void 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 *---------------------------------------------------------------*/
34struct dm_kcopyd_client { 39struct 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
70static struct page_list *alloc_pl(void) 74/*
75 * Obtain one page for the use of kcopyd.
76 */
77static 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
93static 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 */
104static 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
116static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl) 123static 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)