diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/disk-io.c | 2 | ||||
-rw-r--r-- | fs/btrfs/tests/btrfs-tests.c | 6 | ||||
-rw-r--r-- | fs/btrfs/tests/free-space-tree-tests.c | 1 | ||||
-rw-r--r-- | fs/debugfs/inode.c | 2 | ||||
-rw-r--r-- | fs/ext4/crypto.c | 4 | ||||
-rw-r--r-- | fs/ext4/inode.c | 6 | ||||
-rw-r--r-- | fs/f2fs/crypto_policy.c | 3 | ||||
-rw-r--r-- | fs/f2fs/data.c | 13 | ||||
-rw-r--r-- | fs/f2fs/dir.c | 8 | ||||
-rw-r--r-- | fs/f2fs/file.c | 6 | ||||
-rw-r--r-- | fs/f2fs/namei.c | 12 | ||||
-rw-r--r-- | fs/f2fs/super.c | 165 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 33 |
13 files changed, 163 insertions, 98 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 4545e2e2a..d8d68af5a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1830,7 +1830,7 @@ static int cleaner_kthread(void *arg) */ btrfs_delete_unused_bgs(root->fs_info); sleep: - if (!try_to_freeze() && !again) { + if (!again) { set_current_state(TASK_INTERRUPTIBLE); if (!kthread_should_stop()) schedule(); diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c index 0e1e61a7e..d39f714da 100644 --- a/fs/btrfs/tests/btrfs-tests.c +++ b/fs/btrfs/tests/btrfs-tests.c @@ -189,12 +189,6 @@ btrfs_alloc_dummy_block_group(unsigned long length) kfree(cache); return NULL; } - cache->fs_info = btrfs_alloc_dummy_fs_info(); - if (!cache->fs_info) { - kfree(cache->free_space_ctl); - kfree(cache); - return NULL; - } cache->key.objectid = 0; cache->key.offset = length; diff --git a/fs/btrfs/tests/free-space-tree-tests.c b/fs/btrfs/tests/free-space-tree-tests.c index d05fe1ab4..7cea4462a 100644 --- a/fs/btrfs/tests/free-space-tree-tests.c +++ b/fs/btrfs/tests/free-space-tree-tests.c @@ -485,6 +485,7 @@ static int run_test(test_func_t test_func, int bitmaps) cache->bitmap_low_thresh = 0; cache->bitmap_high_thresh = (u32)-1; cache->needs_free_space = 1; + cache->fs_info = root->fs_info; btrfs_init_dummy_trans(&trans); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index bece948b3..8580831ed 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -457,7 +457,7 @@ struct dentry *debugfs_create_automount(const char *name, if (unlikely(!inode)) return failed_creating(dentry); - inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + make_empty_dir_inode(inode); inode->i_flags |= S_AUTOMOUNT; inode->i_private = data; dentry->d_fsdata = (void *)f; diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c index ecb543944..25634c353 100644 --- a/fs/ext4/crypto.c +++ b/fs/ext4/crypto.c @@ -34,6 +34,7 @@ #include <linux/random.h> #include <linux/scatterlist.h> #include <linux/spinlock_types.h> +#include <linux/namei.h> #include "ext4_extents.h" #include "xattr.h" @@ -479,6 +480,9 @@ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags) struct ext4_crypt_info *ci; int dir_has_key, cached_with_key; + if (flags & LOOKUP_RCU) + return -ECHILD; + dir = dget_parent(dentry); if (!ext4_encrypted_inode(d_inode(dir))) { dput(dir); diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index aee960b1a..e6218cbc8 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5261,6 +5261,8 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) might_sleep(); trace_ext4_mark_inode_dirty(inode, _RET_IP_); err = ext4_reserve_inode_write(handle, inode, &iloc); + if (err) + return err; if (ext4_handle_valid(handle) && EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { @@ -5291,9 +5293,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) } } } - if (!err) - err = ext4_mark_iloc_dirty(handle, inode, &iloc); - return err; + return ext4_mark_iloc_dirty(handle, inode, &iloc); } /* diff --git a/fs/f2fs/crypto_policy.c b/fs/f2fs/crypto_policy.c index d4a96af51..596f02490 100644 --- a/fs/f2fs/crypto_policy.c +++ b/fs/f2fs/crypto_policy.c @@ -192,7 +192,8 @@ int f2fs_inherit_context(struct inode *parent, struct inode *child, return res; ci = F2FS_I(parent)->i_crypt_info; - BUG_ON(ci == NULL); + if (ci == NULL) + return -ENOKEY; ctx.format = F2FS_ENCRYPTION_CONTEXT_FORMAT_V1; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5c06db17e..44802599f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -67,7 +67,6 @@ static void f2fs_write_end_io(struct bio *bio) f2fs_restore_and_release_control_page(&page); if (unlikely(bio->bi_error)) { - set_page_dirty(page); set_bit(AS_EIO, &page->mapping->flags); f2fs_stop_checkpoint(sbi); } @@ -504,7 +503,7 @@ static int __allocate_data_blocks(struct inode *inode, loff_t offset, struct dnode_of_data dn; u64 start = F2FS_BYTES_TO_BLK(offset); u64 len = F2FS_BYTES_TO_BLK(count); - bool allocated; + bool allocated = false; u64 end_offset; int err = 0; @@ -546,7 +545,7 @@ static int __allocate_data_blocks(struct inode *inode, loff_t offset, f2fs_put_dnode(&dn); f2fs_unlock_op(sbi); - f2fs_balance_fs(sbi, dn.node_changed); + f2fs_balance_fs(sbi, allocated); } return err; @@ -556,7 +555,7 @@ sync_out: f2fs_put_dnode(&dn); out: f2fs_unlock_op(sbi); - f2fs_balance_fs(sbi, dn.node_changed); + f2fs_balance_fs(sbi, allocated); return err; } @@ -650,14 +649,14 @@ get_next: if (dn.ofs_in_node >= end_offset) { if (allocated) sync_inode_page(&dn); - allocated = false; f2fs_put_dnode(&dn); if (create) { f2fs_unlock_op(sbi); - f2fs_balance_fs(sbi, dn.node_changed); + f2fs_balance_fs(sbi, allocated); f2fs_lock_op(sbi); } + allocated = false; set_new_dnode(&dn, inode, NULL, NULL, 0); err = get_dnode_of_data(&dn, pgofs, mode); @@ -715,7 +714,7 @@ put_out: unlock_out: if (create) { f2fs_unlock_op(sbi); - f2fs_balance_fs(sbi, dn.node_changed); + f2fs_balance_fs(sbi, allocated); } out: trace_f2fs_map_blocks(inode, map, err); diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index faa7495e2..30e6b6563 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -892,11 +892,19 @@ out: return err; } +static int f2fs_dir_open(struct inode *inode, struct file *filp) +{ + if (f2fs_encrypted_inode(inode)) + return f2fs_get_encryption_info(inode) ? -EACCES : 0; + return 0; +} + const struct file_operations f2fs_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate = f2fs_readdir, .fsync = f2fs_sync_file, + .open = f2fs_dir_open, .unlocked_ioctl = f2fs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = f2fs_compat_ioctl, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ea272be62..5a322bc00 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -425,6 +425,8 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma) err = f2fs_get_encryption_info(inode); if (err) return 0; + if (!f2fs_encrypted_inode(inode)) + return -ENOKEY; } /* we don't need to use inline_data strictly */ @@ -444,7 +446,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) if (!ret && f2fs_encrypted_inode(inode)) { ret = f2fs_get_encryption_info(inode); if (ret) - ret = -EACCES; + return -EACCES; + if (!f2fs_encrypted_inode(inode)) + return -ENOKEY; } return ret; } diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 6f944e5eb..7e9e38769 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -980,12 +980,6 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, } memcpy(cstr.name, sd->encrypted_path, cstr.len); - /* this is broken symlink case */ - if (unlikely(cstr.name[0] == 0)) { - res = -ENOENT; - goto errout; - } - if ((cstr.len + sizeof(struct f2fs_encrypted_symlink_data) - 1) > max_size) { /* Symlink data on the disk is corrupted */ @@ -1002,6 +996,12 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, kfree(cstr.name); + /* this is broken symlink case */ + if (unlikely(pstr.name[0] == 0)) { + res = -ENOENT; + goto errout; + } + paddr = pstr.name; /* Null-terminate the name */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 6134832ba..013a62b2f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -926,9 +926,25 @@ static loff_t max_file_blocks(void) return result; } +static int __f2fs_commit_super(struct buffer_head *bh, + struct f2fs_super_block *super) +{ + lock_buffer(bh); + if (super) + memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); + set_buffer_uptodate(bh); + set_buffer_dirty(bh); + unlock_buffer(bh); + + /* it's rare case, we can do fua all the time */ + return __sync_dirty_buffer(bh, WRITE_FLUSH_FUA); +} + static inline bool sanity_check_area_boundary(struct super_block *sb, - struct f2fs_super_block *raw_super) + struct buffer_head *bh) { + struct f2fs_super_block *raw_super = (struct f2fs_super_block *) + (bh->b_data + F2FS_SUPER_OFFSET); u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr); u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr); u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr); @@ -942,6 +958,10 @@ static inline bool sanity_check_area_boundary(struct super_block *sb, u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main); u32 segment_count = le32_to_cpu(raw_super->segment_count); u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg); + u64 main_end_blkaddr = main_blkaddr + + (segment_count_main << log_blocks_per_seg); + u64 seg_end_blkaddr = segment0_blkaddr + + (segment_count << log_blocks_per_seg); if (segment0_blkaddr != cp_blkaddr) { f2fs_msg(sb, KERN_INFO, @@ -986,22 +1006,45 @@ static inline bool sanity_check_area_boundary(struct super_block *sb, return true; } - if (main_blkaddr + (segment_count_main << log_blocks_per_seg) != - segment0_blkaddr + (segment_count << log_blocks_per_seg)) { + if (main_end_blkaddr > seg_end_blkaddr) { f2fs_msg(sb, KERN_INFO, - "Wrong MAIN_AREA boundary, start(%u) end(%u) blocks(%u)", + "Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)", main_blkaddr, - segment0_blkaddr + (segment_count << log_blocks_per_seg), + segment0_blkaddr + + (segment_count << log_blocks_per_seg), segment_count_main << log_blocks_per_seg); return true; + } else if (main_end_blkaddr < seg_end_blkaddr) { + int err = 0; + char *res; + + /* fix in-memory information all the time */ + raw_super->segment_count = cpu_to_le32((main_end_blkaddr - + segment0_blkaddr) >> log_blocks_per_seg); + + if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) { + res = "internally"; + } else { + err = __f2fs_commit_super(bh, NULL); + res = err ? "failed" : "done"; + } + f2fs_msg(sb, KERN_INFO, + "Fix alignment : %s, start(%u) end(%u) block(%u)", + res, main_blkaddr, + segment0_blkaddr + + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + if (err) + return true; } - return false; } static int sanity_check_raw_super(struct super_block *sb, - struct f2fs_super_block *raw_super) + struct buffer_head *bh) { + struct f2fs_super_block *raw_super = (struct f2fs_super_block *) + (bh->b_data + F2FS_SUPER_OFFSET); unsigned int blocksize; if (F2FS_SUPER_MAGIC != le32_to_cpu(raw_super->magic)) { @@ -1068,7 +1111,7 @@ static int sanity_check_raw_super(struct super_block *sb, } /* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */ - if (sanity_check_area_boundary(sb, raw_super)) + if (sanity_check_area_boundary(sb, bh)) return 1; return 0; @@ -1134,103 +1177,87 @@ static void init_sb_info(struct f2fs_sb_info *sbi) /* * Read f2fs raw super block. - * Because we have two copies of super block, so read the first one at first, - * if the first one is invalid, move to read the second one. + * Because we have two copies of super block, so read both of them + * to get the first valid one. If any one of them is broken, we pass + * them recovery flag back to the caller. */ static int read_raw_super_block(struct super_block *sb, struct f2fs_super_block **raw_super, int *valid_super_block, int *recovery) { - int block = 0; + int block; struct buffer_head *bh; - struct f2fs_super_block *super, *buf; + struct f2fs_super_block *super; int err = 0; super = kzalloc(sizeof(struct f2fs_super_block), GFP_KERNEL); if (!super) return -ENOMEM; -retry: - bh = sb_bread(sb, block); - if (!bh) { - *recovery = 1; - f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", + + for (block = 0; block < 2; block++) { + bh = sb_bread(sb, block); + if (!bh) { + f2fs_msg(sb, KERN_ERR, "Unable to read %dth superblock", block + 1); - err = -EIO; - goto next; - } + err = -EIO; + continue; + } - buf = (struct f2fs_super_block *)(bh->b_data + F2FS_SUPER_OFFSET); + /* sanity checking of raw super */ + if (sanity_check_raw_super(sb, bh)) { + f2fs_msg(sb, KERN_ERR, + "Can't find valid F2FS filesystem in %dth superblock", + block + 1); + err = -EINVAL; + brelse(bh); + continue; + } - /* sanity checking of raw super */ - if (sanity_check_raw_super(sb, buf)) { + if (!*raw_super) { + memcpy(super, bh->b_data + F2FS_SUPER_OFFSET, + sizeof(*super)); + *valid_super_block = block; + *raw_super = super; + } brelse(bh); - *recovery = 1; - f2fs_msg(sb, KERN_ERR, - "Can't find valid F2FS filesystem in %dth superblock", - block + 1); - err = -EINVAL; - goto next; } - if (!*raw_super) { - memcpy(super, buf, sizeof(*super)); - *valid_super_block = block; - *raw_super = super; - } - brelse(bh); - -next: - /* check the validity of the second superblock */ - if (block == 0) { - block++; - goto retry; - } + /* Fail to read any one of the superblocks*/ + if (err < 0) + *recovery = 1; /* No valid superblock */ - if (!*raw_super) { + if (!*raw_super) kfree(super); - return err; - } + else + err = 0; - return 0; + return err; } -static int __f2fs_commit_super(struct f2fs_sb_info *sbi, int block) +int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) { - struct f2fs_super_block *super = F2FS_RAW_SUPER(sbi); struct buffer_head *bh; int err; - bh = sb_getblk(sbi->sb, block); + /* write back-up superblock first */ + bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1); if (!bh) return -EIO; - - lock_buffer(bh); - memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); - set_buffer_uptodate(bh); - set_buffer_dirty(bh); - unlock_buffer(bh); - - /* it's rare case, we can do fua all the time */ - err = __sync_dirty_buffer(bh, WRITE_FLUSH_FUA); + err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); brelse(bh); - return err; -} - -int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) -{ - int err; - - /* write back-up superblock first */ - err = __f2fs_commit_super(sbi, sbi->valid_super_block ? 0 : 1); - /* if we are in recovery path, skip writing valid superblock */ if (recover || err) return err; /* write current valid superblock */ - return __f2fs_commit_super(sbi, sbi->valid_super_block); + bh = sb_getblk(sbi->sb, sbi->valid_super_block); + if (!bh) + return -EIO; + err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); + brelse(bh); + return err; } static int f2fs_fill_super(struct super_block *sb, void *data, int silent) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index d4403544a..6c4f2fb26 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1507,6 +1507,32 @@ static struct page *can_gather_numa_stats(pte_t pte, struct vm_area_struct *vma, return page; } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +static struct page *can_gather_numa_stats_pmd(pmd_t pmd, + struct vm_area_struct *vma, + unsigned long addr) +{ + struct page *page; + int nid; + + if (!pmd_present(pmd)) + return NULL; + + page = vm_normal_page_pmd(vma, addr, pmd); + if (!page) + return NULL; + + if (PageReserved(page)) + return NULL; + + nid = page_to_nid(page); + if (!node_isset(nid, node_states[N_MEMORY])) + return NULL; + + return page; +} +#endif + static int gather_pte_stats(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { @@ -1516,14 +1542,14 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, pte_t *orig_pte; pte_t *pte; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE ptl = pmd_trans_huge_lock(pmd, vma); if (ptl) { - pte_t huge_pte = *(pte_t *)pmd; struct page *page; - page = can_gather_numa_stats(huge_pte, vma, addr); + page = can_gather_numa_stats_pmd(*pmd, vma, addr); if (page) - gather_stats(page, md, pte_dirty(huge_pte), + gather_stats(page, md, pmd_dirty(*pmd), HPAGE_PMD_SIZE/PAGE_SIZE); spin_unlock(ptl); return 0; @@ -1531,6 +1557,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, if (pmd_trans_unstable(pmd)) return 0; +#endif orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); do { struct page *page = can_gather_numa_stats(*pte, vma, addr); |