/*
 * tools/lib/lv_setup_COW_table_for_create.c
 *
 * Copyright (C)  2000  Heinz Mauelshagen, Sistina Software
 *
 * July 2000
 *
 *
 *
 * 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
 *
 *    26/06/2001 - fix off-by-one error when allocating COW table.
 */

#include <liblvm.h>


int lv_setup_COW_table_for_create ( vg_t *vg,
                                    char *lv_org_name,
                                    int l_new,
                                    int chunk_size) {
   int e, end, index, le, l_org, ret = 0, start, COW_table_chunks_per_PE;
   ulong size;
   lv_t *lv = NULL;

   debug_enter ( "lv_setup_COW_table_for_create -- CALLED\n");

   if ( vg_check_consistency ( vg) < 0 ||
        lv_org_name == NULL ||
        lv_check_name ( lv_org_name) < 0 ||
        vg->lv[l_new] == NULL) ret = -LVM_EPARAM;
   else {
      l_org = lv_get_index_by_name ( vg, lv_org_name);
      lv = vg->lv[l_new];
      lv->lv_access |= LV_SNAPSHOT;
      lv->lv_snapshot_org = NULL;
      lv->lv_snapshot_minor = MINOR ( vg->lv[l_org]->lv_dev);
      vg->lv[l_org]->lv_access |= LV_SNAPSHOT_ORG;
      vg->lv[l_org]->lv_snapshot_minor = 0;

      /* remap chunk size */
      lv->lv_chunk_size = ( chunk_size * 1024) / SECTOR_SIZE;
      COW_table_chunks_per_PE = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv);
      end = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv);

      if(!end) {
	      ret = LVM_ELV_SETUP_COW_TABLE_FOR_CREATE_MALLOC;
	      goto out;
      }

      start = COW_table_chunks_per_PE - end;
      size = end * sizeof(lv_block_exception_t) * lv->lv_allocated_le;

      if ( ( lv->lv_block_exception = malloc ( size)) == NULL) {
         fprintf(stderr, "%s -- ERROR: malloc at line %d\n\n", cmd, __LINE__);
         ret = LVM_ELV_SETUP_COW_TABLE_FOR_CREATE_MALLOC;
      } else {
         memset ( lv->lv_block_exception, 0, size);
         index = 0;

         for ( le = 0; le < lv->lv_allocated_le; le++) {
            for ( e = start; e < COW_table_chunks_per_PE; e++) {
               lv->lv_block_exception[index].rdev_new =
                  lv->lv_current_pe[le].dev;
               lv->lv_block_exception[index].rsector_new =
                  lv->lv_current_pe[le].pe + e * lv->lv_chunk_size;
               index++;
            }
         }
         lv->lv_remap_end = index;
         lv->lv_remap_ptr = 0;
      }
   }

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