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