]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Merge remote-tracking branch 'origin/master' into wip-rgw-geo
authorYehuda Sadeh <yehuda@inktank.com>
Thu, 4 Jul 2013 00:09:56 +0000 (17:09 -0700)
committerYehuda Sadeh <yehuda@inktank.com>
Thu, 4 Jul 2013 00:09:56 +0000 (17:09 -0700)
Conflicts:
src/Makefile.am
src/include/rados/librados.hpp
src/rgw/rgw_admin.cc
src/rgw/rgw_bucket.cc
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_json_enc.cc
src/rgw/rgw_main.cc
src/rgw/rgw_op.h
src/rgw/rgw_rados.cc
src/rgw/rgw_tools.cc
src/rgw/rgw_user.cc
src/rgw/rgw_user.h

Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
28 files changed:
1  2 
src/Makefile.am
src/cls/rgw/cls_rgw.cc
src/common/config_opts.h
src/include/rados/librados.hpp
src/key_value_store/kv_flat_btree_async.cc
src/key_value_store/kv_flat_btree_async.h
src/librados/librados.cc
src/osd/ReplicatedPG.cc
src/osd/ReplicatedPG.h
src/osdc/Objecter.h
src/rgw/rgw_acl_s3.cc
src/rgw/rgw_admin.cc
src/rgw/rgw_bucket.cc
src/rgw/rgw_bucket.h
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_json_enc.cc
src/rgw/rgw_log.cc
src/rgw/rgw_main.cc
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rados.cc
src/rgw/rgw_rest.cc
src/rgw/rgw_swift_auth.cc
src/rgw/rgw_tools.cc
src/rgw/rgw_user.cc
src/rgw/rgw_user.h
src/test/encoding/types.h

diff --cc src/Makefile.am
index 0e755a15b1f266fdea7d0f1e902674b8d72dd02a,7b82e9d23e4e3b76a11becfdb3c91dc25893406e..c799e0f9415c8532e8a26ba31deaef9e9b932b87
@@@ -408,10 -396,9 +405,10 @@@ librgw_a_CXXFLAGS = -Woverloaded-virtua
  noinst_LIBRARIES += librgw.a
  
  my_radosgw_ldadd = \
 -       librgw.a librados.la libcls_rgw_client.a \
 -       libcls_lock_client.a libcls_refcount_client.a -lcurl -lexpat \
 -       $(LIBGLOBAL_LDA) 
 +       libglobal.la librgw.a librados.la libcls_rgw_client.a libcls_log_client.a \
 +       libcls_statelog_client.a libcls_replica_log_client.a libcls_lock_client.a \
 +       libcls_refcount_client.a libcls_version_client.a -lcurl -lexpat \
-        $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS)
++       $(PTHREAD_LIBS) -lm $(CRYPTO_LIBS) $(EXTRALIBS) $(LIBGLOBAL_LDA)
  
  radosgw_SOURCES = \
        rgw/rgw_resolve.cc \
@@@ -971,31 -914,9 +983,30 @@@ check_PROGRAMS += unittest_texttabl
  
  if WITH_RADOSGW
  ceph_test_cors_SOURCES = test/test_cors.cc
