diff options
author | Michal Marek <mmarek@suse.cz> | 2011-03-09 10:15:44 -0500 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2011-03-09 10:15:44 -0500 |
commit | 2d8ad8719591fa803b0d589ed057fa46f49b7155 (patch) | |
tree | 4ae051577dad1161c91dafbf4207bb10a9dc91bb /lib/scatterlist.c | |
parent | 9b4ce7bce5f30712fd926ab4599a803314a07719 (diff) | |
parent | c56eb8fb6dccb83d9fe62fd4dc00c834de9bc470 (diff) |
Merge commit 'v2.6.38-rc1' into kbuild/packaging
Diffstat (limited to 'lib/scatterlist.c')
-rw-r--r-- | lib/scatterlist.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 0d475d8167bf..4ceb05d772ae 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c | |||
@@ -7,8 +7,10 @@ | |||
7 | * Version 2. See the file COPYING for more details. | 7 | * Version 2. See the file COPYING for more details. |
8 | */ | 8 | */ |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/slab.h> | ||
10 | #include <linux/scatterlist.h> | 11 | #include <linux/scatterlist.h> |
11 | #include <linux/highmem.h> | 12 | #include <linux/highmem.h> |
13 | #include <linux/kmemleak.h> | ||
12 | 14 | ||
13 | /** | 15 | /** |
14 | * sg_next - return the next scatterlist entry in a list | 16 | * sg_next - return the next scatterlist entry in a list |
@@ -114,17 +116,29 @@ EXPORT_SYMBOL(sg_init_one); | |||
114 | */ | 116 | */ |
115 | static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) | 117 | static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) |
116 | { | 118 | { |
117 | if (nents == SG_MAX_SINGLE_ALLOC) | 119 | if (nents == SG_MAX_SINGLE_ALLOC) { |
118 | return (struct scatterlist *) __get_free_page(gfp_mask); | 120 | /* |
119 | else | 121 | * Kmemleak doesn't track page allocations as they are not |
122 | * commonly used (in a raw form) for kernel data structures. | ||
123 | * As we chain together a list of pages and then a normal | ||
124 | * kmalloc (tracked by kmemleak), in order to for that last | ||
125 | * allocation not to become decoupled (and thus a | ||
126 | * false-positive) we need to inform kmemleak of all the | ||
127 | * intermediate allocations. | ||
128 | */ | ||
129 | void *ptr = (void *) __get_free_page(gfp_mask); | ||
130 | kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask); | ||
131 | return ptr; | ||
132 | } else | ||
120 | return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); | 133 | return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); |
121 | } | 134 | } |
122 | 135 | ||
123 | static void sg_kfree(struct scatterlist *sg, unsigned int nents) | 136 | static void sg_kfree(struct scatterlist *sg, unsigned int nents) |
124 | { | 137 | { |
125 | if (nents == SG_MAX_SINGLE_ALLOC) | 138 | if (nents == SG_MAX_SINGLE_ALLOC) { |
139 | kmemleak_free(sg); | ||
126 | free_page((unsigned long) sg); | 140 | free_page((unsigned long) sg); |
127 | else | 141 | } else |
128 | kfree(sg); | 142 | kfree(sg); |
129 | } | 143 | } |
130 | 144 | ||
@@ -234,8 +248,18 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents, | |||
234 | left -= sg_size; | 248 | left -= sg_size; |
235 | 249 | ||
236 | sg = alloc_fn(alloc_size, gfp_mask); | 250 | sg = alloc_fn(alloc_size, gfp_mask); |
237 | if (unlikely(!sg)) | 251 | if (unlikely(!sg)) { |
238 | return -ENOMEM; | 252 | /* |
253 | * Adjust entry count to reflect that the last | ||
254 | * entry of the previous table won't be used for | ||
255 | * linkage. Without this, sg_kfree() may get | ||
256 | * confused. | ||
257 | */ | ||
258 | if (prv) | ||
259 | table->nents = ++table->orig_nents; | ||
260 | |||
261 | return -ENOMEM; | ||
262 | } | ||
239 | 263 | ||
240 | sg_init_table(sg, alloc_size); | 264 | sg_init_table(sg, alloc_size); |
241 | table->nents = table->orig_nents += sg_size; | 265 | table->nents = table->orig_nents += sg_size; |