Commit 622daaff0a8975fb5c5b95f24f3234550ba32e92

Authored by Ryusuke Konishi
1 parent 27e6c7a3ce

nilfs2: fiemap support

This adds fiemap to nilfs.  Two new functions, nilfs_fiemap and
nilfs_find_uncommitted_extent are added.

nilfs_fiemap() implements the fiemap inode operation, and
nilfs_find_uncommitted_extent() helps to get a range of data blocks
whose physical location has not been determined.

nilfs_fiemap() collects extent information by looping through
nilfs_bmap_lookup_contig and nilfs_find_uncommitted_extent routines.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>

Showing 6 changed files with 222 additions and 0 deletions Side-by-side Diff

... ... @@ -155,6 +155,7 @@
155 155 .truncate = nilfs_truncate,
156 156 .setattr = nilfs_setattr,
157 157 .permission = nilfs_permission,
  158 + .fiemap = nilfs_fiemap,
158 159 };
159 160  
160 161 /* end of file */
... ... @@ -916,4 +916,135 @@
916 916 nilfs_mark_inode_dirty(inode);
917 917 nilfs_transaction_commit(inode->i_sb); /* never fails */
918 918 }
  919 +
  920 +int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
  921 + __u64 start, __u64 len)
  922 +{
  923 + struct the_nilfs *nilfs = NILFS_I_NILFS(inode);
  924 + __u64 logical = 0, phys = 0, size = 0;
  925 + __u32 flags = 0;
  926 + loff_t isize;
  927 + sector_t blkoff, end_blkoff;
  928 + sector_t delalloc_blkoff;
  929 + unsigned long delalloc_blklen;
  930 + unsigned int blkbits = inode->i_blkbits;
  931 + int ret, n;
  932 +
  933 + ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC);
  934 + if (ret)
  935 + return ret;
  936 +
  937 + mutex_lock(&inode->i_mutex);
  938 +
  939 + isize = i_size_read(inode);
  940 +
  941 + blkoff = start >> blkbits;
  942 + end_blkoff = (start + len - 1) >> blkbits;
  943 +
  944 + delalloc_blklen = nilfs_find_uncommitted_extent(inode, blkoff,
  945 + &delalloc_blkoff);
  946 +
  947 + do {
  948 + __u64 blkphy;
  949 + unsigned int maxblocks;
  950 +
  951 + if (delalloc_blklen && blkoff == delalloc_blkoff) {
  952 + if (size) {
  953 + /* End of the current extent */
  954 + ret = fiemap_fill_next_extent(
  955 + fieinfo, logical, phys, size, flags);
  956 + if (ret)
  957 + break;
  958 + }
  959 + if (blkoff > end_blkoff)
  960 + break;
  961 +
  962 + flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_DELALLOC;
  963 + logical = blkoff << blkbits;
  964 + phys = 0;
  965 + size = delalloc_blklen << blkbits;
  966 +
  967 + blkoff = delalloc_blkoff + delalloc_blklen;
  968 + delalloc_blklen = nilfs_find_uncommitted_extent(
  969 + inode, blkoff, &delalloc_blkoff);
  970 + continue;
  971 + }
  972 +
  973 + /*
  974 + * Limit the number of blocks that we look up so as
  975 + * not to get into the next delayed allocation extent.
  976 + */
  977 + maxblocks = INT_MAX;
  978 + if (delalloc_blklen)
  979 + maxblocks = min_t(sector_t, delalloc_blkoff - blkoff,
  980 + maxblocks);
  981 + blkphy = 0;
  982 +
  983 + down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
  984 + n = nilfs_bmap_lookup_contig(
  985 + NILFS_I(inode)->i_bmap, blkoff, &blkphy, maxblocks);
  986 + up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
  987 +
  988 + if (n < 0) {
  989 + int past_eof;
  990 +
  991 + if (unlikely(n != -ENOENT))
  992 + break; /* error */
  993 +
  994 + /* HOLE */
  995 + blkoff++;
  996 + past_eof = ((blkoff << blkbits) >= isize);
  997 +
  998 + if (size) {
  999 + /* End of the current extent */
  1000 +
  1001 + if (past_eof)
  1002 + flags |= FIEMAP_EXTENT_LAST;
  1003 +
  1004 + ret = fiemap_fill_next_extent(
  1005 + fieinfo, logical, phys, size, flags);
  1006 + if (ret)
  1007 + break;
  1008 + size = 0;
  1009 + }
  1010 + if (blkoff > end_blkoff || past_eof)
  1011 + break;
  1012 + } else {
  1013 + if (size) {
  1014 + if (phys && blkphy << blkbits == phys + size) {
  1015 + /* The current extent goes on */
  1016 + size += n << blkbits;
  1017 + } else {
  1018 + /* Terminate the current extent */
  1019 + ret = fiemap_fill_next_extent(
  1020 + fieinfo, logical, phys, size,
  1021 + flags);
  1022 + if (ret || blkoff > end_blkoff)
  1023 + break;
  1024 +
  1025 + /* Start another extent */
  1026 + flags = FIEMAP_EXTENT_MERGED;
  1027 + logical = blkoff << blkbits;
  1028 + phys = blkphy << blkbits;
  1029 + size = n << blkbits;
  1030 + }
  1031 + } else {
  1032 + /* Start a new extent */
  1033 + flags = FIEMAP_EXTENT_MERGED;
  1034 + logical = blkoff << blkbits;
  1035 + phys = blkphy << blkbits;
  1036 + size = n << blkbits;
  1037 + }
  1038 + blkoff += n;
  1039 + }
  1040 + cond_resched();
  1041 + } while (true);
  1042 +
  1043 + /* If ret is 1 then we just hit the end of the extent array */
  1044 + if (ret == 1)
  1045 + ret = 0;
  1046 +
  1047 + mutex_unlock(&inode->i_mutex);
  1048 + return ret;
  1049 +}
