Repository: juicedata/juicefs
Pull request #2791 (2022-09-21 10:06:30)

CI:refactor filebench

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=juicedata_juicefs&pullRequest=2791)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=juicedata_juicefs&pullRequest=2791&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=juicedata_juicefs&pullRequest=2791&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/.github/actions/filebench/action.yml b/.github/actions/filebench/action.yml
new file mode 100644
index 00000000..1533a59f
--- /dev/null
+++ b/.github/actions/filebench/action.yml
@@ -0,0 +1,121 @@
+name: 'JuiceFS Filebench Action'
+description: 'JuiceFS Filebench Action'
+inputs:
+  workload:
+    description: 'type of the workload'
+    required: true
+    default: 'none'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Set up Go
+      uses: actions/setup-go@v2
+      with:
+        go-version: '1.18.x'
+
+    - name: Set up Docker
+      uses: docker-practice/actions-setup-docker@master
+
+    - uses: actions/cache@v3
+      with:
+        path: |
+          ~/.cache/go-build
+          ~/go/pkg/mod
+        key: ${{ runner.os }}-go
+        restore-keys: |
+          ${{ runner.os }}-go
+
+    - name: Build linux target
+      shell: bash
+      run: make juicefs
+
+    - name: Run Redis
+      shell: bash
+      run: |
+        sudo docker run -d --name redis -v redis-data:/data  \
+        -p 6379:6379  redis redis-server --appendonly yes
+
+
+    - name: Setup minio
+      shell: bash
+      run: |
+        docker run -d -p 9000:9000 --name minio \
+                  -e "MINIO_ACCESS_KEY=minioadmin" \
+                  -e "MINIO_SECRET_KEY=minioadmin" \
+                  -v /tmp/data:/data \
+                  -v /tmp/config:/root/.minio \
+                  minio/minio server /data
+        sleep 5
+
+    - name: Juicefs Format
+      shell: bash
+      run: |
+        pwd
+        echo "hello"
+        ls
+        sudo ./juicefs format --trash-days 0  --storage minio --bucket http://127.0.0.1:9000/mypics \
+           --access-key minioadmin \
+           --secret-key minioadmin \
+           redis://127.0.0.1:6379/1 pics
+
+    - name: Juicefs Mount
+      shell: bash
+      run: |
+        sudo ./juicefs mount -d redis://127.0.0.1:6379/1 /data/jfs --no-usage-report &
+
+
+    - name: Install Dependency
+      shell: bash
+      run: |
+        wget -O filebench.tar.gz https://github.com/filebench/filebench/releases/download/1.5-alpha3/filebench-1.5-alpha3.tar.gz
+        tar -zxvf filebench.tar.gz
+        cd filebench-1.5-alpha3
+        #sudo apt install -y bison
+        #sudo apt install -y byacc
+        #sudo apt install -y flex
+        ./configure
+        make
+        sudo make install
+        filebench -h
+        echo 0 >randomize_va_space
+        sudo cp randomize_va_space /proc/sys/kernel/
+        echo "randomize_va_space"
+        cat /proc/sys/kernel/randomize_va_space
+
+
+    - name: Run Workload
+      shell: bash
+      run: |
+        cd /usr/local/share/filebench/workloads/
+        sudo chmod 777 *
+        if [ ${{inputs.workload}} == "varmail" ];then
+          echo "run varmail workload"
+          sudo sed -i "s?/tmp?/data/jfs?" varmail.f
+          sudo sed -i "s?run 60?run 1800?" varmail.f
+          cat varmail.f
+          sudo filebench -f varmail.f
+        elif [ ${{inputs.workload}} == "webserver" ];then
+          echo "run webserver workload"
+          sudo sed -i "s?/tmp?/data/jfs?" webserver.f
+          sudo sed -i "s?run 60?run 1800?" webserver.f
+          cat webserver.f
+          sudo filebench -f webserver.f
+        elif [ ${{inputs.workload}} == "videoserver" ];then
+          echo "run videoserver worload"
+          sudo sed -i "s?/tmp?/data/jfs?" videoserver.f
+          sudo sed -i "s?$filesize=10g?$filesize=100m?" videoserver.f
+          sudo sed -i "s?$numpassivevids=194?$numpassivevids=100?" videoserver.f
+          sudo echo "run 1800" >>videoserver.f
+          cat videoserver.f
+          sudo filebench -f videoserver.f
+        fi
+
+    - name: Log
+      shell: bash
+      if: ${{ always() }}
+      run: |
+        df -lh
+        echo "juicefs log"
+        sudo tail -n 1000 /var/log/juicefs.log
+        grep "<FATAL>:" /var/log/juicefs.log && exit 1 || true
\ No newline at end of file
diff --git a/.github/actions/gateway/action.yml b/.github/actions/gateway/action.yml
deleted file mode 100644
index e1d862d8..00000000
--- a/.github/actions/gateway/action.yml
+++ /dev/null
@@ -1,197 +0,0 @@
-name: 'JuiceFS Gateway Action'
-description: 'JuiceFS gateway action'
-inputs:
-  meta_url:  
-    description: 'meta url'
-    required: true
-    default: ''
-  file_count:  
-    description: 'count of files to upload to gateway'
-    required: true
-    default: '100'
-  file_size:
-    description: 'size of each file in human read format, eg 1K, 1M, 1G.'
-    required: true
-    default: '4K'
-  threads:
-    description: 'thread number for juicefs sync command'
-    required: true
-    default: 10
-  isolation_level:
-    description: 'isolation level for mysql, include read uncommitted, read committed, repeatable read, serializable'
-    required: true
-    default: "repeatable read"
-  mount_point:
-    description: 'mount point'
-    required: true
-    default: /tmp/myjfs
-  volume_name:
-    description: 'volume name'
-    required: true
-    default: myjfs
-  
-runs:
-  using: "composite"
-  steps:
-    - name: Checkout
-      uses: actions/checkout@v2
-      with:
-        fetch-depth: 1
-
-    - name: Set up Go
-      uses: actions/setup-go@v2
-      with:
-        go-version: '1.18.x'
-
-    - uses: actions/cache@v3
-      with:
-        path: |
-          ~/.cache/go-build
-          ~/go/pkg/mod
-        key: ${{ runner.os }}-go
-        restore-keys: |
-          ${{ runner.os }}-go
-
-    - name: Build linux target
-      run: |
-        #if it is self ruuner
-        hostname | grep bench && export GOPATH=/usr/local/go && export HOME=/root
-        make juicefs 
-        #wget -q https://github.com/juicedata/juicefs/releases/download/v1.0.0-beta3/juicefs-1.0.0-beta3-linux-amd64.tar.gz
-        #tar -xzf juicefs-1.0.0-beta3-linux-amd64.tar.gz
-      shell: bash
-
-    - name: Install tools
-      run: | 
-        wget -q https://dl.minio.io/client/mc/release/linux-amd64/mc
-        chmod +x mc 
-      shell: bash
-
-    - name: Init
-      shell: bash
-      run: | 
-        set -x
-        mp=${{inputs.mount_point}}
-        meta_url=${{inputs.meta_url}}
-        volume=${{inputs.volume_name}}
-        test -d $mp && ./juicefs umount -f $mp
-        ./juicefs status $meta_url && UUID=$(./juicefs status $meta_url | grep UUID | cut -d '"' -f 4) || echo "meta not exist"
-        if [ -n "$UUID" ];then
-          ./juicefs destroy --force $meta_url $UUID
-        fi
-        test -d /var/jfs/$volume && rm -rf /var/jfs/$volume || true
-        echo finished
-      
-    - name: create database
-      shell: bash
-      run: | 
-        meta_url=${{inputs.meta_url}}
-        isolation_level="${{inputs.isolation_level}}"
-        db_name=$(basename $meta_url | awk -F? '{print $1}')
-        if [[ "$meta_url" == mysql* ]]; then
-          user=$(echo $meta_url |  awk -F/ '{print $3}' | awk -F@ '{print $1}' | awk -F: '{print $1}')
-          password=$(echo $meta_url |  awk -F/ '{print $3}' | awk -F@ '{print $1}' | awk -F: '{print $2}')
-          test -n "$password" && password="-p$password" || password=""
-          host=$(basename $(dirname $meta_url) | awk -F@ '{print $2}'| sed 's/(//g' | sed 's/)//g' | awk -F: '{print $1}')
-          port=$(basename $(dirname $meta_url) | awk -F@ '{print $2}'| sed 's/(//g' | sed 's/)//g' | awk -F: '{print $2}')
-          test -z "$port" && port="3306"
-          mysql -u$user $password -h $host -P $port -e "set global transaction isolation level $isolation_level;" 
-          mysql -u$user $password -h $host -P $port -e "show variables like '%isolation%;'" 
-          mysql -u$user $password -h $host -P $port -e "drop database if exists $db_name; create database $db_name;" 
-        elif [[ "$meta_url" == postgres* ]]; then
-          export PGPASSWORD="postgres"
-          printf "\set AUTOCOMMIT on\ndrop database if exists $db_name; create database $db_name; " |  psql -U postgres -h localhost
-          printf "\set AUTOCOMMIT on\nALTER DATABASE $db_name SET DEFAULT_TRANSACTION_ISOLATION TO '$isolation_level';" |  psql -U postgres -h localhost
-        fi      
-      
-    - name: start gateway
-      shell: bash
-      run: |
-        meta_url=${{inputs.meta_url}}
-        mp=${{inputs.mount_point}}
-        volume=${{inputs.volume_name}}
-        export MINIO_ROOT_USER=minioadmin
-        export MINIO_ROOT_PASSWORD=minioadmin
-        ./juicefs format $meta_url $volume --trash-days 0
-        if [[ "$meta_url" == badger* ]]; then
-          ./juicefs gateway $meta_url localhost:8080 --no-usage-report /tmp/access1.log &
-        else
-          ./juicefs gateway $meta_url localhost:8080 --access-log /tmp/access1.log &
-          #./juicefs gateway $meta_url localhost:9000 --access-log /tmp/access1.log &
-          #./juicefs gateway $meta_url localhost:9001 --access-log /tmp/access2.log &
-          #sudo cp .github/workflows/resources/load-balancer.conf /etc/nginx/conf.d/load-balancer.conf
-          #sudo rm /etc/nginx/sites-enabled/default
-          #sudo systemctl restart nginx
-        fi
-      
-    - name: Sync with multiple process
-      shell: bash
-      run: |
-        meta_url=${{inputs.meta_url}}
-        file_size=${{inputs.file_size}}
-        file_count=${{inputs.file_count}}
-        threads=${{inputs.threads}}
-        mp=${{inputs.mount_point}}
-        volume=${{inputs.volume_name}}
-        
-        dd if=/dev/urandom of=file iflag=fullblock,count_bytes bs=4k count="$file_size" > /dev/null
-        mkdir data
-        for i in $(seq 1 $file_count); do
-          cp file data/file$i
-        done
-        start=`date +%s`
-        declare -a pids   
-        ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
-        pids+=($!)
-        ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
-        pids+=($!)
-        ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
-        pids+=($!)
-        wait "${pids[@]}"
-        rm -rf $HOME/.juicefs/cache/ || true
-        # ./mc alias set minio http://localhost:9000 minioadmin minioadmin --api S3v4
-        # ./mc mb minio/$volume
-        # ./mc cp --recursive data/  minio/$volume/data
-        end=`date +%s`
-        time=$((end-start))
-        echo time cost is: $time second
-        killall juicefs 
-        sleep 3
-        ./juicefs mount -d $meta_url $mp
-        diff -ur data/ $mp/data/ 
-        echo "diff succeed"
-        ./juicefs umount  $mp --force
-      
-    - name: Sync with empty dir
-      run: |
-        meta_url=${{inputs.meta_url}}
-        threads=${{inputs.threads}}
-        mp=${{inputs.mount_point}}
-        volume=${{inputs.volume_name}}
-        export MINIO_ROOT_USER=minioadmin
-        export MINIO_ROOT_PASSWORD=minioadmin
-        ./juicefs mdtest $meta_url test --dirs 10 --depth 2 --files 10 --threads 10 --no-usage-report
-        ./juicefs gateway $meta_url localhost:8080 --access-log /tmp/access1.log &
-        sleep 10
-        mkdir emptydir
-        declare -a pids  
-        ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
-        pids+=($!)
-        ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
-        pids+=($!)
-        ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
-        pids+=($!)
-        wait "${pids[@]}"
-        killall juicefs
-        sleep 3
-        ./juicefs mount -d $meta_url $mp
-        [ -d "$mp/test/" ] && exit 1 
-        ./juicefs umount  $mp --force
-      shell: bash
-
-    - name: log
-      if: ${{ always() }}
-      shell: bash
-      run: | 
-        tail -300 ~/.juicefs/juicefs.log
-        grep "<FATAL>:" ~/.juicefs/juicefs.log && exit 1 || true
\ No newline at end of file
diff --git a/.github/workflows/filebench.yml b/.github/workflows/filebench.yml
index 10c44524..8b0b784f 100644
--- a/.github/workflows/filebench.yml
+++ b/.github/workflows/filebench.yml
@@ -16,156 +16,57 @@ on:
     - cron:  '30 20 * * *'
   workflow_dispatch:
 
