Skip to content

Commit

Permalink
core: Deprecate old MR modes
Browse files Browse the repository at this point in the history
FI_MR_BASIC / FI_MR_SCALABLE / FI_MR_UNSPEC / FI_LOCAL_MR have been
deprecated since verison 1.5. However, no mechanism was in place to
discourage their usage.

Add compiler directives to generate warning messages if these defintions
are used. Providers use internal version of these values to maintain
application compatibility w/o generating warning messages.

Signed-off-by: Jianxin Xiong <jianxin.xiong@intel.com>
  • Loading branch information
j-xiong committed Aug 3, 2024
1 parent 1698fa4 commit 2c364ea
Show file tree
Hide file tree
Showing 46 changed files with 126 additions and 124 deletions.
5 changes: 5 additions & 0 deletions include/ofi.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ extern "C" {
* These are used internally to avoid compiler warnings.
*/

#define OFI_MR_UNSPEC 0
#define OFI_MR_BASIC (1 << 0)
#define OFI_MR_SCALABLE (1 << 1)

#define OFI_LOCAL_MR (1ULL << 55)
#define OFI_REG_MR (1ULL << 59)

static inline int
Expand Down
6 changes: 3 additions & 3 deletions include/ofi_mr.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ static inline int ofi_mr_local(const struct fi_info *info)
if (info->domain_attr->mr_mode & FI_MR_LOCAL)
return 1;

if (info->domain_attr->mr_mode & ~(FI_MR_BASIC | FI_MR_SCALABLE))
if (info->domain_attr->mr_mode & ~(OFI_MR_BASIC | OFI_MR_SCALABLE))
return 0;

check_local_mr:
return (info->mode & FI_LOCAL_MR) ? 1 : 0;
return (info->mode & OFI_LOCAL_MR) ? 1 : 0;
}

#define OFI_MR_MODE_RMA_TARGET (FI_MR_RAW | FI_MR_VIRT_ADDR | \
Expand All @@ -101,7 +101,7 @@ static inline uint64_t ofi_mr_get_prov_mode(uint32_t version,
(user_info->domain_attr &&
!(user_info->domain_attr->mr_mode & FI_MR_LOCAL))) {
return (prov_info->domain_attr->mr_mode & FI_MR_LOCAL) ?
prov_info->mode | FI_LOCAL_MR : prov_info->mode;
prov_info->mode | OFI_LOCAL_MR : prov_info->mode;
} else {
return prov_info->mode;
}
Expand Down
12 changes: 5 additions & 7 deletions include/rdma/fabric.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,10 @@ enum fi_av_type {
FI_AV_TABLE
};

/* Named enum for backwards compatibility */
enum fi_mr_mode {
FI_MR_UNSPEC,
FI_MR_BASIC, /* (1 << 0) */
FI_MR_SCALABLE, /* (1 << 1) */
};
#define FI_MR_UNSPEC _Pragma("GCC warning \"'FI_MR_UNSPEC' is deprecated\"") (0)
#define FI_MR_BASIC _Pragma("GCC warning \"'FI_MR_BASIC' is deprecated\"") (1 << 0)
#define FI_MR_SCALABLE _Pragma("GCC warning \"'FI_MR_SCALABLE' is deprecated\"") (1 << 1)

#define FI_MR_LOCAL (1 << 2)
#define FI_MR_RAW (1 << 3)
#define FI_MR_VIRT_ADDR (1 << 4)
Expand Down Expand Up @@ -369,7 +367,7 @@ static inline uint8_t fi_tc_dscp_get(uint32_t tclass)
#define FI_MSG_PREFIX (1ULL << 58)
#define FI_ASYNC_IOV (1ULL << 57)
#define FI_RX_CQ_DATA (1ULL << 56)
#define FI_LOCAL_MR (1ULL << 55)
#define FI_LOCAL_MR _Pragma("GCC warning \"'FI_LOCAL_MR' is deprecated\"") (1ULL << 55)
/* #define FI_NOTIFY_FLAGS_ONLY (1ULL << 54) */
/* #define FI_RESTRICTED_COMP (1ULL << 53) */
#define FI_CONTEXT2 (1ULL << 52)
Expand Down
6 changes: 3 additions & 3 deletions man/fi_domain.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ The following values may be specified.
: Indicates that the memory regions associated with completion counters
must be explicitly enabled after being bound to any counter.

