282 lines
9.3 KiB
C
282 lines
9.3 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <paths.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <err.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
#ifdef __FreeBSD__
|
|
#include <sys/resource.h>
|
|
#include <devstat.h>
|
|
#include <sys/devicestat.h>
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/ucred.h>
|
|
#include <sys/mount.h>
|
|
|
|
#else // linux
|
|
#include <mntent.h>
|
|
#include <sys/vfs.h>
|
|
#endif // __FreeBSD__
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <httpd.h>
|
|
#include <http_config.h>
|
|
#include <http_protocol.h>
|
|
#include <http_log.h>
|
|
|
|
#include "dav_repos.h"
|
|
|
|
#define DISABLE_FLAG ".disable"
|
|
|
|
|
|
// CHG 2019-09-24 huibong Bigbox FHS 장비 사용에 따른 mount 별 운영여유공간 계산방식 개선 (#32807)
|
|
// - 285 TB 급 bigbox FHS 장비 사용으로 인해
|
|
// - 기존과 같이 각 mount 별 1% 여유공간을 남길경우... 2.8 TB 가 남겨져 저장공간 낭비가 심해
|
|
// - 다음과 같이 개선 처리함.
|
|
// -- 각 mount total 공간 ( used + avail ) > 3TB 이면... avail 공간은 30 GByte 초과할 경우 write 가능
|
|
// -- 각 mount total 공간 ( used + avail ) <= 3TB 이면... 기존과 같이 사용률이 99% 미만인 경우 write 가능
|
|
// - 기존 conf 상의 DavProviderStorageLimit 설정은 제거 처리
|
|
|
|
#define MOUNT_WRITE_CHECK_PERCENT_LIMIT 3298534883328 // 3 TB
|
|
#define MOUNT_WRITE_LIMIT_SIZE 32212254720 // 30 GB
|
|
#define MOUNT_WRITE_LIMIT_PERCENT 99 // 99%
|
|
|
|
typedef struct
|
|
{
|
|
char * f_mntonname;
|
|
apr_int64_t f_bavail; // 해당 mount 의 여유용량, 8Byte long 최대값은 9,223,372,036,854,775,807 이므로.. 9,223 PB 까지 저장 가능.
|
|
apr_int64_t total_size; // 해당 mount 의 total size, UFS 의 8% 예약공간 이슈로... used size + avail size 로 계산한다. (2019-09-24 #32807 로 추가)
|
|
int capacity; // 사용량 정보 (%), int 형변환 때문에 99.99 % -> 99 로 표시됨.
|
|
|
|
} diskinfo;
|
|
|
|
int get_writable_path(apr_pool_t *p, const char *homepath, char *subpath)
|
|
{
|
|
// 2015.06.15 dadamin
|
|
// 램덤 처리 시 동일한 타입을 사용않을 시
|
|
// 특정 볼륨(node0)로 몰리는 현상이 발견되어
|
|
// 램덤 함수에서 사용하는 타입으로 수정함
|
|
unsigned int current = 0;
|
|
diskinfo *info;
|
|
apr_array_header_t *storgelist = NULL;
|
|
long used, availblks;
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
int mntsize = 0, i = 0;
|
|
struct statfs *mntbuf = NULL;
|
|
|
|
apr_global_mutex_lock(local_disk_lock);
|
|
mntsize = getmntinfo(&mntbuf, MNT_WAIT);
|
|
|
|
if( mntsize == 0 )
|
|
{
|
|
apr_global_mutex_unlock(local_disk_lock);
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path::getmntinfo error [%d]", errno);
|
|
return -1; // error
|
|
}
|
|
|
|
storgelist = apr_array_make(p, 0, sizeof(diskinfo));
|
|
if(storgelist == NULL)
|
|
{
|
|
apr_global_mutex_unlock(local_disk_lock);
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path::apr_array_make error [%d]", errno);
|
|
return -1; // error
|
|
}
|
|
for (i = 0; i < mntsize; i++)
|
|
{
|
|
// storage root
|
|
if (strncmp(homepath, mntbuf[i].f_mntonname, strlen(homepath)))
|
|
continue;
|
|
|
|
info = (diskinfo *) apr_array_push(storgelist);
|
|
|
|
// multi volume
|
|
info->f_mntonname = mntbuf[i].f_mntonname;
|
|
info->f_bavail = mntbuf[i].f_bavail * mntbuf[i].f_bsize;
|
|
|
|
used = mntbuf[i].f_blocks - mntbuf[i].f_bfree;
|
|
availblks = mntbuf[i].f_bavail + used;
|
|
|
|
// 각 mount total size 정보는 UFS 예약 8% 를 제거하기 위해 실제 사용량 + free 용량 정보를 더해서 계산한다.
|
|
info->total_size = availblks * mntbuf[i].f_bsize;
|
|
info->capacity = (int)(availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
|
|
}
|
|
|
|
apr_global_mutex_unlock(local_disk_lock);
|
|
|
|
#else // linux
|
|
|
|
FILE *f;
|
|
struct mntent mnt;
|
|
struct mntent *mnte;
|
|
char buf[512];
|
|
if ((f = setmntent ("/etc/mtab", "r")) != NULL)
|
|
{
|
|
storgelist = apr_array_make(p, 0, sizeof(diskinfo));
|
|
while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL)
|
|
{
|
|
// storage root
|
|
if (strncmp(homepath, mnt.mnt_dir, strlen(homepath)))
|
|
continue;
|
|
|
|
struct statfs statfsbuf;
|
|
if(statfs(mnt.mnt_dir, &statfsbuf) == 0)
|
|
{
|
|
info = (diskinfo *) apr_array_push(storgelist);
|
|
// multi volume
|
|
info->f_mntonname = mnt.mnt_dir;
|
|
info->f_bavail = statfsbuf.f_bavail * statfsbuf.f_bsize;
|
|
|
|
used = statfsbuf.f_blocks - statfsbuf.f_bfree;
|
|
availblks = statfsbuf.f_bavail + used;
|
|
|
|
// 각 mount total size 정보는 특정 시스템의 예약 8% 를 제거하기 위해 실제 사용량 + free 용량 정보를 더해서 계산한다.
|
|
info->total_size = availblks * statfsbuf.f_bsize;
|
|
info->capacity = (int)(availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
|
|
}
|
|
else
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path:: multi volume statfs error [%d]", errno);
|
|
}
|
|
endmntent(f);
|
|
}
|
|
else
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path::setmntent error [%d]", errno);
|
|
return -1; // error
|
|
}
|
|
|
|
#endif //
|
|
|
|
if(storgelist->nelts == 0)
|
|
{
|
|
// single volume
|
|
struct statfs statfsbuf;
|
|
if(statfs(homepath, &statfsbuf) == 0)
|
|
{
|
|
info = (diskinfo *) apr_array_push(storgelist);
|
|
info->f_mntonname = (char *)homepath;
|
|
info->f_bavail = statfsbuf.f_bavail * statfsbuf.f_bsize;
|
|
|
|
used = statfsbuf.f_blocks - statfsbuf.f_bfree;
|
|
availblks = statfsbuf.f_bavail + used;
|
|
|
|
// 각 mount total size 정보는 UFS 예약 8% 를 제거하기 위해 실제 사용량 + free 용량 정보를 더해서 계산한다.
|
|
info->total_size = availblks * statfsbuf.f_bsize;
|
|
info->capacity = (int)(availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
|
|
}
|
|
else
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path::statfs error [%d]", errno);
|
|
}
|
|
|
|
if(storgelist->nelts > 0)
|
|
{
|
|
char disable_flag[1024] = {0};
|
|
struct stat sb;
|
|
int not_exist = -1;
|
|
|
|
apr_generate_random_bytes((unsigned char *)¤t, sizeof(unsigned int));
|
|
|
|
current = current % storgelist->nelts;
|
|
|
|
info = &((diskinfo *) storgelist->elts)[current];
|
|
|
|
sprintf(disable_flag, "%s%s", info->f_mntonname, DISABLE_FLAG);
|
|
not_exist = stat(disable_flag, &sb);
|
|
|
|
// CHG 2019-09-24 huibong Bigbox FHS 장비 사용에 따른 mount 별 운영여유공간 계산방식 개선 (#32807)
|
|
// - 285 TB 급 bigbox FHS 장비 사용으로 인해
|
|
// - 기존과 같이 각 mount 별 1% 여유공간을 남길경우... 2.8 TB 가 남겨져 저장공간 낭비가 심해
|
|
// - 다음과 같이 개선 처리함.
|
|
// -- 각 mount total 공간 ( used + avail ) > 3TB 이면... avail 공간은 30 GByte 초과할 경우 write 가능
|
|
// -- 각 mount total 공간 ( used + avail ) <= 3TB 이면... 기존과 같이 사용률이 99% 미만인 경우 write 가능
|
|
// - 기존 conf 상의 DavProviderStorageLimit 설정은 제거 처리
|
|
if( info->total_size > MOUNT_WRITE_CHECK_PERCENT_LIMIT )
|
|
{
|
|
if( not_exist && info->f_bavail > MOUNT_WRITE_LIMIT_SIZE )
|
|
{
|
|
strcpy( subpath, info->f_mntonname );
|
|
|
|
// for debug
|
|
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path: random, total size greater 3TB, free size greater 30GB, return [%s]", subpath );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( not_exist && info->capacity < MOUNT_WRITE_LIMIT_PERCENT )
|
|
{
|
|
strcpy( subpath, info->f_mntonname );
|
|
|
|
// for debug
|
|
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path: random, total size less than or equal 3TB, used percent less than 99%%, return [%s]", subpath );
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 2014-02-28 dadamin
|
|
// 램덤 실패 시 해당 결과 순회 후 정상 디스크를 선택
|
|
int first = 0, diskcnt = storgelist->nelts;
|
|
first = current;
|
|
for ( current = first ; current < diskcnt; ++current)
|
|
{
|
|
char disable_flag[1024] = {0};
|
|
struct stat sb;
|
|
int not_exist = -1;
|
|
|
|
info = &((diskinfo *) storgelist->elts)[current];
|
|
|
|
sprintf(disable_flag, "%s%s", info->f_mntonname, DISABLE_FLAG);
|
|
not_exist = stat(disable_flag, &sb);
|
|
|
|
// CHG 2019-09-24 huibong Bigbox FHS 장비 사용에 따른 mount 별 운영여유공간 계산방식 개선 (#32807)
|
|
// - 285 TB 급 bigbox FHS 장비 사용으로 인해
|
|
// - 기존과 같이 각 mount 별 1% 여유공간을 남길경우... 2.8 TB 가 남겨져 저장공간 낭비가 심해
|
|
// - 다음과 같이 개선 처리함.
|
|
// -- 각 mount total 공간 ( used + avail ) > 3TB 이면... avail 공간은 30 GByte 초과할 경우 write 가능
|
|
// -- 각 mount total 공간 ( used + avail ) <= 3TB 이면... 기존과 같이 사용률이 99% 미만인 경우 write 가능
|
|
// - 기존 conf 상의 DavProviderStorageLimit 설정은 제거 처리
|
|
if( info->total_size > MOUNT_WRITE_CHECK_PERCENT_LIMIT )
|
|
{
|
|
if( not_exist && info->f_bavail > MOUNT_WRITE_LIMIT_SIZE )
|
|
{
|
|
strcpy( subpath, info->f_mntonname );
|
|
|
|
// for debug
|
|
//ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path: sequence, total size greater 3TB, free size greater 30GB, return [%s]", subpath );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( not_exist && info->capacity < MOUNT_WRITE_LIMIT_PERCENT )
|
|
{
|
|
strcpy( subpath, info->f_mntonname );
|
|
|
|
// for debug
|
|
//ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path: sequence, total size less than or equal 3TB, used percent less than 99%%, return [%s]", subpath );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if( first > 0 && (current+1) >= diskcnt )
|
|
{
|
|
current = -1;
|
|
diskcnt = first;
|
|
first = 0;
|
|
}
|
|
}
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "get_writable_path::Empty writable");
|
|
return -1; // error
|
|
}
|