Blame view

fs/ubifs/tnc_misc.c 12.2 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
2
3
4
5
6
  /*
   * This file is part of UBIFS.
   *
   * Copyright (C) 2006-2008 Nokia Corporation.
   *
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
7
8
9
10
11
12
13
14
15
16
   * Authors: Adrian Hunter
   *          Artem Bityutskiy (Битюцкий Артём)
   */
  
  /*
   * This file contains miscelanious TNC-related functions shared betweend
   * different files. This file does not form any logically separate TNC
   * sub-system. The file was created because there is a lot of TNC code and
   * putting it all in one file would make that file too big and unreadable.
   */
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
17
  #ifdef __UBOOT__
61b29b826   Simon Glass   dm: core: Require...
18
  #include <dm/devres.h>
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
19
20
  #include <linux/err.h>
  #endif
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  #include "ubifs.h"
  
  /**
   * ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal.
   * @zr: root of the subtree to traverse
   * @znode: previous znode
   *
   * This function implements levelorder TNC traversal. The LNC is ignored.
   * Returns the next element or %NULL if @znode is already the last one.
   */
  struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
  					      struct ubifs_znode *znode)
  {
  	int level, iip, level_search = 0;
  	struct ubifs_znode *zn;
  
  	ubifs_assert(zr);
  
  	if (unlikely(!znode))
  		return zr;
  
  	if (unlikely(znode == zr)) {
  		if (znode->level == 0)
  			return NULL;
  		return ubifs_tnc_find_child(zr, 0);
  	}
  
  	level = znode->level;
  
  	iip = znode->iip;
  	while (1) {
  		ubifs_assert(znode->level <= zr->level);
  
  		/*
  		 * First walk up until there is a znode with next branch to
  		 * look at.
  		 */
  		while (znode->parent != zr && iip >= znode->parent->child_cnt) {
  			znode = znode->parent;
  			iip = znode->iip;
  		}
  
  		if (unlikely(znode->parent == zr &&
  			     iip >= znode->parent->child_cnt)) {
  			/* This level is done, switch to the lower one */
  			level -= 1;
  			if (level_search || level < 0)
  				/*
  				 * We were already looking for znode at lower
  				 * level ('level_search'). As we are here
  				 * again, it just does not exist. Or all levels
  				 * were finished ('level < 0').
  				 */
  				return NULL;
  
  			level_search = 1;
  			iip = -1;
  			znode = ubifs_tnc_find_child(zr, 0);
  			ubifs_assert(znode);
  		}
  
  		/* Switch to the next index */
  		zn = ubifs_tnc_find_child(znode->parent, iip + 1);
  		if (!zn) {
  			/* No more children to look at, we have walk up */
  			iip = znode->parent->child_cnt;
  			continue;
  		}
  
  		/* Walk back down to the level we came from ('level') */
  		while (zn->level != level) {
  			znode = zn;
  			zn = ubifs_tnc_find_child(zn, 0);
  			if (!zn) {
  				/*
  				 * This path is not too deep so it does not
  				 * reach 'level'. Try next path.
  				 */
  				iip = znode->iip;
  				break;
  			}
  		}
  
  		if (zn) {
  			ubifs_assert(zn->level >= 0);
  			return zn;
  		}
  	}
  }
  
  /**
   * ubifs_search_zbranch - search znode branch.
   * @c: UBIFS file-system description object
   * @znode: znode to search in
   * @key: key to search for
   * @n: znode branch slot number is returned here
   *
   * This is a helper function which search branch with key @key in @znode using
   * binary search. The result of the search may be:
   *   o exact match, then %1 is returned, and the slot number of the branch is
   *     stored in @n;
   *   o no exact match, then %0 is returned and the slot number of the left
   *     closest branch is returned in @n; the slot if all keys in this znode are
   *     greater than @key, then %-1 is returned in @n.
   */
  int ubifs_search_zbranch(const struct ubifs_info *c,
  			 const struct ubifs_znode *znode,
  			 const union ubifs_key *key, int *n)
  {
  	int beg = 0, end = znode->child_cnt, uninitialized_var(mid);
  	int uninitialized_var(cmp);
  	const struct ubifs_zbranch *zbr = &znode->zbranch[0];
  
  	ubifs_assert(end > beg);
  
  	while (end > beg) {
  		mid = (beg + end) >> 1;
  		cmp = keys_cmp(c, key, &zbr[mid].key);
  		if (cmp > 0)
  			beg = mid + 1;
  		else if (cmp < 0)
  			end = mid;
  		else {
  			*n = mid;
  			return 1;
  		}
  	}
  
  	*n = end - 1;
  
  	/* The insert point is after *n */
  	ubifs_assert(*n >= -1 && *n < znode->child_cnt);
  	if (*n == -1)
  		ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0);
  	else
  		ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0);
  	if (*n + 1 < znode->child_cnt)
  		ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0);
  
  	return 0;
  }
  
  /**
   * ubifs_tnc_postorder_first - find first znode to do postorder tree traversal.
   * @znode: znode to start at (root of the sub-tree to traverse)
   *
   * Find the lowest leftmost znode in a subtree of the TNC tree. The LNC is
   * ignored.
   */
  struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode)
  {
  	if (unlikely(!znode))
  		return NULL;
  
  	while (znode->level > 0) {
  		struct ubifs_znode *child;
  
  		child = ubifs_tnc_find_child(znode, 0);
  		if (!child)
  			return znode;
  		znode = child;
  	}
  
  	return znode;
  }
  
  /**
   * ubifs_tnc_postorder_next - next TNC tree element in postorder traversal.
   * @znode: previous znode
   *
   * This function implements postorder TNC traversal. The LNC is ignored.
   * Returns the next element or %NULL if @znode is already the last one.
   */
  struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
  {
  	struct ubifs_znode *zn;
  
  	ubifs_assert(znode);
  	if (unlikely(!znode->parent))
  		return NULL;
  
  	/* Switch to the next index in the parent */
  	zn = ubifs_tnc_find_child(znode->parent, znode->iip + 1);
  	if (!zn)
  		/* This is in fact the last child, return parent */
  		return znode->parent;
  
  	/* Go to the first znode in this new subtree */
  	return ubifs_tnc_postorder_first(zn);
  }
  
  /**
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
   * ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree.
   * @znode: znode defining subtree to destroy
   *
   * This function destroys subtree of the TNC tree. Returns number of clean
   * znodes in the subtree.
   */
  long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode)
  {
  	struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode);
  	long clean_freed = 0;
  	int n;
  
  	ubifs_assert(zn);
  	while (1) {
  		for (n = 0; n < zn->child_cnt; n++) {
  			if (!zn->zbranch[n].znode)
  				continue;
  
  			if (zn->level > 0 &&
  			    !ubifs_zn_dirty(zn->zbranch[n].znode))
  				clean_freed += 1;
  
  			cond_resched();
  			kfree(zn->zbranch[n].znode);
  		}
  
  		if (zn == znode) {
  			if (!ubifs_zn_dirty(zn))
  				clean_freed += 1;
  			kfree(zn);
  			return clean_freed;
  		}
  
  		zn = ubifs_tnc_postorder_next(zn);
  	}
  }
  
  /**
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
   * read_znode - read an indexing node from flash and fill znode.
   * @c: UBIFS file-system description object
   * @lnum: LEB of the indexing node to read
   * @offs: node offset
   * @len: node length
   * @znode: znode to read to
   *
   * This function reads an indexing node from the flash media and fills znode
   * with the read data. Returns zero in case of success and a negative error
   * code in case of failure. The read indexing node is validated and if anything
   * is wrong with it, this function prints complaint messages and returns
   * %-EINVAL.
   */
  static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
  		      struct ubifs_znode *znode)
  {
  	int i, err, type, cmp;
  	struct ubifs_idx_node *idx;
  
  	idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
  	if (!idx)
  		return -ENOMEM;
  
  	err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
  	if (err < 0) {
  		kfree(idx);
  		return err;
  	}
  
  	znode->child_cnt = le16_to_cpu(idx->child_cnt);
  	znode->level = le16_to_cpu(idx->level);
  
  	dbg_tnc("LEB %d:%d, level %d, %d branch",
  		lnum, offs, znode->level, znode->child_cnt);
  
  	if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
287
  		ubifs_err(c, "current fanout %d, branch count %d",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
288
  			  c->fanout, znode->child_cnt);
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
289
  		ubifs_err(c, "max levels %d, znode level %d",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
290
  			  UBIFS_MAX_LEVELS, znode->level);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  		err = 1;
  		goto out_dump;
  	}
  
  	for (i = 0; i < znode->child_cnt; i++) {
  		const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
  		struct ubifs_zbranch *zbr = &znode->zbranch[i];
  
  		key_read(c, &br->key, &zbr->key);
  		zbr->lnum = le32_to_cpu(br->lnum);
  		zbr->offs = le32_to_cpu(br->offs);
  		zbr->len  = le32_to_cpu(br->len);
  		zbr->znode = NULL;
  
  		/* Validate branch */
  
  		if (zbr->lnum < c->main_first ||
  		    zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
  		    zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
310
  			ubifs_err(c, "bad branch %d", i);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
311
312
313
314
315
316
317
318
319
320
321
  			err = 2;
  			goto out_dump;
  		}
  
  		switch (key_type(c, &zbr->key)) {
  		case UBIFS_INO_KEY:
  		case UBIFS_DATA_KEY:
  		case UBIFS_DENT_KEY:
  		case UBIFS_XENT_KEY:
  			break;
  		default:
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
322
  			ubifs_err(c, "bad key type at slot %d: %d",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
323
  				  i, key_type(c, &zbr->key));
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
324
325
326
327
328
329
330
331
332
333
  			err = 3;
  			goto out_dump;
  		}
  
  		if (znode->level)
  			continue;
  
  		type = key_type(c, &zbr->key);
  		if (c->ranges[type].max_len == 0) {
  			if (zbr->len != c->ranges[type].len) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
334
  				ubifs_err(c, "bad target node (type %d) length (%d)",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
335
  					  type, zbr->len);
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
336
  				ubifs_err(c, "have to be %d", c->ranges[type].len);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
337
338
339
340
341
  				err = 4;
  				goto out_dump;
  			}
  		} else if (zbr->len < c->ranges[type].min_len ||
  			   zbr->len > c->ranges[type].max_len) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
