]> Git Repo - linux.git/commitdiff
Merge tag 'ext4_for_linus-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Thu, 2 Nov 2023 17:45:14 +0000 (07:45 -1000)
committerLinus Torvalds <[email protected]>
Thu, 2 Nov 2023 17:45:14 +0000 (07:45 -1000)
Pull ext4 updates from Ted Ts'o:
 "Cleanup ext4's multi-block allocator, including adding some unit
  tests, as well as cleaning how we update the backup superblock after
  online resizes or updating the label or uuid.

  Optimize handling of released data blocks in ext4's commit machinery
  to avoid a potential lock contention on s_md_lock spinlock.

  Fix a number of ext4 bugs:

   - fix race between writepages and remount

   - fix racy may inline data check in dio write

   - add missed brelse in an error path in update_backups

   - fix umask handling when ACL support is disabled

   - fix lost EIO error when a journal commit races with a fsync of the
     blockdev

   - fix potential improper i_size when there is a crash right after an
     O_SYNC direct write.

   - check extent node for validity before potentially using what might
     be an invalid pointer

   - fix potential stale data exposure when writing to an unwritten
     extent and the file system is nearly out of space

   - fix potential accounting error around block reservations when
     writing partial delayed allocation writes to a bigalloc cluster

   - avoid memory allocation failure when tracking partial delayed
     allocation writes to a bigalloc cluster

   - fix various debugging print messages"

* tag 'ext4_for_linus-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (41 commits)
  ext4: properly sync file size update after O_SYNC direct IO
  ext4: fix racy may inline data check in dio write
  ext4: run mballoc test with different layouts setting
  ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc
  ext4: add some kunit stub for mballoc kunit test
  ext4: call ext4_mb_mark_context in ext4_group_add_blocks()
  ext4: Separate block bitmap and buddy bitmap freeing in ext4_group_add_blocks()
  ext4: call ext4_mb_mark_context in ext4_mb_clear_bb
  ext4: Separate block bitmap and buddy bitmap freeing in ext4_mb_clear_bb()
  ext4: call ext4_mb_mark_context in ext4_mb_mark_diskspace_used
  ext4: extend ext4_mb_mark_context to support allocation under journal
  ext4: call ext4_mb_mark_context in ext4_free_blocks_simple
  ext4: factor out codes to update block bitmap and group descriptor on disk from ext4_mb_mark_bb
  ext4: make state in ext4_mb_mark_bb to be bool
  jbd2: fix potential data lost in recovering journal raced with synchronizing fs bdev
  ext4: apply umask if ACL support is disabled
  ext4: mark buffer new if it is unwritten to avoid stale data exposure
  ext4: move 'ix' sanity check to corrent position
  jbd2: fix printk format type for 'io_block' in do_one_pass()
  jbd2: print io_block if check data block checksum failed when do recovery
  ...

1  2 
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/inode.c
fs/ext4/namei.c
fs/ext4/super.c

