]> err.no Git - linux-2.6/commitdiff
[GFS2] Update truncate function (shrinking partial blocks)
authorSteven Whitehouse <swhiteho@redhat.com>
Tue, 31 Jan 2006 10:00:25 +0000 (10:00 +0000)
committerSteven Whitehouse <swhiteho@redhat.com>
Tue, 31 Jan 2006 10:00:25 +0000 (10:00 +0000)
Update the function in GFS2 which deals with truncation of
partial blocks. Some of the code is "borrowed" from ext3
since it appears to give a good model of how to do this
operation. The function is renamed gfs2_block_truncate_page
accordingly.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
fs/gfs2/bmap.c
fs/gfs2/ops_address.c
fs/gfs2/page.c
fs/gfs2/page.h

index ff4a9175b4e1c117a2d89a6a1b0d189d72570715..bd194f645c52df0a5797575e2158739284ff18e1 100644 (file)
@@ -872,7 +872,7 @@ static int trunc_start(struct gfs2_inode *ip, uint64_t size)
                        if (do_div(junk, sdp->sd_jbsize))
                                error = truncator_journaled(ip, size);
                } else if (size & (uint64_t)(sdp->sd_sb.sb_bsize - 1))
-                       error = gfs2_truncator_page(ip, size);
+                       error = gfs2_block_truncate_page(ip->i_vnode->i_mapping);
 
                if (!error) {
                        ip->i_di.di_size = size;
index da5a0b445188ac793035893ce1adea4cd6d307e7..d611b2ad2e97f087c0bb91863698b738009075fd 100644 (file)
@@ -385,7 +385,7 @@ static int gfs2_commit_write(struct file *file, struct page *page,
                        i_size_write(inode, file_size);
        } else {
                if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED)
-                       gfs2_page_add_databufs(sdp, page, from, to);
+                       gfs2_page_add_databufs(ip, page, from, to);
                error = generic_commit_write(file, page, from, to);
                if (error)
                        goto fail;
index 05453c5a06f087766f23f0ea35a258ca3b239b35..ea31bceac4f288f3e68ab6713c52bbfc7fd78fb3 100644 (file)
@@ -21,6 +21,7 @@
 #include "inode.h"
 #include "page.h"
 #include "trans.h"
+#include "ops_address.h"
 
 /**
  * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
@@ -184,76 +185,81 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
 }
 
 /**
- * gfs2_truncator_page - truncate a partial data block in the page cache
- * @ip: the inode
- * @size: the size the file should be
+ * gfs2_block_truncate_page - Deal with zeroing out data for truncate
  *
- * Returns: errno
+ * This is partly borrowed from ext3.
  */
-
-int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size)
+int gfs2_block_truncate_page(struct address_space *mapping)
 {
+       struct inode *inode = mapping->host;
+       struct gfs2_inode *ip = get_v2ip(inode);
        struct gfs2_sbd *sdp = ip->i_sbd;
-       struct inode *inode = ip->i_vnode;
-       struct page *page;
+       loff_t from = inode->i_size;
+       unsigned long index = from >> PAGE_CACHE_SHIFT;
+       unsigned offset = from & (PAGE_CACHE_SIZE-1);
+       unsigned blocksize, iblock, length, pos;
        struct buffer_head *bh;
+       struct page *page;
        void *kaddr;
-       uint64_t lbn, dbn;
-       unsigned long index;
-       unsigned int offset;
-       unsigned int bufnum;
-       int new = 0;
-       int error;
-
-       lbn = size >> inode->i_blkbits;
-       error = gfs2_block_map(ip, lbn, &new, &dbn, NULL);
-       if (error || !dbn)
-               return error;
-
-       index = size >> PAGE_CACHE_SHIFT;
-       offset = size & (PAGE_CACHE_SIZE - 1);
-       bufnum = lbn - (index << (PAGE_CACHE_SHIFT - inode->i_blkbits));
-
-       page = read_cache_page(inode->i_mapping, index,
-                              (filler_t *)inode->i_mapping->a_ops->readpage,
-                              NULL);
-       if (IS_ERR(page))
-               return PTR_ERR(page);
-
-       lock_page(page);
-
-       if (!PageUptodate(page) || PageError(page)) {
-               error = -EIO;
-               goto out;
-       }
+       int err;
+
+       page = grab_cache_page(mapping, index);
+       if (!page)
+               return 0;
 
-       kaddr = kmap(page);
-       memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
-       kunmap(page);
+       blocksize = inode->i_sb->s_blocksize;
+       length = blocksize - (offset & (blocksize - 1));
+       iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
 
        if (!page_has_buffers(page))
-               create_empty_buffers(page, 1 << inode->i_blkbits,
-                                    (1 << BH_Uptodate));
+               create_empty_buffers(page, blocksize, 0);
 
-       for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page)
-               /* Do nothing */;
+       /* Find the buffer that contains "offset" */
+       bh = page_buffers(page);
+       pos = blocksize;
+       while (offset >= pos) {
+               bh = bh->b_this_page;
+               iblock++;
+               pos += blocksize;
+       }
 
-       if (!buffer_mapped(bh))
-               map_bh(bh, inode->i_sb, dbn);
+       err = 0;
 
-       set_buffer_uptodate(bh);
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED)
+       if (!buffer_mapped(bh)) {
+               gfs2_get_block(inode, iblock, bh, 0);
+               /* unmapped? It's a hole - nothing to do */
+               if (!buffer_mapped(bh))
+                       goto unlock;
+       }
+
+       /* Ok, it's mapped. Make sure it's up-to-date */
+       if (PageUptodate(page))
+               set_buffer_uptodate(bh);
+
+       if (!buffer_uptodate(bh)) {
+               err = -EIO;
+               ll_rw_block(READ, 1, &bh);
+               wait_on_buffer(bh);
+               /* Uhhuh. Read error. Complain and punt. */
+               if (!buffer_uptodate(bh))
+                       goto unlock;
+       }
+
+       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED/* || gfs2_is_jdata(ip)*/)
                gfs2_trans_add_databuf(sdp, bh);
-       mark_buffer_dirty(bh);
 
- out:
+       kaddr = kmap_atomic(page, KM_USER0);
+       memset(kaddr + offset, 0, length);
+       flush_dcache_page(page);
+       kunmap_atomic(kaddr, KM_USER0);
+
+unlock:
        unlock_page(page);
        page_cache_release(page);
-
-       return error;
+       return err;
 }
 
-void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page,
+void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
                            unsigned int from, unsigned int to)
 {
        struct buffer_head *head = page_buffers(page);
@@ -267,7 +273,7 @@ void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page,
                end = start + bsize;
                if (end <= from || start >= to)
                        continue;
-               gfs2_trans_add_databuf(sdp, bh);
+               gfs2_trans_add_databuf(ip->i_sbd, bh);
        }
 }
 
index 7ad8c99ee0efceff1f758a51fe7a1786029912de..346e296420c6295b048f27ef95369203f0f0cdf3 100644 (file)
@@ -16,8 +16,8 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags);
 
 int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
                        uint64_t block, void *private);
-int gfs2_truncator_page(struct gfs2_inode *ip, uint64_t size);
-void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page,
+int gfs2_block_truncate_page(struct address_space *mapping);
+void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
                            unsigned int from, unsigned int to);
 
 #endif /* __PAGE_DOT_H__ */