... ... @@ -577,6 +577,7 @@
577 577 .rename = nilfs_rename,
578 578 .setattr = nilfs_setattr,
579 579 .permission = nilfs_permission,
  580 + .fiemap = nilfs_fiemap,
580 581 };
581 582  
582 583 const struct inode_operations nilfs_special_inode_operations = {
... ... @@ -264,6 +264,8 @@
264 264 unsigned);
265 265 extern int nilfs_mark_inode_dirty(struct inode *);
266 266 extern void nilfs_dirty_inode(struct inode *);
  267 +int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
  268 + __u64 start, __u64 len);
267 269  
268 270 /* super.c */
269 271 extern struct inode *nilfs_alloc_inode(struct super_block *);
... ... @@ -546,4 +546,88 @@
546 546 }
547 547 return TestClearPageDirty(page);
548 548 }
  549 +
  550 +/**
  551 + * nilfs_find_uncommitted_extent - find extent of uncommitted data
  552 + * @inode: inode
  553 + * @start_blk: start block offset (in)
  554 + * @blkoff: start offset of the found extent (out)
  555 + *
  556 + * This function searches an extent of buffers marked "delayed" which
  557 + * starts from a block offset equal to or larger than @start_blk. If
  558 + * such an extent was found, this will store the start offset in
  559 + * @blkoff and return its length in blocks. Otherwise, zero is
  560 + * returned.
  561 + */
  562 +unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
  563 + sector_t start_blk,
  564 + sector_t *blkoff)
  565 +{
  566 + unsigned int i;
  567 + pgoff_t index;
  568 + unsigned int nblocks_in_page;
  569 + unsigned long length = 0;
  570 + sector_t b;
  571 + struct pagevec pvec;
  572 + struct page *page;
  573 +
  574 + if (inode->i_mapping->nrpages == 0)
  575 + return 0;
  576 +
  577 + index = start_blk >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
  578 + nblocks_in_page = 1U << (PAGE_CACHE_SHIFT - inode->i_blkbits);
  579 +
  580 + pagevec_init(&pvec, 0);
  581 +
  582 +repeat:
  583 + pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE,
  584 + pvec.pages);
  585 + if (pvec.nr == 0)
  586 + return length;
  587 +
  588 + if (length > 0 && pvec.pages[0]->index > index)
  589 + goto out;
  590 +
  591 + b = pvec.pages[0]->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
  592 + i = 0;
  593 + do {
  594 + page = pvec.pages[i];
  595 +
  596 + lock_page(page);
  597 + if (page_has_buffers(page)) {
  598 + struct buffer_head *bh, *head;
  599 +
  600 + bh = head = page_buffers(page);
  601 + do {
  602 + if (b < start_blk)
  603 + continue;
  604 + if (buffer_delay(bh)) {
  605 + if (length == 0)
  606 + *blkoff = b;
  607 + length++;
  608 + } else if (length > 0) {
  609 + goto out_locked;
  610 + }
  611 + } while (++b, bh = bh->b_this_page, bh != head);
  612 + } else {
  613 + if (length > 0)
  614 + goto out_locked;
  615 +
  616 + b += nblocks_in_page;
  617 + }
  618 + unlock_page(page);
  619 +
  620 + } while (++i < pagevec_count(&pvec));
  621 +
  622 + index = page->index + 1;
  623 + pagevec_release(&pvec);
  624 + cond_resched();
  625 + goto repeat;
  626 +
  627 +out_locked:
  628 + unlock_page(page);
  629 +out:
  630 + pagevec_release(&pvec);
  631 + return length;
  632 +}
... ... @@ -66,6 +66,9 @@
66 66 struct backing_dev_info *bdi,
67 67 const struct address_space_operations *aops);
68 68 unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned);
  69 +unsigned long nilfs_find_uncommitted_extent(struct inode *inode,
  70 + sector_t start_blk,
  71 + sector_t *blkoff);
69 72  
70 73 #define NILFS_PAGE_BUG(page, m, a...) \
71 74 do { nilfs_page_bug(page); BUG(); } while (0)