172 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * This file is part of UBIFS.
 | 
						|
 *
 | 
						|
 * Copyright (C) 2006-2008 Nokia Corporation.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify it
 | 
						|
 * under the terms of the GNU General Public License version 2 as published by
 | 
						|
 * the Free Software Foundation.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful, but WITHOUT
 | 
						|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 | 
						|
 * more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License along with
 | 
						|
 * this program; if not, write to the Free Software Foundation, Inc., 51
 | 
						|
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 | 
						|
 *
 | 
						|
 * Authors: Adrian Hunter
 | 
						|
 *          Artem Bityutskiy (Битюцкий Артём)
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * This file implements commit-related functionality of the LEB properties
 | 
						|
 * subsystem.
 | 
						|
 */
 | 
						|
 | 
						|
#include "crc16.h"
 | 
						|
#include "ubifs.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * free_obsolete_cnodes - free obsolete cnodes for commit end.
 | 
						|
 * @c: UBIFS file-system description object
 | 
						|
 */
 | 
						|
static void free_obsolete_cnodes(struct ubifs_info *c)
 | 
						|
{
 | 
						|
	struct ubifs_cnode *cnode, *cnext;
 | 
						|
 | 
						|
	cnext = c->lpt_cnext;
 | 
						|
	if (!cnext)
 | 
						|
		return;
 | 
						|
	do {
 | 
						|
		cnode = cnext;
 | 
						|
		cnext = cnode->cnext;
 | 
						|
		if (test_bit(OBSOLETE_CNODE, &cnode->flags))
 | 
						|
			kfree(cnode);
 | 
						|
		else
 | 
						|
			cnode->cnext = NULL;
 | 
						|
	} while (cnext != c->lpt_cnext);
 | 
						|
	c->lpt_cnext = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * first_nnode - find the first nnode in memory.
 | 
						|
 * @c: UBIFS file-system description object
 | 
						|
 * @hght: height of tree where nnode found is returned here
 | 
						|
 *
 | 
						|
 * This function returns a pointer to the nnode found or %NULL if no nnode is
 | 
						|
 * found. This function is a helper to 'ubifs_lpt_free()'.
 | 
						|
 */
 | 
						|
static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
 | 
						|
{
 | 
						|
	struct ubifs_nnode *nnode;
 | 
						|
	int h, i, found;
 | 
						|
 | 
						|
	nnode = c->nroot;
 | 
						|
	*hght = 0;
 | 
						|
	if (!nnode)
 | 
						|
		return NULL;
 | 
						|
	for (h = 1; h < c->lpt_hght; h++) {
 | 
						|
		found = 0;
 | 
						|
		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 | 
						|
			if (nnode->nbranch[i].nnode) {
 | 
						|
				found = 1;
 | 
						|
				nnode = nnode->nbranch[i].nnode;
 | 
						|
				*hght = h;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (!found)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	return nnode;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * next_nnode - find the next nnode in memory.
 | 
						|
 * @c: UBIFS file-system description object
 | 
						|
 * @nnode: nnode from which to start.
 | 
						|
 * @hght: height of tree where nnode is, is passed and returned here
 | 
						|
 *
 | 
						|
 * This function returns a pointer to the nnode found or %NULL if no nnode is
 | 
						|
 * found. This function is a helper to 'ubifs_lpt_free()'.
 | 
						|
 */
 | 
						|
static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
 | 
						|
				      struct ubifs_nnode *nnode, int *hght)
 | 
						|
{
 | 
						|
	struct ubifs_nnode *parent;
 | 
						|
	int iip, h, i, found;
 | 
						|
 | 
						|
	parent = nnode->parent;
 | 
						|
	if (!parent)
 | 
						|
		return NULL;
 | 
						|
	if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
 | 
						|
		*hght -= 1;
 | 
						|
		return parent;
 | 
						|
	}
 | 
						|
	for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
 | 
						|
		nnode = parent->nbranch[iip].nnode;
 | 
						|
		if (nnode)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (!nnode) {
 | 
						|
		*hght -= 1;
 | 
						|
		return parent;
 | 
						|
	}
 | 
						|
	for (h = *hght + 1; h < c->lpt_hght; h++) {
 | 
						|
		found = 0;
 | 
						|
		for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 | 
						|
			if (nnode->nbranch[i].nnode) {
 | 
						|
				found = 1;
 | 
						|
				nnode = nnode->nbranch[i].nnode;
 | 
						|
				*hght = h;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (!found)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	return nnode;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * ubifs_lpt_free - free resources owned by the LPT.
 | 
						|
 * @c: UBIFS file-system description object
 | 
						|
 * @wr_only: free only resources used for writing
 | 
						|
 */
 | 
						|
void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
 | 
						|
{
 | 
						|
	struct ubifs_nnode *nnode;
 | 
						|
	int i, hght;
 | 
						|
 | 
						|
	/* Free write-only things first */
 | 
						|
 | 
						|
	free_obsolete_cnodes(c); /* Leftover from a failed commit */
 | 
						|
 | 
						|
	vfree(c->ltab_cmt);
 | 
						|
	c->ltab_cmt = NULL;
 | 
						|
	vfree(c->lpt_buf);
 | 
						|
	c->lpt_buf = NULL;
 | 
						|
	kfree(c->lsave);
 | 
						|
	c->lsave = NULL;
 | 
						|
 | 
						|
	if (wr_only)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* Now free the rest */
 | 
						|
 | 
						|
	nnode = first_nnode(c, &hght);
 | 
						|
	while (nnode) {
 | 
						|
		for (i = 0; i < UBIFS_LPT_FANOUT; i++)
 | 
						|
			kfree(nnode->nbranch[i].nnode);
 | 
						|
		nnode = next_nnode(c, nnode, &hght);
 | 
						|
	}
 | 
						|
	for (i = 0; i < LPROPS_HEAP_CNT; i++)
 | 
						|
		kfree(c->lpt_heap[i].arr);
 | 
						|
	kfree(c->dirty_idx.arr);
 | 
						|
	kfree(c->nroot);
 | 
						|
	vfree(c->ltab);
 | 
						|
	kfree(c->lpt_nod_buf);
 | 
						|
}
 |