*FI_MR_UNSPEC*
*FI_MR_UNSPEC* (deprecated)
: Defined for compatibility -- library versions 1.4 and earlier. Setting
mr_mode to 0 indicates that FI_MR_BASIC or FI_MR_SCALABLE are requested
and supported.
Expand All @@ -584,14 +584,14 @@ The following values may be specified.
: Registered memory regions are referenced by peers using the virtual address
of the registered memory region, rather than a 0-based offset.

*FI_MR_BASIC*
*FI_MR_BASIC* (deprecated)
: Defined for compatibility -- library versions 1.4 and earlier. Only
basic memory registration operations are requested or supported.
This mode is equivalent to the FI_MR_VIRT_ADDR, FI_MR_ALLOCATED, and
FI_MR_PROV_KEY flags being set in later library versions. This flag
may not be used in conjunction with other mr_mode bits.

*FI_MR_SCALABLE*
*FI_MR_SCALABLE* (deprecated)
: Defined for compatibility -- library versions 1.4 and earlier.
Only scalable memory registration operations
are requested or supported. Scalable registration uses offset based
Expand Down
2 changes: 1 addition & 1 deletion man/fi_getinfo.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ supported set of modes will be returned in the info structure(s).
The requirements for using struct fi_context2 are identical as
defined for FI_CONTEXT above.

*FI_LOCAL_MR*
*FI_LOCAL_MR* (deprecated)
: The provider is optimized around having applications register memory
for locally accessed data buffers. Data buffers used in send and
receive operations and as the source buffer for RMA and atomic
Expand Down
2 changes: 1 addition & 1 deletion man/fi_mr.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ The following apply to memory registration.
desc parameter is NULL, any required local memory registration will be handled
by the provider.
*Basic Memory Registration*
*Basic Memory Registration* (deprecated)
: Basic memory registration was deprecated in libfabric version 1.5, but
is supported for backwards compatibility. Basic memory registration
is indicated by setting mr_mode equal to FI_MR_BASIC.
Expand Down
2 changes: 1 addition & 1 deletion man/fi_verbs.7.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Verbs provider requires applications to support the following modes:

#### FI_EP_MSG endpoint type

* FI_LOCAL_MR / FI_MR_LOCAL mr mode.
* FI_MR_LOCAL mr mode.

