/*---------------------------------------------------------------------------*/ static coffee_page_t find_contiguous_pages(coffee_page_t amount) { coffee_page_t page, start; struct file_header hdr; start = INVALID_PAGE; for(page = *next_free; page < COFFEE_PAGE_COUNT;) { read_header(&hdr, page); if(HDR_FREE(hdr)) { if(start == INVALID_PAGE) { start = page; if(start + amount >= COFFEE_PAGE_COUNT) { /* We can stop immediately if the remaining pages are not enough. */ break; } } /* All remaining pages in this sector are free -- jump to the next sector. */ page = next_file(page, &hdr); if(start + amount <= page) { if(start == *next_free) { *next_free = start + amount; } return start; } } else { start = INVALID_PAGE; page = next_file(page, &hdr); } } return INVALID_PAGE; }
/*---------------------------------------------------------------------------*/ static coffee_page_t next_file(coffee_page_t page, struct file_header *hdr) { if(HDR_FREE(*hdr)) { return (page + COFFEE_PAGES_PER_SECTOR) & ~(COFFEE_PAGES_PER_SECTOR - 1); } else if(HDR_ISOLATED(*hdr)) { return page + 1; } return page + hdr->max_pages; }
/*---------------------------------------------------------------------------*/ static coffee_page_t next_file(coffee_page_t page, struct file_header *hdr) { /* * The quick-skip algorithm for finding file extents is the most * essential part of Coffee. The file allocation rules enables this * algorithm to quickly jump over free areas and allocated extents * after reading single headers and determining their status. * * The worst-case performance occurs when we encounter multiple long * sequences of isolated pages, but such sequences are uncommon and * always shorter than a sector. */ if(HDR_FREE(*hdr)) { return (page + COFFEE_PAGES_PER_SECTOR) & ~(COFFEE_PAGES_PER_SECTOR - 1); } else if(HDR_ISOLATED(*hdr)) { return page + 1; } return page + hdr->max_pages; }