Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 19:49:17 +0000 (12:49 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 19:49:17 +0000 (12:49 -0700)
Pull ext4 updates from Ted Ts'o:
 "A lot of cleanups and bug fixes, especially dealing with corrupted
  file systems"

* tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (23 commits)
  ext4: fix fencepost error in check for inode count overflow during resize
  ext4: correctly handle a zero-length xattr with a non-zero e_value_offs
  ext4: bubble errors from ext4_find_inline_data_nolock() up to ext4_iget()
  ext4: do not allow external inodes for inline data
  ext4: report delalloc reserve as non-free in statfs for project quota
  ext4: remove NULL check before calling kmem_cache_destroy()
  jbd2: remove NULL check before calling kmem_cache_destroy()
  jbd2: remove bunch of empty lines with jbd2 debug
  ext4: handle errors on ext4_commit_super
  ext4: do not update s_last_mounted of a frozen fs
  ext4: factor out helper ext4_sample_last_mounted()
  vfs: add the sb_start_intwrite_trylock() helper
  ext4: update mtime in ext4_punch_hole even if no blocks are released
  ext4: add verifier check for symlink with append/immutable flags
  fs: ext4: add new return type vm_fault_t
  ext4: fix hole length detection in ext4_ind_map_blocks()
  ext4: mark block bitmap corrupted when found
  ext4: mark inode bitmap corrupted when found
  ext4: add new ext4_mark_group_bitmap_corrupted() helper
  ext4: fix wrong return value in ext4_read_inode_bitmap()
  ...

1  2 
fs/ext4/ext4.h
fs/ext4/mballoc.c
include/linux/fs.h

diff --combined fs/ext4/ext4.h
@@@ -2390,7 -2390,7 +2390,7 @@@ extern int ext4_init_inode_table(struc
  extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
  
  /* mballoc.c */
 -extern const struct file_operations ext4_seq_mb_groups_fops;
 +extern const struct seq_operations ext4_mb_seq_groups_ops;
  extern long ext4_mb_stats;
  extern long ext4_mb_max_to_scan;
  extern int ext4_mb_init(struct super_block *);
@@@ -2530,6 -2530,9 +2530,9 @@@ extern int ext4_alloc_flex_bg_array(str
                                    ext4_group_t ngroup);
  extern const char *ext4_decode_error(struct super_block *sb, int errno,
                                     char nbuf[16]);
+ extern void ext4_mark_group_bitmap_corrupted(struct super_block *sb,
+                                            ext4_group_t block_group,
+                                            unsigned int flags);
  
  extern __printf(4, 5)
  void __ext4_error(struct super_block *, const char *, unsigned int,
@@@ -2857,6 -2860,10 +2860,10 @@@ struct ext4_group_info 
  #define EXT4_GROUP_INFO_WAS_TRIMMED_BIT               1
  #define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT   2
  #define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT   3
+ #define EXT4_GROUP_INFO_BBITMAP_CORRUPT               \
+       (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
+ #define EXT4_GROUP_INFO_IBITMAP_CORRUPT               \
+       (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
  
  #define EXT4_MB_GRP_NEED_INIT(grp)    \
        (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
diff --combined fs/ext4/mballoc.c
@@@ -470,6 -470,8 +470,8 @@@ static void mb_free_blocks_double(struc
                                              "freeing block already freed "
                                              "(bit %u)",
                                              first + i);
+                       ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group,
+                                       EXT4_GROUP_INFO_BBITMAP_CORRUPT);
                }
                mb_clear_bit(first + i, e4b->bd_info->bb_bitmap);
        }
@@@ -747,10 -749,8 +749,8 @@@ void ext4_mb_generate_buddy(struct supe
                 * corrupt and update bb_free using bitmap value
                 */
                grp->bb_free = free;
-               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
-                       percpu_counter_sub(&sbi->s_freeclusters_counter,
-                                          grp->bb_free);
-               set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
+               ext4_mark_group_bitmap_corrupted(sb, group,
+                                       EXT4_GROUP_INFO_BBITMAP_CORRUPT);
        }
        mb_set_largest_free_order(sb, grp);
  
@@@ -1454,12 -1454,8 +1454,8 @@@ static void mb_free_blocks(struct inod
                                      "freeing already freed block "
                                      "(bit %u); block bitmap corrupt.",
                                      block);
-               if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))
-                       percpu_counter_sub(&sbi->s_freeclusters_counter,
-                                          e4b->bd_info->bb_free);
-               /* Mark the block group as corrupt. */
-               set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
-                       &e4b->bd_info->bb_state);
+               ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group,
+                               EXT4_GROUP_INFO_BBITMAP_CORRUPT);
                mb_regenerate_buddy(e4b);
                goto done;
        }
@@@ -1956,6 -1952,8 +1952,8 @@@ void ext4_mb_complex_scan_group(struct 
                                        "%d free clusters as per "
                                        "group info. But bitmap says 0",
                                        free);
