Messages in this thread Patch in this message | | | Date | Wed, 25 Oct 2000 14:44:58 -0400 (EDT) | From | Alexander Viro <> | Subject | Re: PATCH: killing read_ahead[] |
| |
On Wed, 25 Oct 2000, Alexander Viro wrote:
> I can do the proof-of-concept patch (below 10Kb, ext2 + generic code, with > the need to repeat the fs-specific parts for other filesystems) in an > hour. Clearance?
OK, it didn't take an hour. Warning: completely untested, needs (trivial) changes to other filesystems.
Rules: when you change i_size for inode with non-trivial ->a_ops - either call update_cached_size(inode) or do the equivalent by hands (e.g. generic_commit_write have to mess with i_size value to update the ->size_in_pages and ->last_page_size - we already have them calculated). Ditto for the places where you set ->a_ops.
Invariants: inode->i_mapping->size_in_pages == (inode->i_size + PAGE_CACHE_SIZE - 1)>>PAGE_CACHE_SHIFT; inode->i_size == ((....->size_in_pages-1)<<PAGE_CACHE_SHIFT) + ....->last_page_size;
Linus, what do you think about that? I can do the remaining filesystems and give it initial testing today.
diff -urN rc10-pre5/fs/buffer.c rc10-pre5-size_in_pages/fs/buffer.c --- rc10-pre5/fs/buffer.c Tue Oct 24 01:27:28 2000 +++ rc10-pre5-size_in_pages/fs/buffer.c Wed Oct 25 17:46:25 2000 @@ -1751,6 +1751,9 @@ kunmap(page); if (pos > inode->i_size) { inode->i_size = pos; + /* to is always positive */ + page->mapping->size_in_pages = page->index+1; + page->mapping->last_page_size = to; mark_inode_dirty(inode); } return 0; @@ -1835,19 +1838,22 @@ int block_write_full_page(struct page *page, get_block_t *get_block) { struct inode *inode = (struct inode*)page->mapping->host; - unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + unsigned long end_index = page->mapping->size_in_pages; unsigned offset; int err; /* easy case */ - if (page->index < end_index) - return __block_write_full_page(inode, page, get_block); - - /* things got complicated... */ - offset = inode->i_size & (PAGE_CACHE_SIZE-1); + if (page->index+1 < end_index) + goto easy; /* OK, are we completely out? */ - if (page->index >= end_index+1 || !offset) + if (page->index+1 > end_index) return -EIO; + + offset = inode->i_mapping->last_page_size; + /* Another easy case - 'partial' page is not */ + if (offset == PAGE_CACHE_SIZE) + goto easy; + /* Sigh... will have to work, then... */ err = __block_prepare_write(inode, page, 0, offset, get_block); if (!err) { @@ -1860,6 +1866,8 @@ } ClearPageUptodate(page); goto done; +easy: + return __block_write_full_page(inode, page, get_block); } int generic_block_bmap(struct address_space *mapping, long block, get_block_t *get_block) diff -urN rc10-pre5/fs/ext2/inode.c rc10-pre5-size_in_pages/fs/ext2/inode.c --- rc10-pre5/fs/ext2/inode.c Wed Oct 4 03:44:54 2000 +++ rc10-pre5-size_in_pages/fs/ext2/inode.c Wed Oct 25 17:41:24 2000 @@ -54,6 +54,8 @@ mark_inode_dirty(inode); ext2_update_inode(inode, IS_SYNC(inode)); inode->i_size = 0; + inode.i_data->size_in_pages = 0; + inode.i_data->last_page_size = PAGE_CACHE_SIZE; if (inode->i_blocks) ext2_truncate (inode); ext2_free_inode (inode); @@ -1063,6 +1065,7 @@ inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; inode->i_mapping->a_ops = &ext2_aops; + update_cached_size(inode); } else if (S_ISDIR(inode->i_mode)) { inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; @@ -1072,6 +1075,7 @@ else { inode->i_op = &page_symlink_inode_operations; inode->i_mapping->a_ops = &ext2_aops; + update_cached_size(inode); } } else init_special_inode(inode, inode->i_mode, diff -urN rc10-pre5/fs/inode.c rc10-pre5-size_in_pages/fs/inode.c --- rc10-pre5/fs/inode.c Tue Oct 24 01:27:29 2000 +++ rc10-pre5-size_in_pages/fs/inode.c Wed Oct 25 17:39:28 2000 @@ -529,6 +529,8 @@ inode->i_bdev = NULL; inode->i_data.a_ops = &empty_aops; inode->i_data.host = (void*)inode; + inode->i_data.size_in_pages = 0; + inode->i_data.last_page_size = PAGE_CACHE_SIZE; inode->i_mapping = &inode->i_data; } diff -urN rc10-pre5/include/linux/fs.h rc10-pre5-size_in_pages/include/linux/fs.h --- rc10-pre5/include/linux/fs.h Tue Oct 24 01:27:36 2000 +++ rc10-pre5-size_in_pages/include/linux/fs.h Wed Oct 25 17:31:40 2000 @@ -366,6 +366,8 @@ struct vm_area_struct *i_mmap; /* list of private mappings */ struct vm_area_struct *i_mmap_shared; /* list of shared mappings */ spinlock_t i_shared_lock; /* and spinlock protecting it */ + unsigned long size_in_pages; + unsigned last_page_size; }; struct block_device { @@ -456,6 +458,16 @@ #define I_LOCK 2 #define I_FREEING 4 #define I_CLEAR 8 + +static inline void update_cached_size(struct inode *inode) +{ + loff_t size = inode->i_size; + inode->i_mapping.size_in_pages = + (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + if ((size &= ~PAGE_CACHE_MASK) == 0) + size = PAGE_CACHE_SIZE; + inode->i_mapping.last_page_size = size; +} extern void __mark_inode_dirty(struct inode *); static inline void mark_inode_dirty(struct inode *inode) diff -urN rc10-pre5/mm/filemap.c rc10-pre5-size_in_pages/mm/filemap.c --- rc10-pre5/mm/filemap.c Tue Oct 24 01:27:38 2000 +++ rc10-pre5-size_in_pages/mm/filemap.c Wed Oct 25 17:43:01 2000 @@ -429,8 +429,7 @@ */ static inline int page_cache_read(struct file * file, unsigned long offset) { - struct inode *inode = file->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct page **hash = page_hash(mapping, offset); struct page *page; @@ -633,8 +632,7 @@ */ static void drop_behind(struct file * file, unsigned long index) { - struct inode *inode = file->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct page **hash; struct page *page; unsigned long start; @@ -794,7 +792,7 @@ struct file * filp, struct inode * inode, struct page * page) { - unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; + unsigned long end_index = inode->i_mapping->size_in_pages; unsigned long index = page->index; unsigned long max_ahead, ahead; unsigned long raend; @@ -819,8 +817,8 @@ filp->f_rawin = 0; filp->f_ralen = 1; if (!max_ahead) { - filp->f_raend = index + filp->f_ralen; - filp->f_rawin += filp->f_ralen; + filp->f_raend = index + 1; + filp->f_rawin = 1; } } } @@ -966,14 +964,14 @@ for (;;) { struct page *page, **hash; - unsigned long end_index, nr; + unsigned nr; - end_index = inode->i_size >> PAGE_CACHE_SHIFT; - if (index > end_index) + if (index >= mapping->size_in_pages) break; + nr = PAGE_CACHE_SIZE; - if (index == end_index) { - nr = inode->i_size & ~PAGE_CACHE_MASK; + if (index == mapping->size_in_pages - 1) { + nr = mapping->last_page_size; if (nr <= offset) break; } @@ -1328,10 +1326,9 @@ { int error; struct file *file = area->vm_file; - struct inode *inode = file->f_dentry->d_inode; - struct address_space *mapping = inode->i_mapping; + struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct page *page, **hash, *old_page; - unsigned long size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + unsigned long size = mapping->size_in_pages; unsigned long pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; @@ -1910,8 +1907,7 @@ if (!vma->vm_file) return error; file = vma->vm_file; - size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; + size = file->f_dentry->d_inode->i_mapping->size_in_pages; start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; if (end > vma->vm_end) diff -urN rc10-pre5/mm/memory.c rc10-pre5-size_in_pages/mm/memory.c --- rc10-pre5/mm/memory.c Tue Oct 24 01:27:38 2000 +++ rc10-pre5-size_in_pages/mm/memory.c Wed Oct 25 17:44:14 2000 @@ -979,6 +979,7 @@ if (inode->i_size < offset) goto do_expand; inode->i_size = offset; + update_cached_size(inode); truncate_inode_pages(mapping, offset); spin_lock(&mapping->i_shared_lock); if (!mapping->i_mmap && !mapping->i_mmap_shared) @@ -1013,6 +1014,7 @@ } } inode->i_size = offset; + update_cached_size(inode); if (inode->i_op && inode->i_op->truncate) inode->i_op->truncate(inode); out: - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
| |