]> git-server-git.apps.pok.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, 14 Mar 2016 17:25:30 +0000 (10:25 -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>
src/os/filestore/LFNIndex.cc
src/os/filestore/LFNIndex.h

index 2151d14b1a241d666c3a6691e74ebbf89586ec8a..47436ea444d02d4e8ad301ca49a1e8b34e255829 100644 (file)
@@ -935,10 +935,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))
@@ -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);
index 8f04407fc855c1461f4285c01cac0ed8835c55d5..1cf4f0b8e7f0dfc60df869691644d47583134275 100644 (file)
@@ -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.