Skip to content

Commit 5ebbc2b

Browse files
authored
Merge pull request #173 from aliyun/release_1.91.5
release 1.91.5
2 parents eb95599 + 16edb35 commit 5ebbc2b

18 files changed

+896
-81
lines changed

ChangeLog

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
ChangeLog for OSSFS
22
------------------
3+
## v1.91.5 (25/12/2024)
4+
- Fixed some bugs that users get unexpected results on mounting with specific policies for the bucket/prefix set.
5+
- Fixed a bug that ossfs take a file as existing if HeadObj returns 403.
6+
- Change the default value of complement_stat to true.
7+
- Support free_space_ratio.
8+
9+
## v1.91.4 (24/09/2024)
10+
- Add a new option sigv4 to support OSS V4 signature.
11+
- Fixed a bug that concurrent writing may cause deadlock when disk space is insufficient.
12+
- Support authentication via dynamic lib.
13+
- Fixed a bug that AK and SK are stored in wrong environment variables.
14+
315
## v1.91.3 (04/06/2024)
416
- Fixed a bug that IO fails when running out of disk space.
517
- Fixed a bug that default_acl option does not working.

configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
dnl Process this file with autoconf to produce a configure script.
2121

2222
AC_PREREQ(2.59)
23-
AC_INIT(ossfs, 1.91.4)
23+
AC_INIT(ossfs, 1.91.5)
2424
AC_CONFIG_HEADER([config.h])
2525

2626
AC_CANONICAL_SYSTEM

doc/man/ossfs.1.in

+8-2
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@ sets MB to ensure disk free space. This option means the threshold of free space
187187
ossfs makes file for downloading, uploading and caching files.
188188
If the disk free space is smaller than this value, ossfs do not use disk space as possible in exchange for the performance.
189189
.TP
190+
\fB\-o\fR free_space_ratio (default="0")
191+
sets min free space ratio of the disk. The value of this option can be between 0 and 100. It will control
192+
the size of the cache according to this ratio to ensure that the idle ratio of the disk is greater than this value.
193+
For example, when the disk space is 50GB, the 10% value will
194+
ensure that the disk will reserve at least 50GB * 10% = 5GB of remaining space.
195+
.TP
190196
\fB\-o\fR multipart_threshold (default="25")
191197
threshold, in MB, to use multipart upload instead of
192198
single-part. Must be at least 5 MB.
@@ -291,9 +297,9 @@ https://curl.haxx.se/docs/ssl-ciphers.html
291297
The instance name of the current ossfs mountpoint.
292298
This name will be added to logging messages and user agent headers sent by ossfs.
293299
.TP
294-
\fB\-o\fR complement_stat (complement lack of file/directory mode)
300+
\fB\-o\fR complement_stat (complement lack of file/directory mode, enabled by default)
295301
ossfs complements lack of information about file/directory mode if a file or a directory object does not have x-oss-meta-mode header.
296-
As default, ossfs does not complements stat information for a object, then the object will not be able to be allowed to list/modify.
302+
If disabled, ossfs does not complements stat information for a object, then the object will not be able to be allowed to list/modify.
297303
.TP
298304
\fB\-o\fR notsup_compat_dir (disable support of alternative directory names)
299305
.RS

scripts/ossfs-coverage-centos7.sh

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ rm -rf ${OSSFS_SOURCE_DIR}/coverage_html && mkdir ${OSSFS_SOURCE_DIR}/coverage_h
3434

3535
DBGLEVEL=debug ALL_TESTS=1 OSSFS_CREDENTIALS_FILE=/root/.passwd-ossfs TEST_BUCKET_1=${BUCKET} S3PROXY_BINARY="" OSS_URL=${URL} ./small-integration-test.sh
3636

37+
${OSSFS_SOURCE_DIR}/src/test_page_list
38+
${OSSFS_SOURCE_DIR}/src/test_curl_util
39+
${OSSFS_SOURCE_DIR}/src/test_string_util
40+
3741
gcovr -r ${OSSFS_SOURCE_DIR}/src --html-details -o ${OSSFS_SOURCE_DIR}/coverage_html/coverage.html
3842

3943

