~ubuntu-branches/ubuntu/quantal/linux-lowlatency/quantal

« back to all changes in this revision

Viewing changes to ubuntu/ndiswrapper/wrapmem.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-04kado7d1u2er2rl
Tags: 3.2.0-16.25
Add new lowlatency kernel flavour

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2006 Giridhar Pemmasani
 
3
 *
 
4
 *  This program is free software; you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation; either version 2 of the License, or
 
7
 *  (at your option) any later version.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful,
 
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
12
 *  GNU General Public License for more details.
 
13
 *
 
14
 */
 
15
 
 
16
#define _WRAPMEM_C_
 
17
 
 
18
#include "ntoskernel.h"
 
19
 
 
20
struct slack_alloc_info {
 
21
        struct nt_list list;
 
22
        size_t size;
 
23
};
 
24
 
 
25
static struct nt_list allocs;
 
26
static struct nt_list slack_allocs;
 
27
static spinlock_t alloc_lock;
 
28
 
 
29
struct vmem_block {
 
30
        struct nt_list list;
 
31
        int size;
 
32
};
 
33
 
 
34
static struct nt_list vmem_list;
 
35
 
 
36
#if defined(ALLOC_DEBUG)
 
37
struct alloc_info {
 
38
        enum alloc_type type;
 
39
        size_t size;
 
40
#if ALLOC_DEBUG > 1
 
41
        struct nt_list list;
 
42
        const char *file;
 
43
        int line;
 
44
        ULONG tag;
 
45
#endif
 
46
};
 
47
 
 
48
static atomic_t alloc_sizes[ALLOC_TYPE_MAX];
 
49
#endif
 
50
 
 
51
void wrapmem_info(void)
 
52
{
 
53
#ifdef ALLOC_DEBUG
 
54
        enum alloc_type type;
 
55
        for (type = 0; type < ALLOC_TYPE_MAX; type++)
 
56
                INFO("total size of allocations in %d: %d",
 
57
                       type, atomic_read(&alloc_sizes[type]));
 
58
#endif
 
59
}
 
60
 
 
61
/* allocate memory and add it to list of allocated pointers; if a
 
62
 * driver doesn't free this memory for any reason (buggy driver or we
 
63
 * allocate space behind driver's back since we need more space than
 
64
 * corresponding Windows structure provides etc.), this gets freed
 
65
 * automatically when module is unloaded
 
66
 */
 
67
void *slack_kmalloc(size_t size)
 
68
{
 
69
        struct slack_alloc_info *info;
 
70
        gfp_t flags;
 
71
 
 
72
        ENTER4("size = %lu", (unsigned long)size);
 
73
 
 
74
        if (irql_gfp() & GFP_ATOMIC)
 
75
                flags = GFP_ATOMIC;
 
76
        else
 
77
                flags = GFP_KERNEL;
 
78
        info = kmalloc(size + sizeof(*info), flags);
 
79
        if (!info)
 
80
                return NULL;
 
81
        info->size = size;
 
82
        spin_lock_bh(&alloc_lock);
 
83
        InsertTailList(&slack_allocs, &info->list);
 
84
        spin_unlock_bh(&alloc_lock);
 
85
#ifdef ALLOC_DEBUG
 
86
        atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
87
#endif
 
88
        TRACE4("%p, %p", info, info + 1);
 
89
        EXIT4(return info + 1);
 
90
}
 
91
 
 
92
/* free pointer and remove from list of allocated pointers */
 
93
void slack_kfree(void *ptr)
 
94
{
 
95
        struct slack_alloc_info *info;
 
96
 
 
97
        ENTER4("%p", ptr);
 
98
        info = ptr - sizeof(*info);
 
99
        spin_lock_bh(&alloc_lock);
 
100
        RemoveEntryList(&info->list);
 
101
        spin_unlock_bh(&alloc_lock);
 
102
#ifdef ALLOC_DEBUG
 
103
        atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
104
#endif
 
105
        kfree(info);
 
106
        EXIT4(return);
 
107
}
 
108
 
 
109
#if defined(ALLOC_DEBUG)
 
110
void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line)
 
111
{
 
112
        struct alloc_info *info;
 
113
 
 
114
        info = kmalloc(size + sizeof(*info), flags);
 
115
        if (!info)
 
116
                return NULL;
 
117
        if (flags & GFP_ATOMIC)
 
118
                info->type = ALLOC_TYPE_KMALLOC_ATOMIC;
 
119
        else
 
120
                info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC;
 
121
        info->size = size;
 
122
        atomic_add(size, &alloc_sizes[info->type]);
 
123
#if ALLOC_DEBUG > 1
 
124
        info->file = file;
 
125
        info->line = line;
 
126
        info->tag = 0;
 
127
        spin_lock_bh(&alloc_lock);
 
128
        InsertTailList(&allocs, &info->list);
 
129
        spin_unlock_bh(&alloc_lock);
 
130
#endif
 
131
        TRACE4("%p", info + 1);
 
132
        return info + 1;
 
133
}
 
