/*
 * tools/lib/lv_release.c
 *
 * Copyright (C) 1997 - 2001  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * January 2000
 * January,April 2001
 *
 *
 * This LVM library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This LVM library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this LVM library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 *
 */

/*
 * Changelog
 *
 *    31/01/2000 - use debug_enter()/debug_leave()
 *    08/01/2000 - reset the original snapshot in case the last
 *                 snapshot is released
 *    09/04/2001 - cleaned up debug output (Andreas Dilger)
 *
 */

#include <liblvm.h>

int lv_release ( vg_t *vg, char *lv_name) {
   int l = 0;
   int lv_num = 0;
   int p = 0;
   uint pe = 0;
   uint pe_released = 0;
   int ret = 0;

   debug_enter ( "lv_release -- CALLED with %s\n", lv_name);

   if ( vg == NULL || lv_check_name ( lv_name) < 0) {
      ret = -LVM_EPARAM;
      goto lv_release_end;
   }

   /* search for this LV */
   for ( l = 0; l < vg->lv_max; l++)
      if ( vg->lv[l] != NULL &&
           strcmp ( vg->lv[l]->lv_name, lv_name) == 0) break;
   debug ( "lv_release -- after search for %s\n", lv_name);
   if ( l == vg->lv_max) {
      debug ( "lv_release -- %s NOT found\n", lv_name);
      ret = -LVM_ELV_RELEASE_LV_NUM;
      goto lv_release_end;
   }
   debug ( "lv_release -- %s found\n", lv_name);
   /* if it was a snapshot we optionally need to
      update the snapshot origin */
   if ( vg->lv[l]->lv_access & LV_SNAPSHOT &&
       vg->lv[l]->lv_snapshot_next == NULL &&
       vg->lv[l]->lv_snapshot_org->lv_snapshot_next == vg->lv[l]) {
      vg->lv[l]->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG;
   }

   lv_num = l + 1;
   debug ( "lv_release -- l: %d  lv_num: %d  pv_cur: %lu\n",
            l, lv_num, vg->pv_cur);
   /* walk through physical volumes freeing physical extents */
   p = 0;
   for ( p = 0; p < vg->pv_cur; p++) {
      pe_released = 0;
      debug ( "lv_release -- vg->pv[%d]: %X\n", p, ( uint) vg->pv[p]);
      debug ( "lv_release -- vg->pv[%d]->pe: %X\n", p,
               ( uint) vg->pv[p]->pe);
      /* walk through physical extents */
      for ( pe = 0; pe < vg->pv[p]->pe_total; pe++) {
         if ( vg->pv[p]->pe[pe].lv_num == lv_num) {
             vg->pv[p]->pe[pe].lv_num = vg->pv[p]->pe[pe].le_num = 0;
             vg->pv[p]->pe_allocated--;
             pe_released++;
         }
      }
      if ( pe_released > 0) vg->pv[p]->lv_cur--;
   }

   vg->lv_cur--;
   vg->pe_allocated -= vg->lv[l]->lv_allocated_le;
   free ( vg->lv[l]);
   vg->lv[l] = NULL;

lv_release_end:

   debug_leave ( "lv_release -- LEAVING with ret: %d\n", ret);
   return ret;
}