diff --combined fs/ext4/ext4.h
index 8da5fb680210417da2c42d0368d57610104833e3,8ccebe0d4fbc9fb321765390e0b2358c1d027f4a..f16aa375c02ba8d4d99e450af5378d3c5605f966
@@@ -891,13 -891,10 +891,13 @@@ do {                                                                            
                (raw_inode)->xtime = cpu_to_le32(clamp_t(int32_t, (ts).tv_sec, S32_MIN, S32_MAX));      \
  } while (0)
  
 -#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)                         \
 -      EXT4_INODE_SET_XTIME_VAL(xtime, inode, raw_inode, (inode)->xtime)
 +#define EXT4_INODE_SET_ATIME(inode, raw_inode)                                                \
 +      EXT4_INODE_SET_XTIME_VAL(i_atime, inode, raw_inode, inode_get_atime(inode))
  
 -#define EXT4_INODE_SET_CTIME(inode, raw_inode)                                        \
 +#define EXT4_INODE_SET_MTIME(inode, raw_inode)                                                \
 +      EXT4_INODE_SET_XTIME_VAL(i_mtime, inode, raw_inode, inode_get_mtime(inode))
 +
 +#define EXT4_INODE_SET_CTIME(inode, raw_inode)                                                \
        EXT4_INODE_SET_XTIME_VAL(i_ctime, inode, raw_inode, inode_get_ctime(inode))
  
  #define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)                               \
                        .tv_sec = (signed)le32_to_cpu((raw_inode)->xtime)       \
                })
  
 -#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)                         \
 +#define EXT4_INODE_GET_ATIME(inode, raw_inode)                                        \
 +do {                                                                          \
 +      inode_set_atime_to_ts(inode,                                            \
 +              EXT4_INODE_GET_XTIME_VAL(i_atime, inode, raw_inode));           \
 +} while (0)
 +
 +#define EXT4_INODE_GET_MTIME(inode, raw_inode)                                        \
  do {                                                                          \
 -      (inode)->xtime = EXT4_INODE_GET_XTIME_VAL(xtime, inode, raw_inode);     \
 +      inode_set_mtime_to_ts(inode,                                            \
 +              EXT4_INODE_GET_XTIME_VAL(i_mtime, inode, raw_inode));           \
  } while (0)
  
  #define EXT4_INODE_GET_CTIME(inode, raw_inode)                                        \
@@@ -1504,6 -1494,7 +1504,7 @@@ struct ext4_sb_info 
        loff_t s_bitmap_maxbytes;       /* max bytes for bitmap files */
        struct buffer_head * s_sbh;     /* Buffer containing the super block */
        struct ext4_super_block *s_es;  /* Pointer to the super block in the buffer */
+       /* Array of bh's for the block group descriptors */
        struct buffer_head * __rcu *s_group_desc;
        unsigned int s_mount_opt;
        unsigned int s_mount_opt2;
        unsigned long s_commit_interval;
        u32 s_max_batch_time;
        u32 s_min_batch_time;
 -      struct block_device *s_journal_bdev;
 +      struct bdev_handle *s_journal_bdev_handle;
  #ifdef CONFIG_QUOTA
        /* Names of quota files with journalled quota */
        char __rcu *s_qf_names[EXT4_MAXQUOTAS];
        unsigned int *s_mb_maxs;
        unsigned int s_group_info_size;
        unsigned int s_mb_free_pending;
-       struct list_head s_freed_data_list;     /* List of blocks to be freed
+       struct list_head s_freed_data_list[2];  /* List of blocks to be freed
                                                   after commit completed */
        struct list_head s_discard_list;
        struct work_struct s_discard_work;
  
        /*
         * Barrier between writepages ops and changing any inode's JOURNAL_DATA
-        * or EXTENTS flag.
+        * or EXTENTS flag or between writepages ops and changing DELALLOC or
+        * DIOREAD_NOLOCK mount options on remount.
         */
        struct percpu_rw_semaphore s_writepages_rwsem;
        struct dax_device *s_daxdev;
