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: v10.1.0~76^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=850ce11ea3c4dacc6ff1a3ce7ff37000818267c2;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 --- diff --git a/src/os/filestore/LFNIndex.cc b/src/os/filestore/LFNIndex.cc index 2151d14b1a24..47436ea444d0 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 8f04407fc855..1cf4f0b8e7f0 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.