[GFS2] Add generation number
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / fs / gfs2 / page.c
index 05453c5a06f087766f23f0ea35a258ca3b239b35..b93caf294b9f49e7e6429bf2fcc3cb3e3d42acdb 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
- * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
  *
  * This copyrighted material is made available to anyone wishing to use,
  * modify, copy, or redistribute it subject to the terms and conditions
 #include <linux/buffer_head.h>
 #include <linux/pagemap.h>
 #include <linux/mm.h>
-#include <asm/semaphore.h>
+#include <linux/gfs2_ondisk.h>
 
 #include "gfs2.h"
+#include "lm_interface.h"
+#include "incore.h"
 #include "bmap.h"
 #include "inode.h"
 #include "page.h"
 #include "trans.h"
+#include "ops_address.h"
+#include "util.h"
 
 /**
  * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
@@ -33,21 +37,18 @@ void gfs2_pte_inval(struct gfs2_glock *gl)
        struct gfs2_inode *ip;
        struct inode *inode;
 
-       ip = get_gl2ip(gl);
+       ip = gl->gl_object;
+       inode = &ip->i_inode;
        if (!ip || !S_ISREG(ip->i_di.di_mode))
                return;
 
        if (!test_bit(GIF_PAGED, &ip->i_flags))
                return;
 
-       inode = gfs2_ip2v_lookup(ip);
-       if (inode) {
-               unmap_shared_mapping_range(inode->i_mapping, 0, 0);
-               iput(inode);
+       unmap_shared_mapping_range(inode->i_mapping, 0, 0);
 
-               if (test_bit(GIF_SW_PAGED, &ip->i_flags))
-                       set_bit(GLF_DIRTY, &gl->gl_flags);
-       }
+       if (test_bit(GIF_SW_PAGED, &ip->i_flags))
+               set_bit(GLF_DIRTY, &gl->gl_flags);
 
        clear_bit(GIF_SW_PAGED, &ip->i_flags);
 }
@@ -63,20 +64,13 @@ void gfs2_page_inval(struct gfs2_glock *gl)
        struct gfs2_inode *ip;
        struct inode *inode;
 
-       ip = get_gl2ip(gl);
+       ip = gl->gl_object;
+       inode = &ip->i_inode;
        if (!ip || !S_ISREG(ip->i_di.di_mode))
                return;
 
-       inode = gfs2_ip2v_lookup(ip);
-       if (inode) {
-               struct address_space *mapping = inode->i_mapping;
-
-               truncate_inode_pages(mapping, 0);
-               gfs2_assert_withdraw(ip->i_sbd, !mapping->nrpages);
-
-               iput(inode);
-       }
-
+       truncate_inode_pages(inode->i_mapping, 0);
+       gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
        clear_bit(GIF_PAGED, &ip->i_flags);
 }
 
@@ -93,32 +87,30 @@ void gfs2_page_sync(struct gfs2_glock *gl, int flags)
 {
        struct gfs2_inode *ip;
        struct inode *inode;
+       struct address_space *mapping;
+       int error = 0;
 
-       ip = get_gl2ip(gl);
+       ip = gl->gl_object;
+       inode = &ip->i_inode;
        if (!ip || !S_ISREG(ip->i_di.di_mode))
                return;
 
-       inode = gfs2_ip2v_lookup(ip);
-       if (inode) {
-               struct address_space *mapping = inode->i_mapping;
-               int error = 0;
+       mapping = inode->i_mapping;
 
-               if (flags & DIO_START)
-                       filemap_fdatawrite(mapping);
-               if (!error && (flags & DIO_WAIT))
-                       error = filemap_fdatawait(mapping);
+       if (flags & DIO_START)
+               filemap_fdatawrite(mapping);
+       if (!error && (flags & DIO_WAIT))
+               error = filemap_fdatawait(mapping);
 
-               /* Put back any errors cleared by filemap_fdatawait()
-                  so they can be caught by someone who can pass them
-                  up to user space. */
+       /* Put back any errors cleared by filemap_fdatawait()
+          so they can be caught by someone who can pass them
+          up to user space. */
 
-               if (error == -ENOSPC)
-                       set_bit(AS_ENOSPC, &mapping->flags);
-               else if (error)
-                       set_bit(AS_EIO, &mapping->flags);
+       if (error == -ENOSPC)
+               set_bit(AS_ENOSPC, &mapping->flags);
+       else if (error)
+               set_bit(AS_EIO, &mapping->flags);
 
-               iput(inode);
-       }
 }
 
 /**
@@ -134,8 +126,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)
 {
-       struct gfs2_sbd *sdp = ip->i_sbd;
-       struct inode *inode = ip->i_vnode;
+       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct inode *inode = &ip->i_inode;
        struct page *page = (struct page *)private;
        struct buffer_head *bh;
        int release = 0;
@@ -150,11 +142,9 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
        if (!PageUptodate(page)) {
                void *kaddr = kmap(page);
 
-               memcpy(kaddr,
-                      dibh->b_data + sizeof(struct gfs2_dinode),
+               memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
                       ip->i_di.di_size);
-               memset(kaddr + ip->i_di.di_size,
-                      0,
+               memset(kaddr + ip->i_di.di_size, 0,
                       PAGE_CACHE_SIZE - ip->i_di.di_size);
                kunmap(page);
 
@@ -171,8 +161,8 @@ int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
                map_bh(bh, inode->i_sb, block);
 
        set_buffer_uptodate(bh);
-       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED)
-               gfs2_trans_add_databuf(sdp, bh);
+       if ((sdp->sd_args.ar_data == GFS2_DATA_ORDERED) || gfs2_is_jdata(ip))
+               gfs2_trans_add_bh(ip->i_gl, bh, 0);
        mark_buffer_dirty(bh);
 
        if (release) {
@@ -184,76 +174,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 gfs2_sbd *sdp = ip->i_sbd;
-       struct inode *inode = ip->i_vnode;
-       struct page *page;
+       struct inode *inode = mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       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)
-               gfs2_trans_add_databuf(sdp, bh);
-       mark_buffer_dirty(bh);
+       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;
+       }
 
- out:
+       if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+               gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+       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);
@@ -261,13 +256,12 @@ void gfs2_page_add_databufs(struct gfs2_sbd *sdp, struct page *page,
        struct buffer_head *bh;
        unsigned int start, end;
 
-       for (bh = head, start = 0;
-            bh != head || !start;
+       for (bh = head, start = 0; bh != head || !start;
             bh = bh->b_this_page, start = end) {
                end = start + bsize;
                if (end <= from || start >= to)
                        continue;
-               gfs2_trans_add_databuf(sdp, bh);
+               gfs2_trans_add_bh(ip->i_gl, bh, 0);
        }
 }