diff --git a/src/Makefile.am b/src/Makefile.am index 237a82e..744b3ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,7 @@ s3fs_SOURCES = \ fdcache_entity.cpp \ fdcache_page.cpp \ fdcache_stat.cpp \ + fdcache_auto.cpp \ addhead.cpp \ sighandlers.cpp \ autolock.cpp \ diff --git a/src/fdcache.cpp b/src/fdcache.cpp index 928399b..0ca8ff0 100644 --- a/src/fdcache.cpp +++ b/src/fdcache.cpp @@ -378,6 +378,7 @@ FdManager::~FdManager() if(this == FdManager::get()){ for(fdent_map_t::iterator iter = fent.begin(); fent.end() != iter; ++iter){ FdEntity* ent = (*iter).second; + S3FS_PRN_WARN("To exit with the cache file opened: path=%s, refcnt=%d", ent->GetPath(), ent->GetRefCnt()); delete ent; } fent.clear(); @@ -403,7 +404,7 @@ FdManager::~FdManager() } } -FdEntity* FdManager::GetFdEntity(const char* path, int existfd) +FdEntity* FdManager::GetFdEntity(const char* path, int existfd, bool increase_ref) { S3FS_PRN_INFO3("[path=%s][fd=%d]", SAFESTRPTR(path), existfd); @@ -414,7 +415,9 @@ FdEntity* FdManager::GetFdEntity(const char* path, int existfd) fdent_map_t::iterator iter = fent.find(std::string(path)); if(fent.end() != iter && (-1 == existfd || (*iter).second->GetFd() == existfd)){ - iter->second->Dup(); + if(increase_ref){ + iter->second->Dup(); + } return (*iter).second; } @@ -423,7 +426,9 @@ FdEntity* FdManager::GetFdEntity(const char* path, int existfd) if((*iter).second && (*iter).second->GetFd() == existfd){ // found opened fd in map if(0 == strcmp((*iter).second->GetPath(), path)){ - iter->second->Dup(); + if(increase_ref){ + iter->second->Dup(); + } return (*iter).second; } // found fd, but it is used another file(file descriptor is recycled) diff --git a/src/fdcache.h b/src/fdcache.h index 3bd3b6e..d13dcd8 100644 --- a/src/fdcache.h +++ b/src/fdcache.h @@ -76,7 +76,7 @@ class FdManager static bool HaveLseekHole(void); // Return FdEntity associated with path, returning NULL on error. This operation increments the reference count; callers must decrement via Close after use. - FdEntity* GetFdEntity(const char* path, int existfd = -1); + FdEntity* GetFdEntity(const char* path, int existfd = -1, bool increase_ref = true); FdEntity* Open(const char* path, headers_t* pmeta = NULL, off_t size = -1, time_t time = -1, bool force_tmpfile = false, bool is_create = true, bool no_fd_lock_wait = false); FdEntity* ExistOpen(const char* path, int existfd = -1, bool ignore_existfd = false); void Rename(const std::string &from, const std::string &to); diff --git a/src/fdcache_auto.cpp b/src/fdcache_auto.cpp new file mode 100644 index 0000000..e337d3f --- /dev/null +++ b/src/fdcache_auto.cpp @@ -0,0 +1,144 @@ +/* + * s3fs - FUSE-based file system backed by Amazon S3 + * + * Copyright(C) 2007 Takeshi Nakatani + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include "common.h" +#include "s3fs.h" +#include "fdcache_auto.h" +#include "fdcache.h" + +//------------------------------------------------ +// AutoFdEntity methods +//------------------------------------------------ +AutoFdEntity::AutoFdEntity() : pFdEntity(NULL) +{ +} + +// [NOTE] +// The copy constructor should not be called, then this is private method. +// Even if it is called, the consistency of the number of +// references can be maintained, but this case is not assumed. +// +AutoFdEntity::AutoFdEntity(AutoFdEntity& other) : pFdEntity(NULL) +{ + S3FS_PRN_WARN("This method should not be called. Please check the caller."); + + if(other.pFdEntity){ + other.pFdEntity->Dup(); + pFdEntity = other.pFdEntity; + } +} + +AutoFdEntity::~AutoFdEntity() +{ + Close(); +} + +bool AutoFdEntity::Close() +{ + if(pFdEntity){ + if(!FdManager::get()->Close(pFdEntity)){ + S3FS_PRN_ERR("Failed to close fdentity."); + return false; + } + pFdEntity = NULL; + } + return true; +} + +// [NOTE] +// This method touches the internal fdentity with. +// This is used to keep the file open. +// +bool AutoFdEntity::Detach() +{ + if(!pFdEntity){ + S3FS_PRN_ERR("Does not have a associated FdEntity."); + return false; + } + pFdEntity = NULL; + return true; +} + +// [NOTE] +// This method calls the FdManager method without incrementing the +// reference count. +// This means that it will only be used to map to a file descriptor +// that was already open. +// +FdEntity* AutoFdEntity::GetFdEntity(const char* path, int existfd, bool increase_ref) +{ + Close(); + + if(NULL == (pFdEntity = FdManager::get()->GetFdEntity(path, existfd, increase_ref))){ + S3FS_PRN_ERR("Could not find fd(file=%s, existfd=%d)", path, existfd); + return NULL; + } + return pFdEntity; +} + +FdEntity* AutoFdEntity::Open(const char* path, headers_t* pmeta, off_t size, time_t time, bool force_tmpfile, bool is_create, bool no_fd_lock_wait) +{ + Close(); + + if(NULL == (pFdEntity = FdManager::get()->Open(path, pmeta, size, time, force_tmpfile, is_create, no_fd_lock_wait))){ + return NULL; + } + return pFdEntity; +} + +FdEntity* AutoFdEntity::ExistOpen(const char* path, int existfd, bool ignore_existfd) +{ + Close(); + + if(NULL == (pFdEntity = FdManager::get()->ExistOpen(path, existfd, ignore_existfd))){ + return NULL; + } + return pFdEntity; +} + +// [NOTE] +// This operator should not be called, then this is private method. +// Even if it is called, the consistency of the number of +// references can be maintained, but this case is not assumed. +// +bool AutoFdEntity::operator=(AutoFdEntity& other) +{ + S3FS_PRN_WARN("This method should not be called. Please check the caller."); + + Close(); + + if(other.pFdEntity){ + other.pFdEntity->Dup(); + pFdEntity = other.pFdEntity; + } + return true; +} + +/* +* Local variables: +* tab-width: 4 +* c-basic-offset: 4 +* End: +* vim600: expandtab sw=4 ts=4 fdm=marker +* vim<600: expandtab sw=4 ts=4 +*/ diff --git a/src/fdcache_auto.h b/src/fdcache_auto.h new file mode 100644 index 0000000..06eb9e9 --- /dev/null +++ b/src/fdcache_auto.h @@ -0,0 +1,63 @@ +/* + * s3fs - FUSE-based file system backed by Amazon S3 + * + * Copyright(C) 2007 Randy Rizun + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef S3FS_FDCACHE_AUTO_H_ +#define S3FS_FDCACHE_AUTO_H_ + +#include "fdcache_entity.h" + +//------------------------------------------------ +// class AutoFdEntity +//------------------------------------------------ +// A class that opens fdentiry and closes it automatically. +// This class object is used to prevent inconsistencies in +// the number of references in fdentiry. +// The methods are wrappers to the method of the FdManager class. +// +class AutoFdEntity +{ + private: + FdEntity* pFdEntity; + + private: + AutoFdEntity(AutoFdEntity& other); + bool operator=(AutoFdEntity& other); + + public: + AutoFdEntity(); + ~AutoFdEntity(); + + bool Close(void); + bool Detach(void); + FdEntity* GetFdEntity(const char* path, int existfd = -1, bool increase_ref = true); + FdEntity* Open(const char* path, headers_t* pmeta = NULL, off_t size = -1, time_t time = -1, bool force_tmpfile = false, bool is_create = true, bool no_fd_lock_wait = false); + FdEntity* ExistOpen(const char* path, int existfd = -1, bool ignore_existfd = false); +}; + +#endif // S3FS_FDCACHE_AUTO_H_ + +/* +* Local variables: +* tab-width: 4 +* c-basic-offset: 4 +* End: +* vim600: expandtab sw=4 ts=4 fdm=marker +* vim<600: expandtab sw=4 ts=4 +*/ diff --git a/src/fdcache_entity.h b/src/fdcache_entity.h index fd3bc0b..19cfcd2 100644 --- a/src/fdcache_entity.h +++ b/src/fdcache_entity.h @@ -75,6 +75,7 @@ class FdEntity int Open(headers_t* pmeta = NULL, off_t size = -1, time_t time = -1, bool no_fd_lock_wait = false); bool OpenAndLoadAll(headers_t* pmeta = NULL, off_t* size = NULL, bool force_load = false); int Dup(bool lock_already_held = false); + int GetRefCnt(void) const { return refcnt; } // [NOTE] Use only debugging const char* GetPath(void) const { return path.c_str(); } bool RenamePath(const std::string& newpath, std::string& fentmapkey); diff --git a/src/s3fs.cpp b/src/s3fs.cpp index 310f452..07ade58 100644 --- a/src/s3fs.cpp +++ b/src/s3fs.cpp @@ -32,6 +32,7 @@ #include "s3fs.h" #include "metaheader.h" #include "fdcache.h" +#include "fdcache_auto.h" #include "curl.h" #include "curl_multi.h" #include "s3objlist.h" @@ -116,7 +117,7 @@ static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t static int check_object_access(const char* path, int mask, struct stat* pstbuf); static int check_object_owner(const char* path, struct stat* pstbuf); static int check_parent_object_access(const char* path, int mask); -static FdEntity* get_local_fent(const char* path, bool is_load = false); +static FdEntity* get_local_fent(AutoFdEntity& autoent, const char* path, bool is_load = false); static bool multi_head_callback(S3fsCurl* s3fscurl); static S3fsCurl* multi_head_retry_callback(S3fsCurl* s3fscurl); static int readdir_multi_head(const char* path, const S3ObjList& head, void* buf, fuse_fill_dir_t filler); @@ -674,7 +675,7 @@ bool get_object_sse_type(const char* path, sse_type_t& ssetype, std::string& sse return true; } -static FdEntity* get_local_fent(const char* path, bool is_load) +static FdEntity* get_local_fent(AutoFdEntity& autoent, const char* path, bool is_load) { struct stat stobj; FdEntity* ent; @@ -690,14 +691,14 @@ static FdEntity* get_local_fent(const char* path, bool is_load) time_t mtime = (!S_ISREG(stobj.st_mode) || S_ISLNK(stobj.st_mode)) ? -1 : stobj.st_mtime; bool force_tmpfile = S_ISREG(stobj.st_mode) ? false : true; - if(NULL == (ent = FdManager::get()->Open(path, &meta, stobj.st_size, mtime, force_tmpfile, true))){ + if(NULL == (ent = autoent.Open(path, &meta, stobj.st_size, mtime, force_tmpfile, true))){ S3FS_PRN_ERR("Could not open file. errno(%d)", errno); return NULL; } // load if(is_load && !ent->OpenAndLoadAll(&meta)){ S3FS_PRN_ERR("Could not load file. errno(%d)", errno); - FdManager::get()->Close(ent); + autoent.Close(); return NULL; } return ent; @@ -739,18 +740,18 @@ int put_headers(const char* path, headers_t& meta, bool is_copy) // if path is 'dir/', it does not have cache(could not open file for directory stat) // if('/' != path[strlen(path) - 1]){ - FdEntity* ent = NULL; - if(NULL == (ent = FdManager::get()->ExistOpen(path, -1, !FdManager::IsCacheDir()))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = autoent.ExistOpen(path, -1, !FdManager::IsCacheDir()))){ // no opened fd if(FdManager::IsCacheDir()){ // create cache file if be needed - ent = FdManager::get()->Open(path, &meta, buf.st_size, -1, false, true); + ent = autoent.Open(path, &meta, buf.st_size, -1, false, true); } } if(ent){ time_t mtime = get_mtime(meta); ent->SetMtime(mtime); - FdManager::get()->Close(ent); } } return 0; @@ -773,14 +774,13 @@ static int s3fs_getattr(const char* _path, struct stat* stbuf) // If has already opened fd, the st_size should be instead. // (See: Issue 241) if(stbuf){ - FdEntity* ent; - - if(NULL != (ent = FdManager::get()->ExistOpen(path))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path))){ struct stat tmpstbuf; if(ent->GetStats(tmpstbuf)){ stbuf->st_size = tmpstbuf.st_size; } - FdManager::get()->Close(ent); } stbuf->st_blksize = 4096; stbuf->st_blocks = get_blocks(stbuf->st_size); @@ -803,32 +803,30 @@ static int s3fs_readlink(const char* _path, char* buf, size_t size) // check symblic link cache if(!StatCache::getStatCacheData()->GetSymlink(std::string(path), strValue)){ // not found in cache, then open the path - FdEntity* ent; - if(NULL == (ent = get_local_fent(path))){ - S3FS_PRN_ERR("could not get fent(file=%s)", path); - return -EIO; + { // scope for AutoFdEntity + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = get_local_fent(autoent, path))){ + S3FS_PRN_ERR("could not get fent(file=%s)", path); + return -EIO; + } + // Get size + off_t readsize; + if(!ent->GetSize(readsize)){ + S3FS_PRN_ERR("could not get file size(file=%s)", path); + return -EIO; + } + if(static_cast(size) <= readsize){ + readsize = size - 1; + } + // Read + ssize_t ressize; + if(0 > (ressize = ent->Read(buf, 0, readsize))){ + S3FS_PRN_ERR("could not read file(file=%s, ressize=%zd)", path, ressize); + return static_cast(ressize); + } + buf[ressize] = '\0'; } - // Get size - off_t readsize; - if(!ent->GetSize(readsize)){ - S3FS_PRN_ERR("could not get file size(file=%s)", path); - FdManager::get()->Close(ent); - return -EIO; - } - if(static_cast(size) <= readsize){ - readsize = size - 1; - } - // Read - ssize_t ressize; - if(0 > (ressize = ent->Read(buf, 0, readsize))){ - S3FS_PRN_ERR("could not read file(file=%s, ressize=%zd)", path, ressize); - FdManager::get()->Close(ent); - return static_cast(ressize); - } - buf[ressize] = '\0'; - - // close - FdManager::get()->Close(ent); // check buf if it has space words. strValue = trim(std::string(buf)); @@ -971,14 +969,17 @@ static int s3fs_create(const char* _path, mode_t mode, struct fuse_file_info* fi return result; } - FdEntity* ent; - headers_t meta; + AutoFdEntity autoent; + FdEntity* ent; + headers_t meta; get_object_attribute(path, NULL, &meta, true, NULL, true); // no truncate cache - if(NULL == (ent = FdManager::get()->Open(path, &meta, 0, -1, false, true))){ + if(NULL == (ent = autoent.Open(path, &meta, 0, -1, false, true))){ StatCache::getStatCacheData()->DelStat(path); return -EIO; } + autoent.Detach(); // KEEP fdentity open fi->fh = ent->GetFd(); + S3FS_MALLOCTRIM(0); return 0; @@ -1161,24 +1162,26 @@ static int s3fs_symlink(const char* _from, const char* _to) headers["x-amz-meta-gid"] = str(pcxt->gid); // open tmpfile - FdEntity* ent; - if(NULL == (ent = FdManager::get()->Open(to, &headers, 0, -1, true, true))){ - S3FS_PRN_ERR("could not open tmpfile(errno=%d)", errno); - return -errno; + std::string strFrom; + { // scope for AutoFdEntity + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = autoent.Open(to, &headers, 0, -1, true, true))){ + S3FS_PRN_ERR("could not open tmpfile(errno=%d)", errno); + return -errno; + } + // write(without space words) + strFrom = trim(std::string(from)); + ssize_t from_size = static_cast(strFrom.length()); + if(from_size != ent->Write(strFrom.c_str(), 0, from_size)){ + S3FS_PRN_ERR("could not write tmpfile(errno=%d)", errno); + return -errno; + } + // upload + if(0 != (result = ent->Flush(true))){ + S3FS_PRN_WARN("could not upload tmpfile(result=%d)", result); + } } - // write(without space words) - std::string strFrom = trim(std::string(from)); - ssize_t from_size = static_cast(strFrom.length()); - if(from_size != ent->Write(strFrom.c_str(), 0, from_size)){ - S3FS_PRN_ERR("could not write tmpfile(errno=%d)", errno); - FdManager::get()->Close(ent); - return -errno; - } - // upload - if(0 != (result = ent->Flush(true))){ - S3FS_PRN_WARN("could not upload tmpfile(result=%d)", result); - } - FdManager::get()->Close(ent); StatCache::getStatCacheData()->DelStat(to); if(!StatCache::getStatCacheData()->AddSymlink(std::string(to), strFrom)){ @@ -1245,28 +1248,28 @@ static int rename_object_nocopy(const char* from, const char* to) } // open & load - FdEntity* ent; - if(NULL == (ent = get_local_fent(from, true))){ - S3FS_PRN_ERR("could not open and read file(%s)", from); - return -EIO; - } + { // scope for AutoFdEntity + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = get_local_fent(autoent, from, true))){ + S3FS_PRN_ERR("could not open and read file(%s)", from); + return -EIO; + } - // Set header - if(!ent->SetContentType(to)){ - S3FS_PRN_ERR("could not set content-type for %s", to); - return -EIO; - } + // Set header + if(!ent->SetContentType(to)){ + S3FS_PRN_ERR("could not set content-type for %s", to); + return -EIO; + } - // upload - if(0 != (result = ent->RowFlush(to, true))){ - S3FS_PRN_ERR("could not upload file(%s): result=%d", to, result); - FdManager::get()->Close(ent); - return result; + // upload + if(0 != (result = ent->RowFlush(to, true))){ + S3FS_PRN_ERR("could not upload file(%s): result=%d", to, result); + return result; + } + FdManager::get()->Rename(from, to); } - FdManager::get()->Rename(from, to); - FdManager::get()->Close(ent); - // Remove file result = s3fs_unlink(from); @@ -1489,15 +1492,16 @@ static int s3fs_rename(const char* _from, const char* _to) } // flush pending writes if file is open - FdEntity *entity = FdManager::get()->ExistOpen(from); - if(entity != NULL){ - if(0 != (result = entity->Flush(true))){ - S3FS_PRN_ERR("could not upload file(%s): result=%d", to, result); - return result; + { // scope for AutoFdEntity + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(from))){ + if(0 != (result = ent->Flush(true))){ + S3FS_PRN_ERR("could not upload file(%s): result=%d", to, result); + return result; + } + StatCache::getStatCacheData()->DelStat(from); } - StatCache::getStatCacheData()->DelStat(from); - FdManager::get()->Close(entity); - entity = NULL; } // files larger than 5GB must be modified via the multipart interface @@ -1588,8 +1592,9 @@ static int s3fs_chmod(const char* _path, mode_t mode) // we need to put these header after finishing upload. // Or if the file is only open, we must update to FdEntity's internal meta. // - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, -1, true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, -1, true))){ // the file is opened now. if(ent->MergeOrgMeta(updatemeta)){ // now uploading @@ -1599,12 +1604,10 @@ static int s3fs_chmod(const char* _path, mode_t mode) // allow to put header // updatemeta already merged the orgmeta of the opened files. if(0 != put_headers(strpath.c_str(), updatemeta, true)){ - FdManager::get()->Close(ent); return -EIO; } StatCache::getStatCacheData()->DelStat(nowcache); } - FdManager::get()->Close(ent); }else{ // not opened file, then put headers merge_headers(meta, updatemeta, true); @@ -1672,8 +1675,9 @@ static int s3fs_chmod_nocopy(const char* _path, mode_t mode) // normal object or directory object of newer version // open & load - FdEntity* ent; - if(NULL == (ent = get_local_fent(strpath.c_str(), true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = get_local_fent(autoent, strpath.c_str(), true))){ S3FS_PRN_ERR("could not open and read file(%s)", strpath.c_str()); return -EIO; } @@ -1686,11 +1690,8 @@ static int s3fs_chmod_nocopy(const char* _path, mode_t mode) // upload if(0 != (result = ent->Flush(true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", strpath.c_str(), result); - FdManager::get()->Close(ent); return result; } - FdManager::get()->Close(ent); - StatCache::getStatCacheData()->DelStat(nowcache); } S3FS_MALLOCTRIM(0); @@ -1767,8 +1768,9 @@ static int s3fs_chown(const char* _path, uid_t uid, gid_t gid) // we need to put these header after finishing upload. // Or if the file is only open, we must update to FdEntity's internal meta. // - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, -1, true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, -1, true))){ // the file is opened now. if(ent->MergeOrgMeta(updatemeta)){ // now uploading @@ -1778,12 +1780,10 @@ static int s3fs_chown(const char* _path, uid_t uid, gid_t gid) // allow to put header // updatemeta already merged the orgmeta of the opened files. if(0 != put_headers(strpath.c_str(), updatemeta, true)){ - FdManager::get()->Close(ent); return -EIO; } StatCache::getStatCacheData()->DelStat(nowcache); } - FdManager::get()->Close(ent); }else{ // not opened file, then put headers merge_headers(meta, updatemeta, true); @@ -1858,8 +1858,9 @@ static int s3fs_chown_nocopy(const char* _path, uid_t uid, gid_t gid) // normal object or directory object of newer version // open & load - FdEntity* ent; - if(NULL == (ent = get_local_fent(strpath.c_str(), true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = get_local_fent(autoent, strpath.c_str(), true))){ S3FS_PRN_ERR("could not open and read file(%s)", strpath.c_str()); return -EIO; } @@ -1873,11 +1874,8 @@ static int s3fs_chown_nocopy(const char* _path, uid_t uid, gid_t gid) // upload if(0 != (result = ent->Flush(true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", strpath.c_str(), result); - FdManager::get()->Close(ent); return result; } - FdManager::get()->Close(ent); - StatCache::getStatCacheData()->DelStat(nowcache); } S3FS_MALLOCTRIM(0); @@ -1948,8 +1946,9 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2]) // we need to put these header after finishing upload. // Or if the file is only open, we must update to FdEntity's internal meta. // - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, -1, true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, -1, true))){ // the file is opened now. if(ent->MergeOrgMeta(updatemeta)){ // now uploading @@ -1959,12 +1958,10 @@ static int s3fs_utimens(const char* _path, const struct timespec ts[2]) // allow to put header // updatemeta already merged the orgmeta of the opened files. if(0 != put_headers(strpath.c_str(), updatemeta, true)){ - FdManager::get()->Close(ent); return -EIO; } StatCache::getStatCacheData()->DelStat(nowcache); } - FdManager::get()->Close(ent); }else{ // not opened file, then put headers merge_headers(meta, updatemeta, true); @@ -2034,8 +2031,9 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2]) // normal object or directory object of newer version // open & load - FdEntity* ent; - if(NULL == (ent = get_local_fent(strpath.c_str(), true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = get_local_fent(autoent, strpath.c_str(), true))){ S3FS_PRN_ERR("could not open and read file(%s)", strpath.c_str()); return -EIO; } @@ -2043,18 +2041,14 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2]) // set mtime if(0 != (result = ent->SetMtime(ts[1].tv_sec))){ S3FS_PRN_ERR("could not set mtime to file(%s): result=%d", strpath.c_str(), result); - FdManager::get()->Close(ent); return result; } // upload if(0 != (result = ent->Flush(true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", strpath.c_str(), result); - FdManager::get()->Close(ent); return result; } - FdManager::get()->Close(ent); - StatCache::getStatCacheData()->DelStat(nowcache); } S3FS_MALLOCTRIM(0); @@ -2065,9 +2059,10 @@ static int s3fs_utimens_nocopy(const char* _path, const struct timespec ts[2]) static int s3fs_truncate(const char* _path, off_t size) { WTF8_ENCODE(path) - int result; - headers_t meta; - FdEntity* ent = NULL; + int result; + headers_t meta; + AutoFdEntity autoent; + FdEntity* ent = NULL; S3FS_PRN_INFO("[path=%s][size=%lld]", path, static_cast(size)); @@ -2085,13 +2080,12 @@ static int s3fs_truncate(const char* _path, off_t size) // Get file information if(0 == (result = get_object_attribute(path, NULL, &meta))){ // Exists -> Get file(with size) - if(NULL == (ent = FdManager::get()->Open(path, &meta, size, -1, false, true))){ + if(NULL == (ent = autoent.Open(path, &meta, size, -1, false, true))){ S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno); return -EIO; } if(0 != (result = ent->Load(0, size))){ S3FS_PRN_ERR("could not download file(%s): result=%d", path, result); - FdManager::get()->Close(ent); return result; } @@ -2110,7 +2104,7 @@ static int s3fs_truncate(const char* _path, off_t size) meta["x-amz-meta-uid"] = str(pcxt->uid); meta["x-amz-meta-gid"] = str(pcxt->gid); - if(NULL == (ent = FdManager::get()->Open(path, &meta, size, -1, true, true))){ + if(NULL == (ent = autoent.Open(path, &meta, size, -1, true, true))){ S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno); return -EIO; } @@ -2119,10 +2113,8 @@ static int s3fs_truncate(const char* _path, off_t size) // upload if(0 != (result = ent->Flush(true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result); - FdManager::get()->Close(ent); return result; } - FdManager::get()->Close(ent); StatCache::getStatCacheData()->DelStat(path); S3FS_MALLOCTRIM(0); @@ -2174,10 +2166,11 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi) st.st_mtime = -1; } - FdEntity* ent; - headers_t meta; + AutoFdEntity autoent; + FdEntity* ent; + headers_t meta; get_object_attribute(path, NULL, &meta, true, NULL, true); // no truncate cache - if(NULL == (ent = FdManager::get()->Open(path, &meta, st.st_size, st.st_mtime, false, true))){ + if(NULL == (ent = autoent.Open(path, &meta, st.st_size, st.st_mtime, false, true))){ StatCache::getStatCacheData()->DelStat(path); return -EIO; } @@ -2185,13 +2178,13 @@ static int s3fs_open(const char* _path, struct fuse_file_info* fi) if (needs_flush){ if(0 != (result = ent->RowFlush(path, true))){ S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result); - FdManager::get()->Close(ent); StatCache::getStatCacheData()->DelStat(path); return result; } } - + autoent.Detach(); // KEEP fdentity open fi->fh = ent->GetFd(); + S3FS_MALLOCTRIM(0); return 0; @@ -2204,8 +2197,9 @@ static int s3fs_read(const char* _path, char* buf, size_t size, off_t offset, st S3FS_PRN_DBG("[path=%s][size=%zu][offset=%lld][fd=%llu]", path, size, static_cast(offset), (unsigned long long)(fi->fh)); - FdEntity* ent; - if(NULL == (ent = FdManager::get()->ExistOpen(path, static_cast(fi->fh)))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = autoent.ExistOpen(path, static_cast(fi->fh)))){ S3FS_PRN_ERR("could not find opened fd(%s)", path); return -EIO; } @@ -2217,14 +2211,12 @@ static int s3fs_read(const char* _path, char* buf, size_t size, off_t offset, st off_t realsize = 0; if(!ent->GetSize(realsize) || 0 == realsize){ S3FS_PRN_DBG("file size is 0, so break to read."); - FdManager::get()->Close(ent); return 0; } if(0 > (res = ent->Read(buf, offset, size, false))){ S3FS_PRN_WARN("failed to read file(%s). result=%zd", path, res); } - FdManager::get()->Close(ent); return static_cast(res); } @@ -2236,8 +2228,9 @@ static int s3fs_write(const char* _path, const char* buf, size_t size, off_t off S3FS_PRN_DBG("[path=%s][size=%zu][offset=%lld][fd=%llu]", path, size, static_cast(offset), (unsigned long long)(fi->fh)); - FdEntity* ent; - if(NULL == (ent = FdManager::get()->ExistOpen(path, static_cast(fi->fh)))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL == (ent = autoent.ExistOpen(path, static_cast(fi->fh)))){ S3FS_PRN_ERR("could not find opened fd(%s)", path); return -EIO; } @@ -2247,7 +2240,6 @@ static int s3fs_write(const char* _path, const char* buf, size_t size, off_t off if(0 > (res = ent->Write(buf, offset, size))){ S3FS_PRN_WARN("failed to write file(%s). result=%zd", path, res); } - FdManager::get()->Close(ent); return static_cast(res); } @@ -2284,11 +2276,11 @@ static int s3fs_flush(const char* _path, struct fuse_file_info* fi) return result; } - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, static_cast(fi->fh)))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, static_cast(fi->fh)))){ ent->UpdateMtime(); result = ent->Flush(false); - FdManager::get()->Close(ent); } S3FS_MALLOCTRIM(0); @@ -2305,13 +2297,13 @@ static int s3fs_fsync(const char* _path, int datasync, struct fuse_file_info* fi S3FS_PRN_INFO("[path=%s][fd=%llu]", path, (unsigned long long)(fi->fh)); - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, static_cast(fi->fh)))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, static_cast(fi->fh)))){ if(0 == datasync){ ent->UpdateMtime(); } result = ent->Flush(false); - FdManager::get()->Close(ent); } S3FS_MALLOCTRIM(0); @@ -2341,22 +2333,30 @@ static int s3fs_release(const char* _path, struct fuse_file_info* fi) StatCache::getStatCacheData()->DelStat(path); } - FdEntity* ent; - if(NULL == (ent = FdManager::get()->GetFdEntity(path, static_cast(fi->fh)))){ - S3FS_PRN_ERR("could not find fd(file=%s)", path); - return -EIO; - } - if(ent->GetFd() != static_cast(fi->fh)){ - S3FS_PRN_WARN("different fd(%d - %llu)", ent->GetFd(), (unsigned long long)(fi->fh)); - } + { // scope for AutoFdEntity + AutoFdEntity autoent; + FdEntity* ent; - // Once for the implicit refcnt from GetFdEntity and again for release - ent->Close(); - FdManager::get()->Close(ent); + // [NOTE] + // The number of references to fdEntity corresponding to fi-> fh is already incremented + // when it is opened. Therefore, when an existing fdEntity is detected here, the reference + // count must not be incremented. And if detected, the number of references incremented + // when opened will be decremented when the AutoFdEntity object is subsequently destroyed. + // + if(NULL == (ent = autoent.GetFdEntity(path, static_cast(fi->fh), false))){ + S3FS_PRN_ERR("could not find fd(file=%s)", path); + return -EIO; + } + if(ent->GetFd() != static_cast(fi->fh)){ + S3FS_PRN_WARN("different fd(%d - %llu)", ent->GetFd(), (unsigned long long)(fi->fh)); + } + } // check - for debug if(IS_S3FS_LOG_DBG()){ - if(NULL != (ent = FdManager::get()->GetFdEntity(path, static_cast(fi->fh)))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.GetFdEntity(path, static_cast(fi->fh)))){ S3FS_PRN_WARN("file(%s),fd(%d) is still opened.", path, ent->GetFd()); } } @@ -2899,8 +2899,9 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value, // we need to put these header after finishing upload. // Or if the file is only open, we must update to FdEntity's internal meta. // - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, -1, true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, -1, true))){ // the file is opened now. // get xattr and make new xattr @@ -2914,7 +2915,6 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value, ent->SetXattr(strxattr); } if(0 != (result = set_xattrs_to_header(updatemeta, name, value, size, flags))){ - FdManager::get()->Close(ent); return result; } @@ -2926,12 +2926,10 @@ static int s3fs_setxattr(const char* path, const char* name, const char* value, // allow to put header // updatemeta already merged the orgmeta of the opened files. if(0 != put_headers(strpath.c_str(), updatemeta, true)){ - FdManager::get()->Close(ent); return -EIO; } StatCache::getStatCacheData()->DelStat(nowcache); } - FdManager::get()->Close(ent); }else{ // not opened file, then put headers merge_headers(meta, updatemeta, true); @@ -3191,8 +3189,9 @@ static int s3fs_removexattr(const char* path, const char* name) // we need to put these header after finishing upload. // Or if the file is only open, we must update to FdEntity's internal meta. // - FdEntity* ent; - if(NULL != (ent = FdManager::get()->ExistOpen(path, -1, true))){ + AutoFdEntity autoent; + FdEntity* ent; + if(NULL != (ent = autoent.ExistOpen(path, -1, true))){ // the file is opened now. if(ent->MergeOrgMeta(updatemeta)){ // now uploading @@ -3205,12 +3204,10 @@ static int s3fs_removexattr(const char* path, const char* name) updatemeta.erase("x-amz-meta-xattr"); } if(0 != put_headers(strpath.c_str(), updatemeta, true)){ - FdManager::get()->Close(ent); return -EIO; } StatCache::getStatCacheData()->DelStat(nowcache); } - FdManager::get()->Close(ent); }else{ // not opened file, then put headers if(updatemeta["x-amz-meta-xattr"].empty()){