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 <ggtakec@gmail.com>
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>

* 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 <ggtakec@gmail.com>
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>

---------

Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
This commit is contained in:
Eryu Guan 2023-05-30 17:39:50 +08:00 committed by GitHub
parent 0d6b02090e
commit 6ca5a24a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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){