mirror of
https://github.com/s3fs-fuse/s3fs-fuse.git
synced 2024-12-23 01:08:54 +00:00
Fixed issue 291, and Adds "disable_noobj_cache" option.
1) Man file has wrong permissions for passwd file(Issue 291) Fixes man page for wrong permissions of passwd file. 2) Fixes a bug and Strictly checks passwd file permission. * Fixes a bug about checking passwd file permission. A bug is that s3fs continues to run after s3fs finds invalid passwd file permission. * Checks passwd file strictly. Before this revision, s3fs allows executable permission for a passwd file and allows group writable permission for a passwd file(which is not "/etc/passwd-s3fs"). New s3fs checks permission strictly, that is /etc/passwd-s3fs is allowed owner readable/writable and group readable, and the passwd file(which is not "/etc/passwd-s3fs") is allowed only owner readable/writable. 3) Adds disable_noobj_cache option for no-existing object. s3fs v1.68 always has to check whether file(or sub directory) exists under object(path) when s3fs does some command, since s3fs has recognized a directory which does not exist and has files or sub directories under itself. It increases ListBucket request and makes performance bad. For performance if the disable_noobj_cache option is specified, s3fs memorizes in stat cache that the object(file or directory) does not exist. git-svn-id: http://s3fs.googlecode.com/svn/trunk@420 df820570-a93a-0410-bd06-b72b767a4274
This commit is contained in:
parent
5de37a6807
commit
6b78bfdf4b
@ -23,8 +23,8 @@ If you have more than one set of credentials, this syntax is also recognized:
|
|||||||
.PP
|
.PP
|
||||||
Password files can be stored in two locations:
|
Password files can be stored in two locations:
|
||||||
.RS 4
|
.RS 4
|
||||||
\fB/etc/passwd-s3fs\fP [0600]
|
\fB/etc/passwd-s3fs\fP [0640]
|
||||||
\fB$HOME/.passwd-s3fs\fP [0640]
|
\fB$HOME/.passwd-s3fs\fP [0600]
|
||||||
.RE
|
.RE
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
.SS "general options"
|
.SS "general options"
|
||||||
@ -80,6 +80,12 @@ maximum number of entries in the stat cache
|
|||||||
\fB\-o\fR stat_cache_expire (default is no expire)
|
\fB\-o\fR stat_cache_expire (default is no expire)
|
||||||
specify expire time(seconds) for entries in the stat cache
|
specify expire time(seconds) for entries in the stat cache
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-o\fR enable_noobj_cache (default is disable)
|
||||||
|
enable cache entries for the object which does not exist.
|
||||||
|
s3fs always has to check whether file(or sub directory) exists under object(path) when s3fs does some command, since s3fs has recognized a directory which does not exist and has files or sub directories under itself.
|
||||||
|
It increases ListBucket request and makes performance bad.
|
||||||
|
You can specify this option for performance, s3fs memorizes in stat cache that the object(file or directory) does not exist.
|
||||||
|
.TP
|
||||||
\fB\-o\fR url (default="http://s3.amazonaws.com")
|
\fB\-o\fR url (default="http://s3.amazonaws.com")
|
||||||
sets the url to use to access Amazon S3. If you want to use HTTPS, then you can set url=https://s3.amazonaws.com
|
sets the url to use to access Amazon S3. If you want to use HTTPS, then you can set url=https://s3.amazonaws.com
|
||||||
.TP
|
.TP
|
||||||
|
@ -51,9 +51,10 @@ StatCache::StatCache()
|
|||||||
}else{
|
}else{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
CacheSize = 1000;
|
CacheSize = 1000;
|
||||||
ExpireTime = 0;
|
ExpireTime = 0;
|
||||||
IsExpireTime = false;
|
IsExpireTime = false;
|
||||||
|
IsCacheNoObject = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatCache::~StatCache()
|
StatCache::~StatCache()
|
||||||
@ -101,6 +102,13 @@ time_t StatCache::UnsetExpireTime(void)
|
|||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StatCache::SetCacheNoObject(bool flag)
|
||||||
|
{
|
||||||
|
bool old = IsCacheNoObject;
|
||||||
|
IsCacheNoObject = flag;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
|
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
|
||||||
{
|
{
|
||||||
bool is_delete_cache = false;
|
bool is_delete_cache = false;
|
||||||
@ -120,6 +128,16 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
|
|||||||
|
|
||||||
if(iter != stat_cache.end()) {
|
if(iter != stat_cache.end()) {
|
||||||
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
||||||
|
if((*iter).second.noobjcache){
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
if(!IsCacheNoObject){
|
||||||
|
// need to delete this cache.
|
||||||
|
DelStat(strpath);
|
||||||
|
}else{
|
||||||
|
// noobjcache = true means no object.
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// hit without checking etag
|
// hit without checking etag
|
||||||
if(petag){
|
if(petag){
|
||||||
string stretag = (*iter).second.meta["ETag"];
|
string stretag = (*iter).second.meta["ETag"];
|
||||||
@ -165,6 +183,47 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StatCache::IsNoObjectCache(string& key, bool overcheck)
|
||||||
|
{
|
||||||
|
bool is_delete_cache = false;
|
||||||
|
string strpath = key;
|
||||||
|
|
||||||
|
if(!IsCacheNoObject){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
|
stat_cache_t::iterator iter = stat_cache.end();
|
||||||
|
if(overcheck && '/' != strpath[strpath.length() - 1]){
|
||||||
|
strpath += "/";
|
||||||
|
iter = stat_cache.find(strpath.c_str());
|
||||||
|
}
|
||||||
|
if(iter == stat_cache.end()){
|
||||||
|
strpath = key;
|
||||||
|
iter = stat_cache.find(strpath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iter != stat_cache.end()) {
|
||||||
|
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
||||||
|
if((*iter).second.noobjcache){
|
||||||
|
// noobjcache = true means no object.
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
// timeout
|
||||||
|
is_delete_cache = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
|
if(is_delete_cache){
|
||||||
|
DelStat(strpath);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
|
bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
|
||||||
{
|
{
|
||||||
if(CacheSize< 1){
|
if(CacheSize< 1){
|
||||||
@ -188,6 +247,7 @@ bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
|
|||||||
stat_cache[key].hit_count = 0;
|
stat_cache[key].hit_count = 0;
|
||||||
stat_cache[key].cache_date = time(NULL); // Set time.
|
stat_cache[key].cache_date = time(NULL); // Set time.
|
||||||
stat_cache[key].isforce = forcedir;
|
stat_cache[key].isforce = forcedir;
|
||||||
|
stat_cache[key].noobjcache = false;
|
||||||
|
|
||||||
//copy only some keys
|
//copy only some keys
|
||||||
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
|
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
|
||||||
@ -216,6 +276,36 @@ bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StatCache::AddNoObjectCache(string& key)
|
||||||
|
{
|
||||||
|
if(!IsCacheNoObject){
|
||||||
|
return true; // pretend successful
|
||||||
|
}
|
||||||
|
if(CacheSize < 1){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FGPRINT(" add_stat_cache_entry - noobjcache[path=%s]\n", key.c_str());
|
||||||
|
|
||||||
|
if(stat_cache.size() > CacheSize){
|
||||||
|
if(!TruncateCache()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
memset(&st, 0, sizeof(struct stat));
|
||||||
|
|
||||||
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
|
stat_cache[key].stbuf = st;
|
||||||
|
stat_cache[key].hit_count = 0;
|
||||||
|
stat_cache[key].cache_date = time(NULL); // Set time.
|
||||||
|
stat_cache[key].isforce = false;
|
||||||
|
stat_cache[key].noobjcache = true;
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool StatCache::TruncateCache(void)
|
bool StatCache::TruncateCache(void)
|
||||||
{
|
{
|
||||||
string path_to_delete;
|
string path_to_delete;
|
||||||
|
18
src/cache.h
18
src/cache.h
@ -12,8 +12,9 @@ struct stat_cache_entry {
|
|||||||
time_t cache_date;
|
time_t cache_date;
|
||||||
headers_t meta;
|
headers_t meta;
|
||||||
bool isforce;
|
bool isforce;
|
||||||
|
bool noobjcache; // Flag: cache is no object for no listing.
|
||||||
|
|
||||||
stat_cache_entry() : hit_count(0), cache_date(0), isforce(false) {
|
stat_cache_entry() : hit_count(0), cache_date(0), isforce(false), noobjcache(false) {
|
||||||
memset(&stbuf, 0, sizeof(struct stat));
|
memset(&stbuf, 0, sizeof(struct stat));
|
||||||
meta.clear();
|
meta.clear();
|
||||||
}
|
}
|
||||||
@ -33,6 +34,7 @@ class StatCache
|
|||||||
bool IsExpireTime;
|
bool IsExpireTime;
|
||||||
time_t ExpireTime;
|
time_t ExpireTime;
|
||||||
unsigned long CacheSize;
|
unsigned long CacheSize;
|
||||||
|
bool IsCacheNoObject;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
|
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
|
||||||
@ -54,6 +56,16 @@ class StatCache
|
|||||||
time_t GetExpireTime(void) const;
|
time_t GetExpireTime(void) const;
|
||||||
time_t SetExpireTime(time_t expire);
|
time_t SetExpireTime(time_t expire);
|
||||||
time_t UnsetExpireTime(void);
|
time_t UnsetExpireTime(void);
|
||||||
|
bool SetCacheNoObject(bool flag);
|
||||||
|
bool EnableCacheNoObject(void) {
|
||||||
|
return SetCacheNoObject(true);
|
||||||
|
}
|
||||||
|
bool DisableCacheNoObject(void) {
|
||||||
|
return SetCacheNoObject(false);
|
||||||
|
}
|
||||||
|
bool GetCacheNoObject(void) const {
|
||||||
|
return IsCacheNoObject;
|
||||||
|
}
|
||||||
|
|
||||||
// Get stat cache
|
// Get stat cache
|
||||||
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck = true, bool* pisforce = NULL) {
|
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck = true, bool* pisforce = NULL) {
|
||||||
@ -72,6 +84,10 @@ class StatCache
|
|||||||
return GetStat(key, NULL, NULL, overcheck, etag, NULL);
|
return GetStat(key, NULL, NULL, overcheck, etag, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cache For no object
|
||||||
|
bool IsNoObjectCache(std::string& key, bool overcheck = true);
|
||||||
|
bool AddNoObjectCache(std::string& key);
|
||||||
|
|
||||||
// Add stat cache
|
// Add stat cache
|
||||||
bool AddStat(std::string& key, headers_t& meta, bool forcedir = false);
|
bool AddStat(std::string& key, headers_t& meta, bool forcedir = false);
|
||||||
|
|
||||||
|
36
src/s3fs.cpp
36
src/s3fs.cpp
@ -334,6 +334,10 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
|
|||||||
if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
|
if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if(StatCache::getStatCacheData()->IsNoObjectCache(strpath)){
|
||||||
|
// there is the path in the cache for no object, it is no object.
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
// At first, check "object/".
|
// At first, check "object/".
|
||||||
strpath = path;
|
strpath = path;
|
||||||
@ -374,6 +378,9 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
|
|||||||
(*pisforce) = true;
|
(*pisforce) = true;
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
// Add no object cache.
|
||||||
|
strpath = path; // reset original
|
||||||
|
StatCache::getStatCacheData()->AddNoObjectCache(strpath);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1712,9 +1719,10 @@ static int s3fs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
result = create_file_object(path, mode, pcxt->uid, pcxt->gid);
|
result = create_file_object(path, mode, pcxt->uid, pcxt->gid);
|
||||||
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
if(result != 0)
|
if(result != 0){
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// object created, open it
|
// object created, open it
|
||||||
if((fi->fh = get_local_fd(path)) <= 0)
|
if((fi->fh = get_local_fd(path)) <= 0)
|
||||||
@ -1804,7 +1812,9 @@ static int s3fs_mkdir(const char *path, mode_t mode)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return create_directory_object(path, mode, time(NULL), pcxt->uid, pcxt->gid);
|
result = create_directory_object(path, mode, time(NULL), pcxt->uid, pcxt->gid);
|
||||||
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s3fs_unlink(const char *path) {
|
static int s3fs_unlink(const char *path) {
|
||||||
@ -3781,6 +3791,18 @@ static int check_passwd_file_perms (void) {
|
|||||||
program_name.c_str(), passwd_file.c_str());
|
program_name.c_str(), passwd_file.c_str());
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
// "/etc/passwd-s3fs" does not allow group write.
|
||||||
|
if((info.st_mode & S_IWGRP)){
|
||||||
|
fprintf (stderr, "%s: credentials file %s should not have group writable permissions\n",
|
||||||
|
program_name.c_str(), passwd_file.c_str());
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if((info.st_mode & S_IXUSR) || (info.st_mode & S_IXGRP)){
|
||||||
|
fprintf (stderr, "%s: credentials file %s should not have executable permissions\n",
|
||||||
|
program_name.c_str(), passwd_file.c_str());
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -3812,7 +3834,9 @@ static int read_passwd_file (void) {
|
|||||||
// if you got here, the password file
|
// if you got here, the password file
|
||||||
// exists and is readable by the
|
// exists and is readable by the
|
||||||
// current user, check for permissions
|
// current user, check for permissions
|
||||||
check_passwd_file_perms();
|
if(EXIT_SUCCESS != check_passwd_file_perms()){
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
aws_format = check_for_aws_format();
|
aws_format = check_for_aws_format();
|
||||||
if(1 == aws_format){
|
if(1 == aws_format){
|
||||||
@ -4151,6 +4175,10 @@ static int my_fuse_opt_proc(void *data, const char *arg, int key, struct fuse_ar
|
|||||||
StatCache::getStatCacheData()->SetExpireTime(expr_time);
|
StatCache::getStatCacheData()->SetExpireTime(expr_time);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if(strstr(arg, "enable_noobj_cache") != 0) {
|
||||||
|
StatCache::getStatCacheData()->EnableCacheNoObject();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(strstr(arg, "noxmlns") != 0) {
|
if(strstr(arg, "noxmlns") != 0) {
|
||||||
noxmlns = true;
|
noxmlns = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -594,6 +594,16 @@ void show_help (void)
|
|||||||
" stat_cache_expire (default is no expire)\n"
|
" stat_cache_expire (default is no expire)\n"
|
||||||
" - specify expire time(seconds) for entries in the stat cache.\n"
|
" - specify expire time(seconds) for entries in the stat cache.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" enable_noobj_cache (default is disable)\n"
|
||||||
|
" - enable cache entries for the object which does not exist.\n"
|
||||||
|
" s3fs always has to check whether file(or sub directory) exists \n"
|
||||||
|
" under object(path) when s3fs does some command, since s3fs has \n"
|
||||||
|
" recognized a directory which does not exist and has files or \n"
|
||||||
|
" sub directories under itself. It increases ListBucket request \n"
|
||||||
|
" and makes performance bad.\n"
|
||||||
|
" You can specify this option for performance, s3fs memorizes \n"
|
||||||
|
" in stat cache that the object(file or directory) does not exist.\n"
|
||||||
|
"\n"
|
||||||
" url (default=\"http://s3.amazonaws.com\")\n"
|
" url (default=\"http://s3.amazonaws.com\")\n"
|
||||||
" - sets the url to use to access amazon s3\n"
|
" - sets the url to use to access amazon s3\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user