~ubuntu-branches/ubuntu/edgy/ndiswrapper/edgy

« back to all changes in this revision

Viewing changes to driver/wrapmem.c

  • Committer: Bazaar Package Importer
  • Author(s): Tollef Fog Heen
  • Date: 2006-07-10 14:06:05 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060710140605-56bdqtz5m7ze7aw3
Tags: 1.18-1ubuntu1
Sync with Debian.

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 NT_SPIN_LOCK alloc_lock;
 
28
 
 
29
#if defined(ALLOC_DEBUG)
 
30
struct alloc_info {
 
31
        enum alloc_type type;
 
32
        size_t size;
 
33
#if ALLOC_DEBUG > 1
 
34
        struct nt_list list;
 
35
        const char *file;
 
36
        int line;
 
37
#if ALLOC_DEBUG > 2
 
38
        ULONG tag;
 
39
#endif
 
40
#endif
 
41
};
 
42
 
 
43
static atomic_t alloc_sizes[ALLOC_TYPE_MAX];
 
44
#endif
 
45
 
 
46
int wrapmem_init(void)
 
47
{
 
48
        InitializeListHead(&allocs);
 
49
        InitializeListHead(&slack_allocs);
 
50
        nt_spin_lock_init(&alloc_lock);
 
51
        return 0;
 
52
}
 
53
 
 
54
void wrapmem_exit(void)
 
55
{
 
56
        enum alloc_type type;
 
57
        struct nt_list *ent;
 
58
 
 
59
        /* free all pointers on the slack list */
 
60
        nt_spin_lock(&alloc_lock);
 
61
        while ((ent = RemoveHeadList(&slack_allocs))) {
 
62
                struct slack_alloc_info *info;
 
63
                info = container_of(ent, struct slack_alloc_info, list);
 
64
#ifdef ALLOC_DEBUG
 
65
                atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
66
#endif
 
67
                kfree(info);
 
68
        }
 
69
        nt_spin_unlock(&alloc_lock);
 
70
        type = 0;
 
71
#ifdef ALLOC_DEBUG
 
72
        for (type = 0; type < ALLOC_TYPE_MAX; type++) {
 
73
                int n = atomic_read(&alloc_sizes[type]);
 
74
                if (n)
 
75
                        WARNING("%d bytes of memory in %d leaking", n, type);
 
76
        }       
 
77
 
 
78
#if ALLOC_DEBUG > 1
 
79
        nt_spin_lock(&alloc_lock);
 
80
        while ((ent = RemoveHeadList(&allocs))) {
 
81
                struct alloc_info *info;
 
82
                info = container_of(ent, struct alloc_info, list);
 
83
                atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
84
                WARNING("memory in %d of size %lu allocated at %s(%d) "
 
85
#if ALLOC_DEBUG > 2
 
86
                        "with tag 0x%08X "
 
87
#endif
 
88
                        "leaking; freeing it now", info->type, info->size,
 
89
                        info->file, info->line
 
90
#if ALLOC_DEBUG > 2
 
91
                        , info->tag
 
92
#endif
 
93
                        );
 
94
                if (info->type == ALLOC_TYPE_ATOMIC ||
 
95
                    info->type == ALLOC_TYPE_NON_ATOMIC)
 
96
                        kfree(info);
 
97
                else if (info->type == ALLOC_TYPE_VMALLOC)
 
98
                        vfree(info);
 
99
                else
 
100
                        WARNING("invalid type: %d; not freed", info->type);
 
101
 
 
102
        }
 
103
        nt_spin_unlock(&alloc_lock);
 
104
#endif
 
105
#endif
 
106
        return;
 
107
}
 
108
 
 
109
void wrapmem_info(void)
 
110
{
 
111
#ifdef ALLOC_DEBUG
 
112
        enum alloc_type type;
 
113
        for (type = 0; type < ALLOC_TYPE_MAX; type++)
 
114
                INFO("total size of allocations in %d: %d",
 
115
                       type, atomic_read(&alloc_sizes[type]));
 
116
        
 
117
#endif
 
118
}
 