+
 jobs:
-  filebench:
+  filebench_varmail:
     timeout-minutes: 60
     runs-on: ubuntu-latest
     steps:
-      - name: Set up Go
-        uses: actions/setup-go@v2
-        with:
-          go-version: '1.18.x'
-
-      - name: Set up Docker
-        uses: docker-practice/actions-setup-docker@master
-
       - name: Checkout
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           fetch-depth: 1
-
-
-      - uses: actions/cache@v3
+      - name: Varmail
+        uses: ./.github/actions/filebench/
         with:
-          path: |
-            ~/.cache/go-build
-            ~/go/pkg/mod
-          key: ${{ runner.os }}-go
-          restore-keys: |
-            ${{ runner.os }}-go
-
-      - name: Build linux target
-        run: |
-          make juicefs
-
-      - name: Run Redis
-        run: |
-          sudo docker run -d --name redis -v redis-data:/data  \
-          -p 6379:6379  redis redis-server --appendonly yes
-
-
-      - name: Setup minio
-        run: |
-          docker run -d -p 9000:9000 --name minio \
-                    -e "MINIO_ACCESS_KEY=minioadmin" \
-                    -e "MINIO_SECRET_KEY=minioadmin" \
-                    -v /tmp/data:/data \
-                    -v /tmp/config:/root/.minio \
-                    minio/minio server /data
-          sleep 5
+          workload: varmail
 
 
-      - name: Juicefs Format
-        run: |
-          sudo ./juicefs format --trash-days 0 --storage minio --bucket http://127.0.0.1:9000/mypics \
-             --access-key minioadmin \
-             --secret-key minioadmin \
-             redis://127.0.0.1:6379/1 pics
-
-
-      - name: Juicefs Mount
-        run: |
-          sudo ./juicefs mount -d redis://127.0.0.1:6379/1 /data/jfs --no-usage-report &
-
-
-      - name: Install Dependency
-        run: |
-          wget -O filebench.tar.gz https://github.com/filebench/filebench/releases/download/1.5-alpha3/filebench-1.5-alpha3.tar.gz
-          tar -zxvf filebench.tar.gz
-          cd filebench-1.5-alpha3
-          #sudo apt install -y bison
-          #sudo apt install -y byacc
-          #sudo apt install -y flex
-          ./configure
-          make
-          sudo make install
-          filebench -h
-          echo 0 >randomize_va_space
-          sudo cp randomize_va_space /proc/sys/kernel/
-          echo "randomize_va_space"
-          cat /proc/sys/kernel/randomize_va_space
-
+      - name: Setup upterm session
+        if: ${{ failure() }}
+        uses: lhotari/action-upterm@v1
 