134
 
 
135
void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line)
 
136
{
 
137
        void *ptr = wrap_kmalloc(size, flags, file, line);
 
138
        if (ptr)
 
139
                memset(ptr, 0, size);
 
140
        return ptr;
 
141
}
 
142
 
 
143
void wrap_kfree(void *ptr)
 
144
{
 
145
        struct alloc_info *info;
 
146
 
 
147
        TRACE4("%p", ptr);
 
148
        if (!ptr)
 
149
                return;
 
150
        info = ptr - sizeof(*info);
 
151
        atomic_sub(info->size, &alloc_sizes[info->type]);
 
152
#if ALLOC_DEBUG > 1
 
153
        spin_lock_bh(&alloc_lock);
 
154
        RemoveEntryList(&info->list);
 
155
        spin_unlock_bh(&alloc_lock);
 
156
        if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC ||
 
157
              info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC))
 
158
                WARNING("invliad type: %d", info->type);
 
159
#endif
 
160
        kfree(info);
 
161
}
 
162
 
 
163
void *wrap_vmalloc(unsigned long size, const char *file, int line)
 
164
{
 
165
        struct alloc_info *info;
 
166
 
 
167
        info = vmalloc(size + sizeof(*info));
 
168
        if (!info)
 
169
                return NULL;
 
170
        info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC;
 
171
        info->size = size;
 
172
        atomic_add(size, &alloc_sizes[info->type]);
 
173
#if ALLOC_DEBUG > 1
 
174
        info->file = file;
 
175
        info->line = line;
 
176
        info->tag = 0;
 
177
        spin_lock_bh(&alloc_lock);
 
178
        InsertTailList(&allocs, &info->list);
 
179
        spin_unlock_bh(&alloc_lock);
 
180
#endif
 
181
        return info + 1;
 
182
}
 
183
 
 
184
void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
 
185
                    const char *file, int line)
 
186
{
 
187
        struct alloc_info *info;
 
188
 
 
189
        info = __vmalloc(size + sizeof(*info), gfp_mask, prot);
 
190
        if (!info)
 
191
                return NULL;
 
192
        if (gfp_mask & GFP_ATOMIC)
 
193
                info->type = ALLOC_TYPE_VMALLOC_ATOMIC;
 
194
        else
 
195
                info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC;
 
196
        info->size = size;
 
197
        atomic_add(size, &alloc_sizes[info->type]);
 
198
#if ALLOC_DEBUG > 1
 
199
        info->file = file;
 
200
        info->line = line;
 
201
        info->tag = 0;
 
202
        spin_lock_bh(&alloc_lock);
 
203
        InsertTailList(&allocs, &info->list);
 
204
        spin_unlock_bh(&alloc_lock);
 
205
#endif
 
206
        return info + 1;
 
207
}
 
208
 
 
209
void wrap_vfree(void *ptr)
 
210
{
 
211
        struct alloc_info *info;
 
212
 
 
213
        info = ptr - sizeof(*info);
 
214
        atomic_sub(info->size, &alloc_sizes[info->type]);
 
215
#if ALLOC_DEBUG > 1
 
216
        spin_lock_bh(&alloc_lock);
 
217
        RemoveEntryList(&info->list);
 
218
        spin_unlock_bh(&alloc_lock);
 
219
        if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC ||
 
220
              info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC))
 
221
                WARNING("invliad type: %d", info->type);
 
222
#endif
 
223
        vfree(info);
 
224
}
 
225
 
 
226
void *wrap_alloc_pages(gfp_t flags, unsigned int size,
 
227
                       const char *file, int line)
 
228
{
 
229
        struct alloc_info *info;
 
230
 
 
231
        size += sizeof(*info);
 
232
        info = (struct alloc_info *)__get_free_pages(flags, get_order(size));
 
233
        if (!info)
 
234
                return NULL;
 
235
        info->type = ALLOC_TYPE_PAGES;
 
236
        info->size = size;
 
237
        atomic_add(size, &alloc_sizes[info->type]);
 
238
#if ALLOC_DEBUG > 1
 
239
        info->file = file;
 
240
        info->line = line;
 
241
        info->tag = 0;
 
242
        spin_lock_bh(&alloc_lock);
 
243
        InsertTailList(&allocs, &info->list);
 
244
        spin_unlock_bh(&alloc_lock);
 
245
#endif
 
246
        return info + 1;
 
247
}
 
