yaffs direct: Add proper error handler for too many files open
[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_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
24 {
25         dev = dev;
26 }
27
28 void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *dev)
29 {
30         dev = dev;
31 }
32
33 yaffs_tnode_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
34 {
35         return (yaffs_tnode_t *)YMALLOC(dev->tnode_size);
36 }
37
38 void yaffs_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *tn)
39 {
40         dev = dev;
41         YFREE(tn);
42 }
43
44 void yaffs_init_raw_objs(yaffs_dev_t *dev)
45 {
46         dev = dev;
47 }
48
49 void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
50 {
51         dev = dev;
52 }
53
54 yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
55 {
56         dev = dev;
57         return (yaffs_obj_t *) YMALLOC(sizeof(yaffs_obj_t));
58 }
59
60
61 void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *obj)
62 {
63
64         dev = dev;
65         YFREE(obj);
66 }
67
68 #else
69
70 struct yaffs_tnode_list {
71         struct yaffs_tnode_list *next;
72         yaffs_tnode_t *tnodes;
73 };
74
75 typedef struct yaffs_tnode_list yaffs_tnodelist_t;
76
77 struct yaffs_obj_list_struct {
78         yaffs_obj_t *objects;
79         struct yaffs_obj_list_struct *next;
80 };
81
82 typedef struct yaffs_obj_list_struct yaffs_obj_list;
83
84
85 struct yaffs_AllocatorStruct {
86         int n_tnodesCreated;
87         yaffs_tnode_t *freeTnodes;
88         int nFreeTnodes;
89         yaffs_tnodelist_t *allocatedTnodeList;
90
91         int n_objCreated;
92         yaffs_obj_t *freeObjects;
93         int nFreeObjects;
94
95         yaffs_obj_list *allocated_list;
96 };
97
98 typedef struct yaffs_AllocatorStruct yaffs_Allocator;
99
100
101 static void yaffs_deinit_raw_tnodes(yaffs_dev_t *dev)
102 {
103
104         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
105
106         yaffs_tnodelist_t *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->n_tnodesCreated = 0;
125 }
126
127 static void yaffs_init_raw_tnodes(yaffs_dev_t *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->n_tnodesCreated = 0;
136         } else
137                 YBUG();
138 }
139
140 static int yaffs_create_tnodes(yaffs_dev_t *dev, int n_tnodes)
141 {
142         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
143         int i;
144         yaffs_tnode_t *newTnodes;
145         __u8 *mem;
146         yaffs_tnode_t *curr;
147         yaffs_tnode_t *next;
148         yaffs_tnodelist_t *tnl;
149
150         if(!allocator){
151                 YBUG();
152                 return YAFFS_FAIL;
153         }
154
155         if (n_tnodes < 1)
156                 return YAFFS_OK;
157
158
159         /* make these things */
160
161         newTnodes = YMALLOC(n_tnodes * dev->tnode_size);
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 < n_tnodes - 1; i++) {
172                 curr = (yaffs_tnode_t *) &mem[i * dev->tnode_size];
173                 next = (yaffs_tnode_t *) &mem[(i+1) * dev->tnode_size];
174                 curr->internal[0] = next;
175         }
176
177         curr = (yaffs_tnode_t *) &mem[(n_tnodes - 1) * dev->tnode_size];
178         curr->internal[0] = allocator->freeTnodes;
179         allocator->freeTnodes = (yaffs_tnode_t *)mem;
180
181         allocator->nFreeTnodes += n_tnodes;
182         allocator->n_tnodesCreated += n_tnodes;
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_t));
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_t *yaffs_alloc_raw_tnode(yaffs_dev_t *dev)
208 {
209         yaffs_Allocator *allocator = (yaffs_Allocator *)dev->allocator;
210         yaffs_tnode_t *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_create_tnodes(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_free_raw_tnode(yaffs_dev_t *dev, yaffs_tnode_t *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->checkpoint_blocks_required = 0; /* force recalculation*/
246 }
247
248
249
250 static void yaffs_init_raw_objs(yaffs_dev_t *dev)
251 {
252         yaffs_Allocator *allocator = dev->allocator;
253
254         if(allocator) {
255                 allocator->allocated_list = NULL;
256                 allocator->freeObjects = NULL;
257                 allocator->nFreeObjects = 0;
258         } else
259                 YBUG();
260 }
261
262 static void yaffs_deinit_raw_objs(yaffs_dev_t *dev)
263 {
264         yaffs_Allocator *allocator = dev->allocator;
265         yaffs_obj_list *tmp;
266
267         if(!allocator){
268                 YBUG();
269                 return;
270         }
271
272         while (allocator->allocated_list) {
273                 tmp = allocator->allocated_list->next;
274                 YFREE(allocator->allocated_list->objects);
275                 YFREE(allocator->allocated_list);
276
277                 allocator->allocated_list = tmp;
278         }
279
280         allocator->freeObjects = NULL;
281         allocator->nFreeObjects = 0;
282         allocator->n_objCreated = 0;
283 }
284
285
286 static int yaffs_create_free_objs(yaffs_dev_t *dev, int n_obj)
287 {
288         yaffs_Allocator *allocator = dev->allocator;
289
290         int i;
291         yaffs_obj_t *newObjects;
292         yaffs_obj_list *list;
293
294         if(!allocator){
295                 YBUG();
296                 return YAFFS_FAIL;
297         }
298
299         if (n_obj < 1)
300                 return YAFFS_OK;
301
302         /* make these things */
303         newObjects = YMALLOC(n_obj * sizeof(yaffs_obj_t));
304         list = YMALLOC(sizeof(yaffs_obj_list));
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 < n_obj - 1; i++) {
322                 newObjects[i].siblings.next =
323                                 (struct ylist_head *)(&newObjects[i + 1]);
324         }
325
326         newObjects[n_obj - 1].siblings.next = (void *)allocator->freeObjects;
327         allocator->freeObjects = newObjects;
328         allocator->nFreeObjects += n_obj;
329         allocator->n_objCreated += n_obj;
330
331         /* Now add this bunch of Objects to a list for freeing up. */
332
333         list->objects = newObjects;
334         list->next = allocator->allocated_list;
335         allocator->allocated_list = list;
336
337         return YAFFS_OK;
338 }
339
340 yaffs_obj_t *yaffs_alloc_raw_obj(yaffs_dev_t *dev)
341 {
342         yaffs_obj_t *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_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
353
354         if (allocator->freeObjects) {
355                 obj = allocator->freeObjects;
356                 allocator->freeObjects =
357                         (yaffs_obj_t *) (allocator->freeObjects->siblings.next);
358                 allocator->nFreeObjects--;
359         }
360
361         return obj;
362 }
363
364
365 void yaffs_free_raw_obj(yaffs_dev_t *dev, yaffs_obj_t *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_deinit_raw_tnodes_and_objs(yaffs_dev_t *dev)
381 {
382         if(dev->allocator){
383                 yaffs_deinit_raw_tnodes(dev);
384                 yaffs_deinit_raw_objs(dev);
385
386                 YFREE(dev->allocator);
387                 dev->allocator=NULL;
388         } else
389                 YBUG();
390 }
391
392 void yaffs_init_raw_tnodes_and_objs(yaffs_dev_t *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_init_raw_tnodes(dev);
401                         yaffs_init_raw_objs(dev);
402                 }
403         } else
404                 YBUG();
405 }
406
407
408 #endif