src/fdcache.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@ bool FdManager::InitFakeUsedDiskSize(off_t fake_freesize)
272272
return true;
273273
}
274274

275+
off_t FdManager::GetTotalDiskSpaceByRatio(int ratio)
276+
{
277+
return FdManager::GetTotalDiskSpace(nullptr) * ratio / 100;
278+
}
279+
275280
off_t FdManager::GetTotalDiskSpace(const char* path)
276281
{
277282
struct statvfs vfsbuf;
@@ -328,6 +333,18 @@ bool FdManager::IsSafeDiskSpace(const char* path, off_t size)
328333
return size + FdManager::GetEnsureFreeDiskSpace() <= fsize;
329334
}
330335

336+
bool FdManager::IsSafeDiskSpaceWithLog(const char* path, off_t size)
337+
{
338+
off_t fsize = FdManager::GetFreeDiskSpace(path);
339+
off_t needsize = size + FdManager::GetEnsureFreeDiskSpace();
340+
if(needsize <= fsize){
341+
return true;
342+
} else {
343+
S3FS_PRN_EXIT("There is no enough disk space for used as cache(or temporary) directory by ossfs. Requires %.3f MB, already has %.3f MB.", static_cast<double>(needsize) / 1024 / 1024, static_cast<double>(fsize) / 1024 / 1024);
344+
return false;
345+
}
346+
}
347+
331348
bool FdManager::HaveLseekHole()
332349
{
333350
if(FdManager::checked_lseek){

src/fdcache.h

+2
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@ class FdManager
8484
static off_t SetEnsureFreeDiskSpace(off_t size);
8585
static bool InitFakeUsedDiskSize(off_t fake_freesize);
8686
static bool IsSafeDiskSpace(const char* path, off_t size);
87+
static bool IsSafeDiskSpaceWithLog(const char* path, off_t size);
8788
static void FreeReservedDiskSpace(off_t size);
8889
static bool ReserveDiskSpace(off_t size);
8990
static bool HaveLseekHole();
9091
static bool SetTmpDir(const char* dir);
9192
static bool CheckTmpDirExist();
9293
static FILE* MakeTempFile();
94+
static off_t GetTotalDiskSpaceByRatio(int ratio);
9395

9496
// Return FdEntity associated with path, returning NULL on error. This operation increments the reference count; callers must decrement via Close after use.
9597
FdEntity* GetFdEntity(const char* path, int& existfd, bool newfd = true, bool lock_already_held = false);

src/s3fs.cpp

+66-70
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@ static int rename_object(const char* from, const char* to, bool update_ctime);
131131
static int rename_object_nocopy(const char* from, const char* to, bool update_ctime);
132132
static int clone_directory_object(const char* from, const char* to, bool update_ctime);
133133
static int rename_directory(const char* from, const char* to);
134-
static int remote_mountpath_exists(const char* path);
135134
static void free_xattrs(xattrs_t& xattrs);
136135
static bool parse_xattr_keyval(const std::string& xattrpair, std::string& key, PXATTRVAL& pval);
137136
static size_t parse_xattrs(const std::string& strxattrs, xattrs_t& xattrs);
@@ -396,26 +395,7 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t
396395
s3fscurl.DestroyCurlHandle();
397396

398397
// if not found target path object, do over checking
399-
if(-EPERM == result){
400-
// [NOTE]
401-
// In case of a permission error, it exists in directory
402-
// file list but inaccessible. So there is a problem that
403-
// it will send a HEAD request every time, because it is
404-
// not registered in the Stats cache.
405-
// Therefore, even if the file has a permission error, it
406-
// should be registered in the Stats cache. However, if
407-
// the response without modifying is registered in the
408-
// cache, the file permission will be 0644(umask dependent)
409-
// because the meta header does not exist.
410-
// Thus, set the mode of 0000 here in the meta header so
411-
// that ossfs can print a permission error when the file
412-
// is actually accessed.
413-
// It is better not to set meta header other than mode,
414-
// so do not do it.
415-
//
416-
(*pheader)["x-oss-meta-mode"] = str(0);
417-
418-
}else if(0 != result){
398+
if(0 != result){
419399
if(overcheck){
420400
// when support_compat_dir is disabled, strpath maybe have "_$folder$".
421401
if('/' != *strpath.rbegin() && std::string::npos == strpath.find("_$folder$", 0)){
@@ -467,7 +447,7 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t
467447
// If the file is listed but not allowed access, put it in
468448
// the positive cache instead of the negative cache.
469449
//
470-
if(0 != result && -EPERM != result){
450+
if(0 != result){
471451
// finally, "path" object did not find. Add no object cache.
472452
strpath = path; // reset original
473453
StatCache::getStatCacheData()->AddNoObjectCache(strpath);
@@ -3031,24 +3011,6 @@ static int list_bucket(const char* path, S3ObjList& head, const char* delimiter,
30313011
return 0;
30323012
}
30333013

3034-
static int remote_mountpath_exists(const char* path)
3035-
{
3036-
struct stat stbuf;
3037-
int result;
3038-
3039-
S3FS_PRN_INFO1("[path=%s]", path);
3040-
3041-
// getattr will prefix the path with the remote mountpoint
3042-
if(0 != (result = get_object_attribute("/", &stbuf, NULL))){
3043-
return result;
3044-
}
3045-
if(!S_ISDIR(stbuf.st_mode)){
3046-
return -ENOTDIR;
3047-
}
3048-
return 0;
3049-
}
3050-
3051-
30523014
static void free_xattrs(xattrs_t& xattrs)
30533015
{
30543016
for(xattrs_t::iterator iter = xattrs.begin(); iter != xattrs.end(); ++iter){
@@ -3777,7 +3739,7 @@ static int s3fs_check_service()
37773739

37783740
S3fsCurl s3fscurl;
37793741
int res;
3780-
if(0 > (res = s3fscurl.CheckBucket("/"))){
3742+
if(0 > (res = s3fscurl.CheckBucket(get_realpath("/").c_str()))){
37813743
// get response code
37823744
long responseCode = s3fscurl.GetLastResponseCode();
37833745

@@ -3828,7 +3790,9 @@ static int s3fs_check_service()
38283790
} else {
38293791
s3host = "http://" + expecthost;
38303792
}
3831-
//extract region from host for sigv4
3793+
// extract region from host for sigv4
3794+
// The region of the government cloud/financial cloud may not be derived from the domain name
3795+
// https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints?spm=a2c4g.11186623.0.0.13ad12c1N7PoaV
38323796
if(!strncasecmp(expecthost.c_str(), "oss-", 4)){
38333797
std::size_t found;
38343798
if ((found = expecthost.find_first_of(".")) != std::string::npos) {
@@ -3838,18 +3802,11 @@ static int s3fs_check_service()
38383802
}
38393803
// retry to check with new host
38403804
s3fscurl.DestroyCurlHandle();
3841-
res = s3fscurl.CheckBucket("/");
3805+
res = s3fscurl.CheckBucket(get_realpath("/").c_str());
38423806
responseCode = s3fscurl.GetLastResponseCode();
38433807
}
38443808
}
38453809

3846-
// retry to check with mount prefix
3847-
if(300 <= responseCode && responseCode < 500 && !mount_prefix.empty()){
3848-
s3fscurl.DestroyCurlHandle();
3849-
res = s3fscurl.CheckBucket(get_realpath("/").c_str());
3850-
responseCode = s3fscurl.GetLastResponseCode();
3851-
}
3852-
38533810
// try signature v2
38543811
/*
38553812
if(0 > res && (responseCode == 400 || responseCode == 403) && S3fsCurl::GetSignatureType() == V1_OR_V4){
@@ -3864,35 +3821,39 @@ static int s3fs_check_service()
38643821
}
38653822
*/
38663823
// check errors(after retrying)
3824+
// [NOTE]
3825+
// When mounting a bucket, an error code is returned and the mount fails.
3826+
// However, when mounting a prefix, success should be returned if the prefix does not exist.
3827+
//
38673828
if(0 > res && responseCode != 200 && responseCode != 301){
38683829
// parse error message if existed
38693830
std::string errMessage;
38703831
const std::string* body = s3fscurl.GetBodyData();
38713832
check_error_message(body->c_str(), body->size(), errMessage);
3872-
3833+
bool is_failure = true;
38733834
if(responseCode == 400){
38743835
S3FS_PRN_CRIT("Failed to check bucket and directory for mount point : Bad Request(host=%s, message=%s)", s3host.c_str(), errMessage.c_str());
38753836
}else if(responseCode == 403){
38763837
S3FS_PRN_CRIT("Failed to check bucket and directory for mount point : Invalid Credentials(host=%s, message=%s)", s3host.c_str(), errMessage.c_str());
3877-
}else if(responseCode == 404){
3878-
S3FS_PRN_CRIT("Failed to check bucket and directory for mount point : Bucket or directory not found(host=%s, message=%s)", s3host.c_str(), errMessage.c_str());
3838+
}else if (responseCode == 404) {
3839+
std::string value;
3840+
if(simple_parse_xml(body->c_str(), body->size(), "Code", value)) {
3841+
if(value == "NoSuchBucket") {
3842+
S3FS_PRN_CRIT("Failed to check bucket : Bucket not found(host=%s, message=%s)", s3host.c_str(), errMessage.c_str());
3843+
} else {
3844+
is_failure = false;
3845+
}
3846+
}
38793847
}else{
38803848
S3FS_PRN_CRIT("Failed to check bucket and directory for mount point : Unable to connect(host=%s, message=%s)", s3host.c_str(), errMessage.c_str());
38813849
}
3882-
return EXIT_FAILURE;
3883-
}
3884-
}
3885-
s3fscurl.DestroyCurlHandle();
3886-
3887-
// make sure remote mountpath exists and is a directory
3888-
if(!mount_prefix.empty()){
3889-
if(remote_mountpath_exists(mount_prefix.c_str()) != 0){
3890-
S3FS_PRN_CRIT("remote mountpath %s not found.", mount_prefix.c_str());
3891-
return EXIT_FAILURE;
3850+
if (is_failure) {
3851+
return EXIT_FAILURE;
3852+
}
38923853
}
38933854
}
38943855
S3FS_MALLOCTRIM(0);
3895-
3856+
38963857
return EXIT_SUCCESS;
38973858
}
38983859

@@ -4407,8 +4368,34 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar
44074368
max_dirty_data = size;
44084369
return 0;
44094370
}
4371+
if(is_prefix(arg, "free_space_ratio=")){
4372+
int ratio = static_cast<int>(cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10));
4373+
if(FdManager::GetEnsureFreeDiskSpace()!=0){
4374+
S3FS_PRN_EXIT("option free_space_ratio conflicts with ensure_diskfree, please set only one of them.");
4375+
return -1;
4376+
}
4377+
if(ratio < 0 || ratio > 100){
4378+
S3FS_PRN_EXIT("option free_space_ratio must between 0 to 100, which is: %d", ratio);
4379+
return -1;
4380+
}
4381+
off_t dfsize = FdManager::GetTotalDiskSpaceByRatio(ratio);
4382+
S3FS_PRN_INFO("Free space ratio set to %d %%, ensure the available disk space is greater than %.3f MB", ratio, static_cast<double>(dfsize) / 1024 / 1024);
4383+
if(dfsize < S3fsCurl::GetMultipartSize()){
4384+
S3FS_PRN_WARN("specified size to ensure disk free space is smaller than multipart size, so set multipart size to it.");
4385+
dfsize = S3fsCurl::GetMultipartSize();
4386+
}
4387+
FdManager::SetEnsureFreeDiskSpace(dfsize);
4388+
return 0;
4389+
}
44104390
if(is_prefix(arg, "ensure_diskfree=")){
44114391
off_t dfsize = cvt_strtoofft(strchr(arg, '=') + sizeof(char), /*base=*/ 10) * 1024 * 1024;
4392+
4393+
if(FdManager::GetEnsureFreeDiskSpace()!=0){
4394+
S3FS_PRN_EXIT("option free_space_ratio conflicts with ensure_diskfree, please set only one of them.");
4395+
return -1;
4396+
}
4397+
S3FS_PRN_INFO("Set and ensure the available disk space is greater than %.3f MB.", static_cast<double>(dfsize) / 1024 / 1024);
4398+
44124399
if(dfsize < S3fsCurl::GetMultipartSize()){
44134400
S3FS_PRN_WARN("specified size to ensure disk free space is smaller than multipart size, so set multipart size to it.");
44144401
dfsize = S3fsCurl::GetMultipartSize();
@@ -5078,12 +5065,16 @@ int main(int argc, char* argv[])
50785065

50795066
// check free disk space
50805067
if(!FdManager::IsSafeDiskSpace(NULL, S3fsCurl::GetMultipartSize() * S3fsCurl::GetMaxParallelCount())){
5081-
S3FS_PRN_EXIT("There is no enough disk space for used as cache(or temporary) directory by s3fs.");
5082-
S3fsCurl::DestroyS3fsCurl();
5083-
s3fs_destroy_global_ssl();
5084-
destroy_parser_xml_lock();
5085-
delete ps3fscred;
5086-
exit(EXIT_FAILURE);
5068+
// clean cache dir and retry
5069+
S3FS_PRN_WARN("No enough disk space for ossfs, try to clean cache dir");
5070+
FdManager::get()->CleanupCacheDir();
5071+
if(!FdManager::IsSafeDiskSpaceWithLog(nullptr, S3fsCurl::GetMultipartSize() * S3fsCurl::GetMaxParallelCount())){
5072+
S3fsCurl::DestroyS3fsCurl();
5073+
s3fs_destroy_global_ssl();
5074+
destroy_parser_xml_lock();
5075+
delete ps3fscred;
5076+
exit(EXIT_FAILURE);
5077+
}
50875078
}
50885079

50895080
// check readdir_optimize
@@ -5101,6 +5092,11 @@ int main(int argc, char* argv[])
51015092
S3FS_PRN_INFO("Readdir optimize, flag(%d, %lld)", is_refresh_fakemeta, static_cast<long long int>(readdir_check_size));
51025093
}
51035094

5095+
// try to check s3fs service
5096+
if (EXIT_SUCCESS != s3fs_check_service()) {
5097+
exit(EXIT_FAILURE);
5098+
}
5099+
51045100
s3fs_oper.getattr = s3fs_getattr;
51055101
s3fs_oper.readlink = s3fs_readlink;
51065102
s3fs_oper.mknod = s3fs_mknod;

src/s3fs_global.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
bool foreground = false;
2828
bool nomultipart = false;
2929
bool pathrequeststyle = false;
30-
bool complement_stat = false;
30+
bool complement_stat = true;
3131
bool noxmlns = true;
3232
bool direct_read = false;
3333

src/s3fs_help.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,15 @@ static const char help_string[] =
219219
" space is smaller than this value, ossfs do not use disk space\n"
220220
" as possible in exchange for the performance.\n"
221221
"\n"
222+
" free_space_ratio (default=\"0\")\n"
223+
" - sets min free space ratio of the disk.\n"
224+
" The value of this option can be between 0 and 100. It will control\n"
225+
" the size of the cache according to this ratio to ensure that the\n"
226+
" idle ratio of the disk is greater than this value.\n"
227+
" For example, when the disk space is 50GB, the default value will\n"
228+
" ensure that the disk will reserve at least 50GB * 10%% = 5GB of\n"
229+
" remaining space.\n"
230+
"\n"
222231
" multipart_threshold (default=\"25\")\n"
223232
" - threshold, in MB, to use multipart upload instead of\n"
224233
" single-part. Must be at least 5 MB.\n"
@@ -357,10 +366,10 @@ static const char help_string[] =
357366
" instance_name - The instance name of the current ossfs mountpoint.\n"
358367
" This name will be added to logging messages and user agent headers sent by ossfs.\n"
359368
"\n"
360-
" complement_stat (complement lack of file/directory mode)\n"
369+
" complement_stat (complement lack of file/directory mode, enabled by default)\n"
361370
" ossfs complements lack of information about file/directory mode\n"
362371
" if a file or a directory object does not have x-oss-meta-mode\n"
363-
" header. As default, ossfs does not complements stat information\n"
372+
" header. If disabled, ossfs does not complements stat information\n"
364373
" for a object, then the object will not be able to be allowed to\n"
365374
" list/modify.\n"
366375
"\n"

0 commit comments

Comments
 (0)