Actions
Bug #38327
closedrgw_file: can't retrieve etag of empty object written through NFS
% Done:
0%
Source:
Tags:
Backport:
luminous, mimic, nautilus
Regression:
No
Severity:
3 - minor
Reviewed:
Description
Hi all, it seems that empty file written by NFS will get a empty etag and acls.
ceph version: V12.2.5
nfs-ganesha version: V2.6.2
Way to reproduce:¶
1.start nfs-ganesha server
2.mount export to local, like /mnt
3.cd /mnt && touch empty_file
run a python script in order to get object infoļ¼
import boto3
s3 = boto3.client(
's3',
aws_access_key_id="xxx",
aws_secret_access_key="xxx",
endpoint_url="rgw_endpoint_addr")
response = s3.list_objects(
Bucket='bucket_name'
)
print(response)
here is the results:
{
'Name':'bucket1',
'ResponseMetadata':{
'HTTPStatusCode':200,
'RetryAttempts':0,
'HostId':'',
'RequestId':'tx00000000000000000000d-005c663612-114b-default',
'HTTPHeaders':{
'transfer-encoding':'chunked',
'date':'Fri, 15 Feb 2019 03:46:26 GMT',
'x-amz-request-id':'tx00000000000000000000d-005c663612-114b-default',
'content-type':'application/xml'
}
},
'MaxKeys':1000,
'Prefix':'',
'Marker':'',
'EncodingType':'url',
'IsTruncated':False,
'Contents':[
{
'LastModified':datetime.datetime(2019,2,13,6,34,52,478000,tzinfo=tzutc()),
'ETag':'""',
'StorageClass':'STANDARD',
'Key':'ccc',
'Owner':{
'DisplayName':'',
'ID':''
},
'Size':0
}
]
}
ETag got nothing.
Way to resolve¶
NFS will send a setattr request to backend when create request is done.
In rgw_setattr function, only RGW_ATTR_UNIX_KEY1 and RGW_ATTR_UNIX1 are saved to request, RGW_ATTR_ETAG and RGW_ATTR_ACL are forgotten. though RGW_ATTR_ETAG and RGW_ATTR_ACL are written in rgw_create step, by these two attrs will be efface in rgw_setattr:
int RGWLibFS::setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
uint32_t flags)
{
int rc, rc2;
buffer::list ux_key, ux_attrs;
lock_guard guard(rgw_fh->mtx);
switch(rgw_fh->fh.fh_type) {
case RGW_FS_TYPE_FILE:
{
if (rgw_fh->deleted())
return -ESTALE;
}
break;
default:
break;
};
string obj_name{rgw_fh->relative_object_name()};
if (rgw_fh->is_dir() &&
(likely(! rgw_fh->is_bucket()))) {
obj_name += "/";
}
RGWSetAttrsRequest req(cct, get_user(), rgw_fh->bucket_name(), obj_name);
rgw_fh->create_stat(st, mask);
rgw_fh->encode_attrs(ux_key, ux_attrs);
/* 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();
if (rc == -ENOENT) {
/* special case: materialize placeholder dir */
buffer::list bl;
RGWPutObjRequest req(get_context(), get_user(), rgw_fh->bucket_name(),
obj_name, bl);
rgw_fh->encode_attrs(ux_key, ux_attrs); /* because std::moved */
/* 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();
}
if ((rc != 0) || (rc2 != 0)) {
return -EIO;
}
rgw_fh->set_ctime(real_clock::to_timespec(real_clock::now()));
return 0;
} /* RGWLibFS::setattr */
So I think it will be better to save RGW_ATTR_ETAG and RGW_ATTR_ACL attr in rgw_setattr function.
Actions