/* Copyright (c) 2016, 2021, MariaDB Corporation.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "mysys_priv.h"
my_bool my_may_have_atomic_write= IF_WIN(1 ,0 );
#ifdef __linux__
my_bool has_shannon_atomic_write, has_fusion_io_atomic_write,
has_sfx_atomic_write;
my_bool has_sfx_card;
#include <sys/ioctl.h>
/* Linux seems to allow up to 15 partitions per block device.
Partition number 0 is the whole block device. */
# define SAME_DEV(fs_dev, blk_dev) \
(fs_dev == blk_dev) || ((fs_dev & ~15 U) == blk_dev)
/***********************************************************************
FUSION_IO
************************************************************************/
/** FusionIO atomic write control info */
#define DFS_IOCTL_ATOMIC_WRITE_SET _IOW(0 x95, 2 , uint)
/**
Check if the system has a funsion_io card
@ return TRUE Card exists
*/
static my_bool test_if_fusion_io_card_exists()
{
/* Fusion card requires fallocate to exists */
#ifndef HAVE_POSIX_FALLOCATE
return 0 ;
#else
return (access("/dev/fcta" , F_OK)) == 0 ;
#endif
}
/**
Check if a file is on a Fusion_IO device and that it supports atomic_write
@ param [ in ] file OS file handle
@ param [ in ] page_size page size
@ return TRUE Atomic write supported
*/
static my_bool fusion_io_has_atomic_write(File file, int page_size)
{
int atomic= 1 ;
if (page_size <= 32768 &&
ioctl(file, DFS_IOCTL_ATOMIC_WRITE_SET, &atomic) != -1 )
return (TRUE );
return (FALSE );
}
/***********************************************************************
SHANNON
************************************************************************/
#define SHANNON_IOMAGIC 'x'
#define SHANNON_IOCQATOMIC_SIZE _IO(SHANNON_IOMAGIC, 22 )
#define SHANNON_MAX_DEVICES 32
#define SHANNON_NO_ATOMIC_SIZE_YET -2
struct shannon_dev
{
char dev_name[32 ];
dev_t st_dev;
int atomic_size;
};
static struct shannon_dev shannon_devices[SHANNON_MAX_DEVICES+1 ];
/**
Check if the system has a Shannon card
If card exists , record device numbers to allow us to later check if
a given file is on this device .
@ return TRUE Card exists
*/
static my_bool test_if_shannon_card_exists()
{
uint shannon_found_devices= 0 ;
char dev_part;
uint dev_no;
if (access("/dev/scta" , F_OK) < 0 )
return 0 ;
/*
The Shannon devices are / dev / dfX , where X can be from a - z .
We have to check all of them as some may be missing if the user
removed one with the U . 2 interface .
*/
for (dev_part= 'a' ; dev_part < 'z' ; dev_part++)
{
char path[32 ];
struct stat stat_buff;
snprintf(path, sizeof (path), "/dev/df%c" , dev_part);
#ifdef TEST_SHANNON
if (stat(path, &stat_buff) < 0 )
{
printf("%s(): stat %s failed.\n" , __func__, path);
break ;
}
#endif
shannon_devices[shannon_found_devices].st_dev= stat_buff.st_rdev;
snprintf(shannon_devices[shannon_found_devices].dev_name,
sizeof (shannon_devices[shannon_found_devices].dev_name),
"/dev/sct%c" ,
dev_part);
#ifdef TEST_SHANNON
printf("%s(): i=%d, stat_buff.st_dev=0x%lx, stat_buff.st_rdev=0x%lx, st_rdev=0x%lx, dev_name=%s\n" ,
__func__,
shannon_found_devices,
(ulong) stat_buff.st_dev,
(ulong) stat_buff.st_rdev,
(ulong) shannon_devices[shannon_found_devices].st_dev,
shannon_devices[shannon_found_devices].dev_name);
#endif
/*
The atomic size will be checked on first access . This is needed
as a normal user can ' t open the / dev / scta file
*/
shannon_devices[shannon_found_devices].atomic_size=
SHANNON_NO_ATOMIC_SIZE_YET;
if (++shannon_found_devices== SHANNON_MAX_DEVICES)
goto end;
for (dev_no= 1 ; dev_no < 9 ; dev_no++)
{
snprintf(path, sizeof (path), "/dev/df%c%d" , dev_part, dev_no);
if (stat(path, &stat_buff) < 0 )
break ;
shannon_devices[shannon_found_devices].st_dev= stat_buff.st_rdev;
snprintf(shannon_devices[shannon_found_devices].dev_name,
sizeof (shannon_devices[shannon_found_devices].dev_name),
"/dev/sct%c%d" ,
dev_part, dev_no);
#ifdef TEST_SHANNON
printf("%s(): i=%d, st_dev=0x%lx, st_rdev=0x%lx, dev_name=%s\n" ,
__func__,
shannon_found_devices,
(ulong) stat_buff.st_dev,
(ulong) shannon_devices[shannon_found_devices].st_dev,
shannon_devices[shannon_found_devices].dev_name);
#endif
/*
The atomic size will be checked on first access . This is needed
as a normal user can ' t open the / dev / scta file
*/
shannon_devices[shannon_found_devices].atomic_size=
SHANNON_NO_ATOMIC_SIZE_YET;
if (++shannon_found_devices == SHANNON_MAX_DEVICES)
goto end;
}
}
end:
shannon_devices[shannon_found_devices].st_dev= 0 ;
return shannon_found_devices > 0 ;
}
static my_bool shannon_dev_has_atomic_write(struct shannon_dev *dev,
int page_size)
{
#ifdef TEST_SHANNON
printf("%s: enter: page_size=%d, atomic_size=%d, dev_name=%s\n" ,
__func__,
page_size,
dev->atomic_size,
dev->dev_name);
#endif
if (dev->atomic_size == SHANNON_NO_ATOMIC_SIZE_YET)
{
int fd= open(dev->dev_name, 0 );
if (fd < 0 )
{
fprintf(stderr, "Unable to determine if atomic writes are supported:"
" open(\" %s\"): %m\n" , dev->dev_name);
dev->atomic_size= 0 ; /* Don't try again */
return FALSE ;
}
dev->atomic_size= ioctl(fd, SHANNON_IOCQATOMIC_SIZE);
close(fd);
}
#ifdef TEST_SHANNON
printf("%s: exit: page_size=%d, atomic_size=%d, dev_name=%s\n" ,
__func__,
page_size,
dev->atomic_size,
dev->dev_name);
#endif
return (page_size <= dev->atomic_size);
}
/**
Check if a file is on a Shannon device and that it supports atomic_write
@ param [ in ] file OS file handle
@ param [ in ] page_size page size
@ return TRUE Atomic write supported
@ notes
This is called only at first open of a file . In this case it doesn ' t
matter so much that we loop over all cards .
We update the atomic size on first access .
*/
static my_bool shannon_has_atomic_write(File file, int page_size)
{
struct shannon_dev *dev;
struct stat stat_buff;
if (fstat(file, &stat_buff) < 0 )
{
#ifdef TEST_SHANNON
printf("%s(): fstat failed\n" , __func__);
#endif
return 0 ;
}
#ifdef TEST_SHANNON
printf("%s(): st_dev=0x%lx, st_rdev=0x%lx\n" , __func__,
(ulong) stat_buff.st_dev, (ulong) stat_buff.st_rdev);
#endif
for (dev= shannon_devices ; dev->st_dev; dev++)
{
#ifdef TEST_SHANNON
printf("%s(): st_rdev=0x%lx\n" , __func__, (ulong) dev->st_dev);
#endif
if (SAME_DEV(stat_buff.st_dev, dev->st_dev))
return shannon_dev_has_atomic_write(dev, page_size);
}
return 0 ;
}
/***********************************************************************
ScaleFlux
************************************************************************/
#define SFX_GET_ATOMIC_SIZE _IOR('N' , 0 x243, int )
#define SFX_MAX_DEVICES (32 )
#define SFX_UNKNOWN_ATOMIC_WRITE_YET (-2 )
#define SFX_MAX_ATOMIC_SIZE (256 * 1024 )
#define SFX_GET_SPACE_RATIO _IO('N' , 0 x244)
#define SFX_UNKNOWN_PUNCH_HOLE_YET (-3 )
/**
Threshold for logical_space / physical_space
No less than the threshold means we can disable hole punching
*/
#define SFX_DISABLE_PUNCH_HOLE_RATIO (2 )
struct sfx_dev
{
char dev_name[32 ];
dev_t st_dev;
int atomic_write;
int disable_punch_hole;
};
static struct sfx_dev sfx_devices[SFX_MAX_DEVICES + 1 ];
/**
Check if the system has a ScaleFlux card
If card exists , record device numbers to allow us to later check if
a given file is on this device
Variables for atomic_write and disable_punch_hole will be initialized
@ return TRUE Card exists
*/
static my_bool test_if_sfx_card_exists()
{
uint sfx_found_devices = 0 ;
uint dev_num;
for (dev_num = 0 ; dev_num < SFX_MAX_DEVICES; dev_num++)
{
struct stat stat_buff;
snprintf(sfx_devices[sfx_found_devices].dev_name,
sizeof (sfx_devices[sfx_found_devices].dev_name),
"/dev/sfdv%dn1" , dev_num);
if (stat(sfx_devices[sfx_found_devices].dev_name, &stat_buff) < 0 )
break ;
sfx_devices[sfx_found_devices].st_dev= stat_buff.st_rdev;
/*
The atomic size will be checked on first access . This is needed
as a normal user can ' t open the / dev / sfdvXn1 file
*/
sfx_devices[sfx_found_devices].atomic_write= SFX_UNKNOWN_ATOMIC_WRITE_YET;
sfx_devices[sfx_found_devices].disable_punch_hole=
SFX_UNKNOWN_PUNCH_HOLE_YET;
if (++sfx_found_devices == SFX_MAX_DEVICES)
goto end;
}
end:
sfx_devices[sfx_found_devices].st_dev= 0 ;
has_sfx_card = (sfx_found_devices > 0 );
return sfx_found_devices > 0 ;
}
static my_bool sfx_dev_has_atomic_write(struct sfx_dev *dev,
int page_size)
{
int result= -1 , max_atomic_size= SFX_MAX_ATOMIC_SIZE;
if (dev->atomic_write == SFX_UNKNOWN_ATOMIC_WRITE_YET)
{
int fd= open(dev->dev_name, 0 );
if (fd < 0 )
fprintf(stderr, "Unable to determine if atomic writes are supported:"
" open(\" %s\"): %m\n" , dev->dev_name);
else
{
result= ioctl(fd, SFX_GET_ATOMIC_SIZE, &max_atomic_size);
close(fd);
}
dev->atomic_write= result == 0 && page_size <= max_atomic_size;
}
return dev->atomic_write;
}
/**
Check if a file is on a ScaleFlux device and that it supports atomic_write
@ param [ in ] file OS file handle
@ param [ in ] page_size page size
@ return TRUE Atomic write supported
@ notes
This is called only at first open of a file . In this case it doesn ' t
matter so much that we loop over all cards .
We update the atomic size on first access .
*/
static my_bool sfx_has_atomic_write(File file, int page_size)
{
struct sfx_dev *dev;
struct stat stat_buff;
if (fstat(file, &stat_buff) == 0 )
for (dev= sfx_devices; dev->st_dev; dev++)
if (SAME_DEV(stat_buff.st_dev, dev->st_dev))
return sfx_dev_has_atomic_write(dev, page_size);
return 0 ;
}
static my_bool sfx_dev_could_disable_punch_hole(struct sfx_dev *dev, File file)
{
int result = 0 ;
if (dev->disable_punch_hole == SFX_UNKNOWN_PUNCH_HOLE_YET)
{
int fd= open(dev->dev_name, 0 );
if (fd < 0 )
{
fprintf(stderr, "Unable to determine if thin provisioning is used:"
" open(\" %s\"): %m\n" , dev->dev_name);
dev->disable_punch_hole= 0 ; /* Don't try again */
return FALSE ;
}
/*
Ratio left - shifts 8 ( multiplies 256 ) inside the ioctl ;
will also add 1 to guarantee a round - up integer .
*/
result= ioctl(fd, SFX_GET_SPACE_RATIO);
result+= 1 ;
dev->disable_punch_hole= (result >= (((double )SFX_DISABLE_PUNCH_HOLE_RATIO) * 256 ));
}
return dev->disable_punch_hole;
}
/**
Check if a file is on a ScaleFlux device and whether it is possible to
disable hole punch .
@ param [ in ] file OS file handle
@ return TRUE Could disable hole punch
@ notes
This is called only at first open of a file . In this case it ' s doesn ' t
matter so much that we loop over all cards
*/
static my_bool sfx_could_disable_punch_hole(File file)
{
struct sfx_dev *dev;
struct stat stat_buff;
if (fstat(file, &stat_buff) == 0 )
for (dev = sfx_devices; dev->st_dev; dev++)
if (SAME_DEV(stat_buff.st_dev, dev->st_dev))
return sfx_dev_could_disable_punch_hole(dev, file);
return 0 ;
}
/***********************************************************************
Generic atomic write code
************************************************************************/
/**
Initialize the atomic write subsystem .
Checks if we have any devices that supports atomic write
*/
void my_init_atomic_write(void )
{
has_shannon_atomic_write= test_if_shannon_card_exists();
has_fusion_io_atomic_write= test_if_fusion_io_card_exists();
has_sfx_atomic_write= test_if_sfx_card_exists();
my_may_have_atomic_write= has_shannon_atomic_write ||
has_fusion_io_atomic_write || has_sfx_atomic_write;
#ifdef TEST_SHANNON
printf("%s(): has_shannon_atomic_write=%d, my_may_have_atomic_write=%d\n" ,
__func__,
has_shannon_atomic_write,
my_may_have_atomic_write);
#endif
}
/**
Check if a file supports atomic write
@ return FALSE No atomic write support
TRUE File supports atomic write
*/
my_bool my_test_if_atomic_write(File handle, int page_size)
{
#ifdef TEST_SHANNON
printf("%s(): has_shannon_atomic_write=%d, my_may_have_atomic_write=%d\n" ,
__func__,
has_shannon_atomic_write,
my_may_have_atomic_write);
#endif
if (!my_may_have_atomic_write)
return 0 ;
if (has_shannon_atomic_write &&
shannon_has_atomic_write(handle, page_size))
return 1 ;
if (has_fusion_io_atomic_write &&
fusion_io_has_atomic_write(handle, page_size))
return 1 ;
if (has_sfx_atomic_write &&
sfx_has_atomic_write(handle, page_size))
return 1 ;
return 0 ;
}
/**
Check if a file resides on thinly provisioned storage .
@ return FALSE File cannot disable hole punch
TRUE File could disable hole punch
*/
my_bool my_test_if_thinly_provisioned(File handle)
{
if (has_sfx_card && sfx_could_disable_punch_hole(handle))
return 1 ;
return 0 ;
}
#ifdef TEST_SHANNON
int main()
{
int fd, ret;
my_init_atomic_write();
fd= open("/u01/1.file" , O_RDWR);
ret= my_test_if_atomic_write(fd, 4096 );
if (ret)
printf("support atomic_write\n" );
else
printf("do not support atomic_write\n" );
close(fd);
return 0 ;
}
#endif
#else /* __linux__ */
/* Dummy functions to provide the interfaces for other systems */
void my_init_atomic_write(void )
{
}
#endif /* __linux__ */
Messung V0.5 in Prozent C=95 H=87 G=90
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-10-08)
¤
*© Formatika GbR, Deutschland