]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds: add json handling in setvxattr
authorMilind Changire <mchangir@redhat.com>
Fri, 21 Jan 2022 13:53:27 +0000 (19:23 +0530)
committerMilind Changire <mchangir@redhat.com>
Thu, 17 Mar 2022 13:15:19 +0000 (18:45 +0530)
Setting the entire layout via setfattr -n ceph.dir.layout.json
requires a json value with the name of all mandatory fields as
returned by getfattr, except 'inheritance'.
Also, the json format expects a 'pool_name' or 'pool_id'.
If both are specified, the 'pool_name' is given priority over
'pool_id' for better disambiguation.

ceph.(dir|file).layout.pool_name and ceph.(dir|file).layout.pool_id
can also be set and fetched as individual fields.

Fixes: https://tracker.ceph.com/issues/51062
Signed-off-by: Milind Changire <mchangir@redhat.com>
(cherry picked from commit 50ff98751c7b0a8ff17b554e8b14c08a1da3abca)

Conflicts:
src/mds/Server.h
- minor change in function prototype argument type specification

src/mds/Server.cc
src/mds/Server.h

index 759d80c2459494d3569bcd0055e2dd5368bf514a..dd0a27fcf72cdd5eef17798aadb933a58592b476 100644 (file)
@@ -5415,11 +5415,85 @@ void Server::handle_client_setdirlayout(MDRequestRef& mdr)
 }
 
 // XATTRS
