ext4: handle transient ENOSPC properly for DAX
authorJan Kara <jack@suse.cz>
Fri, 13 May 2016 04:38:16 +0000 (00:38 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 13 May 2016 04:38:16 +0000 (00:38 -0400)
ext4_dax_get_blocks() was accidentally omitted fixing get blocks
handlers to properly handle transient ENOSPC errors. Fix it now to use
ext4_get_blocks_trans() helper which takes care of these errors.

Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/inode.c

index 4d8ebbe0045674410be430476e811b8fb27545db..32825dee81d43a5d020f9a4dccf4f6dbb6b0ebb8 100644 (file)
@@ -3232,72 +3232,37 @@ static int ext4_releasepage(struct page *page, gfp_t wait)
 int ext4_dax_mmap_get_block(struct inode *inode, sector_t iblock,
                            struct buffer_head *bh_result, int create)
 {
-       int ret, err;
-       int credits;
-       struct ext4_map_blocks map;
-       handle_t *handle = NULL;
-       int flags = 0;
+       int ret;
 
        ext4_debug("ext4_dax_mmap_get_block: inode %lu, create flag %d\n",
                   inode->i_ino, create);
-       map.m_lblk = iblock;
-       map.m_len = bh_result->b_size >> inode->i_blkbits;
-       credits = ext4_chunk_trans_blocks(inode, map.m_len);
-       if (create) {
-               flags |= EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_CREATE_ZERO;
-               handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       return ret;
-               }
-       }
+       if (!create)
+               return _ext4_get_block(inode, iblock, bh_result, 0);
 
-       ret = ext4_map_blocks(handle, inode, &map, flags);
-       if (create) {
-               err = ext4_journal_stop(handle);
-               if (ret >= 0 && err < 0)
-                       ret = err;
-       }
-       if (ret <= 0)
-               goto out;
-       if (map.m_flags & EXT4_MAP_UNWRITTEN) {
-               int err2;
+       ret = ext4_get_block_trans(inode, iblock, bh_result,
+                                  EXT4_GET_BLOCKS_PRE_IO |
+                                  EXT4_GET_BLOCKS_CREATE_ZERO);
+       if (ret < 0)
+               return ret;
 
+       if (buffer_unwritten(bh_result)) {
                /*
                 * We are protected by i_mmap_sem so we know block cannot go
                 * away from under us even though we dropped i_data_sem.
                 * Convert extent to written and write zeros there.
-                *
-                * Note: We may get here even when create == 0.
                 */
-               handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, credits);
-               if (IS_ERR(handle)) {
-                       ret = PTR_ERR(handle);
-                       goto out;
-               }
-
-               err = ext4_map_blocks(handle, inode, &map,
-                     EXT4_GET_BLOCKS_CONVERT | EXT4_GET_BLOCKS_CREATE_ZERO);
-               if (err < 0)
-                       ret = err;
-               err2 = ext4_journal_stop(handle);
-               if (err2 < 0 && ret > 0)
-                       ret = err2;
-       }
-out:
-       WARN_ON_ONCE(ret == 0 && create);
-       if (ret > 0) {
-               map_bh(bh_result, inode->i_sb, map.m_pblk);
-               /*
-                * At least for now we have to clear BH_New so that DAX code
-                * doesn't attempt to zero blocks again in a racy way.
-                */
-               map.m_flags &= ~EXT4_MAP_NEW;
-               ext4_update_bh_state(bh_result, map.m_flags);
-               bh_result->b_size = map.m_len << inode->i_blkbits;
-               ret = 0;
+               ret = ext4_get_block_trans(inode, iblock, bh_result,
+                                          EXT4_GET_BLOCKS_CONVERT |
+                                          EXT4_GET_BLOCKS_CREATE_ZERO);
+               if (ret < 0)
+                       return ret;
        }
-       return ret;
+       /*
+        * At least for now we have to clear BH_New so that DAX code
+        * doesn't attempt to zero blocks again in a racy way.
+        */
+       clear_buffer_new(bh_result);
+       return 0;
 }
 #endif