v2.4.9.9 -> v2.4.9.10
[opensuse:kernel.git] / fs / jffs2 / build.c
1 /*
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: build.c,v 1.16 2001/03/15 15:38:23 dwmw2 Exp $
35  *
36  */
37
38 #include <linux/kernel.h>
39 #include <linux/jffs2.h>
40 #include <linux/slab.h>
41 #include "nodelist.h"
42
43 int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
44 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
45
46
47 #define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) 
48
49 /* Scan plan:
50  - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
51  - Scan directory tree from top down, setting nlink in inocaches
52  - Scan inocaches for inodes with nlink==0
53 */
54 int jffs2_build_filesystem(struct jffs2_sb_info *c)
55 {
56         int ret;
57         int i;
58         struct jffs2_inode_cache *ic;
59
60         /* First, scan the medium and build all the inode caches with
61            lists of physical nodes */
62         ret = jffs2_scan_medium(c);
63         if (ret)
64                 return ret;
65
66         D1(printk(KERN_DEBUG "Scanned flash completely\n"));
67         /* Now build the data map for each inode, marking obsoleted nodes
68            as such, and also increase nlink of any children. */
69         for_each_inode(i, c, ic) {
70                 D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
71                 ret = jffs2_build_inode_pass1(c, ic);
72                 if (ret) {
73                         D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
74                         return ret;
75                 }
76         }
77         D1(printk(KERN_DEBUG "Pass 1 complete\n"));
78
79         /* Next, scan for inodes with nlink == 0 and remove them. If
80            they were directories, then decrement the nlink of their
81            children too, and repeat the scan. As that's going to be
82            a fairly uncommon occurrence, it's not so evil to do it this
83            way. Recursion bad. */
84         do { 
85                 D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
86                 ret = 0;
87                 for_each_inode(i, c, ic) {
88                         D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
89                         if (ic->nlink)
90                                 continue;
91                         
92                         ret = jffs2_build_remove_unlinked_inode(c, ic);
93                         if (ret)
94                                 break;
95                 /* -EAGAIN means the inode's nlink was zero, so we deleted it,
96                    and furthermore that it had children and their nlink has now
97                    gone to zero too. So we have to restart the scan. */
98                 } 
99         } while(ret == -EAGAIN);
100         
101         D1(printk(KERN_DEBUG "Pass 2 complete\n"));
102         
103         /* Finally, we can scan again and free the dirent nodes and scan_info structs */
104         for_each_inode(i, c, ic) {
105                 struct jffs2_scan_info *scan = ic->scan;
106                 struct jffs2_full_dirent *fd;
107                 D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
108                 if (!scan) {
109                         if (ic->nlink) {
110                                 D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink));
111                         }
112                         continue;
113                 }
114                 ic->scan = NULL;
115                 while(scan->dents) {
116                         fd = scan->dents;
117                         scan->dents = fd->next;
118                         jffs2_free_full_dirent(fd);
119                 }
120                 kfree(scan);
121         }
122         D1(printk(KERN_DEBUG "Pass 3 complete\n"));
123
124         return ret;
125 }
126         
127 int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
128 {
129         struct jffs2_tmp_dnode_info *tn;
130         struct jffs2_full_dirent *fd;
131         struct jffs2_node_frag *fraglist = NULL;
132         struct jffs2_tmp_dnode_info *metadata = NULL;
133
134         D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
135         if (ic->ino > c->highest_ino)
136                 c->highest_ino = ic->ino;
137
138         if (!ic->scan->tmpnodes && ic->ino != 1) {
139                 D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino));
140         }
141         /* Build the list to make sure any obsolete nodes are marked as such */
142         while(ic->scan->tmpnodes) {
143                 tn = ic->scan->tmpnodes;
144                 ic->scan->tmpnodes = tn->next;
145                 
146                 if (metadata && tn->version > metadata->version) {
147                         D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
148                                   metadata->fn->raw->flash_offset &~3));
149                         
150                         jffs2_free_full_dnode(metadata->fn);
151                         jffs2_free_tmp_dnode_info(metadata);
152                         metadata = NULL;
153                 }
154                         
155                 if (tn->fn->size) {
156                         jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
157                         jffs2_free_tmp_dnode_info(tn);
158                 } else {
159                         if (!metadata) {
160                                 metadata = tn;
161                         } else {
162                                 D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
163                                           tn->fn->raw->flash_offset &~3));
164                                 
165                                 jffs2_free_full_dnode(tn->fn);
166                                 jffs2_free_tmp_dnode_info(tn);
167                         }
168                 }
169         }
170                 
171         /* OK. Now clear up */
172         if (metadata) {
173                 jffs2_free_full_dnode(metadata->fn);
174                 jffs2_free_tmp_dnode_info(metadata);
175         }
176         metadata = NULL;
177         
178         while (fraglist) {
179                 struct jffs2_node_frag *frag;
180                 frag = fraglist;
181                 fraglist = fraglist->next;
182                 
183                 if (frag->node && !(--frag->node->frags)) {
184                         jffs2_free_full_dnode(frag->node);
185                 }
186                 jffs2_free_node_frag(frag);
187         }
188
189         /* Now for each child, increase nlink */
190         for(fd=ic->scan->dents; fd; fd = fd->next) {
191                 struct jffs2_inode_cache *child_ic;
192                 if (!fd->ino)
193                         continue;
194
195                 child_ic = jffs2_get_ino_cache(c, fd->ino);
196                 if (!child_ic) {
197                         printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
198                                   fd->name, fd->ino, ic->ino);
199                         continue;
200                 }
201
202                 if (child_ic->nlink++ && fd->type == DT_DIR) {
203                         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);
204                         /* What do we do about it? */
205                 }
206                 D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
207                 /* Can't free them. We might need them in pass 2 */
208         }
209         return 0;
210 }
211
212 int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
213 {
214         struct jffs2_raw_node_ref *raw;
215         struct jffs2_full_dirent *fd;
216         int ret = 0;
217
218         if(!ic->scan) {
219                 D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
220                 return 0;
221         }
222
223         D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
224         
225         for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
226                 D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3));
227                 jffs2_mark_node_obsolete(c, raw);
228         }
229
230         if (ic->scan->dents) {
231                 printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
232         
233                 while(ic->scan->dents) {
234                         struct jffs2_inode_cache *child_ic;
235
236                         fd = ic->scan->dents;
237                         ic->scan->dents = fd->next;
238
239                         D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
240                                   fd->name, fd->ino));
241                         
242                         child_ic = jffs2_get_ino_cache(c, fd->ino);
243                         if (!child_ic) {
244                                 printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
245                                 continue;
246                         }
247                         jffs2_free_full_dirent(fd);
248                         child_ic->nlink--;
249                 }
250                 ret = -EAGAIN;
251         }
252         kfree(ic->scan);
253         ic->scan = NULL;
254         //      jffs2_del_ino_cache(c, ic);
255         //      jffs2_free_inode_cache(ic);
256         return ret;
257 }