From: Samuel Just Date: Thu, 10 Mar 2016 23:19:15 +0000 (-0800) Subject: LFNIndex::lfn_translate: consider alt attr as well X-Git-Tag: v0.94.8~51^2~4 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=9d1ee7cf390154c5939a01ff439e33d303a952c2;p=ceph.git 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 (cherry picked from commit 850ce11ea3c4dacc6ff1a3ce7ff37000818267c2) --- diff --git a/src/os/LFNIndex.cc b/src/os/LFNIndex.cc index 2658e9929b81..5aa06283a6dc 100644 --- a/src/os/LFNIndex.cc +++ b/src/os/LFNIndex.cc @@ -950,10 +950,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)) @@ -1310,6 +1326,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/LFNIndex.h b/src/os/LFNIndex.h index 5cd35238165c..f3e5e437554e 100644 --- a/src/os/LFNIndex.h +++ b/src/os/LFNIndex.h @@ -576,6 +576,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.