@@@ -2934,7 -2926,7 +2936,7 @@@ extern int ext4_group_add_blocks(handle
  extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
  extern void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid);
  extern void ext4_mb_mark_bb(struct super_block *sb, ext4_fsblk_t block,
-                      int len, int state);
+                           int len, bool state);
  static inline bool ext4_mb_cr_expensive(enum criteria cr)
  {
        return cr >= CR_GOAL_LEN_SLOW;
diff --combined fs/ext4/extents.c
index 4c4176ee174930712d488164800e79fa590515fa,880f383df684bbce063ebbf04c9073eaacdf8b1a..d5efe076d3d3fbb36a6d4ef5c3ea2e1f904c8366
@@@ -1010,6 -1010,11 +1010,11 @@@ static int ext4_ext_insert_index(handle
                ix = curp->p_idx;
        }
  
+       if (unlikely(ix > EXT_MAX_INDEX(curp->p_hdr))) {
+               EXT4_ERROR_INODE(inode, "ix > EXT_MAX_INDEX!");
+               return -EFSCORRUPTED;
+       }
        len = EXT_LAST_INDEX(curp->p_hdr) - ix + 1;
        BUG_ON(len < 0);
        if (len > 0) {
                memmove(ix + 1, ix, len * sizeof(struct ext4_extent_idx));
        }
  
-       if (unlikely(ix > EXT_MAX_INDEX(curp->p_hdr))) {
-               EXT4_ERROR_INODE(inode, "ix > EXT_MAX_INDEX!");
-               return -EFSCORRUPTED;
-       }
        ix->ei_block = cpu_to_le32(logical);
        ext4_idx_store_pblock(ix, ptr);
        le16_add_cpu(&curp->p_hdr->eh_entries, 1);
@@@ -4481,8 -4481,7 +4481,8 @@@ retry
                        if (epos > new_size)
                                epos = new_size;
                        if (ext4_update_inode_size(inode, epos) & 0x1)
 -                              inode->i_mtime = inode_get_ctime(inode);
 +                              inode_set_mtime_to_ts(inode,
 +                                                    inode_get_ctime(inode));
                }
                ret2 = ext4_mark_inode_dirty(handle, inode);
                ext4_update_inode_fsync_trans(handle, inode, 1);
@@@ -4618,7 -4617,7 +4618,7 @@@ static long ext4_zero_range(struct fil
  
                /* Now release the pages and zero block aligned part of pages */
                truncate_pagecache_range(inode, start, end - 1);
 -              inode->i_mtime = inode_set_ctime_current(inode);
 +              inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
  
                ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size,
                                             flags);
                goto out_mutex;
        }
  
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        if (new_size)
                ext4_update_inode_size(inode, new_size);
        ret = ext4_mark_inode_dirty(handle, inode);
@@@ -5379,7 -5378,7 +5379,7 @@@ static int ext4_collapse_range(struct f
        up_write(&EXT4_I(inode)->i_data_sem);
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        ret = ext4_mark_inode_dirty(handle, inode);
        ext4_update_inode_fsync_trans(handle, inode, 1);
  
@@@ -5489,7 -5488,7 +5489,7 @@@ static int ext4_insert_range(struct fil
        /* Expand file to avoid data loss if there is error while shifting */
        inode->i_size += len;
        EXT4_I(inode)->i_disksize += len;
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        ret = ext4_mark_inode_dirty(handle, inode);
        if (ret)
                goto out_stop;
@@@ -6081,13 -6080,13 +6081,13 @@@ int ext4_ext_clear_bb(struct inode *ino
                                for (j = 0; j < path->p_depth; j++) {
  
                                        ext4_mb_mark_bb(inode->i_sb,
-                                                       path[j].p_block, 1, 0);
+                                                       path[j].p_block, 1, false);
                                        ext4_fc_record_regions(inode->i_sb, inode->i_ino,
                                                        0, path[j].p_block, 1, 1);
                                }
                                ext4_free_ext_path(path);
                        }
-                       ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, 0);
+                       ext4_mb_mark_bb(inode->i_sb, map.m_pblk, map.m_len, false);
                        ext4_fc_record_regions(inode->i_sb, inode->i_ino,
                                        map.m_lblk, map.m_pblk, map.m_len, 1);
                }
