If gnttab_grant_foreign_access() fails for any of the indirection pages, the code breaks out of both the loops without freeing the local variable indirectpages, causing a memory leak.
Details
Diff Detail
- Lint
Lint Skipped - Unit
Tests Skipped
Event Timeline
Do you also need to free cm_sg_refs and destroy the dmamap in case of failure?
sys/dev/xen/blkfront/blkfront.c | ||
---|---|---|
1346 | I think it would be easier to just add the contigfree here, since you can avoid the indirectpages != NULL check. |
sys/dev/xen/blkfront/blkfront.c | ||
---|---|---|
1346 | The contigmalloc(9) man page says:
|
sys/dev/xen/blkfront/blkfront.c | ||
---|---|---|
1346 | Will blkfront work correctly if xbd_max_request_indirectpages > 0 and cm->cm_indirectionpages == NULL? |
sys/dev/xen/blkfront/blkfront.c | ||
---|---|---|
1346 | It wouldn't. I noticed another problem. There is no NULL check for contigmalloc() above. The man page seems to imply that contigmalloc() can fail even when M_NOWAIT is not passed.
I think it would be better to add a NULL check there and remove it from here. |
sys/dev/xen/blkfront/blkfront.c | ||
---|---|---|
1346 | I'm not sure what exactly the man page means. It could mean that unless M_NOWAIT is specified, it will evict a page from memory, and move it to disk (sleeping in the process). But it would still always succeed. In that case a NULL check is not needed. Or it could mean that it is still possible for contigmalloc() to fail, but it will first try to evict a page to disk before giving up (and returning NULL). Could you please confirm which one of these two is correct? |
I asked on freebsd-hackers@ mailing list, and Conrad Meyer says that contigmalloc() can fail even when M_NOWAIT is not specified. Link to the email.
So there should be a NULL check after contigmalloc() above. Should I add that change in this same revision or create a different one?
Every memory allocation in xbd_connect uses m_NOWAIT, so I assume it's not safe to sleep in that function? If it's possible to sleep then you could use M_WAITOK which is guaranteed to never return NULL.
Also, could you fix your review requests so that the diff can be expanded? Right now it says "Context not available."
The contigmalloc(9) man page says only 2 flags can be used: M_NOWAIT and M_ZERO. All other flags (if present) will be ignored. So M_WAITOK can not be used.
Since contigmalloc() above only specifies M_ZERO, it can sleep, but that does not guarantee success (as confirmed by Conrad Meyer in the email I linked in the previous comment). contigmalloc(9) works a little differently from malloc(9) in this regard. Since every other malloc in xbd_connect() specifies M_NOWAIT, I think that M_NOWAIT should be specified to contigmalloc as well, along with M_ZERO. This might be a simple mistake from the person who wrote the code.
Also, I have no idea why my diffs can't be expanded. I simply run git diff and then upload it here. Should I do something differently?
Updated the diff to add flag M_NOWAIT to the contigmalloc() used to allocate the indirection pages. Also, added a NULL check there in case contigmalloc fails.
PS: I figured out how to show context. I just had to add the option -U9999 to git diff, to increase the number of context lines from the default 3 to more than the length of the file.
I think it will work better if you use the arc command line tool, see: https://wiki.freebsd.org/Phabricator
The code is OK, but the coding style is not. I had to fix the lines to be < 80 cols and adjust the indentation.
Probably a difference in the tab width. I don't get why there is indentation with both tabs and spaces in a single line. The entire blkfront code is like that. Some places its all tabs, some places it is a mix of tabs and spaces for indentation. Its weird and confusing.
style(9) details when you should use tabs or spaces:
"Indentation is an 8 character tab. Second level indents are four spaces. If you have to wrap a long statement, put the operator at the end of the line."
So if you have a function that has a long list of arguments it should be split like:
foobar(a, b, c, d);