2014-07-09 18:49:15

by Steve Wise

[permalink] [raw]
Subject: [PATCH] svcrdma: send_write() must not overflow the device's max sge

Function send_write() must stop creating sges when it reaches the device
max and return the amount sent in the RDMA Write to the caller.

Signed-off-by: Steve Wise <[email protected]>
---

net/sunrpc/xprtrdma/svc_rdma_sendto.c | 39 +++++++++++++--------------------
1 files changed, 15 insertions(+), 24 deletions(-)

diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 49fd21a..9f1b506 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -192,6 +192,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
xdr_sge_no++;
BUG_ON(xdr_sge_no > vec->count);
bc -= sge_bytes;
+ if (sge_no == xprt->sc_max_sge)
+ break;
}

/* Prepare WRITE WR */
@@ -209,7 +211,7 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
atomic_inc(&rdma_stat_write);
if (svc_rdma_send(xprt, &write_wr))
goto err;
- return 0;
+ return write_len - bc;
err:
svc_rdma_unmap_dma(ctxt);
svc_rdma_put_context(ctxt, 0);
@@ -225,7 +227,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
{
u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
int write_len;
- int max_write;
u32 xdr_off;
int chunk_off;
int chunk_no;
@@ -239,8 +240,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
res_ary = (struct rpcrdma_write_array *)
&rdma_resp->rm_body.rm_chunks[1];

- max_write = xprt->sc_max_sge * PAGE_SIZE;
-
/* Write chunks start at the pagelist */
for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
xfer_len && chunk_no < arg_ary->wc_nchunks;
@@ -260,23 +259,21 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
write_len);
chunk_off = 0;
while (write_len) {
- int this_write;
- this_write = min(write_len, max_write);
ret = send_write(xprt, rqstp,
ntohl(arg_ch->rs_handle),
rs_offset + chunk_off,
xdr_off,
- this_write,
+ write_len,
vec);
- if (ret) {
+ if (ret <= 0) {
dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
ret);
return -EIO;
}
- chunk_off += this_write;
- xdr_off += this_write;
- xfer_len -= this_write;
- write_len -= this_write;
+ chunk_off += ret;
+ xdr_off += ret;
+ xfer_len -= ret;
+ write_len -= ret;
}
}
/* Update the req with the number of chunks actually used */
@@ -293,7 +290,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
{
u32 xfer_len = rqstp->rq_res.len;
int write_len;
- int max_write;
u32 xdr_off;
int chunk_no;
int chunk_off;
@@ -311,8 +307,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
res_ary = (struct rpcrdma_write_array *)
&rdma_resp->rm_body.rm_chunks[2];

- max_write = xprt->sc_max_sge * PAGE_SIZE;
-
/* xdr offset starts at RPC message */
nchunks = ntohl(arg_ary->wc_nchunks);
for (xdr_off = 0, chunk_no = 0;
@@ -330,24 +324,21 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
write_len);
chunk_off = 0;
while (write_len) {
- int this_write;
-
- this_write = min(write_len, max_write);
ret = send_write(xprt, rqstp,
ntohl(ch->rs_handle),
rs_offset + chunk_off,
xdr_off,
- this_write,
+ write_len,
vec);
- if (ret) {
+ if (ret <= 0) {
dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
ret);
return -EIO;
}
- chunk_off += this_write;
- xdr_off += this_write;
- xfer_len -= this_write;
- write_len -= this_write;
+ chunk_off += ret;
+ xdr_off += ret;
+ xfer_len -= ret;
+ write_len -= ret;
}
}
/* Update the req with the number of chunks actually used */



2014-07-10 19:51:12

by Steve Wise

[permalink] [raw]
Subject: RE: [PATCH] svcrdma: send_write() must not overflow the device's max sge

I tested this with nfsv3 and v4, over cxgb4 and mlx4: cthon04, iozone, fio, and xfs. No regressions seen...

Steve.


2014-07-10 20:17:07

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH] svcrdma: send_write() must not overflow the device's max sge

