/*
 * tools/lib/pv_reserve_pe.c
 *
 * Copyright (C) 1997 - 2000  Heinz Mauelshagen, Sistina Software
 *
 * March 1997
 * July  1998
 * January,July,September 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
 *
 *    07/07/1998 - added read/write statistic init
 *    21/01/1999 - fixed contiguous logical volume extension bug
 *    05/07/1999 - fixed striped logical volume shrink bug
 *    29/10/1999 - fixed possible free() bug
 *    08/02/2000 - use debug_enter()/debug_leave()
 *
 */

#include <liblvm.h>

int pv_reserve_pe ( pv_t *pv, pe_disk_t *lv_pe, uint *pe,
                    pe_t *pe_p, uint allocation, int new) {
   int np = 0;
   int p = 0;
   int ret = 0;

#ifdef DEBUG
   debug_enter ( "pv_reserve_pe -- CALLED: pv->pv_dev: %02d:%02d  lv_num: %d"
                 "  le_num: %d  pv->pe_total: %lu\n",
                 MAJOR(pv->pv_dev),
                 MINOR(pv->pv_dev),
                 lv_pe->lv_num,
                 lv_pe->le_num,
                 pv->pe_total);
#endif

   if ( pv == NULL || lv_pe == NULL || lv_pe->lv_num > MAX_LV ||
        pe == NULL || *pe == 0 || pe_p == NULL ||
        ( allocation != 0 && allocation != LV_CONTIGUOUS) ||
        ( new != TRUE && new != FALSE)) {
      ret = -LVM_EPARAM;
      goto pv_reserve_pe_end;
   }

   for ( p = 0; p < pv->pe_total && np < *pe; p++) {
      if ( pv->pe[p].lv_num == 0) {
#ifdef DEBUG
      debug ( "pv_reserve_pe -- empty PE %d\n", p);
#endif
         /* check in case of contiguous allocation */
         if ( lv_check_on_pv ( pv, lv_pe->lv_num) == TRUE) {
            if ( new == FALSE && ( allocation & LV_CONTIGUOUS) &&
                 pv->pe[p-1].lv_num != lv_pe->lv_num) {
               ret = -LVM_ESIZE;
               goto pv_reserve_pe_end;
            }
         }
         pv->pe[p].lv_num = lv_pe->lv_num;
         pv->pe[p].le_num = lv_pe->le_num;
         lv_pe->le_num++;
         pv->pe_allocated++;
         pe_p->dev = pv->pv_dev;
         pe_p->pe = LVM_PE_DISK_OFFSET( p, pv);
         pe_p->reads = pe_p->writes = 0;
         pe_p++;
         np++;
      }
   }
   *pe -= np;

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