Merge branch 'master' of ssh://www.aleph1.co.uk/home/aleph1/git/yaffs2
[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_KMALLOC_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 *)kmalloc(dev->tnode_size, GFP_NOFS);
34 }
35
36 void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
37 {
38         dev = dev;
39         kfree(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 *)kmalloc(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         kfree(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                 kfree(allocator->alloc_tnode_list->tnodes);
107                 kfree(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 = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
153         mem = (u8 *) new_tnodes;
154
155         if (!new_tnodes) {
156                 yaffs_trace(YAFFS_TRACE_ERROR,
157                         "yaffs: Could not allocate Tnodes");
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 = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
181         if (!tnl) {
182                 yaffs_trace(YAFFS_TRACE_ERROR,
183                         "Could not add tnodes to management list");
184                 return YAFFS_FAIL;
185         } else {
186                 tnl->tnodes = new_tnodes;
187                 tnl->next = allocator->alloc_tnode_list;
188                 allocator->alloc_tnode_list = tnl;
189         }
190
191         yaffs_trace(YAFFS_TRACE_ALLOCATE,"Tnodes added");
192
193         return YAFFS_OK;
194 }
195
196 struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
197 {
198         struct yaffs_allocator *allocator =
199             (struct yaffs_allocator *)dev->allocator;
200         struct yaffs_tnode *tn = NULL;
201
202         if (!allocator) {
203                 YBUG();
204                 return NULL;
205         }
206
207         /* If there are none left make more */
208         if (!allocator->free_tnodes)
209                 yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
210
211         if (allocator->free_tnodes) {
212                 tn = allocator->free_tnodes;
213                 allocator->free_tnodes = allocator->free_tnodes->internal[0];
214                 allocator->n_free_tnodes--;
215         }
216
217         return tn;
218 }
219
220 /* FreeTnode frees up a tnode and puts it back on the free list */
221 void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
222 {
223         struct yaffs_allocator *allocator = dev->allocator;
224
225         if (!allocator) {
226                 YBUG();
227                 return;
228         }
229
230         if (tn) {
231                 tn->internal[0] = allocator->free_tnodes;
232                 allocator->free_tnodes = tn;
233                 allocator->n_free_tnodes++;
234         }
235         dev->checkpoint_blocks_required = 0;    /* force recalculation */
236 }
237
238 static void yaffs_init_raw_objs(struct yaffs_dev *dev)
239 {
240         struct yaffs_allocator *allocator = dev->allocator;
241
242         if (allocator) {
243                 allocator->allocated_obj_list = NULL;
244                 allocator->free_objs = NULL;
245                 allocator->n_free_objects = 0;
246         } else {
247                 YBUG();
248         }
249 }
250
251 static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
252 {
253         struct yaffs_allocator *allocator = dev->allocator;
254         struct yaffs_obj_list *tmp;
255
256         if (!allocator) {
257                 YBUG();
258                 return;
259         }
260
261         while (allocator->allocated_obj_list) {
262                 tmp = allocator->allocated_obj_list->next;
263                 kfree(allocator->allocated_obj_list->objects);
264                 kfree(allocator->allocated_obj_list);
265
266                 allocator->allocated_obj_list = tmp;
267         }
268
269         allocator->free_objs = NULL;
270         allocator->n_free_objects = 0;
271         allocator->n_obj_created = 0;
272 }
273
274 static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
275 {
276         struct yaffs_allocator *allocator = dev->allocator;
277
278         int i;
279         struct yaffs_obj *new_objs;
280         struct yaffs_obj_list *list;
281
282         if (!allocator) {
283                 YBUG();
284                 return YAFFS_FAIL;
285         }
286
287         if (n_obj < 1)
288                 return YAFFS_OK;
289
290         /* make these things */
291         new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
292         list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
293
294         if (!new_objs || !list) {
295                 if (new_objs) {
296                         kfree(new_objs);
297                         new_objs = NULL;
298                 }
299                 if (list) {
300                         kfree(list);
301                         list = NULL;
302                 }
303                 yaffs_trace(YAFFS_TRACE_ALLOCATE,
304                         "Could not allocate more objects");
305                 return YAFFS_FAIL;
306         }
307
308         /* Hook them into the free list */
309         for (i = 0; i < n_obj - 1; i++) {
310                 new_objs[i].siblings.next =
311                     (struct list_head *)(&new_objs[i + 1]);
312         }
313
314         new_objs[n_obj - 1].siblings.next = (void *)allocator->free_objs;
315         allocator->free_objs = new_objs;
316         allocator->n_free_objects += n_obj;
317         allocator->n_obj_created += n_obj;
318
319         /* Now add this bunch of Objects to a list for freeing up. */
320
321         list->objects = new_objs;
322         list->next = allocator->allocated_obj_list;
323         allocator->allocated_obj_list = list;
324
325         return YAFFS_OK;
326 }
327
328 struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
329 {
330         struct yaffs_obj *obj = NULL;
331         struct yaffs_allocator *allocator = dev->allocator;
332
333         if (!allocator) {
334                 YBUG();
335                 return obj;
336         }
337
338         /* If there are none left make more */
339         if (!allocator->free_objs)
340                 yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
341
342         if (allocator->free_objs) {
343                 obj = allocator->free_objs;
344                 allocator->free_objs =
345                     (struct yaffs_obj *)(allocator->free_objs->siblings.next);
346                 allocator->n_free_objects--;
347         }
348
349         return obj;
350 }
351
352 void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
353 {
354
355         struct yaffs_allocator *allocator = dev->allocator;
356
357         if (!allocator)
358                 YBUG();
359         else {
360                 /* Link into the free list. */
361                 obj->siblings.next = (struct list_head *)(allocator->free_objs);
362                 allocator->free_objs = obj;
363                 allocator->n_free_objects++;
364         }
365 }
366
367 void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
368 {
369         if (dev->allocator) {
370                 yaffs_deinit_raw_tnodes(dev);
371                 yaffs_deinit_raw_objs(dev);
372
373                 kfree(dev->allocator);
374                 dev->allocator = NULL;
375         } else {
376                 YBUG();
377         }
378 }
379
380 void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
381 {
382         struct yaffs_allocator *allocator;
383
384         if (!dev->allocator) {
385                 allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
386                 if (allocator) {
387                         dev->allocator = allocator;
388                         yaffs_init_raw_tnodes(dev);
389                         yaffs_init_raw_objs(dev);
390                 }
391         } else {
392                 YBUG();
393         }
394 }
395
396 #endif