aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2011-05-29 08:03:07 -0400
committerAlasdair G Kergon <agk@redhat.com>2011-05-29 08:03:07 -0400
commitd04714580f12379fcf7a0f799e86c92b96dd4e1f (patch)
tree3a6c152dcb0d062dadfecd9fb8b1866a0fdbfce5 /drivers
parentf99b55eec795bd0fd577ab3ca06f3acfbe3b1ab1 (diff)
dm kcopyd: alloc pages from the main page allocator
This patch changes dm-kcopyd so that it allocates pages from the main page allocator with __GFP_NOWARN | __GFP_NORETRY flags (so that it can fail in case of memory pressure). If the allocation fails, dm-kcopyd allocates pages from its own reserve. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/dm-kcopyd.c91
1 files changed, 60 insertions, 31 deletions
diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c
index 0270844c2a3d..5dfbdcb40a47 100644
--- a/drivers/md/dm-kcopyd.c
+++ b/drivers/md/dm-kcopyd.c
@@ -37,8 +37,8 @@
37 *---------------------------------------------------------------*/ 37 *---------------------------------------------------------------*/
38struct dm_kcopyd_client { 38struct dm_kcopyd_client {
39 struct page_list *pages; 39 struct page_list *pages;
40 unsigned int nr_pages; 40 unsigned nr_reserved_pages;
41 unsigned int nr_free_pages; 41 unsigned nr_free_pages;
42 42
43 struct dm_io_client *io_client; 43 struct dm_io_client *io_client;
44 44
@@ -70,6 +70,9 @@ static void wake(struct dm_kcopyd_client *kc)
70 queue_work(kc->kcopyd_wq, &kc->kcopyd_work); 70 queue_work(kc->kcopyd_wq, &kc->kcopyd_work);
71} 71}
72 72
73/*
74 * Obtain one page for the use of kcopyd.
75 */
73static struct page_list *alloc_pl(gfp_t gfp) 76static struct page_list *alloc_pl(gfp_t gfp)
74{ 77{
75 struct page_list *pl; 78 struct page_list *pl;
@@ -93,34 +96,56 @@ static void free_pl(struct page_list *pl)
93 kfree(pl); 96 kfree(pl);
94} 97}
95 98
96static int kcopyd_get_pages(struct dm_kcopyd_client *kc, 99/*
97 unsigned int nr, struct page_list **pages) 100 * Add the provided pages to a client's free page list, releasing
101 * back to the system any beyond the reserved_pages limit.
102 */
103static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl)
98{ 104{
99 struct page_list *pl; 105 struct page_list *next;
100
101 if (kc->nr_free_pages < nr)
102 return -ENOMEM;
103 106
104 kc->nr_free_pages -= nr; 107 do {
105 for (*pages = pl = kc->pages; --nr; pl = pl->next) 108 next = pl->next;
106 ;
107 109
108 kc->pages = pl->next; 110 if (kc->nr_free_pages >= kc->nr_reserved_pages)
109 pl->next = NULL; 111 free_pl(pl);
112 else {
113 pl->next = kc->pages;
114 kc->pages = pl;
115 kc->nr_free_pages++;
116 }
110 117
111 return 0; 118 pl = next;
119 } while (pl);
112} 120}
113 121
114static void kcopyd_put_pages(struct dm_kcopyd_client *kc, struct page_list *pl) 122static int kcopyd_get_pages(struct dm_kcopyd_client *kc,
123 unsigned int nr, struct page_list **pages)
115{ 124{
116 struct page_list *cursor; 125 struct page_list *pl;
117 126
118 for (cursor = pl; cursor->next; cursor = cursor->next) 127 *pages = NULL;
119 kc->nr_free_pages++; 128
129 do {
130 pl = alloc_pl(__GFP_NOWARN | __GFP_NORETRY);
131 if (unlikely(!pl)) {
132 /* Use reserved pages */
133 pl = kc->pages;
134 if (unlikely(!pl))
135 goto out_of_memory;
136 kc->pages = pl->next;
137 kc->nr_free_pages--;
138 }
139 pl->next = *pages;
140 *pages = pl;
141 } while (--nr);
142
143 return 0;
120 144
121 kc->nr_free_pages++; 145out_of_memory:
122 cursor->next = kc->pages; 146 if (*pages)
123 kc->pages = pl; 147 kcopyd_put_pages(kc, *pages);
148 return -ENOMEM;
124} 149}
125 150
126/* 151/*
@@ -137,12 +162,15 @@ static void drop_pages(struct page_list *pl)
137 } 162 }
138} 163}
139 164
140static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr) 165/*
166 * Allocate and reserve nr_pages for the use of a specific client.
167 */
168static int client_reserve_pages(struct dm_kcopyd_client *kc, unsigned nr_pages)
141{ 169{
142 unsigned int i; 170 unsigned i;
143 struct page_list *pl = NULL, *next; 171 struct page_list *pl = NULL, *next;
144 172
145 for (i = 0; i < nr; i++) { 173 for (i = 0; i < nr_pages; i++) {
146 next = alloc_pl(GFP_KERNEL); 174 next = alloc_pl(GFP_KERNEL);
147 if (!next) { 175 if (!next) {
148 if (pl) 176 if (pl)
@@ -153,17 +181,18 @@ static int client_alloc_pages(struct dm_kcopyd_client *kc, unsigned int nr)
153 pl = next; 181 pl = next;
154 } 182 }
155 183
184 kc->nr_reserved_pages += nr_pages;
156 kcopyd_put_pages(kc, pl); 185 kcopyd_put_pages(kc, pl);
157 kc->nr_pages += nr; 186
158 return 0; 187 return 0;
159} 188}
160 189
161static void client_free_pages(struct dm_kcopyd_client *kc) 190static void client_free_pages(struct dm_kcopyd_client *kc)
162{ 191{
163 BUG_ON(kc->nr_free_pages != kc->nr_pages); 192 BUG_ON(kc->nr_free_pages != kc->nr_reserved_pages);
164 drop_pages(kc->pages); 193 drop_pages(kc->pages);
165 kc->pages = NULL; 194 kc->pages = NULL;
166 kc->nr_free_pages = kc->nr_pages = 0; 195 kc->nr_free_pages = kc->nr_reserved_pages = 0;
167} 196}
168 197
169/*----------------------------------------------------------------- 198/*-----------------------------------------------------------------
@@ -607,7 +636,7 @@ int kcopyd_cancel(struct kcopyd_job *job, int block)
607/*----------------------------------------------------------------- 636/*-----------------------------------------------------------------
608 * Client setup 637 * Client setup
609 *---------------------------------------------------------------*/ 638 *---------------------------------------------------------------*/
610int dm_kcopyd_client_create(unsigned int nr_pages, 639int dm_kcopyd_client_create(unsigned min_pages,
611 struct dm_kcopyd_client **result) 640 struct dm_kcopyd_client **result)
612{ 641{
613 int r = -ENOMEM; 642 int r = -ENOMEM;
@@ -633,12 +662,12 @@ int dm_kcopyd_client_create(unsigned int nr_pages,
633 goto bad_workqueue; 662 goto bad_workqueue;
634 663
635 kc->pages = NULL; 664 kc->pages = NULL;
636 kc->nr_pages = kc->nr_free_pages = 0; 665 kc->nr_reserved_pages = kc->nr_free_pages = 0;
637 r = client_alloc_pages(kc, nr_pages); 666 r = client_reserve_pages(kc, min_pages);
638 if (r) 667 if (r)
639 goto bad_client_pages; 668 goto bad_client_pages;
640 669
641 kc->io_client = dm_io_client_create(nr_pages); 670 kc->io_client = dm_io_client_create(min_pages);
642 if (IS_ERR(kc->io_client)) { 671 if (IS_ERR(kc->io_client)) {
643 r = PTR_ERR(kc->io_client); 672 r = PTR_ERR(kc->io_client);
644 goto bad_io_client; 673 goto bad_io_client;