1 /*
2  * This file is part of UBIFS.
3  *
4  * Copyright (C) 2006-2008 Nokia Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * Authors: Adrian Hunter
20  *          Artem Bityutskiy (Битюцкий Артём)
21  */
22 
23 /*
24  * This file implements commit-related functionality of the LEB properties
25  * subsystem.
26  */
27 
28 #include "crc16.h"
29 #include "ubifs.h"
30 
31 /**
32  * free_obsolete_cnodes - free obsolete cnodes for commit end.
33  * @c: UBIFS file-system description object
34  */
free_obsolete_cnodes(struct ubifs_info * c)35 static void free_obsolete_cnodes(struct ubifs_info *c)
36 {
37 	struct ubifs_cnode *cnode, *cnext;
38 
39 	cnext = c->lpt_cnext;
40 	if (!cnext)
41 		return;
42 	do {
43 		cnode = cnext;
44 		cnext = cnode->cnext;
45 		if (test_bit(OBSOLETE_CNODE, &cnode->flags))
46 			kfree(cnode);
47 		else
48 			cnode->cnext = NULL;
49 	} while (cnext != c->lpt_cnext);
50 	c->lpt_cnext = NULL;
51 }
52 
53 /**
54  * first_nnode - find the first nnode in memory.
55  * @c: UBIFS file-system description object
56  * @hght: height of tree where nnode found is returned here
57  *
58  * This function returns a pointer to the nnode found or %NULL if no nnode is
59  * found. This function is a helper to 'ubifs_lpt_free()'.
60  */
first_nnode(struct ubifs_info * c,int * hght)61 static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
62 {
63 	struct ubifs_nnode *nnode;
64 	int h, i, found;
65 
66 	nnode = c->nroot;
67 	*hght = 0;
68 	if (!nnode)
69 		return NULL;
70 	for (h = 1; h < c->lpt_hght; h++) {
71 		found = 0;
72 		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
73 			if (nnode->nbranch[i].nnode) {
74 				found = 1;
75 				nnode = nnode->nbranch[i].nnode;
76 				*hght = h;
77 				break;
78 			}
79 		}
80 		if (!found)
81 			break;
82 	}
83 	return nnode;
84 }
85 
86 /**
87  * next_nnode - find the next nnode in memory.
88  * @c: UBIFS file-system description object
89  * @nnode: nnode from which to start.
90  * @hght: height of tree where nnode is, is passed and returned here
91  *
92  * This function returns a pointer to the nnode found or %NULL if no nnode is
93  * found. This function is a helper to 'ubifs_lpt_free()'.
94  */
next_nnode(struct ubifs_info * c,struct ubifs_nnode * nnode,int * hght)95 static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
96 				      struct ubifs_nnode *nnode, int *hght)
97 {
98 	struct ubifs_nnode *parent;
99 	int iip, h, i, found;
100 
101 	parent = nnode->parent;
102 	if (!parent)
103 		return NULL;
104 	if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
105 		*hght -= 1;
106 		return parent;
107 	}
108 	for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
109 		nnode = parent->nbranch[iip].nnode;
110 		if (nnode)
111 			break;
112 	}
113 	if (!nnode) {
114 		*hght -= 1;
115 		return parent;
116 	}
117 	for (h = *hght + 1; h < c->lpt_hght; h++) {
118 		found = 0;
119 		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
120 			if (nnode->nbranch[i].nnode) {
121 				found = 1;
122 				nnode = nnode->nbranch[i].nnode;
123 				*hght = h;
124 				break;
125 			}
126 		}
127 		if (!found)
128 			break;
129 	}
130 	return nnode;
131 }
132 
133 /**
134  * ubifs_lpt_free - free resources owned by the LPT.
135  * @c: UBIFS file-system description object
136  * @wr_only: free only resources used for writing
137  */
ubifs_lpt_free(struct ubifs_info * c,int wr_only)138 void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
139 {
140 	struct ubifs_nnode *nnode;
141 	int i, hght;
142 
143 	/* Free write-only things first */
144 
145 	free_obsolete_cnodes(c); /* Leftover from a failed commit */
146 
147 	vfree(c->ltab_cmt);
148 	c->ltab_cmt = NULL;
149 	vfree(c->lpt_buf);
150 	c->lpt_buf = NULL;
151 	kfree(c->lsave);
152 	c->lsave = NULL;
153 
154 	if (wr_only)
155 		return;
156 
157 	/* Now free the rest */
158 
159 	nnode = first_nnode(c, &hght);
160 	while (nnode) {
161 		for (i = 0; i < UBIFS_LPT_FANOUT; i++)
162 			kfree(nnode->nbranch[i].nnode);
163 		nnode = next_nnode(c, nnode, &hght);
164 	}
165 	for (i = 0; i < LPROPS_HEAP_CNT; i++)
166 		kfree(c->lpt_heap[i].arr);
167 	kfree(c->dirty_idx.arr);
168 	kfree(c->nroot);
169 	vfree(c->ltab);
170 	kfree(c->lpt_nod_buf);
171 }
172