rgw_file: fixup attrs across renames

Once Unix attributes were materialized as RGW object/bucket
attributes, it became possible to verify the serialized bucket and
object hashes with the expected values (based on the file-type
invariant path to the object).

Prior to this change, we saved the serialized hash values with the
rest of the Unix attrs, in RGW_ATTR_UNIX1.  Unfortunately, these
values were invalidated by rename operations.  To address this problem,
and to faciliate future operations on objects by their hashed ids,
the id hashes have been moved into their own RGW attr
RGW_ATTR_UNIX_KEY1.  This should allow more efficient search by, but
more importantly to the invalidation problem, allows us to use the
ATTRSMOD_MERGE behavior in RGWCopyObj to get copy offload while still
fixing up the object id.

The code at this commit doesn't use the serialized unix_mode value as
the outgoing st.st_mode result for rgw_getattr operations, pending a
bugfix for Ganesha's expected value range.

Signed-off-by: Matt Benjamin <mbenjamin@redhat.com>
This commit is contained in:
Matt Benjamin 2016-04-13 19:46:25 -04:00
parent b6297a704b
commit a353eaca61
3 changed files with 85 additions and 32 deletions

View File

@ -96,7 +96,8 @@ using ceph::crypto::MD5;
#define RGW_ATTR_OLH_PENDING_PREFIX RGW_ATTR_OLH_PREFIX "pending."
/* RGW File Attributes */
#define RGW_ATTR_UNIX1 RGW_ATTR_PREFIX "unix1"
#define RGW_ATTR_UNIX_KEY1 RGW_ATTR_PREFIX "unix-key1"
#define RGW_ATTR_UNIX1 RGW_ATTR_PREFIX "unix1"
#define RGW_BUCKETS_OBJ_SUFFIX ".buckets"

View File

