yaffs Merge branch 'namechange'
[yaffs2.git] / yaffs_allocator.c
1 /*
2  * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License version 2.1 as
11  * published by the Free Software Foundation.
12  *
13  * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14  */
15
16
17 #include "yaffs_allocator.h"
18 #include "yaffs_guts.h"
19 #include "yaffs_trace.h"
20 #include "yportenv.h"
21
22 #ifdef CONFIG_YAFFS_YMALLOC_ALLOCATOR
23
24 void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
25 {
26         dev = dev;
27 }
28
29 void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
30 {
31         dev = dev;
32 }
33
34 yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
35 {
36         return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
37 }
38
39 void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
40 {
41         dev = dev;
42         YFREE(tn);
43 }
44
45 void yaffs_init_raw_objs(yaffs_dev_t *dev)
46 {
47         dev = dev;
48 }
49
50 void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
51 {
52         dev = dev;
53 }
54
55 yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
56 {
57         dev = dev;
58         return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
59 }
60
61
62 void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
63 {
64
65         dev = dev;
66         YFREE(obj);
67 }
68
69 #else
70
71 struct yaffs_tnode_list {
72         struct yaffs_tnode_list *next;
73         yaffs_tnode_t *tnodes;
74 };
75
76 typedef struct yaffs_tnode_list yaffs_tnodelist_t;
77
78 struct yaffs_obj_tList_struct {
79         yaffs_obj_t *objects;
80         struct yaffs_obj_tList_struct *next;
81 };
82
83 typedef struct yaffs_obj_tList_struct yaffs_obj_tList;
84
85
86 struct yaffs_AllocatorStruct {
87         int n_tnodesCreated;
88         yaffs_tnode_t *freeTnodes;
89         int nFreeTnodes;
90         yaffs_tnodelist_t *allocatedTnodeList;
91
92         int n_objCreated;
93         yaffs_obj_t *freeObjects;
94         int nFreeObjects;
95
96         yaffs_obj_tList *allocatedObjectList;
97 };
98
99 typedef struct yaffs_AllocatorStruct yaffs_Allocator;
100
101
102 static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
103 {
104
105         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
106
107         yaffs_tnodelist_t *tmp;
108
109         if(!allocator){
110                 YBUG();
111                 return;
112         }
113
114         while (allocator->allocatedTnodeList) {
115                 tmp = allocator->allocatedTnodeList->next;
116
117                 YFREE(allocator->allocatedTnodeList->tnodes);
118                 YFREE(allocator->allocatedTnodeList);
119                 allocator->allocatedTnodeList = tmp;
120
121         }
122
123         allocator->freeTnodes = NULL;
124         allocator->nFreeTnodes = 0;
125         allocator->n_tnodesCreated = 0;
126 }
127
128 static void yaffs_init_raw_tnodes(yaffs_dev_t *dev)
129 {
130         yaffs_Allocator *allocator = dev->allocator;
131
132         if(allocator){
133                 allocator->allocatedTnodeList = NULL;
134                 allocator->freeTnodes = NULL;
135                 allocator->nFreeTnodes = 0;
136                 allocator->n_tnodesCreated = 0;
137         } else
138                 YBUG();
139 }
140
141 static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
142 {
143         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
144         int i;
145         yaffs_tnode_t *newTnodes;
146         __u8 *mem;
147         yaffs_tnode_t *curr;
148         yaffs_tnode_t *next;
149         yaffs_tnodelist_t *tnl;
150
151         if(!allocator){
152                 YBUG();
153                 return YAFFS_FAIL;
154         }
155
156         if (n_tnodes < 1)
157                 return YAFFS_OK;
158
159
160         /* make these things */
161
162         newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
163         mem = (__u8 *)newTnodes;
164
165         if (!newTnodes) {
166                 T(YAFFS_TRACE_ERROR,
167                         (TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
168                 return YAFFS_FAIL;
169         }
170
171         /* New hookup for wide tnodes */
172         for (i = 0; i < n_tnodes - 1; i++) {
173                 curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
174                 next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
175                 curr->internal[0] = next;
176         }
177
178         curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
179         curr->internal[0] = allocator->freeTnodes;
180         allocator->freeTnodes = (yaffs_tnode_t *)mem;
181
182         allocator->nFreeTnodes += n_tnodes;
183         allocator->n_tnodesCreated += n_tnodes;
184
185         /* Now add this bunch of tnodes to a list for freeing up.
186          * NB If we can't add this to the management list it isn't fatal
187          * but it just means we can't free this bunch of tnodes later.
188          */
189
190         tnl = YMALLOC(sizeof(yaffs_tnodelist_t));
191         if (!tnl) {
192                 T(YAFFS_TRACE_ERROR,
193                   (TSTR
194                    ("yaffs: Could not add tnodes to management list" TENDSTR)));
195                    return YAFFS_FAIL;
196         } else {
197                 tnl->tnodes = newTnodes;
198                 tnl->next = allocator->allocatedTnodeList;
199                 allocator->allocatedTnodeList = tnl;
200         }
201
202         T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
203
204         return YAFFS_OK;
205 }
206
207
208 yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
209 {
210         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
211         yaffs_tnode_t *tn = NULL;
212
213         if(!allocator){
214                 YBUG();
215                 return NULL;
216         }
217
218         /* If there are none left make more */
219         if (!allocator->freeTnodes)
220                 yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
221
222         if (allocator->freeTnodes) {
223                 tn = allocator->freeTnodes;
224                 allocator->freeTnodes = allocator->freeTnodes->internal[0];
225                 allocator->nFreeTnodes--;
226         }
227
228         return tn;
229 }
230
231 /* FreeTnode frees up a tnode and puts it back on the free list */
232 void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
233 {
234         yaffs_Allocator *allocator = dev->allocator;
235
236         if(!allocator){
237                 YBUG();
238                 return;
239         }
240
241         if (tn) {
242                 tn->internal[0] = allocator->freeTnodes;
243                 allocator->freeTnodes = tn;
244                 allocator->nFreeTnodes++;
245         }
246         dev->checkpoint_blocks_required = 0; /* force recalculation*/
247 }
248
249
250
251 static void yaffs_init_raw_objs(yaffs_dev_t *dev)
252 {
253         yaffs_Allocator *allocator = dev->allocator;
254
255         if(allocator) {
256                 allocator->allocatedObjectList = NULL;
257                 allocator->freeObjects = NULL;
258                 allocator->nFreeObjects = 0;
259         } else
260                 YBUG();
261 }
262
263 static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
264 {
265         yaffs_Allocator *allocator = dev->allocator;
266         yaffs_obj_tList *tmp;
267
268         if(!allocator){
269                 YBUG();
270                 return;
271         }
272
273         while (allocator->allocatedObjectList) {
274                 tmp = allocator->allocatedObjectList->next;
275                 YFREE(allocator->allocatedObjectList->objects);
276                 YFREE(allocator->allocatedObjectList);
277
278                 allocator->allocatedObjectList = tmp;
279         }
280
281         allocator->freeObjects = NULL;
282         allocator->nFreeObjects = 0;
283         allocator->n_objCreated = 0;
284 }
285
286
287 static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
288 {
289         yaffs_Allocator *allocator = dev->allocator;
290
291         int i;
292         yaffs_obj_t *newObjects;
293         yaffs_obj_tList *list;
294
295         if(!allocator){
296                 YBUG();
297                 return YAFFS_FAIL;
298         }
299
300         if (n_obj < 1)
301                 return YAFFS_OK;
302
303         /* make these things */
304         newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
305         list = YMALLOC(sizeof(yaffs_obj_tList));
306
307         if (!newObjects || !list) {
308                 if (newObjects){
309                         YFREE(newObjects);
310                         newObjects = NULL;
311                 }
312                 if (list){
313                         YFREE(list);
314                         list = NULL;
315                 }
316                 T(YAFFS_TRACE_ALLOCATE,
317                   (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
318                 return YAFFS_FAIL;
319         }
320
321         /* Hook them into the free list */
322         for (i = 0; i < n_obj - 1; i++) {
323                 newObjects[i].siblings.next =
324                                 (struct ylist_head *)(&newObjects[i + 1]);
325         }
326
327         newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
328         allocator->freeObjects = newObjects;
329         allocator->nFreeObjects += n_obj;
330         allocator->n_objCreated += n_obj;
331
332         /* Now add this bunch of Objects to a list for freeing up. */
333
334         list->objects = newObjects;
335         list->next = allocator->allocatedObjectList;
336         allocator->allocatedObjectList = list;
337
338         return YAFFS_OK;
339 }
340
341 yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
342 {
343         yaffs_obj_t *obj = NULL;
344         yaffs_Allocator *allocator = dev->allocator;
345
346         if(!allocator) {
347                 YBUG();
348                 return obj;
349         }
350
351         /* If there are none left make more */
352         if (!allocator->freeObjects)
353                 yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
354
355         if (allocator->freeObjects) {
356                 obj = allocator->freeObjects;
357                 allocator->freeObjects =
358                         (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
359                 allocator->nFreeObjects--;
360         }
361
362         return obj;
363 }
364
365
366 void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
367 {
368
369         yaffs_Allocator *allocator = dev->allocator;
370
371         if(!allocator)
372                 YBUG();
373         else {
374                 /* Link into the free list. */
375                 obj->siblings.next = (struct ylist_head *)(allocator->freeObjects);
376                 allocator->freeObjects = obj;
377                 allocator->nFreeObjects++;
378         }
379 }
380
381 void yaffs_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
382 {
383         if(dev->allocator){
384                 yaffs_deinit_raw_tnodes(dev);
385                 yaffs_deinit_raw_objs(dev);
386
387                 YFREE(dev->allocator);
388                 dev->allocator=NULL;
389         } else
390                 YBUG();
391 }
392
393 void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
394 {
395         yaffs_Allocator *allocator;
396
397         if(!dev->allocator){
398                 allocator = YMALLOC(sizeof(yaffs_Allocator));
399                 if(allocator){
400                         dev->allocator = allocator;
401                         yaffs_init_raw_tnodes(dev);
402                         yaffs_init_raw_objs(dev);
403                 }
404         } else
405                 YBUG();
406 }
407
408
409 #endif