diff --combined fs/ext4/inode.c
index 08cb5c0e0d516b74b0bd448b4d2e00e3fa01cd58,d7732320431ac780879a86f74ce87e947c26c3a4..a6838f54ae91698b7fce3e6ecf948a299097f66b
@@@ -789,10 -789,22 +789,22 @@@ int ext4_get_block(struct inode *inode
  int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
                             struct buffer_head *bh_result, int create)
  {
+       int ret = 0;
        ext4_debug("ext4_get_block_unwritten: inode %lu, create flag %d\n",
                   inode->i_ino, create);
-       return _ext4_get_block(inode, iblock, bh_result,
+       ret = _ext4_get_block(inode, iblock, bh_result,
                               EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT);
+       /*
+        * If the buffer is marked unwritten, mark it as new to make sure it is
+        * zeroed out correctly in case of partial writes. Otherwise, there is
+        * a chance of stale data getting exposed.
+        */
+       if (ret == 0 && buffer_unwritten(bh_result))
+               set_buffer_new(bh_result);
+       return ret;
  }
  
  /* Maximum number of blocks we map for direct IO at once. */
@@@ -4020,7 -4032,7 +4032,7 @@@ int ext4_punch_hole(struct file *file, 
        if (IS_SYNC(inode))
                ext4_handle_sync(handle);
  
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        ret2 = ext4_mark_inode_dirty(handle, inode);
        if (unlikely(ret2))
                ret = ret2;
@@@ -4180,7 -4192,7 +4192,7 @@@ out_stop
        if (inode->i_nlink)
                ext4_orphan_del(handle, inode);
  
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        err2 = ext4_mark_inode_dirty(handle, inode);
        if (unlikely(err2 && !err))
                err = err2;
@@@ -4284,8 -4296,8 +4296,8 @@@ static int ext4_fill_raw_inode(struct i
        raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
  
        EXT4_INODE_SET_CTIME(inode, raw_inode);
 -      EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
 -      EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
 +      EXT4_INODE_SET_MTIME(inode, raw_inode);
 +      EXT4_INODE_SET_ATIME(inode, raw_inode);
        EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
  
        raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
@@@ -4893,8 -4905,8 +4905,8 @@@ struct inode *__ext4_iget(struct super_
        }
  
        EXT4_INODE_GET_CTIME(inode, raw_inode);
 -      EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
 -      EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
 +      EXT4_INODE_GET_ATIME(inode, raw_inode);
 +      EXT4_INODE_GET_MTIME(inode, raw_inode);
        EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
  
        if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) {
@@@ -5019,8 -5031,8 +5031,8 @@@ static void __ext4_update_other_inode_t
  
                spin_lock(&ei->i_raw_lock);
                EXT4_INODE_SET_CTIME(inode, raw_inode);
 -              EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
 -              EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
 +              EXT4_INODE_SET_MTIME(inode, raw_inode);
 +              EXT4_INODE_SET_ATIME(inode, raw_inode);
                ext4_inode_csum_set(inode, raw_inode, ei);
                spin_unlock(&ei->i_raw_lock);
                trace_ext4_other_inode_update_time(inode, orig_ino);
@@@ -5413,8 -5425,7 +5425,8 @@@ int ext4_setattr(struct mnt_idmap *idma
                         * update c/mtime in shrink case below
                         */
                        if (!shrink)
 -                              inode->i_mtime = inode_set_ctime_current(inode);
 +                              inode_set_mtime_to_ts(inode,
 +                                                    inode_set_ctime_current(inode));
  
                        if (shrink)
                                ext4_fc_track_range(handle, inode,
diff --combined fs/ext4/namei.c
index 057d744672935f3eed3a1115bbf81a8e020050a0,cbe756144d8df9203eeb45b960a53c7b53311595..d252935f9c8abbf72217451398287919b69d4c09
@@@ -2207,7 -2207,7 +2207,7 @@@ static int add_dirent_to_buf(handle_t *
         * happen is that the times are slightly out of date
         * and/or different from the directory change time.
         */
 -      dir->i_mtime = inode_set_ctime_current(dir);
 +      inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
        ext4_update_dx_flag(dir);
        inode_inc_iversion(dir);
        err2 = ext4_mark_inode_dirty(handle, dir);
@@@ -2280,8 -2280,7 +2280,7 @@@ static int make_indexed_dir(handle_t *h
        top = data2 + len;
        while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) {
                if (ext4_check_dir_entry(dir, NULL, de, bh2, data2, len,
-                                        (data2 + (blocksize - csum_size) -
-                                         (char *) de))) {
+                                       (char *)de - data2)) {
                        brelse(bh2);
                        brelse(bh);
                        return -EFSCORRUPTED;
@@@ -3202,7 -3201,7 +3201,7 @@@ static int ext4_rmdir(struct inode *dir
         * recovery. */
        inode->i_size = 0;
        ext4_orphan_add(handle, inode);
 -      dir->i_mtime = inode_set_ctime_current(dir);
 +      inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
        inode_set_ctime_current(inode);
        retval = ext4_mark_inode_dirty(handle, inode);
        if (retval)
@@@ -3277,7 -3276,7 +3276,7 @@@ int __ext4_unlink(struct inode *dir, co
                retval = ext4_delete_entry(handle, dir, de, bh);
                if (retval)
                        goto out_handle;
 -              dir->i_mtime = inode_set_ctime_current(dir);
 +              inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
                ext4_update_dx_flag(dir);
                retval = ext4_mark_inode_dirty(handle, dir);
                if (retval)
@@@ -3648,7 -3647,7 +3647,7 @@@ static int ext4_setent(handle_t *handle
        if (ext4_has_feature_filetype(ent->dir->i_sb))
                ent->de->file_type = file_type;
        inode_inc_iversion(ent->dir);
 -      ent->dir->i_mtime = inode_set_ctime_current(ent->dir);
 +      inode_set_mtime_to_ts(ent->dir, inode_set_ctime_current(ent->dir));
        retval = ext4_mark_inode_dirty(handle, ent->dir);
        BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata");
        if (!ent->inlined) {
@@@ -3963,7 -3962,7 +3962,7 @@@ static int ext4_rename(struct mnt_idma
                ext4_dec_count(new.inode);
                inode_set_ctime_current(new.inode);
        }
 -      old.dir->i_mtime = inode_set_ctime_current(old.dir);
 +      inode_set_mtime_to_ts(old.dir, inode_set_ctime_current(old.dir));
        ext4_update_dx_flag(old.dir);
        if (old.dir_bh) {
                retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino);
diff --combined fs/ext4/super.c
index 42a44990d99c7e96a104dbebfe7cee578129add8,d062383ea50ef4f8a4962bc139d0337d76d9c4b3..77e2b694c7d5d14a1451795ad2ae5677884b7323
@@@ -768,7 -768,8 +768,8 @@@ static void update_super_work(struct wo
         */
        if (!sb_rdonly(sbi->s_sb) && journal) {
                struct buffer_head *sbh = sbi->s_sbh;
-               bool call_notify_err;
+               bool call_notify_err = false;
                handle = jbd2_journal_start(journal, 1);
                if (IS_ERR(handle))
                        goto write_directly;
@@@ -1351,14 -1352,14 +1352,14 @@@ static void ext4_put_super(struct super
  
        sync_blockdev(sb->s_bdev);
        invalidate_bdev(sb->s_bdev);
 -      if (sbi->s_journal_bdev) {
 +      if (sbi->s_journal_bdev_handle) {
                /*
                 * Invalidate the journal device's buffers.  We don't want them
                 * floating about in memory - the physical journal device may
                 * hotswapped, and it breaks the `ro-after' testing code.
                 */
 -              sync_blockdev(sbi->s_journal_bdev);
 -              invalidate_bdev(sbi->s_journal_bdev);
 +              sync_blockdev(sbi->s_journal_bdev_handle->bdev);
 +              invalidate_bdev(sbi->s_journal_bdev_handle->bdev);
        }
  
        ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
@@@ -4233,7 -4234,7 +4234,7 @@@ int ext4_calculate_overhead(struct supe
         * Add the internal journal blocks whether the journal has been
         * loaded or not
         */
 -      if (sbi->s_journal && !sbi->s_journal_bdev)
 +      if (sbi->s_journal && !sbi->s_journal_bdev_handle)
                overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_total_len);
        else if (ext4_has_feature_journal(sb) && !sbi->s_journal && j_inum) {
                /* j_inum for internal journal is non-zero */
@@@ -5670,9 -5671,9 +5671,9 @@@ failed_mount
  #endif
        fscrypt_free_dummy_policy(&sbi->s_dummy_enc_policy);
        brelse(sbi->s_sbh);
 -      if (sbi->s_journal_bdev) {
 -              invalidate_bdev(sbi->s_journal_bdev);
 -              blkdev_put(sbi->s_journal_bdev, sb);
 +      if (sbi->s_journal_bdev_handle) {
 +              invalidate_bdev(sbi->s_journal_bdev_handle->bdev);
 +              bdev_release(sbi->s_journal_bdev_handle);
        }
  out_fail:
        invalidate_bdev(sb->s_bdev);
@@@ -5842,13 -5843,12 +5843,13 @@@ static journal_t *ext4_open_inode_journ
        return journal;
  }
  
 -static struct block_device *ext4_get_journal_blkdev(struct super_block *sb,
 +static struct bdev_handle *ext4_get_journal_blkdev(struct super_block *sb,
                                        dev_t j_dev, ext4_fsblk_t *j_start,
                                        ext4_fsblk_t *j_len)
  {
        struct buffer_head *bh;
        struct block_device *bdev;
 +      struct bdev_handle *bdev_handle;
        int hblock, blocksize;
        ext4_fsblk_t sb_block;
        unsigned long offset;
  
        /* see get_tree_bdev why this is needed and safe */
        up_write(&sb->s_umount);
 -      bdev = blkdev_get_by_dev(j_dev, BLK_OPEN_READ | BLK_OPEN_WRITE, sb,
 -                               &fs_holder_ops);
 +      bdev_handle = bdev_open_by_dev(j_dev, BLK_OPEN_READ | BLK_OPEN_WRITE,
 +                                     sb, &fs_holder_ops);
        down_write(&sb->s_umount);
 -      if (IS_ERR(bdev)) {
 +      if (IS_ERR(bdev_handle)) {
                ext4_msg(sb, KERN_ERR,
                         "failed to open journal device unknown-block(%u,%u) %ld",
 -                       MAJOR(j_dev), MINOR(j_dev), PTR_ERR(bdev));
 -              return ERR_CAST(bdev);
 +                       MAJOR(j_dev), MINOR(j_dev), PTR_ERR(bdev_handle));
 +              return bdev_handle;
        }
  
 +      bdev = bdev_handle->bdev;
        blocksize = sb->s_blocksize;
        hblock = bdev_logical_block_size(bdev);
        if (blocksize < hblock) {
        *j_start = sb_block + 1;
        *j_len = ext4_blocks_count(es);
        brelse(bh);
 -      return bdev;
 +      return bdev_handle;
  
  out_bh:
        brelse(bh);
  out_bdev:
 -      blkdev_put(bdev, sb);
 +      bdev_release(bdev_handle);
        return ERR_PTR(errno);
  }
  
@@@ -5929,14 -5928,14 +5930,14 @@@ static journal_t *ext4_open_dev_journal
        journal_t *journal;
        ext4_fsblk_t j_start;
        ext4_fsblk_t j_len;
 -      struct block_device *journal_bdev;
 +      struct bdev_handle *bdev_handle;
        int errno = 0;
  
 -      journal_bdev = ext4_get_journal_blkdev(sb, j_dev, &j_start, &j_len);
 -      if (IS_ERR(journal_bdev))
 -              return ERR_CAST(journal_bdev);
 +      bdev_handle = ext4_get_journal_blkdev(sb, j_dev, &j_start, &j_len);
 +      if (IS_ERR(bdev_handle))
 +              return ERR_CAST(bdev_handle);
  
 -      journal = jbd2_journal_init_dev(journal_bdev, sb->s_bdev, j_start,
 +      journal = jbd2_journal_init_dev(bdev_handle->bdev, sb->s_bdev, j_start,
                                        j_len, sb->s_blocksize);
        if (IS_ERR(journal)) {
                ext4_msg(sb, KERN_ERR, "failed to create device journal");
                goto out_journal;
        }
        journal->j_private = sb;
 -      EXT4_SB(sb)->s_journal_bdev = journal_bdev;
 +      EXT4_SB(sb)->s_journal_bdev_handle = bdev_handle;
        ext4_init_journal_params(sb, journal);
        return journal;
  
  out_journal:
        jbd2_journal_destroy(journal);
  out_bdev:
 -      blkdev_put(journal_bdev, sb);
 +      bdev_release(bdev_handle);
        return ERR_PTR(errno);
  }
  
@@@ -6444,6 -6443,7 +6445,7 @@@ static int __ext4_remount(struct fs_con
        struct ext4_mount_options old_opts;
        ext4_group_t g;
        int err = 0;
+       int alloc_ctx;
  #ifdef CONFIG_QUOTA
        int enable_quota = 0;
        int i, j;
  
        }
  
+       /*
+        * Changing the DIOREAD_NOLOCK or DELALLOC mount options may cause
+        * two calls to ext4_should_dioread_nolock() to return inconsistent
+        * values, triggering WARN_ON in ext4_add_complete_io(). we grab
+        * here s_writepages_rwsem to avoid race between writepages ops and
+        * remount.
+        */
+       alloc_ctx = ext4_writepages_down_write(sb);
        ext4_apply_options(fc, sb);
+       ext4_writepages_up_write(sb, alloc_ctx);
  
        if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^
            test_opt(sb, JOURNAL_CHECKSUM)) {
@@@ -6702,6 -6711,8 +6713,8 @@@ restore_opts
        if (sb_rdonly(sb) && !(old_sb_flags & SB_RDONLY) &&
            sb_any_quota_suspended(sb))
                dquot_resume(sb, -1);
+       alloc_ctx = ext4_writepages_down_write(sb);
        sb->s_flags = old_sb_flags;
        sbi->s_mount_opt = old_opts.s_mount_opt;
        sbi->s_mount_opt2 = old_opts.s_mount_opt2;
        sbi->s_commit_interval = old_opts.s_commit_interval;
        sbi->s_min_batch_time = old_opts.s_min_batch_time;
        sbi->s_max_batch_time = old_opts.s_max_batch_time;
+       ext4_writepages_up_write(sb, alloc_ctx);
        if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
                ext4_release_system_zone(sb);
  #ifdef CONFIG_QUOTA
@@@ -7129,7 -7142,7 +7144,7 @@@ static int ext4_quota_off(struct super_
        }
        EXT4_I(inode)->i_flags &= ~(EXT4_NOATIME_FL | EXT4_IMMUTABLE_FL);
        inode_set_flags(inode, 0, S_NOATIME | S_IMMUTABLE);
 -      inode->i_mtime = inode_set_ctime_current(inode);
 +      inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        err = ext4_mark_inode_dirty(handle, inode);
        ext4_journal_stop(handle);
  out_unlock:
@@@ -7302,12 -7315,12 +7317,12 @@@ static inline int ext3_feature_set_ok(s
  static void ext4_kill_sb(struct super_block *sb)
  {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 -      struct block_device *journal_bdev = sbi ? sbi->s_journal_bdev : NULL;
 +      struct bdev_handle *handle = sbi ? sbi->s_journal_bdev_handle : NULL;
  
        kill_block_super(sb);
  
 -      if (journal_bdev)
 -              blkdev_put(journal_bdev, sb);
 +      if (handle)
 +              bdev_release(handle);
  }
  
  static struct file_system_type ext4_fs_type = {
This page took 0.11118 seconds and 4 git commands to generate.