OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [jffs2/] [nodemgmt.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * JFFS2 -- Journalling Flash File System, Version 2.
3
 *
4
 * Copyright (C) 2001 Red Hat, Inc.
5
 *
6
 * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
7
 *
8
 * The original JFFS, from which the design for JFFS2 was derived,
9
 * was designed and implemented by Axis Communications AB.
10
 *
11
 * The contents of this file are subject to the Red Hat eCos Public
12
 * License Version 1.1 (the "Licence"); you may not use this file
13
 * except in compliance with the Licence.  You may obtain a copy of
14
 * the Licence at http://www.redhat.com/
15
 *
16
 * Software distributed under the Licence is distributed on an "AS IS"
17
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
18
 * See the Licence for the specific language governing rights and
19
 * limitations under the Licence.
20
 *
21
 * The Original Code is JFFS2 - Journalling Flash File System, version 2
22
 *
23
 * Alternatively, the contents of this file may be used under the
24
 * terms of the GNU General Public License version 2 (the "GPL"), in
25
 * which case the provisions of the GPL are applicable instead of the
26
 * above.  If you wish to allow the use of your version of this file
27
 * only under the terms of the GPL and not to allow others to use your
28
 * version of this file under the RHEPL, indicate your decision by
29
 * deleting the provisions above and replace them with the notice and
30
 * other provisions required by the GPL.  If you do not delete the
31
 * provisions above, a recipient may use your version of this file
32
 * under either the RHEPL or the GPL.
33
 *
34
 * $Id: nodemgmt.c,v 1.1.1.1 2004-04-15 01:11:02 phoenix Exp $
35
 *
36
 */
37
 
38
#include <linux/kernel.h>
39
#include <linux/slab.h>
40
#include <linux/jffs2.h>
41
#include <linux/mtd/mtd.h>
42
#include <linux/interrupt.h>
43
#include "nodelist.h"
44
 
45
/**
46
 *      jffs2_reserve_space - request physical space to write nodes to flash
47
 *      @c: superblock info
48
 *      @minsize: Minimum acceptable size of allocation
49
 *      @ofs: Returned value of node offset
50
 *      @len: Returned value of allocation length
51
 *      @prio: Allocation type - ALLOC_{NORMAL,DELETION}
52
 *
53
 *      Requests a block of physical space on the flash. Returns zero for success
54
 *      and puts 'ofs' and 'len' into the appriopriate place, or returns -ENOSPC
55
 *      or other error if appropriate.
56
 *
57
 *      If it returns zero, jffs2_reserve_space() also downs the per-filesystem
58
 *      allocation semaphore, to prevent more than one allocation from being
59
 *      active at any time. The semaphore is later released by jffs2_commit_allocation()
60
 *
61
 *      jffs2_reserve_space() may trigger garbage collection in order to make room
62
 *      for the requested allocation.
63
 */
64
 
65
static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  __u32 minsize, __u32 *ofs, __u32 *len);
66
 
67
int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio)
68
{
69
        int ret = -EAGAIN;
70
        int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE;
71
        /* align it */
72
        minsize = PAD(minsize);
73
 
74
        if (prio == ALLOC_DELETION)
75
                blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION;
76
 
77
        D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
78
        down(&c->alloc_sem);
79
 
80
        D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));
81
 
82
        spin_lock_bh(&c->erase_completion_lock);
83
 
84
        /* this needs a little more thought */
85
        while(ret == -EAGAIN) {
86
                while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
87
                        int ret;
88
 
89
                        up(&c->alloc_sem);
90
                        if (c->dirty_size < c->sector_size) {
91
                                D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size));
92
                                spin_unlock_bh(&c->erase_completion_lock);
93
                                return -ENOSPC;
94
                        }
95
                        D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
96
                                  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
97
                                  c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
98
                        spin_unlock_bh(&c->erase_completion_lock);
99
 
100
                        ret = jffs2_garbage_collect_pass(c);
101
                        if (ret)
102
                                return ret;
103
 
104
                        if (current->need_resched)
105
                                schedule();
106
 
107
                        if (signal_pending(current))
108
                                return -EINTR;
109
 
110
                        down(&c->alloc_sem);
111
                        spin_lock_bh(&c->erase_completion_lock);
112
                }
113
 
114
                ret = jffs2_do_reserve_space(c, minsize, ofs, len);
115
                if (ret) {
116
                        D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
117
                }
118
        }
119
        spin_unlock_bh(&c->erase_completion_lock);
120
        if (ret)
121
                up(&c->alloc_sem);
122
        return ret;
123
}
124
 
