diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-23 15:28:51 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-23 15:28:51 -0800 |
commit | debf798b1ed82053689d900670eb27fb2f1b4bd3 (patch) | |
tree | 00684a077494864a990e3be82ad2796367f825f9 /fs/xfs | |
parent | b0e6e962992b76580f4900b166a337bad7c1e81b (diff) | |
parent | 4d74f423c722b8cadfabe087369200013b217b67 (diff) |
Merge git://oss.sgi.com:8090/oss/git/xfs-2.6
* git://oss.sgi.com:8090/oss/git/xfs-2.6: (71 commits)
[XFS] Sync up one/two other minor changes missed in previous merges.
[XFS] Reenable the noikeep (delete inode cluster space) option by default.
[XFS] Check that a page has dirty buffers before finding it acceptable for
[XFS] Fixup naming inconsistencies found by Pekka Enberg and one from Jan
[XFS] Explain the race closed by the addition of vn_iowait() to the start
[XFS] Fixing the error caused by the conflict between DIO Write's
[XFS] Fixing KDB's xrwtrc command, also added the current process id into
[XFS] Fix compiler warning from xfs_file_compat_invis_ioctl prototype.
[XFS] remove bogus INT_GET for u8 variables in xfs_dir_leaf.c
[XFS] endianess annotations for xfs_da_node_hdr_t
[XFS] endianess annotations for xfs_da_node_entry_t
[XFS] store xfs_attr_inactive_list_t in native endian
[XFS] store xfs_attr_sf_sort in native endian
[XFS] endianess annotations for xfs_attr_shortform_t
[XFS] endianess annotations for xfs_attr_leaf_name_remote_t
[XFS] endianess annotations for xfs_attr_leaf_name_local_t
[XFS] endianess annotations for xfs_attr_leaf_entry_t
[XFS] endianess annotations for xfs_attr_leaf_hdr_t
[XFS] remove bogus INT_GET on u8 variables in xfs_dir2_block.c
[XFS] endianess annotations for xfs_da_blkinfo_t
...
Diffstat (limited to 'fs/xfs')
68 files changed, 4902 insertions, 3118 deletions
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6 index 97bd4743b46..5d73eaa1971 100644 --- a/fs/xfs/Makefile-linux-2.6 +++ b/fs/xfs/Makefile-linux-2.6 @@ -1,33 +1,19 @@ # -# Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. +# Copyright (c) 2000-2005 Silicon Graphics, Inc. +# All Rights Reserved. # -# This program is free software; you can redistribute it and/or modify it -# under the terms of version 2 of the GNU General Public License as +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as # published by the Free Software Foundation. # -# This program is distributed in the hope that it would be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -# Further, this software is distributed without any warranty that it is -# free of the rightful claim of any third person regarding infringement -# or the like. Any license provided herein, whether implied or -# otherwise, applies only to this software file. Patent licenses, if -# any, provided herein do not apply to combinations of this program with -# other software, or any other product whatsoever. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write the Free Software Foundation, Inc., 59 -# Temple Place - Suite 330, Boston MA 02111-1307, USA. -# -# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, -# Mountain View, CA 94043, or: -# -# http://www.sgi.com -# -# For further information regarding this notice, see: -# -# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# You should have received a copy of the GNU General Public License +# along with this program; if not, write the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # EXTRA_CFLAGS += -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char @@ -36,7 +22,7 @@ XFS_LINUX := linux-2.6 ifeq ($(CONFIG_XFS_DEBUG),y) EXTRA_CFLAGS += -g -DSTATIC="" -DDEBUG - EXTRA_CFLAGS += -DPAGEBUF_LOCK_TRACKING + EXTRA_CFLAGS += -DXFS_BUF_LOCK_TRACKING endif ifeq ($(CONFIG_XFS_TRACE),y) EXTRA_CFLAGS += -DXFS_ALLOC_TRACE @@ -50,7 +36,7 @@ ifeq ($(CONFIG_XFS_TRACE),y) EXTRA_CFLAGS += -DXFS_ILOCK_TRACE EXTRA_CFLAGS += -DXFS_LOG_TRACE EXTRA_CFLAGS += -DXFS_RW_TRACE - EXTRA_CFLAGS += -DPAGEBUF_TRACE + EXTRA_CFLAGS += -DXFS_BUF_TRACE EXTRA_CFLAGS += -DXFS_VNODE_TRACE endif diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index c64a29cdfff..f0268a84e6f 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h @@ -23,17 +23,8 @@ #include <linux/mm.h> /* - * memory management routines + * Process flags handling */ -#define KM_SLEEP 0x0001u -#define KM_NOSLEEP 0x0002u -#define KM_NOFS 0x0004u -#define KM_MAYFAIL 0x0008u - -#define kmem_zone kmem_cache -#define kmem_zone_t struct kmem_cache - -typedef unsigned long xfs_pflags_t; #define PFLAGS_TEST_NOIO() (current->flags & PF_NOIO) #define PFLAGS_TEST_FSTRANS() (current->flags & PF_FSTRANS) @@ -67,74 +58,102 @@ typedef unsigned long xfs_pflags_t; *(NSTATEP) = *(OSTATEP); \ } while (0) -static __inline gfp_t kmem_flags_convert(unsigned int __nocast flags) +/* + * General memory allocation interfaces + */ + +#define KM_SLEEP 0x0001u +#define KM_NOSLEEP 0x0002u +#define KM_NOFS 0x0004u +#define KM_MAYFAIL 0x0008u + +/* + * We use a special process flag to avoid recursive callbacks into + * the filesystem during transactions. We will also issue our own + * warnings, so we explicitly skip any generic ones (silly of us). + */ +static inline gfp_t +kmem_flags_convert(unsigned int __nocast flags) { - gfp_t lflags = __GFP_NOWARN; /* we'll report problems, if need be */ + gfp_t lflags; -#ifdef DEBUG - if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL))) { - printk(KERN_WARNING - "XFS: memory allocation with wrong flags (%x)\n", flags); - BUG(); - } -#endif + BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL)); if (flags & KM_NOSLEEP) { - lflags |= GFP_ATOMIC; + lflags = GFP_ATOMIC | __GFP_NOWARN; } else { - lflags |= GFP_KERNEL; - - /* avoid recusive callbacks to filesystem during transactions */ + lflags = GFP_KERNEL | __GFP_NOWARN; if (PFLAGS_TEST_FSTRANS() || (flags & KM_NOFS)) lflags &= ~__GFP_FS; } - - return lflags; + return lflags; } -static __inline kmem_zone_t * +extern void *kmem_alloc(size_t, unsigned int __nocast); +extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast); +extern void *kmem_zalloc(size_t, unsigned int __nocast); +extern void kmem_free(void *, size_t); + +/* + * Zone interfaces + */ + +#define KM_ZONE_HWALIGN SLAB_HWCACHE_ALIGN +#define KM_ZONE_RECLAIM SLAB_RECLAIM_ACCOUNT +#define KM_ZONE_SPREAD 0 + +#define kmem_zone kmem_cache +#define kmem_zone_t struct kmem_cache + +static inline kmem_zone_t * kmem_zone_init(int size, char *zone_name) { return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); } -static __inline void +static inline kmem_zone_t * +kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, + void (*construct)(void *, kmem_zone_t *, unsigned long)) +{ + return kmem_cache_create(zone_name, size, 0, flags, construct, NULL); +} + +static inline void kmem_zone_free(kmem_zone_t *zone, void *ptr) { kmem_cache_free(zone, ptr); } -static __inline void +static inline void kmem_zone_destroy(kmem_zone_t *zone) { if (zone && kmem_cache_destroy(zone)) BUG(); } -extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast); extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast); +extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast); -extern void *kmem_alloc(size_t, unsigned int __nocast); -extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast); -extern void *kmem_zalloc(size_t, unsigned int __nocast); -extern void kmem_free(void *, size_t); +/* + * Low memory cache shrinkers + */ typedef struct shrinker *kmem_shaker_t; typedef int (*kmem_shake_func_t)(int, gfp_t); -static __inline kmem_shaker_t +static inline kmem_shaker_t kmem_shake_register(kmem_shake_func_t sfunc) { return set_shrinker(DEFAULT_SEEKS, sfunc); } -static __inline void +static inline void kmem_shake_deregister(kmem_shaker_t shrinker) { remove_shrinker(shrinker); } -static __inline int +static inline int kmem_shake_allow(gfp_t gfp_mask) { return (gfp_mask & __GFP_WAIT); diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 74d8be87f98..97fc056130e 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -43,7 +43,29 @@ #include <linux/pagevec.h> #include <linux/writeback.h> -STATIC void xfs_count_page_state(struct page *, int *, int *, int *); +STATIC void +xfs_count_page_state( + struct page *page, + int *delalloc, + int *unmapped, + int *unwritten) +{ + struct buffer_head *bh, *head; + + *delalloc = *unmapped = *unwritten = 0; + + bh = head = page_buffers(page); + do { + if (buffer_uptodate(bh) && !buffer_mapped(bh)) + (*unmapped) = 1; + else if (buffer_unwritten(bh) && !buffer_delay(bh)) + clear_buffer_unwritten(bh); + else if (buffer_unwritten(bh)) + (*unwritten) = 1; + else if (buffer_delay(bh)) + (*delalloc) = 1; + } while ((bh = bh->b_this_page) != head); +} #if defined(XFS_RW_TRACE) void @@ -54,7 +76,7 @@ xfs_page_trace( int mask) { xfs_inode_t *ip; - vnode_t *vp = LINVFS_GET_VP(inode); + vnode_t *vp = vn_from_inode(inode); loff_t isize = i_size_read(inode); loff_t offset = page_offset(page); int delalloc = -1, unmapped = -1, unwritten = -1; @@ -81,7 +103,7 @@ xfs_page_trace( (void *)((unsigned long)delalloc), (void *)((unsigned long)unmapped), (void *)((unsigned long)unwritten), - (void *)NULL, + (void *)((unsigned long)current_pid()), (void *)NULL); } #else @@ -192,7 +214,7 @@ xfs_alloc_ioend( ioend->io_uptodate = 1; /* cleared if any I/O fails */ ioend->io_list = NULL; ioend->io_type = type; - ioend->io_vnode = LINVFS_GET_VP(inode); + ioend->io_vnode = vn_from_inode(inode); ioend->io_buffer_head = NULL; ioend->io_buffer_tail = NULL; atomic_inc(&ioend->io_vnode->v_iocount); @@ -217,7 +239,7 @@ xfs_map_blocks( xfs_iomap_t *mapp, int flags) { - vnode_t *vp = LINVFS_GET_VP(inode); + vnode_t *vp = vn_from_inode(inode); int error, nmaps = 1; VOP_BMAP(vp, offset, count, flags, mapp, &nmaps, error); @@ -462,28 +484,37 @@ xfs_add_to_ioend( } STATIC void +xfs_map_buffer( + struct buffer_head *bh, + xfs_iomap_t *mp, + xfs_off_t offset, + uint block_bits) +{ + sector_t bn; + + ASSERT(mp->iomap_bn != IOMAP_DADDR_NULL); + + bn = (mp->iomap_bn >> (block_bits - BBSHIFT)) + + ((offset - mp->iomap_offset) >> block_bits); + + ASSERT(bn || (mp->iomap_flags & IOMAP_REALTIME)); + + bh->b_blocknr = bn; + set_buffer_mapped(bh); +} + +STATIC void xfs_map_at_offset( struct buffer_head *bh, loff_t offset, int block_bits, xfs_iomap_t *iomapp) { - xfs_daddr_t bn; - int sector_shift; - ASSERT(!(iomapp->iomap_flags & IOMAP_HOLE)); ASSERT(!(iomapp->iomap_flags & IOMAP_DELAY)); - ASSERT(iomapp->iomap_bn != IOMAP_DADDR_NULL); - - sector_shift = block_bits - BBSHIFT; - bn = (iomapp->iomap_bn >> sector_shift) + - ((offset - iomapp->iomap_offset) >> block_bits); - - ASSERT(bn || (iomapp->iomap_flags & IOMAP_REALTIME)); - ASSERT((bn << sector_shift) >= iomapp->iomap_bn); lock_buffer(bh); - bh->b_blocknr = bn; + xfs_map_buffer(bh, iomapp, offset, block_bits); bh->b_bdev = iomapp->iomap_target->bt_bdev; set_buffer_mapped(bh); clear_buffer_delay(bh); @@ -616,7 +647,7 @@ xfs_is_delayed_page( acceptable = (type == IOMAP_UNWRITTEN); else if (buffer_delay(bh)) acceptable = (type == IOMAP_DELAY); - else if (buffer_mapped(bh)) + else if (buffer_dirty(bh) && buffer_mapped(bh)) acceptable = (type == 0); else break; @@ -1040,8 +1071,159 @@ error: return err; } +/* + * writepage: Called from one of two places: + * + * 1. we are flushing a delalloc buffer head. + * + * 2. we are writing out a dirty page. Typically the page dirty + * state is cleared before we get here. In this case is it + * conceivable we have no buffer heads. + * + * For delalloc space on the page we need to allocate space and + * flush it. For unmapped buffer heads on the page we should + * allocate space if the page is uptodate. For any other dirty + * buffer heads on the page we should flush them. + * + * If we detect that a transaction would be required to flush + * the page, we have to check the process flags first, if we + * are already in a transaction or disk I/O during allocations + * is off, we need to fail the writepage and redirty the page. + */ + +STATIC int +xfs_vm_writepage( + struct page *page, + struct writeback_control *wbc) +{ + int error; + int need_trans; + int delalloc, unmapped, unwritten; + struct inode *inode = page->mapping->host; + + xfs_page_trace(XFS_WRITEPAGE_ENTER, inode, page, 0); + + /* + * We need a transaction if: + * 1. There are delalloc buffers on the page + * 2. The page is uptodate and we have unmapped buffers + * 3. The page is uptodate and we have no buffers + * 4. There are unwritten buffers on the page + */ + + if (!page_has_buffers(page)) { + unmapped = 1; + need_trans = 1; + } else { + xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); + if (!PageUptodate(page)) + unmapped = 0; + need_trans = delalloc + unmapped + unwritten; + } + + /* + * If we need a transaction and the process flags say + * we are already in a transaction, or no IO is allowed + * then mark the page dirty again and leave the page + * as is. + */ + if (PFLAGS_TEST_FSTRANS() && need_trans) + goto out_fail; + + /* + * Delay hooking up buffer heads until we have + * made our go/no-go decision. + */ + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << inode->i_blkbits, 0); + + /* + * Convert delayed allocate, unwritten or unmapped space + * to real space and flush out to disk. + */ + error = xfs_page_state_convert(inode, page, wbc, 1, unmapped); + if (error == -EAGAIN) + goto out_fail; + if (unlikely(error < 0)) + goto out_unlock; + + return 0; + +out_fail: + redirty_page_for_writepage(wbc, page); + unlock_page(page); + return 0; +out_unlock: + unlock_page(page); + return error; +} + +/* + * Called to move a page into cleanable state - and from there + * to be released. Possibly the page is already clean. We always + * have buffer heads in this call. + * + * Returns 0 if the page is ok to release, 1 otherwise. + * + * Possible scenarios are: + * + * 1. We are being called to release a page which has been written + * to via regular I/O. buffer heads will be dirty and possibly + * delalloc. If no delalloc buffer heads in this case then we + * can just return zero. + * + * 2. We are called to release a page which has been written via + * mmap, all we need to do is ensure there is no delalloc + * state in the buffer heads, if not we can let the caller + * free them and we should come back later via writepage. + */ STATIC int -__linvfs_get_block( +xfs_vm_releasepage( + struct page *page, + gfp_t gfp_mask) +{ + struct inode *inode = page->mapping->host; + int dirty, delalloc, unmapped, unwritten; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 1, + }; + + xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask); + + if (!page_has_buffers(page)) + return 0; + + xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); + if (!delalloc && !unwritten) + goto free_buffers; + + if (!(gfp_mask & __GFP_FS)) + return 0; + + /* If we are already inside a transaction or the thread cannot + * do I/O, we cannot release this page. + */ + if (PFLAGS_TEST_FSTRANS()) + return 0; + + /* + * Convert delalloc space to real space, do not flush the + * data out to disk, that will be done by the caller. + * Never need to allocate space here - we will always + * come back to writepage in that case. + */ + dirty = xfs_page_state_convert(inode, page, &wbc, 0, 0); + if (dirty == 0 && !unwritten) + goto free_buffers; + return 0; + +free_buffers: + return try_to_free_buffers(page); +} + +STATIC int +__xfs_get_block( struct inode *inode, sector_t iblock, unsigned long blocks, @@ -1050,7 +1232,7 @@ __linvfs_get_block( int direct, bmapi_flags_t flags) { - vnode_t *vp = LINVFS_GET_VP(inode); + vnode_t *vp = vn_from_inode(inode); xfs_iomap_t iomap; xfs_off_t offset; ssize_t size; @@ -1073,21 +1255,13 @@ __linvfs_get_block( return 0; if (iomap.iomap_bn != IOMAP_DADDR_NULL) { - xfs_daddr_t bn; - xfs_off_t delta; - - /* For unwritten extents do not report a disk address on + /* + * For unwritten extents do not report a disk address on * the read case (treat as if we're reading into a hole). */ if (create || !(iomap.iomap_flags & IOMAP_UNWRITTEN)) { - delta = offset - iomap.iomap_offset; - delta >>= inode->i_blkbits; - - bn = iomap.iomap_bn >> (inode->i_blkbits - BBSHIFT); - bn += delta; - BUG_ON(!bn && !(iomap.iomap_flags & IOMAP_REALTIME)); - bh_result->b_blocknr = bn; - set_buffer_mapped(bh_result); + xfs_map_buffer(bh_result, &iomap, offset, + inode->i_blkbits); } if (create && (iomap.iomap_flags & IOMAP_UNWRITTEN)) { if (direct) @@ -1130,30 +1304,30 @@ __linvfs_get_block( } int -linvfs_get_block( +xfs_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { - return __linvfs_get_block(inode, iblock, 0, bh_result, + return __xfs_get_block(inode, iblock, 0, bh_result, create, 0, BMAPI_WRITE); } STATIC int -linvfs_get_blocks_direct( +xfs_get_blocks_direct( struct inode *inode, sector_t iblock, unsigned lon |