- ceph_test_cors_LDFLAGS = libglobal.la
- ceph_test_cors_LDADD = librados.la librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} $(CRYPTO_LIBS) -lcurl -luuid -lexpat
+ ceph_test_cors_LDADD = librados.la librgw.a $(LIBGLOBAL_LDA) ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcurl -luuid -lexpat
  ceph_test_cors_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
  bin_DEBUGPROGRAMS += ceph_test_cors
 +
 +cls_test_rgw_meta_SOURCES = test/test_rgw_admin_meta.cc
 +cls_test_rgw_meta_LDFLAGS = libglobal.la 
 +cls_test_rgw_meta_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat  librados.la libcls_version_client.a \
 + libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
 +cls_test_rgw_meta_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 +bin_DEBUGPROGRAMS += cls_test_rgw_meta
 +
 +cls_test_rgw_log_SOURCES = test/test_rgw_admin_log.cc
 +cls_test_rgw_log_LDFLAGS = libglobal.la 
 +cls_test_rgw_log_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat  librados.la libcls_version_client.a \
 + libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
 +cls_test_rgw_log_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 +bin_DEBUGPROGRAMS += cls_test_rgw_log
 +
 +cls_test_rgw_opstate_SOURCES = test/test_rgw_admin_opstate.cc
 +cls_test_rgw_opstate_LDFLAGS = libglobal.la 
 +cls_test_rgw_opstate_LDADD = librgw.a ${UNITTEST_LDADD} ${UNITTEST_STATIC_LDADD} -lcryptopp -lcurl -luuid -lexpat  librados.la libcls_version_client.a \
 + libcls_log_client.a libcls_statelog_client.a libcls_refcount_client.a libcls_rgw_client.a libcls_lock_client.a
 +cls_test_rgw_opstate_CXXFLAGS = ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 +bin_DEBUGPROGRAMS += cls_test_rgw_opstate
  endif
  
  ceph_test_librbd_SOURCES = test/librbd/test_librbd.cc test/librados/test.cc
Simple merge
Simple merge
index 697969f2fbcde4633091232af9dd2f422fcaea99,497fc212db19de4b1b7100ee2d76778518ea7464..b6ea02595839b69b0a146dd1f1c3d85f24d05ce7
@@@ -110,13 -120,19 +120,25 @@@ namespace librado
      OP_FAILOK = 2,
    };
  
 +  class ObjectOperationCompletion {
 +  public:
 +    virtual ~ObjectOperationCompletion() {}
 +    virtual void handle_completion(int r, bufferlist& outbl) = 0;
 +  };
 +