119
 
 
120
/* allocate memory and add it to list of allocated pointers; if a
 
121
 * driver doesn't free this memory for any reason (buggy driver or we
 
122
 * allocate space behind driver's back since we need more space than
 
123
 * corresponding Windows structure provides etc.), this gets freed
 
124
 * automatically when module is unloaded
 
125
 */
 
126
void *slack_kmalloc(size_t size)
 
127
{
 
128
        struct slack_alloc_info *info;
 
129
        unsigned int flags, n;
 
130
        void *ptr;
 
131
 
 
132
        TRACEENTER4("size = %lu", (unsigned long)size);
 
133
 
 
134
        if (current_irql() < DISPATCH_LEVEL)
 
135
                flags = GFP_KERNEL;
 
136
        else
 
137
                flags = GFP_ATOMIC;
 
138
        n = size + sizeof(*info);
 
139
        info = kmalloc(n, flags);
 
140
        if (!info)
 
141
                return NULL;
 
142
        info->size = size;
 
143
        ptr = info + 1;
 
144
        nt_spin_lock(&alloc_lock);
 
145
        InsertTailList(&slack_allocs, &info->list);
 
146
        nt_spin_unlock(&alloc_lock);
 
147
#ifdef ALLOC_DEBUG
 
148
        atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
149
#endif
 
150
        DBGTRACE4("%p, %p", info, ptr);
 
151
        TRACEEXIT4(return ptr);
 
152
}
 
153
 
 
154
/* free pointer and remove from list of allocated pointers */
 
155
void slack_kfree(void *ptr)
 
156
{
 
157
        struct slack_alloc_info *info;
 
158
 
 
159
        TRACEENTER4("%p", ptr);
 
160
        info = ptr - sizeof(*info);
 
161
        nt_spin_lock(&alloc_lock);
 
162
        RemoveEntryList(&info->list);
 
163
        nt_spin_unlock(&alloc_lock);
 
164
#ifdef ALLOC_DEBUG
 
165
        atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]);
 
166
#endif
 
167
        kfree(info);
 
168
        TRACEEXIT4(return);
 
169
}
 
170
 
 
171
#if defined(ALLOC_DEBUG)
 
172
void *wrap_kmalloc(size_t size, unsigned flags, const char *file, int line)
 
173
{
 
174
        struct alloc_info *info;
 
175
        size_t n;
 
176
        n = size + sizeof(*info);
 
177
        info = kmalloc(n, flags);
 
178
        if (!info)
 
179
                return NULL;
 
180
        if (flags & GFP_ATOMIC)
 
181
                info->type = ALLOC_TYPE_ATOMIC;
 
182
        else
 
183
                info->type = ALLOC_TYPE_NON_ATOMIC;
 
184
        info->size = size;
 
185
        atomic_add(size, &alloc_sizes[info->type]);
 
186
#if ALLOC_DEBUG > 1
 
187
        info->file = file;
 
188
        info->line = line;
 
189
#if ALLOC_DEBUG > 2
 
190
        info->tag = 0;
 
191
#endif
 
192
        nt_spin_lock(&alloc_lock);
 
193
        InsertTailList(&allocs, &info->list);
 
194
        nt_spin_unlock(&alloc_lock);
 
195
#endif
 
196
        return (info + 1);
 
197
}
 
198
 
 
199
void wrap_kfree(void *ptr)
 
200
{
 
201
        struct alloc_info *info;
 
202
        info = ptr - sizeof(*info);
 
203
        atomic_sub(info->size, &alloc_sizes[info->type]);
 
204
#if ALLOC_DEBUG > 1
 
205
        nt_spin_lock(&alloc_lock);
 
206
        RemoveEntryList(&info->list);
 
207
        nt_spin_unlock(&alloc_lock);
 
208
        if (!(info->type == ALLOC_TYPE_ATOMIC ||
 
209
              info->type == ALLOC_TYPE_NON_ATOMIC))
 
210
                WARNING("invliad type: %d", info->type);
 
211
#endif
 
212
        kfree(info);
 
213
}
 
214
 
 
215
void *wrap_vmalloc(unsigned long size, const char *file, int line)
 
