kernel: Allow fhold() in allfiles_scan_exclusive()
Before this commit following race could happen, if fhold() is used
during allfiles_scan_exclusive():
Thread1 Thread2
: :
: fdrop(fp)
: {
Scan all fps if (f_count-- == 1) {
(*) fhold(fp) [f_count++] :
: fo_close(fp);
Access fp Unlink fp from filehead;
fdrop(fp) free(fp);
: }
: }
This could cause use-after-free or double free (since f_count == 1
when fdrop() was called in Thread1, fp will be freed again).
We now handle f_count 1->0 transition specially: hold the filehead
spin lock then do the f_count 1->0 transition, if the f_count 1->0
transition succeeds, the fp is unlinked from the filehead. This
prevents the above race from happening. This solution is mainly
based on dillon@'s input.