248
 
 
249
void wrap_free_pages(unsigned long ptr, int order)
 
250
{
 
251
        struct alloc_info *info;
 
252
 
 
253
        info = (void *)ptr - sizeof(*info);
 
254
        atomic_sub(info->size, &alloc_sizes[info->type]);
 
255
#if ALLOC_DEBUG > 1
 
256
        spin_lock_bh(&alloc_lock);
 
257
        RemoveEntryList(&info->list);
 
258
        spin_unlock_bh(&alloc_lock);
 
259
        if (info->type != ALLOC_TYPE_PAGES)
 
260
                WARNING("invliad type: %d", info->type);
 
261
#endif
 
262
        free_pages((unsigned long)info, get_order(info->size));
 
263
}
 
264
 
 
265
#if ALLOC_DEBUG > 1
 
266
#undef ExAllocatePoolWithTag
 
267
void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size,
 
268
                                 ULONG tag, const char *file, int line)
 
269
{
 
270
        void *addr;
 
271
        struct alloc_info *info;
 
272
 
 
273
        ENTER4("pool_type: %d, size: %lu, tag: %u", pool_type, size, tag);
 
274
        addr = ExAllocatePoolWithTag(pool_type, size, tag);
 
275
        if (!addr)
 
276
                return NULL;
 
277
        info = addr - sizeof(*info);
 
278
        info->file = file;
 
279
        info->line = line;
 
280
        info->tag = tag;
 
281
        EXIT4(return addr);
 
282
}
 
283
#endif
 
284
 
 
285
int alloc_size(enum alloc_type type)
 
286
{
 
287
        if (type >= 0 && type < ALLOC_TYPE_MAX)
 
288
                return atomic_read(&alloc_sizes[type]);
 
289
        else
 
290
                return -EINVAL;
 
291
}
 
292
 
 
293
#endif // ALLOC_DEBUG
 
294
 
 
295
int wrapmem_init(void)
 
296
{
 
297
        InitializeListHead(&allocs);
 
298
        InitializeListHead(&slack_allocs);
 
299
        InitializeListHead(&vmem_list);
 
300
        spin_lock_init(&alloc_lock);
 
301
        return 0;
 
302
}
 
303
 
 
304
void wrapmem_exit(void)
 
305
{
 
306
        enum alloc_type type;
 
307
        struct nt_list *ent;
 
308
 
 
309
        /* free all pointers on the slack list */
 
310
        while (1) {
 
311
                struct slack_alloc_info *info;
 
312
                spin_lock_bh(&alloc_lock);
 
313
                ent = RemoveHeadList(&slack_allocs);
 
314
                spin_unlock_bh(&alloc_lock);
 
315
                if (!ent)
 
316
                        break;
 
317
                info = container_of(ent, struct slack_alloc_info, list);
 
318
#ifdef ALLOC_DEBUG
 
319
                atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
320
#endif
 
321
                kfree(info);
 
322
        }
 
323
        type = 0;
 
324
#ifdef ALLOC_DEBUG
 
325
        for (type = 0; type < ALLOC_TYPE_MAX; type++) {
 
326
                int n = atomic_read(&alloc_sizes[type]);
 
327
                if (n)
 
328
                        WARNING("%d bytes of memory in %d leaking", n, type);
 
329
        }
 
330
 
 
331
#if ALLOC_DEBUG > 1
 
332
        while (1) {
 
333
                struct alloc_info *info;
 
334
 
 
335
                spin_lock_bh(&alloc_lock);
 
336
                ent = RemoveHeadList(&allocs);
 
337
                spin_unlock_bh(&alloc_lock);
 
338
                if (!ent)
 
339
                        break;
 
340
                info = container_of(ent, struct alloc_info, list);
 
341
                atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
342
                WARNING("%p in %d of size %zu allocated at %s(%d) "
 
343
                        "with tag 0x%08X leaking; freeing it now",
 
344
                        info + 1, info->type, info->size, info->file,
 
345
                        info->line, info->tag);
 
346
                if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC ||
 
347
                    info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)
 
348
                        kfree(info);
 
349
                else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC ||
 
350
                         info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)
 
351
                        vfree(info);
 
352
                else if (info->type == ALLOC_TYPE_PAGES)
 
353
                        free_pages((unsigned long)info, get_order(info->size));
 
354
                else
 
355
                        WARNING("invalid type: %d; not freed", info->type);
 
356
        }
 
357
#endif
 
358
#endif
 
359
        return;
 
360
}