125
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len)
126
{
127
        int ret = -EAGAIN;
128
        minsize = PAD(minsize);
129
 
130
        D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize));
131
 
132
        spin_lock_bh(&c->erase_completion_lock);
133
        while(ret == -EAGAIN) {
134
                ret = jffs2_do_reserve_space(c, minsize, ofs, len);
135
                if (ret) {
136
                        D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
137
                }
138
        }
139
        spin_unlock_bh(&c->erase_completion_lock);
140
        return ret;
141
}
142
 
143
/* Called with alloc sem _and_ erase_completion_lock */
144
static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  __u32 minsize, __u32 *ofs, __u32 *len)
145
{
146
        struct jffs2_eraseblock *jeb = c->nextblock;
147
 
148
 restart:
149
        if (jeb && minsize > jeb->free_size) {
150
                /* Skip the end of this block and file it as having some dirty space */
151
                c->dirty_size += jeb->free_size;
152
                c->free_size -= jeb->free_size;
153
                jeb->dirty_size += jeb->free_size;
154
                jeb->free_size = 0;
155
                D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
156
                          jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
157
                list_add_tail(&jeb->list, &c->dirty_list);
158
                c->nextblock = jeb = NULL;
159
        }
160
 
161
        if (!jeb) {
162
                struct list_head *next;
163
                /* Take the next block off the 'free' list */
164
 
165
                if (list_empty(&c->free_list)) {
166
 
167
                        DECLARE_WAITQUEUE(wait, current);
168
 
169
                        if (!c->nr_erasing_blocks) {
170
//                      if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) {
171
                                /* Ouch. We're in GC, or we wouldn't have got here.
172
                                   And there's no space left. At all. */
173
                                printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
174
                                       c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
175
                                return -ENOSPC;
176
                        }
177
                        /* Make sure this can't deadlock. Someone has to start the erases
178
                           of erase_pending blocks */
179
                        set_current_state(TASK_INTERRUPTIBLE);
180
                        add_wait_queue(&c->erase_wait, &wait);
181
                        D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n",
182
                                  c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
183
                        if (!list_empty(&c->erase_pending_list)) {
184
                                D1(printk(KERN_DEBUG "Triggering pending erases\n"));
185
                                jffs2_erase_pending_trigger(c);
186
                        }
187
                        spin_unlock_bh(&c->erase_completion_lock);
188
                        schedule();
189
                        remove_wait_queue(&c->erase_wait, &wait);
190
                        spin_lock_bh(&c->erase_completion_lock);
191
                        if (signal_pending(current)) {
192
                                return -EINTR;
193
                        }
194
                        /* An erase may have failed, decreasing the
195
                           amount of free space available. So we must
196
                           restart from the beginning */
197
                        return -EAGAIN;
198
                }
199
 
200
                next = c->free_list.next;
201
                list_del(next);
202
                c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
203
                c->nr_free_blocks--;
204
                if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) {
205
                        printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
206
                        goto restart;
207
                }
208
        }
209
        /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
210
           enough space */
211
        *ofs = jeb->offset + (c->sector_size - jeb->free_size);
212
        *len = jeb->free_size;
213
        D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
214
        return 0;
215
}
216
 
217
/**
218
 *      jffs2_add_physical_node_ref - add a physical node reference to the list
219
 *      @c: superblock info
220
 *      @ofs: physical location of this physical node
221
 *      @len: length of this physical node
222
 *      @ino: inode number with which this physical node is associated
223
 *
224
 *      Should only be used to report nodes for which space has been allocated
225
 *      by jffs2_reserve_space.
226
 *
227
 *      Must be called with the alloc_sem held.
228
 */
229
 
230
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty)
231
{
232
        struct jffs2_eraseblock *jeb;
233
 
234
        len = PAD(len);
235
        jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size];
236
        D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len));
237
#if 1
238
        if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) {
239
                printk(KERN_WARNING "argh. node added in wrong place\n");
240
                jffs2_free_raw_node_ref(new);
241
                return -EINVAL;
242
        }
243
#endif
244
        if (!jeb->first_node)
245
                jeb->first_node = new;
246
        if (jeb->last_node)
247
                jeb->last_node->next_phys = new;
248
        jeb->last_node = new;
249
 
250
        spin_lock_bh(&c->erase_completion_lock);
251
        jeb->free_size -= len;
252
        c->free_size -= len;
253
        if (dirty) {
254
                new->flash_offset |= 1;
255
                jeb->dirty_size += len;
256
                c->dirty_size += len;
257
        } else {
258
                jeb->used_size += len;
259
                c->used_size += len;
260
        }
