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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [fs/] [jffs2/] [v2_0/] [src/] [build.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
/*
2
 * JFFS2 -- Journalling Flash File System, Version 2.
3
 *
4
 * Copyright (C) 2001, 2002 Red Hat, Inc.
5
 *
6
 * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
7
 *
8
 * For licensing information, see the file 'LICENCE' in this directory.
9
 *
10
 * $Id: build.c,v 1.1.1.1 2004-02-14 13:29:21 phoenix Exp $
11
 *
12
 */
13
 
14
#include <linux/kernel.h>
15
#include <linux/sched.h>
16
#include <linux/slab.h>
17
#include "nodelist.h"
18
 
19
int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
20
int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
21
 
22
 
23
#define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) 
24
 
25
/* Scan plan:
26
 - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
27
 - Scan directory tree from top down, setting nlink in inocaches
28
 - Scan inocaches for inodes with nlink==0
29
*/
30
static int jffs2_build_filesystem(struct jffs2_sb_info *c)
31
{
32
        int ret;
33
        int i;
34
        struct jffs2_inode_cache *ic;
35
 
36
        /* First, scan the medium and build all the inode caches with
37
           lists of physical nodes */
38
 
39
        c->flags |= JFFS2_SB_FLAG_MOUNTING;
40
        ret = jffs2_scan_medium(c);
41
        c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
42
 
43
        if (ret)
44
                return ret;
45
 
46
        D1(printk(KERN_DEBUG "Scanned flash completely\n"));
47
        D1(jffs2_dump_block_lists(c));
48
 
49
        /* Now scan the directory tree, increasing nlink according to every dirent found. */
50
        for_each_inode(i, c, ic) {
51
                D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
52
                ret = jffs2_build_inode_pass1(c, ic);
53
                if (ret) {
54
                        D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
55
                        return ret;
56
                }
57
                cond_resched();
58
        }
59
        D1(printk(KERN_DEBUG "Pass 1 complete\n"));
60
        D1(jffs2_dump_block_lists(c));
61
 
62
        /* Next, scan for inodes with nlink == 0 and remove them. If
63
           they were directories, then decrement the nlink of their
64
           children too, and repeat the scan. As that's going to be
65
           a fairly uncommon occurrence, it's not so evil to do it this
66
           way. Recursion bad. */
67
        do {
68
                D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
69
                ret = 0;
70
                for_each_inode(i, c, ic) {
71
                        D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
72
                        if (ic->nlink)
73
                                continue;
74
 
75
                        /* XXX: Can get high latency here. Move the cond_resched() from the end of the loop? */
76
 
77
                        ret = jffs2_build_remove_unlinked_inode(c, ic);
78
                        if (ret)
79
                                break;
80
                /* -EAGAIN means the inode's nlink was zero, so we deleted it,
81
                   and furthermore that it had children and their nlink has now
82
                   gone to zero too. So we have to restart the scan. */
83
                }
84
                D1(jffs2_dump_block_lists(c));
85
 
86
                cond_resched();
87
 
88
        } while(ret == -EAGAIN);
89
 
90
        D1(printk(KERN_DEBUG "Pass 2 complete\n"));
91
 
92
        /* Finally, we can scan again and free the dirent nodes and scan_info structs */
93
        for_each_inode(i, c, ic) {
94
                struct jffs2_full_dirent *fd;
95
                D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
96
 
97
                while(ic->scan_dents) {
98
                        fd = ic->scan_dents;
99
                        ic->scan_dents = fd->next;
100
                        jffs2_free_full_dirent(fd);
101
                }
102
                ic->scan_dents = NULL;
103
                cond_resched();
104
        }
105
        D1(printk(KERN_DEBUG "Pass 3 complete\n"));
106
        D1(jffs2_dump_block_lists(c));
107
 
108
        /* Rotate the lists by some number to ensure wear levelling */
109
        jffs2_rotate_lists(c);
110
 
111
        return ret;
112
}
113
 
114
int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
115
{
116
        struct jffs2_full_dirent *fd;
117
 
118
        D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
119
 
120
        if (ic->ino > c->highest_ino)
121
                c->highest_ino = ic->ino;
122
 
123
        /* For each child, increase nlink */
124
        for(fd=ic->scan_dents; fd; fd = fd->next) {
125
                struct jffs2_inode_cache *child_ic;
126
                if (!fd->ino)
127
                        continue;
128
 
129
                /* XXX: Can get high latency here with huge directories */
130
 
131
                child_ic = jffs2_get_ino_cache(c, fd->ino);
132
                if (!child_ic) {
133
                        printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
134
                                  fd->name, fd->ino, ic->ino);
135
                        continue;
136
                }
137
 
138
                if (child_ic->nlink++ && fd->type == DT_DIR) {
139
                        printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
140
                        if (fd->ino == 1 && ic->ino == 1) {
141
                                printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
142
                                printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
143
                        }
144
                        /* What do we do about it? */
145
                }
146
                D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
147
                /* Can't free them. We might need them in pass 2 */
148
        }
149
        return 0;
150
}
151
 
