diff options
Diffstat (limited to 'fs/gfs2/bmap.c')
-rw-r--r-- | fs/gfs2/bmap.c | 78 |
1 files changed, 77 insertions, 1 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 72b19c5d7807..d20d41e1c028 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -22,12 +22,12 @@ | |||
22 | #include "glock.h" | 22 | #include "glock.h" |
23 | #include "inode.h" | 23 | #include "inode.h" |
24 | #include "meta_io.h" | 24 | #include "meta_io.h" |
25 | #include "page.h" | ||
26 | #include "quota.h" | 25 | #include "quota.h" |
27 | #include "rgrp.h" | 26 | #include "rgrp.h" |
28 | #include "trans.h" | 27 | #include "trans.h" |
29 | #include "dir.h" | 28 | #include "dir.h" |
30 | #include "util.h" | 29 | #include "util.h" |
30 | #include "ops_address.h" | ||
31 | 31 | ||
32 | /* This doesn't need to be that large as max 64 bit pointers in a 4k | 32 | /* This doesn't need to be that large as max 64 bit pointers in a 4k |
33 | * block is 512, so __u16 is fine for that. It saves stack space to | 33 | * block is 512, so __u16 is fine for that. It saves stack space to |
@@ -885,6 +885,82 @@ static int do_grow(struct gfs2_inode *ip, uint64_t size) | |||
885 | return error; | 885 | return error; |
886 | } | 886 | } |
887 | 887 | ||
888 | |||
889 | /** | ||
890 | * gfs2_block_truncate_page - Deal with zeroing out data for truncate | ||
891 | * | ||
892 | * This is partly borrowed from ext3. | ||
893 | */ | ||
894 | static int gfs2_block_truncate_page(struct address_space *mapping) | ||
895 | { | ||
896 | struct inode *inode = mapping->host; | ||
897 | struct gfs2_inode *ip = GFS2_I(inode); | ||
898 | struct gfs2_sbd *sdp = GFS2_SB(inode); | ||
899 | loff_t from = inode->i_size; | ||
900 | unsigned long index = from >> PAGE_CACHE_SHIFT; | ||
901 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
902 | unsigned blocksize, iblock, length, pos; | ||
903 | struct buffer_head *bh; | ||
904 | struct page *page; | ||
905 | void *kaddr; | ||
906 | int err; | ||
907 | |||
908 | page = grab_cache_page(mapping, index); | ||
909 | if (!page) | ||
910 | return 0; | ||
911 | |||
912 | blocksize = inode->i_sb->s_blocksize; | ||
913 | length = blocksize - (offset & (blocksize - 1)); | ||
914 | iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); | ||
915 | |||
916 | if (!page_has_buffers(page)) | ||
917 | create_empty_buffers(page, blocksize, 0); | ||
918 | |||
919 | /* Find the buffer that contains "offset" */ | ||
920 | bh = page_buffers(page); | ||
921 | pos = blocksize; | ||
922 | while (offset >= pos) { | ||
923 | bh = bh->b_this_page; | ||
924 | iblock++; | ||
925 | pos += blocksize; | ||
926 | } | ||
927 | |||
928 | err = 0; | ||
929 | |||
930 | if (!buffer_mapped(bh)) { | ||
931 | gfs2_get_block(inode, iblock, bh, 0); | ||
932 | /* unmapped? It's a hole - nothing to do */ | ||
933 | if (!buffer_mapped(bh)) | ||
934 | goto unlock; | ||
935 | } | ||
936 | |||
937 | /* Ok, it's mapped. Make sure it's up-to-date */ | ||
938 | if (PageUptodate(page)) | ||
939 | set_buffer_uptodate(bh); | ||
940 | |||
941 | if (!buffer_uptodate(bh)) { | ||
942 | err = -EIO; | ||
943 | ll_rw_block(READ, 1, &bh); | ||
944 | wait_on_buffer(bh); | ||
945 | /* Uhhuh. Read error. Complain and punt. */ | ||
946 | if (!buffer_uptodate(bh)) | ||
947 | goto unlock; | ||
948 | } | ||
949 | |||
950 | if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) | ||
951 | gfs2_trans_add_bh(ip->i_gl, bh, 0); | ||
952 | |||
953 | kaddr = kmap_atomic(page, KM_USER0); | ||
954 | memset(kaddr + offset, 0, length); | ||
955 | flush_dcache_page(page); | ||
956 | kunmap_atomic(kaddr, KM_USER0); | ||
957 | |||
958 | unlock: | ||
959 | unlock_page(page); | ||
960 | page_cache_release(page); | ||
961 | return err; | ||
962 | } | ||
963 | |||
888 | static int trunc_start(struct gfs2_inode *ip, uint64_t size) | 964 | static int trunc_start(struct gfs2_inode *ip, uint64_t size) |
889 | { | 965 | { |
890 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 966 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |