On 08/10/12 16:02, Jie Liu wrote: > On 08/09/12 22:41, Mark Tinguely wrote: >> On 08/03/12 01:10, Jeff Liu wrote: >>> Introduce helpers to probe data or hole offset from page cache for >>> unwritten extents. >>> >>> --- >>> fs/xfs/xfs_file.c | 213 >>> +++++++++++++++++++++++++++++++++++++++++++++++++++++ >>> 1 files changed, 213 insertions(+), 0 deletions(-) >>> >>> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c >>> index 98642cf..aff0c30 100644 >>> --- a/fs/xfs/xfs_file.c >>> +++ b/fs/xfs/xfs_file.c >>> @@ -36,6 +36,7 @@ >>> >> >>> + * keep the offset argument unchanged. >>> + */ >>> +STATIC bool >>> +xfs_lookup_buffer_offset( >> I am fine with this helper routine. >> >> >>> + >>> +/* >>> + * This routine is called to find out and return a data or hole offset >>> + * from the page cache for unwritten extents according to the desired >>> + * type for xfs_seek_data() or xfs_seek_hole(). >>> + * >>> + * The argument offset is used to tell where we start to search from >>> the >>> + * page cache. Map is used to figure out the end points of the >>> range to >>> + * lookup pages. >>> + * >>> + * Return true if the desired type of offset was found, and the >>> argument >>> + * offset is filled with that address. Otherwise, return false and >>> keep >>> + * offset unchanged. >>> + */ >>> +STATIC bool >>> +xfs_find_get_desired_pgoff( >>> + struct inode *inode, >>> + struct xfs_bmbt_irec *map, >>> + unsigned int type, >>> + loff_t *offset) >>> +{ >>> + struct xfs_inode *ip = XFS_I(inode); >>> + struct xfs_mount *mp = ip->i_mount; >>> + struct pagevec pvec; >>> + pgoff_t index; >>> + pgoff_t end; >>> + loff_t endoff; >>> + loff_t startoff = *offset; >>> + loff_t lastoff = startoff; >>> + bool found = false; >>> + >>> + pagevec_init(&pvec, 0); >>> + >>> + index = startoff>> PAGE_CACHE_SHIFT; >>> + endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount); >>> + end = endoff>> PAGE_CACHE_SHIFT; >>> + do { >>> + int want; >>> + unsigned nr_pages; >>> + unsigned int i; >>> + >>> + want = min_t(pgoff_t, end - index, (pgoff_t)PAGEVEC_SIZE); >>> + nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, >>> + want); >>> + /* >>> + * No page mapped into given range. If we are searching holes >>> + * and if this is the first time we got into the loop, it means >>> + * that the given offset is landed in a hole, return it. >>> + * >>> + * If we have already stepped through some block buffers to >>> find >>> + * holes but they all contains data. In this case, the last >>> + * offset is already updated and pointed to the end of the last >>> + * mapped page, if it does not reach the endpoint to search, >>> + * that means there should be a hole between them. >>> + */ >>> + if (nr_pages == 0) { >>> + /* Data search found nothing */ >>> + if (type == DATA_OFF) >>> + break; >>> + >>> + ASSERT(type == HOLE_OFF); >>> + if (lastoff == startoff || lastoff< endoff) { >>> + found = true; >>> + *offset = lastoff; >>> + } >>> + break; >>> + } >>> + >>> + /* >>> + * At lease we found one page. If this is the first time we >>> + * step into the loop, and if the first page index offset is >>> + * greater than the given search offset, a hole was found. >>> + */ >>> + if (type == HOLE_OFF&& lastoff == startoff&& >>> + lastoff< page_offset(pvec.pages[0])) { >>> + found = true; >>> + break; >>> + } >> I played with the code and appreciate the trickiness of the startoff. >> I this can be refined a bit more. see below. >> >>> + >>> + for (i = 0; i< nr_pages; i++) { >>> + struct page *page = pvec.pages[i]; >>> + loff_t b_offset; >>> + >>> + /* >>> + * Page index is out of range, searching done. >>> + * If the current offset is not reaches the end >>> + * of the specified search range, there should >>> + * be a hole between them. >>> + */ >>> + if (page->index> end) { >>> + if (type == HOLE_OFF&& lastoff< endoff) { >>> + *offset = lastoff; >>> + found = true; >>> + } >>> + goto out; >>> + } >> Before we take the lock, we can check to see if the page starts later >> than expected (a hole). The pre-loop start check can be removed and >> something like the follow added: >> >> /* Skip over this page if it precedes the start offset */ >> if (page_offset(page) + PAGE_SIZE < startoff) >> continue; >> >> if (type == HOLE_OFF && page_offset(page) > >> lastoff) { >> *offset = lastoff; >> found = true; >> goto out; >> } >> >> My experiment passes your newest, more extensive tests. I can give you >> the >> complete experiment patch if you want. > It's better to show me your code, this really optimize the logic a bit > than me. >> >>> + >>> + lock_page(page); >>> + /* >>> + * Page truncated or invalidated(page->mapping == NULL). >>> + * We can freely skip it and proceed to check the next >>> + * page. >>> + */ >>> + if (unlikely(page->mapping != inode->i_mapping)) { >>> + unlock_page(page); >>> + continue; >>> + } >>> + >>> + if (!page_has_buffers(page)) { >>> + unlock_page(page); >>> + continue; >>> + } >> Would this be a hole condition? I suppose the next iteration of the >> loop will figure this out. > This is a fuzzy point to me. If there is no buffer heads associated > with a page, can we treat it as an invalid page like the mapping check > up above? In other words, an unwritten extent have real block numbers on disk. Hence a valid page mapping to that exent should have BHs associated with, Am I right? Thanks, -Jeff >>> + >>> + found = xfs_lookup_buffer_offset(page,&b_offset, type); >>> + if (found) { >>> + /* >>> + * The found offset may be less than the start >>> + * point to search if this is the first time to >>> + * come here. >>> + */ >>> + *offset = max_t(loff_t, startoff, b_offset); >>> + goto out; >>> + } >>> + >>> + /* >>> + * We either searching data but nothing was found, or >>> + * searching hole but found a data buffer. In either >>> + * case, probably the next page contains the desired >>> + * things, update the last offset to it so. >>> + */ >>> + lastoff = page_offset(page) + PAGE_SIZE; >>> + unlock_page(page); >>> + } >>> + >>> + /* >>> + * The number of returned pages less than our desired, search >>> + * done. In this case, nothing was found for searching data, >>> + * but we found a hole behind the last offset. >>> + */ >>> + if (nr_pages< want) { >>> + if (type == HOLE_OFF) { >>> + *offset = lastoff; >>> + found = true; >>> + } >>> + break; >>> + } >>> + >>> + index = pvec.pages[i - 1]->index + 1; >>> + pagevec_release(&pvec); >>> + } while (index< end); >>> + >>> +out: >>> + pagevec_release(&pvec); >>> + return found; >>> +} >>> + >>> STATIC loff_t >>> xfs_seek_data( >>> struct file *file, >> _______________________________________________ >> xfs mailing list >> xfs@xxxxxxxxxxx >> http://oss.sgi.com/mailman/listinfo/xfs _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs