Fixed a bug with setting the statvfs value

This commit is contained in:
Takeshi Nakatani 2023-09-04 13:24:04 +00:00 committed by Andrew Gaul
parent 3f64c72c24
commit a74034a012
2 changed files with 118 additions and 59 deletions

View File

@ -101,7 +101,8 @@ static bool use_wtf8 = false;
static off_t fake_diskfree_size = -1; // default is not set(-1)
static int max_thread_count = 5; // default is 5
static bool update_parent_dir_stat= false; // default not updating parent directory stats
static fsblkcnt_t bucket_size; // advertised size of the bucket
static fsblkcnt_t bucket_block_count; // advertised block count of the bucket
static unsigned long s3fs_block_size = 16 * 1024 * 1024; // s3fs block size is 16MB
//-------------------------------------------------------------------
// Global functions : prototype
@ -2968,20 +2969,24 @@ static int s3fs_write(const char* _path, const char* buf, size_t size, off_t off
static int s3fs_statfs(const char* _path, struct statvfs* stbuf)
{
// WTF8_ENCODE(path)
stbuf->f_bsize = 16 * 1024 * 1024;
stbuf->f_bsize = s3fs_block_size;
stbuf->f_namemax = NAME_MAX;
#if defined(__MSYS__)
// WinFsp resolves the free space from f_bfree * f_frsize, and the total space from f_blocks * f_frsize (in bytes).
stbuf->f_blocks = bucket_block_count;
stbuf->f_frsize = stbuf->f_bsize;
stbuf->f_blocks = bucket_size;
stbuf->f_bfree = stbuf->f_blocks;
stbuf->f_bfree = stbuf->f_blocks;
#elif defined(__APPLE__)
stbuf->f_blocks = bucket_size;
stbuf->f_blocks = bucket_block_count;
stbuf->f_frsize = stbuf->f_bsize;
stbuf->f_bfree = stbuf->f_blocks;
stbuf->f_files = UINT32_MAX;
stbuf->f_ffree = UINT32_MAX;
stbuf->f_favail = UINT32_MAX;
#else
stbuf->f_blocks = bucket_size / stbuf->f_bsize;
stbuf->f_frsize = stbuf->f_bsize;
stbuf->f_blocks = bucket_block_count;
stbuf->f_bfree = stbuf->f_blocks;
#endif
stbuf->f_bavail = stbuf->f_blocks;
@ -4576,65 +4581,96 @@ static int set_bucket(const char* arg)
return 0;
}
// parse --bucket_size option
// max_size: a string like 20000000, 30GiB, 20TB etc
// return: the integer of type fsblkcnt_t corresponding to max_size,
// or 0 when errors
//
// Utility function for parse "--bucket_size" option
//
// max_size: A string like 20000000, 30GiB, 20TB etc
// return: An integer of type fsblkcnt_t corresponding to the number
// of blocks with max_size calculated with the s3fs block size,
// or 0 on error
//
static fsblkcnt_t parse_bucket_size(char* max_size)
{
const unsigned long long ten00 = 1000L;
const unsigned long long ten24 = 1024L;
unsigned long long scale = 1;
unsigned long long n_bytes = 0;
char *ptr;
fsblkcnt_t scale=1;
fsblkcnt_t n_bytes=0;
fsblkcnt_t ten00=static_cast<fsblkcnt_t>(1000L);
fsblkcnt_t ten24=static_cast<fsblkcnt_t>(1024L);
if ((ptr=strstr(max_size,"GB"))!=nullptr) {
scale=ten00*ten00*ten00;
if(strlen(ptr)>2)return 0; // no trailing garbage
*ptr='\0';
if(nullptr != (ptr = strstr(max_size, "GB"))){
scale = ten00 * ten00 * ten00;
if(2 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"GiB"))!=nullptr) {
scale=ten24*ten24*ten24;
if(strlen(ptr)>3)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "GiB"))){
scale = ten24 * ten24 * ten24;
if(3 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"TB"))!=nullptr) {
scale=ten00*ten00*ten00*ten00;
if(strlen(ptr)>2)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "TB"))){
scale = ten00 * ten00 * ten00 * ten00;
if(2 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"TiB"))!=nullptr) {
scale=ten24*ten24*ten24*ten24;
if(strlen(ptr)>3)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "TiB"))){
scale = ten24 * ten24 * ten24 * ten24;
if(3 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"PB"))!=nullptr) {
scale=ten00*ten00*ten00*ten00*ten00;
if(strlen(ptr)>2)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "PB"))){
scale = ten00 * ten00 * ten00 * ten00 * ten00;
if(2 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"PiB"))!=nullptr) {
scale=ten24*ten24*ten24*ten24*ten24;
if(strlen(ptr)>3)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "PiB"))){
scale = ten24 * ten24 * ten24 * ten24 * ten24;
if(3 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"EB"))!=nullptr) {
scale=ten00*ten00*ten00*ten00*ten00*ten00;
if(strlen(ptr)>2)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "EB"))){
scale = ten00 * ten00 * ten00 * ten00 * ten00 * ten00;
if(2 < strlen(ptr)){
return 0; // no trailing garbage
}
else if ((ptr=strstr(max_size,"EiB"))!=nullptr) {
scale=ten24*ten24*ten24*ten24*ten24*ten24;
if(strlen(ptr)>3)return 0; // no trailing garbage
*ptr='\0';
*ptr = '\0';
}else if(nullptr != (ptr = strstr(max_size, "EiB"))){
scale = ten24 * ten24 * ten24 * ten24 * ten24 * ten24;
if(3 < strlen(ptr)){
return 0; // no trailing garbage
}
*ptr = '\0';
}
// extra check
for(ptr=max_size;*ptr!='\0';++ptr) if( ! isdigit(*ptr) ) return 0;
n_bytes=static_cast<fsblkcnt_t>(strtoul(max_size,nullptr,10));
n_bytes*=scale;
if(n_bytes<=0)return 0;
return n_bytes;
for(ptr = max_size; *ptr != '\0'; ++ptr){
if(!isdigit(*ptr)){
return 0; // wrong number
}
n_bytes = static_cast<unsigned long long>(strtoull(max_size, nullptr, 10));
if((INT64_MAX / scale) < n_bytes){
return 0; // overflow
}
n_bytes *= scale;
}
// [NOTE]
// To round a number by s3fs block size.
// And need to check the result value because fsblkcnt_t is 32bit in macos etc.
//
n_bytes /= s3fs_block_size;
if(sizeof(fsblkcnt_t) <= 4){
if(INT32_MAX < n_bytes){
return 0; // overflow
}
}
return static_cast<fsblkcnt_t>(n_bytes); // cast to fsblkcnt_t
}
static bool is_cmd_exists(const std::string& command)
@ -4766,8 +4802,8 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar
return 1; // continue for fuse option
}
else if(is_prefix(arg, "bucket_size=")){
bucket_size = parse_bucket_size(const_cast<char *>(strchr(arg, '=')) + sizeof(char));
if(0 == bucket_size){
bucket_block_count = parse_bucket_size(const_cast<char *>(strchr(arg, '=')) + sizeof(char));
if(0 == bucket_block_count){
S3FS_PRN_EXIT("invalid bucket_size option.");
return -1;
}
@ -5440,16 +5476,15 @@ int main(int argc, char* argv[])
{nullptr, 0, nullptr, 0}
};
// init bucket_size
// init bucket_block_size
#if defined(__MSYS__)
bucket_size=static_cast<fsblkcnt_t>(INT32_MAX);
bucket_block_count = static_cast<fsblkcnt_t>(INT32_MAX);
#elif defined(__APPLE__)
bucket_size=static_cast<fsblkcnt_t>(INT32_MAX);
bucket_block_count = static_cast<fsblkcnt_t>(INT32_MAX);
#else
bucket_size=~0U;
bucket_block_count = ~0U;
#endif
// init xml2
xmlInitParser();
LIBXML_TEST_VERSION

View File

@ -2555,6 +2555,29 @@ function test_file_names_longer_than_posix() {
rm -f "${a256}"
}
function test_statvfs() {
describe "Testing the free/available size on mount point(statvfs)..."
# [NOTE]
# The df command result format is different between Linux and macos,
# but the order of Total/Used/Available size is the same.
#
local MOUNTPOINT_DIR; MOUNTPOINT_DIR=$(cd ..; pwd)
local DF_RESULT; DF_RESULT=$(df "${MOUNTPOINT_DIR}" 2>/dev/null | tail -n +2)
local TOTAL_SIZE; TOTAL_SIZE=$(echo "${DF_RESULT}" | awk '{print $2}')
local USED_SIZE; USED_SIZE=$(echo "${DF_RESULT}" | awk '{print $3}')
local AVAIL_SIZE; AVAIL_SIZE=$(echo "${DF_RESULT}" | awk '{print $4}')
# [NOTE]
# In the disk information (statvfs) provided by s3fs, Total size and
# Available size are always the same and not 0, and used size is always 0.
#
if [ -z "${TOTAL_SIZE}" ] || [ -z "${AVAIL_SIZE}" ] || [ -z "${USED_SIZE}" ] || [ "${TOTAL_SIZE}" = "0" ] || [ "${AVAIL_SIZE}" = "0" ] || [ "${TOTAL_SIZE}" != "${AVAIL_SIZE}" ] || [ "${USED_SIZE}" != "0" ]; then
echo "The result of df <mount point> command is wrong: Total=${TOTAL_SIZE}, Used=${USED_SIZE}, Available=${AVAIL_SIZE}"
return 1
fi
}
function add_all_tests {
if s3fs_args | grep -q use_cache; then
add_tests test_cache_file_stat
@ -2658,6 +2681,7 @@ function add_all_tests {
# add_tests test_chmod_mountpoint
# add_tests test_chown_mountpoint
add_tests test_time_mountpoint
add_tests test_statvfs
}
init_suite