comparison packages/fs/jffs2/current/src/build.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children a7947d436e85
comparison
equal deleted inserted replaced
207:74c807ddde34 208:e0c0827131d1
1 /*
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.22 2002/01/09 16:30:57 dwmw2 Exp $
11 *
12 */
13
14 #ifndef __ECOS
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #endif
18 #include "nodelist.h"
19
20 int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
21 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
22
23
24 #define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next)
25
26 /* Scan plan:
27 - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
28 - Scan directory tree from top down, setting nlink in inocaches
29 - Scan inocaches for inodes with nlink==0
30 */
31 static int jffs2_build_filesystem(struct jffs2_sb_info *c)
32 {
33 int ret;
34 int i;
35 struct jffs2_inode_cache *ic;
36
37 /* First, scan the medium and build all the inode caches with
38 lists of physical nodes */
39 ret = jffs2_scan_medium(c);
40 if (ret)
41 return ret;
42
43 D1(printk(KERN_DEBUG "Scanned flash completely\n"));
44 /* Now build the data map for each inode, marking obsoleted nodes
45 as such, and also increase nlink of any children. */
46 for_each_inode(i, c, ic) {
47 D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
48 ret = jffs2_build_inode_pass1(c, ic);
49 if (ret) {
50 D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
51 return ret;
52 }
53 }
54 D1(printk(KERN_DEBUG "Pass 1 complete\n"));
55
56 /* Next, scan for inodes with nlink == 0 and remove them. If
57 they were directories, then decrement the nlink of their
58 children too, and repeat the scan. As that's going to be
59 a fairly uncommon occurrence, it's not so evil to do it this
60 way. Recursion bad. */
61 do {
62 D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
63 ret = 0;
64 for_each_inode(i, c, ic) {
65 D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
66 if (ic->nlink)
67 continue;
68
69 ret = jffs2_build_remove_unlinked_inode(c, ic);
70 if (ret)
71 break;
72 /* -EAGAIN means the inode's nlink was zero, so we deleted it,
73 and furthermore that it had children and their nlink has now
74 gone to zero too. So we have to restart the scan. */
75 }
76 } while(ret == -EAGAIN);
77
78 D1(printk(KERN_DEBUG "Pass 2 complete\n"));
79
80 /* Finally, we can scan again and free the dirent nodes and scan_info structs */
81 for_each_inode(i, c, ic) {
82 struct jffs2_scan_info *scan = ic->scan;
83 struct jffs2_full_dirent *fd;
84 D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
85 if (!scan) {
86 if (ic->nlink) {
87 D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink));
88 }
89 continue;
90 }
91 ic->scan = NULL;
92 while(scan->dents) {
93 fd = scan->dents;
94 scan->dents = fd->next;
95 jffs2_free_full_dirent(fd);
96 }
97 kfree(scan);
98 }
99 D1(printk(KERN_DEBUG "Pass 3 complete\n"));
100
101 return ret;
102 }
103
104 int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
105 {
106 struct jffs2_tmp_dnode_info *tn;
107 struct jffs2_full_dirent *fd;
108 struct jffs2_node_frag *fraglist = NULL;
109 struct jffs2_tmp_dnode_info *metadata = NULL;
110
111 D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
112 if (ic->ino > c->highest_ino)
113 c->highest_ino = ic->ino;
114
115 if (!ic->scan->tmpnodes && ic->ino != 1) {
116 D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino));
117 }
118 /* Build the list to make sure any obsolete nodes are marked as such */
119 while(ic->scan->tmpnodes) {
120 tn = ic->scan->tmpnodes;
121 ic->scan->tmpnodes = tn->next;
122
123 if (metadata && tn->version > metadata->version) {
124 D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
125 metadata->fn->raw->flash_offset &~3));
126
127 jffs2_free_full_dnode(metadata->fn);
128 jffs2_free_tmp_dnode_info(metadata);
129 metadata = NULL;
130 }
131
132 if (tn->fn->size) {
133 jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
134 jffs2_free_tmp_dnode_info(tn);
135 } else {
136 if (!metadata) {
137 metadata = tn;
138 } else {
139 D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
140 tn->fn->raw->flash_offset &~3));
141
142 jffs2_free_full_dnode(tn->fn);
143 jffs2_free_tmp_dnode_info(tn);
144 }
145 }
146 }
147
148 /* OK. Now clear up */
149 if (metadata) {
150 jffs2_free_full_dnode(metadata->fn);
151 jffs2_free_tmp_dnode_info(metadata);
152 }
153 metadata = NULL;
154
155 while (fraglist) {
156 struct jffs2_node_frag *frag;
157 frag = fraglist;
158 fraglist = fraglist->next;
159
160 if (frag->node && !(--frag->node->frags)) {
161 jffs2_free_full_dnode(frag->node);
162 }
163 jffs2_free_node_frag(frag);
164 }
165
166 /* Now for each child, increase nlink */
167 for(fd=ic->scan->dents; fd; fd = fd->next) {
168 struct jffs2_inode_cache *child_ic;
169 if (!fd->ino)
170 continue;
171
172 child_ic = jffs2_get_ino_cache(c, fd->ino);
173 if (!child_ic) {
174 printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
175 fd->name, fd->ino, ic->ino);
176 continue;
177 }
178
179 if (child_ic->nlink++ && fd->type == DT_DIR) {
180 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);
181 /* What do we do about it? */
182 }
183 D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
184 /* Can't free them. We might need them in pass 2 */
185 }
186 return 0;
187 }
188
189 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
190 {
191 struct jffs2_raw_node_ref *raw;
192 struct jffs2_full_dirent *fd;
193 int ret = 0;
194
195 if(!ic->scan) {
196 D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
197 return 0;
198 }
199
200 D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
201
202 for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
203 D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3));
204 jffs2_mark_node_obsolete(c, raw);
205 }
206
207 if (ic->scan->dents) {
208 printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
209
210 while(ic->scan->dents) {
211 struct jffs2_inode_cache *child_ic;
212
213 fd = ic->scan->dents;
214 ic->scan->dents = fd->next;
215
216 D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
217 fd->name, fd->ino));
218
219 child_ic = jffs2_get_ino_cache(c, fd->ino);
220 if (!child_ic) {
221 printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
222 continue;
223 }
224 jffs2_free_full_dirent(fd);
225 child_ic->nlink--;
226 }
227 ret = -EAGAIN;
228 }
229 kfree(ic->scan);
230 ic->scan = NULL;
231
232 /*
233 We don't delete the inocache from the hash list and free it yet.
234 The erase code will do that, when all the nodes are completely gone.
235 */
236
237 return ret;
238 }
239
240 int jffs2_do_mount_fs(struct jffs2_sb_info *c)
241 {
242 int i;
243
244 c->free_size = c->flash_size;
245 c->nr_blocks = c->flash_size / c->sector_size;
246 c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
247 if (!c->blocks)
248 return -ENOMEM;
249 for (i=0; i<c->nr_blocks; i++) {
250 INIT_LIST_HEAD(&c->blocks[i].list);
251 c->blocks[i].offset = i * c->sector_size;
252 c->blocks[i].free_size = c->sector_size;
253 c->blocks[i].dirty_size = 0;
254 c->blocks[i].used_size = 0;
255 c->blocks[i].first_node = NULL;
256 c->blocks[i].last_node = NULL;
257 }
258
259 spin_lock_init(&c->nodelist_lock);
260 init_MUTEX(&c->alloc_sem);
261 init_waitqueue_head(&c->erase_wait);
262 spin_lock_init(&c->erase_completion_lock);
263 spin_lock_init(&c->inocache_lock);
264
265 INIT_LIST_HEAD(&c->clean_list);
266 INIT_LIST_HEAD(&c->dirty_list);
267 INIT_LIST_HEAD(&c->erasing_list);
268 INIT_LIST_HEAD(&c->erase_pending_list);
269 INIT_LIST_HEAD(&c->erase_complete_list);
270 INIT_LIST_HEAD(&c->free_list);
271 INIT_LIST_HEAD(&c->bad_list);
272 INIT_LIST_HEAD(&c->bad_used_list);
273 c->highest_ino = 1;
274
275 if (jffs2_build_filesystem(c)) {
276 D1(printk(KERN_DEBUG "build_fs failed\n"));
277 jffs2_free_ino_caches(c);
278 jffs2_free_raw_node_refs(c);
279 kfree(c->blocks);
280 return -EIO;
281 }
282 return 0;
283 }