From 6ca5a24a7f29718967de1b8cc78dfe68c839729a Mon Sep 17 00:00:00 2001 From: Eryu Guan <45746212+eryugey@users.noreply.github.com> Date: Tue, 30 May 2023 17:39:50 +0800 Subject: [PATCH] Fix two inconsistency issues between stat cache and cache file (#2152) * Fix inconsistency between stat cache file and cache file We unlock stat cache file too early in FdEntity::Open(), and would truncate cache file and update stat cache file, so there's a window that stat cache doesn't reflect cache file status. Suggested-by: Takeshi Nakatani Signed-off-by: Eryu Guan * Mark pagelist as unloaded if cache file has been truncated If cache file size doesn't match object size, the cache file might be corrupted, so invalidate it and save new cache stat file. Suggested-by: Takeshi Nakatani Signed-off-by: Eryu Guan --------- Signed-off-by: Eryu Guan --- src/fdcache_entity.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/fdcache_entity.cpp b/src/fdcache_entity.cpp index e060a08..9a71d30 100644 --- a/src/fdcache_entity.cpp +++ b/src/fdcache_entity.cpp @@ -485,6 +485,8 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts bool need_save_csf = false; // need to save(reset) cache stat file bool is_truncate = false; // need to truncate + CacheFileStat* pcfstat = NULL; + if(!cachepath.empty()){ // using cache struct stat st; @@ -498,12 +500,12 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts } // open cache and cache stat file, load page info. - CacheFileStat cfstat(path.c_str()); + pcfstat = new CacheFileStat(path.c_str()); // try to open cache file if( -1 != (physical_fd = open(cachepath.c_str(), O_RDWR)) && 0 != (inode = FdEntity::GetInode(physical_fd)) && - pagelist.Serialize(cfstat, false, inode) ) + pagelist.Serialize(*pcfstat, false, inode) ) { // succeed to open cache file and to load stats data memset(&st, 0, sizeof(struct stat)); @@ -517,13 +519,18 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts if(-1 == size){ if(st.st_size != pagelist.Size()){ pagelist.Resize(st.st_size, false, true); // Areas with increased size are modified - need_save_csf = true; // need to update page info + need_save_csf = true; // need to update page info } size = st.st_size; }else{ + // First if the current cache file size and pagelist do not match, fix pagelist. + if(st.st_size != pagelist.Size()){ + pagelist.Resize(st.st_size, false, true); // Areas with increased size are modified + need_save_csf = true; // need to update page info + } if(size != pagelist.Size()){ pagelist.Resize(size, false, true); // Areas with increased size are modified - need_save_csf = true; // need to update page info + need_save_csf = true; // need to update page info } if(size != st.st_size){ is_truncate = true; @@ -631,12 +638,14 @@ int FdEntity::Open(const headers_t* pmeta, off_t size, const struct timespec& ts } // reset cache stat file - if(need_save_csf){ - CacheFileStat cfstat(path.c_str()); - if(!pagelist.Serialize(cfstat, true, inode)){ + if(need_save_csf && pcfstat){ + if(!pagelist.Serialize(*pcfstat, true, inode)){ S3FS_PRN_WARN("failed to save cache stat file(%s), but continue...", path.c_str()); } } + if(pcfstat){ + delete pcfstat; + } // set original headers and size in it. if(pmeta){