342
  			ubifs_err(c, "bad target node (type %d) length (%d)",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
343
  				  type, zbr->len);
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
344
  			ubifs_err(c, "have to be in range of %d-%d",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
345
346
  				  c->ranges[type].min_len,
  				  c->ranges[type].max_len);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  			err = 5;
  			goto out_dump;
  		}
  	}
  
  	/*
  	 * Ensure that the next key is greater or equivalent to the
  	 * previous one.
  	 */
  	for (i = 0; i < znode->child_cnt - 1; i++) {
  		const union ubifs_key *key1, *key2;
  
  		key1 = &znode->zbranch[i].key;
  		key2 = &znode->zbranch[i + 1].key;
  
  		cmp = keys_cmp(c, key1, key2);
  		if (cmp > 0) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
364
  			ubifs_err(c, "bad key order (keys %d and %d)", i, i + 1);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
365
366
367
368
  			err = 6;
  			goto out_dump;
  		} else if (cmp == 0 && !is_hash_key(c, key1)) {
  			/* These can only be keys with colliding hash */
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
369
  			ubifs_err(c, "keys %d and %d are not hashed but equivalent",
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
370
  				  i, i + 1);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
371
372
373
374
375
376
377
378
379
  			err = 7;
  			goto out_dump;
  		}
  	}
  
  	kfree(idx);
  	return 0;
  
  out_dump:
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
380
  	ubifs_err(c, "bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
381
  	ubifs_dump_node(c, idx);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  	kfree(idx);
  	return -EINVAL;
  }
  
  /**
   * ubifs_load_znode - load znode to TNC cache.
   * @c: UBIFS file-system description object
   * @zbr: znode branch
   * @parent: znode's parent
   * @iip: index in parent
   *
   * This function loads znode pointed to by @zbr into the TNC cache and
   * returns pointer to it in case of success and a negative error code in case
   * of failure.
   */
  struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
  				     struct ubifs_zbranch *zbr,
  				     struct ubifs_znode *parent, int iip)
  {
  	int err;
  	struct ubifs_znode *znode;
  
  	ubifs_assert(!zbr->znode);
  	/*
  	 * A slab cache is not presently used for znodes because the znode size
  	 * depends on the fanout which is stored in the superblock.
  	 */
  	znode = kzalloc(c->max_znode_sz, GFP_NOFS);
  	if (!znode)
  		return ERR_PTR(-ENOMEM);
  
  	err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode);
  	if (err)
  		goto out;
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
416
417
418
419
420
421
422
423
424
  	atomic_long_inc(&c->clean_zn_cnt);
  
  	/*
  	 * Increment the global clean znode counter as well. It is OK that
  	 * global and per-FS clean znode counters may be inconsistent for some
  	 * short time (because we might be preempted at this point), the global
  	 * one is only used in shrinker.
  	 */
  	atomic_long_inc(&ubifs_clean_zn_cnt);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  	zbr->znode = znode;
  	znode->parent = parent;
  	znode->time = get_seconds();
  	znode->iip = iip;
  
  	return znode;
  
  out:
  	kfree(znode);
  	return ERR_PTR(err);
  }
  
  /**
   * ubifs_tnc_read_node - read a leaf node from the flash media.
   * @c: UBIFS file-system description object
   * @zbr: key and position of the node
   * @node: node is returned here
   *
   * This function reads a node defined by @zbr from the flash media. Returns
   * zero in case of success or a negative negative error code in case of
   * failure.
   */
  int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
  			void *node)
  {
  	union ubifs_key key1, *key = &zbr->key;
  	int err, type = key_type(c, key);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
452
  	struct ubifs_wbuf *wbuf;
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
453

ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
454
455
456
457
458
459
460
461
462
463
464
  	/*
  	 * 'zbr' has to point to on-flash node. The node may sit in a bud and
  	 * may even be in a write buffer, so we have to take care about this.
  	 */
  	wbuf = ubifs_get_wbuf(c, zbr->lnum);
  	if (wbuf)
  		err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len,
  					   zbr->lnum, zbr->offs);
  	else
  		err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
  				      zbr->offs);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
465
466
  
  	if (err) {
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
467
  		dbg_tnck(key, "key ");
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
468
469
470
471
472
473
  		return err;
  	}
  
  	/* Make sure the key of the read node is correct */
  	key_read(c, node + UBIFS_KEY_OFFSET, &key1);
  	if (!keys_eq(c, key, &key1)) {
0195a7bb3   Heiko Schocher   ubi,ubifs: sync w...
474
  		ubifs_err(c, "bad key in node at LEB %d:%d",
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
475
  			  zbr->lnum, zbr->offs);
ff94bc40a   Heiko Schocher   mtd, ubi, ubifs: ...
476
477
478
  		dbg_tnck(key, "looked for key ");
  		dbg_tnck(&key1, "but found node's key ");
  		ubifs_dump_node(c, node);
9eefe2a2b   Stefan Roese   UBIFS: Implement ...
479
480
481
482
483
  		return -EINVAL;
  	}
  
  	return 0;
  }