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