xfs
[Top] [All Lists]

Re: [PATCH v5 2/4]xfs: Introduce a new function to find the desired type

To: xfs@xxxxxxxxxxx
Subject: Re: [PATCH v5 2/4]xfs: Introduce a new function to find the desired type of offset from page cache
From: Jeff Liu <jeff.liu@xxxxxxxxxx>
Date: Thu, 26 Jul 2012 23:16:51 +0800
In-reply-to: <50110629.4090304@xxxxxxxxxx>
Organization: Oracle
References: <50110629.4090304@xxxxxxxxxx>
Reply-to: jeff.liu@xxxxxxxxxx
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.28) Gecko/20120313 Thunderbird/3.1.20
On 07/26/2012 04:56 PM, Jeff Liu wrote:

> This function is called by xfs_seek_data() and xfs_seek_hole() to find
> the desired offset from page cache.
> 
> Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx>
> Reviewed-by: Mark Tinguely <tinguely@xxxxxxx>
> Reviewed-by: Christoph Hellwig <hch@xxxxxx>
> Reviewed-by: Dave Chinner <dchinner@xxxxxxxxxx>
> 
> ---
>  fs/xfs/xfs_file.c |  203 
> +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 203 insertions(+), 0 deletions(-)
> 
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 98642cf..43f5e61 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -36,6 +36,7 @@
>  
>  #include <linux/dcache.h>
>  #include <linux/falloc.h>
> +#include <linux/pagevec.h>
>  
>  static const struct vm_operations_struct xfs_file_vm_ops;
>  
> @@ -966,6 +967,208 @@ xfs_vm_page_mkwrite(
>       return block_page_mkwrite(vma, vmf, xfs_get_blocks);
>  }
>  
> +/*
> + * This type is designed to indicate the type of offset we would like
> + * to search from page cache for either xfs_seek_data() or xfs_seek_hole().
> + */
> +enum {
> +     HOLE_OFF = 0,
> +     DATA_OFF,
> +};
> +
> +/*
> + * 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, and it will be filled with the desired type of offset if
> + * it was found, or it will keep unchanged.  map is used to figure out
> + * the end points of the range to lookup pages.
> + */
> +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                  coff = *offset; /* current search offset */
> +     bool                    found = false;
> +
> +     pagevec_init(&pvec, 0);
> +     index = XFS_FSB_TO_B(mp, XFS_B_TO_FSBT(mp, coff)) >> PAGE_CACHE_SHIFT;
> +
> +     /* The end offset to search for */
> +     endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount);
> +     end = endoff >> PAGE_CACHE_SHIFT;
> +
> +     do {
> +             unsigned int    i;
> +             unsigned        nr_pages;
> +             int             want = min_t(pgoff_t, end - index,
> +                                          (pgoff_t)PAGEVEC_SIZE - 1) + 1;
> +
> +             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 and return ture.
> +              *
> +              * If we have already stepped through some block buffers to find
> +              * holes but those buffers are all contains data, in this case,
> +              * the current search offset is already aligned to block buffer
> +              * unit boundary and pointed to the end of the last mapped page.
> +              * If it's location is less than the end range given for search,
> +              * that means there should be a hole between them, so return the
> +              * current search offset if we are searching hole.
> +              */
> +             if (nr_pages == 0) {
> +                     if (type == HOLE_OFF) {
> +                             if (coff == *offset)
> +                                     found = true;
> +                             if (coff < endoff) {
> +                                     found = true;
> +                                     *offset = coff;
> +                             }
> +                     }
> +                     /* Search data but nothing found */
> +                     break;
> +             }
> +
> +             /*
> +              * At least we found one page.  If this 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, return true
> +              * if we are searching holes.
> +              */
> +             if ((type == HOLE_OFF) && (coff == *offset)) {
> +                     if (coff < pvec.pages[0]->index << PAGE_CACHE_SHIFT) {
> +                             found = true;
> +                             break;
> +                     }
> +             }
> +
> +             for (i = 0; i < nr_pages; i++) {
> +                     struct page             *page = pvec.pages[i];
> +                     struct buffer_head      *bh;
> +                     struct buffer_head      *head;
> +                     xfs_fileoff_t           last;
> +
> +                     /*
> +                      * Page index is out of range, we need to deal with
> +                      * hole search condition in paticular if that is the
> +                      * desired type for the lookup.
> +                      * stepping into the block buffer checkup, it probably
> +                      * means that there is no page mapped at all in the
> +                      * specified range to search, so we found a hole.
> +                      * If we have already done some block buffer checking
> +                      * and found one or more data buffers before, in this
> +                      * case, the coff is already updated and it point to
> +                      * the end of the last data buffer, so the left range
> +                      * behind it might be a hole.  In either case, we will
> +                      * return the coff to indicate a hole's location because
> +                      * it must be greater than or equal to the search start.
> +                      */
> +                     if (page->index > end) {
> +                             if (type == HOLE_OFF && coff < endoff) {
> +                                     *offset = coff;
> +                                     found = true;
> +                             }
> +                             goto out;
> +                     }
> +
> +                     if (!trylock_page(page))
> +                             goto out;
> +
> +                     if (!page_has_buffers(page)) {
> +                             unlock_page(page);
> +                             continue;
> +                     }
> +
> +                     last = XFS_B_TO_FSBT(mp,
> +                                          page->index << PAGE_CACHE_SHIFT);
> +                     bh = head = page_buffers(page);
> +                     do {
> +                             off_t           lastoff = 0;
> +
> +                             /*
> +                              * The 1st block buffer offset in current page.
> +                              */
> +                             lastoff = XFS_FSB_TO_B(mp, last);
> +                             /*
> +                              * An extent in XFS_EXT_UNWRITTEN has disk
> +                              * blocks already mapped to it, but no data
> +                              * has been committed to them yet.  If it has
> +                              * dirty data in the page cache it can be
> +                              * identified by having BH_Unwritten set in
> +                              * each buffers.  Also, the buffer head state
> +                              * might be in BH_Uptodate too if the buffer
> +                              * writeback procedure was fired, we have to
> +                              * check it up as well.
> +                              */
> +                             if (buffer_unwritten(bh) ||
> +                                 buffer_uptodate(bh)) {
> +                                     /*
> +                                      * Found a data buffer and we are
> +                                      * searching data, great.
> +                                      */
> +                                     if (type == DATA_OFF)
> +                                             found = true;
> +                             } else {
> +                                     /*
> +                                      * Nothing was found and we are
> +                                      * searching holes, great.
> +                                      */
> +                                     if (type == HOLE_OFF)
> +                                             found = true;
> +                             }
> +                             if (found) {
> +                                     /*
> +                                      * Return if we found the desired
> +                                      * page offset.
> +                                      */
> +                                     *offset = max_t(loff_t, coff, lastoff);
> +                                     unlock_page(page);
> +                                     goto out;
> +                             }
> +                             /*
> +                              * We either searching data but nothing was
> +                              * found, or searching hole but found a data
> +                              * block buffer.  In either case, probably the
> +                              * next block buffer is what we are desired,
> +                              * so that we need to round up the current
> +                              * offset to it.
> +                              */
> +                             coff = round_up(lastoff + 1, bh->b_size);
> +                             last++;
> +                     } while ((bh = bh->b_this_page) != head);
> +                     unlock_page(page);
> +             }
> +
> +             /*
> +              * If the number of returned pages less than our desired,
> +              * there should no more pages mapped, search done.
> +              */
> +             if (nr_pages < want)
> +                     break;

Just found an issue here, should check the 'nr_pages < want' condition
for searching hole, I'll re-send this patch set a little while.
Sorry for the noise!

-Jeff

> +
> +             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,


<Prev in Thread] Current Thread [Next in Thread>