+   /**
+    * These flags apply to the ObjectOperation as a whole.
+    *
+    * BALANCE_READS and LOCALIZE_READS should only be used
+    * when reading from data you're certain won't change,
+    * like a snapshot, or where eventual consistency is ok.
+    */
+   enum ObjectOperationGlobalFlags {
+     OPERATION_NOFLAG         = 0,
+     OPERATION_BALANCE_READS  = 1,
+     OPERATION_LOCALIZE_READS = 2,
+   };
    /*
     * ObjectOperation : compound object operation
     * Batch multiple object operations into a single request, to be applied
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 24e27c17a5bfc6ad855df37af54934b95b9efa43,c505cc207640979cdf575ce697429e62f92189ef..4f3d41530061a43799b31bd4cb01933dee40fd3c
@@@ -693,26 -484,10 +695,27 @@@ int main(int argc, char **argv
    map<string, bool> categories;
    string caps;
    int check_objects = false;
 -  std::string infile;
    RGWUserAdminOpState user_op;
    RGWBucketAdminOpState bucket_op;
 +  string infile;
 +  string metadata_key;
 +  RGWObjVersionTracker objv_tracker;
 +  string marker;
 +  string start_marker;
 +  string end_marker;
 +  int max_entries = -1;
 +  int system = false;
 +  bool system_specified = false;
 +  int shard_id = -1;
 +  bool specified_shard_id = false;
 +  string daemon_id;
 +  bool specified_daemon_id = false;
 +  string client_id;
 +  string op_id;
 +  string state_str;
 +  string replica_log_type_str;
 +  ReplicaLogType replica_log_type = ReplicaLog_Invalid;
+   string op_mask_str;
  
    std::string val;
    std::ostringstream errs;
        pool_name = val;
      } else if (ceph_argparse_witharg(args, i, &val, "-o", "--object", (char*)NULL)) {
        object = val;
 +    } else if (ceph_argparse_witharg(args, i, &val, "--client-id", (char*)NULL)) {
 +      client_id = val;
 +    } else if (ceph_argparse_witharg(args, i, &val, "--op-id", (char*)NULL)) {
 +      op_id = val;
 +    } else if (ceph_argparse_witharg(args, i, &val, "--state", (char*)NULL)) {
 +      state_str = val;
+     } else if (ceph_argparse_witharg(args, i, &val, "--op-mask", (char*)NULL)) {
+       op_mask_str = val;
      } else if (ceph_argparse_witharg(args, i, &val, "--key-type", (char*)NULL)) {
        key_type_str = val;
        if (key_type_str.compare("swift") == 0) {
@@@ -1724,8 -1151,8 +1740,7 @@@ next
    }
  
    if (opt_cmd == OPT_GC_LIST) {
-     int ret;
      int index = 0;
 -    string marker;
      bool truncated;
      formatter->open_array_section("entries");
  
index fc364cfec8dd0aeef746467a0a5ff0f77c66f015,6a6b576235281779c7358bd702c69cd45f06af43..e86abfe6eabcd2c0de791334bf349f2ab8a19a4b
@@@ -309,9 -275,9 +309,8 @@@ int rgw_remove_bucket(RGWRados *store, 
      return ret;
  
    obj.bucket = bucket;
-   int max = 1000;
  
 -  ret = rgw_get_obj(store, NULL, store->zone.domain_root,\
 -           bucket.name, bl, NULL);
 +  ret = rgw_get_system_obj(store, NULL, store->zone.domain_root, bucket.name, bl, NULL, NULL);
  
    bufferlist::iterator iter = bl.begin();
    try {
    }
  
    if (delete_children) {
 -    ret = store->list_objects(bucket, max, prefix, delim, marker,\
 -            objs, common_prefixes,\
 -            false, ns, (bool *)false, NULL);
+     int max = 1000;
 +    ret = store->list_objects(bucket, max, prefix, delim, marker,
 +            objs, common_prefixes,
 +            false, ns, true, NULL, NULL);
  
      if (ret < 0)
        return ret;
index d5f023f7bd9fa7a04a832b96ec8cd965a066ac39,e2f4d5eee40518386dcd40cf30cb3718753ad761..5ee6a9b41cd3de36fc855fbb6eb7ed7f995ee42f
@@@ -186,9 -173,11 +186,9 @@@ class RGWBucke
  private:
  
  public:
-   RGWBucket() : store(NULL), failure(false) {}
+   RGWBucket() : store(NULL), handle(NULL), failure(false) {}
    int init(RGWRados *storage, RGWBucketAdminOpState& op_state);
  
 -  int create_bucket(string bucket_str, string& user_id, string& display_name);
 -  
    int check_bad_index_multipart(RGWBucketAdminOpState& op_state,
            list<std::string>& objs_to_unlink, std::string *err_msg = NULL);
  
index a17f1c2017e5bef2943ed131b1198d7ebde8d4e7,9e300ad6e04a5f6324228292ee40c8c7c1a2a071..aea396bf3def15db187f7c93516e51b1c0d80b50
@@@ -507,14 -447,10 +507,15 @@@ int XMLArgs::parse(
      if (ret >= 0) {
        string& name = nv.get_name();
        string& val = nv.get_val();
 -      val_map[name] = val;
 +
 +      if (name.compare(0, sizeof(RGW_SYS_PARAM_PREFIX) - 1, RGW_SYS_PARAM_PREFIX) == 0) {
 +        sys_val_map[name] = val;
 +      } else {
 +        val_map[name] = val;
 +      }
  
        if ((name.compare("acl") == 0) ||
+           (name.compare("cors") == 0) ||
            (name.compare("location") == 0) ||
            (name.compare("logging") == 0) ||
            (name.compare("delete") == 0) ||
@@@ -703,64 -639,13 +704,62 @@@ bool url_decode(string& src_str, string
    return true;
  }
  
- static struct {
 +string rgw_trim_whitespace(const string& src)
 +{
 +  if (src.empty()) {
 +    return string();
 +  }
 +
 +  int start = 0;
 +  for (; start != (int)src.size(); start++) {
 +    if (!isspace(src[start]))
 +      break;
 +  }
 +
 +  int end = src.size() - 1;
 +  if (end <= start) {
 +    return string();
 +  }
 +
 +  for (; end > start; end--) {
 +    if (!isspace(src[end]))
 +      break;
 +  }
 +
 +  return src.substr(start, end - start + 1);
 +}
 +
 +string rgw_trim_quotes(const string& val)
 +{
 +  string s = rgw_trim_whitespace(val);
 +  if (s.size() < 2)
 +    return s;
 +
 +  int start = 0;
 +  int end = s.size() - 1;
 +  int quotes_count = 0;
 +
 +  if (s[start] == '"') {
 +    start++;
 +    quotes_count++;
 +  }
 +  if (s[end] == '"') {
 +    end--;
 +    quotes_count++;
 +  }
 +  if (quotes_count == 2) {
 +    return s.substr(start, end - start + 1);
 +  }
 +  return s;
 +}
 +
+ struct rgw_name_to_flag {
    const char *type_name;
-   uint32_t perm;
- } cap_names[] = { {"*",     RGW_CAP_ALL},
-                   {"read",  RGW_CAP_READ},
-                 {"write", RGW_CAP_WRITE},
-                 {NULL, 0} };
+   uint32_t flag;
+ };
  
- int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm)
+ static int parse_list_of_flags(struct rgw_name_to_flag *mapping,
+                                const string& str, uint32_t *perm)
  {
    list<string> strs;
    get_str_list(str, strs);
index c03ee74367ff8db2bdff07e2948b9b8dd7332e65,9b761810286f13bc7ed33ef5f18fa16c4b4445d6..c885724efbdbabc3db757ab45be859c9da0635d2
@@@ -409,15 -387,13 +415,16 @@@ struct RGWUserInf
    map<string, RGWSubUser> subusers;
    __u8 suspended;
    uint32_t max_buckets;
+   uint32_t op_mask;
    RGWUserCaps caps;
 +  __u8 system;
 +  string default_placement;
 +  list<string> placement_tags;
  
-   RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), system(0) {}
 -  RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL) {}
++  RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS), op_mask(RGW_OP_TYPE_ALL), system(0) {}
  
    void encode(bufferlist& bl) const {
 -     ENCODE_START(12, 9, bl);
 +     ENCODE_START(13, 9, bl);
       ::encode(auid, bl);
       string access_key;
       string secret_key;
       ::encode(swift_keys, bl);
       ::encode(max_buckets, bl);
       ::encode(caps, bl);
+      ::encode(op_mask, bl);
 +     ::encode(system, bl);
 +     ::encode(default_placement, bl);
 +     ::encode(placement_tags, bl);
       ENCODE_FINISH(bl);
    }
    void decode(bufferlist::iterator& bl) {
--     DECODE_START_LEGACY_COMPAT_LEN_32(11, 9, 9, bl);
++     DECODE_START_LEGACY_COMPAT_LEN_32(13, 9, 9, bl);
       if (struct_v >= 2) ::decode(auid, bl);
       else auid = CEPH_AUTH_UID_DEFAULT;
       string access_key;
      if (struct_v >= 11) {
        ::decode(caps, bl);
      }
-     system = 0;
      if (struct_v >= 12) {
-       ::decode(system, bl);
+       ::decode(op_mask, bl);
+     } else {
+       op_mask = RGW_OP_TYPE_ALL;
      }
++    system = 0;
 +    if (struct_v >= 13) {
++      ::decode(system, bl);
 +      ::decode(default_placement, bl);
 +      ::decode(placement_tags, bl); /* tags of allowed placement rules */
 +    }
      DECODE_FINISH(bl);
    }
    void dump(Formatter *f) const;
