From cbfbe637851c7ebe4a9ec1fd6e429cdf85aef608 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Fri, 18 Jul 2014 17:09:07 -0700 Subject: [PATCH] os/LFNIndex: handle long object names with multiple links (i.e., rename) When we rename an object (collection_move_rename) to a different name, and the name is long, we run into problems because the lfn xattr can only track a single long name linking to the inode. For example, suppose we have foobar -> foo_123_0 (attr: foobar) where foobar hashes to 123. At first, collection_add could only link a file to another file in a different collection with the same name. Allowing collection_move_rename to rename the file, however, means that we have to convert: col1/foobar -> foo_123_0 (attr: foobar) to col1/foobaz -> foo_234_0 (attr: foobaz) This is a problem because if we link, reset xattr, unlink we end up with col1/foobar -> foo_123_0 (attr: foobaz) if we restart after we reset the attr. This will cause the initial foobar lookup to since the attr doesn't match, and the file won't be able to be looked up. Fix this by allow *two* (long) names to link to the same inode. If we lfn_link a second (different) name, move the previous name to the "alt" xattr and set the new name. (This works because link is always followed by unlink.) On lookup, check either xattr. Don't even bother to remove the alt xattr on unlink. This works as long as the old name and new name don't hash to the same shortname and end up in the same LFN chain. (Don't worry, we'll fix that next.) Fixes part of #8701 Signed-off-by: Sage Weil (cherry picked from commit b2cdfce6461b81f4926602a8c63b54aa92684e6c) --- src/os/LFNIndex.cc | 42 ++++++++++++++++++++++++++++++++++++------ src/os/LFNIndex.h | 8 ++++++-- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/os/LFNIndex.cc b/src/os/LFNIndex.cc index a460e5cdb3058..04ad734447b0b 100644 --- a/src/os/LFNIndex.cc +++ b/src/os/LFNIndex.cc @@ -753,7 +753,8 @@ int LFNIndex::lfn_get_name(const vector &path, for ( ; ; ++i) { candidate = lfn_get_short_name(oid, i); candidate_path = get_full_path(path, candidate); - r = chain_getxattr(candidate_path.c_str(), get_lfn_attr().c_str(), buf, sizeof(buf)); + r = chain_getxattr(candidate_path.c_str(), get_lfn_attr().c_str(), + buf, sizeof(buf)); if (r < 0) { if (errno != ENODATA && errno != ENOENT) return -errno; @@ -784,6 +785,21 @@ int LFNIndex::lfn_get_name(const vector &path, *exists = 1; return 0; } + r = chain_getxattr(candidate_path.c_str(), get_alt_lfn_attr().c_str(), + buf, sizeof(buf)); + if (r > 0) { + buf[MIN((int)sizeof(buf) - 1, r)] = '\0'; + if (!strcmp(buf, full_name.c_str())) { + dout(20) << __func__ << " used alt attr for " << full_name << dendl; + if (mangled_name) + *mangled_name = candidate; + if (out_path) + *out_path = candidate_path; + if (exists) + *exists = 1; + return 0; + } + } } assert(0); // Unreachable return 0; @@ -798,7 +814,24 @@ int LFNIndex::lfn_created(const vector &path, string full_path = get_full_path(path, mangled_name); string full_name = lfn_generate_object_name(oid); maybe_inject_failure(); - return chain_setxattr(full_path.c_str(), get_lfn_attr().c_str(), + + // if the main attr exists and is different, move it to the alt attr. + char buf[FILENAME_MAX_LEN + 1]; + int r = chain_getxattr(full_path.c_str(), get_lfn_attr().c_str(), + buf, sizeof(buf)); + if (r >= 0 && (r != (int)full_name.length() || + memcmp(buf, full_name.c_str(), full_name.length()))) { + dout(20) << __func__ << " " << mangled_name + << " moving old name to alt attr " + << string(buf, r) + << ", new name is " << full_name << dendl; + r = chain_setxattr(full_path.c_str(), get_alt_lfn_attr().c_str(), + buf, r); + if (r < 0) + return r; + } + + return chain_setxattr(full_path.c_str(), get_lfn_attr().c_str(), full_name.c_str(), full_name.size()); } @@ -846,8 +879,6 @@ int LFNIndex::lfn_unlink(const vector &path, maybe_inject_failure(); if (r < 0) return -errno; - else - return 0; } else { string rename_to = get_full_path(path, mangled_name); string rename_from = get_full_path(path, lfn_get_short_name(oid, i - 1)); @@ -856,9 +887,8 @@ int LFNIndex::lfn_unlink(const vector &path, maybe_inject_failure(); if (r < 0) return -errno; - else - return 0; } + return 0; } int LFNIndex::lfn_translate(const vector &path, diff --git a/src/os/LFNIndex.h b/src/os/LFNIndex.h index c9c7f5ed141db..646e7267bb7e8 100644 --- a/src/os/LFNIndex.h +++ b/src/os/LFNIndex.h @@ -123,7 +123,7 @@ protected: } private: - string lfn_attribute; + string lfn_attribute, lfn_alt_attribute; coll_t collection; public: @@ -146,7 +146,8 @@ public: char buf[100]; snprintf(buf, sizeof(buf), "%d", index_version); lfn_attribute = LFN_ATTR + string(buf); - } + lfn_alt_attribute = LFN_ATTR + string(buf) + "-alt"; + } } coll_t coll() const { return collection; } @@ -423,6 +424,9 @@ private: const string &get_lfn_attr() const { return lfn_attribute; } + const string &get_alt_lfn_attr() const { + return lfn_alt_attribute; + } /** * Gets the filename corresponsing to oid in path. -- 2.39.5