+                       ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group,
+                                       EXT4_GROUP_INFO_BBITMAP_CORRUPT);
                        break;
                }
  
                                        "%d free clusters as per "
                                        "group info. But got %d blocks",
                                        free, ex.fe_len);
+                       ext4_mark_group_bitmap_corrupted(sb, e4b->bd_group,
+                                       EXT4_GROUP_INFO_BBITMAP_CORRUPT);
                        /*
                         * The number of free blocks differs. This mostly
                         * indicate that the bitmap is corrupt. So exit
@@@ -2254,7 -2254,7 +2254,7 @@@ out
  
  static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
  {
 -      struct super_block *sb = seq->private;
 +      struct super_block *sb = PDE_DATA(file_inode(seq->file));
        ext4_group_t group;
  
        if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
  
  static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
  {
 -      struct super_block *sb = seq->private;
 +      struct super_block *sb = PDE_DATA(file_inode(seq->file));
        ext4_group_t group;
  
        ++*pos;
  
  static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v)
  {
 -      struct super_block *sb = seq->private;
 +      struct super_block *sb = PDE_DATA(file_inode(seq->file));
        ext4_group_t group = (ext4_group_t) ((unsigned long) v);
        int i;
        int err, buddy_loaded = 0;
@@@ -2330,13 -2330,34 +2330,13 @@@ static void ext4_mb_seq_groups_stop(str
  {
  }
  
 -static const struct seq_operations ext4_mb_seq_groups_ops = {
 +const struct seq_operations ext4_mb_seq_groups_ops = {
        .start  = ext4_mb_seq_groups_start,
        .next   = ext4_mb_seq_groups_next,
        .stop   = ext4_mb_seq_groups_stop,
        .show   = ext4_mb_seq_groups_show,
  };
  
 -static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file)
 -{
 -      struct super_block *sb = PDE_DATA(inode);
 -      int rc;
 -
 -      rc = seq_open(file, &ext4_mb_seq_groups_ops);
 -      if (rc == 0) {
 -              struct seq_file *m = file->private_data;
 -              m->private = sb;
 -      }
 -      return rc;
 -
 -}
 -
 -const struct file_operations ext4_seq_mb_groups_fops = {
 -      .open           = ext4_mb_seq_groups_open,
 -      .read           = seq_read,
 -      .llseek         = seq_lseek,
 -      .release        = seq_release,
 -};
 -
  static struct kmem_cache *get_groupinfo_cache(int blocksize_bits)
  {
        int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE;
@@@ -2516,8 -2537,7 +2516,7 @@@ static void ext4_groupinfo_destroy_slab
        int i;
  
        for (i = 0; i < NR_GRPINFO_CACHES; i++) {
-               if (ext4_groupinfo_caches[i])
-                       kmem_cache_destroy(ext4_groupinfo_caches[i]);
+               kmem_cache_destroy(ext4_groupinfo_caches[i]);
                ext4_groupinfo_caches[i] = NULL;
        }
  }
diff --combined include/linux/fs.h
@@@ -94,7 -94,7 +94,7 @@@ typedef int (dio_iodone_t)(struct kioc
  
  /*
   * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
 - * to O_WRONLY and O_RDWR via the strange trick in __dentry_open()
 + * to O_WRONLY and O_RDWR via the strange trick in do_dentry_open()
   */
  
  /* file is open for reading */
@@@ -1250,7 -1250,7 +1250,7 @@@ static inline int locks_lock_file_wait(
  }
  
  struct fasync_struct {
 -      spinlock_t              fa_lock;
 +      rwlock_t                fa_lock;
        int                     magic;
        int                     fa_fd;
        struct fasync_struct    *fa_next; /* singly linked list */
@@@ -1597,6 -1597,11 +1597,11 @@@ static inline void sb_start_intwrite(st
        __sb_start_write(sb, SB_FREEZE_FS, true);
  }
  
+ static inline int sb_start_intwrite_trylock(struct super_block *sb)
+ {
+       return __sb_start_write(sb, SB_FREEZE_FS, false);
+ }
  
  extern bool inode_owner_or_capable(const struct inode *inode);
  
@@@ -1711,8 -1716,6 +1716,8 @@@ struct file_operations 
        int (*iterate) (struct file *, struct dir_context *);
        int (*iterate_shared) (struct file *, struct dir_context *);
        __poll_t (*poll) (struct file *, struct poll_table_struct *);
 +      struct wait_queue_head * (*get_poll_head)(struct file *, __poll_t);
 +      __poll_t (*poll_mask) (struct file *, __poll_t);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
@@@ -2572,7 -2575,7 +2577,7 @@@ extern bool is_bad_inode(struct inode *
  
  #ifdef CONFIG_BLOCK
  extern void check_disk_size_change(struct gendisk *disk,
 -                                 struct block_device *bdev);
 +              struct block_device *bdev, bool verbose);
  extern int revalidate_disk(struct gendisk *);
  extern int check_disk_change(struct block_device *);
  extern int __invalidate_device(struct block_device *, bool);