Whamcloud - gitweb
5dc79588f991664d7823bd5646c44438134fe344
[fs/lustre-release.git] / libcfs / libcfs / winnt / winnt-mem.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LNET
38
39 #include <libcfs/libcfs.h>
40
41
42 struct kmem_cache *cfs_page_t_slab;
43 struct kmem_cache *cfs_page_p_slab;
44
45 struct page *virt_to_page(void *addr)
46 {
47         struct page *pg;
48         pg = kmem_cache_alloc(cfs_page_t_slab, 0);
49
50         if (NULL == pg) {
51                 cfs_enter_debugger();
52                 return NULL;
53         }
54
55         memset(pg, 0, sizeof(struct page));
56         pg->addr = (void *)((__u64)addr & (~((__u64)PAGE_SIZE-1)));
57         pg->mapping = addr;
58         cfs_atomic_set(&pg->count, 1);
59         set_bit(PG_virt, &(pg->flags));
60         cfs_enter_debugger();
61         return pg;
62 }
63
64 /*
65  * alloc_page
66  *   To allocate the struct page and also 1 page of memory
67  *
68  * Arguments:
69  *   flags:  the allocation options
70  *
71  * Return Value:
72  *   pointer to the struct page strcture in success or
73  *   NULL in failure case
74  *
75  * Notes: 
76  *   N/A
77  */
78
79 cfs_atomic_t libcfs_total_pages;
80
81 struct page *alloc_page(int flags)
82 {
83         struct page *pg;
84         pg = kmem_cache_alloc(cfs_page_t_slab, 0);
85
86         if (NULL == pg) {
87         cfs_enter_debugger();
88         return NULL;
89         }
90
91         memset(pg, 0, sizeof(struct page));
92         pg->addr = kmem_cache_alloc(cfs_page_p_slab, 0);
93         cfs_atomic_set(&pg->count, 1);
94
95         if (pg->addr) {
96                 if (cfs_is_flag_set(flags, __GFP_ZERO))
97                         memset(pg->addr, 0, PAGE_CACHE_SIZE);
98                 cfs_atomic_inc(&libcfs_total_pages);
99         } else {
100                 cfs_enter_debugger();
101                 kmem_cache_free(cfs_page_t_slab, pg);
102                 pg = NULL;
103         }
104
105         return pg;
106 }
107
108 /*
109  * __free_page
110  *   To free the struct page including the page
111  *
112  * Arguments:
113  *   pg:  pointer to the struct page strcture
114  *
115  * Return Value:
116  *   N/A
117  *
118  * Notes: 
119  *   N/A
120  */
121 void __free_page(struct page *pg)
122 {
123         ASSERT(pg != NULL);
124         ASSERT(pg->addr  != NULL);
125         ASSERT(cfs_atomic_read(&pg->count) <= 1);
126
127         if (!test_bit(PG_virt, &pg->flags)) {
128                 kmem_cache_free(cfs_page_p_slab, pg->addr);
129                 cfs_atomic_dec(&libcfs_total_pages);
130         } else {
131                 cfs_enter_debugger();
132         }
133         kmem_cache_free(cfs_page_t_slab, pg);
134 }
135
136 int kmem_is_in_cache(const void *addr, const struct kmem_cache *kmem)
137 {
138         KdPrint(("kmem_is_in_cache: not implemented. (should maintain a"
139                  "chain to keep all allocations traced.)\n"));
140         return 1;
141 }
142
143 /*
144  * kmalloc
145  *   To allocate memory from system pool
146  *
147  * Arguments:
148  *   nr_bytes:  length in bytes of the requested buffer
149  *   flags:     flags indiction
150  *
151  * Return Value:
152  *   NULL: if there's no enough memory space in system
153  *   the address of the allocated memory in success.
154  *
155  * Notes: 
156  *   This operation can be treated as atomic.
157  */
158
159 void *
160 kmalloc(size_t nr_bytes, u_int32_t flags)
161 {
162         void *ptr;
163
164         /* Ignore the flags: always allcoate from NonPagedPool */
165         ptr = ExAllocatePoolWithTag(NonPagedPool, nr_bytes, 'Lufs');
166         if (ptr != NULL && (flags & __GFP_ZERO))
167                 memset(ptr, 0, nr_bytes);
168
169         if (!ptr)
170                 cfs_enter_debugger();
171
172         return ptr;
173 }
174
175 /*
176  * kfree
177  *   To free the sepcified memory to system pool
178  *
179  * Arguments:
180  *   addr:   pointer to the buffer to be freed
181  *
182  * Return Value:
183  *   N/A
184  *
185  * Notes: 
186  *    This operation can be treated as atomic.
187  */
188
189 void
190 kfree(void *addr)
191 {
192         ExFreePool(addr);
193 }
194
195 /*
196  * vmalloc
197  *   To allocate large block of memory from system pool
198  *
199  * Arguments:
200  *   nr_bytes:  length in bytes of the requested buffer
201  *
202  * Return Value:
203  *   NULL: if there's no enough memory space in system
204  *   the address of the allocated memory in success.
205  *
206  * Notes: 
207  *   N/A
208  */
209
210 void *
211 vmalloc(size_t nr_bytes)
212 {
213         return kmalloc(nr_bytes, 0);
214 }
215
216 /*
217  * vfree
218  *   To free the sepcified memory to system pool
219  *
220  * Arguments:
221  *   addr:   pointer to the buffer to be freed
222  *
223  * Return Value:
224  *   N/A
225  *
226  * Notes: 
227  *   N/A
228  */
229
230 void vfree(void *addr)
231 {
232         kfree(addr);
233 }
234
235
236 /*
237  * kmem_cache_create
238  *   To create a SLAB cache
239  *
240  * Arguments:
241  *   name:   name string of the SLAB cache to be created
242  *   size:   size in bytes of SLAB entry buffer
243  *   offset: offset in the page
244  *   flags:  SLAB creation flags
245 *
246  * Return Value:
247  *   The poitner of cfs_memory_cache structure in success.
248  *   NULL pointer in failure case.
249  *
250  * Notes: 
251  *   1, offset won't be used here.
252  *   2, it could be better to induce a lock to protect the access of the
253  *       SLAB structure on SMP if there's not outside lock protection.
254  *   3, parameters C/D are removed.
255  */
256
257 struct kmem_cache *kmem_cache_create(const char *name, size_t size,
258                                      size_t offset, unsigned long flags,
259                                      void *ctor)
260 {
261         struct kmem_cache *kmc = NULL;
262
263         /*  The name of the SLAB could not exceed 20 chars */
264
265         if (name && strlen(name) >= 20)
266                 goto errorout;
267
268         /* Allocate and initialize the SLAB strcture */
269
270         kmc = kmalloc(sizeof(struct kmem_cache), 0);
271
272         if (NULL == kmc)
273                 goto errorout;
274
275         memset(kmc, 0, sizeof(struct kmem_cache));
276         kmc->flags = flags;
277
278     if (name) {
279         strcpy(&kmc->name[0], name);
280     }
281
282     /* Initialize the corresponding LookAside list */
283
284     ExInitializeNPagedLookasideList(
285             &(kmc->npll),
286             NULL,
287             NULL,
288             0,
289             size,
290             'pnmk',
291             0);
292  
293 errorout:
294
295     return kmc;
296 }
297
298 /*
299  *kmem_cache_destroy
300  *   To destroy the unused SLAB cache
301  *
302  * Arguments:
303  *   kmc: the SLAB cache to be destroied.
304  *
305  * Return Value:
306  *   0: in success case.
307  *   1: in failure case.
308  *
309  * Notes: 
310  *   N/A
311  */
312
313 kmem_cache_destroy(struct kmem_cache *kmc)
314 {
315         ASSERT(kmc != NULL);
316
317         ExDeleteNPagedLookasideList(&(kmc->npll));
318
319         kfree(kmc);
320
321         return 0;
322 }
323
324 /*
325  * kmem_cache_alloc
326  *   To allocate an object (LookAside entry) from the SLAB
327  *
328  * Arguments:
329  *   kmc:   the SLAB cache to be allocated from.
330  *   flags: flags for allocation options
331  *
332  * Return Value:
333  *   object buffer address: in success case.
334  *   NULL: in failure case.
335  *
336  * Notes: 
337  *   N/A
338  */
339
340 void *kmem_cache_alloc(struct kmem_cache *kmc, int flags)
341 {
342         void *buf = NULL;
343
344         buf = ExAllocateFromNPagedLookasideList(&(kmc->npll));
345
346         return buf;
347 }
348
349 /*
350  * kmem_cache_free
351  *   To free an object (LookAside entry) to the SLAB cache
352  *
353  * Arguments:
354  *   kmc: the SLAB cache to be freed to.
355  *   buf: the pointer to the object to be freed.
356  *
357  * Return Value:
358  *   N/A
359  *
360  * Notes: 
361  *   N/A
362  */
363
364 void kmem_cache_free(struct kmem_cache *kmc, void *buf)
365 {
366     ExFreeToNPagedLookasideList(&(kmc->npll), buf);
367 }
368
369 spinlock_t  shrinker_guard = {0};
370 CFS_LIST_HEAD(shrinker_hdr);
371 cfs_timer_t shrinker_timer = {0};
372
373 struct shrinker *set_shrinker(int seeks, shrink_callback cb)
374 {
375         struct shrinker *s = (struct shrinker *)
376         kmalloc(sizeof(struct shrinker), __GFP_ZERO);
377         if (s) {
378                 s->cb = cb;
379                 s->seeks = seeks;
380                 s->nr = 2;
381                 spin_lock(&shrinker_guard);
382                 cfs_list_add(&s->list, &shrinker_hdr);
383                 spin_unlock(&shrinker_guard);
384         }
385
386         return s;
387 }
388
389 void remove_shrinker(struct shrinker *s)
390 {
391         struct shrinker *tmp;
392         spin_lock(&shrinker_guard);
393 #if TRUE
394         cfs_list_for_each_entry_typed(tmp, &shrinker_hdr,
395                                       struct shrinker, list) {
396                 if (tmp == s) {
397                         cfs_list_del(&tmp->list);
398                         break;
399                 }
400         }
401 #else
402         cfs_list_del(&s->list);
403 #endif
404         spin_unlock(&shrinker_guard);
405         kfree(s);
406 }
407
408 /* time ut test proc */
409 void shrinker_timer_proc(ulong_ptr_t arg)
410 {
411         struct shrinker *s;
412         spin_lock(&shrinker_guard);
413
414         cfs_list_for_each_entry_typed(s, &shrinker_hdr,
415                                       struct shrinker, list) {
416                 s->cb(s->nr, __GFP_FS);
417         }
418         spin_unlock(&shrinker_guard);
419         cfs_timer_arm(&shrinker_timer, 300);
420 }
421
422 int start_shrinker_timer()
423 {
424     /* initialize shriner timer */
425     cfs_timer_init(&shrinker_timer, shrinker_timer_proc, NULL);
426
427     /* start the timer to trigger in 5 minutes */
428     cfs_timer_arm(&shrinker_timer, 300);
429
430     return 0;
431 }
432
433 void stop_shrinker_timer()
434 {
435     /* cancel the timer */
436     cfs_timer_disarm(&shrinker_timer);
437     cfs_timer_done(&shrinker_timer);
438 }