=========================================================================== Index: linux/drivers/block/ll_rw_blk.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/drivers/block/ll_rw_blk.c_1.80 Mon Mar 18 16:12:36 2002 +++ linux/drivers/block/ll_rw_blk.c Fri Mar 15 18:34:55 2002 @@ -898,6 +898,9 @@ if (!test_bit(BH_Lock, &bh->b_state)) BUG(); + if (buffer_delay(bh) || !buffer_mapped(bh)) + BUG(); + set_bit(BH_Req, &bh->b_state); /* @@ -974,8 +977,6 @@ correct_size, bh->b_size); goto sorry; } - if (buffer_delay(bh) || !buffer_mapped(bh)) - BUG(); } if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) { =========================================================================== Index: linux/fs/buffer.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/fs/buffer.c_1.102 Mon Mar 18 16:12:36 2002 +++ linux/fs/buffer.c Fri Mar 15 21:00:34 2002 @@ -84,6 +84,8 @@ static int grow_buffers(kdev_t dev, unsigned long block, int size); static void __refile_buffer(struct buffer_head *); +static void __insert_into_lru_list(struct buffer_head *, int); +static void __remove_from_lru_list(struct buffer_head *); /* This is used by some architectures to estimate available memory. */ atomic_t buffermem_pages = ATOMIC_INIT(0); @@ -120,66 +122,45 @@ int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,10000*HZ, 6000*HZ, 100, 0, 0}; -int -_write_buffer(struct buffer_head *bh, int wait) +static void +write_buffer_delay(struct buffer_head *bh) { struct page *page = bh->b_page; - if (!page) - BUG(); - if (wait) { - lock_page(page); - } else if (TryLockPage(page)) { - if (current->need_resched) + if (TryLockPage(page)) { + __remove_from_lru_list(bh); + __insert_into_lru_list(bh, BUF_DIRTY); + spin_unlock(&lru_list_lock); + unlock_buffer(bh); + if (current->need_resched) { schedule(); - return 0; - } - - if (buffer_delay(bh)) { + } + } else { + spin_unlock(&lru_list_lock); + unlock_buffer(bh); page->mapping->a_ops->writepage(page); - return 1; } - UnlockPage(page); - return 0; } -static inline void +static void write_buffer(struct buffer_head *bh) { - if (!buffer_delay(bh)) { + if (!buffer_delay(bh)) ll_rw_block(WRITE, 1, &bh); - } else - _write_buffer(bh, 1); -} - -static inline int -write_buffer_locked(struct buffer_head *bh) -{ - int ret; + else { + struct page *page = bh->b_page; - if (!buffer_delay(bh)) { - bh->b_end_io = end_buffer_io_sync; - submit_bh(WRITE, bh); - return 1; - } else { - clear_bit(BH_Lock, &bh->b_state); - smp_mb__after_clear_bit(); - ret = _write_buffer(bh, 0); - brelse(bh); - if (ret == 0) { - clear_bit(BH_Wait_IO, &bh->b_state); - clear_bit(BH_launder, &bh->b_state); - smp_mb__after_clear_bit(); - if (waitqueue_active(&bh->b_wait)) { - wake_up(&bh->b_wait); - } + lock_page(page); + if (buffer_delay(bh)) { + page->mapping->a_ops->writepage(page); + } else { + UnlockPage(page); + ll_rw_block(WRITE, 1, &bh); } - return ret; } } - void unlock_buffer(struct buffer_head *bh) { clear_bit(BH_Wait_IO, &bh->b_state); @@ -266,16 +247,15 @@ if (dev && bh->b_dev != dev) continue; + + if (test_and_set_bit(BH_Lock, &bh->b_state)) + continue; if (buffer_delay(bh)) { - spin_unlock(&lru_list_lock); + write_buffer_delay(bh); if (count) write_locked_buffers(array, count); - _write_buffer(bh, 0); return -EAGAIN; } - - if (test_and_set_bit(BH_Lock, &bh->b_state)) - continue; if (atomic_set_buffer_clean(bh)) { __refile_buffer(bh); get_bh(bh); @@ -2694,7 +2674,9 @@ __mark_buffer_clean(bh); get_bh(bh); set_bit(BH_launder, &bh->b_state); - tryagain = write_buffer_locked(bh) == 0; + bh->b_end_io = end_buffer_io_sync; + submit_bh(WRITE, bh); + tryagain = 0; } while ((bh = bh->b_this_page) != head); return tryagain; @@ -2703,7 +2685,7 @@ /* * Can the buffer be thrown out? */ -#define BUFFER_BUSY_BITS ((1<b_count) | ((bh)->b_state & BUFFER_BUSY_BITS)) /* =========================================================================== Index: linux/fs/xfs/linux/xfs_iops.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/fs/xfs/linux/xfs_iops.c_1.127 Mon Mar 18 16:12:36 2002 +++ linux/fs/xfs/linux/xfs_iops.c Mon Mar 18 14:47:36 2002 @@ -637,11 +637,24 @@ STATIC int linvfs_write_full_page(struct page *page) { - if ((current->flags & PF_FSTRANS) && DelallocPage(page)) + int ret; + int flagset = 0; + + if ((current->flags & (PF_FSTRANS|PF_NOIO)) && + (!page->buffers || buffer_delay(page->buffers))) goto out_fail; - return pagebuf_write_full_page(page, linvfs_pb_bmap); + if (!page->buffers || buffer_delay(page->buffers)) { + current->flags |= PF_NOIO; + flagset = 1; + } + + ret = pagebuf_write_full_page(page, linvfs_pb_bmap); + if (flagset) + current->flags &= ~PF_NOIO; + + return ret; out_fail: SetPageDirty(page); UnlockPage(page); @@ -657,11 +670,30 @@ return pagebuf_prepare_write(file, page, from, to, linvfs_pb_bmap); } +/* This gets a page into cleanable state - page locked on entry + * kept locked on exit. + */ +STATIC int linvfs_release_page( + struct page *page, + int gfp_mask) +{ + if (page->buffers && !buffer_delay(page->buffers)) { + return 1; + } + + if (!(gfp_mask & __GFP_FS)) { + return 0; + } + pagebuf_release_page(page, linvfs_pb_bmap); + return 1; +} + struct address_space_operations linvfs_aops = { readpage: linvfs_read_full_page, writepage: linvfs_write_full_page, sync_page: block_sync_page, + releasepage: linvfs_release_page, bmap: linvfs_bmap, prepare_write: linvfs_prepare_write, commit_write: pagebuf_commit_write, =========================================================================== Index: linux/fs/xfs/pagebuf/page_buf.h =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/fs/xfs/pagebuf/page_buf.h_1.7 Mon Mar 18 16:12:36 2002 +++ linux/fs/xfs/pagebuf/page_buf.h Mon Mar 18 14:23:11 2002 @@ -599,6 +599,10 @@ struct page *, /* page to write */ pagebuf_bmap_fn_t); /* bmap function */ +extern void pagebuf_release_page( /* Attempt to convert a delalloc page */ + struct page *, /* page to write */ + pagebuf_bmap_fn_t); /* bmap function */ + extern int pagebuf_commit_write( struct file *, /* file to write */ struct page *, /* page to write */ =========================================================================== Index: linux/fs/xfs/pagebuf/page_buf_io.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/fs/xfs/pagebuf/page_buf_io.c_1.16 Mon Mar 18 16:12:36 2002 +++ linux/fs/xfs/pagebuf/page_buf_io.c Mon Mar 18 14:33:01 2002 @@ -71,7 +71,7 @@ unsigned, unsigned, int, pagebuf_bmap_fn_t, page_buf_bmap_t *, int); STATIC int pagebuf_delalloc_convert(struct inode *, struct page *, - unsigned long, pagebuf_bmap_fn_t); + unsigned long, pagebuf_bmap_fn_t, int); STATIC void hook_buffers_to_page(struct inode *, struct page *, page_buf_bmap_t *); @@ -690,6 +690,17 @@ return 0; } +void pagebuf_release_page(struct page *page, pagebuf_bmap_fn_t bmap) +{ + struct inode *inode = (struct inode*)page->mapping->host; + unsigned long pb_flags; + + if (DelallocPage(page)) + pb_flags = PBF_WRITE|PBF_FILE_ALLOCATE; + else + pb_flags = PBF_WRITE|PBF_DIRECT; + pagebuf_delalloc_convert(inode, page, pb_flags, bmap, 0); +} /* * pagebuf_write_full_page @@ -699,60 +710,24 @@ { struct inode *inode = (struct inode*)page->mapping->host; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT, pb_flags; - loff_t offset; int ret; if (DelallocPage(page)) pb_flags = PBF_WRITE|PBF_FILE_ALLOCATE; else pb_flags = PBF_WRITE|PBF_DIRECT; - /* easy case */ - if (page->index < end_index) { - ret = pagebuf_delalloc_convert(inode, page, pb_flags, bmap); - goto out; - } - - /* things got complicated... */ - offset = inode->i_size & (PAGE_CACHE_SIZE-1); - /* OK, are we completely out? */ - if ((page->index >= end_index+1) || !offset) { - ret = -EIO; - goto out; - } - ret = __pb_block_prepare_write_async(inode, page, - 0, PAGE_CACHE_SIZE, 1, bmap, NULL, pb_flags); - if (!ret) { - struct buffer_head *bh, *head, *next; - __pb_block_commit_write_async(inode, page, 0); - - /* - * Pages over holes may have just been allocated - * buffers, so bh needs to be looked up now. - */ - bh = page->buffers; - /* - * Kick-start that last write... - */ - head = bh; - - do { - lock_buffer(bh); - set_buffer_async_io(bh); - set_bit(BH_Uptodate, &bh->b_state); - clear_bit(BH_Dirty, &bh->b_state); - bh = bh->b_this_page; - } while (bh != head); - - do { - next = bh->b_this_page; - submit_bh(WRITE, bh); - bh = next; - } while (bh != head); + /* Are we off teh end of the file ? */ + if (page->index > end_index) { + loff_t offset = inode->i_size & (PAGE_CACHE_SIZE-1); + if ((page->index >= end_index+1) || !offset) { + ret = -EIO; + goto out; + } } - kunmap(page); + ret = pagebuf_delalloc_convert(inode, page, pb_flags, bmap, 1); out: if (ret < 0) { /* @@ -807,11 +782,12 @@ bn = mp->pbm_bn >> (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); bn += (delta >> PAGE_CACHE_SHIFT); + lock_buffer(bh); bh->b_blocknr = bn; bh->b_dev = mp->pbm_dev; - if (buffer_locked(bh)) - BUG(); set_bit(BH_Mapped, &bh->b_state); + clear_bit(BH_Delay, &bh->b_state); + unlock_buffer(bh); } STATIC void @@ -880,11 +856,6 @@ if (mp->pbm_bn >= 0) { hook_buffers_to_page(inode, page, mp); bh = page->buffers; - if (dp) { - lock_buffer(bh); - clear_bit(BH_Delay, &bh->b_state); - unlock_buffer(bh); - } } } @@ -1329,45 +1300,57 @@ return page; } +/* Actually push the data out to disk */ +static void +submit_page_io(struct page *page) +{ + struct buffer_head *head, *bh; + + head = bh = page->buffers; + do { + lock_buffer(bh); + set_buffer_async_io(bh); + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + bh = bh->b_this_page; + } while (bh != head); + + do { + struct buffer_head *next = bh->b_this_page; + submit_bh(WRITE, bh); + bh = next; + } while (bh != head); + + SetPageUptodate(page); +} /* * Allocate & map buffers for page given the extent map. Write it out. + * except for the original page of a writepage, this is called on + * delalloc pages only, for the original page it is possible that + * the page has no mapping at all. */ STATIC void -convert_page(struct inode *inode, struct page *page, page_buf_bmap_t *mp) +convert_page( + struct inode *inode, + struct page *page, + page_buf_bmap_t *mp, + int do_write) { - struct buffer_head *head, *bh = page->buffers; - struct buffer_head *array[PAGE_CACHE_SIZE >> 9]; - int i, count = 0; + struct buffer_head *bh = page->buffers; + /* Three possible conditions - page with delayed buffers, + * page with real buffers, or page with no buffers (mmap) + */ if (!bh || DelallocPage(page)) { hook_buffers_to_page(inode, page, mp); - bh = page->buffers; } - head = bh; - do { - lock_buffer(bh); - if (!test_and_clear_bit(BH_Delay, &bh->b_state) || - atomic_set_buffer_clean(bh)) { - get_bh(bh); - bh->b_end_io = end_buffer_io_sync; - refile_buffer(bh); - array[count++] = bh; - } else { - unlock_buffer(bh); - refile_buffer(bh); - } - bh = bh->b_this_page; - } while (bh != head); - - for (i = 0; i < count; i++) { - submit_bh(WRITE, array[i]); + if (do_write) { + submit_page_io(page); } - SetPageUptodate(page); - UnlockPage(page); page_cache_release(page); } @@ -1379,7 +1362,8 @@ STATIC int cluster_write(struct inode *inode, struct page *startpage, - page_buf_bmap_t *mp) + page_buf_bmap_t *mp, + int do_write) { unsigned long tindex, tlast; struct page *page; @@ -1389,16 +1373,16 @@ for (tindex = startpage->index-1; tindex >= tlast; tindex--) { if (!(page = probe_page(inode, tindex))) break; - convert_page(inode, page, mp); + convert_page(inode, page, mp, 1); } } - convert_page(inode, startpage, mp); + convert_page(inode, startpage, mp, do_write); tlast = PAGE_CACHE_ALIGN_LL(mp->pbm_offset + mp->pbm_bsize) >> PAGE_CACHE_SHIFT; for (tindex = startpage->index + 1; tindex < tlast; tindex++) { if (!(page = probe_page(inode, tindex))) break; - convert_page(inode, page, mp); + convert_page(inode, page, mp, 1); } return 0; } @@ -1408,12 +1392,19 @@ struct inode *inode, struct page *page, /* delalloc page to convert - locked */ unsigned long flags, /* allocation mode to use */ - pagebuf_bmap_fn_t bmap) /* bmap function */ + pagebuf_bmap_fn_t bmap,/* bmap function */ + int do_write) { page_buf_bmap_t maps[PBF_MAX_MAPS]; int maps_returned, error; loff_t rounded_offset; + /* Fast path for mapped page */ + if (do_write && page->buffers && !buffer_delay(page->buffers)) { + submit_page_io(page); + return 0; + } + rounded_offset = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; error = bmap(inode, rounded_offset, PAGE_CACHE_SIZE, &maps[0], PBF_MAX_MAPS, &maps_returned, flags); @@ -1436,6 +1427,6 @@ * which is a locked page with an extra reference. */ page_cache_get(page); - return cluster_write(inode, page, &maps[0]); + return cluster_write(inode, page, &maps[0], do_write); } =========================================================================== Index: linux/fs/xfs_support/kmem.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/fs/xfs_support/kmem.c_1.21 Mon Mar 18 16:12:36 2002 +++ linux/fs/xfs_support/kmem.c Mon Mar 18 14:09:58 2002 @@ -51,7 +51,7 @@ { if (flags & KM_NOSLEEP) return GFP_ATOMIC; /* If we're in a transaction, FS activity is not ok */ - if (current->flags & PF_FSTRANS) return GFP_NOFS; + if (current->flags & (PF_FSTRANS|PF_NOIO)) return GFP_NOFS; return GFP_KERNEL; } =========================================================================== Index: linux/mm/vmscan.c =========================================================================== --- /usr/tmp/TmpDir.26429-0/linux/mm/vmscan.c_1.93 Mon Mar 18 16:12:36 2002 +++ linux/mm/vmscan.c Mon Mar 18 09:03:01 2002 @@ -391,7 +391,7 @@ continue; } - if ((PageDirty(page) || DelallocPage(page)) && is_page_cache_freeable(page) && page->mapping) { + if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) { /* * It is not critical here to write it only if * the page is unmapped beause any direct writer