diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/drivers/block/loop.c work/drivers/block/loop.c --- orig/drivers/block/loop.c 2003-02-17 09:59:25.000000000 -0600 +++ work/drivers/block/loop.c 2003-02-19 17:44:13.000000000 -0600 @@ -693,8 +693,8 @@ fput(file); goto out_putf; } - lo->old_gfp_mask = inode->i_mapping->gfp_mask; - inode->i_mapping->gfp_mask = GFP_NOIO; + lo->old_gfp_mask = mapping_gfp_mask(inode->i_mapping); + mapping_set_gfp_mask(inode->i_mapping, GFP_NOIO); set_blocksize(bdev, lo_blocksize); @@ -800,7 +800,7 @@ memset(lo->lo_name, 0, LO_NAME_SIZE); invalidate_bdev(bdev, 0); set_capacity(disks[lo->lo_number], 0); - filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp; + mapping_set_gfp_mask(filp->f_dentry->d_inode->i_mapping, gfp); lo->lo_state = Lo_unbound; fput(filp); MOD_DEC_USE_COUNT; diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/block_dev.c work/fs/block_dev.c --- orig/fs/block_dev.c 2003-01-16 20:23:01.000000000 -0600 +++ work/fs/block_dev.c 2003-02-19 17:44:13.000000000 -0600 @@ -318,7 +318,7 @@ inode->i_rdev = kdev; inode->i_bdev = new_bdev; inode->i_data.a_ops = &def_blk_aops; - inode->i_data.gfp_mask = GFP_USER; + mapping_set_gfp_mask(&inode->i_data, GFP_USER); inode->i_data.backing_dev_info = &default_backing_dev_info; spin_lock(&bdev_lock); bdev = bdfind(dev, head); diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/buffer.c work/fs/buffer.c --- orig/fs/buffer.c 2003-02-19 17:44:13.000000000 -0600 +++ work/fs/buffer.c 2003-02-19 17:44:13.000000000 -0600 @@ -563,7 +563,7 @@ buffer_io_error(bh); printk(KERN_WARNING "lost page write due to I/O error on %s\n", bdevname(bh->b_bdev)); - page->mapping->error = -EIO; + set_bit(AS_EIO, &page->mapping->flags); clear_buffer_uptodate(bh); SetPageError(page); } @@ -2714,7 +2714,7 @@ do { check_ttfb_buffer(page, bh); if (buffer_write_io_error(bh)) - page->mapping->error = -EIO; + set_bit(AS_EIO, &page->mapping->flags); if (buffer_busy(bh)) goto failed; if (!buffer_uptodate(bh) && !buffer_req(bh)) diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/inode.c work/fs/inode.c --- orig/fs/inode.c 2003-02-19 17:44:13.000000000 -0600 +++ work/fs/inode.c 2003-02-19 17:44:13.000000000 -0600 @@ -18,6 +18,7 @@ #include #include #include +#include /* * This is needed for the following functions: @@ -130,11 +131,11 @@ mapping->a_ops = &empty_aops; mapping->host = inode; - mapping->gfp_mask = GFP_HIGHUSER; + mapping->flags = 0; + mapping_set_gfp_mask(mapping, GFP_HIGHUSER); mapping->dirtied_when = 0; mapping->assoc_mapping = NULL; mapping->backing_dev_info = &default_backing_dev_info; - mapping->error = 0; if (sb->s_bdev) inode->i_data.backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; memset(&inode->u, 0, sizeof(inode->u)); diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/jfs/inode.c work/fs/jfs/inode.c --- orig/fs/jfs/inode.c 2003-02-11 11:12:26.000000000 -0600 +++ work/fs/jfs/inode.c 2003-02-19 17:44:13.000000000 -0600 @@ -57,7 +57,7 @@ inode->i_op = &jfs_dir_inode_operations; inode->i_fop = &jfs_dir_operations; inode->i_mapping->a_ops = &jfs_aops; - inode->i_mapping->gfp_mask = GFP_NOFS; + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); } else if (S_ISLNK(inode->i_mode)) { if (inode->i_size >= IDATASIZE) { inode->i_op = &page_symlink_inode_operations; diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/jfs/namei.c work/fs/jfs/namei.c --- orig/fs/jfs/namei.c 2003-02-17 09:59:31.000000000 -0600 +++ work/fs/jfs/namei.c 2003-02-19 17:44:13.000000000 -0600 @@ -257,7 +257,7 @@ ip->i_op = &jfs_dir_inode_operations; ip->i_fop = &jfs_dir_operations; ip->i_mapping->a_ops = &jfs_aops; - ip->i_mapping->gfp_mask = GFP_NOFS; + mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS); insert_inode_hash(ip); mark_inode_dirty(ip); diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/mpage.c work/fs/mpage.c --- orig/fs/mpage.c 2003-02-19 17:44:13.000000000 -0600 +++ work/fs/mpage.c 2003-02-19 17:44:13.000000000 -0600 @@ -570,8 +570,12 @@ * mapping. */ lock_page(page); - if (page->mapping == mapping) - mapping->error = *ret; + if (page->mapping == mapping) { + if (*ret == -EIO) + set_bit(AS_EIO, &mapping->flags); + else if (*ret == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + } unlock_page(page); } out: @@ -684,8 +688,12 @@ * mapping. */ lock_page(page); - if (page->mapping == mapping) - mapping->error = ret; + if (page->mapping == mapping) { + if (ret == -EIO) + set_bit(AS_EIO, &mapping->flags); + else if (ret == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + } unlock_page(page); } } else { diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/fs/open.c work/fs/open.c --- orig/fs/open.c 2003-02-19 17:44:13.000000000 -0600 +++ work/fs/open.c 2003-02-19 17:44:13.000000000 -0600 @@ -20,6 +20,7 @@ #include #include #include +#include #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) @@ -853,11 +854,10 @@ retval = err; } - err = mapping->error; - if (err && !retval) { - mapping->error = 0; - retval = err; - } + if (test_and_clear_bit(AS_ENOSPC, &mapping->flags)) + retval = -ENOSPC; + if (test_and_clear_bit(AS_EIO, &mapping->flags)) + retval = -EIO; if (!file_count(filp)) { printk(KERN_ERR "VFS: Close: file count is 0\n"); diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/include/linux/fs.h work/include/linux/fs.h --- orig/include/linux/fs.h 2003-02-19 17:44:13.000000000 -0600 +++ work/include/linux/fs.h 2003-02-19 17:44:13.000000000 -0600 @@ -321,12 +321,11 @@ struct list_head i_mmap_shared; /* list of private mappings */ struct semaphore i_shared_sem; /* and sem protecting it */ unsigned long dirtied_when; /* jiffies of first page dirtying */ - int gfp_mask; /* how to allocate the pages */ + unsigned long flags; /* error bits/gfp mask */ struct backing_dev_info *backing_dev_info; /* device readahead, etc */ spinlock_t private_lock; /* for use by the address_space */ struct list_head private_list; /* ditto */ struct address_space *assoc_mapping; /* ditto */ - int error; /* write error for fsync */ }; struct char_device { diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/include/linux/gfp.h work/include/linux/gfp.h --- orig/include/linux/gfp.h 2003-02-11 11:12:30.000000000 -0600 +++ work/include/linux/gfp.h 2003-02-19 17:44:13.000000000 -0600 @@ -11,7 +11,10 @@ #define __GFP_DMA 0x01 #define __GFP_HIGHMEM 0x02 -/* Action modifiers - doesn't change the zoning */ +/* + * Action modifiers - doesn't change the zoning. + * Note that you must update __GFP_BITS_SHIFT if you add lots more of these.. + */ #define __GFP_WAIT 0x10 /* Can wait and reschedule? */ #define __GFP_HIGH 0x20 /* Should access emergency pools? */ #define __GFP_IO 0x40 /* Can start physical IO? */ @@ -19,6 +22,9 @@ #define __GFP_COLD 0x100 /* Cache-cold page required */ #define __GFP_NOWARN 0x200 /* Suppress page allocation failure warning */ +#define __GFP_BITS_SHIFT 16 /* Room for 16 __GFP_FOO bits */ +#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1) + #define GFP_ATOMIC (__GFP_HIGH) #define GFP_NOIO (__GFP_WAIT) #define GFP_NOFS (__GFP_WAIT | __GFP_IO) diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/include/linux/pagemap.h work/include/linux/pagemap.h --- orig/include/linux/pagemap.h 2003-02-19 17:38:05.000000000 -0600 +++ work/include/linux/pagemap.h 2003-02-19 17:44:13.000000000 -0600 @@ -8,7 +8,30 @@ #include #include #include +#include #include +#include + +/* + * Bits in mapping->flags. The lower __GFP_BITS_SHIFT bits are the page + * allocation mode flags. + */ +#define AS_EIO (__GFP_BITS_SHIFT + 0) /* IO error on async write */ +#define AS_ENOSPC (__GFP_BITS_SHIFT + 1) /* ENOSPC on async write */ + +static inline int mapping_gfp_mask(struct address_space * mapping) +{ + return mapping->flags & __GFP_BITS_MASK; +} + +/* + * This is non-atomic. Only to be used before the mapping is activated. + * Probably needs a barrier... + */ +static inline void mapping_set_gfp_mask(struct address_space *m, int mask) +{ + m->flags = (m->flags & ~__GFP_BITS_MASK) | mask; +} /* * The page cache can done in larger chunks than @@ -29,12 +52,12 @@ static inline struct page *page_cache_alloc(struct address_space *x) { - return alloc_pages(x->gfp_mask, 0); + return alloc_pages(mapping_gfp_mask(x), 0); } static inline struct page *page_cache_alloc_cold(struct address_space *x) { - return alloc_pages(x->gfp_mask|__GFP_COLD, 0); + return alloc_pages(mapping_gfp_mask(x)|__GFP_COLD, 0); } typedef int filler_t(void *, struct page *); @@ -56,7 +79,7 @@ */ static inline struct page *grab_cache_page(struct address_space *mapping, unsigned long index) { - return find_or_create_page(mapping, index, mapping->gfp_mask); + return find_or_create_page(mapping, index, mapping_gfp_mask(mapping)); } extern struct page * grab_cache_page_nowait(struct address_space *mapping, diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/mm/filemap.c work/mm/filemap.c --- orig/mm/filemap.c 2003-02-19 17:44:13.000000000 -0600 +++ work/mm/filemap.c 2003-02-19 17:44:13.000000000 -0600 @@ -187,11 +187,10 @@ write_unlock(&mapping->page_lock); /* Check for outstanding write errors */ - if (mapping->error) - { - ret = mapping->error; - mapping->error = 0; - } + if (test_and_clear_bit(AS_ENOSPC, &mapping->flags)) + ret = -ENOSPC; + if (test_and_clear_bit(AS_EIO, &mapping->flags)) + ret = -EIO; return ret; } @@ -514,7 +513,7 @@ page_cache_release(page); return NULL; } - gfp_mask = mapping->gfp_mask & ~__GFP_FS; + gfp_mask = mapping_gfp_mask(mapping) & ~__GFP_FS; page = alloc_pages(gfp_mask, 0); if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) { page_cache_release(page); diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/mm/shmem.c work/mm/shmem.c --- orig/mm/shmem.c 2003-01-16 20:22:04.000000000 -0600 +++ work/mm/shmem.c 2003-02-19 17:44:13.000000000 -0600 @@ -316,7 +316,7 @@ spin_unlock(&sbinfo->stat_lock); spin_unlock(&info->lock); - page = shmem_dir_alloc(inode->i_mapping->gfp_mask); + page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping)); if (page) { clear_highpage(page); page->nr_swapped = 0; diff -urN -x '*.ver' -x '.patch*' -x '*.orig' orig/mm/vmscan.c work/mm/vmscan.c --- orig/mm/vmscan.c 2003-02-19 17:44:13.000000000 -0600 +++ work/mm/vmscan.c 2003-02-19 17:44:13.000000000 -0600 @@ -349,13 +349,14 @@ * mapping. */ lock_page(page); - if (page->mapping == mapping) - mapping->error = res; + if (page->mapping == mapping) { + if (res == -EIO) + set_bit(AS_EIO, &mapping->flags); + else if (res == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + } unlock_page(page); } - if (res < 0) { - mapping->error = res; - } if (res == WRITEPAGE_ACTIVATE) { ClearPageReclaim(page); goto activate_locked;