On Wed, Jul 09, 2014 at 01:49:15PM -0500, Steve Wise wrote:
> Function send_write() must stop creating sges when it reaches the device
> max and return the amount sent in the RDMA Write to the caller.

Queueing up for 3.17, thanks.--b.

>
> Signed-off-by: Steve Wise <[email protected]>
> ---
>
> net/sunrpc/xprtrdma/svc_rdma_sendto.c | 39 +++++++++++++--------------------
> 1 files changed, 15 insertions(+), 24 deletions(-)
>
> diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
> index 49fd21a..9f1b506 100644
> --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
> +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
> @@ -192,6 +192,8 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
> xdr_sge_no++;
> BUG_ON(xdr_sge_no > vec->count);
> bc -= sge_bytes;
> + if (sge_no == xprt->sc_max_sge)
> + break;
> }
>
> /* Prepare WRITE WR */
> @@ -209,7 +211,7 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
> atomic_inc(&rdma_stat_write);
> if (svc_rdma_send(xprt, &write_wr))
> goto err;
> - return 0;
> + return write_len - bc;
> err:
> svc_rdma_unmap_dma(ctxt);
> svc_rdma_put_context(ctxt, 0);
> @@ -225,7 +227,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
> {
> u32 xfer_len = rqstp->rq_res.page_len + rqstp->rq_res.tail[0].iov_len;
> int write_len;
> - int max_write;
> u32 xdr_off;
> int chunk_off;
> int chunk_no;
> @@ -239,8 +240,6 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
> res_ary = (struct rpcrdma_write_array *)
> &rdma_resp->rm_body.rm_chunks[1];
>
> - max_write = xprt->sc_max_sge * PAGE_SIZE;
> -
> /* Write chunks start at the pagelist */
> for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
> xfer_len && chunk_no < arg_ary->wc_nchunks;
> @@ -260,23 +259,21 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
> write_len);
> chunk_off = 0;
> while (write_len) {
> - int this_write;
> - this_write = min(write_len, max_write);
> ret = send_write(xprt, rqstp,
> ntohl(arg_ch->rs_handle),
> rs_offset + chunk_off,
> xdr_off,
> - this_write,
> + write_len,
> vec);
> - if (ret) {
> + if (ret <= 0) {
> dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
> ret);
> return -EIO;
> }
> - chunk_off += this_write;
> - xdr_off += this_write;
> - xfer_len -= this_write;
> - write_len -= this_write;
> + chunk_off += ret;
> + xdr_off += ret;
> + xfer_len -= ret;
> + write_len -= ret;
> }
> }
> /* Update the req with the number of chunks actually used */
> @@ -293,7 +290,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
> {
> u32 xfer_len = rqstp->rq_res.len;
> int write_len;
> - int max_write;
> u32 xdr_off;
> int chunk_no;
> int chunk_off;
> @@ -311,8 +307,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
> res_ary = (struct rpcrdma_write_array *)
> &rdma_resp->rm_body.rm_chunks[2];
>
> - max_write = xprt->sc_max_sge * PAGE_SIZE;
> -
> /* xdr offset starts at RPC message */
> nchunks = ntohl(arg_ary->wc_nchunks);
> for (xdr_off = 0, chunk_no = 0;
> @@ -330,24 +324,21 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
> write_len);
> chunk_off = 0;
> while (write_len) {
> - int this_write;
> -
> - this_write = min(write_len, max_write);
> ret = send_write(xprt, rqstp,
> ntohl(ch->rs_handle),
> rs_offset + chunk_off,
> xdr_off,
> - this_write,
> + write_len,
> vec);
> - if (ret) {
> + if (ret <= 0) {
> dprintk("svcrdma: RDMA_WRITE failed, ret=%d\n",
> ret);
> return -EIO;
> }
> - chunk_off += this_write;
> - xdr_off += this_write;
> - xfer_len -= this_write;
> - write_len -= this_write;
> + chunk_off += ret;
> + xdr_off += ret;
> + xfer_len -= ret;
> + write_len -= ret;
> }
> }
> /* Update the req with the number of chunks actually used */
>

2014-07-16 06:16:07

by Devesh Sharma

[permalink] [raw]
Subject: RE: [PATCH] svcrdma: send_write() must not overflow the device's max sge

UmVwb3J0ZWQtQnk6IERldmVzaCBTaGFybWEgPGRldmVzaC5zaGFybWEgYXQgRW11bGV4LmNvbT4N
CkFja2VkLUJ5OiBEZXZlc2ggU2hhcm1hIDxEZXZlc2guc2hhcm1hIGF0IEVtdWxleC5jb20+DQoN
Cj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogbGludXgtcmRtYS1vd25lckB2
Z2VyLmtlcm5lbC5vcmcgW21haWx0bzpsaW51eC1yZG1hLQ0KPiBvd25lckB2Z2VyLmtlcm5lbC5v
cmddIE9uIEJlaGFsZiBPZiBTdGV2ZSBXaXNlDQo+IFNlbnQ6IFRodXJzZGF5LCBKdWx5IDEwLCAy
MDE0IDEyOjE5IEFNDQo+IFRvOiBiZmllbGRzQGZpZWxkc2VzLm9yZw0KPiBDYzogbGludXgtcmRt
YUB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4LW5mc0B2Z2VyLmtlcm5lbC5vcmc7IHRvbUBvZ2MudXMN
Cj4gU3ViamVjdDogW1BBVENIXSBzdmNyZG1hOiBzZW5kX3dyaXRlKCkgbXVzdCBub3Qgb3ZlcmZs
b3cgdGhlIGRldmljZSdzIG1heA0KPiBzZ2UNCj4gDQo+IEZ1bmN0aW9uIHNlbmRfd3JpdGUoKSBt
dXN0IHN0b3AgY3JlYXRpbmcgc2dlcyB3aGVuIGl0IHJlYWNoZXMgdGhlIGRldmljZQ0KPiBtYXgg
YW5kIHJldHVybiB0aGUgYW1vdW50IHNlbnQgaW4gdGhlIFJETUEgV3JpdGUgdG8gdGhlIGNhbGxl
ci4NCj4gDQo+IFNpZ25lZC1vZmYtYnk6IFN0ZXZlIFdpc2UgPHN3aXNlQG9wZW5ncmlkY29tcHV0
aW5nLmNvbT4NCj4gLS0tDQo+IA0KPiAgbmV0L3N1bnJwYy94cHJ0cmRtYS9zdmNfcmRtYV9zZW5k
dG8uYyB8ICAgMzkgKysrKysrKysrKysrKy0tLS0tLS0tLS0tLS0tDQo+IC0tLS0tLQ0KPiAgMSBm
aWxlcyBjaGFuZ2VkLCAxNSBpbnNlcnRpb25zKCspLCAyNCBkZWxldGlvbnMoLSkNCj4gDQo+IGRp
ZmYgLS1naXQgYS9uZXQvc3VucnBjL3hwcnRyZG1hL3N2Y19yZG1hX3NlbmR0by5jDQo+IGIvbmV0
L3N1bnJwYy94cHJ0cmRtYS9zdmNfcmRtYV9zZW5kdG8uYw0KPiBpbmRleCA0OWZkMjFhLi45ZjFi
NTA2IDEwMDY0NA0KPiAtLS0gYS9uZXQvc3VucnBjL3hwcnRyZG1hL3N2Y19yZG1hX3NlbmR0by5j
DQo+ICsrKyBiL25ldC9zdW5ycGMveHBydHJkbWEvc3ZjX3JkbWFfc2VuZHRvLmMNCj4gQEAgLTE5
Miw2ICsxOTIsOCBAQCBzdGF0aWMgaW50IHNlbmRfd3JpdGUoc3RydWN0IHN2Y3hwcnRfcmRtYSAq
eHBydCwgc3RydWN0DQo+IHN2Y19ycXN0ICpycXN0cCwNCj4gIAkJeGRyX3NnZV9ubysrOw0KPiAg
CQlCVUdfT04oeGRyX3NnZV9ubyA+IHZlYy0+Y291bnQpOw0KPiAgCQliYyAtPSBzZ2VfYnl0ZXM7
DQo+ICsJCWlmIChzZ2Vfbm8gPT0geHBydC0+c2NfbWF4X3NnZSkNCj4gKwkJCWJyZWFrOw0KPiAg
CX0NCj4gDQo+ICAJLyogUHJlcGFyZSBXUklURSBXUiAqLw0KPiBAQCAtMjA5LDcgKzIxMSw3IEBA
IHN0YXRpYyBpbnQgc2VuZF93cml0ZShzdHJ1Y3Qgc3ZjeHBydF9yZG1hICp4cHJ0LCBzdHJ1Y3QN
Cj4gc3ZjX3Jxc3QgKnJxc3RwLA0KPiAgCWF0b21pY19pbmMoJnJkbWFfc3RhdF93cml0ZSk7DQo+
ICAJaWYgKHN2Y19yZG1hX3NlbmQoeHBydCwgJndyaXRlX3dyKSkNCj4gIAkJZ290byBlcnI7DQo+
IC0JcmV0dXJuIDA7DQo+ICsJcmV0dXJuIHdyaXRlX2xlbiAtIGJjOw0KPiAgIGVycjoNCj4gIAlz
dmNfcmRtYV91bm1hcF9kbWEoY3R4dCk7DQo+ICAJc3ZjX3JkbWFfcHV0X2NvbnRleHQoY3R4dCwg
MCk7DQo+IEBAIC0yMjUsNyArMjI3LDYgQEAgc3RhdGljIGludCBzZW5kX3dyaXRlX2NodW5rcyhz
dHJ1Y3Qgc3ZjeHBydF9yZG1hDQo+ICp4cHJ0LCAgew0KPiAgCXUzMiB4ZmVyX2xlbiA9IHJxc3Rw
LT5ycV9yZXMucGFnZV9sZW4gKyBycXN0cC0NCj4gPnJxX3Jlcy50YWlsWzBdLmlvdl9sZW47DQo+
ICAJaW50IHdyaXRlX2xlbjsNCj4gLQlpbnQgbWF4X3dyaXRlOw0KPiAgCXUzMiB4ZHJfb2ZmOw0K
PiAgCWludCBjaHVua19vZmY7DQo+ICAJaW50IGNodW5rX25vOw0KPiBAQCAtMjM5LDggKzI0MCw2
IEBAIHN0YXRpYyBpbnQgc2VuZF93cml0ZV9jaHVua3Moc3RydWN0IHN2Y3hwcnRfcmRtYQ0KPiAq
eHBydCwNCj4gIAlyZXNfYXJ5ID0gKHN0cnVjdCBycGNyZG1hX3dyaXRlX2FycmF5ICopDQo+ICAJ
CSZyZG1hX3Jlc3AtPnJtX2JvZHkucm1fY2h1bmtzWzFdOw0KPiANCj4gLQltYXhfd3JpdGUgPSB4
cHJ0LT5zY19tYXhfc2dlICogUEFHRV9TSVpFOw0KPiAtDQo+ICAJLyogV3JpdGUgY2h1bmtzIHN0
YXJ0IGF0IHRoZSBwYWdlbGlzdCAqLw0KPiAgCWZvciAoeGRyX29mZiA9IHJxc3RwLT5ycV9yZXMu
aGVhZFswXS5pb3ZfbGVuLCBjaHVua19ubyA9IDA7DQo+ICAJICAgICB4ZmVyX2xlbiAmJiBjaHVu
a19ubyA8IGFyZ19hcnktPndjX25jaHVua3M7IEBAIC0yNjAsMjMNCj4gKzI1OSwyMSBAQCBzdGF0
aWMgaW50IHNlbmRfd3JpdGVfY2h1bmtzKHN0cnVjdCBzdmN4cHJ0X3JkbWEgKnhwcnQsDQo+ICAJ
CQkJCQl3cml0ZV9sZW4pOw0KPiAgCQljaHVua19vZmYgPSAwOw0KPiAgCQl3aGlsZSAod3JpdGVf
bGVuKSB7DQo+IC0JCQlpbnQgdGhpc193cml0ZTsNCj4gLQkJCXRoaXNfd3JpdGUgPSBtaW4od3Jp
dGVfbGVuLCBtYXhfd3JpdGUpOw0KPiAgCQkJcmV0ID0gc2VuZF93cml0ZSh4cHJ0LCBycXN0cCwN
Cj4gIAkJCQkJIG50b2hsKGFyZ19jaC0+cnNfaGFuZGxlKSwNCj4gIAkJCQkJIHJzX29mZnNldCAr
IGNodW5rX29mZiwNCj4gIAkJCQkJIHhkcl9vZmYsDQo+IC0JCQkJCSB0aGlzX3dyaXRlLA0KPiAr
CQkJCQkgd3JpdGVfbGVuLA0KPiAgCQkJCQkgdmVjKTsNCj4gLQkJCWlmIChyZXQpIHsNCj4gKwkJ
CWlmIChyZXQgPD0gMCkgew0KPiAgCQkJCWRwcmludGsoInN2Y3JkbWE6IFJETUFfV1JJVEUgZmFp
bGVkLA0KPiByZXQ9JWRcbiIsDQo+ICAJCQkJCXJldCk7DQo+ICAJCQkJcmV0dXJuIC1FSU87DQo+
ICAJCQl9DQo+IC0JCQljaHVua19vZmYgKz0gdGhpc193cml0ZTsNCj4gLQkJCXhkcl9vZmYgKz0g
dGhpc193cml0ZTsNCj4gLQkJCXhmZXJfbGVuIC09IHRoaXNfd3JpdGU7DQo+IC0JCQl3cml0ZV9s
ZW4gLT0gdGhpc193cml0ZTsNCj4gKwkJCWNodW5rX29mZiArPSByZXQ7DQo+ICsJCQl4ZHJfb2Zm
ICs9IHJldDsNCj4gKwkJCXhmZXJfbGVuIC09IHJldDsNCj4gKwkJCXdyaXRlX2xlbiAtPSByZXQ7
DQo+ICAJCX0NCj4gIAl9DQo+ICAJLyogVXBkYXRlIHRoZSByZXEgd2l0aCB0aGUgbnVtYmVyIG9m
IGNodW5rcyBhY3R1YWxseSB1c2VkICovIEBAIC0NCj4gMjkzLDcgKzI5MCw2IEBAIHN0YXRpYyBp
bnQgc2VuZF9yZXBseV9jaHVua3Moc3RydWN0IHN2Y3hwcnRfcmRtYSAqeHBydCwgIHsNCj4gIAl1
MzIgeGZlcl9sZW4gPSBycXN0cC0+cnFfcmVzLmxlbjsNCj4gIAlpbnQgd3JpdGVfbGVuOw0KPiAt
CWludCBtYXhfd3JpdGU7DQo+ICAJdTMyIHhkcl9vZmY7DQo+ICAJaW50IGNodW5rX25vOw0KPiAg
CWludCBjaHVua19vZmY7DQo+IEBAIC0zMTEsOCArMzA3LDYgQEAgc3RhdGljIGludCBzZW5kX3Jl
cGx5X2NodW5rcyhzdHJ1Y3Qgc3ZjeHBydF9yZG1hDQo+ICp4cHJ0LA0KPiAgCXJlc19hcnkgPSAo
c3RydWN0IHJwY3JkbWFfd3JpdGVfYXJyYXkgKikNCj4gIAkJJnJkbWFfcmVzcC0+cm1fYm9keS5y
bV9jaHVua3NbMl07DQo+IA0KPiAtCW1heF93cml0ZSA9IHhwcnQtPnNjX21heF9zZ2UgKiBQQUdF
X1NJWkU7DQo+IC0NCj4gIAkvKiB4ZHIgb2Zmc2V0IHN0YXJ0cyBhdCBSUEMgbWVzc2FnZSAqLw0K
PiAgCW5jaHVua3MgPSBudG9obChhcmdfYXJ5LT53Y19uY2h1bmtzKTsNCj4gIAlmb3IgKHhkcl9v
ZmYgPSAwLCBjaHVua19ubyA9IDA7DQo+IEBAIC0zMzAsMjQgKzMyNCwyMSBAQCBzdGF0aWMgaW50
IHNlbmRfcmVwbHlfY2h1bmtzKHN0cnVjdCBzdmN4cHJ0X3JkbWENCj4gKnhwcnQsDQo+ICAJCQkJ
CQl3cml0ZV9sZW4pOw0KPiAgCQljaHVua19vZmYgPSAwOw0KPiAgCQl3aGlsZSAod3JpdGVfbGVu
KSB7DQo+IC0JCQlpbnQgdGhpc193cml0ZTsNCj4gLQ0KPiAtCQkJdGhpc193cml0ZSA9IG1pbih3
cml0ZV9sZW4sIG1heF93cml0ZSk7DQo+ICAJCQlyZXQgPSBzZW5kX3dyaXRlKHhwcnQsIHJxc3Rw
LA0KPiAgCQkJCQkgbnRvaGwoY2gtPnJzX2hhbmRsZSksDQo+ICAJCQkJCSByc19vZmZzZXQgKyBj
aHVua19vZmYsDQo+ICAJCQkJCSB4ZHJfb2ZmLA0KPiAtCQkJCQkgdGhpc193cml0ZSwNCj4gKwkJ
CQkJIHdyaXRlX2xlbiwNCj4gIAkJCQkJIHZlYyk7DQo+IC0JCQlpZiAocmV0KSB7DQo+ICsJCQlp
ZiAocmV0IDw9IDApIHsNCj4gIAkJCQlkcHJpbnRrKCJzdmNyZG1hOiBSRE1BX1dSSVRFIGZhaWxl
ZCwNCj4gcmV0PSVkXG4iLA0KPiAgCQkJCQlyZXQpOw0KPiAgCQkJCXJldHVybiAtRUlPOw0KPiAg
CQkJfQ0KPiAtCQkJY2h1bmtfb2ZmICs9IHRoaXNfd3JpdGU7DQo+IC0JCQl4ZHJfb2ZmICs9IHRo
aXNfd3JpdGU7DQo+IC0JCQl4ZmVyX2xlbiAtPSB0aGlzX3dyaXRlOw0KPiAtCQkJd3JpdGVfbGVu
IC09IHRoaXNfd3JpdGU7DQo+ICsJCQljaHVua19vZmYgKz0gcmV0Ow0KPiArCQkJeGRyX29mZiAr
PSByZXQ7DQo+ICsJCQl4ZmVyX2xlbiAtPSByZXQ7DQo+ICsJCQl3cml0ZV9sZW4gLT0gcmV0Ow0K
PiAgCQl9DQo+ICAJfQ0KPiAgCS8qIFVwZGF0ZSB0aGUgcmVxIHdpdGggdGhlIG51bWJlciBvZiBj
aHVua3MgYWN0dWFsbHkgdXNlZCAqLw0KPiANCj4gLS0NCj4gVG8gdW5zdWJzY3JpYmUgZnJvbSB0
aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LXJkbWEiIGluIHRoZQ0K
PiBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnIE1vcmUgbWFq
b3Jkb21vIGluZm8gYXQNCj4gaHR0cDovL3ZnZXIua2VybmVsLm9yZy9tYWpvcmRvbW8taW5mby5o
dG1sDQo=