Whamcloud - gitweb
LU-1346 libcfs: replace libcfs wrappers with kernel API
[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 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  */
34
35 #define DEBUG_SUBSYSTEM S_LNET
36
37 #include <libcfs/libcfs.h>
38
39
40 cfs_mem_cache_t *cfs_page_t_slab = NULL;
41 cfs_mem_cache_t *cfs_page_p_slab = NULL;
42
43 cfs_page_t * virt_to_page(void * addr)
44 {
45     cfs_page_t *pg;
46     pg = cfs_mem_cache_alloc(cfs_page_t_slab, 0);
47     
48     if (NULL == pg) {
49         cfs_enter_debugger();
50         return NULL;
51     }
52
53     memset(pg, 0, sizeof(cfs_page_t));
54     pg->addr = (void *)((__u64)addr & (~((__u64)PAGE_SIZE-1)));
55     pg->mapping = addr;
56     cfs_atomic_set(&pg->count, 1);
57         set_bit(PG_virt, &(pg->flags));
58     cfs_enter_debugger();
59     return pg;
60 }
61
62 /*
63  * cfs_alloc_page
64  *   To allocate the cfs_page_t and also 1 page of memory
65  *
66  * Arguments:
67  *   flags:  the allocation options
68  *
69  * Return Value:
70  *   pointer to the cfs_page_t strcture in success or
71  *   NULL in failure case
72  *
73  * Notes: 
74  *   N/A
75  */
76
77 cfs_atomic_t libcfs_total_pages;
78
79 cfs_page_t * cfs_alloc_page(int flags)
80 {
81     cfs_page_t *pg;
82     pg = cfs_mem_cache_alloc(cfs_page_t_slab, 0);
83     
84     if (NULL == pg) {
85         cfs_enter_debugger();
86         return NULL;
87     }
88
89     memset(pg, 0, sizeof(cfs_page_t));
90     pg->addr = cfs_mem_cache_alloc(cfs_page_p_slab, 0);
91     cfs_atomic_set(&pg->count, 1);
92
93     if (pg->addr) {
94         if (cfs_is_flag_set(flags, CFS_ALLOC_ZERO)) {
95             memset(pg->addr, 0, CFS_PAGE_SIZE);
96         }
97         cfs_atomic_inc(&libcfs_total_pages);
98     } else {
99         cfs_enter_debugger();
100         cfs_mem_cache_free(cfs_page_t_slab, pg);
101         pg = NULL;
102     }
103
104     return pg;
105 }
106
107 /*
108  * cfs_free_page
109  *   To free the cfs_page_t including the page
110  *
111  * Arguments:
112  *   pg:  pointer to the cfs_page_t strcture
113  *
114  * Return Value:
115  *   N/A
116  *
117  * Notes: 
118  *   N/A
119  */
120 void cfs_free_page(cfs_page_t *pg)
121 {
122     ASSERT(pg != NULL);
123     ASSERT(pg->addr  != NULL);
124     ASSERT(cfs_atomic_read(&pg->count) <= 1);
125
126         if (!test_bit(PG_virt, &pg->flags)) {
127         cfs_mem_cache_free(cfs_page_p_slab, pg->addr);
128         cfs_atomic_dec(&libcfs_total_pages);
129     } else {
130         cfs_enter_debugger();
131     }
132     cfs_mem_cache_free(cfs_page_t_slab, pg);
133 }
134
135 int cfs_mem_is_in_cache(const void *addr, const cfs_mem_cache_t *kmem)
136 {
137     KdPrint(("cfs_mem_is_in_cache: not implemented. (should maintain a"
138               "chain to keep all allocations traced.)\n"));
139     return 1;
140 }
141
142 /*
143  * cfs_alloc
144  *   To allocate memory from system pool
145  *
146  * Arguments:
147  *   nr_bytes:  length in bytes of the requested buffer
148  *   flags:     flags indiction
149  *
150  * Return Value:
151  *   NULL: if there's no enough memory space in system
152  *   the address of the allocated memory in success.
153  *
154  * Notes: 
155  *   This operation can be treated as atomic.
156  */
157
158 void *
159 cfs_alloc(size_t nr_bytes, u_int32_t flags)
160 {
161     void *ptr;
162
163     /* Ignore the flags: always allcoate from NonPagedPool */
164     ptr = ExAllocatePoolWithTag(NonPagedPool, nr_bytes, 'Lufs');
165     if (ptr != NULL && (flags & CFS_ALLOC_ZERO)) {
166         memset(ptr, 0, nr_bytes);
167     }
168
169     if (!ptr) {
170         cfs_enter_debugger();
171     }
172
173     return ptr;
174 }
175
176 /*
177  * cfs_free
178  *   To free the sepcified memory to system pool
179  *
180  * Arguments:
181  *   addr:   pointer to the buffer to be freed
182  *
183  * Return Value:
184  *   N/A
185  *
186  * Notes: 
187  *    This operation can be treated as atomic.
188  */
189
190 void
191 cfs_free(void *addr)
192 {
193     ExFreePool(addr);
194 }
195
196 /*
197  * cfs_alloc_large
198  *   To allocate large block of memory from system pool
199  *
200  * Arguments:
201  *   nr_bytes:  length in bytes of the requested buffer
202  *
203  * Return Value:
204  *   NULL: if there's no enough memory space in system
205  *   the address of the allocated memory in success.
206  *
207  * Notes: 
208  *   N/A
209  */
210
211 void *
212 cfs_alloc_large(size_t nr_bytes)
213 {
214     return cfs_alloc(nr_bytes, 0);
215 }
216
217 /*
218  * cfs_free_large
219  *   To free the sepcified memory to system pool
220  *
221  * Arguments:
222  *   addr:   pointer to the buffer to be freed
223  *
224  * Return Value:
225  *   N/A
226  *
227  * Notes: 
228  *   N/A
229  */
230
231 void
232 cfs_free_large(void *addr)
233 {
234     cfs_free(addr);
235 }
236
237
238 /*
239  * cfs_mem_cache_create
240  *   To create a SLAB cache
241  *
242  * Arguments:
243  *   name:   name string of the SLAB cache to be created
244  *   size:   size in bytes of SLAB entry buffer
245  *   offset: offset in the page
246  *   flags:  SLAB creation flags
247 *
248  * Return Value:
249  *   The poitner of cfs_memory_cache structure in success.
250  *   NULL pointer in failure case.
251  *
252  * Notes: 
253  *   1, offset won't be used here.
254  *   2, it could be better to induce a lock to protect the access of the
255  *       SLAB structure on SMP if there's not outside lock protection.
256  *   3, parameters C/D are removed.
257  */
258
259 cfs_mem_cache_t *
260 cfs_mem_cache_create(
261     const char * name,
262     size_t size,
263     size_t offset,
264     unsigned long flags
265     )
266 {
267     cfs_mem_cache_t * kmc = NULL;
268
269     /*  The name of the SLAB could not exceed 20 chars */
270
271     if (name && strlen(name) >= 20) {
272         goto errorout;
273     }
274
275     /* Allocate and initialize the SLAB strcture */
276
277     kmc = cfs_alloc (sizeof(cfs_mem_cache_t), 0);
278
279     if (NULL == kmc) {
280         goto errorout;
281     }
282
283     memset(kmc, 0, sizeof(cfs_mem_cache_t));
284     kmc->flags = flags;
285
286     if (name) {
287         strcpy(&kmc->name[0], name);
288     }
289
290     /* Initialize the corresponding LookAside list */
291
292     ExInitializeNPagedLookasideList(
293             &(kmc->npll),
294             NULL,
295             NULL,
296             0,
297             size,
298             'pnmk',
299             0);
300  
301 errorout:
302
303     return kmc;
304 }
305
306 /*
307  * cfs_mem_cache_destroy
308  *   To destroy the unused SLAB cache
309  *
310  * Arguments:
311  *   kmc: the SLAB cache to be destroied.
312  *
313  * Return Value:
314  *   0: in success case.
315  *   1: in failure case.
316  *
317  * Notes: 
318  *   N/A
319  */
320
321 int cfs_mem_cache_destroy (cfs_mem_cache_t * kmc)
322 {
323     ASSERT(kmc != NULL);
324
325     ExDeleteNPagedLookasideList(&(kmc->npll));
326
327     cfs_free(kmc);
328
329     return 0;
330 }
331
332 /*
333  * cfs_mem_cache_alloc
334  *   To allocate an object (LookAside entry) from the SLAB
335  *
336  * Arguments:
337  *   kmc:   the SLAB cache to be allocated from.
338  *   flags: flags for allocation options
339  *
340  * Return Value:
341  *   object buffer address: in success case.
342  *   NULL: in failure case.
343  *
344  * Notes: 
345  *   N/A
346  */
347
348 void *cfs_mem_cache_alloc(cfs_mem_cache_t * kmc, int flags)
349 {
350     void *buf = NULL;
351
352     buf = ExAllocateFromNPagedLookasideList(&(kmc->npll));
353
354     return buf;
355 }
356
357 /*
358  * cfs_mem_cache_free
359  *   To free an object (LookAside entry) to the SLAB cache
360  *
361  * Arguments:
362  *   kmc: the SLAB cache to be freed to.
363  *   buf: the pointer to the object to be freed.
364  *
365  * Return Value:
366  *   N/A
367  *
368  * Notes: 
369  *   N/A
370  */
371
372 void cfs_mem_cache_free(cfs_mem_cache_t * kmc, void * buf)
373 {
374     ExFreeToNPagedLookasideList(&(kmc->npll), buf);
375 }
376
377 spinlock_t  shrinker_guard = {0};
378 CFS_LIST_HEAD(shrinker_hdr);
379 cfs_timer_t shrinker_timer = {0};
380
381 struct cfs_shrinker * cfs_set_shrinker(int seeks, shrink_callback cb)
382 {
383     struct cfs_shrinker * s = (struct cfs_shrinker *)
384         cfs_alloc(sizeof(struct cfs_shrinker), CFS_ALLOC_ZERO);
385         if (s) {
386                 s->cb = cb;
387                 s->seeks = seeks;
388                 s->nr = 2;
389                 spin_lock(&shrinker_guard);
390                 cfs_list_add(&s->list, &shrinker_hdr);
391                 spin_unlock(&shrinker_guard);
392         }
393
394         return s;
395 }
396
397 void cfs_remove_shrinker(struct cfs_shrinker *s)
398 {
399         struct cfs_shrinker *tmp;
400         spin_lock(&shrinker_guard);
401 #if TRUE
402     cfs_list_for_each_entry_typed(tmp, &shrinker_hdr,
403                                   struct cfs_shrinker, list) {
404         if (tmp == s) {
405             cfs_list_del(&tmp->list);
406             break;
407         } 
408     }
409 #else
410     cfs_list_del(&s->list);
411 #endif
412         spin_unlock(&shrinker_guard);
413         cfs_free(s);
414 }
415
416 /* time ut test proc */
417 void shrinker_timer_proc(ulong_ptr_t arg)
418 {
419         struct cfs_shrinker *s;
420         spin_lock(&shrinker_guard);
421
422         cfs_list_for_each_entry_typed(s, &shrinker_hdr,
423                                       struct cfs_shrinker, list) {
424                 s->cb(s->nr, __GFP_FS);
425         }
426         spin_unlock(&shrinker_guard);
427         cfs_timer_arm(&shrinker_timer, 300);
428 }
429
430 int start_shrinker_timer()
431 {
432     /* initialize shriner timer */
433     cfs_timer_init(&shrinker_timer, shrinker_timer_proc, NULL);
434
435     /* start the timer to trigger in 5 minutes */
436     cfs_timer_arm(&shrinker_timer, 300);
437
438     return 0;
439 }
440
441 void stop_shrinker_timer()
442 {
443     /* cancel the timer */
444     cfs_timer_disarm(&shrinker_timer);
445     cfs_timer_done(&shrinker_timer);
446 }