Commit 7c7951ed authored by Ramon Nou's avatar Ramon Nou
Browse files

fix(symlinks,rename,replication): fix external symlink encoding, cyclic...

fix(symlinks,rename,replication): fix external symlink encoding, cyclic rename, and degraded read failover

- Tag cross-mount external symlinks with '/__gkfs_ext__' so internal symlinks preserve relative paths to mountdir and readlink returns proper paths.
- Enforce max symlink depth with ELOOP in get_metadata and gkfs_open_impl.
- Fix cyclic rename handling in gkfs_rename to restore stubs and clean up source files.
- Guard forward_rename against creating nodes with empty paths when clearing stubs.
- Allow inline data writes at offset 0 during cyclic rename restore.
- Trigger replica retry on degraded chunk reads when a server reports 0 bytes for non-empty chunk request.
- Ensure all code passes check_format.sh.
parent f013bd35
Loading
Loading
Loading
Loading
Loading
+17 −0
Changes for include/client/preload_util.hpp: 17 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -162,6 +162,23 @@ lookup_proxy_addr();
void
reload_client_topology();

constexpr const char* kExternalSymlinkPrefix = "/__gkfs_ext__";

inline bool
is_external_symlink(const std::string& target) {
    static const std::string prefix = "/__gkfs_ext__";
    return target.rfind(prefix, 0) == 0;
}

inline std::string
strip_external_symlink_prefix(const std::string& target) {
    static const std::string prefix = "/__gkfs_ext__";
    if(target.rfind(prefix, 0) == 0) {
        return target.substr(prefix.size());
    }
    return target;
}

} // namespace gkfs::utils


+9 −2
Changes for src/client/gkfs_libc.cpp: 9 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@
#include <client/open_file_map.hpp>
#include <client/preload.hpp>
#include <client/preload_context.hpp>
#include <client/preload_util.hpp>
#include <client/user_functions.hpp>

// Forward declaration removed
@@ -2290,7 +2291,10 @@ symlink(const char* path1, const char* path2) throw() {
                      PathStatus::Internal) {
                return gkfs::syscall::gkfs_mk_symlink(resolved2, resolved);
            } else {
                return gkfs::syscall::gkfs_mk_symlink(resolved2, path1);
                std::string ext_target =
                        std::string(gkfs::utils::kExternalSymlinkPrefix) +
                        path1;
                return gkfs::syscall::gkfs_mk_symlink(resolved2, ext_target);
            }
        }
    }
@@ -2326,7 +2330,10 @@ symlinkat(const char* path1, int newdirfd, const char* path2) throw() {
                      PathStatus::Internal) {
                return gkfs::syscall::gkfs_mk_symlink(resolved2, resolved);
            } else {
                return gkfs::syscall::gkfs_mk_symlink(resolved2, path1);
                std::string ext_target =
                        std::string(gkfs::utils::kExternalSymlinkPrefix) +
                        path1;
                return gkfs::syscall::gkfs_mk_symlink(resolved2, ext_target);
            }
        }
    }
+23 −10
Changes for src/client/gkfs_metadata.cpp: 23 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -323,13 +323,14 @@ gkfs_open_impl(const std::string& path, mode_t mode, int flags,
            errno = ELOOP;
            return -1;
        }
        std::string rel_target;
        if(!CTX->relativize_path(md.target_path().c_str(), rel_target)) {
        if(gkfs::utils::is_external_symlink(md.target_path())) {
            // External target (e.g. /usr/bin/python3): open on host filesystem
            return ::syscall(SYS_openat, AT_FDCWD, md.target_path().c_str(),
                             flags, mode);
            auto ext_target = gkfs::utils::strip_external_symlink_prefix(
                    md.target_path());
            return ::syscall(SYS_openat, AT_FDCWD, ext_target.c_str(), flags,
                             mode);
        }
        return gkfs_open_impl(rel_target, mode, flags, symlink_depth + 1);
        return gkfs_open_impl(md.target_path(), mode, flags, symlink_depth + 1);
    }
    if(gkfs::config::metadata::rename_support) {
        if(md.blocks() == -1) {
@@ -623,7 +624,8 @@ gkfs_rename(const string& old_path, const string& new_path) {
    if(md_new) {
        // the new file exists... check for circular...
        if(md_new.value().blocks() == -1 &&
           md_old.value().target_path() == new_path) {
           (md_old.value().target_path() == new_path ||
            md_new.value().target_path() == old_path)) {
            // the new file is a renamed file, so we need to get the
            // metadata of the original file.
            LOG(DEBUG, "Destroying Circular Rename '{}' --> '{}'", old_path,
@@ -637,6 +639,17 @@ gkfs_rename(const string& old_path, const string& new_path) {
                errno = err;
                return -1;
            }
            if(gkfs::config::metadata::use_inline_data &&
               !md_old.value().inline_data().empty()) {
                auto res = gkfs::rpc::forward_write_inline(
                        new_path, md_old.value().inline_data().data(), 0,
                        md_old.value().inline_data().size(), false,
                        CTX->get_replicas());
                if(res.first != 0) {
                    errno = res.first;
                    return -1;
                }
            }
            // Delete old file
            auto is_dir = false;
            if(S_ISDIR(md_old->mode()))
@@ -1696,11 +1709,11 @@ gkfs_readlink(const std::string& path, char* buf, int bufsize) {
        return -1;
    }
    std::string return_path;
    std::string rel_dummy;
    if(CTX->relativize_path(md->target_path().c_str(), rel_dummy)) {
        return_path = CTX->mountdir() + rel_dummy;
    if(gkfs::utils::is_external_symlink(md->target_path())) {
        return_path =
                gkfs::utils::strip_external_symlink_prefix(md->target_path());
    } else {
        return_path = md->target_path();
        return_path = CTX->mountdir() + md->target_path();
    }
    int path_size = return_path.size();
    if(path_size >= bufsize) {
+4 −1
Changes for src/client/hooks.cpp: 4 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -656,8 +656,11 @@ hook_symlinkat(const char* oldname, int newdfd, const char* newname) {
            } else {
                // Cross-mount symlink pointing to an external host path (e.g.
                // /usr/bin/python3).
                std::string ext_target =
                        std::string(gkfs::utils::kExternalSymlinkPrefix) +
                        oldname;
                return with_errno(gkfs::syscall::gkfs_mk_symlink(
                        newname_resolved, oldname));
                        newname_resolved, ext_target));
            }
        }

+8 −10
Changes for src/client/intercept.cpp: 8 added lines, 10 removed lines.
Original line number Diff line number Diff line
@@ -698,13 +698,12 @@ hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,
                        }
                        if(md->is_link()) {
                            std::string target = md->target_path();
                            std::string next_rel;
                            if(!CTX->relativize_path(target.c_str(),
                                                     next_rel)) {
                                resolved_exec = target;
                            if(gkfs::utils::is_external_symlink(target)) {
                                resolved_exec = gkfs::utils::
                                        strip_external_symlink_prefix(target);
                                break;
                            }
                            current_rel = next_rel;
                            current_rel = target;
                        } else {
                            break;
                        }
@@ -740,13 +739,12 @@ hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, long arg4,
                        }
                        if(md->is_link()) {
                            std::string target = md->target_path();
                            std::string next_rel;
                            if(!CTX->relativize_path(target.c_str(),
                                                     next_rel)) {
                                resolved_exec = target;
                            if(gkfs::utils::is_external_symlink(target)) {
                                resolved_exec = gkfs::utils::
                                        strip_external_symlink_prefix(target);
                                break;
                            }
                            current_rel = next_rel;
                            current_rel = target;
                        } else {
                            break;
                        }
Loading