216
{
 
217
        struct alloc_info *info;
 
218
        size_t n;
 
219
        n = size + sizeof(*info);
 
220
        info = vmalloc(n);
 
221
        if (!info)
 
222
                return NULL;
 
223
        info->type = ALLOC_TYPE_VMALLOC;
 
224
        info->size = size;
 
225
        atomic_add(size, &alloc_sizes[info->type]);
 
226
#if ALLOC_DEBUG > 1
 
227
        info->file = file;
 
228
        info->line = line;
 
229
#if ALLOC_DEBUG > 2
 
230
        info->tag = 0;
 
231
#endif
 
232
        nt_spin_lock(&alloc_lock);
 
233
        InsertTailList(&allocs, &info->list);
 
234
        nt_spin_unlock(&alloc_lock);
 
235
#endif
 
236
        return (info + 1);
 
237
}
 
238
 
 
239
void *wrap__vmalloc(unsigned long size, unsigned int gfp_mask, pgprot_t prot,
 
240
                    const char *file, int line)
 
241
{
 
242
        struct alloc_info *info;
 
243
        size_t n;
 
244
        n = size + sizeof(*info);
 
245
        info = __vmalloc(n, gfp_mask, prot);
 
246
        if (!info)
 
247
                return NULL;
 
248
        info->type = ALLOC_TYPE_VMALLOC;
 
249
        info->size = size;
 
250
        atomic_add(size, &alloc_sizes[info->type]);
 
251
#if ALLOC_DEBUG > 1
 
252
        info->file = file;
 
253
        info->line = line;
 
254
#if ALLOC_DEBUG > 2
 
255
        info->tag = 0;
 
256
#endif
 
257
        nt_spin_lock(&alloc_lock);
 
258
        InsertTailList(&allocs, &info->list);
 
259
        nt_spin_unlock(&alloc_lock);
 
260
#endif
 
261
        return (info + 1);
 
262
}
 
263
 
 
264
void wrap_vfree(void *ptr)
 
265
{
 
266
        struct alloc_info *info;
 
267
        info = ptr - sizeof(*info);
 
268
        atomic_sub(info->size, &alloc_sizes[info->type]);
 
269
#if ALLOC_DEBUG > 1
 
270
        nt_spin_lock(&alloc_lock);
 
271
        RemoveEntryList(&info->list);
 
272
        nt_spin_unlock(&alloc_lock);
 
273
        if (info->type != ALLOC_TYPE_VMALLOC)
 
274
                WARNING("invliad type: %d", info->type);
 
275
#endif
 
276
        vfree(info);
 
277
}
 
278
 
 
279
#if ALLOC_DEBUG > 1
 
280
void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size,
 
281
                                 ULONG tag, const char *file, int line)
 
282
{
 
283
        void *addr;
 
284
        no_warn_unused struct alloc_info *info;
 
285
 
 
286
        TRACEENTER4("pool_type: %d, size: %lu, tag: %u", pool_type,
 
287
                    size, tag);
 
288
 
 
289
        if (size <= KMALLOC_THRESHOLD) {
 
290
                if (current_irql() < DISPATCH_LEVEL)
 
291
                        addr = wrap_kmalloc(size, GFP_KERNEL, file, line);
 
292
                else
 
293
                        addr = wrap_kmalloc(size, GFP_ATOMIC, file, line);
 
294
        } else {
 
295
                if (current_irql() < DISPATCH_LEVEL)
 
296
                        addr = wrap_vmalloc(size, file, line);
 
297
                else
 
298
                        addr = wrap__vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM,
 
299
                                             PAGE_KERNEL, file, line);
 
300
        }
 
301
#if ALLOC_DEBUG > 2
 
302
        info = addr - sizeof(*info);
 
303
        info->tag = tag;
 
304
#endif
 
305
        TRACEEXIT4(return addr);
 
306
}
 
307
#endif
 
308
 
 
309
int alloc_size(enum alloc_type type)
 
310
{
 
311
        if (type >= 0 && type < ALLOC_TYPE_MAX)
 
312
                return atomic_read(&alloc_sizes[type]);
 
313
        else
 
314
                return -EINVAL;
 
315
}
 
316
 
 
317
#endif // ALLOC_DEBUG