152
int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
153
{
154
        struct jffs2_raw_node_ref *raw;
155
        struct jffs2_full_dirent *fd;
156
        int ret = 0;
157
 
158
        D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
159
 
160
        for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
161
                D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
162
                jffs2_mark_node_obsolete(c, raw);
163
        }
164
 
165
        if (ic->scan_dents) {
166
                int whinged = 0;
167
                D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
168
 
169
                while(ic->scan_dents) {
170
                        struct jffs2_inode_cache *child_ic;
171
 
172
                        fd = ic->scan_dents;
173
                        ic->scan_dents = fd->next;
174
 
175
                        if (!fd->ino) {
176
                                /* It's a deletion dirent. Ignore it */
177
                                D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
178
                                jffs2_free_full_dirent(fd);
179
                                continue;
180
                        }
181
                        if (!whinged) {
182
                                whinged = 1;
183
                                printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
184
                        }
185
 
186
                        D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
187
                                  fd->name, fd->ino));
188
 
189
                        child_ic = jffs2_get_ino_cache(c, fd->ino);
190
                        if (!child_ic) {
191
                                printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
192
                                jffs2_free_full_dirent(fd);
193
                                continue;
194
                        }
195
                        jffs2_free_full_dirent(fd);
196
                        child_ic->nlink--;
197
                }
198
                ret = -EAGAIN;
199
        }
200
 
201
        /*
202
           We don't delete the inocache from the hash list and free it yet.
203
           The erase code will do that, when all the nodes are completely gone.
204
        */
205
 
206
        return ret;
207
}
208
 
209
int jffs2_do_mount_fs(struct jffs2_sb_info *c)
210
{
211
        int i;
212
 
213
        c->free_size = c->flash_size;
214
        c->nr_blocks = c->flash_size / c->sector_size;
215
        c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
216
        if (!c->blocks)
217
                return -ENOMEM;
218
        for (i=0; i<c->nr_blocks; i++) {
219
                INIT_LIST_HEAD(&c->blocks[i].list);
220
                c->blocks[i].offset = i * c->sector_size;
221
                c->blocks[i].free_size = c->sector_size;
222
                c->blocks[i].dirty_size = 0;
223
                c->blocks[i].wasted_size = 0;
224
                c->blocks[i].unchecked_size = 0;
225
                c->blocks[i].used_size = 0;
226
                c->blocks[i].first_node = NULL;
227
                c->blocks[i].last_node = NULL;
228
        }
229
 
230
        init_MUTEX(&c->alloc_sem);
231
        init_MUTEX(&c->erase_free_sem);
232
        init_waitqueue_head(&c->erase_wait);
233
        init_waitqueue_head(&c->inocache_wq);
234
        spin_lock_init(&c->erase_completion_lock);
235
        spin_lock_init(&c->inocache_lock);
236
 
237
        INIT_LIST_HEAD(&c->clean_list);
238
        INIT_LIST_HEAD(&c->very_dirty_list);
239
        INIT_LIST_HEAD(&c->dirty_list);
240
        INIT_LIST_HEAD(&c->erasable_list);
241
        INIT_LIST_HEAD(&c->erasing_list);
242
        INIT_LIST_HEAD(&c->erase_pending_list);
243
        INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
244
        INIT_LIST_HEAD(&c->erase_complete_list);
245
        INIT_LIST_HEAD(&c->free_list);
246
        INIT_LIST_HEAD(&c->bad_list);
247
        INIT_LIST_HEAD(&c->bad_used_list);
248
        c->highest_ino = 1;
249
 
250
        if (jffs2_build_filesystem(c)) {
251
                D1(printk(KERN_DEBUG "build_fs failed\n"));
252
                jffs2_free_ino_caches(c);
253
                jffs2_free_raw_node_refs(c);
254
                kfree(c->blocks);
255
                return -EIO;
256
        }
257
        return 0;
258
}

powered by: WebSVN 2.1.0

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