| /* |
| * 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); |
| } |