index face8534eb581956efee4ae00f0d72b37edab3f2,e26299f24adde6b37af5380d7e0449240353639a..6ab073bb9874c6347a7384f7618d8ef68357ef73
@@@ -368,11 -357,10 +385,16 @@@ void RGWUserInfo::dump(Formatter *f) co
    encode_json_map("swift_keys", NULL, "key", NULL, user_info_dump_swift_key,(void *)this, swift_keys, f);
  
    encode_json("caps", caps, f);
+   char buf[256];
+   op_type_to_str(op_mask, buf, sizeof(buf));
+   encode_json("op_mask", (const char *)buf, f);
++
 +  if (system) { /* no need to show it for every user */
 +    encode_json("system", (bool)system, f);
 +  }
 +  encode_json("default_placement", default_placement, f);
 +  encode_json("placement_tags", placement_tags, f);
  }
  
  
@@@ -413,11 -401,10 +435,16 @@@ void RGWUserInfo::decode_json(JSONObj *
    JSONDecoder::decode_json("subusers", subusers, decode_subusers, obj);
  
    JSONDecoder::decode_json("caps", caps, obj);
+   string mask_str;
+   JSONDecoder::decode_json("op_mask", mask_str, obj);
+   rgw_parse_op_type_list(mask_str, &op_mask);
++
 +  bool sys = false;
 +  JSONDecoder::decode_json("system", sys, obj);
 +  system = (__u8)sys;
 +  JSONDecoder::decode_json("default_placement", default_placement, obj);
 +  JSONDecoder::decode_json("placement_tags", placement_tags, obj);
  }
  
  void rgw_bucket::dump(Formatter *f) const
