From: Oliver Xymoron This patch just saves a few bytes in the inode by turning mapping->gfp_mask into an unsigned long mapping->flags. The mapping's gfp mask is placed in the 16 high bits of mapping->flags and two of the remaining 16 bits are used for tracking EIO and ENOSPC errors. This leaves 14 bits in the mapping for future use. They should be accessed with the atomic bitops. drivers/block/loop.c | 7 ++++--- fs/block_dev.c | 2 +- fs/buffer.c | 4 ++-- fs/inode.c | 5 +++-- fs/jfs/inode.c | 3 ++- fs/jfs/jfs_imap.c | 3 ++- fs/jfs/namei.c | 2 +- fs/mpage.c | 18 ++++++++++++++---- fs/open.c | 9 +++++---- include/linux/fs.h | 3 +-- include/linux/gfp.h | 3 +++ include/linux/pagemap.h | 29 ++++++++++++++++++++++++++--- mm/filemap.c | 11 +++++------ mm/shmem.c | 2 +- mm/vmscan.c | 8 ++++++-- 15 files changed, 76 insertions(+), 33 deletions(-) diff -puN drivers/block/loop.c~awe-use-gfp_flags drivers/block/loop.c --- 25/drivers/block/loop.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/drivers/block/loop.c 2003-08-18 22:38:38.000000000 -0700 @@ -728,8 +728,9 @@ static int loop_set_fd(struct loop_devic fput(file); goto out_putf; } - lo->old_gfp_mask = inode->i_mapping->gfp_mask; - inode->i_mapping->gfp_mask &= ~(__GFP_IO|__GFP_FS); + lo->old_gfp_mask = mapping_gfp_mask(inode->i_mapping); + mapping_set_gfp_mask(inode->i_mapping, + lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); set_blocksize(bdev, lo_blocksize); @@ -845,7 +846,7 @@ static int loop_clr_fd(struct loop_devic memset(lo->lo_file_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); /* This is safe: open() is still holding a reference. */ diff -puN fs/block_dev.c~awe-use-gfp_flags fs/block_dev.c --- 25/fs/block_dev.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/block_dev.c 2003-08-18 22:38:38.000000000 -0700 @@ -320,7 +320,7 @@ struct block_device *bdget(dev_t dev) 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 -puN fs/buffer.c~awe-use-gfp_flags fs/buffer.c --- 25/fs/buffer.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/buffer.c 2003-08-18 22:38:38.000000000 -0700 @@ -579,7 +579,7 @@ void end_buffer_async_write(struct buffe buffer_io_error(bh); printk(KERN_WARNING "lost page write due to I/O error on %s\n", bdevname(bh->b_bdev, b)); - page->mapping->error = -EIO; + set_bit(AS_EIO, &page->mapping->flags); clear_buffer_uptodate(bh); SetPageError(page); } @@ -2815,7 +2815,7 @@ drop_buffers(struct page *page, struct b 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 -puN fs/inode.c~awe-use-gfp_flags fs/inode.c --- 25/fs/inode.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/inode.c 2003-08-18 22:38:38.000000000 -0700 @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -141,11 +142,11 @@ static struct inode *alloc_inode(struct 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) mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; memset(&inode->u, 0, sizeof(inode->u)); diff -puN fs/jfs/inode.c~awe-use-gfp_flags fs/jfs/inode.c --- 25/fs/jfs/inode.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/jfs/inode.c 2003-08-18 22:38:38.000000000 -0700 @@ -20,6 +20,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" #include "jfs_imap.h" @@ -51,7 +52,7 @@ void jfs_read_inode(struct inode *inode) 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 -puN fs/jfs/jfs_imap.c~awe-use-gfp_flags fs/jfs/jfs_imap.c --- 25/fs/jfs/jfs_imap.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/jfs/jfs_imap.c 2003-08-18 22:38:38.000000000 -0700 @@ -43,6 +43,7 @@ #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" @@ -504,7 +505,7 @@ struct inode *diReadSpecial(struct super } ip->i_mapping->a_ops = &jfs_aops; - ip->i_mapping->gfp_mask = GFP_NOFS; + mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS); if ((inum == FILESYSTEM_I) && (JFS_IP(ip)->ipimap == sbi->ipaimap)) { sbi->gengen = le32_to_cpu(dp->di_gengen); diff -puN fs/jfs/namei.c~awe-use-gfp_flags fs/jfs/namei.c --- 25/fs/jfs/namei.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/jfs/namei.c 2003-08-18 22:38:38.000000000 -0700 @@ -258,7 +258,7 @@ int jfs_mkdir(struct inode *dip, struct 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 -puN fs/mpage.c~awe-use-gfp_flags fs/mpage.c --- 25/fs/mpage.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/mpage.c 2003-08-18 22:41:59.000000000 -0700 @@ -566,8 +566,12 @@ confused: /* * The caller has a ref on the inode, so *mapping is stable */ - if (*ret < 0) - mapping->error = *ret; + if (*ret) { + if (*ret == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else + set_bit(AS_EIO, &mapping->flags); + } out: return bio; } @@ -669,8 +673,14 @@ mpage_writepages(struct address_space *m test_clear_page_dirty(page)) { if (writepage) { ret = (*writepage)(page, wbc); - if (ret < 0) - mapping->error = ret; + if (ret) { + if (ret == -ENOSPC) + set_bit(AS_ENOSPC, + &mapping->flags); + else + set_bit(AS_EIO, + &mapping->flags); + } } else { bio = mpage_writepage(bio, page, get_block, &last_block_in_bio, &ret, wbc); diff -puN fs/open.c~awe-use-gfp_flags fs/open.c --- 25/fs/open.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/fs/open.c 2003-08-18 22:38:39.000000000 -0700 @@ -21,6 +21,7 @@ #include #include #include +#include int vfs_statfs(struct super_block *sb, struct kstatfs *buf) { @@ -954,10 +955,10 @@ int filp_close(struct file *filp, fl_own retval = err; } - err = mapping->error; - if (!retval) - retval = err; - mapping->error = 0; + 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 -puN include/linux/fs.h~awe-use-gfp_flags include/linux/fs.h --- 25/include/linux/fs.h~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/include/linux/fs.h 2003-08-18 22:38:39.000000000 -0700 @@ -327,12 +327,11 @@ struct address_space { struct semaphore i_shared_sem; /* protect both above lists */ atomic_t truncate_count; /* Cover race condition with truncate */ 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 block_device { diff -puN include/linux/gfp.h~awe-use-gfp_flags include/linux/gfp.h --- 25/include/linux/gfp.h~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/include/linux/gfp.h 2003-08-18 22:38:39.000000000 -0700 @@ -33,6 +33,9 @@ #define __GFP_NORETRY 0x1000 /* Do not retry. Might fail */ #define __GFP_NO_GROW 0x2000 /* Slab internal usage */ +#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 -puN include/linux/pagemap.h~awe-use-gfp_flags include/linux/pagemap.h --- 25/include/linux/pagemap.h~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/include/linux/pagemap.h 2003-08-18 22:38:39.000000000 -0700 @@ -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 @@ void release_pages(struct page **pages, 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 @@ extern unsigned int find_get_pages(struc */ 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 -puN mm/filemap.c~awe-use-gfp_flags mm/filemap.c --- 25/mm/filemap.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/mm/filemap.c 2003-08-18 22:38:39.000000000 -0700 @@ -205,11 +205,10 @@ restart: spin_unlock(&mapping->page_lock); /* Check for outstanding write errors */ - if (mapping->error) { - if (!ret) - 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; } @@ -532,7 +531,7 @@ grab_cache_page_nowait(struct address_sp 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 -puN mm/shmem.c~awe-use-gfp_flags mm/shmem.c --- 25/mm/shmem.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/mm/shmem.c 2003-08-18 22:38:39.000000000 -0700 @@ -320,7 +320,7 @@ static swp_entry_t *shmem_swp_alloc(stru 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 -puN mm/vmscan.c~awe-use-gfp_flags mm/vmscan.c --- 25/mm/vmscan.c~awe-use-gfp_flags 2003-08-18 22:38:38.000000000 -0700 +++ 25-akpm/mm/vmscan.c 2003-08-18 22:38:39.000000000 -0700 @@ -251,8 +251,12 @@ static void handle_write_error(struct ad struct page *page, int error) { lock_page(page); - if (page->mapping == mapping) - mapping->error = error; + if (page->mapping == mapping) { + if (error == -ENOSPC) + set_bit(AS_ENOSPC, &mapping->flags); + else + set_bit(AS_EIO, &mapping->flags); + } unlock_page(page); } _