@ -55,9 +55,10 @@ namespace rgw {
if (get<0>(fhr)) {
RGWFileHandle* rgw_fh = get<0>(fhr);
/* restore attributes */
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_attrs) {
rgw_fh->decode_attrs(ux_attrs);
if (ux_key && ux_attrs) {
rgw_fh->decode_attrs(ux_key, ux_attrs);
}
}
}
@ -118,9 +119,10 @@ namespace rgw {
rgw_fh->set_size(req.get_size());
rgw_fh->set_mtime(real_clock::to_timespec(req.get_mtime()));
/* restore attributes */
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_attrs) {
rgw_fh->decode_attrs(ux_attrs);
if (ux_key && ux_attrs) {
rgw_fh->decode_attrs(ux_key, ux_attrs);
}
}
goto done;
@ -143,9 +145,10 @@ namespace rgw {
rgw_fh->set_size(req.get_size());
rgw_fh->set_mtime(real_clock::to_timespec(req.get_mtime()));
/* restore attributes */
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_attrs) {
rgw_fh->decode_attrs(ux_attrs);
if (ux_key && ux_attrs) {
rgw_fh->decode_attrs(ux_key, ux_attrs);
}
}
goto done;
@ -321,7 +324,7 @@ namespace rgw {
LookupFHResult fhr;
RGWFileHandle* rgw_fh = nullptr;
buffer::list ux_attrs;
buffer::list ux_key, ux_attrs;
fhr = lookup_fh(parent, name,
RGWFileHandle::FLAG_CREATE|
@ -332,7 +335,7 @@ namespace rgw {
rgw_fh->create_stat(st, mask);
rgw_fh->set_times(real_clock::now());
/* save attrs */
rgw_fh->encode_attrs(ux_attrs);
rgw_fh->encode_attrs(ux_key, ux_attrs);
rgw_fh->stat(st);
get<0>(mkr) = rgw_fh;
} else {
@ -355,7 +358,11 @@ namespace rgw {
string uri = "/" + bname; /* XXX get rid of URI some day soon */
RGWCreateBucketRequest req(get_context(), get_user(), uri);
/* save attrs */
req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
rc = rgwlib.get_fe()->execute_req(&req);
rc2 = req.get_ret();
} else {
@ -369,9 +376,14 @@ namespace rgw {
dir_name += "/";
dir_name += name;
dir_name += "/";
RGWPutObjRequest req(get_context(), get_user(), parent->bucket_name(),
dir_name, bl);
/* save attrs */
req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
rc = rgwlib.get_fe()->execute_req(&req);
rc2 = req.get_ret();
}
@ -549,15 +561,24 @@ namespace rgw {
} while (! stop);
} /* RGWLibFS::gc */
void RGWFileHandle::encode_attrs(buffer::list& bl)
void RGWFileHandle::encode_attrs(ceph::buffer::list& ux_key1,
ceph::buffer::list& ux_attrs1)
{
rgw::encode(*this, bl);
} /* RGWFileHandle::decode_attrs */
fh_key fhk(this->fh.fh_hk);
rgw::encode(fhk, ux_key1);
rgw::encode(*this, ux_attrs1);
} /* RGWFileHandle::encode_attrs */
void RGWFileHandle::decode_attrs(const buffer::list* cbl)
void RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
const ceph::buffer::list* ux_attrs1)
{
auto bl_iter = const_cast<buffer::list*>(cbl)->begin();
rgw::decode(*this, bl_iter);
fh_key fhk;
auto bl_iter_key1 = const_cast<buffer::list*>(ux_key1)->begin();
rgw::decode(fhk, bl_iter_key1);
assert(this->fh.fh_hk == fhk.fh_hk);
auto bl_iter_unix1 = const_cast<buffer::list*>(ux_attrs1)->begin();
rgw::decode(*this, bl_iter_unix1);
} /* RGWFileHandle::decode_attrs */
bool RGWFileHandle::reclaim() {
@ -779,7 +800,7 @@ namespace rgw {
int RGWWriteRequest::exec_finish()
{
buffer::list bl, aclbl, bl_unix;
buffer::list bl, aclbl, ux_key, ux_attrs;
map<string, string>::iterator iter;
char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
@ -806,8 +827,9 @@ namespace rgw {
policy.encode(aclbl);
emplace_attr(RGW_ATTR_ACL, std::move(aclbl));
rgw_fh->encode_attrs(bl_unix);
emplace_attr(RGW_ATTR_UNIX1, std::move(bl_unix));
rgw_fh->encode_attrs(ux_key, ux_attrs);
emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end();
++iter) {

View File

@ -100,8 +100,24 @@ namespace rgw {
fh_hk.bucket = XXH64(_b.c_str(), _o.length(), seed);
fh_hk.object = XXH64(_o.c_str(), _o.length(), seed);
}
void encode(buffer::list& bl) const {
ENCODE_START(1, 1, bl);
::encode(fh_hk.bucket, bl);
::encode(fh_hk.object, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
DECODE_START(1, bl);
::decode(fh_hk.bucket, bl);
::decode(fh_hk.object, bl);
DECODE_FINISH(bl);
}
}; /* fh_key */
WRITE_CLASS_ENCODER(fh_key);
inline bool operator<(const fh_key& lhs, const fh_key& rhs)
{
return ((lhs.fh_hk.bucket < rhs.fh_hk.bucket) ||
@ -326,10 +342,10 @@ namespace rgw {
if (mask & RGW_SETATTR_MODE) {
switch (fh.fh_type) {
case RGW_FS_TYPE_DIRECTORY:
st->st_mode = state.unix_mode|S_IFDIR;
state.unix_mode = st->st_mode|S_IFDIR;
break;
case RGW_FS_TYPE_FILE:
st->st_mode = state.unix_mode|S_IFREG;
state.unix_mode = st->st_mode|S_IFREG;
default:
break;
}
@ -353,11 +369,11 @@ namespace rgw {
switch (fh.fh_type) {
case RGW_FS_TYPE_DIRECTORY:
st->st_mode = RGW_RWXMODE|S_IFDIR;
st->st_mode = RGW_RWXMODE|S_IFDIR /* state.unix_mode|S_IFDIR */;
st->st_nlink = 3;
break;
case RGW_FS_TYPE_FILE:
st->st_mode = RGW_RWMODE|S_IFREG;
st->st_mode = RGW_RWMODE|S_IFREG /* state.unix_mode|S_IFREG */;
st->st_nlink = 1;
st->st_blksize = 4096;
st->st_size = state.size;
@ -430,7 +446,7 @@ namespace rgw {
return fh_key(fhk.fh_hk.object, name.c_str());
else {
std::string key_name = make_key_name(name.c_str());
return fh_key(fhk.fh_hk.object, key_name.c_str());
return fh_key(fhk.fh_hk.bucket, key_name.c_str());
}
}
@ -528,8 +544,6 @@ namespace rgw {
void encode(buffer::list& bl) const {
ENCODE_START(1, 1, bl);
::encode(uint32_t(fh.fh_type), bl);
::encode(fh.fh_hk.bucket, bl);
::encode(fh.fh_hk.object, bl);
::encode(state.dev, bl);
::encode(state.size, bl);
::encode(state.nlink, bl);
@ -544,13 +558,9 @@ namespace rgw {
void decode(bufferlist::iterator& bl) {
DECODE_START(1, bl);
struct rgw_file_handle tfh;
uint32_t fh_type;
::decode(fh_type, bl);
tfh.fh_type = static_cast<enum rgw_fh_type>(fh_type);
::decode(tfh.fh_hk.bucket, bl);
::decode(tfh.fh_hk.object, bl);
assert(fh.fh_hk == tfh.fh_hk);
assert(fh.fh_type == fh_type);
::decode(state.dev, bl);
::decode(state.size, bl);
::decode(state.nlink, bl);
@ -565,9 +575,11 @@ namespace rgw {
DECODE_FINISH(bl);
}
void decode_attrs(const ceph::buffer::list* bl);
void encode_attrs(ceph::buffer::list& ux_key1,
ceph::buffer::list& ux_attrs1);
void encode_attrs(ceph::buffer::list& bl);
void decode_attrs(const ceph::buffer::list* ux_key1,
const ceph::buffer::list* ux_attrs1);
virtual bool reclaim();
@ -801,6 +813,12 @@ namespace rgw {
std::string obj_name{name};
std::string key_name{parent->make_key_name(name)};
lsubdout(get_context(), rgw, 10)
<< __func__ << " lookup called on "
<< parent->object_name() << " for " << key_name
<< " (" << obj_name << ")"
<< dendl;
fh_key fhk = parent->make_fhk(key_name);
retry:
@ -1972,7 +1990,11 @@ public:
const std::string& _src_name, const std::string& _dst_name)
: RGWLibRequest(_cct, _user), src_parent(_src_parent),
dst_parent(_dst_parent), src_name(_src_name), dst_name(_dst_name) {
/* all requests have this */
op = this;
/* allow this request to replace selected attrs */
attrs_mod = RGWRados::ATTRSMOD_MERGE;
}
virtual bool only_bucket() { return true; }
@ -2008,6 +2030,14 @@ public:
if (! valid_s3_object_name(dest_object))
return -ERR_INVALID_OBJECT_NAME;
/* XXX and fixup key attr (could optimize w/string ref and
* dest_object) */
buffer::list ux_key;
std::string key_name{dst_parent->make_key_name(dst_name.c_str())};
fh_key fhk = dst_parent->make_fhk(key_name);
rgw::encode(fhk, ux_key);
emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
#if 0 /* XXX needed? */
s->relative_uri = uri;
s->info.request_uri = uri; // XXX