Simple merge
index c1f48579f9a883e703208c338ba5d655ad273f91,3d6bfb908f046dabc3937e1fae201700ecd1da01..f06e794b301fa7feb4c13f0d7a807c79742ced3d
@@@ -343,7 -335,14 +343,14 @@@ void RGWProcess::handle_request(RGWRequ
  
    req->log(s, "reading the cors attr");
    handler->read_cors_config();
 -  
 + 
+   req->log(s, "verifying op mask");
+   ret = op->verify_op_mask();
+   if (ret < 0) {
+     abort_early(s, ret);
+     goto done;
+   }
    req->log(s, "verifying op permissions");
    ret = op->verify_permission();
    if (ret < 0) {
Simple merge
index fc12470c3d678f1f10bb83fde7baa4d1dae92cfe,184935228b3479429c9a52ca95ede1af39caa897..7a2e4920ba8e8e6a7f729595054aed8a7677c0f5
@@@ -26,7 -26,9 +26,6 @@@ using namespace std
  struct req_state;
  class RGWHandler;
  
 -void rgw_get_request_metadata(struct req_state *s, map<string, bufferlist>& attrs);
 -int rgw_build_policies(RGWRados *store, struct req_state *s, bool only_bucket, bool prefetch_data);
--
  /**
   * Provide the base class for all ops.
   */
@@@ -266,8 -271,36 +275,9 @@@ public
  
    virtual void send_response() = 0;
    virtual const char *name() { return "delete_bucket"; }
+   virtual uint32_t op_mask() { return RGW_OP_TYPE_DELETE; }
  };
  
 -class RGWPutObjProcessor
 -{
 -protected:
 -  RGWRados *store;
 -  struct req_state *s;
 -  bool is_complete;
 -
 -  virtual int do_complete(string& etag, map<string, bufferlist>& attrs) = 0;
 -
 -  list<rgw_obj> objs;
 -
 -  void add_obj(rgw_obj& obj) {
 -    objs.push_back(obj);
 -  }
 -public:
 -  RGWPutObjProcessor() : store(NULL), s(NULL), is_complete(false) {}
 -  virtual ~RGWPutObjProcessor();
 -  virtual int prepare(RGWRados *_store, struct req_state *_s) {
 -    store = _store;
 -    s = _s;
 -    return 0;
 -  };
 -  virtual int handle_data(bufferlist& bl, off_t ofs, void **phandle) = 0;
 -  virtual int throttle_data(void *handle) = 0;
 -  virtual int complete(string& etag, map<string, bufferlist>& attrs);
 -};
 -
  class RGWPutObj : public RGWOp {
  
    friend class RGWPutObjProcessor;
index d1fdce17d58513c121a27b87816795eab37d4050,5c0bb6e8bbd5de74ff520a3e76d5ab1e5a969152..c836a4eb0f18b1a38542716b4ea05e048ca4a625
@@@ -2479,97 -1303,25 +2481,97 @@@ int RGWRados::copy_obj(void *ctx
  
    void *handle = NULL;
  
 -  map<string, bufferlist> attrset;
 +  map<string, bufferlist> src_attrs;
    off_t ofs = 0;
    off_t end = -1;
 -  ret = prepare_get_obj(ctx, src_obj, &ofs, &end, &attrset,
 -                mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &obj_size, &handle, err);
 +  if (!remote_src && source_zone.empty()) {
 +    ret = prepare_get_obj(ctx, src_obj, &ofs, &end, &src_attrs,
 +                  mod_ptr, unmod_ptr, &lastmod, if_match, if_nomatch, &total_len, &obj_size, NULL, &handle, err);
 +    if (ret < 0)
 +      return ret;
 +  } else {
 +    /* source is in a different region, copy it there */
  
 -  if (ret < 0)
 -    return ret;
 +    RGWRESTStreamReadRequest *in_stream_req;
 +    string tag;
 +    append_rand_alpha(cct, tag, tag, 32);
  
 -  if (replace_attrs) {
 -    if (!attrs[RGW_ATTR_ETAG].length())
 -      attrs[RGW_ATTR_ETAG] = attrset[RGW_ATTR_ETAG];
 +    RGWPutObjProcessor_Atomic processor(dest_obj.bucket, dest_obj.object,
 +                                        cct->_conf->rgw_obj_stripe_size, tag);
 +    ret = processor.prepare(this, ctx);
 +    if (ret < 0)
 +      return ret;
  
 -    attrset = attrs;
 -  } else {
 -    /* copying attrs from source, however acls should not be copied */
 -    attrset[RGW_ATTR_ACL] = attrs[RGW_ATTR_ACL];
 +    RGWRESTConn *conn;
 +    if (source_zone.empty()) {
 +      conn = rest_master_conn;
 +    } else {
 +      map<string, RGWRESTConn *>::iterator iter = zone_conn_map.find(source_zone);
 +      if (iter == zone_conn_map.end()) {
 +        ldout(cct, 0) << "could not find zone connection to zone: " << source_zone << dendl;
 +        return -ENOENT;
 +      }
 +      conn = iter->second;
 +    }
 +
 +    string obj_name = dest_obj.bucket.name + "/" + dest_obj.object;
 +
 +    RGWOpStateSingleOp opstate(this, client_id, op_id, obj_name);
 +
 +    int ret = opstate.set_state(RGWOpState::OPSTATE_IN_PROGRESS);
 +    if (ret < 0) {
 +      ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
 +      return ret;
 +    }
 +    RGWRadosPutObj cb(&processor, &opstate);
 +    string etag;
 +    map<string, string> req_headers;
 +    time_t set_mtime;
 +   
 +    ret = conn->get_obj(user_id, info, src_obj, true, &cb, &in_stream_req);
 +    if (ret < 0)
 +      goto set_err_state;
 +
 +    ret = conn->complete_request(in_stream_req, etag, &set_mtime, req_headers);
 +    if (ret < 0)
 +      goto set_err_state;
 +
 +    { /* opening scope so that we can do goto, sorry */
 +      bufferlist& extra_data_bl = processor.get_extra_data();
 +      if (extra_data_bl.length()) {
 +        JSONParser jp;
 +        if (!jp.parse(extra_data_bl.c_str(), extra_data_bl.length())) {
 +          ldout(cct, 0) << "failed to parse response extra data. len=" << extra_data_bl.length() << " data=" << extra_data_bl.c_str() << dendl;
 +          goto set_err_state;
 +        }
 +
 +        JSONDecoder::decode_json("attrs", src_attrs, &jp);
 +
 +        src_attrs.erase(RGW_ATTR_MANIFEST); // not interested in original object layout
 +      }
 +    }
 +
 +    set_copy_attrs(src_attrs, attrs, replace_attrs, !source_zone.empty());
 +
 +    ret = cb.complete(etag, mtime, set_mtime, src_attrs);
 +    if (ret < 0)
 +      goto set_err_state;
 +
 +    ret = opstate.set_state(RGWOpState::OPSTATE_COMPLETE);
 +    if (ret < 0) {
 +      ldout(cct, 0) << "ERROR: failed to set opstate ret=" << ret << dendl;
 +    }
 +
 +    return 0;
 +set_err_state:
 +    int r = opstate.set_state(RGWOpState::OPSTATE_ERROR);
 +    if (r < 0) {
 +      ldout(cct, 0) << "ERROR: failed to set opstate r=" << ret << dendl;
 +    }
 +    return ret;
    }
 -  attrset.erase(RGW_ATTR_ID_TAG);
 +  set_copy_attrs(src_attrs, attrs, replace_attrs, false);
++  src_attrs.erase(RGW_ATTR_ID_TAG);
  
    RGWObjManifest manifest;
    RGWObjState *astate = NULL;
@@@ -3917,33 -2702,27 +3920,32 @@@ int RGWRados::get_obj(void *ctx, RGWObj
      r = append_atomic_test(rctx, read_obj, op, &astate);
      if (r < 0)
        goto done_ret;
-   }
  
-   if (objv_tracker) {
-     objv_tracker->prepare_op_for_read(&op);
-   }
+     if (astate) {
+       if (!ofs && astate->data.length() >= len) {
+         bl = astate->data;
+         goto done;
+       }
  
-   read_len = len;
+       if (ofs < astate->data.length()) {
+         unsigned copy_len = min((uint64_t)astate->data.length() - ofs, len);
+         astate->data.copy(ofs, copy_len, bl);
+         read_len -= copy_len;
+         read_ofs += copy_len;
+         if (!read_len)
+         goto done;
  
-   if (astate) {
-     if (!ofs && astate->data.length() >= len) {
-       bl = astate->data;
-       goto done;
+         merge_bl = true;
+         pbl = &read_bl;
+       }
      }
+   }
  
-     if (ofs < astate->data.length()) {
-       unsigned copy_len = min((uint64_t)astate->data.length(), len);
-       astate->data.copy(ofs, copy_len, bl);
-       read_len -= copy_len;
-       read_ofs += copy_len;
-       if (!read_len)
-       goto done;
-       merge_bl = true;
-       pbl = &read_bl;
-     }
++  if (objv_tracker) {
++    objv_tracker->prepare_op_for_read(&op);
 +  }
 +
++
    ldout(cct, 20) << "rados->read obj-ofs=" << ofs << " read_ofs=" << read_ofs << " read_len=" << read_len << dendl;
    op.read(read_ofs, read_len, pbl, NULL);
  
index 04223dd00ce407203a9ac8cade57fe45eacdacae,a9fb136a4df97b120dc22d73fba39e1ee551ccc0..623bb0b5e16afe96f520e5bb69caa26c10b41277
@@@ -1119,10 -1208,10 +1144,10 @@@ RGWRESTMgr *RGWRESTMgr::get_resource_mg
    for (iter = resources_by_size.rbegin(); iter != resources_by_size.rend(); ++iter) {
      string& resource = iter->second;
      if (uri.compare(0, iter->first, resource) == 0 &&
-       (resource.size() == iter->first ||
-        resource[iter->first] == '/')) {
+       (uri.size() == iter->first ||
+        uri[iter->first] == '/')) {
        string suffix = uri.substr(iter->first);
 -      return resource_mgrs[resource]->get_resource_mgr(s, suffix);
 +      return resource_mgrs[resource]->get_resource_mgr(s, suffix, out_uri);
      }
    }
  
Simple merge
index 10f29df4b26fe9886491194cc7860240249309df,20aa02292c8f7aea50e0f1654e762ba8e9a89231..49894eae7ced03d0a78e0368c68ba9a2a5933f08
@@@ -34,19 -33,16 +34,19 @@@ int rgw_put_system_obj(RGWRados *rgwsto
    return ret;
  }
  
 -int rgw_get_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, string& key, bufferlist& bl, map<string, bufferlist> *pattrs)
 +int rgw_get_system_obj(RGWRados *rgwstore, void *ctx, rgw_bucket& bucket, const string& key, bufferlist& bl,
 +                       RGWObjVersionTracker *objv_tracker, time_t *pmtime, map<string, bufferlist> *pattrs)
  {
-   int ret;
    struct rgw_err err;
    void *handle = NULL;
    bufferlist::iterator iter;
    int request_len = READ_CHUNK_LEN;
    rgw_obj obj(bucket, key);
 +
    do {
-     ret = rgwstore->prepare_get_obj(ctx, obj, NULL, NULL, pattrs, NULL,
-                                   NULL, pmtime, NULL, NULL, NULL, NULL, objv_tracker, &handle, &err);
+     int ret = rgwstore->prepare_get_obj(ctx, obj, NULL, NULL, pattrs, NULL,
 -                                  NULL, NULL, NULL, NULL, NULL, NULL, &handle, &err);
++                                        NULL, pmtime, NULL, NULL, NULL, NULL,
++                                        objv_tracker, &handle, &err);
      if (ret < 0)
        return ret;
  
index 8cb28a2b314781645f84882b42d77f3d73f2d3d2,781fce46eda81728398598d1003630aec2dd0ec5..391c61d854cd080b0c19431761979a3c544a5311
@@@ -1675,8 -1640,10 +1677,11 @@@ int RGWUser::execute_add(RGWUserAdminOp
  
    user_info.max_buckets = op_state.get_max_buckets();
    user_info.suspended = op_state.get_suspension_status();
 +  user_info.system = op_state.system;
  
+   if (op_state.op_mask_specified)
+     user_info.op_mask = op_state.get_op_mask();
    // update the request
    op_state.set_user_info(user_info);
    op_state.set_populated();
@@@ -1873,9 -1840,9 +1878,12 @@@ int RGWUser::execute_modify(RGWUserAdmi
    if (op_state.max_buckets_specified)
      user_info.max_buckets = max_buckets;
  
 +  if (op_state.system_specified)
 +    user_info.system = op_state.system;
 +
+   if (op_state.op_mask_specified)
+     user_info.op_mask = op_state.get_op_mask();
    if (op_state.has_suspension_op()) {
      __u8 suspended = op_state.get_suspension_status();
      user_info.suspended = suspended;
index 5051b9abca498513e86bd8a29f11c57b95dbb551,42e6097dddfcb7d61fe9298bf0aa077eaf36cb2a..32bcf199001c9a6ef68cdfb633174469defd5830
@@@ -127,9 -138,8 +127,10 @@@ struct RGWUserAdminOpState 
    std::string display_name;
    uint32_t max_buckets;
    __u8 suspended;
 +  __u8 system;
    std::string caps;
 +  RGWObjVersionTracker objv;
+   uint32_t op_mask;
  
    // subuser attributes
    std::string subuser;
    bool user_email_specified;
    bool max_buckets_specified;
    bool perm_specified;
+   bool op_mask_specified;
    bool caps_specified;
    bool suspension_op;
 +  bool system_specified;
    bool key_op;
  
    // req parameters
      key_type = -1;
      perm_mask = 0;
      suspended = 0;
 +    system = 0;
+     op_mask = 0;
  
      existing_user = false;
      existing_key = false;
Simple merge