-      - name: Varmail
-        timeout-minutes: 10
-        run: |
-          cd /usr/local/share/filebench/workloads/
-          sudo chmod 777 *
-          sudo sed -i "s?/tmp?/data/jfs?" varmail.f
-          sudo sed -i "s?run 60?run 300?" varmail.f
-          cat varmail.f
-          sudo filebench -f varmail.f
 
+  filebench_webserver:
+    timeout-minutes: 60
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 1
       - name: Webserver
-        timeout-minutes: 10
-        run: |
-          cd /usr/local/share/filebench/workloads/
-          sudo sed -i "s?/tmp?/data/jfs?" webserver.f
-          sudo sed -i "s?run 60?run 300?" webserver.f
-          cat webserver.f
-          sudo filebench -f webserver.f
-
-
-      - name: Videoserver
-        timeout-minutes: 10
-        run: |
-          cd /usr/local/share/filebench/workloads/
-          sudo sed -i "s?/tmp?/data/jfs?" videoserver.f
-          sudo sed -i "s?$filesize=10g?$filesize=100m?" videoserver.f
-          sudo sed -i "s?$numpassivevids=194?$numpassivevids=100?" videoserver.f
-          sudo echo "run 300" >>videoserver.f
-          df -lh
-          cat videoserver.f
-          sudo filebench -f videoserver.f
-
-
-      - name: Videoserver 500M
-        timeout-minutes: 10
-        run: |
-          cd /usr/local/share/filebench/workloads/
-          sudo cp videoserver.f videoserver_500m.f
-          sudo sed -i "s?$eventrate=96?$eventrate=500?" videoserver_500m.f
-          df -lh
-          cat videoserver_500m.f
-          sudo filebench -f videoserver_500m.f
-
-
-      - name: Videoserver 1000M
-        timeout-minutes: 10
-        run: |
-          cd /usr/local/share/filebench/workloads/
-          sudo cp videoserver.f videoserver_1000m.f
-          sudo sed -i "s?$eventrate=96?$eventrate=1000?" videoserver_1000m.f
-          df -lh
-          cat videoserver_1000m.f
-          sudo filebench -f videoserver_1000m.f
-          df -lh
+        uses: ./.github/actions/filebench/
+        with:
+          workload: webserver
 
+      - name: Setup upterm session
+        if: ${{ failure() }}
+        uses: lhotari/action-upterm@v1
 
-      - name: Log
-        if: ${{ always() }}
-        run: |
-          df -lh
-          tail -300 /var/log/juicefs.log
-          grep "<FATAL>:" /var/log/juicefs.log && exit 1 || true
 
-      - name: Send Slack Notification
-        if: ${{ failure() }}
-        uses: juicedata/slack-notify-action@main
+  filebench_videoserver:
+    timeout-minutes: 60
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
         with:
-          channel-id: "${{ secrets.SLACK_CHANNEL_ID_FOR_PR_CHECK_NOTIFY }}"
-          slack_bot_token: "${{ secrets.SLACK_BOT_TOKEN }}"
-
+          fetch-depth: 1
+      - name: Videoserver
+        uses: ./.github/actions/filebench/
+        with:
+          workload: videoserver
 
       - name: Setup upterm session
         if: ${{ failure() }}
diff --git a/.github/workflows/gateway.yml b/.github/workflows/gateway.yml
index 98e923ea..8ee59483 100644
--- a/.github/workflows/gateway.yml
+++ b/.github/workflows/gateway.yml
@@ -17,318 +17,47 @@ on:
   workflow_dispatch:
 
 jobs:
