]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
LFNIndex::lfn_translate: consider alt attr as well
authorSamuel Just <sjust@redhat.com>
Thu, 10 Mar 2016 23:19:15 +0000 (15:19 -0800)
committerSamuel Just <sjust@redhat.com>
Mon, 9 May 2016 21:38:22 +0000 (14:38 -0700)
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 <sjust@redhat.com>
(cherry picked from commit 850ce11ea3c4dacc6ff1a3ce7ff37000818267c2)

src/os/LFNIndex.cc
src/os/LFNIndex.h

index 2658e9929b812ac309052f25a286416e127f7cec..5aa06283a6dcff6a3876c5a5dc209422bf374ecf 100644 (file)
@@ -950,10 +950,26 @@ int LFNIndex::lfn_translate(const vector<string> &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);
index 5cd35238165cf70ff33fbc78803b1fb7e94e2879..f3e5e437554ec086ada618c0aa68f6292c08bfd4 100644 (file)
@@ -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.