261
        spin_unlock_bh(&c->erase_completion_lock);
262
        if (!jeb->free_size && !jeb->dirty_size) {
263
                /* If it lives on the dirty_list, jffs2_reserve_space will put it there */
264
                D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
265
                          jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
266
                list_add_tail(&jeb->list, &c->clean_list);
267
                c->nextblock = NULL;
268
        }
269
        ACCT_SANITY_CHECK(c,jeb);
270
        ACCT_PARANOIA_CHECK(jeb);
271
 
272
        return 0;
273
}
274
 
275
 
276
void jffs2_complete_reservation(struct jffs2_sb_info *c)
277
{
278
        D1(printk(KERN_DEBUG "jffs2_complete_reservation()\n"));
279
        jffs2_garbage_collect_trigger(c);
280
        up(&c->alloc_sem);
281
}
282
 
283
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
284
{
285
        struct jffs2_eraseblock *jeb;
286
        int blocknr;
287
        struct jffs2_unknown_node n;
288
        int ret;
289
        ssize_t retlen;
290
 
291
        if(!ref) {
292
                printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
293
                return;
294
        }
295
        if (ref->flash_offset & 1) {
296
                D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3));
297
                return;
298
        }
299
        blocknr = ref->flash_offset / c->sector_size;
300
        if (blocknr >= c->nr_blocks) {
301
                printk(KERN_NOTICE "raw node at 0x%08x is off the end of device!\n", ref->flash_offset);
302
                BUG();
303
        }
304
        jeb = &c->blocks[blocknr];
305
        if (jeb->used_size < ref->totlen) {
306
                printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
307
                       ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
308
                BUG();
309
        }
310
 
311
        spin_lock_bh(&c->erase_completion_lock);
312
        jeb->used_size -= ref->totlen;
313
        jeb->dirty_size += ref->totlen;
314
        c->used_size -= ref->totlen;
315
        c->dirty_size += ref->totlen;
316
        ref->flash_offset |= 1;
317
 
318
        ACCT_SANITY_CHECK(c, jeb);
319
 
320
        ACCT_PARANOIA_CHECK(jeb);
321
 
322
        if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
323
                /* Mount in progress. Don't muck about with the block
324
                   lists because they're not ready yet, and don't actually
325
                   obliterate nodes that look obsolete. If they weren't
326
                   marked obsolete on the flash at the time they _became_
327
                   obsolete, there was probably a reason for that. */
328
                spin_unlock_bh(&c->erase_completion_lock);
329
                return;
330
        }
331
        if (jeb == c->nextblock) {
332
                D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
333
        } else if (jeb == c->gcblock) {
334
                D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
335
#if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static
336
         data and a few blocks free, and you just create new files and keep deleting/overwriting
337
         them, then you'd keep erasing and reusing those blocks without ever moving stuff around.
338
         So we leave completely obsoleted blocks on the dirty_list and let the GC delete them
339
         when it finds them there. That way, we still get the 'once in a while, take a clean block'
340
         to spread out the flash usage */
341
        } else if (!jeb->used_size) {
342
                D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset));
343
                list_del(&jeb->list);
344
                D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n"));
345
                list_add_tail(&jeb->list, &c->erase_pending_list);
346
                c->nr_erasing_blocks++;
347
                jffs2_erase_pending_trigger(c);
348
                //              OFNI_BS_2SFFJ(c)->s_dirt = 1;
349
                D1(printk(KERN_DEBUG "Done OK\n"));
350
#endif
351
        } else if (jeb->dirty_size == ref->totlen) {
352
                D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
353
                list_del(&jeb->list);
354
                D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
355
                list_add_tail(&jeb->list, &c->dirty_list);
356
        }
357
        spin_unlock_bh(&c->erase_completion_lock);
358
 
359
        if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM)
360
                return;
361
        if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
362
                return;
363
 
364
        D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3));
365
        ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n);
366
        if (ret) {
367
                printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
368
                return;
369
        }
370
        if (retlen != sizeof(n)) {
371
                printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
372
                return;
373
        }
374
        if (PAD(n.totlen) != PAD(ref->totlen)) {
375
                printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen);
376
                return;
377
        }
378
        if (!(n.nodetype & JFFS2_NODE_ACCURATE)) {
379
                D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype));
380
                return;
381
        }
382
        n.nodetype &= ~JFFS2_NODE_ACCURATE;
383
        ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n);
384
        if (ret) {
385
                printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret);
386
                return;
387
        }
388
        if (retlen != sizeof(n)) {
389
                printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen);
390
                return;
391
        }
392
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.