Allow removal of bad direntries in VitastorFS (direntries referring non-existent inodes)

This commit is contained in:
Vitaliy Filippov
2025-05-01 01:14:23 +03:00
parent ef80f121f6
commit 96b5a72630
4 changed files with 66 additions and 8 deletions
+7 -1
View File
@@ -13,6 +13,12 @@ void kv_read_inode(nfs_proxy_t *proxy, uint64_t ino,
std::function<void(int res, const std::string & value, json11::Json ientry)> cb,
bool allow_cache)
{
if (!ino)
{
// Zero value can not exist
cb(-ENOENT, "", json11::Json());
return;
}
auto key = kv_inode_key(ino);
proxy->db->get(key, [=](int res, const std::string & value)
{
@@ -49,7 +55,7 @@ int kv_nfs3_getattr_proc(void *opaque, rpc_op_t *rop)
auto ino = kv_fh_inode(fh);
if (self->parent->trace)
fprintf(stderr, "[%d] GETATTR %ju\n", self->nfs_fd, ino);
if (!kv_fh_valid(fh))
if (!kv_fh_valid(fh) || !ino)
{
*reply = (GETATTR3res){ .status = NFS3ERR_INVAL };
rpc_queue_reply(rop);
+23 -2
View File
@@ -43,9 +43,30 @@ int kv_nfs3_lookup_proc(void *opaque, rpc_op_t *rop)
uint64_t ino = direntry["ino"].uint64_value();
kv_read_inode(self->parent, ino, [=](int res, const std::string & value, json11::Json ientry)
{
if (res < 0)
if (res == -ENOENT)
{
*reply = (LOOKUP3res){ .status = vitastor_nfs_map_err(res == -ENOENT ? -EIO : res) };
*reply = (LOOKUP3res){
.status = NFS3_OK,
.resok = (LOOKUP3resok){
.object = xdr_copy_string(rop->xdrs, kv_fh(ino)),
.obj_attributes = {
.attributes_follow = 1,
.attributes = (fattr3){
.type = (ftype3)0,
.mode = 0666,
.nlink = 1,
.fsid = self->parent->fsid,
.fileid = ino,
},
},
},
};
rpc_queue_reply(rop);
return;
}
else if (res < 0)
{
*reply = (LOOKUP3res){ .status = vitastor_nfs_map_err(res) };
rpc_queue_reply(rop);
return;
}
+16 -5
View File
@@ -89,12 +89,23 @@ resume_1:
resume_2:
if (st->res < 0)
{
fprintf(stderr, "error reading inode %s: %s (code %d)\n",
kv_inode_key(st->ino).c_str(), strerror(-st->res), st->res);
auto cb = std::move(st->cb);
cb(st->res);
return;
if (st->res == -ENOENT)
{
// Just delete direntry and skip inode
fprintf(stderr, "direntry %s references a non-existing inode %ju, deleting\n",
kv_direntry_key(st->dir_ino, st->filename).c_str(), st->ino);
st->ino = 0;
}
else
{
fprintf(stderr, "error reading inode %s: %s (code %d)\n",
kv_inode_key(st->ino).c_str(), strerror(-st->res), st->res);
auto cb = std::move(st->cb);
cb(st->res);
return;
}
}
else
{
std::string err;
st->ientry = json11::Json::parse(st->ientry_text, err);
+20
View File
@@ -165,4 +165,24 @@ if ls ./testdata/nfs | grep over1; then false; fi
[[ "`cat ./testdata/nfs/linked1`" = "BABABA" ]]
format_green "rename over existing file ok"
# check listing and removal of a bad direntry
sudo umount ./testdata/nfs/
build/src/kv/vitastor-kv --etcd_address $ETCD_URL fsmeta set d11/settings.jsonLGNmGn '{"ino": 123}'
sudo mount localhost:/ ./testdata/nfs -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp
ls -l ./testdata/nfs
ls -l ./testdata/nfs/settings.jsonLGNmGn
rm ./testdata/nfs/settings.jsonLGNmGn
build/src/kv/vitastor-kv --etcd_address $ETCD_URL fsmeta get d11/settings.jsonLGNmGn 2>&1 | grep '(code -2)'
ls -l ./testdata/nfs
# repeat with ino=0
sudo umount ./testdata/nfs/
build/src/kv/vitastor-kv --etcd_address $ETCD_URL fsmeta set d11/settings.jsonLGNmGn '{"ino": 0}'
sudo mount localhost:/ ./testdata/nfs -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp
ls -l ./testdata/nfs
ls -l ./testdata/nfs/settings.jsonLGNmGn
rm ./testdata/nfs/settings.jsonLGNmGn
build/src/kv/vitastor-kv --etcd_address $ETCD_URL fsmeta get d11/settings.jsonLGNmGn 2>&1 | grep '(code -2)'
ls -l ./testdata/nfs
format_green OK