/*
 * tools/lib/vg_read_with_pv_and_lv.c
 *
 * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Sistina Software
 *
 * March,October,November 1997
 * June,August 1998
 * January,March 1999
 * January 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
 *
 *    12/06/1998 - seperated memory for PVs, PEs and LVs
 *                 in vg_read_with_pv_and_lv() from pv_read_all_pv cache
 *    20/03/1999 - added major device number correction in case
 *                 of old block device major 
 *    08/02/2000 - use debug_enter()/debug_leave()
 *    08/01/2001 - set up core pointers for snapshots
 *
 */

#include <liblvm.h>


int vg_read_with_pv_and_lv ( char *vg_name, vg_t **vg) {
   int l = 0;
   int lv_num = 0;
   int p = 0;
   int ope = 0;
   int npe = 0;
   int ret = 0;
   int size = 0;
   uint pe_index = 0;
   pe_disk_t **pe = NULL;
   lv_t **lv = NULL;
   vg_t *vg_this = NULL;
   pv_t **pv = NULL;

#ifdef DEBUG
   debug_enter ( "vg_read_with_pv_and_lv -- CALLED\n");
#endif

   if ( vg_name == NULL || vg == NULL ||
        vg_check_name ( vg_name) < 0) {
      ret = -LVM_EPARAM;
      goto vg_read_with_pv_and_lv_end;
   }

   *vg = NULL;
   if ( ( ret = vg_read ( vg_name, &vg_this)) < 0 &&
        ret != -LVM_EVG_READ_VG_EXPORTED)
      goto vg_read_with_pv_and_lv_end;

#ifdef DEBUG
   debug ( "vg_read_with_pv_and_lv -- AFTER vg_read; "
            " vg_this->lv_cur: %lu\n", vg_this->lv_cur);
#endif

   if ( vg_this->pv_cur == 0) {
      ret = -LVM_EVG_READ_WITH_PV_AND_LV_PV_CUR;
      goto vg_read_with_pv_and_lv_end;
   }

   if ( ( ret = pv_read_all_pv_of_vg ( vg_name, &pv, FALSE)) < 0)
      goto vg_read_with_pv_and_lv_end;

#ifdef DEBUG
   debug ( "vg_read_with_pv_and_lv -- AFTER pv_read_all_pv_of_vg\n");
#endif

   if ( ( ret = pv_read_all_pe_of_vg ( vg_name, &pe, FALSE)) < 0)
      goto vg_read_with_pv_and_lv_end;

#ifdef DEBUG
   debug ( "vg_read_with_pv_and_lv -- AFTER pv_read_all_pe_of_vg\n");
#endif

   if ( ( ret = lv_read_all_lv ( vg_name, &lv, FALSE)) < 0)
      goto vg_read_with_pv_and_lv_end;

#ifdef DEBUG
   debug ( "vg_read_with_pv_and_lv -- AFTER lv_read_all_lv;"
            " vg_this->pv_cur: %lu  vg_this->pv_max: %lu  ret: %d\n",
            vg_this->pv_cur, vg_this->pv_max, ret);
#endif

   if ( ret == 0) {
#ifdef DEBUG
      debug (  "vg_read_with_pv_and_lv -- BEFORE for PE\n");
#endif
      /* set up PE pointers in PVs */
      for ( p = 0; p < vg_this->pv_cur; p++) {
         if ( ( vg_this->pv[p] = malloc ( sizeof ( pv_t))) == NULL) {
            fprintf ( stderr, "malloc error in %s [line %d]\n",
                              __FILE__, __LINE__);
            vg_free ( vg_this, FALSE);
            ret = -LVM_EVG_READ_WITH_PV_AND_LV_MALLOC;
            goto vg_read_with_pv_and_lv_end;
         }
         memcpy ( vg_this->pv[p], pv[p], sizeof ( pv_t));
         size = vg_this->pv[p]->pe_total * sizeof ( pe_disk_t);
         if ( ( vg_this->pv[p]->pe = malloc ( size)) == NULL) {
            fprintf ( stderr, "malloc error in %s [line %d]\n",
                              __FILE__, __LINE__);
            vg_free ( vg_this, FALSE);
            ret = -LVM_EVG_READ_WITH_PV_AND_LV_MALLOC;
            goto vg_read_with_pv_and_lv_end;
         }
         memcpy ( vg_this->pv[p]->pe, pe[p], size);
      }
#ifdef DEBUG
      debug (  "vg_read_with_pv_and_lv -- AFTER for PE\n");
#endif

      /* build the lv_current_pe structure array */
#ifdef DEBUG
      debug (  "vg_read_with_pv_and_lv -- BEFORE for LV\n");
#endif
      for ( l = 0; l < vg_this->lv_max; l++) vg_this->lv[l] = NULL;
      if ( vg_this->lv_cur > 0) {
         for ( l = 0; l < vg_this->lv_max; l++) {
            lv_num = l + 1;
            if ( lv[l] != NULL) {
               if ( ( vg_this->lv[l] = malloc ( sizeof ( lv_t))) == NULL) {
                  fprintf ( stderr, "malloc error in %s [line %d]\n",
                                    __FILE__, __LINE__);
                  vg_free ( vg_this, FALSE);
                  ret = -LVM_EVG_READ_WITH_PV_AND_LV_MALLOC;
                  goto vg_read_with_pv_and_lv_end;
               }
               memcpy ( vg_this->lv[l], lv[l], sizeof ( lv_t));
#ifdef DEBUG
               debug ( "vg_read_with_pv_and_lv -- vg_this->lv[%d]->"
                        "lv_allocated_le: %lu\n", l,
                        vg_this->lv[l]->lv_allocated_le);
#endif
               if ( ( vg_this->lv[l]->lv_current_pe = malloc (
                         vg_this->lv[l]->lv_allocated_le *
                         sizeof ( pe_t))) == NULL) {
                  fprintf ( stderr, "malloc error in %s [line %d]\n",
                                    __FILE__, __LINE__);
                  vg_free ( vg_this, FALSE);
                  ret = -LVM_EVG_READ_WITH_PV_AND_LV_MALLOC;
                  goto vg_read_with_pv_and_lv_end;
               }
               /* construct the lv_current_pe pointer array */
               p = npe = 0;
               for ( p = 0; p < vg_this->pv_cur &&
                            npe < vg_this->lv[l]->lv_allocated_le; p++) {
                  for ( ope = 0; ope < vg_this->pv[p]->pe_total; ope++) {
                     if ( vg_this->pv[p]->pe[ope].lv_num == lv_num) {
                        pe_index = vg_this->pv[p]->pe[ope].le_num;
                        vg_this->lv[l]->lv_current_pe[pe_index].dev =
                           vg_this->pv[p]->pv_dev;
                        vg_this->lv[l]->lv_current_pe[pe_index].pe =
			   LVM_PE_DISK_OFFSET( ope, vg_this->pv[p]);
                        vg_this->lv[l]->lv_current_pe[pe_index].reads = \
                        vg_this->lv[l]->lv_current_pe[pe_index].writes = 0;
                        npe++;
                     }
                  }
               }
               if ( npe != vg_this->lv[l]->lv_allocated_le) {
                  ret = -LVM_EVG_READ_WITH_PV_AND_LV_LV_ALLOCATED_LE;
                  goto vg_read_with_pv_and_lv_end;
               }
               /* correct LVM_BLK_MAJOR */
               if ( MAJOR ( vg_this->lv[l]->lv_dev) != LVM_BLK_MAJOR) {
                  vg_this->lv[l]->lv_dev = ( LVM_BLK_MAJOR << MINORBITS) +
                                           MINOR ( vg_this->lv[l]->lv_dev);
               }
            } else vg_this->lv[l] = NULL;
         }
      }
   } /* if ( ret == 0) */

   if ( ret == 0) *vg = vg_this;
   else goto vg_read_with_pv_and_lv_end;

   /* Set up core pointers for snapshots */
   vg_setup_pointers_for_snapshots ( *vg);

vg_read_with_pv_and_lv_end:
#ifdef DEBUG
   debug_leave ( "vg_read_with_pv_and_lv -- LEAVING with ret: %d\n", ret);
#endif
   return ret;
}