* FI_RX_CQ_DATA for applications that want to use RMA. Applications must
take responsibility of posting receives for any incoming CQ data.
Expand Down
2 changes: 1 addition & 1 deletion prov/efa/src/efa_prov_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const struct fi_domain_attr efa_domain_attr = {
.control_progress = FI_PROGRESS_AUTO,
.data_progress = FI_PROGRESS_AUTO,
.resource_mgmt = FI_RM_DISABLED,
.mr_mode = OFI_MR_BASIC_MAP | FI_MR_LOCAL | FI_MR_BASIC,
.mr_mode = OFI_MR_BASIC_MAP | FI_MR_LOCAL | OFI_MR_BASIC,
.mr_key_size = sizeof_field(struct ibv_sge, lkey),
.cq_data_size = 0,
.tx_ctx_cnt = 1024,
Expand Down
2 changes: 1 addition & 1 deletion prov/mrail/src/mrail_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct fi_domain_attr mrail_domain_attr = {
.data_progress = FI_PROGRESS_AUTO,
.resource_mgmt = FI_RM_ENABLED,
.av_type = FI_AV_UNSPEC,
.mr_mode = FI_MR_BASIC | FI_MR_SCALABLE | FI_MR_RAW,
.mr_mode = OFI_MR_BASIC | OFI_MR_SCALABLE | FI_MR_RAW,
.mr_key_size = SIZE_MAX,
.cq_data_size = SIZE_MAX,
.cq_cnt = SIZE_MAX,
Expand Down
2 changes: 1 addition & 1 deletion prov/mrail/src/mrail_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static struct fi_info *mrail_create_core_hints(const struct fi_info *hints)
core_hints->mode &= MRAIL_PASSTHRU_MODES;

if (core_hints->domain_attr) {
if (core_hints->domain_attr->mr_mode == FI_MR_BASIC)
if (core_hints->domain_attr->mr_mode == OFI_MR_BASIC)
core_hints->domain_attr->mr_mode = OFI_MR_BASIC_MAP;
removed_mr_mode = core_hints->domain_attr->mr_mode &
~MRAIL_PASSTHRU_MR_MODES;
Expand Down
6 changes: 3 additions & 3 deletions prov/opx/configure.m4
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ AC_DEFUN([FI_OPX_CONFIGURE],[
AC_DEFINE_UNQUOTED(OPX_AV, [$OPX_AV_MODE], [fabric direct address vector])
AS_CASE([x$OPX_MR],
[xscalable], [OPX_MR_MODE=FI_MR_SCALABLE],
[xbasic], [OPX_MR_MODE=FI_MR_BASIC],
[OPX_MR_MODE=FI_MR_SCALABLE])
[xscalable], [OPX_MR_MODE=OFI_MR_SCALABLE],
[xbasic], [OPX_MR_MODE=OFI_MR_BASIC],
[OPX_MR_MODE=OFI_MR_SCALABLE])
AC_SUBST(opx_mr, [$OPX_MR_MODE])
AC_DEFINE_UNQUOTED(OPX_MR, [$OPX_MR_MODE], [fabric direct memory region])
Expand Down
2 changes: 1 addition & 1 deletion prov/opx/include/rdma/opx/fi_opx_domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ struct fi_opx_domain {

enum fi_threading threading;
enum fi_resource_mgmt resource_mgmt;
enum fi_mr_mode mr_mode;
int mr_mode;
enum fi_progress data_progress;

uuid_t unique_job_key;
Expand Down
2 changes: 1 addition & 1 deletion prov/opx/src/fi_opx_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ int fi_opx_check_domain_attr(struct fi_domain_attr *attr)
goto err;
}

if (attr->mr_mode == FI_MR_UNSPEC) {
if (attr->mr_mode == OFI_MR_UNSPEC) {
attr->mr_mode = FI_OPX_BASE_MR_MODE;
}

Expand Down
4 changes: 2 additions & 2 deletions prov/opx/src/fi_opx_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,8 @@ static void do_static_assert_tests()
"sizeof(fi_opx_hmem_info) >> 3 != OPX_HMEM_SIZE_QWS") ;
OPX_COMPILE_TIME_ASSERT(OPX_HFI1_TID_PAGESIZE == 4096,
"OPX_HFI1_TID_PAGESIZE must be 4K!");
OPX_COMPILE_TIME_ASSERT(OPX_MR != FI_MR_UNSPEC,
"OPX_MR should be set to FI_MR_SCALABLE or FI_MR_BASIC, not FI_MR_UNSPEC");
OPX_COMPILE_TIME_ASSERT(OPX_MR != OFI_MR_UNSPEC,
"OPX_MR should be set to 'FI_MR_SCALABLE' or 'FI_MR_BASIC', not 'FI_MR_UNSPEC'");
}
#pragma GCC diagnostic pop

Expand Down
16 changes: 8 additions & 8 deletions prov/opx/src/fi_opx_mr.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static int fi_opx_close_mr(fid_t fid)
HASH_DEL(opx_domain->mr_hashmap, opx_mr);

int ret = 0;
if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
ret = fi_opx_ref_dec(&opx_domain->ref_cnt, "domain");
if (ret) {
FI_WARN(fi_opx_global.prov, FI_LOG_MR,
Expand Down Expand Up @@ -129,7 +129,7 @@ static inline int fi_opx_mr_reg_internal(struct fid *fid,

opx_domain = (struct fi_opx_domain *) container_of(fid, struct fid_domain, fid);

if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
if (requested_key >= opx_domain->num_mr_keys) {
/* requested key is too large */
errno = FI_EKEYREJECTED;
Expand Down Expand Up @@ -182,7 +182,7 @@ static inline int fi_opx_mr_reg_internal(struct fid *fid,
}
opx_mr->attr.requested_key = opx_mr->mr_fid.key;

if (opx_mr->domain->mr_mode & FI_MR_SCALABLE) {
if (opx_mr->domain->mr_mode & OFI_MR_SCALABLE) {
fi_opx_ref_inc(&opx_mr->domain->ref_cnt, "domain");
}
HASH_ADD(hh, opx_domain->mr_hashmap,
Expand Down Expand Up @@ -224,7 +224,7 @@ static inline int fi_opx_mr_reg_internal(struct fid *fid,
opx_mr->mr_fid.fid.fclass = FI_CLASS_MR;
opx_mr->mr_fid.fid.context = context;
opx_mr->mr_fid.fid.ops = &fi_opx_fi_ops;
if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
opx_mr->mr_fid.key = requested_key;
}

Expand All @@ -236,7 +236,7 @@ static inline int fi_opx_mr_reg_internal(struct fid *fid,
opx_mr->flags = flags;
opx_mr->domain = opx_domain;

if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
fi_opx_ref_inc(&opx_domain->ref_cnt, "domain");
}
HASH_ADD(hh, opx_domain->mr_hashmap,
Expand Down Expand Up @@ -315,13 +315,13 @@ int fi_opx_init_mr_ops(struct fid_domain *domain, struct fi_info *info)
struct fi_opx_domain *opx_domain =
container_of(domain, struct fi_opx_domain, domain_fid);

if (info->domain_attr->mr_mode == FI_MR_UNSPEC) goto err;
if (info->domain_attr->mr_mode == OFI_MR_UNSPEC) goto err;

opx_domain->domain_fid.mr = &fi_opx_mr_ops;

opx_domain->mr_mode = info->domain_attr->mr_mode;

if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
opx_domain->num_mr_keys = UINT64_MAX;
}
return 0;
Expand All @@ -335,7 +335,7 @@ int fi_opx_finalize_mr_ops(struct fid_domain *domain)
struct fi_opx_domain *opx_domain =
container_of(domain, struct fi_opx_domain, domain_fid);

if (opx_domain->mr_mode & FI_MR_SCALABLE) {
if (opx_domain->mr_mode & OFI_MR_SCALABLE) {
opx_domain->num_mr_keys = 0;
}
return 0;
Expand Down
2 changes: 1 addition & 1 deletion prov/opx/src/opx_hmem_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ void opx_hmem_cache_delete_region(struct ofi_mr_cache *cache,
}
opx_mr->hmem_dev_reg_handle = 0UL;

if (opx_mr->domain->mr_mode & FI_MR_SCALABLE) {
if (opx_mr->domain->mr_mode & OFI_MR_SCALABLE) {
int ret = fi_opx_ref_dec(&opx_mr->domain->ref_cnt, "domain");
if (ret) {
FI_WARN(fi_opx_global.prov, FI_LOG_MR,
Expand Down
2 changes: 1 addition & 1 deletion prov/psm2/src/psmx2.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ struct psmx2_fid_domain {
uint64_t caps;
psm2_uuid_t uuid;

enum fi_mr_mode mr_mode;
int mr_mode;
ofi_spin_t mr_lock;
uint64_t mr_reserved_key;
RbtHandle mr_map;
Expand Down
6 changes: 3 additions & 3 deletions prov/psm2/src/psmx2_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ static struct fi_domain_attr psmx2_domain_attr = {
.data_progress = FI_PROGRESS_AUTO,
.resource_mgmt = FI_RM_ENABLED,
.av_type = FI_AV_UNSPEC,
.mr_mode = FI_MR_SCALABLE | FI_MR_BASIC,
.mr_mode = OFI_MR_SCALABLE | OFI_MR_BASIC,
.mr_key_size = sizeof(uint64_t),
.cq_data_size = 0, /* 4, 8 */
.cq_cnt = 65535,
Expand Down Expand Up @@ -420,8 +420,8 @@ void psmx2_alter_prov_info(uint32_t api_version,
info->domain_attr->data_progress =
FI_PROGRESS_MANUAL;

if (info->domain_attr->mr_mode == (FI_MR_BASIC | FI_MR_SCALABLE))
info->domain_attr->mr_mode = FI_MR_SCALABLE;
if (info->domain_attr->mr_mode == (OFI_MR_BASIC | OFI_MR_SCALABLE))
info->domain_attr->mr_mode = OFI_MR_SCALABLE;

/*
* Avoid automatically adding secondary caps that may negatively
Expand Down
2 changes: 1 addition & 1 deletion prov/psm2/src/psmx2_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ int psmx2_domain_open(struct fid_fabric *fabric, struct fi_info *info,
struct psmx2_fid_fabric *fabric_priv;
struct psmx2_fid_domain *domain_priv;
struct psmx2_ep_name *src_addr = info->src_addr;
int mr_mode = (info->domain_attr->mr_mode & FI_MR_BASIC) ? FI_MR_BASIC : 0;
int mr_mode = (info->domain_attr->mr_mode & OFI_MR_BASIC) ? OFI_MR_BASIC : 0;
int err, tmp;

FI_INFO(&psmx2_prov, FI_LOG_DOMAIN, "\n");
Expand Down
10 changes: 5 additions & 5 deletions prov/psm2/src/psmx2_mr.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static int psmx2_mr_reserve_key(struct psmx2_fid_domain *domain,

domain->mr_lock_fn(&domain->mr_lock, 1);

if (domain->mr_mode == FI_MR_BASIC) {
if (domain->mr_mode == OFI_MR_BASIC) {
key = domain->mr_reserved_key;
try_count = 10000; /* large enough */
} else {
Expand All @@ -84,7 +84,7 @@ static int psmx2_mr_reserve_key(struct psmx2_fid_domain *domain,
for (i=0; i<try_count; i++, key++) {
if (!rbtFind(domain->mr_map, (void *)key)) {
if (!rbtInsert(domain->mr_map, (void *)key, mr)) {
if (domain->mr_mode == FI_MR_BASIC)
if (domain->mr_mode == OFI_MR_BASIC)
domain->mr_reserved_key = key + 1;
*assigned_key = key;
err = 0;
Expand Down Expand Up @@ -314,7 +314,7 @@ STATIC int psmx2_mr_reg(struct fid *fid, const void *buf, size_t len,
mr_priv->iov_count = 1;
mr_priv->iov[0].iov_base = (void *)buf;
mr_priv->iov[0].iov_len = len;
mr_priv->offset = (domain_priv->mr_mode == FI_MR_BASIC) ? 0 :
mr_priv->offset = (domain_priv->mr_mode == OFI_MR_BASIC) ? 0 :
((uint64_t)mr_priv->iov[0].iov_base - offset);

*mr = &mr_priv->mr;
Expand Down Expand Up @@ -369,7 +369,7 @@ STATIC int psmx2_mr_regv(struct fid *fid,
for (i=0; i<count; i++)
mr_priv->iov[i] = iov[i];
psmx2_mr_normalize_iov(mr_priv->iov, &mr_priv->iov_count);
mr_priv->offset = (domain_priv->mr_mode == FI_MR_BASIC) ? 0 :
mr_priv->offset = (domain_priv->mr_mode == OFI_MR_BASIC) ? 0 :
((uint64_t)mr_priv->iov[0].iov_base - offset);

*mr = &mr_priv->mr;
Expand Down Expand Up @@ -422,7 +422,7 @@ STATIC int psmx2_mr_regattr(struct fid *fid, const struct fi_mr_attr *attr,
for (i=0; i<attr->iov_count; i++)
mr_priv->iov[i] = attr->mr_iov[i];
psmx2_mr_normalize_iov(mr_priv->iov, &mr_priv->iov_count);
mr_priv->offset = (domain_priv->mr_mode == FI_MR_BASIC) ? 0 :
mr_priv->offset = (domain_priv->mr_mode == OFI_MR_BASIC) ? 0 :
((uint64_t)mr_priv->iov[0].iov_base - attr->offset);

*mr = &mr_priv->mr;
Expand Down
2 changes: 1 addition & 1 deletion prov/psm3/src/psmx3.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ struct psmx3_fid_domain {
uint64_t mode;
uint64_t caps;

enum fi_mr_mode mr_mode;
int mr_mode;
ofi_spin_t mr_lock;
uint64_t mr_reserved_key;
RbtHandle mr_map;
Expand Down
6 changes: 3 additions & 3 deletions prov/psm3/src/psmx3_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ static struct fi_domain_attr psmx3_domain_attr = {
.data_progress = FI_PROGRESS_AUTO,
.resource_mgmt = FI_RM_ENABLED,
.av_type = FI_AV_UNSPEC,
.mr_mode = FI_MR_SCALABLE | FI_MR_BASIC,
.mr_mode = OFI_MR_SCALABLE | OFI_MR_BASIC,
.mr_key_size = sizeof(uint64_t),
.cq_data_size = 0, /* 4, 8 */
.cq_cnt = 65535,
Expand Down Expand Up @@ -743,8 +743,8 @@ void psmx3_alter_prov_info(uint32_t api_version,
info->domain_attr->data_progress =
FI_PROGRESS_MANUAL;

if (info->domain_attr->mr_mode == (FI_MR_BASIC | FI_MR_SCALABLE))
info->domain_attr->mr_mode = FI_MR_SCALABLE;
if (info->domain_attr->mr_mode == (OFI_MR_BASIC | OFI_MR_SCALABLE))
info->domain_attr->mr_mode = OFI_MR_SCALABLE;

/*
* Avoid automatically adding secondary caps that may negatively
Expand Down
2 changes: 1 addition & 1 deletion prov/psm3/src/psmx3_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ int psmx3_domain_open(struct fid_fabric *fabric, struct fi_info *info,
struct psmx3_fid_fabric *fabric_priv;
struct psmx3_fid_domain *domain_priv;
struct psmx3_ep_name *src_addr = info->src_addr;
int mr_mode = (info->domain_attr->mr_mode & FI_MR_BASIC) ? FI_MR_BASIC : 0;
int mr_mode = (info->domain_attr->mr_mode & OFI_MR_BASIC) ? OFI_MR_BASIC : 0;
int err;

PSMX3_INFO(&psmx3_prov, FI_LOG_DOMAIN, "\n");
Expand Down
Loading

0 comments on commit 2c364ea

Please sign in to comment.