+int Server::parse_layout_vxattr_json(
+  string name, string value, const OSDMap& osdmap, file_layout_t *layout)
+{
+  auto parse_pool = [&](std::string pool_name, int64_t pool_id) -> int64_t {
+    if (pool_name != "") {
+      int64_t _pool_id = osdmap.lookup_pg_pool_name(pool_name);
+      if (_pool_id < 0) {
+       dout(10) << __func__ << ": unknown pool name:" << pool_name << dendl;
+       return -CEPHFS_EINVAL;
+      }
+      return _pool_id;
+    } else if (pool_id >= 0) {
+      const auto pools = osdmap.get_pools();
+      if (pools.find(pool_id) == pools.end()) {
+       dout(10) << __func__ << ": unknown pool id:" << pool_id << dendl;
+       return -CEPHFS_EINVAL;
+      }
+      return pool_id;
+    } else {
+      return -CEPHFS_EINVAL;
+    }
+  };
 
-int Server::parse_layout_vxattr(string name, string value, const OSDMap& osdmap,
-                               file_layout_t *layout, bool validate)
+  try {
+    if (name == "layout.json") {
+      JSONParser json_parser;
+      if (json_parser.parse(value.c_str(), value.length()) and json_parser.is_object()) {
+       std::string field;
+       try {
+         field = "object_size";
+         JSONDecoder::decode_json("object_size", layout->object_size, &json_parser, true);
+
+         field = "stripe_unit";
+         JSONDecoder::decode_json("stripe_unit", layout->stripe_unit, &json_parser, true);
+
+         field = "stripe_count";
+         JSONDecoder::decode_json("stripe_count", layout->stripe_count, &json_parser, true);
+
+         field = "pool_namespace";
+         JSONDecoder::decode_json("pool_namespace", layout->pool_ns, &json_parser, false);
+
+         field = "pool_id";
+         int64_t pool_id = 0;
+         JSONDecoder::decode_json("pool_id", pool_id, &json_parser, false);
+
+         field = "pool_name";
+         std::string pool_name;
+         JSONDecoder::decode_json("pool_name", pool_name, &json_parser, false);
+
+         pool_id = parse_pool(pool_name, pool_id);
+         if (pool_id < 0) {
+           return (int)pool_id;
+         }
+         layout->pool_id = pool_id;
+       } catch (JSONDecoder::err&) {
+         dout(10) << __func__ << ": json is missing a mandatory field named "
+                  << field << dendl;
+         return -CEPHFS_EINVAL;
+       }
+      } else {
+       dout(10) << __func__ << ": bad json" << dendl;
+       return -CEPHFS_EINVAL;
+      }
+    } else {
+      dout(10) << __func__ << ": unknown layout vxattr " << name << dendl;
+      return -CEPHFS_ENODATA; // no such attribute
+    }
+  } catch (boost::bad_lexical_cast const&) {
+    dout(10) << __func__ << ": bad vxattr value:" << value
+            << ", unable to parse for xattr:" << name << dendl;
+    return -CEPHFS_EINVAL;
+  }
+  return 0;
+}
+
+// parse old style layout string
+int Server::parse_layout_vxattr_string(
+  string name, string value, const OSDMap& osdmap, file_layout_t *layout)
 {
-  dout(20) << "parse_layout_vxattr name " << name << " value '" << value << "'" << dendl;
   try {
     if (name == "layout") {
       string::iterator begin = value.begin();
@@ -5430,14 +5504,14 @@ int Server::parse_layout_vxattr(string name, string value, const OSDMap& osdmap,
        return -CEPHFS_EINVAL;
       }
       string left(begin, end);
-      dout(10) << " parsed " << m << " left '" << left << "'" << dendl;
+      dout(10) << __func__ << ": parsed " << m << " left '" << left << "'" << dendl;
       if (begin != end)
        return -CEPHFS_EINVAL;
       for (map<string,string>::iterator q = m.begin(); q != m.end(); ++q) {
         // Skip validation on each attr, we do it once at the end (avoid
         // rejecting intermediate states if the overall result is ok)
-       int r = parse_layout_vxattr(string("layout.") + q->first, q->second,
-                                    osdmap, layout, false);
+       int r = parse_layout_vxattr_string(string("layout.") + q->first, q->second,
+                                          osdmap, layout);
        if (r < 0)
          return r;
       }
@@ -5453,28 +5527,54 @@ int Server::parse_layout_vxattr(string name, string value, const OSDMap& osdmap,
       } catch (boost::bad_lexical_cast const&) {
        int64_t pool = osdmap.lookup_pg_pool_name(value);
        if (pool < 0) {
-         dout(10) << " unknown pool " << value << dendl;
+         dout(10) << __func__ << ": unknown pool " << value << dendl;
          return -CEPHFS_ENOENT;
        }
        layout->pool_id = pool;
       }
+    } else if (name == "layout.pool_id") {
+      layout->pool_id = boost::lexical_cast<int64_t>(value);
+    } else if (name == "layout.pool_name") {
+      layout->pool_id = osdmap.lookup_pg_pool_name(value);
+      if (layout->pool_id < 0) {
+       dout(10) << __func__ << ": unknown pool " << value << dendl;
+       return -CEPHFS_EINVAL;
+      }
     } else if (name == "layout.pool_namespace") {
       layout->pool_ns = value;
     } else {
-      dout(10) << " unknown layout vxattr " << name << dendl;
-      return -CEPHFS_EINVAL;
+      dout(10) << __func__ << ": unknown layout vxattr " << name << dendl;
+      return -CEPHFS_ENODATA; // no such attribute
     }
   } catch (boost::bad_lexical_cast const&) {
-    dout(10) << "bad vxattr value, unable to parse int for " << name << dendl;
+    dout(10) << __func__ << ": bad vxattr value, unable to parse int for "
+            << name << dendl;
     return -CEPHFS_EINVAL;
   }
+  return 0;
+}
+
+int Server::parse_layout_vxattr(string name, string value, const OSDMap& osdmap,
+                               file_layout_t *layout, bool validate)
+{
+  dout(20) << __func__ << ": name:" << name << " value:'" << value << "'" << dendl;
+
+  int r;
+  if (name == "layout.json") {
+    r = parse_layout_vxattr_json(name, value, osdmap, layout);
+  } else {
+    r = parse_layout_vxattr_string(name, value, osdmap, layout);
+  }
+  if (r < 0) {
+    return r;
+  }
 
   if (validate && !layout->is_valid()) {
-    dout(10) << "bad layout" << dendl;
+    dout(10) << __func__ << ": bad layout" << dendl;
     return -CEPHFS_EINVAL;
   }
   if (!mds->mdsmap->is_data_pool(layout->pool_id)) {
-    dout(10) << " invalid data pool " << layout->pool_id << dendl;
+    dout(10) << __func__ << ": invalid data pool " << layout->pool_id << dendl;
     return -CEPHFS_EINVAL;
   }
   return 0;
index 265bc9cf6da7adefb26755f54c7193a550bfad47..3d69a536ad6fb73548c4bf5abc5759bd9a07505d 100644 (file)
@@ -96,6 +96,7 @@ public:
     TRIM = (1<<2),
     ENFORCE_LIVENESS = (1<<3),
   };
+
   explicit Server(MDSRank *m, MetricsHandler *metrics_handler);
   ~Server() {
     g_ceph_context->get_perfcounters_collection()->remove(logger);
@@ -214,7 +215,11 @@ public:
 
   int parse_quota_vxattr(string name, string value, quota_info_t *quota);
   void create_quota_realm(CInode *in);
-  int parse_layout_vxattr(string name, string value, const OSDMap& osdmap,
+  int parse_layout_vxattr_json(std::string name, std::string value,
+                              const OSDMap& osdmap, file_layout_t *layout);
+  int parse_layout_vxattr_string(std::string name, std::string value, const OSDMap& osdmap,
+                                file_layout_t *layout);
+  int parse_layout_vxattr(std::string name, std::string value, const OSDMap& osdmap,
                          file_layout_t *layout, bool validate=true);
   int check_layout_vxattr(MDRequestRef& mdr,
                           string name,