#include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #include #include #include #include #include #else // linux #include #include #endif // __FreeBSD__ #include #include #include #include #include #include #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 }