From 850ce11ea3c4dacc6ff1a3ce7ff37000818267c2 Mon Sep 17 00:00:00 2001 From: Samuel Just Date: Thu, 10 Mar 2016 15:19:15 -0800 Subject: [PATCH] LFNIndex::lfn_translate: consider alt attr as well If the file has an alt attr, there are two possible matching ghobjects. We want to make sure we choose the right one for the short name we have. If we don't, a split while there are two objects linking to the same inode will result in one of the links being orphaned in the source directory, resulting in #14766. Signed-off-by: Samuel Just --- src/os/filestore/LFNIndex.cc | 42 ++++++++++++++++++++++++++++++++++-- src/os/filestore/LFNIndex.h | 6 ++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/os/filestore/LFNIndex.cc b/src/os/filestore/LFNIndex.cc index 2151d14b1a2..47436ea444d 100644 --- a/src/os/filestore/LFNIndex.cc +++ b/src/os/filestore/LFNIndex.cc @@ -935,10 +935,26 @@ int LFNIndex::lfn_translate(const vector &path, if (!lfn_is_hashed_filename(short_name)) { return lfn_parse_object_name(short_name, out); } - // Get lfn_attr string full_path = get_full_path(path, short_name); char attr[PATH_MAX]; - int r = chain_getxattr(full_path.c_str(), get_lfn_attr().c_str(), attr, sizeof(attr) - 1); + // First, check alt attr + int r = chain_getxattr( + full_path.c_str(), + get_alt_lfn_attr().c_str(), + attr, + sizeof(attr) - 1); + if (r >= 0) { + // There is an alt attr, does it match? + if (r < (int)sizeof(attr)) + attr[r] = '\0'; + if (short_name_matches(short_name.c_str(), attr)) { + string long_name(attr); + return lfn_parse_object_name(long_name, out); + } + } + + // Get lfn_attr + r = chain_getxattr(full_path.c_str(), get_lfn_attr().c_str(), attr, sizeof(attr) - 1); if (r < 0) return -errno; if (r < (int)sizeof(attr)) @@ -1295,6 +1311,28 @@ void LFNIndex::build_filename(const char *old_filename, int i, char *filename, i } } +bool LFNIndex::short_name_matches(const char *short_name, const char *cand_long_name) +{ + const char *end = short_name; + while (*end) ++end; + const char *suffix = end; + if (suffix > short_name) --suffix; // last char + while (suffix > short_name && *suffix != '_') --suffix; // back to first _ + if (suffix > short_name) --suffix; // one behind that + while (suffix > short_name && *suffix != '_') --suffix; // back to second _ + + int index = -1; + char buf[FILENAME_SHORT_LEN + 4]; + assert((end - suffix) < (int)sizeof(buf)); + int r = sscanf(suffix, "_%d_%s", &index, buf); + if (r < 2) + return false; + if (strcmp(buf, FILENAME_COOKIE.c_str()) != 0) + return false; + build_filename(cand_long_name, index, buf, sizeof(buf)); + return strcmp(short_name, buf) == 0; +} + string LFNIndex::lfn_get_short_name(const ghobject_t &oid, int i) { string long_name = lfn_generate_object_name(oid); diff --git a/src/os/filestore/LFNIndex.h b/src/os/filestore/LFNIndex.h index 8f04407fc85..1cf4f0b8e7f 100644 --- a/src/os/filestore/LFNIndex.h +++ b/src/os/filestore/LFNIndex.h @@ -556,6 +556,12 @@ private: const string &attr ///< [in] Attribute to mangle. ); ///< @return Mangled attribute name. + /// checks whether long_name could hash to short_name + bool short_name_matches( + const char *short_name, ///< [in] name to check against + const char *cand_long_name ///< [in] candidate long name + ); + /// Builds hashed filename void build_filename( const char *old_filename, ///< [in] Filename to convert. -- 2.47.3