diff options
author | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2010-12-26 02:38:43 -0500 |
---|---|---|
committer | Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> | 2011-01-10 00:05:46 -0500 |
commit | 622daaff0a8975fb5c5b95f24f3234550ba32e92 (patch) | |
tree | 5ae5de9044f962471fa2694654134f5b58f73ace /fs/nilfs2/inode.c | |
parent | 27e6c7a3ce29ae5fa5bec4ed5917f8508bfac120 (diff) |
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>
Diffstat (limited to 'fs/nilfs2/inode.c')
-rw-r--r-- | fs/nilfs2/inode.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 1a546a86d7a7..b2a815033ee3 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -916,3 +916,134 @@ void nilfs_dirty_inode(struct inode *inode) | |||
916 | nilfs_mark_inode_dirty(inode); | 916 | nilfs_mark_inode_dirty(inode); |
917 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 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 | } | ||