-  upload-big-file-with-redis:
-    runs-on: ubuntu-latest
-    services:
-      redis:
-        # Docker Hub image
-        image: redis
-        # Set health checks to wait until redis has started
-        options: >-
-          --health-cmd "redis-cli ping"
-          --health-interval 10s
-          --health-timeout 5s
-          --health-retries 5
-        ports:
-          # Maps port 6379 on service container to the host
-          - 6379:6379
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "redis://localhost/1"
-          file_size: "100M"
-          file_count: 5
-
-  upload-small-files-with-redis:
-    runs-on: ubuntu-latest
-    services:
-      redis:
-        # Docker Hub image
-        image: redis
-        # Set health checks to wait until redis has started
-        options: >-
-          --health-cmd "redis-cli ping"
-          --health-interval 10s
-          --health-timeout 5s
-          --health-retries 5
-        ports:
-          # Maps port 6379 on service container to the host
-          - 6379:6379
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "redis://localhost/1"
-          file_size: "8K"
-          file_count: 2500
-
-
-  upload-small-files-with-mysql-read-uncommitted:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "8K"
-          file_count: 2500
-          isolation_level: "read uncommitted"    
-
-
-  upload-small-files-with-mysql-read-committed:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "8K"
-          file_count: 2500
-          isolation_level: "read committed"    
-
-
-  upload-small-files-with-mysql-repeatable-read:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "8K"
-          file_count: 2500
-          isolation_level: "repeatable read"   
-
-
-  upload-small-files-with-mysql-serializable:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "8K"
-          file_count: 2500
-          isolation_level: "serializable"     
-
-
-  upload-big-files-with-mysql-read-uncommitted:
-    runs-on: ubuntu-latest          
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "read uncommitted"
-
-
-  upload-big-files-with-mysql-read-committed:
-    runs-on: ubuntu-latest          
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "read committed"
-
-
-  upload-big-files-with-mysql-repeatable-read:
-    runs-on: ubuntu-latest          
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "repeatable read"
-
-
-  upload-big-files-with-mysql-serializable:
-    runs-on: ubuntu-latest          
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo /etc/init.d/mysql start
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "serializable"
-
-
-  upload-big-files-with-mariadb-read-committed:
-    runs-on: ubuntu-latest          
-    steps:
-      - uses: actions/checkout@v3
-      - name: install 
-        run: | 
-          docker run -p 127.0.0.1:3306:3306  --name mdb -e MARIADB_ROOT_PASSWORD=root -d mariadb:latest
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:root@\\(127.0.0.1\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "read committed"
-
-
-  upload-big-files-with-badgerdb:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo go get github.com/dgraph-io/badger/v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "badger://badger-data"
-          file_size: "100M"
-          file_count: 1
-
-
-  upload-small-files-with-badgerdb:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo go get github.com/dgraph-io/badger/v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "badger://badger-data"
-          file_size: "8K"
-          file_count: 2500
-
-
-
-  upload-small-files-with-sqlite:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "sqlite3://test.db"
-          file_size: "8K"
-          file_count: 2500    
-
-
-  upload-big-files-with-sqlite:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "sqlite3://test.db"
-          file_size: "100M"
-          file_count: 5    
-
-
-  upload-small-files-with-pg:
-    runs-on: ubuntu-latest
-    services:
-      postgres:
-        image: postgres
-        env:
-          POSTGRES_PASSWORD: postgres
-        options: >-
-          --health-cmd pg_isready
-          --health-interval 10s
-          --health-timeout 5s
-          --health-retries 5
-        ports:
-          # Maps tcp port 5432 on service container to the host
-          - 5432:5432
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "postgres://postgres:postgres@127.0.0.1:5432/test?sslmode=disable"
-          file_size: "8K"
-          file_count: 2500
-          threads: 10    
-
-
-  upload-big-files-with-pg-read-committed:
-    runs-on: ubuntu-latest
-    services:
-      postgres:
-        image: postgres
-        env:
-          POSTGRES_PASSWORD: postgres
-        options: >-
-          --health-cmd pg_isready
-          --health-interval 10s
-          --health-timeout 5s
-          --health-retries 5
-        ports:
-          # Maps tcp port 5432 on service container to the host
-          - 5432:5432
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "postgres://postgres:postgres@127.0.0.1:5432/test?sslmode=disable"
-          file_size: "100M"
-          file_count: 3
-          threads: 10
-          isolation_level: "read committed"
-
+  gateway:
+    strategy:
+      fail-fast: false
+      matrix:
+        meta: [  'sqlite3', 'redis','tikv', 'badgerdb',  'etcd']
+        file_size: ['100M']
+        isolation_level: ['']
+        include:
+          - meta: 'mariadb'
+            file_size: '100M'
+            isolation_level: "read committed"
+
+          - meta: 'mysql'
+            file_size: '100M'
+            isolation_level: "read committed"
+          - meta: 'mysql'
+            file_size: '100M'
+            isolation_level: "repeatable read"
+          - meta: 'mysql'
+            file_size: '100M'
+            isolation_level: "serializable"
+
+          - meta: 'postgres'
+            file_size: '100M'
+            isolation_level: "read committed"
+          - meta: 'postgres'
+            file_size: '100M'
+            isolation_level: "repeatable read"
+          - meta: 'postgres'
+            file_size: '100M'
+            isolation_level: "serializable"
+
+          - meta: 'tidb'
+            file_size: '100M'
+            isolation_level: "read committed"
+          - meta: 'tidb'
+            file_size: '100M'
+            isolation_level: "repeatable read"
 
-
-  upload-big-files-with-pg-repeatable-read:
     runs-on: ubuntu-latest
-    services:
-      postgres:
-        image: postgres
-        env:
-          POSTGRES_PASSWORD: postgres
-        options: >-
-          --health-cmd pg_isready
-          --health-interval 10s
-          --health-timeout 5s
-          --health-retries 5
-        ports:
-          # Maps tcp port 5432 on service container to the host
-          - 5432:5432
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "postgres://postgres:postgres@127.0.0.1:5432/test?sslmode=disable"
-          file_size: "100M"
-          file_count: 5
-          threads: 10
-          isolation_level: "repeatable read"
 
-
-
-  upload-big-files-with-pg-serializable:
-    runs-on: ubuntu-latest
     services:
       postgres:
         image: postgres
@@ -340,188 +69,14 @@ jobs:
           --health-timeout 5s
           --health-retries 5
         ports:
-          # Maps tcp port 5432 on service container to the host
           - 5432:5432
-    steps:
-      - uses: actions/checkout@v3
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "postgres://postgres:postgres@127.0.0.1:5432/test?sslmode=disable"
-          file_size: "100M"
-          file_count: 5
-          threads: 10
-          isolation_level: "serializable"
-
-
-
-  upload-big-files-with-tidb-read-committed:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Install TiDB
-        run: |
-          curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
-          source /home/runner/.profile
-          tiup playground 5.4.0 &
-          sleep 120
-          mysql -h127.0.0.1 -P4000 -uroot -e "set global tidb_enable_noop_functions=1;"
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:@\\(127.0.0.1:4000\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "read committed"
-
-  upload-big-files-with-tidb-repeatable-read:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Install TiDB
-        run: |
-          curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
-          source /home/runner/.profile
-          tiup playground 5.4.0 &
-          sleep 120
-          mysql -h127.0.0.1 -P4000 -uroot -e "set global tidb_enable_noop_functions=1;"
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "mysql://root:@\\(127.0.0.1:4000\\)/test"
-          file_size: "100M"
-          file_count: 5
-          isolation_level: "repeatable read"
-
-
-  upload-small-files-with-etcd:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo apt install etcd
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "etcd://localhost:2379/jfs"
-          file_size: "8K"
-          file_count: 2500    
-
 
-  upload-big-files-with-etcd:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - run: sudo apt install etcd
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "etcd://localhost:2379/jfs"
-          file_size: "200M"
-          file_count: 5    
-
-
-  # upload-big-file-with-oceanbase-read-committed:
-  #   runs-on: [self-hosted, daily-build, bench-02]
-  #   steps:
-  #     - uses: actions/checkout@v3
-  #     - name: install ob
-  #       run: |
-  #         docker rm obstandalone --force || echo "remove obstandalone failed"
-  #         docker run -p 2881:2881 --name obstandalone -e MINI_MODE=1 -d oceanbase/oceanbase-ce
-  #         sleep 60
-  #         mysql -h127.0.0.1 -P2881 -uroot -e "ALTER SYSTEM SET _ob_enable_prepared_statement=TRUE;" 
-  #     - name: Test
-  #       uses: ./.github/actions/gateway
-  #       with:
-  #         meta_url: "mysql://root:@\\(127.0.0.1:2881\\)/test"
-  #         file_size: "200M"
-  #         file_count: 5
-  #         isolation_level: "read committed"   
-
-  # upload-big-file-with-oceanbase-repeatable-read:
-  #   runs-on: [self-hosted, daily-build, bench-03]
-  #   steps:
-  #     - uses: actions/checkout@v3
-  #     - name: install ob
-  #       run: |
-  #         docker rm obstandalone --force || echo "remove obstandalone failed"
-  #         docker run -p 2881:2881 --name obstandalone -e MINI_MODE=1 -d oceanbase/oceanbase-ce
-  #         sleep 60
-  #         mysql -h127.0.0.1 -P2881 -uroot -e "ALTER SYSTEM SET _ob_enable_prepared_statement=TRUE;" 
-  #     - name: Test
-  #       uses: ./.github/actions/gateway
-  #       with:
-  #         meta_url: "mysql://root:@\\(localhost:2881\\)/test"
-  #         file_size: "200M"
-  #         file_count: 5
-  #         isolation_level: "repeatable read"   
-
-  # upload-big-file-with-oceanbase-serializable:
-  #   runs-on: [self-hosted, daily-build, bench-03]
-  #   steps:
-  #     - uses: actions/checkout@v3
-  #     - name: install ob
-  #       run: |
-  #         docker rm obstandalone --force || echo "remove obstandalone failed"
-  #         docker run -p 2881:2881 --name obstandalone -e MINI_MODE=1 -d oceanbase/oceanbase-ce
-  #         sleep 60
-  #         mysql -h127.0.0.1 -P2881 -uroot -e "ALTER SYSTEM SET _ob_enable_prepared_statement=TRUE;" 
-  #     - name: Test
-  #       uses: ./.github/actions/gateway
-  #       with:
-  #         meta_url: "mysql://root:@\\(localhost:2881\\)/test"
-  #         file_size: "200M"
-  #         file_count: 5
-  #         isolation_level: "serializable"    
-
-  upload-small-files-with-tikv:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Install TiKV
-        run: |
-          curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
-          source /home/runner/.bash_profile
-          source /home/runner/.profile
-          tiup playground --mode tikv-slim &
-          sleep 5
-
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "tikv://127.0.0.1:2379"
-          file_size: "8K"
-          file_count: 2500
-
-
-  upload-big-files-with-tikv:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v3
-      - name: Install TiKV
-        run: |
-          curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
-          source /home/runner/.bash_profile
-          source /home/runner/.profile
-          tiup playground --mode tikv-slim &
-          sleep 5
-
-      - name: Test
-        uses: ./.github/actions/gateway
-        with:
-          meta_url: "tikv://127.0.0.1:2379"
-          file_size: "100M"
-          file_count: 5
-
-
-  sync-to-gateway-with-multithread:
-    runs-on: ubuntu-latest
-    steps:
+    steps: 
       - name: Checkout
         uses: actions/checkout@v2
         with:
           fetch-depth: 1
-          
+
       - name: Set up Go
         uses: actions/setup-go@v2
         with:
@@ -535,33 +90,214 @@ jobs:
           key: ${{ runner.os }}-go
           restore-keys: |
             ${{ runner.os }}-go
-            
+
       - name: Build linux target
         run: |
-          make juicefs
+          #if it is self ruuner
+          hostname | grep bench && export GOPATH=/usr/local/go && export HOME=/root
+          make juicefs 
           #wget -q https://github.com/juicedata/juicefs/releases/download/v1.0.0-beta3/juicefs-1.0.0-beta3-linux-amd64.tar.gz
           #tar -xzf juicefs-1.0.0-beta3-linux-amd64.tar.gz
-      - name: Test sync to gateway with multithread
+        shell: bash
+
+      - name: Set meta url
+        id: vars
+        run: | 
+          echo meta is: ${{matrix.meta}}
+          if [ "${{matrix.meta}}" == "postgres" ]; then
+            meta_url="postgres://postgres:postgres@127.0.0.1:5432/sync_test?sslmode=disable" 
+          elif [ "${{matrix.meta}}" == "mysql" ]; then
+            meta_url="mysql://root:root@\\(127.0.0.1\\)/sync_test"
+          elif [ "${{matrix.meta}}" == "redis" ]; then
+            meta_url="redis://127.0.0.1:6379/1"
+          elif [ "${{matrix.meta}}" == "sqlite3" ]; then
+            meta_url="sqlite3://sync-test.db"
+          elif [ "${{matrix.meta}}" == "tikv" ]; then
+            meta_url="tikv://127.0.0.1:2379/load_test"
+          elif [ "${{matrix.meta}}" == "badgerdb" ]; then
+            meta_url="badger://load_test"
+          elif [ "${{matrix.meta}}" == "mariadb" ]; then
+            meta_url="mysql://root:root@\\(127.0.0.1\\)/test"
+          elif [ "${{matrix.meta}}" == "tidb" ]; then
+            meta_url="mysql://root:@\\(127.0.0.1:4000\\)/load_test"
+          elif [ "${{matrix.meta}}" == "etcd" ]; then
+            meta_url="etcd://localhost:2379/jfs"
+          elif [ "${{matrix.meta}}" == "ob" ]; then
+            meta_url="mysql://root:@\\(127.0.0.1:2881\\)/test"
+          else
+            echo "<FATAL>: meta ${{matrix.meta}} is not supported"
+            exit 1
+          fi
+          echo meta_url is: $meta_url
+          echo ::set-output name=meta_url::$meta_url
+
+      - name: Start meta
+        run: | 
+          if [ "${{matrix.meta}}" == "mysql" ]; then
+            sudo /etc/init.d/mysql start
+          elif [ "${{matrix.meta}}" == "redis" ]; then
+            sudo apt-get install -y redis-tools redis-server
+          elif [ "${{matrix.meta}}" == "tikv" ]; then
+            curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
+            source /home/runner/.bash_profile
+            source /home/runner/.profile
+            tiup playground --mode tikv-slim &
+            sleep 5
+          elif [ "${{matrix.meta}}" == "badgerdb" ]; then
+            sudo go get github.com/dgraph-io/badger/v3
+          elif [ "${{matrix.meta}}" == "mariadb" ]; then
+            docker run -p 127.0.0.1:3306:3306  --name mdb -e MARIADB_ROOT_PASSWORD=root -d mariadb:latest
+            sleep 10
+          elif [ "${{matrix.meta}}" == "tidb" ]; then
+            curl --proto '=https' --tlsv1.2 -sSf https://tiup-mirrors.pingcap.com/install.sh | sh
+            source /home/runner/.profile
+            tiup playground 5.4.0 &
+            sleep 120
+            mysql -h127.0.0.1 -P4000 -uroot -e "set global tidb_enable_noop_functions=1;"
+          elif [ "${{matrix.meta}}" == "etcd" ]; then
+            sudo apt install etcd
+          elif [ "${{matrix.meta}}" == "ob" ]; then
+            docker rm obstandalone --force || echo "remove obstandalone failed"
+            docker run -p 2881:2881 --name obstandalone -e MINI_MODE=1 -d oceanbase/oceanbase-ce
+            sleep 60
+            mysql -h127.0.0.1 -P2881 -uroot -e "ALTER SYSTEM SET _ob_enable_prepared_statement=TRUE;" 
+          fi
+
+      - name: Install tools
         run: | 
-          #test for PR: https://github.com/juicedata/juicefs/pull/2024
           wget -q https://dl.minio.io/client/mc/release/linux-amd64/mc
           chmod +x mc 
-          sudo apt install md5deep
-          sudo /etc/init.d/mysql start
-          meta_url="mysql://root:root@(127.0.0.1)/test"
-          volume=myjfs
-          mp=/tmp/myjfs
-          db_name=$(basename $meta_url)
-          mysql -uroot -proot -e "set global transaction isolation level repeatable read;" 
-          mysql -uroot -proot -e "drop database if exists $db_name; create database $db_name;" 
+        shell: bash
+        
+      - name: create database
+        shell: bash
+        run: | 
+          meta_url=${{ steps.vars.outputs.meta_url }}
+          isolation_level="${{matrix.isolation_level}}"
+          db_name=$(basename $meta_url | awk -F? '{print $1}')
+          if [[ "$meta_url" == mysql* ]]; then
+            user=$(echo $meta_url |  awk -F/ '{print $3}' | awk -F@ '{print $1}' | awk -F: '{print $1}')
+            password=$(echo $meta_url |  awk -F/ '{print $3}' | awk -F@ '{print $1}' | awk -F: '{print $2}')
+            test -n "$password" && password="-p$password" || password=""
+            host=$(basename $(dirname $meta_url) | awk -F@ '{print $2}'| sed 's/(//g' | sed 's/)//g' | awk -F: '{print $1}')
+            port=$(basename $(dirname $meta_url) | awk -F@ '{print $2}'| sed 's/(//g' | sed 's/)//g' | awk -F: '{print $2}')
+            test -z "$port" && port="3306"
+            echo user=$user, password=$password, host=$host, port=$port, db_name=$db_name, isolation_level=$isolation_level
+            mysql -u$user $password -h $host -P $port -e "set global transaction isolation level $isolation_level;" 
+            mysql -u$user $password -h $host -P $port -e "show variables like '%isolation%;'" 
+            mysql -u$user $password -h $host -P $port -e "drop database if exists $db_name; create database $db_name;" 
+          elif [[ "$meta_url" == postgres* ]]; then
+            export PGPASSWORD="postgres"
+            printf "\set AUTOCOMMIT on\ndrop database if exists $db_name; create database $db_name; " |  psql -U postgres -h localhost
+            printf "\set AUTOCOMMIT on\nALTER DATABASE $db_name SET DEFAULT_TRANSACTION_ISOLATION TO '$isolation_level';" |  psql -U postgres -h localhost
+          fi      
+
+      - name: start gateway
+        shell: bash
+        run: |
+          meta_url=${{ steps.vars.outputs.meta_url }}
+          mp="/tmp/myjfs"
+          volume="myjfs"
           export MINIO_ROOT_USER=minioadmin
           export MINIO_ROOT_PASSWORD=minioadmin
-          ./juicefs format $meta_url $volume
-          ./juicefs gateway $meta_url localhost:9000 &
+          ./juicefs format $meta_url $volume --trash-days 0
+          if [[ "$meta_url" == badger* ]]; then
+            ./juicefs gateway $meta_url localhost:8080 --no-usage-report /tmp/access1.log &
+          else
+            ./juicefs gateway $meta_url localhost:8080 --access-log /tmp/access1.log &
+            #./juicefs gateway $meta_url localhost:9000 --access-log /tmp/access1.log &
+            #./juicefs gateway $meta_url localhost:9001 --access-log /tmp/access2.log &
+            #sudo cp .github/workflows/resources/load-balancer.conf /etc/nginx/conf.d/load-balancer.conf
+            #sudo rm /etc/nginx/sites-enabled/default
+            #sudo systemctl restart nginx
+          fi
+        
+      - name: Sync with multiple process
+        shell: bash
+        run: |
+          meta_url=${{ steps.vars.outputs.meta_url }}
+          file_size=${{matrix.file_size}}
+          if [ $file_size="100M" ]; then 
+            file_count=5
+          else
+            file_count=2000
+          fi
+          threads=20
+          mp=/tmp/myjfs
+          volume=myjfs
+          
+          dd if=/dev/urandom of=file iflag=fullblock,count_bytes bs=4k count="$file_size" > /dev/null
+          mkdir data
+          for i in $(seq 1 $file_count); do
+            cp file data/file$i
+          done
           start=`date +%s`
-          ./juicefs sync --dirs ./  s3://minioadmin:minioadmin@localhost:9000/$volume/source_dir/ --no-https -p 50
+          declare -a pids   
+          ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
+          pids+=($!)
+          ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
+          pids+=($!)
+          ./juicefs sync --dirs data/  s3://minioadmin:minioadmin@localhost:8080/$volume/data/ --no-https -p $threads &
+          pids+=($!)
+          wait "${pids[@]}"
+          rm -rf $HOME/.juicefs/cache/ || true
+          # ./mc alias set minio http://localhost:9000 minioadmin minioadmin --api S3v4
+          # ./mc mb minio/$volume
+          # ./mc cp --recursive data/  minio/$volume/data
           end=`date +%s`
           time=$((end-start))
-          echo time is: $time
+          echo time cost is: $time second
+          killall juicefs 
+          sleep 3
           ./juicefs mount -d $meta_url $mp
-          rm -rf $mp/source_dir
+          diff -ur data/ $mp/data/ 
+          echo "diff succeed"
+          ./juicefs umount  $mp --force
+        
+      - name: Sync with empty dir
+        run: |
+          meta_url=${{ steps.vars.outputs.meta_url }}
+          threads=20
+          mp=/tmp/myjfs
+          volume=myjfs
+          export MINIO_ROOT_USER=minioadmin
+          export MINIO_ROOT_PASSWORD=minioadmin
+          ./juicefs mdtest $meta_url test --dirs 10 --depth 2 --files 10 --threads 10 --no-usage-report
+          ./juicefs gateway $meta_url localhost:8080 --access-log /tmp/access1.log &
+          sleep 10
+          mkdir emptydir
+          declare -a pids  
+          ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
+          pids+=($!)
+          ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
+          pids+=($!)
+          ./juicefs sync emptydir/ s3://minioadmin:minioadmin@localhost:8080/$volume/test/ --delete-dst --no-https -p $threads &
+          pids+=($!)
+          wait "${pids[@]}"
+          killall juicefs
+          sleep 3
+          ./juicefs mount -d $meta_url $mp
+          [ -d "$mp/test/" ] && exit 1 
+          ./juicefs umount  $mp --force
+        shell: bash
+
+      - name: log
+        if: ${{ always() }}
+        shell: bash
+        run: | 
+          if [ -f ~/.juicefs/juicefs.log ]; then
+            tail -300 ~/.juicefs/juicefs.log
+            grep "<FATAL>:" ~/.juicefs/juicefs.log && exit 1 || true
+          fi
+
+      - name: Send Slack Notification
+        if: ${{ failure() }}
+        uses: juicedata/slack-notify-action@main
+        with:
+          channel-id: "${{ secrets.SLACK_CHANNEL_ID_FOR_PR_CHECK_NOTIFY }}"
+          slack_bot_token: "${{ secrets.SLACK_BOT_TOKEN }}"  
+
+      - name: Setup upterm session
+        if: ${{ failure() }}
+        timeout-minutes: 1
+        uses: lhotari/action-upterm@v1
\ No newline at end of file
diff --git a/cmd/fsck.go b/cmd/fsck.go
index 64e32289..4a474879 100644
--- a/cmd/fsck.go
+++ b/cmd/fsck.go
@@ -46,7 +46,10 @@ Examples:
 $ juicefs fsck redis://localhost
 
 # Repair broken directories
-$ juicefs fsck redis://localhost --path /d1/d2 --repair`,
+$ juicefs fsck redis://localhost --path /d1/d2 --repair
+
+# recursively check
+$ juicefs fsck redis://localhost --path /d1/d2 --recursive`,
 		Flags: []cli.Flag{
 			&cli.StringFlag{
 				Name:  "path",
@@ -56,6 +59,11 @@ $ juicefs fsck redis://localhost --path /d1/d2 --repair`,
 				Name:  "repair",
 				Usage: "repair specified path if it's broken",
 			},
+			&cli.BoolFlag{
+				Name:    "recursive",
+				Aliases: []string{"r"},
+				Usage:   "recursively check or repair",
+			},
 		},
 	}
 }
