1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 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_yaffs1.h"
15 #include "yportenv.h"
16 #include "yaffs_trace.h"
17 #include "yaffs_bitmap.h"
18 #include "yaffs_getblockinfo.h"
19 #include "yaffs_nand.h"
20 #include "yaffs_attribs.h"
21 #include <dm/devres.h>
22 
yaffs1_scan(struct yaffs_dev * dev)23 int yaffs1_scan(struct yaffs_dev *dev)
24 {
25 	struct yaffs_ext_tags tags;
26 	int blk;
27 	int chunk;
28 	int c;
29 	int deleted;
30 	enum yaffs_block_state state;
31 	LIST_HEAD(hard_list);
32 	struct yaffs_block_info *bi;
33 	u32 seq_number;
34 	struct yaffs_obj_hdr *oh;
35 	struct yaffs_obj *in;
36 	struct yaffs_obj *parent;
37 	int alloc_failed = 0;
38 	struct yaffs_shadow_fixer *shadow_fixers = NULL;
39 	u8 *chunk_data;
40 
41 	yaffs_trace(YAFFS_TRACE_SCAN,
42 		"yaffs1_scan starts  intstartblk %d intendblk %d...",
43 		dev->internal_start_block, dev->internal_end_block);
44 
45 	chunk_data = yaffs_get_temp_buffer(dev);
46 
47 	dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
48 
49 	/* Scan all the blocks to determine their state */
50 	bi = dev->block_info;
51 	for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
52 	     blk++) {
53 		yaffs_clear_chunk_bits(dev, blk);
54 		bi->pages_in_use = 0;
55 		bi->soft_del_pages = 0;
56 
57 		yaffs_query_init_block_state(dev, blk, &state, &seq_number);
58 
59 		bi->block_state = state;
60 		bi->seq_number = seq_number;
61 
62 		if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
63 			bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
64 
65 		yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
66 			"Block scanning block %d state %d seq %d",
67 			blk, state, seq_number);
68 
69 		if (state == YAFFS_BLOCK_STATE_DEAD) {
70 			yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
71 				"block %d is bad", blk);
72 		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
73 			yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
74 			dev->n_erased_blocks++;
75 			dev->n_free_chunks += dev->param.chunks_per_block;
76 		}
77 		bi++;
78 	}
79 
80 	/* For each block.... */
81 	for (blk = dev->internal_start_block;
82 	     !alloc_failed && blk <= dev->internal_end_block; blk++) {
83 
84 		cond_resched();
85 
86 		bi = yaffs_get_block_info(dev, blk);
87 		state = bi->block_state;
88 
89 		deleted = 0;
90 
91 		/* For each chunk in each block that needs scanning.... */
92 		for (c = 0;
93 			!alloc_failed && c < dev->param.chunks_per_block &&
94 			state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
95 			/* Read the tags and decide what to do */
96 			chunk = blk * dev->param.chunks_per_block + c;
97 
98 			yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
99 
100 			/* Let's have a good look at this chunk... */
101 
102 			if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
103 			    tags.is_deleted) {
104 				/* YAFFS1 only...
105 				 * A deleted chunk
106 				 */
107 				deleted++;
108 				dev->n_free_chunks++;
109 			} else if (!tags.chunk_used) {
110 				/* An unassigned chunk in the block
111 				 * This means that either the block is empty or
112 				 * this is the one being allocated from
113 				 */
114 
115 				if (c == 0) {
116 					/* We're looking at the first chunk in
117 					 *the block so the block is unused */
118 					state = YAFFS_BLOCK_STATE_EMPTY;
119 					dev->n_erased_blocks++;
120 				} else {
121 					/* this is the block being allocated */
122 					yaffs_trace(YAFFS_TRACE_SCAN,
123 						" Allocating from %d %d",
124 						blk, c);
125 					state = YAFFS_BLOCK_STATE_ALLOCATING;
126 					dev->alloc_block = blk;
127 					dev->alloc_page = c;
128 					dev->alloc_block_finder = blk;
129 
130 				}
131 
132 				dev->n_free_chunks +=
133 				    (dev->param.chunks_per_block - c);
134 			} else if (tags.chunk_id > 0) {
135 				/* chunk_id > 0 so it is a data chunk... */
136 				unsigned int endpos;
137 
138 				yaffs_set_chunk_bit(dev, blk, c);
139 				bi->pages_in_use++;
140 
141 				in = yaffs_find_or_create_by_number(dev,
142 							tags.obj_id,
143 							YAFFS_OBJECT_TYPE_FILE);
144 				/* PutChunkIntoFile checks for a clash
145 				 * (two data chunks with the same chunk_id).
146 				 */
147 
148 				if (!in)
149 					alloc_failed = 1;
150 
151 				if (in) {
152 					if (!yaffs_put_chunk_in_file
153 					    (in, tags.chunk_id, chunk, 1))
154 						alloc_failed = 1;
155 				}
156 
157 				endpos =
158 				    (tags.chunk_id - 1) *
159 				    dev->data_bytes_per_chunk +
160 				    tags.n_bytes;
161 				if (in &&
162 				    in->variant_type ==
163 				     YAFFS_OBJECT_TYPE_FILE &&
164 				    in->variant.file_variant.scanned_size <
165 				      endpos) {
166 					in->variant.file_variant.scanned_size =
167 					    endpos;
168 					if (!dev->param.use_header_file_size) {
169 						in->variant.
170 						    file_variant.file_size =
171 						    in->variant.
172 						    file_variant.scanned_size;
173 					}
174 
175 				}
176 			} else {
177 				/* chunk_id == 0, so it is an ObjectHeader.
178 				 * Make the object
179 				 */
180 				yaffs_set_chunk_bit(dev, blk, c);
181 				bi->pages_in_use++;
182 
183 				yaffs_rd_chunk_tags_nand(dev, chunk,
184 							 chunk_data, NULL);
185 
186 				oh = (struct yaffs_obj_hdr *)chunk_data;
187 
188 				in = yaffs_find_by_number(dev, tags.obj_id);
189 				if (in && in->variant_type != oh->type) {
190 					/* This should not happen, but somehow
191 					 * Wev'e ended up with an obj_id that
192 					 * has been reused but not yet deleted,
193 					 * and worse still it has changed type.
194 					 * Delete the old object.
195 					 */
196 
197 					yaffs_del_obj(in);
198 					in = NULL;
199 				}
200 
201 				in = yaffs_find_or_create_by_number(dev,
202 								tags.obj_id,
203 								oh->type);
204 
205 				if (!in)
206 					alloc_failed = 1;
207 
208 				if (in && oh->shadows_obj > 0) {
209 
210 					struct yaffs_shadow_fixer *fixer;
211 					fixer =
212 						kmalloc(sizeof
213 						(struct yaffs_shadow_fixer),
214 						GFP_NOFS);
215 					if (fixer) {
216 						fixer->next = shadow_fixers;
217 						shadow_fixers = fixer;
218 						fixer->obj_id = tags.obj_id;
219 						fixer->shadowed_id =
220 						    oh->shadows_obj;
221 						yaffs_trace(YAFFS_TRACE_SCAN,
222 							" Shadow fixer: %d shadows %d",
223 							fixer->obj_id,
224 							fixer->shadowed_id);
225 
226 					}
227 
228 				}
229 
230 				if (in && in->valid) {
231 					/* We have already filled this one.
232 					 * We have a duplicate and need to
233 					 * resolve it. */
234 
235 					unsigned existing_serial = in->serial;
236 					unsigned new_serial =
237 					    tags.serial_number;
238 
239 					if (((existing_serial + 1) & 3) ==
240 					    new_serial) {
241 						/* Use new one - destroy the
242 						 * exisiting one */
243 						yaffs_chunk_del(dev,
244 								in->hdr_chunk,
245 								1, __LINE__);
246 						in->valid = 0;
247 					} else {
248 						/* Use existing - destroy
249 						 * this one. */
250 						yaffs_chunk_del(dev, chunk, 1,
251 								__LINE__);
252 					}
253 				}
254 
255 				if (in && !in->valid &&
256 				    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
257 				     tags.obj_id ==
258 				     YAFFS_OBJECTID_LOSTNFOUND)) {
259 					/* We only load some info, don't fiddle
260 					 * with directory structure */
261 					in->valid = 1;
262 					in->variant_type = oh->type;
263 
264 					in->yst_mode = oh->yst_mode;
265 					yaffs_load_attribs(in, oh);
266 					in->hdr_chunk = chunk;
267 					in->serial = tags.serial_number;
268 
269 				} else if (in && !in->valid) {
270 					/* we need to load this info */
271 
272 					in->valid = 1;
273 					in->variant_type = oh->type;
274 
275 					in->yst_mode = oh->yst_mode;
276 					yaffs_load_attribs(in, oh);
277 					in->hdr_chunk = chunk;
278 					in->serial = tags.serial_number;
279 
280 					yaffs_set_obj_name_from_oh(in, oh);
281 					in->dirty = 0;
282 
283 					/* directory stuff...
284 					 * hook up to parent
285 					 */
286 
287 					parent =
288 					    yaffs_find_or_create_by_number
289 					    (dev, oh->parent_obj_id,
290 					     YAFFS_OBJECT_TYPE_DIRECTORY);
291 					if (!parent)
292 						alloc_failed = 1;
293 					if (parent && parent->variant_type ==
294 					    YAFFS_OBJECT_TYPE_UNKNOWN) {
295 						/* Set up as a directory */
296 						parent->variant_type =
297 						    YAFFS_OBJECT_TYPE_DIRECTORY;
298 						INIT_LIST_HEAD(&parent->
299 							variant.dir_variant.
300 							children);
301 					} else if (!parent ||
302 						parent->variant_type !=
303 						YAFFS_OBJECT_TYPE_DIRECTORY) {
304 						/* Hoosterman, a problem....
305 						 * We're trying to use a
306 						 * non-directory as a directory
307 						 */
308 
309 						yaffs_trace(YAFFS_TRACE_ERROR,
310 							"yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
311 							);
312 						parent = dev->lost_n_found;
313 					}
314 
315 					yaffs_add_obj_to_dir(parent, in);
316 
317 					switch (in->variant_type) {
318 					case YAFFS_OBJECT_TYPE_UNKNOWN:
319 						/* Todo got a problem */
320 						break;
321 					case YAFFS_OBJECT_TYPE_FILE:
322 						if (dev->param.
323 						    use_header_file_size)
324 							in->variant.
325 							file_variant.file_size
326 							= yaffs_oh_to_size(oh);
327 						break;
328 					case YAFFS_OBJECT_TYPE_HARDLINK:
329 						in->variant.
330 						    hardlink_variant.equiv_id =
331 						    oh->equiv_id;
332 						list_add(&in->hard_links,
333 								&hard_list);
334 						break;
335 					case YAFFS_OBJECT_TYPE_DIRECTORY:
336 						/* Do nothing */
337 						break;
338 					case YAFFS_OBJECT_TYPE_SPECIAL:
339 						/* Do nothing */
340 						break;
341 					case YAFFS_OBJECT_TYPE_SYMLINK:
342 						in->variant.symlink_variant.
343 						    alias =
344 						    yaffs_clone_str(oh->alias);
345 						if (!in->variant.
346 						    symlink_variant.alias)
347 							alloc_failed = 1;
348 						break;
349 					}
350 				}
351 			}
352 		}
353 
354 		if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
355 			/* If we got this far while scanning,
356 			 * then the block is fully allocated. */
357 			state = YAFFS_BLOCK_STATE_FULL;
358 		}
359 
360 		if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
361 			/* If the block was partially allocated then
362 			 * treat it as fully allocated. */
363 			state = YAFFS_BLOCK_STATE_FULL;
364 			dev->alloc_block = -1;
365 		}
366 
367 		bi->block_state = state;
368 
369 		/* Now let's see if it was dirty */
370 		if (bi->pages_in_use == 0 &&
371 		    !bi->has_shrink_hdr &&
372 		    bi->block_state == YAFFS_BLOCK_STATE_FULL)
373 			yaffs_block_became_dirty(dev, blk);
374 	}
375 
376 	/* Ok, we've done all the scanning.
377 	 * Fix up the hard link chains.
378 	 * We should now have scanned all the objects, now it's time to add
379 	 * these hardlinks.
380 	 */
381 
382 	yaffs_link_fixup(dev, &hard_list);
383 
384 	/*
385 	 * Fix up any shadowed objects.
386 	 * There should not be more than one of these.
387 	 */
388 	{
389 		struct yaffs_shadow_fixer *fixer;
390 		struct yaffs_obj *obj;
391 
392 		while (shadow_fixers) {
393 			fixer = shadow_fixers;
394 			shadow_fixers = fixer->next;
395 			/* Complete the rename transaction by deleting the
396 			 * shadowed object then setting the object header
397 			 to unshadowed.
398 			 */
399 			obj = yaffs_find_by_number(dev, fixer->shadowed_id);
400 			if (obj)
401 				yaffs_del_obj(obj);
402 
403 			obj = yaffs_find_by_number(dev, fixer->obj_id);
404 
405 			if (obj)
406 				yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
407 
408 			kfree(fixer);
409 		}
410 	}
411 
412 	yaffs_release_temp_buffer(dev, chunk_data);
413 
414 	if (alloc_failed)
415 		return YAFFS_FAIL;
416 
417 	yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
418 
419 	return YAFFS_OK;
420 }
421