2005-04-17 02:20:36 +04:00
/*
2005-11-02 06:58:39 +03:00
* Copyright ( c ) 2000 - 2001 , 2005 Silicon Graphics , Inc .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
2005-04-17 02:20:36 +04:00
* published by the Free Software Foundation .
*
2005-11-02 06:58:39 +03:00
* This program is distributed in the hope that it would 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 .
2005-04-17 02:20:36 +04:00
*
2005-11-02 06:58:39 +03:00
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2005-04-17 02:20:36 +04:00
*/
# include "xfs.h"
2005-11-02 06:38:42 +03:00
# include "xfs_fs.h"
2005-04-17 02:20:36 +04:00
# include "xfs_types.h"
# include "xfs_log.h"
2005-11-02 06:38:42 +03:00
# include "xfs_inum.h"
2005-04-17 02:20:36 +04:00
# include "xfs_trans.h"
# include "xfs_buf_item.h"
# include "xfs_sb.h"
2007-08-28 08:00:13 +04:00
# include "xfs_ag.h"
2005-04-17 02:20:36 +04:00
# include "xfs_mount.h"
# include "xfs_trans_priv.h"
# include "xfs_extfree_item.h"
kmem_zone_t * xfs_efi_zone ;
kmem_zone_t * xfs_efd_zone ;
2010-06-23 12:11:15 +04:00
static inline struct xfs_efi_log_item * EFI_ITEM ( struct xfs_log_item * lip )
{
return container_of ( lip , struct xfs_efi_log_item , efi_item ) ;
}
2005-04-17 02:20:36 +04:00
2005-06-21 09:41:19 +04:00
void
2010-06-23 12:11:15 +04:00
xfs_efi_item_free (
struct xfs_efi_log_item * efip )
2005-06-21 09:41:19 +04:00
{
2010-06-23 12:11:15 +04:00
if ( efip - > efi_format . efi_nextents > XFS_EFI_MAX_FAST_EXTENTS )
2008-05-19 10:31:57 +04:00
kmem_free ( efip ) ;
2010-06-23 12:11:15 +04:00
else
2005-06-21 09:41:19 +04:00
kmem_zone_free ( xfs_efi_zone , efip ) ;
}
2005-04-17 02:20:36 +04:00
2010-12-20 03:59:49 +03:00
/*
* Freeing the efi requires that we remove it from the AIL if it has already
* been placed there . However , the EFI may not yet have been placed in the AIL
* when called by xfs_efi_release ( ) from EFD processing due to the ordering of
* committed vs unpin operations in bulk insert operations . Hence the
* test_and_clear_bit ( XFS_EFI_COMMITTED ) to ensure only the last caller frees
* the EFI .
*/
STATIC void
__xfs_efi_release (
struct xfs_efi_log_item * efip )
{
struct xfs_ail * ailp = efip - > efi_item . li_ailp ;
if ( ! test_and_clear_bit ( XFS_EFI_COMMITTED , & efip - > efi_flags ) ) {
spin_lock ( & ailp - > xa_lock ) ;
/* xfs_trans_ail_delete() drops the AIL lock. */
xfs_trans_ail_delete ( ailp , & efip - > efi_item ) ;
xfs_efi_item_free ( efip ) ;
}
}
2005-04-17 02:20:36 +04:00
/*
* This returns the number of iovecs needed to log the given efi item .
* We only need 1 iovec for an efi item . It just logs the efi_log_format
* structure .
*/
STATIC uint
2010-06-23 12:11:15 +04:00
xfs_efi_item_size (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
return 1 ;
}
/*
* This is called to fill in the vector of log iovecs for the
* given efi log item . We use only 1 iovec , and we point that
* at the efi_log_format structure embedded in the efi item .
* It is at this point that we assert that all of the extent
* slots in the efi item have been filled .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_format (
struct xfs_log_item * lip ,
struct xfs_log_iovec * log_vector )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efi_log_item * efip = EFI_ITEM ( lip ) ;
uint size ;
2005-04-17 02:20:36 +04:00
2010-12-20 03:59:49 +03:00
ASSERT ( atomic_read ( & efip - > efi_next_extent ) = =
efip - > efi_format . efi_nextents ) ;
2005-04-17 02:20:36 +04:00
efip - > efi_format . efi_type = XFS_LI_EFI ;
size = sizeof ( xfs_efi_log_format_t ) ;
size + = ( efip - > efi_format . efi_nextents - 1 ) * sizeof ( xfs_extent_t ) ;
efip - > efi_format . efi_size = 1 ;
2010-06-23 12:11:15 +04:00
log_vector - > i_addr = & efip - > efi_format ;
2005-04-17 02:20:36 +04:00
log_vector - > i_len = size ;
2010-01-19 12:56:45 +03:00
log_vector - > i_type = XLOG_REG_TYPE_EFI_FORMAT ;
2005-04-17 02:20:36 +04:00
ASSERT ( size > = sizeof ( xfs_efi_log_format_t ) ) ;
}
/*
* Pinning has no meaning for an efi item , so just return .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_pin (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
}
/*
2010-12-20 03:57:24 +03:00
* While EFIs cannot really be pinned , the unpin operation is the last place at
* which the EFI is manipulated during a transaction . If we are being asked to
* remove the EFI it ' s because the transaction has been cancelled and by
* definition that means the EFI cannot be in the AIL so remove it from the
2010-12-20 03:59:49 +03:00
* transaction and free it . Otherwise coordinate with xfs_efi_release ( ) ( via
* XFS_EFI_COMMITTED ) to determine who gets to free the EFI .
2005-04-17 02:20:36 +04:00
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_unpin (
struct xfs_log_item * lip ,
int remove )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efi_log_item * efip = EFI_ITEM ( lip ) ;
2005-04-17 02:20:36 +04:00
2010-12-20 03:57:24 +03:00
if ( remove ) {
ASSERT ( ! ( lip - > li_flags & XFS_LI_IN_AIL ) ) ;
2011-01-27 04:13:35 +03:00
if ( lip - > li_desc )
xfs_trans_del_item ( lip ) ;
2005-06-21 09:41:19 +04:00
xfs_efi_item_free ( efip ) ;
2010-12-20 03:59:49 +03:00
return ;
2005-04-17 02:20:36 +04:00
}
2010-12-20 03:59:49 +03:00
__xfs_efi_release ( efip ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Efi items have no locking or pushing . However , since EFIs are
* pulled from the AIL when their corresponding EFDs are committed
* to disk , their situation is very similar to being pinned . Return
* XFS_ITEM_PINNED so that the caller will eventually flush the log .
* This should help in getting the EFI out of the AIL .
*/
STATIC uint
2010-06-23 12:11:15 +04:00
xfs_efi_item_trylock (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
return XFS_ITEM_PINNED ;
}
/*
* Efi items have no locking , so just return .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_unlock (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
if ( lip - > li_flags & XFS_LI_ABORTED )
xfs_efi_item_free ( EFI_ITEM ( lip ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
2010-12-20 03:59:49 +03:00
* The EFI is logged only once and cannot be moved in the log , so simply return
* the lsn at which it ' s been logged . For bulk transaction committed
* processing , the EFI may be processed but not yet unpinned prior to the EFD
* being processed . Set the XFS_EFI_COMMITTED flag so this case can be detected
* when processing the EFD .
2005-04-17 02:20:36 +04:00
*/
STATIC xfs_lsn_t
2010-06-23 12:11:15 +04:00
xfs_efi_item_committed (
struct xfs_log_item * lip ,
xfs_lsn_t lsn )
2005-04-17 02:20:36 +04:00
{
2010-12-20 03:59:49 +03:00
struct xfs_efi_log_item * efip = EFI_ITEM ( lip ) ;
set_bit ( XFS_EFI_COMMITTED , & efip - > efi_flags ) ;
2005-04-17 02:20:36 +04:00
return lsn ;
}
/*
* There isn ' t much you can do to push on an efi item . It is simply
* stuck waiting for all of its corresponding efd items to be
* committed to disk .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_push (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
}
/*
* The EFI dependency tracking op doesn ' t do squat . It can ' t because
* it doesn ' t know where the free extent is coming from . The dependency
* tracking has to be handled by the " enclosing " metadata object . For
* example , for inodes , the inode is locked throughout the extent freeing
* so the dependency should be recorded there .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efi_item_committing (
struct xfs_log_item * lip ,
xfs_lsn_t lsn )
2005-04-17 02:20:36 +04:00
{
}
/*
* This is the ops vector shared by all efi log items .
*/
2011-10-28 13:54:24 +04:00
static const struct xfs_item_ops xfs_efi_item_ops = {
2010-06-23 12:11:15 +04:00
. iop_size = xfs_efi_item_size ,
. iop_format = xfs_efi_item_format ,
. iop_pin = xfs_efi_item_pin ,
. iop_unpin = xfs_efi_item_unpin ,
. iop_trylock = xfs_efi_item_trylock ,
. iop_unlock = xfs_efi_item_unlock ,
. iop_committed = xfs_efi_item_committed ,
. iop_push = xfs_efi_item_push ,
. iop_committing = xfs_efi_item_committing
2005-04-17 02:20:36 +04:00
} ;
/*
* Allocate and initialize an efi item with the given number of extents .
*/
2010-06-23 12:11:15 +04:00
struct xfs_efi_log_item *
xfs_efi_init (
struct xfs_mount * mp ,
uint nextents )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efi_log_item * efip ;
2005-04-17 02:20:36 +04:00
uint size ;
ASSERT ( nextents > 0 ) ;
if ( nextents > XFS_EFI_MAX_FAST_EXTENTS ) {
size = ( uint ) ( sizeof ( xfs_efi_log_item_t ) +
( ( nextents - 1 ) * sizeof ( xfs_extent_t ) ) ) ;
2010-06-23 12:11:15 +04:00
efip = kmem_zalloc ( size , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-06-23 12:11:15 +04:00
efip = kmem_zone_zalloc ( xfs_efi_zone , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-23 02:10:00 +03:00
xfs_log_item_init ( mp , & efip - > efi_item , XFS_LI_EFI , & xfs_efi_item_ops ) ;
2005-04-17 02:20:36 +04:00
efip - > efi_format . efi_nextents = nextents ;
efip - > efi_format . efi_id = ( __psint_t ) ( void * ) efip ;
2010-12-20 03:59:49 +03:00
atomic_set ( & efip - > efi_next_extent , 0 ) ;
2005-04-17 02:20:36 +04:00
2010-06-23 12:11:15 +04:00
return efip ;
2005-04-17 02:20:36 +04:00
}
2006-06-09 08:55:38 +04:00
/*
* Copy an EFI format buffer from the given buf , and into the destination
* EFI format structure .
* The given buffer can be in 32 bit or 64 bit form ( which has different padding ) ,
* one of which will be the native format for this kernel .
* It will handle the conversion of formats if necessary .
*/
int
xfs_efi_copy_format ( xfs_log_iovec_t * buf , xfs_efi_log_format_t * dst_efi_fmt )
{
2010-06-23 12:11:15 +04:00
xfs_efi_log_format_t * src_efi_fmt = buf - > i_addr ;
2006-06-09 08:55:38 +04:00
uint i ;
uint len = sizeof ( xfs_efi_log_format_t ) +
( src_efi_fmt - > efi_nextents - 1 ) * sizeof ( xfs_extent_t ) ;
uint len32 = sizeof ( xfs_efi_log_format_32_t ) +
( src_efi_fmt - > efi_nextents - 1 ) * sizeof ( xfs_extent_32_t ) ;
uint len64 = sizeof ( xfs_efi_log_format_64_t ) +
( src_efi_fmt - > efi_nextents - 1 ) * sizeof ( xfs_extent_64_t ) ;
if ( buf - > i_len = = len ) {
memcpy ( ( char * ) dst_efi_fmt , ( char * ) src_efi_fmt , len ) ;
return 0 ;
} else if ( buf - > i_len = = len32 ) {
2010-06-23 12:11:15 +04:00
xfs_efi_log_format_32_t * src_efi_fmt_32 = buf - > i_addr ;
2006-06-09 08:55:38 +04:00
dst_efi_fmt - > efi_type = src_efi_fmt_32 - > efi_type ;
dst_efi_fmt - > efi_size = src_efi_fmt_32 - > efi_size ;
dst_efi_fmt - > efi_nextents = src_efi_fmt_32 - > efi_nextents ;
dst_efi_fmt - > efi_id = src_efi_fmt_32 - > efi_id ;
for ( i = 0 ; i < dst_efi_fmt - > efi_nextents ; i + + ) {
dst_efi_fmt - > efi_extents [ i ] . ext_start =
src_efi_fmt_32 - > efi_extents [ i ] . ext_start ;
dst_efi_fmt - > efi_extents [ i ] . ext_len =
src_efi_fmt_32 - > efi_extents [ i ] . ext_len ;
}
return 0 ;
} else if ( buf - > i_len = = len64 ) {
2010-06-23 12:11:15 +04:00
xfs_efi_log_format_64_t * src_efi_fmt_64 = buf - > i_addr ;
2006-06-09 08:55:38 +04:00
dst_efi_fmt - > efi_type = src_efi_fmt_64 - > efi_type ;
dst_efi_fmt - > efi_size = src_efi_fmt_64 - > efi_size ;
dst_efi_fmt - > efi_nextents = src_efi_fmt_64 - > efi_nextents ;
dst_efi_fmt - > efi_id = src_efi_fmt_64 - > efi_id ;
for ( i = 0 ; i < dst_efi_fmt - > efi_nextents ; i + + ) {
dst_efi_fmt - > efi_extents [ i ] . ext_start =
src_efi_fmt_64 - > efi_extents [ i ] . ext_start ;
dst_efi_fmt - > efi_extents [ i ] . ext_len =
src_efi_fmt_64 - > efi_extents [ i ] . ext_len ;
}
return 0 ;
}
return EFSCORRUPTED ;
}
2005-04-17 02:20:36 +04:00
/*
2010-12-20 03:59:49 +03:00
* This is called by the efd item code below to release references to the given
* efi item . Each efd calls this with the number of extents that it has
* logged , and when the sum of these reaches the total number of extents logged
* by this efi item we can free the efi item .
2005-04-17 02:20:36 +04:00
*/
void
xfs_efi_release ( xfs_efi_log_item_t * efip ,
uint nextents )
{
2010-12-20 03:59:49 +03:00
ASSERT ( atomic_read ( & efip - > efi_next_extent ) > = nextents ) ;
if ( atomic_sub_and_test ( nextents , & efip - > efi_next_extent ) )
__xfs_efi_release ( efip ) ;
2005-04-17 02:20:36 +04:00
}
2010-06-23 12:11:15 +04:00
static inline struct xfs_efd_log_item * EFD_ITEM ( struct xfs_log_item * lip )
2005-06-21 09:41:19 +04:00
{
2010-06-23 12:11:15 +04:00
return container_of ( lip , struct xfs_efd_log_item , efd_item ) ;
}
2005-04-17 02:20:36 +04:00
2010-06-23 12:11:15 +04:00
STATIC void
xfs_efd_item_free ( struct xfs_efd_log_item * efdp )
{
if ( efdp - > efd_format . efd_nextents > XFS_EFD_MAX_FAST_EXTENTS )
2008-05-19 10:31:57 +04:00
kmem_free ( efdp ) ;
2010-06-23 12:11:15 +04:00
else
2005-06-21 09:41:19 +04:00
kmem_zone_free ( xfs_efd_zone , efdp ) ;
}
2005-04-17 02:20:36 +04:00
/*
* This returns the number of iovecs needed to log the given efd item .
* We only need 1 iovec for an efd item . It just logs the efd_log_format
* structure .
*/
STATIC uint
2010-06-23 12:11:15 +04:00
xfs_efd_item_size (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
return 1 ;
}
/*
* This is called to fill in the vector of log iovecs for the
* given efd log item . We use only 1 iovec , and we point that
* at the efd_log_format structure embedded in the efd item .
* It is at this point that we assert that all of the extent
* slots in the efd item have been filled .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_format (
struct xfs_log_item * lip ,
struct xfs_log_iovec * log_vector )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efd_log_item * efdp = EFD_ITEM ( lip ) ;
uint size ;
2005-04-17 02:20:36 +04:00
ASSERT ( efdp - > efd_next_extent = = efdp - > efd_format . efd_nextents ) ;
efdp - > efd_format . efd_type = XFS_LI_EFD ;
size = sizeof ( xfs_efd_log_format_t ) ;
size + = ( efdp - > efd_format . efd_nextents - 1 ) * sizeof ( xfs_extent_t ) ;
efdp - > efd_format . efd_size = 1 ;
2010-06-23 12:11:15 +04:00
log_vector - > i_addr = & efdp - > efd_format ;
2005-04-17 02:20:36 +04:00
log_vector - > i_len = size ;
2010-01-19 12:56:45 +03:00
log_vector - > i_type = XLOG_REG_TYPE_EFD_FORMAT ;
2005-04-17 02:20:36 +04:00
ASSERT ( size > = sizeof ( xfs_efd_log_format_t ) ) ;
}
/*
* Pinning has no meaning for an efd item , so just return .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_pin (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
}
/*
* Since pinning has no meaning for an efd item , unpinning does
* not either .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_unpin (
struct xfs_log_item * lip ,
int remove )
2005-04-17 02:20:36 +04:00
{
}
/*
* Efd items have no locking , so just return success .
*/
STATIC uint
2010-06-23 12:11:15 +04:00
xfs_efd_item_trylock (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
return XFS_ITEM_LOCKED ;
}
/*
* Efd items have no locking or pushing , so return failure
* so that the caller doesn ' t bother with us .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_unlock (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
if ( lip - > li_flags & XFS_LI_ABORTED )
xfs_efd_item_free ( EFD_ITEM ( lip ) ) ;
2005-04-17 02:20:36 +04:00
}
/*
* When the efd item is committed to disk , all we need to do
* is delete our reference to our partner efi item and then
* free ourselves . Since we ' re freeing ourselves we must
* return - 1 to keep the transaction code from further referencing
* this item .
*/
STATIC xfs_lsn_t
2010-06-23 12:11:15 +04:00
xfs_efd_item_committed (
struct xfs_log_item * lip ,
xfs_lsn_t lsn )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efd_log_item * efdp = EFD_ITEM ( lip ) ;
2005-04-17 02:20:36 +04:00
/*
* If we got a log I / O error , it ' s always the case that the LR with the
* EFI got unpinned and freed before the EFD got aborted .
*/
2010-06-23 12:11:15 +04:00
if ( ! ( lip - > li_flags & XFS_LI_ABORTED ) )
2005-04-17 02:20:36 +04:00
xfs_efi_release ( efdp - > efd_efip , efdp - > efd_format . efd_nextents ) ;
2005-06-21 09:41:19 +04:00
xfs_efd_item_free ( efdp ) ;
2005-04-17 02:20:36 +04:00
return ( xfs_lsn_t ) - 1 ;
}
/*
* There isn ' t much you can do to push on an efd item . It is simply
* stuck waiting for the log to be flushed to disk .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_push (
struct xfs_log_item * lip )
2005-04-17 02:20:36 +04:00
{
}
/*
* The EFD dependency tracking op doesn ' t do squat . It can ' t because
* it doesn ' t know where the free extent is coming from . The dependency
* tracking has to be handled by the " enclosing " metadata object . For
* example , for inodes , the inode is locked throughout the extent freeing
* so the dependency should be recorded there .
*/
STATIC void
2010-06-23 12:11:15 +04:00
xfs_efd_item_committing (
struct xfs_log_item * lip ,
xfs_lsn_t lsn )
2005-04-17 02:20:36 +04:00
{
}
/*
* This is the ops vector shared by all efd log items .
*/
2011-10-28 13:54:24 +04:00
static const struct xfs_item_ops xfs_efd_item_ops = {
2010-06-23 12:11:15 +04:00
. iop_size = xfs_efd_item_size ,
. iop_format = xfs_efd_item_format ,
. iop_pin = xfs_efd_item_pin ,
. iop_unpin = xfs_efd_item_unpin ,
. iop_trylock = xfs_efd_item_trylock ,
. iop_unlock = xfs_efd_item_unlock ,
. iop_committed = xfs_efd_item_committed ,
. iop_push = xfs_efd_item_push ,
. iop_committing = xfs_efd_item_committing
2005-04-17 02:20:36 +04:00
} ;
/*
* Allocate and initialize an efd item with the given number of extents .
*/
2010-06-23 12:11:15 +04:00
struct xfs_efd_log_item *
xfs_efd_init (
struct xfs_mount * mp ,
struct xfs_efi_log_item * efip ,
uint nextents )
2005-04-17 02:20:36 +04:00
{
2010-06-23 12:11:15 +04:00
struct xfs_efd_log_item * efdp ;
2005-04-17 02:20:36 +04:00
uint size ;
ASSERT ( nextents > 0 ) ;
if ( nextents > XFS_EFD_MAX_FAST_EXTENTS ) {
size = ( uint ) ( sizeof ( xfs_efd_log_item_t ) +
( ( nextents - 1 ) * sizeof ( xfs_extent_t ) ) ) ;
2010-06-23 12:11:15 +04:00
efdp = kmem_zalloc ( size , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
} else {
2010-06-23 12:11:15 +04:00
efdp = kmem_zone_zalloc ( xfs_efd_zone , KM_SLEEP ) ;
2005-04-17 02:20:36 +04:00
}
2010-03-23 02:10:00 +03:00
xfs_log_item_init ( mp , & efdp - > efd_item , XFS_LI_EFD , & xfs_efd_item_ops ) ;
2005-04-17 02:20:36 +04:00
efdp - > efd_efip = efip ;
efdp - > efd_format . efd_nextents = nextents ;
efdp - > efd_format . efd_efi_id = efip - > efi_format . efi_id ;
2010-06-23 12:11:15 +04:00
return efdp ;
2005-04-17 02:20:36 +04:00
}