@@ -76,7 +84,7 @@ func fsck(ctx *cli.Context) error {
 		if !strings.HasPrefix(p, "/") {
 			logger.Fatalf("File path should be the absolute path within JuiceFS")
 		}
-		return m.Check(c, p, ctx.Bool("repair"))
+		return m.Check(c, p, ctx.Bool("repair"), ctx.Bool("recursive"))
 	}
 
 	chunkConf := chunk.Config{
diff --git a/pkg/meta/base.go b/pkg/meta/base.go
index 5e22b68e..64c5fc10 100644
--- a/pkg/meta/base.go
+++ b/pkg/meta/base.go
@@ -20,6 +20,7 @@ import (
 	"encoding/json"
 	"fmt"
 	"path"
+	"path/filepath"
 	"runtime"
 	"sort"
 	"strings"
@@ -1045,49 +1046,137 @@ func (m *baseMeta) GetPaths(ctx Context, inode Ino) []string {
 	return paths
 }
 
-func (m *baseMeta) Check(ctx Context, fpath string, repair bool) (st syscall.Errno) {
+func (m *baseMeta) countDirNlink(ctx Context, inode Ino) (uint32, syscall.Errno) {
+	var entries []*Entry
+	if st := m.en.doReaddir(ctx, inode, 0, &entries, -1); st != 0 {
+		logger.Errorf("readdir inode %d: %s", inode, st)
+		return 0, st
+	}
+	var dirCounter uint32 = 2
+	for _, e := range entries {
+		if e.Attr.Typ == TypeDirectory {
+			dirCounter++
+		}
+	}
+	return dirCounter, 0
+}
+
+type metaWalkFunc func(ctx Context, inode Ino, path string, attr *Attr)
+
+func (m *baseMeta) walk(ctx Context, inode Ino, path string, attr *Attr, walkFn metaWalkFunc) syscall.Errno {
+	walkFn(ctx, inode, path, attr)
+	var entries []*Entry
+	st := m.en.doReaddir(ctx, inode, 1, &entries, -1)
+	if st != 0 {
+		logger.Errorf("list %s: %s", path, st)
+		return st
+	}
+	for _, entry := range entries {
+		if !entry.Attr.Full {
+			entry.Attr.Parent = inode
+		}
+		if st := m.walk(ctx, entry.Inode, filepath.Join(path, string(entry.Name)), entry.Attr, walkFn); st != 0 {
+			return st
+		}
+	}
+	return 0
+}
+
+func (m *baseMeta) Check(ctx Context, fpath string, repair bool, recursive bool) (st syscall.Errno) {
 	var attr Attr
-	var inode Ino
-	var parent Ino = 1
-	ps := strings.Split(fpath, "/")
+	var inode = RootInode
+	var parent = RootInode
+	attr.Typ = TypeDirectory
+	ps := strings.FieldsFunc(fpath, func(r rune) bool {
+		return r == '/'
+	})
 	for i, name := range ps {
-		if len(name) == 0 {
-			continue
-		}
+		parent = inode
 		if st = m.Lookup(ctx, parent, name, &inode, &attr); st != 0 {
 			logger.Errorf("Lookup parent %d name %s: %s", parent, name, st)
 			return
 		}
-		if attr.Full {
-			parent = inode
-			continue
-		}
-
-		// missing attribute
-		p := "/" + path.Join(ps[:i+1]...)
-		if attr.Typ != TypeDirectory { // TODO: determine file size?
-			logger.Errorf("Path %s (inode %d type %d) cannot be auto-repaired, you have to repair it manually or remove it", p, inode, attr.Typ)
-		} else if !repair {
-			logger.Warnf("Path %s (inode %d) can be repaired, please re-check with 'repair' enabled", p, inode)
-		} else { // repair directory inode
-			now := time.Now().Unix()
-			attr.Mode = 0644
-			attr.Uid = ctx.Uid()
-			attr.Gid = ctx.Gid()
-			attr.Atime = now
-			attr.Mtime = now
-			attr.Ctime = now
-			attr.Length = 4 << 10
-			attr.Parent = parent
-			if st = m.en.doRepair(ctx, inode, &attr); st == 0 {
-				logger.Infof("Path %s (inode %d) is successfully repaired", p, inode)
+		if !attr.Full && i < len(ps)-1 {
+			// missing attribute
+			p := "/" + path.Join(ps[:i+1]...)
+			if attr.Typ != TypeDirectory { // TODO: determine file size?
+				logger.Warnf("Attribute of %s (inode %d type %d) is missing and cannot be auto-repaired, please repair it manually or remove it", p, inode, attr.Typ)
 			} else {
-				logger.Errorf("Repair path %s inode %d: %s", p, inode, st)
+				logger.Warnf("Attribute of %s (inode %d) is missing, please re-run with '--path %s --repair' to fix it", p, inode, p)
 			}
 		}
-		return // handle one missing inode at a time
 	}
-	logger.Infof("Path %s inode %d is valid", fpath, parent)
+	if !attr.Full {
+		attr.Parent = parent
+	}
+
+	type node struct {
+		inode Ino
+		path  string
+		attr  *Attr
+	}
+	nodes := make(chan *node, 1000)
+	go func() {
+		defer close(nodes)
+		if recursive {
+			st = m.walk(ctx, inode, fpath, &attr, func(ctx Context, inode Ino, path string, attr *Attr) {
+				nodes <- &node{inode, path, attr}
+			})
+		} else {
+			nodes <- &node{inode, fpath, &attr}
+		}
+	}()
+
+	var wg sync.WaitGroup
+	for i := 0; i < 20; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for e := range nodes {
+				inode := e.inode
+				path := e.path
+				attr := e.attr
+				if attr.Typ != TypeDirectory {
+					// TODO
+					continue
+				}
+				if attr.Full {
+					nlink, st := m.countDirNlink(ctx, inode)
+					if st != 0 {
+						logger.Errorf("Count nlink for inode %d: %s", inode, st)
+						continue
+					}
+					if attr.Nlink == nlink {
+						continue
+					}
+					logger.Warnf("nlink of %s should be %d, but got %d", path, nlink, attr.Nlink)
+				} else {
+					logger.Warnf("attribute of %s is missing", path)
+				}
+
+				if repair {
+					if !attr.Full {
+						now := time.Now().Unix()
+						attr.Mode = 0644
+						attr.Uid = ctx.Uid()
+						attr.Gid = ctx.Gid()
+						attr.Atime = now
+						attr.Mtime = now
+						attr.Ctime = now
+						attr.Length = 4 << 10
+					}
+					if st1 := m.en.doRepair(ctx, inode, attr); st1 == 0 {
+						logger.Infof("Path %s (inode %d) is successfully repaired", path, inode)
+					} else {
+						logger.Errorf("Repair path %s inode %d: %s", path, inode, st1)
+					}
+				} else {
+					logger.Warnf("Path %s (inode %d) can be repaired, please re-run with '--path %s --repair' to fix it", path, inode, path)
+				}
+			}
+		}()
+	}
+	wg.Wait()
 	return
 }
 
diff --git a/pkg/meta/interface.go b/pkg/meta/interface.go
index c077179f..b3cd3d57 100644
--- a/pkg/meta/interface.go
+++ b/pkg/meta/interface.go
@@ -351,7 +351,7 @@ type Meta interface {
 	// GetPaths returns all paths of an inode
 	GetPaths(ctx Context, inode Ino) []string
 	// Check integrity of an absolute path and repair it if asked
-	Check(ctx Context, fpath string, repair bool) syscall.Errno
+	Check(ctx Context, fpath string, repair bool, recursive bool) syscall.Errno
 
 	// OnMsg add a callback for the given message type.
 	OnMsg(mtype uint32, cb MsgCallback)
diff --git a/pkg/meta/redis.go b/pkg/meta/redis.go
index 6eb1c1d5..b1be8fbd 100644
--- a/pkg/meta/redis.go
+++ b/pkg/meta/redis.go
@@ -1777,7 +1777,7 @@ func (m *redisMeta) doReaddir(ctx Context, inode Ino, plus uint8, entries *[]*En
 		return errno(err)
 	}
 
-	if plus != 0 {
+	if plus != 0 && len(*entries) != 0 {
 		fillAttr := func(es []*Entry) error {
 			var keys = make([]string, len(es))
 			for i, e := range es {
diff --git a/pkg/meta/sql.go b/pkg/meta/sql.go
index 3ce82b48..7157ae8f 100644
--- a/pkg/meta/sql.go
+++ b/pkg/meta/sql.go
@@ -2622,8 +2622,9 @@ func (m *dbMeta) doRepair(ctx Context, inode Ino, attr *Attr) syscall.Errno {
 		Atime:  attr.Atime * 1e6,
 		Mtime:  attr.Mtime * 1e6,
 		Ctime:  attr.Ctime * 1e6,
-		Length: 4 << 10,
+		Length: attr.Length,
 		Parent: attr.Parent,
+		Nlink:  attr.Nlink,
 	}
 	return errno(m.txn(func(s *xorm.Session) error {
 		n.Nlink = 2
@@ -2636,7 +2637,15 @@ func (m *dbMeta) doRepair(ctx Context, inode Ino, attr *Attr) syscall.Errno {
 				n.Nlink++
 			}
 		}
-		return mustInsert(s, n)
+		ok, err := s.ForUpdate().Get(&node{Inode: inode})
+		if err == nil {
+			if ok {
+				_, err = s.Update(n, &node{Inode: inode})
+			} else {
+				err = mustInsert(s, n)
+			}
+		}
+		return err
 	}, inode))
 }
 
diff --git a/pkg/meta/tkv.go b/pkg/meta/tkv.go
index d5f9dfe3..e9ebac8f 100644
--- a/pkg/meta/tkv.go
+++ b/pkg/meta/tkv.go
@@ -1592,7 +1592,7 @@ func (m *kvMeta) doReaddir(ctx Context, inode Ino, plus uint8, entries *[]*Entry
 		})
 	}
 
-	if plus != 0 {
+	if plus != 0 && len(*entries) != 0 {
 		fillAttr := func(es []*Entry) error {
 			var keys = make([][]byte, len(es))
 			for i, e := range es {
@@ -2224,7 +2224,7 @@ func (m *kvMeta) ListSlices(ctx Context, slices map[Ino][]Slice, delete bool, sh
 func (m *kvMeta) doRepair(ctx Context, inode Ino, attr *Attr) syscall.Errno {
 	return errno(m.txn(func(tx kvTxn) error {
 		attr.Nlink = 2
-		_ = tx.scanValues(m.entryKey(inode, ""), 0, func(k, v []byte) bool {
+		_ = tx.scanValues(m.entryKey(inode, ""), -1, func(k, v []byte) bool {
 			typ, _ := m.parseEntry(v)
 			if typ == TypeDirectory {
 				attr.Nlink++


Test patch:
diff --git a/pkg/meta/base_test.go b/pkg/meta/base_test.go
index 557eaee9..af0b451b 100644
--- a/pkg/meta/base_test.go
+++ b/pkg/meta/base_test.go
@@ -30,7 +30,9 @@ import (
 	"testing"
 	"time"
 
+	"github.com/go-redis/redis/v8"
 	"github.com/juicedata/juicefs/pkg/utils"
+	"xorm.io/xorm"
 )
 
 func TestRedisClient(t *testing.T) {
@@ -76,6 +78,7 @@ func testMeta(t *testing.T, m Meta) {
 	testOpenCache(t, m)
 	base.conf.CaseInsensi = true
 	testCaseIncensi(t, m)
+	testCheckAndRepair(t, m)
 	base.conf.ReadOnly = true
 	testReadOnly(t, m)
 }
@@ -1584,3 +1587,145 @@ func testAttrFlags(t *testing.T, m Meta) {
 		t.Fatalf("copy_file_range f: %s", st)
 	}
 }
+
+func setAttr(t *testing.T, m Meta, inode Ino, attr *Attr) {
+	var err error
+	switch m := m.(type) {
+	case *redisMeta:
+		err = m.txn(Background, func(tx *redis.Tx) error {
+			return tx.Set(Background, m.inodeKey(inode), m.marshal(attr), 0).Err()
+		}, m.inodeKey(inode))
+	case *dbMeta:
+		err = m.txn(func(s *xorm.Session) error {
+			_, err = s.ID(inode).AllCols().Update(&node{
+				Inode:  inode,
+				Type:   attr.Typ,
+				Flags:  attr.Flags,
+				Mode:   attr.Mode,
+				Uid:    attr.Uid,
+				Gid:    attr.Gid,
+				Mtime:  attr.Mtime * 1e6,
+				Ctime:  attr.Ctime * 1e6,
+				Atime:  attr.Atime * 1e6,
+				Nlink:  attr.Nlink,
+				Length: attr.Length,
+				Rdev:   attr.Rdev,
+				Parent: attr.Parent,
+			})
+			return err
+		})
+	case *kvMeta:
+		err = m.txn(func(tx kvTxn) error {
+			tx.set(m.inodeKey(inode), m.marshal(attr))
+			return nil
+		})
+	}
+	if err != nil {
+		t.Fatalf("setAttr: %v", err)
+	}
+}
+
+func testCheckAndRepair(t *testing.T, m Meta) {
+	var checkInode, d1Inode, d2Inode, d3Inode, d4Inode Ino
+	dirAttr := &Attr{Mode: 0644, Full: true, Typ: TypeDirectory, Nlink: 3}
+	if st := m.Mkdir(Background, RootInode, "check", 0640, 022, 0, &checkInode, dirAttr); st != 0 {
+		t.Fatalf("mkdir: %s", st)
+	}
+	if st := m.Mkdir(Background, checkInode, "d1", 0640, 022, 0, &d1Inode, dirAttr); st != 0 {
+		t.Fatalf("mkdir: %s", st)
+	}
+	if st := m.Mkdir(Background, d1Inode, "d2", 0640, 022, 0, &d2Inode, dirAttr); st != 0 {
+		t.Fatalf("mkdir: %s", st)
+	}
+	if st := m.Mkdir(Background, d2Inode, "d3", 0640, 022, 0, &d3Inode, dirAttr); st != 0 {
+		t.Fatalf("mkdir: %s", st)
+	}
+	if st := m.Mkdir(Background, d3Inode, "d4", 0640, 022, 0, &d4Inode, dirAttr); st != 0 {
+		t.Fatalf("mkdir: %s", st)
+	}
+
+	if st := m.GetAttr(Background, checkInode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	dirAttr.Nlink = 0
+	setAttr(t, m, checkInode, dirAttr)
+
+	if st := m.GetAttr(Background, d1Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	dirAttr.Nlink = 0
+	setAttr(t, m, d1Inode, dirAttr)
+
+	if st := m.GetAttr(Background, d2Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	dirAttr.Nlink = 0
+	setAttr(t, m, d2Inode, dirAttr)
+
+	if st := m.GetAttr(Background, d3Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	dirAttr.Nlink = 0
+	setAttr(t, m, d3Inode, dirAttr)
+
+	if st := m.GetAttr(Background, d4Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	dirAttr.Full = false
+	dirAttr.Nlink = 0
+	setAttr(t, m, d4Inode, dirAttr)
+
+	if st := m.Check(Background, "/check", false, false); st != 0 {
+		t.Fatalf("check: %s", st)
+	}
+	if st := m.GetAttr(Background, checkInode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	if dirAttr.Nlink != 0 {
+		t.Fatalf("checkInode nlink should is 0 now: %d", dirAttr.Nlink)
+	}
+
+	if st := m.Check(Background, "/check", true, false); st != 0 {
+		t.Fatalf("check: %s", st)
+	}
+	if st := m.GetAttr(Background, checkInode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	if dirAttr.Nlink != 3 || dirAttr.Parent != RootInode {
+		t.Fatalf("checkInode nlink should is 3 now: %d", dirAttr.Nlink)
+	}
+
+	if st := m.Check(Background, "/check/d1/d2", true, false); st != 0 {
+		t.Fatalf("check: %s", st)
+	}
+	if st := m.GetAttr(Background, d2Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	if dirAttr.Nlink != 3 || dirAttr.Parent != d1Inode {
+		t.Fatalf("d2Inode nlink should is 3 now: %d", dirAttr.Nlink)
+	}
+	if st := m.GetAttr(Background, d1Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	if dirAttr.Nlink != 0 || dirAttr.Parent != checkInode {
+		t.Fatalf("d1Inode nlink should is 0 now: %d", dirAttr.Nlink)
+	}
+
+	if st := m.Check(Background, "/", true, true); st != 0 {
+		t.Fatalf("check: %s", st)
+	}
+	for _, ino := range []Ino{checkInode, d1Inode, d2Inode, d3Inode} {
+		if st := m.GetAttr(Background, ino, dirAttr); st != 0 {
+			t.Fatalf("getattr: %s", st)
+		}
+		if !dirAttr.Full || dirAttr.Nlink != 3 {
+			t.Fatalf("nlink should is 3 now: %d", dirAttr.Nlink)
+		}
+	}
+	if st := m.GetAttr(Background, d4Inode, dirAttr); st != 0 {
+		t.Fatalf("getattr: %s", st)
+	}
+	if !dirAttr.Full || dirAttr.Nlink != 2 || dirAttr.Parent != d3Inode {
+		t.Fatalf("d4Inode attr: %+v", *dirAttr)
+	}
+}