-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QAT support for AES-GCM #7282
QAT support for AES-GCM #7282
Conversation
@wli5 would you mind reviewing this. |
Codecov Report
@@ Coverage Diff @@
## master #7282 +/- ##
==========================================
+ Coverage 76.53% 76.56% +0.03%
==========================================
Files 328 327 -1
Lines 104006 103874 -132
==========================================
- Hits 79600 79536 -64
+ Misses 24406 24338 -68
Continue to review full report at Codecov.
|
@behlendorf Yes, I will do it, thanks! |
@tcaputi sorry for misleading, I just check the doc, you are right, CCM only support 128 bits: |
This commit seems to mix a lot of what must be general refactoring in with the encryption. Ideally, those should be separate commits, which would make review and troubleshooting (e.g. bisection) easier. |
My ability to give a reasonable review on this code is limited, but from a read-through, I don't see anything glaringly wrong. I see there's a 4kB limit on buffer size. How does this interact with recordsize=1M? Does that get encrypted on the CPU, and is that faster than trying to offload it? Is the performance break-even point a function of particular hardware (e.g. as CPUs get faster, even 4kB should be run in software and/or as QAT cards get faster, it would make sense to offload 8kB blocks)? If so, should those numbers be conditionalized on the card model? Or should we do something where we benchmark it on module load (which I think the assembly-optimized versions of checksumming and RAIDZ do)? Or should it be user-configurable (e.g. as a module parameter)? |
module/zfs/qat.c
Outdated
|
||
ret = qat_crypt_init(); | ||
if (ret != 0) | ||
goto error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just wondering when users who don't want to use QAT encryption, they just have DC instances in the configure file, for this case the qat_init should not return fail. Only when qat_dc_init and qat_cy_init all fail, qat_init returns fail. Does it make sense?
@rlaager the buffer size 4KB is for DMA restriction, for each offloading request, it actually can be very large, e.g., in record size - 128KB, but the 128KB record buffer will be split into 32 pages and send to device as one sg-list buffer, this is to make sure the address is physical contiguous for DMA access. |
module/zfs/qat_crypt.c
Outdated
#define QAT_CRYPT_MAX_INSTANCES 48 | ||
|
||
#define MAX_PAGE_NUM 1024 | ||
#define DIGEST_LENGTH 8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems these 4 consts are not used.
module/zfs/qat_crypt.c
Outdated
} | ||
} | ||
|
||
static inline struct page * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
those 3 inline functions exist twice in both qat_crypt.c and qat_compress.c, can we merge them to qat.h?
module/zfs/qat_crypt.c
Outdated
status = init_cy_session_ctx(dir, cy_inst_handle, &cy_session_ctx, key, | ||
crypt, aad_len); | ||
if (status != CPA_STATUS_SUCCESS) | ||
goto error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can return fail directly (safely - as memory are all freed), if goto error branch, the calling of cpaCySymRemoveSession will cause issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, return (status)
here.
module/zfs/qat_crypt.c
Outdated
flat_src_buf = flat_src_buf_array; | ||
flat_dst_buf = flat_dst_buf_array; | ||
while (bytes_left > 0) { | ||
in_pages[page_num] = mem_to_page(in); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forget page_num++, this will cause the pages not un-mapped.
For clarification, the 4kB is a minimum buffer size. The maximum is 128k. As far as how this interacts with |
@wli5 Thanks for your suggestions and your comments have been addressed. Take a look when you get a chance. |
}; | ||
|
||
static kstat_t *qat_ksp = NULL; | ||
int zfs_qat_disable = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should pull the module_param()
for this in to qat.c
as well.
module/zfs/qat.c
Outdated
|
||
ret = qat_dc_init(); | ||
if (ret != 0) | ||
goto error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: please just return (ret)
here, and for the qat_crypt_init()
failure below call qat_dc_fini()
and return. Then we can drop the error
label and it's contents.
module/zfs/qat.c
Outdated
} | ||
|
||
qat_dc_fini(); | ||
qat_crypt_fini(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: qat_crypt_fini()
before qat_dc_fini()
.
module/zfs/qat.h
Outdated
* Note: when qat fail happens, it doesn't mean a critical hardware | ||
* issue, sometimes it is because the output buffer is not big enough, | ||
* and the compression job will be transfered to gzip software again, | ||
* so the functionality of ZFS is not impacted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last sentence needs to be updated to refer to the encyption and not compression job.
module/zfs/qat.h
Outdated
kfree(*pp_mem_addr); | ||
*pp_mem_addr = NULL; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than maintaining mem_alloc_contig()
, and mem_free_contig()
as static inlines
they can be moved to qat.c
converted to normal functions and renamed qat_mem_alloc_contig()
and qat_mem_free_contig()
. Let's add the qat_
prefix to mem_to_page
as well but leave it a static inline since this one might actually have an impact on performance.
module/zfs/qat.h
Outdated
#define PHYS_CONTIG_ALLOC(pp_mem_addr, size_bytes) \ | ||
mem_alloc_contig((void *)(pp_mem_addr), (size_bytes)) | ||
#define PHYS_CONTIG_FREE(p_mem_addr) \ | ||
mem_free_contig((void *)&(p_mem_addr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
QAT_PHYS_CONTIG_ALLOC / QAT_PHYS_CONTIG_FREE, to head off any future namespace collision.
module/zfs/qat_crypt.c
Outdated
|
||
for (i = 0; i < num_inst; i++) { | ||
cpaCyStopInstance(cy_inst_handles[i]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: { }
can be dropped, and the Cpa32U i
declaration moved in to the for
initializer.
for (Cpa32U i = 0; i < num_inst; i++)
cpaCyStopInstance(cy_inst_handles[i]);
module/zfs/qat_crypt.c
Outdated
status = init_cy_session_ctx(dir, cy_inst_handle, &cy_session_ctx, key, | ||
crypt, aad_len); | ||
if (status != CPA_STATUS_SUCCESS) | ||
goto error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, return (status)
here.
module/zfs/qat_crypt.c
Outdated
|
||
return (CPA_STATUS_SUCCESS); | ||
|
||
error: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's model this after qat_compress()
which shares a common cleanup path for success and failure. Lines 351-363 are virtually identical to 370-383.
This patch adds support for acceleration of AES-GCM encryption with Intel Quick Assist Technology. Signed-off-by: Chengfeix Zhu <chengfeix.zhu@intel.com> Signed-off-by: Weigang Li <weigang.li@intel.com> Signed-off-by: Tom Caputi <tcaputi@datto.com>
@behlendorf your comments have been addressed. Thank you for the feedback. |
@tcaputi for QAT hardware, there is no such limitation, we limit it in software for performance reason, user can modify the 128K to 1M in the code, it should be OK. We can also change it in this PR, one concern is for compression, there is a list of intermediate buffers each will be pre-allocated based on the max buffer size, if most cases the record size is < 1M, while we allocated so many "big" intermediate buffer, it is a waste. I don't know how many people use 1M record size, if you think 1M is common, we may change the value to 1M in this PR.
|
These graphs (courtesy of Intel) show the performance improvements granted when using QAT for encryption. I verified these results myself with a spinning disk pool and the results were very similar. As expected, QAT greatly reduces the CPU overhead associated with encryption and provides a marginal bump to throughput (encryption is usually not a bottleneck here). |
@wli5 I think that Either the buffers can be allocated based on |
@adilger thanks for comments. |
Is it possible to have the QAT intermediate compression buffers be reallocated if a larger request is submitted? At worst, if the larger buffer allocation fails it can return an error and fall back to CPU-based compression algorithm for larger buffers (i.e. what it is doing now), but in most cases the allocation should succeed and allow QAT to compress the larger buffers. That avoids the overhead of allocating too-large buffers if they are not needed, while allowing larger blocks to be compressed in the common cases. A more complex buffer management system might allow "small" and "large" buffers separately (we do this for Lustre routers), only using "large" buffers if needed, and using "small" buffers for other requests. That would also reduce the amount of RAM pinned by the intermediate buffers to the number of concurrent "large" requests, rather than guessing in advance how many buffers might be needed and forcing all buffers to be the maximum size. |
This patch adds support for acceleration of AES-GCM encryption
with Intel Quick Assist Technology.
Signed-off-by: Chengfeix Zhu chengfeix.zhu@intel.com
Signed-off-by: Weigang Li weigang.li@intel.com
Signed-off-by: Tom Caputi tcaputi@datto.com
Motivation and Context
This code allows ZFS to utilize QAT for the purpose of accelerating encryption. Unfortunately, QAT does not support AES-CCM (other than 128 bits), so the implementation only runs on AES-GCM.
How Has This Been Tested?
Tested on a system with a QAT DH895x PCIe card installed and with the card disabled to ensure that the implementations with and without the card are compatible. I will have performance numbers soon.
Types of changes
Checklist:
Signed-off-by
.