From: Eric Sandeen <sandeen@redhat.com> Date: Thu, 21 Aug 2008 15:44:23 -0500 Subject: [fs] ext4: backport to rhel5.3 interfaces Message-id: 48ADD3A7.5000403@redhat.com O-Subject: [RHEL5.3 Patch 4/6] ext4: backport to rhel5.3 interfaces Bugzilla: 458718 [Bug 458718] FEAT: RHEL 5.3 ext4 tech preview Many backporting patches rolled up, to accomodate the RHEL5 interfaces. missing_headers generic_file_aio_write_fixup no_READ_META no_PageChecked fix_f_path ra_has_index invalidate_bdev no-print_hex_dump kmem_cache_create-args no-WARN_ON-ret un-constify no_iov_shorten no-vm-ops-fault no-write_begin_end iget_failed export_operations void_percpu_counter_init percpu_counter_sum_positive no-nameidta-path bi_end_io mb_cache_entry_alloc_args no_mnt_want_write no_quota_on_remount proc_create_data enable_falloc HAVE_FALLOCATE no-nr_cpu_ids no_trylock_page no_spin_needbreak ext4-own-zero-page Again, please see fine-grained patches at http://people.redhat.com/esandeen/ext4/ext4-patchset-for-rhel5.3.tar.bz2 if desired. With this, ext4 compiles & runs. diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ac568da..d158d13 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -1624,7 +1624,7 @@ ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, #ifdef CONFIG_SMP if (free_blocks - root_blocks < FBC_BATCH) free_blocks = - percpu_counter_sum_positive(&sbi->s_freeblocks_counter); + percpu_counter_sum(&sbi->s_freeblocks_counter); #endif if (free_blocks <= root_blocks) /* we don't have free space */ diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index f830a6c..cc3b4ed 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -100,7 +100,7 @@ static int ext4_readdir(struct file * filp, struct ext4_dir_entry_2 *de; struct super_block *sb; int err; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; int ret = 0; sb = inode->i_sb; @@ -118,7 +118,7 @@ static int ext4_readdir(struct file * filp, * We don't set the inode dirty flag since it's not * critical that it get flushed back to the disk. */ - EXT4_I(filp->f_path.dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL; + EXT4_I(filp->f_dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL; } stored = 0; offset = filp->f_pos & (sb->s_blocksize - 1); @@ -131,14 +131,12 @@ static int ext4_readdir(struct file * filp, map_bh.b_state = 0; err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0); if (err > 0) { - pgoff_t index = map_bh.b_blocknr >> - (PAGE_CACHE_SHIFT - inode->i_blkbits); - if (!ra_has_index(&filp->f_ra, index)) - page_cache_sync_readahead( - sb->s_bdev->bd_inode->i_mapping, - &filp->f_ra, filp, - index, 1); - filp->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; + page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, + &filp->f_ra, + filp, + map_bh.b_blocknr >> + (PAGE_CACHE_SHIFT - inode->i_blkbits), + 1); bh = ext4_bread(NULL, inode, blk, 0, &err); } @@ -392,7 +390,7 @@ static int call_filldir(struct file * filp, void * dirent, { struct dir_private_info *info = filp->private_data; loff_t curr_pos; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; struct super_block * sb; int error; @@ -422,7 +420,7 @@ static int ext4_dx_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dir_private_info *info = filp->private_data; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; struct fname *fname; int ret; diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 0eb68db..728cbf1 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -18,9 +18,10 @@ #include <linux/types.h> #include <linux/blkdev.h> -#include <linux/magic.h> #include "ext4_i.h" +#define EXT4_SUPER_MAGIC 0xEF53 + /* * The fourth extended filesystem constants/structures */ @@ -1093,6 +1094,7 @@ extern int ext4_group_extend(struct super_block *sb, ext4_fsblk_t n_blocks_count); /* super.c */ +extern struct page *ext4_zero_page; extern void ext4_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4))); extern void __ext4_std_error (struct super_block *, const char *, int); @@ -1209,16 +1211,16 @@ do { \ extern const struct file_operations ext4_dir_operations; /* file.c */ -extern const struct inode_operations ext4_file_inode_operations; -extern const struct file_operations ext4_file_operations; +extern struct inode_operations ext4_file_inode_operations; +extern struct file_operations ext4_file_operations; /* namei.c */ -extern const struct inode_operations ext4_dir_inode_operations; -extern const struct inode_operations ext4_special_inode_operations; +extern struct inode_operations ext4_dir_inode_operations; +extern struct inode_operations ext4_special_inode_operations; /* symlink.c */ -extern const struct inode_operations ext4_symlink_inode_operations; -extern const struct inode_operations ext4_fast_symlink_inode_operations; +extern struct inode_operations ext4_symlink_inode_operations; +extern struct inode_operations ext4_fast_symlink_inode_operations; /* extents.c */ extern int ext4_ext_tree_init(handle_t *handle, struct inode *); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index f3cddb1..8616977 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -38,7 +38,9 @@ #include <linux/quotaops.h> #include <linux/string.h> #include <linux/slab.h> +#ifdef HAVE_FALLOCATE #include <linux/falloc.h> +#endif #include <asm/uaccess.h> #include "ext4_jbd2.h" #include "ext4_extents.h" @@ -2048,7 +2050,8 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start) err = -EIO; break; } - if (WARN_ON(i + 1 > depth)) { + WARN_ON(i + 1 > depth); + if (i + 1 > depth) { err = -EIO; break; } @@ -2151,9 +2154,11 @@ void ext4_ext_release(struct super_block *sb) #endif } -static void bi_complete(struct bio *bio, int error) +#ifdef HAVE_FALLOCATE +static int bi_complete(struct bio *bio, unsigned int bytes, int error) { complete((struct completion *)bio->bi_private); + return 0; } /* FIXME!! we need to try to merge to left or right after zero-out */ @@ -2191,7 +2196,7 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) done = 0; offset = 0; while (done < len) { - ret = bio_add_page(bio, ZERO_PAGE(0), + ret = bio_add_page(bio, ext4_zero_page, blocksize, offset); if (ret != blocksize) { /* @@ -2518,6 +2523,7 @@ fix_extent_len: ext4_ext_dirty(handle, inode, path + depth); return err; } +#endif /* * Block allocation/map/preallocation routine for extents based files @@ -2624,6 +2630,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, EXT4_EXT_CACHE_EXTENT); goto out; } +#ifdef HAVE_FALLOCATE if (create == EXT4_CREATE_UNINITIALIZED_EXT) goto out; if (!create) { @@ -2649,6 +2656,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, } else allocated = ret; goto outnew; +#endif } } @@ -2834,6 +2842,7 @@ out_stop: ext4_journal_stop(handle); } +#ifdef HAVE_FALLOCATE static void ext4_falloc_update_inode(struct inode *inode, int mode, loff_t new_size, int update_ctime) { @@ -2943,3 +2952,4 @@ retry: mutex_unlock(&inode->i_mutex); return ret > 0 ? ret2 : ret; } +#endif diff --git a/fs/ext4/file.c b/fs/ext4/file.c index b9510ba..72d932d 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -48,11 +48,11 @@ static int ext4_release_file (struct inode * inode, struct file * filp) } static ssize_t -ext4_file_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) +ext4_file_write(struct kiocb *iocb, const char __user *buf, + size_t count, loff_t pos) { struct file *file = iocb->ki_filp; - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; ssize_t ret; int err; @@ -63,18 +63,15 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - size_t length = iov_length(iov, nr_segs); if (pos > sbi->s_bitmap_maxbytes) return -EFBIG; - if (pos + length > sbi->s_bitmap_maxbytes) { - nr_segs = iov_shorten((struct iovec *)iov, nr_segs, - sbi->s_bitmap_maxbytes - pos); - } + if (pos + count > sbi->s_bitmap_maxbytes) + count = sbi->s_bitmap_maxbytes - pos; } - ret = generic_file_aio_write(iocb, iov, nr_segs, pos); + ret = generic_file_aio_write(iocb, buf, count, pos); /* * Skip flushing if there was an error, or if nothing was written. */ @@ -124,7 +121,8 @@ force_commit: } static struct vm_operations_struct ext4_file_vm_ops = { - .fault = filemap_fault, + .nopage = filemap_nopage, + .populate = filemap_populate, .page_mkwrite = ext4_page_mkwrite, }; @@ -136,11 +134,10 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) return -ENOEXEC; file_accessed(file); vma->vm_ops = &ext4_file_vm_ops; - vma->vm_flags |= VM_CAN_NONLINEAR; return 0; } -const struct file_operations ext4_file_operations = { +struct file_operations ext4_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, @@ -158,7 +155,7 @@ const struct file_operations ext4_file_operations = { .splice_write = generic_file_splice_write, }; -const struct inode_operations ext4_file_inode_operations = { +struct inode_operations ext4_file_inode_operations = { .truncate = ext4_truncate, .setattr = ext4_setattr, #ifdef CONFIG_EXT4DEV_FS_XATTR @@ -168,6 +165,8 @@ const struct inode_operations ext4_file_inode_operations = { .removexattr = generic_removexattr, #endif .permission = ext4_permission, +#ifdef HAVE_FALLOCATE .fallocate = ext4_fallocate, +#endif }; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8bc09ce..a0cac14 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1167,7 +1167,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, return bh; if (buffer_uptodate(bh)) return bh; - ll_rw_block(READ_META, 1, &bh); + ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); if (buffer_uptodate(bh)) return bh; @@ -1241,50 +1241,34 @@ static int do_journal_get_write_access(handle_t *handle, return ext4_journal_get_write_access(handle, bh); } -static int ext4_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) +static int ext4_prepare_write(struct file *file, struct page *page, + unsigned from, unsigned to) { - struct inode *inode = mapping->host; + struct inode *inode = page->mapping->host; int ret, needed_blocks = ext4_writepage_trans_blocks(inode); handle_t *handle; int retries = 0; - struct page *page; - pgoff_t index; - unsigned from, to; - - index = pos >> PAGE_CACHE_SHIFT; - from = pos & (PAGE_CACHE_SIZE - 1); - to = from + len; retry: - page = __grab_cache_page(mapping, index); - if (!page) - return -ENOMEM; - *pagep = page; - - handle = ext4_journal_start(inode, needed_blocks); - if (IS_ERR(handle)) { - unlock_page(page); - page_cache_release(page); - ret = PTR_ERR(handle); - goto out; + handle = ext4_journal_start(inode, needed_blocks); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; } + if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) + ret = nobh_prepare_write(page, from, to, ext4_get_block); + else + ret = block_prepare_write(page, from, to, ext4_get_block); + if (ret) + goto prepare_write_failed; - ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, - ext4_get_block); - - if (!ret && ext4_should_journal_data(inode)) { + if (ext4_should_journal_data(inode)) { ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, do_journal_get_write_access); } - - if (ret) { +prepare_write_failed: + if (ret) ext4_journal_stop(handle); - unlock_page(page); - page_cache_release(page); - } - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) goto retry; out: @@ -1300,8 +1284,8 @@ int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh) return err; } -/* For write_end() in data=journal mode */ -static int write_end_fn(handle_t *handle, struct buffer_head *bh) +/* For commit_write() in data=journal mode */ +static int commit_write_fn(handle_t *handle, struct buffer_head *bh) { if (!buffer_mapped(bh) || buffer_freed(bh)) return 0; @@ -1310,42 +1294,17 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh) } /* - * Generic write_end handler for ordered and writeback ext4 journal modes. - * We can't use generic_write_end, because that unlocks the page and we need to - * unlock the page after ext4_journal_stop, but ext4_journal_stop must run - * after block_write_end. - */ -static int ext4_generic_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = file->f_mapping->host; - - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); - - if (pos+copied > inode->i_size) { - i_size_write(inode, pos+copied); - mark_inode_dirty(inode); - } - - return copied; -} - -/* * We need to pick up the new inode size which generic_commit_write gave us * `file' can be NULL - eg, when called from page_symlink(). * * ext4 never places buffers on inode->i_mapping->private_list. metadata * buffers are managed internally. */ -static int ext4_ordered_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static int ext4_ordered_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = file->f_mapping->host; + struct inode *inode = page->mapping->host; int ret = 0, ret2; ret = walk_page_buffers(handle, page_buffers(page), @@ -1353,85 +1312,66 @@ static int ext4_ordered_write_end(struct file *file, if (ret == 0) { /* - * generic_write_end() will run mark_inode_dirty() if i_size + * generic_commit_write() will run mark_inode_dirty() if i_size * changes. So let's piggyback the i_disksize mark_inode_dirty * into that. */ loff_t new_i_size; - new_i_size = pos + copied; + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, - page, fsdata); - copied = ret2; - if (ret2 < 0) - ret = ret2; + ret = generic_commit_write(file, page, from, to); } ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - unlock_page(page); - page_cache_release(page); - - return ret ? ret : copied; + return ret; } -static int ext4_writeback_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static int ext4_writeback_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = file->f_mapping->host; + struct inode *inode = page->mapping->host; int ret = 0, ret2; loff_t new_i_size; - new_i_size = pos + copied; + new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; if (new_i_size > EXT4_I(inode)->i_disksize) EXT4_I(inode)->i_disksize = new_i_size; - ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, - page, fsdata); - copied = ret2; - if (ret2 < 0) - ret = ret2; + if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) + ret = nobh_commit_write(file, page, from, to); + else + ret = generic_commit_write(file, page, from, to); ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - unlock_page(page); - page_cache_release(page); - return ret ? ret : copied; + return ret; } -static int ext4_journalled_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) +static int ext4_journalled_commit_write(struct file *file, + struct page *page, unsigned from, unsigned to) { handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = mapping->host; + struct inode *inode = page->mapping->host; int ret = 0, ret2; int partial = 0; - unsigned from, to; - - from = pos & (PAGE_CACHE_SIZE - 1); - to = from + len; - - if (copied < len) { - if (!PageUptodate(page)) - copied = 0; - page_zero_new_buffers(page, from+copied, to); - } + loff_t pos; + /* + * Here we duplicate the generic_commit_write() functionality + */ + pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; ret = walk_page_buffers(handle, page_buffers(page), from, - to, &partial, write_end_fn); + to, &partial, commit_write_fn); if (!partial) SetPageUptodate(page); - if (pos+copied > inode->i_size) - i_size_write(inode, pos+copied); + if (pos > inode->i_size) + i_size_write(inode, pos); EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; if (inode->i_size > EXT4_I(inode)->i_disksize) { EXT4_I(inode)->i_disksize = inode->i_size; @@ -1439,14 +1379,10 @@ static int ext4_journalled_write_end(struct file *file, if (!ret) ret = ret2; } - ret2 = ext4_journal_stop(handle); if (!ret) ret = ret2; - unlock_page(page); - page_cache_release(page); - - return ret ? ret : copied; + return ret; } /* @@ -1688,12 +1624,12 @@ static int ext4_journalled_writepage(struct page *page, goto no_write; } - if (!page_has_buffers(page) || PageChecked(page)) { + if (!page_has_buffers(page) || PageFsMisc(page)) { /* * It's mmapped pagecache. Add buffers and journal it. There * doesn't seem much point in redirtying the page here. */ - ClearPageChecked(page); + ClearPageFsMisc(page); ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, ext4_get_block); if (ret != 0) { @@ -1704,7 +1640,7 @@ static int ext4_journalled_writepage(struct page *page, PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); err = walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, write_end_fn); + PAGE_CACHE_SIZE, NULL, commit_write_fn); if (ret == 0) ret = err; EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; @@ -1750,7 +1686,7 @@ static void ext4_invalidatepage(struct page *page, unsigned long offset) * If it's a full truncate we just forget about the pending dirtying */ if (offset == 0) - ClearPageChecked(page); + ClearPageFsMisc(page); jbd2_journal_invalidatepage(journal, page, offset); } @@ -1759,7 +1695,7 @@ static int ext4_releasepage(struct page *page, gfp_t wait) { journal_t *journal = EXT4_JOURNAL(page->mapping->host); - WARN_ON(PageChecked(page)); + WARN_ON(PageFsMisc(page)); if (!page_has_buffers(page)) return 0; return jbd2_journal_try_to_free_buffers(journal, page, wait); @@ -1863,7 +1799,7 @@ out: */ static int ext4_journalled_set_page_dirty(struct page *page) { - SetPageChecked(page); + SetPageFsMisc(page); return __set_page_dirty_nobuffers(page); } @@ -1872,8 +1808,8 @@ static const struct address_space_operations ext4_ordered_aops = { .readpages = ext4_readpages, .writepage = ext4_ordered_writepage, .sync_page = block_sync_page, - .write_begin = ext4_write_begin, - .write_end = ext4_ordered_write_end, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_ordered_commit_write, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -1886,8 +1822,8 @@ static const struct address_space_operations ext4_writeback_aops = { .readpages = ext4_readpages, .writepage = ext4_writeback_writepage, .sync_page = block_sync_page, - .write_begin = ext4_write_begin, - .write_end = ext4_writeback_write_end, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_writeback_commit_write, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, .releasepage = ext4_releasepage, @@ -1900,8 +1836,8 @@ static const struct address_space_operations ext4_journalled_aops = { .readpages = ext4_readpages, .writepage = ext4_journalled_writepage, .sync_page = block_sync_page, - .write_begin = ext4_write_begin, - .write_end = ext4_journalled_write_end, + .prepare_write = ext4_prepare_write, + .commit_write = ext4_journalled_commit_write, .set_page_dirty = ext4_journalled_set_page_dirty, .bmap = ext4_bmap, .invalidatepage = ext4_invalidatepage, @@ -2725,7 +2661,7 @@ make_io: */ get_bh(bh); bh->b_end_io = end_buffer_read_sync; - submit_bh(READ_META, bh); + submit_bh(READ, bh); wait_on_buffer(bh); if (!buffer_uptodate(bh)) { ext4_error(inode->i_sb, "ext4_get_inode_loc", @@ -2947,7 +2883,9 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) return inode; bad_inode: - iget_failed(inode); + make_bad_inode(inode); + unlock_new_inode(inode); + iput(inode); return ERR_PTR(ret); } @@ -3675,9 +3613,11 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page) unsigned long len; int ret = -EINVAL; struct file *file = vma->vm_file; - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; + lock_page(page); + /* * Get i_alloc_sem to stop truncates messing with the inode. We cannot * get i_mutex because we are already holding mmap_sem. @@ -3705,22 +3645,21 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page) goto out_unlock; } /* - * OK, we need to fill the hole... Do write_begin write_end + * OK, we need to fill the hole... Do prepare_write commit_write * to do block allocation/reservation.We are not holding - * inode.i__mutex here. That allow * parallel write_begin, - * write_end call. lock_page prevent this from happening + * inode.i__mutex here. That allow * parallel prepare_write, + * commit_write call. lock_page prevent this from happening * on the same page though */ - ret = mapping->a_ops->write_begin(file, mapping, page_offset(page), - len, AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); + ret = mapping->a_ops->prepare_write(file, page, 0, len); if (ret < 0) goto out_unlock; - ret = mapping->a_ops->write_end(file, mapping, page_offset(page), - len, len, page, NULL); + ret = mapping->a_ops->commit_write(file, page, 0, len); if (ret < 0) goto out_unlock; ret = 0; out_unlock: up_read(&inode->i_alloc_sem); + unlock_page(page); return ret; } diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 7a6c2f1..426fd0e 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -13,7 +13,6 @@ #include <linux/time.h> #include <linux/compat.h> #include <linux/smp_lock.h> -#include <linux/mount.h> #include <asm/uaccess.h> #include "ext4_jbd2.h" #include "ext4.h" @@ -39,25 +38,24 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) unsigned int oldflags; unsigned int jflag; + if (IS_RDONLY(inode)) + return -EROFS; + if (!is_owner_or_cap(inode)) return -EACCES; if (get_user(flags, (int __user *) arg)) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); - if (err) - return err; - if (!S_ISDIR(inode->i_mode)) flags &= ~EXT4_DIRSYNC_FL; - err = -EPERM; mutex_lock(&inode->i_mutex); /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) - goto flags_out; - + if (IS_NOQUOTA(inode)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } oldflags = ei->i_flags; /* The JOURNAL_DATA flag is modifiable only by root */ @@ -70,8 +68,10 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * This test looks nicer. Thanks to Pauline Middelink */ if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto flags_out; + if (!capable(CAP_LINUX_IMMUTABLE)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } } /* @@ -79,14 +79,17 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) * the relevant capability. */ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { - if (!capable(CAP_SYS_RESOURCE)) - goto flags_out; + if (!capable(CAP_SYS_RESOURCE)) { + mutex_unlock(&inode->i_mutex); + return -EPERM; + } } + handle = ext4_journal_start(inode, 1); if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto flags_out; + mutex_unlock(&inode->i_mutex); + return PTR_ERR(handle); } if (IS_SYNC(inode)) handle->h_sync = 1; @@ -104,14 +107,14 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) err = ext4_mark_iloc_dirty(handle, inode, &iloc); flags_err: ext4_journal_stop(handle); - if (err) - goto flags_out; + if (err) { + mutex_unlock(&inode->i_mutex); + return err; + } if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) err = ext4_change_inode_journal_flag(inode, jflag); -flags_out: mutex_unlock(&inode->i_mutex); - mnt_drop_write(filp->f_path.mnt); return err; } case EXT4_IOC_GETVERSION: @@ -126,20 +129,14 @@ flags_out: if (!is_owner_or_cap(inode)) return -EPERM; - - err = mnt_want_write(filp->f_path.mnt); - if (err) - return err; - if (get_user(generation, (int __user *) arg)) { - err = -EFAULT; - goto setversion_out; - } + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(generation, (int __user *) arg)) + return -EFAULT; handle = ext4_journal_start(inode, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto setversion_out; - } + if (IS_ERR(handle)) + return PTR_ERR(handle); err = ext4_reserve_inode_write(handle, inode, &iloc); if (err == 0) { inode->i_ctime = ext4_current_time(inode); @@ -147,8 +144,6 @@ flags_out: err = ext4_mark_iloc_dirty(handle, inode, &iloc); } ext4_journal_stop(handle); -setversion_out: - mnt_drop_write(filp->f_path.mnt); return err; } #ifdef CONFIG_JBD2_DEBUG @@ -184,21 +179,19 @@ setversion_out: } return -ENOTTY; case EXT4_IOC_SETRSVSZ: { - int err; if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; + if (IS_RDONLY(inode)) + return -EROFS; + if (!is_owner_or_cap(inode)) return -EACCES; if (get_user(rsv_window_size, (int __user *)arg)) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); - if (err) - return err; - if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS) rsv_window_size = EXT4_MAX_RESERVE_BLOCKS; @@ -215,7 +208,6 @@ setversion_out: rsv->rsv_goal_size = rsv_window_size; } up_write(&ei->i_data_sem); - mnt_drop_write(filp->f_path.mnt); return 0; } case EXT4_IOC_GROUP_EXTEND: { @@ -226,18 +218,16 @@ setversion_out: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (get_user(n_blocks_count, (__u32 __user *)arg)) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); - if (err) - return err; - err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_flush(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - mnt_drop_write(filp->f_path.mnt); return err; } @@ -249,19 +239,17 @@ setversion_out: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, sizeof(input))) return -EFAULT; - err = mnt_want_write(filp->f_path.mnt); - if (err) - return err; - err = ext4_group_add(sb, &input); jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); jbd2_journal_flush(EXT4_SB(sb)->s_journal); jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - mnt_drop_write(filp->f_path.mnt); return err; } diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 31f98f3..7000510 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2181,10 +2181,17 @@ static void ext4_mb_history_init(struct super_block *sb) int i; if (sbi->s_mb_proc != NULL) { - proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc, - &ext4_mb_seq_history_fops, sb); - proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc, - &ext4_mb_seq_groups_fops, sb); + struct proc_dir_entry *p; + p = create_proc_entry("mb_history", S_IRUGO, sbi->s_mb_proc); + if (p) { + p->proc_fops = &ext4_mb_seq_history_fops; + p->data = sb; + } + p = create_proc_entry("mb_groups", S_IRUGO, sbi->s_mb_proc); + if (p) { + p->proc_fops = &ext4_mb_seq_groups_fops; + p->data = sb; + } } sbi->s_mb_history_max = 1000; @@ -2540,7 +2547,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT; sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC; - i = sizeof(struct ext4_locality_group) * nr_cpu_ids; + i = sizeof(struct ext4_locality_group) * num_possible_cpus(); sbi->s_locality_groups = kmalloc(i, GFP_KERNEL); if (sbi->s_locality_groups == NULL) { clear_opt(sbi->s_mount_opt, MBALLOC); @@ -2548,7 +2555,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) kfree(sbi->s_mb_maxs); return -ENOMEM; } - for (i = 0; i < nr_cpu_ids; i++) { + for (i = 0; i < num_possible_cpus(); i++) { struct ext4_locality_group *lg; lg = &sbi->s_locality_groups[i]; mutex_init(&lg->lg_mutex); @@ -2740,7 +2747,7 @@ static int ext4_mb_##name##_proc_open(struct inode *inode, struct file *file)\ static ssize_t ext4_mb_##name##_proc_write(struct file *file, \ const char __user *buf, size_t cnt, loff_t *ppos) \ { \ - struct ext4_sb_info *sbi = PDE(file->f_path.dentry->d_inode)->data;\ + struct ext4_sb_info *sbi = PDE(file->f_dentry->d_inode)->data;\ char str[32]; \ long value; \ if (cnt >= sizeof(str)) \ @@ -2772,8 +2779,11 @@ MB_PROC_FOPS(group_prealloc); #define MB_PROC_HANDLER(name, var) \ do { \ - proc = proc_create_data(name, mode, sbi->s_mb_proc, \ - &ext4_mb_##var##_proc_fops, sbi); \ + proc = create_proc_entry(name, mode, sbi->s_mb_proc); \ + if (proc) { \ + proc->proc_fops = &ext4_mb_##var##_proc_fops; \ + proc->data = sb; \ + } \ if (proc == NULL) { \ printk(KERN_ERR "EXT4-fs: can't to create %s\n", name); \ goto err_out; \ @@ -2842,14 +2852,14 @@ int __init init_ext4_mballoc(void) ext4_pspace_cachep = kmem_cache_create("ext4_prealloc_space", sizeof(struct ext4_prealloc_space), - 0, SLAB_RECLAIM_ACCOUNT, NULL); + 0, SLAB_RECLAIM_ACCOUNT, NULL, NULL); if (ext4_pspace_cachep == NULL) return -ENOMEM; ext4_ac_cachep = kmem_cache_create("ext4_alloc_context", sizeof(struct ext4_allocation_context), - 0, SLAB_RECLAIM_ACCOUNT, NULL); + 0, SLAB_RECLAIM_ACCOUNT, NULL, NULL); if (ext4_ac_cachep == NULL) { kmem_cache_destroy(ext4_pspace_cachep); return -ENOMEM; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 387ad98..f3fe06b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -637,7 +637,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, start_minor_hash)); - dir = dir_file->f_path.dentry->d_inode; + dir = dir_file->f_dentry->d_inode; if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) { hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; @@ -648,7 +648,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, } hinfo.hash = start_hash; hinfo.minor_hash = 0; - frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err); + frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err); if (!frame) return err; @@ -912,7 +912,7 @@ restart: bh = ext4_getblk(NULL, dir, b++, 0, &err); bh_use[ra_max] = bh; if (bh) - ll_rw_block(READ_META, 1, &bh); + ll_rw_block(READ, 1, &bh); } } if ((bh = bh_use[ra_ptr++]) == NULL) @@ -2443,7 +2443,7 @@ end_rename: /* * directories can handle most operations... */ -const struct inode_operations ext4_dir_inode_operations = { +struct inode_operations ext4_dir_inode_operations = { .create = ext4_create, .lookup = ext4_lookup, .link = ext4_link, @@ -2463,7 +2463,7 @@ const struct inode_operations ext4_dir_inode_operations = { .permission = ext4_permission, }; -const struct inode_operations ext4_special_inode_operations = { +struct inode_operations ext4_special_inode_operations = { .setattr = ext4_setattr, #ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2f76c1d..0f80083 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -27,7 +27,6 @@ #include <linux/parser.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> -#include <linux/exportfs.h> #include <linux/vfs.h> #include <linux/random.h> #include <linux/mount.h> @@ -64,6 +63,7 @@ static void ext4_unlockfs(struct super_block *sb); static void ext4_write_super(struct super_block *sb); static void ext4_write_super_lockfs(struct super_block *sb); +struct page *ext4_zero_page; ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, struct ext4_group_desc *bg) @@ -534,7 +534,7 @@ static void ext4_put_super(struct super_block *sb) dump_orphan_list(sb, sbi); J_ASSERT(list_empty(&sbi->s_orphan)); - invalidate_bdev(sb->s_bdev); + invalidate_bdev(sb->s_bdev, 0); if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { /* * Invalidate the journal device's buffers. We don't want them @@ -542,7 +542,7 @@ static void ext4_put_super(struct super_block *sb) * hotswapped, and it breaks the `ro-after' testing code. */ sync_blockdev(sbi->journal_bdev); - invalidate_bdev(sbi->journal_bdev); + invalidate_bdev(sbi->journal_bdev, 0); ext4_blkdev_remove(sbi); } sb->s_fs_info = NULL; @@ -580,15 +580,12 @@ static void ext4_destroy_inode(struct inode *inode) if (!list_empty(&(EXT4_I(inode)->i_orphan))) { printk("EXT4 Inode %p: orphan list check failed!\n", EXT4_I(inode)); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, - EXT4_I(inode), sizeof(struct ext4_inode_info), - true); dump_stack(); } kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } -static void init_once(struct kmem_cache *cachep, void *foo) +static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; @@ -606,7 +603,7 @@ static int init_inodecache(void) sizeof(struct ext4_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once); + init_once, NULL); if (ext4_inode_cachep == NULL) return -ENOMEM; return 0; @@ -767,10 +764,14 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) } -static struct inode *ext4_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation) +static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp) { + __u32 *objp = vobjp; + unsigned long ino = objp[0]; + __u32 generation = objp[1]; struct inode *inode; + struct dentry *result; + if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) return ERR_PTR(-ESTALE); @@ -792,22 +793,15 @@ static struct inode *ext4_nfs_get_inode(struct super_block *sb, iput(inode); return ERR_PTR(-ESTALE); } - - return inode; -} - -static struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - ext4_nfs_get_inode); -} - -static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - ext4_nfs_get_inode); + /* now to find a dentry. + * If possible, get a well-connected one + */ + result = d_alloc_anon(inode); + if (!result) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + return result; } #ifdef CONFIG_QUOTA @@ -821,8 +815,7 @@ static int ext4_acquire_dquot(struct dquot *dquot); static int ext4_release_dquot(struct dquot *dquot); static int ext4_mark_dquot_dirty(struct dquot *dquot); static int ext4_write_info(struct super_block *sb, int type); -static int ext4_quota_on(struct super_block *sb, int type, int format_id, - char *path, int remount); +static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path); static int ext4_quota_on_mount(struct super_block *sb, int type); static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); @@ -855,7 +848,7 @@ static struct quotactl_ops ext4_qctl_operations = { }; #endif -static const struct super_operations ext4_sops = { +static struct super_operations ext4_sops = { .alloc_inode = ext4_alloc_inode, .destroy_inode = ext4_destroy_inode, .write_inode = ext4_write_inode, @@ -876,10 +869,9 @@ static const struct super_operations ext4_sops = { #endif }; -static const struct export_operations ext4_export_ops = { - .fh_to_dentry = ext4_fh_to_dentry, - .fh_to_parent = ext4_fh_to_parent, +static struct export_operations ext4_export_ops = { .get_parent = ext4_get_parent, + .get_dentry = ext4_get_dentry, }; enum { @@ -988,7 +980,7 @@ static int parse_options(char *options, struct super_block *sb, int data_opt = 0; int option; #ifdef CONFIG_QUOTA - int qtype, qfmt; + int qtype; char *qname; #endif ext4_fsblk_t last_block; @@ -1172,9 +1164,7 @@ static int parse_options(char *options, struct super_block *sb, case Opt_grpjquota: qtype = GRPQUOTA; set_qf_name: - if ((sb_any_quota_enabled(sb) || - sb_any_quota_suspended(sb)) && - !sbi->s_qf_names[qtype]) { + if (sb_any_quota_enabled(sb)) { printk(KERN_ERR "EXT4-fs: Cannot change journaled " "quota options when quota turned on.\n"); @@ -1212,9 +1202,7 @@ set_qf_name: case Opt_offgrpjquota: qtype = GRPQUOTA; clear_qf_name: - if ((sb_any_quota_enabled(sb) || - sb_any_quota_suspended(sb)) && - sbi->s_qf_names[qtype]) { + if (sb_any_quota_enabled(sb)) { printk(KERN_ERR "EXT4-fs: Cannot change " "journaled quota options when " "quota turned on.\n"); @@ -1227,20 +1215,10 @@ clear_qf_name: sbi->s_qf_names[qtype] = NULL; break; case Opt_jqfmt_vfsold: - qfmt = QFMT_VFS_OLD; - goto set_qf_format; + sbi->s_jquota_fmt = QFMT_VFS_OLD; + break; case Opt_jqfmt_vfsv0: - qfmt = QFMT_VFS_V0; -set_qf_format: - if ((sb_any_quota_enabled(sb) || - sb_any_quota_suspended(sb)) && - sbi->s_jquota_fmt != qfmt) { - printk(KERN_ERR "EXT4-fs: Cannot change " - "journaled quota options when " - "quota turned on.\n"); - return 0; - } - sbi->s_jquota_fmt = qfmt; + sbi->s_jquota_fmt = QFMT_VFS_V0; break; case Opt_quota: case Opt_usrquota: @@ -1724,7 +1702,7 @@ static void ext4_orphan_cleanup(struct super_block *sb, /* Turn quotas off */ for (i = 0; i < MAXQUOTAS; i++) { if (sb_dqopt(sb)->files[i]) - vfs_quota_off(sb, i, 0); + vfs_quota_off(sb, i); } #endif sb->s_flags = s_flags; /* Restore MS_RDONLY status */ @@ -1902,7 +1880,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) int needs_recovery; __le32 features; __u64 blocks_count; - int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -2221,20 +2198,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - err = percpu_counter_init(&sbi->s_freeblocks_counter, + percpu_counter_init(&sbi->s_freeblocks_counter, ext4_count_free_blocks(sb)); - if (!err) { - err = percpu_counter_init(&sbi->s_freeinodes_counter, + percpu_counter_init(&sbi->s_freeinodes_counter, ext4_count_free_inodes(sb)); - } - if (!err) { - err = percpu_counter_init(&sbi->s_dirs_counter, + percpu_counter_init(&sbi->s_dirs_counter, ext4_count_dirs(sb)); - } - if (err) { - printk(KERN_ERR "EXT4-fs: insufficient memory\n"); - goto failed_mount3; - } /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -3129,13 +3098,14 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); + /* percpu_counter_sum already _positive in RHEL5 */ + buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); ext4_free_blocks_count_set(es, buf->f_bfree); buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); if (buf->f_bfree < ext4_r_blocks_count(es)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); + buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT4_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ @@ -3295,30 +3265,27 @@ static int ext4_quota_on_mount(struct super_block *sb, int type) * Standard function to be called on quota_on */ static int ext4_quota_on(struct super_block *sb, int type, int format_id, - char *path, int remount) + char *path) { int err; struct nameidata nd; if (!test_opt(sb, QUOTA)) return -EINVAL; - /* When remounting, no checks are needed and in fact, path is NULL */ - if (remount) - return vfs_quota_on(sb, type, format_id, path, remount); err = path_lookup(path, LOOKUP_FOLLOW, &nd); if (err) return err; /* Quotafile not on the same filesystem? */ - if (nd.path.mnt->mnt_sb != sb) { - path_put(&nd.path); + if (nd.mnt->mnt_sb != sb) { + path_release(&nd); return -EXDEV; } /* Journaling quota? */ if (EXT4_SB(sb)->s_qf_names[type]) { /* Quotafile not in fs root? */ - if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) + if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) printk(KERN_WARNING "EXT4-fs: Quota file not on filesystem root. " "Journaled quota will not work.\n"); @@ -3328,7 +3295,7 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, * When we journal data on quota file, we have to flush journal to see * all updates to the file when we bypass pagecache... */ - if (ext4_should_journal_data(nd.path.dentry->d_inode)) { + if (ext4_should_journal_data(nd.dentry->d_inode)) { /* * We don't need to lock updates but journal_flush() could * otherwise be livelocked... @@ -3338,8 +3305,8 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); } - path_put(&nd.path); - return vfs_quota_on(sb, type, format_id, path, remount); + path_release(&nd); + return vfs_quota_on(sb, type, format_id, path); } /* Read data from quotafile - avoid pagecache and such because we cannot afford @@ -3464,17 +3431,27 @@ static struct file_system_type ext4dev_fs_type = { .name = "ext4dev", .get_sb = ext4_get_sb, .kill_sb = kill_block_super, +#ifdef HAVE_FALLOCATE + .fs_flags = FS_REQUIRES_DEV|FS_HAS_FALLOCATE, +#else .fs_flags = FS_REQUIRES_DEV, +#endif }; static int __init init_ext4_fs(void) { int err; + void *p; + + ext4_zero_page = alloc_page(GFP_USER); + if (!ext4_zero_page) + return -ENOMEM; + p = kmap(ext4_zero_page); + memset(p, 0, PAGE_SIZE); err = init_ext4_mballoc(); if (err) - return err; - + goto out3; err = init_ext4_xattr(); if (err) goto out2; @@ -3491,6 +3468,8 @@ out1: exit_ext4_xattr(); out2: exit_ext4_mballoc(); +out3: + __free_page(ext4_zero_page); return err; } @@ -3500,6 +3479,7 @@ static void __exit exit_ext4_fs(void) destroy_inodecache(); exit_ext4_xattr(); exit_ext4_mballoc(); + __free_page(ext4_zero_page); } MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index e917864..a8c25ad 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -30,7 +30,7 @@ static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -const struct inode_operations ext4_symlink_inode_operations = { +struct inode_operations ext4_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -42,7 +42,7 @@ const struct inode_operations ext4_symlink_inode_operations = { #endif }; -const struct inode_operations ext4_fast_symlink_inode_operations = { +struct inode_operations ext4_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ext4_follow_link, #ifdef CONFIG_EXT4DEV_FS_XATTR diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 8954208..0034670 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -1389,7 +1389,7 @@ ext4_xattr_cache_insert(struct buffer_head *bh) struct mb_cache_entry *ce; int error; - ce = mb_cache_entry_alloc(ext4_xattr_cache, GFP_NOFS); + ce = mb_cache_entry_alloc(ext4_xattr_cache); if (!ce) { ea_bdebug(bh, "out of memory"); return; diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 6914598..3f18958 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -353,8 +353,7 @@ restart: } retry = __process_buffer(journal, jh, bhs, &batch_count, transaction); - if (!retry && (need_resched() || - spin_needbreak(&journal->j_list_lock))) { + if (!retry && lock_need_resched(&journal->j_list_lock)) { spin_unlock(&journal->j_list_lock); retry = 1; break; diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index b706b7d..04ee96f 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -65,7 +65,7 @@ static void release_buffer_page(struct buffer_head *bh) goto nope; /* OK, it's a truncated page */ - if (!trylock_page(page)) + if (TestSetPageLocked(page)) goto nope; page_cache_get(page); @@ -360,7 +360,7 @@ write_out_data: put_bh(bh); } - if (need_resched() || spin_needbreak(&journal->j_list_lock)) { + if (lock_need_resched(&journal->j_list_lock)) { spin_unlock(&journal->j_list_lock); goto write_out_data; } diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index e52a41d..1bd9060 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -30,7 +30,6 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/mm.h> -#include <linux/freezer.h> #include <linux/pagemap.h> #include <linux/kthread.h> #include <linux/poison.h> @@ -903,10 +902,19 @@ static void jbd2_stats_proc_init(journal_t *journal) bdevname(journal->j_dev, name); journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats); if (journal->j_proc_entry) { - proc_create_data("history", S_IRUGO, journal->j_proc_entry, - &jbd2_seq_history_fops, journal); - proc_create_data("info", S_IRUGO, journal->j_proc_entry, - &jbd2_seq_info_fops, journal); + struct proc_dir_entry *p; + p = create_proc_entry("history", S_IRUGO, + journal->j_proc_entry); + if (p) { + p->proc_fops = &jbd2_seq_history_fops; + p->data = journal; + p = create_proc_entry("info", S_IRUGO, + journal->j_proc_entry); + if (p) { + p->proc_fops = &jbd2_seq_info_fops; + p->data = journal; + } + } } } @@ -1964,8 +1972,9 @@ static int journal_init_jbd2_journal_head_cache(void) jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head", sizeof(struct journal_head), 0, /* offset */ - SLAB_TEMPORARY, /* flags */ - NULL); /* ctor */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ retval = 0; if (!jbd2_journal_head_cache) { retval = -ENOMEM; @@ -2261,8 +2270,9 @@ static int __init journal_init_handle_cache(void) jbd2_handle_cache = kmem_cache_create("jbd2_journal_handle", sizeof(handle_t), 0, /* offset */ - SLAB_TEMPORARY, /* flags */ - NULL); /* ctor */ + 0, /* flags */ + NULL, /* ctor */ + NULL); /* dtor */ if (jbd2_handle_cache == NULL) { printk(KERN_EMERG "JBD: failed to create handle cache\n"); return -ENOMEM; diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 257ff26..4adcb09 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c @@ -187,14 +187,14 @@ int __init jbd2_journal_init_revoke_caches(void) jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record", sizeof(struct jbd2_revoke_record_s), 0, - SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, - NULL); + SLAB_HWCACHE_ALIGN, + NULL, NULL); if (!jbd2_revoke_record_cache) goto record_cache_failure; jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table", sizeof(struct jbd2_revoke_table_s), - 0, SLAB_TEMPORARY, NULL); + 0, 0, NULL, NULL); if (!jbd2_revoke_table_cache) goto table_cache_failure; return 0;