When enabling TRIM support for a block device, a request can
result in a write beyond the end of such a block device, as shown
in the following in the following debug output:
+*handling trim request client->exportsize : 134217728 req->from : 67109888 cur.startoff : 0 reqoff : 67109888 next.startoff : 134217728 curlen : 67107840 curlen - reqoff : 18446744073709549568 req->len : 8388608
Request to punch a hole in fd=5, starting from 67109888, length 18446744073709549568 Performed TRIM request from 67109888 to 8388608
As a result of such a request the nbd-server process will hang
with 100% cpu load while the kernel writes a lot of warnings and
can not be killed until all requests are handled by the kernel.
I used the following patch to mitigate the problem and get
trim/discard working for a simple block device export:
--- nbdsrv.c.old +++ nbdsrv.c @@ -268,6 +268,7 @@ FILE_INFO cur = g_array_index(client->export, FILE_INFO, 0); FILE_INFO next; int i = 1; + uint64_t reqfrom = req->from; do { if(i<client->export->len) { next = g_array_index(client->export, FILE_INFO, i); @@ -275,13 +276,14 @@ next.fhandle = -1; next.startoff = client->exportsize; } - if(cur.startoff <= req->from && next.startoff - cur.startoff >= req->len) { - off_t reqoff = req->from - cur.startoff; - off_t curlen = next.startoff - reqoff; - off_t reqlen = curlen - reqoff > req->len ? req->len : curlen - reqoff; - punch_hole(cur.fhandle, reqoff, reqlen); + if(cur.startoff <= reqfrom) { + uint64_t end = MIN(req->from + req->len, next.startoff) - cur.startoff; + uint64_t start = reqfrom - cur.startoff; + uint64_t len = end - start; + punch_hole(cur.fhandle, start, len); } cur = next; + reqfrom = cur.startoff; i++; } while(i < client->export->len && cur.startoff < (req->from + req->len)); DEBUG("Performed TRIM request from %llu to %llu", (unsigned long long) req->from, (unsigned long long) req->len);
The patch was not tested against multi-file exports or reviewed, but I though it might help in fixing the issue.
with kind regards
Raphael