diff options
-rw-r--r-- | fs/gfs2/Makefile | 2 | ||||
-rw-r--r-- | fs/gfs2/bmap.c | 78 | ||||
-rw-r--r-- | fs/gfs2/glops.c | 89 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 19 | ||||
-rw-r--r-- | fs/gfs2/ops_inode.c | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_super.c | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_vm.c | 1 | ||||
-rw-r--r-- | fs/gfs2/page.c | 207 | ||||
-rw-r--r-- | fs/gfs2/page.h | 21 |
9 files changed, 184 insertions, 235 deletions
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile index 0b79776..b92852b 100644 --- a/fs/gfs2/Makefile +++ b/fs/gfs2/Makefile @@ -2,7 +2,7 @@ obj-$(CONFIG_GFS2_FS) += gfs2.o gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \ glops.o inode.o lm.o log.o lops.o locking.o lvb.o main.o meta_io.o \ mount.o ondisk.o ops_address.o ops_dentry.o ops_export.o ops_file.o \ - ops_fstype.o ops_inode.o ops_super.o ops_vm.o page.o quota.o \ + ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \ recovery.o rgrp.o super.o sys.o trans.o util.o obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/ diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 72b19c5..d20d41e 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -22,12 +22,12 @@ #include "glock.h" #include "inode.h" #include "meta_io.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" #include "dir.h" #include "util.h" +#include "ops_address.h" /* This doesn't need to be that large as max 64 bit pointers in a 4k * 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) return error; } + +/** + * gfs2_block_truncate_page - Deal with zeroing out data for truncate + * + * This is partly borrowed from ext3. + */ +static int gfs2_block_truncate_page(struct address_space *mapping) +{ + 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; + int err; + + page = grab_cache_page(mapping, index); + if (!page) + return 0; + + 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, blocksize, 0); + + /* Find the buffer that contains "offset" */ + bh = page_buffers(page); + pos = blocksize; + while (offset >= pos) { + bh = bh->b_this_page; + iblock++; + pos += blocksize; + } + + err = 0; + + 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_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 err; +} + static int trunc_start(struct gfs2_inode *ip, uint64_t size) { struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index a01874c..3f909a8 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -23,11 +23,98 @@ #include "inode.h" #include "log.h" #include "meta_io.h" -#include "page.h" #include "recovery.h" #include "rgrp.h" #include "util.h" + +/** + * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock + * @gl: the glock + * + */ + +static void gfs2_pte_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + struct inode *inode; + + 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; + + 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); + + clear_bit(GIF_SW_PAGED, &ip->i_flags); +} + +/** + * gfs2_page_inval - Invalidate all pages associated with a glock + * @gl: the glock + * + */ + +static void gfs2_page_inval(struct gfs2_glock *gl) +{ + struct gfs2_inode *ip; + struct inode *inode; + + ip = gl->gl_object; + inode = &ip->i_inode; + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + 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); +} + +/** + * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock + * @gl: the glock + * @flags: DIO_START | DIO_WAIT + * + * Syncs data (not metadata) for a regular file. + * No-op for all other types. + */ + +static 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 = gl->gl_object; + inode = &ip->i_inode; + if (!ip || !S_ISREG(ip->i_di.di_mode)) + return; + + mapping = inode->i_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. */ + + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else if (error) + set_bit(AS_EIO, &mapping->flags); + +} + /** * meta_go_sync - sync out the metadata for this glock * @gl: the glock diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 93e00a8..fca69f1 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c @@ -27,7 +27,6 @@ #include "log.h" #include "meta_io.h" #include "ops_address.h" -#include "page.h" #include "quota.h" #include "trans.h" #include "rgrp.h" @@ -35,6 +34,24 @@ #include "util.h" #include "glops.h" + +static 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); + unsigned int bsize = head->b_size; + struct buffer_head *bh; + unsigned int start, end; + + 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_bh(ip->i_gl, bh, 0); + } +} + /** * gfs2_get_block - Fills in a buffer head with details about a block * @inode: The inode diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index caecafe..8fb7c5c 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -34,7 +34,6 @@ #include "meta_io.h" #include "ops_dentry.h" #include "ops_inode.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 50ea7f2..730c722 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -30,7 +30,6 @@ #include "log.h" #include "mount.h" #include "ops_super.h" -#include "page.h" #include "quota.h" #include "recovery.h" #include "rgrp.h" diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index 910722d..aff6637 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -23,7 +23,6 @@ #include "glock.h" #include "inode.h" #include "ops_vm.h" -#include "page.h" #include "quota.h" #include "rgrp.h" #include "trans.h" diff --git a/fs/gfs2/page.c b/fs/gfs2/page.c deleted file mode 100644 index 0d6befe..0000000 --- a/fs/gfs2/page.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 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 - * of the GNU General Public License v.2. - */ - -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/completion.h> -#include <linux/buffer_head.h> -#include <linux/pagemap.h> -#include <linux/mm.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 - * @gl: the glock - * - */ - -void gfs2_pte_inval(struct gfs2_glock *gl) -{ - struct gfs2_inode *ip; - struct inode *inode; - - 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; - - 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); - - clear_bit(GIF_SW_PAGED, &ip->i_flags); -} - -/** - * gfs2_page_inval - Invalidate all pages associated with a glock - * @gl: the glock - * - */ - -void gfs2_page_inval(struct gfs2_glock *gl) -{ - struct gfs2_inode *ip; - struct inode *inode; - - ip = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) - return; - - 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); -} - -/** - * gfs2_page_sync - Sync the data pages (not metadata) associated with a glock - * @gl: the glock - * @flags: DIO_START | DIO_WAIT - * - * Syncs data (not metadata) for a regular file. - * No-op for all other types. - */ - -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 = gl->gl_object; - inode = &ip->i_inode; - if (!ip || !S_ISREG(ip->i_di.di_mode)) - return; - - mapping = inode->i_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. */ - - if (error == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else if (error) - set_bit(AS_EIO, &mapping->flags); - -} - -/** - * gfs2_block_truncate_page - Deal with zeroing out data for truncate - * - * This is partly borrowed from ext3. - */ -int gfs2_block_truncate_page(struct address_space *mapping) -{ - 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; - int err; - - page = grab_cache_page(mapping, index); - if (!page) - return 0; - - 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, blocksize, 0); - - /* Find the buffer that contains "offset" */ - bh = page_buffers(page); - pos = blocksize; - while (offset >= pos) { - bh = bh->b_this_page; - iblock++; - pos += blocksize; - } - - err = 0; - - 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_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 err; -} - -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); - unsigned int bsize = head->b_size; - struct buffer_head *bh; - unsigned int start, end; - - 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_bh(ip->i_gl, bh, 0); - } -} - diff --git a/fs/gfs2/page.h b/fs/gfs2/page.h deleted file mode 100644 index 67a4f4b..0000000 --- a/fs/gfs2/page.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) Sistina Software, Inc. 1997-2003 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 - * of the GNU General Public License v.2. - */ - -#ifndef __PAGE_DOT_H__ -#define __PAGE_DOT_H__ - -void gfs2_pte_inval(struct gfs2_glock *gl); -void gfs2_page_inval(struct gfs2_glock *gl); -void gfs2_page_sync(struct gfs2_glock *gl, int flags); - -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__ */ |