1f5166768STheodore Ts'o // SPDX-License-Identifier: LGPL-2.1 267cf5b09STao Ma /* 367cf5b09STao Ma * Copyright (c) 2012 Taobao. 467cf5b09STao Ma * Written by Tao Ma <boyu.mt@taobao.com> 567cf5b09STao Ma */ 64bdfc873SMichael Halcrow 77046ae35SAndreas Gruenbacher #include <linux/iomap.h> 84bdfc873SMichael Halcrow #include <linux/fiemap.h> 95a57bca9SZhang Yi #include <linux/namei.h> 10ee73f9a5SJeff Layton #include <linux/iversion.h> 114034247aSNeilBrown #include <linux/sched/mm.h> 124bdfc873SMichael Halcrow 1367cf5b09STao Ma #include "ext4_jbd2.h" 1467cf5b09STao Ma #include "ext4.h" 1567cf5b09STao Ma #include "xattr.h" 16f19d5870STao Ma #include "truncate.h" 1767cf5b09STao Ma 1867cf5b09STao Ma #define EXT4_XATTR_SYSTEM_DATA "data" 1967cf5b09STao Ma #define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS)) 208af0f082STao Ma #define EXT4_INLINE_DOTDOT_OFFSET 2 213c47d541STao Ma #define EXT4_INLINE_DOTDOT_SIZE 4 2267cf5b09STao Ma 23c197855eSStephen Hemminger static int ext4_get_inline_size(struct inode *inode) 2467cf5b09STao Ma { 2567cf5b09STao Ma if (EXT4_I(inode)->i_inline_off) 2667cf5b09STao Ma return EXT4_I(inode)->i_inline_size; 2767cf5b09STao Ma 2867cf5b09STao Ma return 0; 2967cf5b09STao Ma } 3067cf5b09STao Ma 3167cf5b09STao Ma static int get_max_inline_xattr_value_size(struct inode *inode, 3267cf5b09STao Ma struct ext4_iloc *iloc) 3367cf5b09STao Ma { 3467cf5b09STao Ma struct ext4_xattr_ibody_header *header; 3567cf5b09STao Ma struct ext4_xattr_entry *entry; 3667cf5b09STao Ma struct ext4_inode *raw_inode; 372220eaf9STheodore Ts'o void *end; 3867cf5b09STao Ma int free, min_offs; 3967cf5b09STao Ma 40c9fd167dSBaokun Li if (!EXT4_INODE_HAS_XATTR_SPACE(inode)) 41c9fd167dSBaokun Li return 0; 42c9fd167dSBaokun Li 4367cf5b09STao Ma min_offs = EXT4_SB(inode->i_sb)->s_inode_size - 4467cf5b09STao Ma EXT4_GOOD_OLD_INODE_SIZE - 4567cf5b09STao Ma EXT4_I(inode)->i_extra_isize - 4667cf5b09STao Ma sizeof(struct ext4_xattr_ibody_header); 4767cf5b09STao Ma 4867cf5b09STao Ma /* 4967cf5b09STao Ma * We need to subtract another sizeof(__u32) since an in-inode xattr 5067cf5b09STao Ma * needs an empty 4 bytes to indicate the gap between the xattr entry 5167cf5b09STao Ma * and the name/value pair. 5267cf5b09STao Ma */ 5367cf5b09STao Ma if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) 5467cf5b09STao Ma return EXT4_XATTR_SIZE(min_offs - 5567cf5b09STao Ma EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) - 5667cf5b09STao Ma EXT4_XATTR_ROUND - sizeof(__u32)); 5767cf5b09STao Ma 5867cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 5967cf5b09STao Ma header = IHDR(inode, raw_inode); 6067cf5b09STao Ma entry = IFIRST(header); 612220eaf9STheodore Ts'o end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; 6267cf5b09STao Ma 6367cf5b09STao Ma /* Compute min_offs. */ 642220eaf9STheodore Ts'o while (!IS_LAST_ENTRY(entry)) { 652220eaf9STheodore Ts'o void *next = EXT4_XATTR_NEXT(entry); 662220eaf9STheodore Ts'o 672220eaf9STheodore Ts'o if (next >= end) { 682220eaf9STheodore Ts'o EXT4_ERROR_INODE(inode, 692220eaf9STheodore Ts'o "corrupt xattr in inline inode"); 702220eaf9STheodore Ts'o return 0; 712220eaf9STheodore Ts'o } 72e50e5129SAndreas Dilger if (!entry->e_value_inum && entry->e_value_size) { 7367cf5b09STao Ma size_t offs = le16_to_cpu(entry->e_value_offs); 7467cf5b09STao Ma if (offs < min_offs) 7567cf5b09STao Ma min_offs = offs; 7667cf5b09STao Ma } 772220eaf9STheodore Ts'o entry = next; 7867cf5b09STao Ma } 7967cf5b09STao Ma free = min_offs - 8067cf5b09STao Ma ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); 8167cf5b09STao Ma 8267cf5b09STao Ma if (EXT4_I(inode)->i_inline_off) { 8367cf5b09STao Ma entry = (struct ext4_xattr_entry *) 8467cf5b09STao Ma ((void *)raw_inode + EXT4_I(inode)->i_inline_off); 8567cf5b09STao Ma 86c4932dbeSboxi liu free += EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); 8767cf5b09STao Ma goto out; 8867cf5b09STao Ma } 8967cf5b09STao Ma 9067cf5b09STao Ma free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)); 9167cf5b09STao Ma 9267cf5b09STao Ma if (free > EXT4_XATTR_ROUND) 9367cf5b09STao Ma free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND); 9467cf5b09STao Ma else 9567cf5b09STao Ma free = 0; 9667cf5b09STao Ma 9767cf5b09STao Ma out: 9867cf5b09STao Ma return free; 9967cf5b09STao Ma } 10067cf5b09STao Ma 10167cf5b09STao Ma /* 10267cf5b09STao Ma * Get the maximum size we now can store in an inode. 10367cf5b09STao Ma * If we can't find the space for a xattr entry, don't use the space 10467cf5b09STao Ma * of the extents since we have no space to indicate the inline data. 10567cf5b09STao Ma */ 10667cf5b09STao Ma int ext4_get_max_inline_size(struct inode *inode) 10767cf5b09STao Ma { 10867cf5b09STao Ma int error, max_inline_size; 10967cf5b09STao Ma struct ext4_iloc iloc; 11067cf5b09STao Ma 11167cf5b09STao Ma if (EXT4_I(inode)->i_extra_isize == 0) 11267cf5b09STao Ma return 0; 11367cf5b09STao Ma 11467cf5b09STao Ma error = ext4_get_inode_loc(inode, &iloc); 11567cf5b09STao Ma if (error) { 11654d3adbcSTheodore Ts'o ext4_error_inode_err(inode, __func__, __LINE__, 0, -error, 11767cf5b09STao Ma "can't get inode location %lu", 11867cf5b09STao Ma inode->i_ino); 11967cf5b09STao Ma return 0; 12067cf5b09STao Ma } 12167cf5b09STao Ma 12267cf5b09STao Ma down_read(&EXT4_I(inode)->xattr_sem); 12367cf5b09STao Ma max_inline_size = get_max_inline_xattr_value_size(inode, &iloc); 12467cf5b09STao Ma up_read(&EXT4_I(inode)->xattr_sem); 12567cf5b09STao Ma 12667cf5b09STao Ma brelse(iloc.bh); 12767cf5b09STao Ma 12867cf5b09STao Ma if (!max_inline_size) 12967cf5b09STao Ma return 0; 13067cf5b09STao Ma 13167cf5b09STao Ma return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE; 13267cf5b09STao Ma } 13367cf5b09STao Ma 13467cf5b09STao Ma /* 13567cf5b09STao Ma * this function does not take xattr_sem, which is OK because it is 13667cf5b09STao Ma * currently only used in a code path coming form ext4_iget, before 13767cf5b09STao Ma * the new inode has been unlocked 13867cf5b09STao Ma */ 13967cf5b09STao Ma int ext4_find_inline_data_nolock(struct inode *inode) 14067cf5b09STao Ma { 14167cf5b09STao Ma struct ext4_xattr_ibody_find is = { 14267cf5b09STao Ma .s = { .not_found = -ENODATA, }, 14367cf5b09STao Ma }; 14467cf5b09STao Ma struct ext4_xattr_info i = { 14567cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 14667cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 14767cf5b09STao Ma }; 14867cf5b09STao Ma int error; 14967cf5b09STao Ma 15067cf5b09STao Ma if (EXT4_I(inode)->i_extra_isize == 0) 15167cf5b09STao Ma return 0; 15267cf5b09STao Ma 15367cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 15467cf5b09STao Ma if (error) 15567cf5b09STao Ma return error; 15667cf5b09STao Ma 15767cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 15867cf5b09STao Ma if (error) 15967cf5b09STao Ma goto out; 16067cf5b09STao Ma 16167cf5b09STao Ma if (!is.s.not_found) { 162117166efSTheodore Ts'o if (is.s.here->e_value_inum) { 163117166efSTheodore Ts'o EXT4_ERROR_INODE(inode, "inline data xattr refers " 164117166efSTheodore Ts'o "to an external xattr inode"); 165117166efSTheodore Ts'o error = -EFSCORRUPTED; 166117166efSTheodore Ts'o goto out; 167117166efSTheodore Ts'o } 16867cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 16967cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 17067cf5b09STao Ma EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + 17167cf5b09STao Ma le32_to_cpu(is.s.here->e_value_size); 17267cf5b09STao Ma } 17367cf5b09STao Ma out: 17467cf5b09STao Ma brelse(is.iloc.bh); 17567cf5b09STao Ma return error; 17667cf5b09STao Ma } 17767cf5b09STao Ma 17867cf5b09STao Ma static int ext4_read_inline_data(struct inode *inode, void *buffer, 17967cf5b09STao Ma unsigned int len, 18067cf5b09STao Ma struct ext4_iloc *iloc) 18167cf5b09STao Ma { 18267cf5b09STao Ma struct ext4_xattr_entry *entry; 18367cf5b09STao Ma struct ext4_xattr_ibody_header *header; 18467cf5b09STao Ma int cp_len = 0; 18567cf5b09STao Ma struct ext4_inode *raw_inode; 18667cf5b09STao Ma 18767cf5b09STao Ma if (!len) 18867cf5b09STao Ma return 0; 18967cf5b09STao Ma 19067cf5b09STao Ma BUG_ON(len > EXT4_I(inode)->i_inline_size); 19167cf5b09STao Ma 19266267814SJiangshan Yi cp_len = min_t(unsigned int, len, EXT4_MIN_INLINE_DATA_SIZE); 19367cf5b09STao Ma 19467cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 19567cf5b09STao Ma memcpy(buffer, (void *)(raw_inode->i_block), cp_len); 19667cf5b09STao Ma 19767cf5b09STao Ma len -= cp_len; 19867cf5b09STao Ma buffer += cp_len; 19967cf5b09STao Ma 20067cf5b09STao Ma if (!len) 20167cf5b09STao Ma goto out; 20267cf5b09STao Ma 20367cf5b09STao Ma header = IHDR(inode, raw_inode); 20467cf5b09STao Ma entry = (struct ext4_xattr_entry *)((void *)raw_inode + 20567cf5b09STao Ma EXT4_I(inode)->i_inline_off); 20667cf5b09STao Ma len = min_t(unsigned int, len, 20767cf5b09STao Ma (unsigned int)le32_to_cpu(entry->e_value_size)); 20867cf5b09STao Ma 20967cf5b09STao Ma memcpy(buffer, 21067cf5b09STao Ma (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len); 21167cf5b09STao Ma cp_len += len; 21267cf5b09STao Ma 21367cf5b09STao Ma out: 21467cf5b09STao Ma return cp_len; 21567cf5b09STao Ma } 21667cf5b09STao Ma 21767cf5b09STao Ma /* 21867cf5b09STao Ma * write the buffer to the inline inode. 21967cf5b09STao Ma * If 'create' is set, we don't need to do the extra copy in the xattr 220310c097cSRitesh Harjani * value since it is already handled by ext4_xattr_ibody_set. 2210d812f77STao Ma * That saves us one memcpy. 22267cf5b09STao Ma */ 223c197855eSStephen Hemminger static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, 22467cf5b09STao Ma void *buffer, loff_t pos, unsigned int len) 22567cf5b09STao Ma { 22667cf5b09STao Ma struct ext4_xattr_entry *entry; 22767cf5b09STao Ma struct ext4_xattr_ibody_header *header; 22867cf5b09STao Ma struct ext4_inode *raw_inode; 22967cf5b09STao Ma int cp_len = 0; 23067cf5b09STao Ma 2310db1ff22STheodore Ts'o if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) 2320db1ff22STheodore Ts'o return; 2330db1ff22STheodore Ts'o 23467cf5b09STao Ma BUG_ON(!EXT4_I(inode)->i_inline_off); 23567cf5b09STao Ma BUG_ON(pos + len > EXT4_I(inode)->i_inline_size); 23667cf5b09STao Ma 23767cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 23867cf5b09STao Ma buffer += pos; 23967cf5b09STao Ma 24067cf5b09STao Ma if (pos < EXT4_MIN_INLINE_DATA_SIZE) { 24167cf5b09STao Ma cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ? 24267cf5b09STao Ma EXT4_MIN_INLINE_DATA_SIZE - pos : len; 24367cf5b09STao Ma memcpy((void *)raw_inode->i_block + pos, buffer, cp_len); 24467cf5b09STao Ma 24567cf5b09STao Ma len -= cp_len; 24667cf5b09STao Ma buffer += cp_len; 24767cf5b09STao Ma pos += cp_len; 24867cf5b09STao Ma } 24967cf5b09STao Ma 25067cf5b09STao Ma if (!len) 25167cf5b09STao Ma return; 25267cf5b09STao Ma 25367cf5b09STao Ma pos -= EXT4_MIN_INLINE_DATA_SIZE; 25467cf5b09STao Ma header = IHDR(inode, raw_inode); 25567cf5b09STao Ma entry = (struct ext4_xattr_entry *)((void *)raw_inode + 25667cf5b09STao Ma EXT4_I(inode)->i_inline_off); 25767cf5b09STao Ma 25867cf5b09STao Ma memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos, 25967cf5b09STao Ma buffer, len); 26067cf5b09STao Ma } 26167cf5b09STao Ma 26267cf5b09STao Ma static int ext4_create_inline_data(handle_t *handle, 26367cf5b09STao Ma struct inode *inode, unsigned len) 26467cf5b09STao Ma { 26567cf5b09STao Ma int error; 26667cf5b09STao Ma void *value = NULL; 26767cf5b09STao Ma struct ext4_xattr_ibody_find is = { 26867cf5b09STao Ma .s = { .not_found = -ENODATA, }, 26967cf5b09STao Ma }; 27067cf5b09STao Ma struct ext4_xattr_info i = { 27167cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 27267cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 27367cf5b09STao Ma }; 27467cf5b09STao Ma 27567cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 27667cf5b09STao Ma if (error) 27767cf5b09STao Ma return error; 27867cf5b09STao Ma 2795d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 280188c299eSJan Kara error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, 281188c299eSJan Kara EXT4_JTR_NONE); 28267cf5b09STao Ma if (error) 28367cf5b09STao Ma goto out; 28467cf5b09STao Ma 28567cf5b09STao Ma if (len > EXT4_MIN_INLINE_DATA_SIZE) { 286bd9926e8STheodore Ts'o value = EXT4_ZERO_XATTR_VALUE; 28767cf5b09STao Ma len -= EXT4_MIN_INLINE_DATA_SIZE; 28867cf5b09STao Ma } else { 28967cf5b09STao Ma value = ""; 29067cf5b09STao Ma len = 0; 29167cf5b09STao Ma } 29267cf5b09STao Ma 2937ca4fcbaSkyoungho koo /* Insert the xttr entry. */ 29467cf5b09STao Ma i.value = value; 29567cf5b09STao Ma i.value_len = len; 29667cf5b09STao Ma 29767cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 29867cf5b09STao Ma if (error) 29967cf5b09STao Ma goto out; 30067cf5b09STao Ma 30167cf5b09STao Ma BUG_ON(!is.s.not_found); 30267cf5b09STao Ma 303310c097cSRitesh Harjani error = ext4_xattr_ibody_set(handle, inode, &i, &is); 30467cf5b09STao Ma if (error) { 30567cf5b09STao Ma if (error == -ENOSPC) 30667cf5b09STao Ma ext4_clear_inode_state(inode, 30767cf5b09STao Ma EXT4_STATE_MAY_INLINE_DATA); 30867cf5b09STao Ma goto out; 30967cf5b09STao Ma } 31067cf5b09STao Ma 31167cf5b09STao Ma memset((void *)ext4_raw_inode(&is.iloc)->i_block, 31267cf5b09STao Ma 0, EXT4_MIN_INLINE_DATA_SIZE); 31367cf5b09STao Ma 31467cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 31567cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 31667cf5b09STao Ma EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE; 31767cf5b09STao Ma ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); 31867cf5b09STao Ma ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA); 31967cf5b09STao Ma get_bh(is.iloc.bh); 32067cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 32167cf5b09STao Ma 32267cf5b09STao Ma out: 32367cf5b09STao Ma brelse(is.iloc.bh); 32467cf5b09STao Ma return error; 32567cf5b09STao Ma } 32667cf5b09STao Ma 32767cf5b09STao Ma static int ext4_update_inline_data(handle_t *handle, struct inode *inode, 32867cf5b09STao Ma unsigned int len) 32967cf5b09STao Ma { 33067cf5b09STao Ma int error; 33167cf5b09STao Ma void *value = NULL; 33267cf5b09STao Ma struct ext4_xattr_ibody_find is = { 33367cf5b09STao Ma .s = { .not_found = -ENODATA, }, 33467cf5b09STao Ma }; 33567cf5b09STao Ma struct ext4_xattr_info i = { 33667cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 33767cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 33867cf5b09STao Ma }; 33967cf5b09STao Ma 34067cf5b09STao Ma /* If the old space is ok, write the data directly. */ 34167cf5b09STao Ma if (len <= EXT4_I(inode)->i_inline_size) 34267cf5b09STao Ma return 0; 34367cf5b09STao Ma 34467cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 34567cf5b09STao Ma if (error) 34667cf5b09STao Ma return error; 34767cf5b09STao Ma 34867cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 34967cf5b09STao Ma if (error) 35067cf5b09STao Ma goto out; 35167cf5b09STao Ma 35267cf5b09STao Ma BUG_ON(is.s.not_found); 35367cf5b09STao Ma 35467cf5b09STao Ma len -= EXT4_MIN_INLINE_DATA_SIZE; 35567cf5b09STao Ma value = kzalloc(len, GFP_NOFS); 356578620f4SDan Carpenter if (!value) { 357578620f4SDan Carpenter error = -ENOMEM; 35867cf5b09STao Ma goto out; 359578620f4SDan Carpenter } 36067cf5b09STao Ma 36167cf5b09STao Ma error = ext4_xattr_ibody_get(inode, i.name_index, i.name, 36267cf5b09STao Ma value, len); 363*2a534e1dSTheodore Ts'o if (error < 0) 36467cf5b09STao Ma goto out; 36567cf5b09STao Ma 3665d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 367188c299eSJan Kara error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, 368188c299eSJan Kara EXT4_JTR_NONE); 36967cf5b09STao Ma if (error) 37067cf5b09STao Ma goto out; 37167cf5b09STao Ma 372b483bb77SRandy Dunlap /* Update the xattr entry. */ 37367cf5b09STao Ma i.value = value; 37467cf5b09STao Ma i.value_len = len; 37567cf5b09STao Ma 376310c097cSRitesh Harjani error = ext4_xattr_ibody_set(handle, inode, &i, &is); 37767cf5b09STao Ma if (error) 37867cf5b09STao Ma goto out; 37967cf5b09STao Ma 38067cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 38167cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 38267cf5b09STao Ma EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + 38367cf5b09STao Ma le32_to_cpu(is.s.here->e_value_size); 38467cf5b09STao Ma ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 38567cf5b09STao Ma get_bh(is.iloc.bh); 38667cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 38767cf5b09STao Ma 38867cf5b09STao Ma out: 38967cf5b09STao Ma kfree(value); 39067cf5b09STao Ma brelse(is.iloc.bh); 39167cf5b09STao Ma return error; 39267cf5b09STao Ma } 39367cf5b09STao Ma 394c197855eSStephen Hemminger static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, 39567cf5b09STao Ma unsigned int len) 39667cf5b09STao Ma { 397c755e251STheodore Ts'o int ret, size, no_expand; 39867cf5b09STao Ma struct ext4_inode_info *ei = EXT4_I(inode); 39967cf5b09STao Ma 40067cf5b09STao Ma if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) 40167cf5b09STao Ma return -ENOSPC; 40267cf5b09STao Ma 40367cf5b09STao Ma size = ext4_get_max_inline_size(inode); 40467cf5b09STao Ma if (size < len) 40567cf5b09STao Ma return -ENOSPC; 40667cf5b09STao Ma 407c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 40867cf5b09STao Ma 40967cf5b09STao Ma if (ei->i_inline_off) 41067cf5b09STao Ma ret = ext4_update_inline_data(handle, inode, len); 41167cf5b09STao Ma else 41267cf5b09STao Ma ret = ext4_create_inline_data(handle, inode, len); 41367cf5b09STao Ma 414c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 41567cf5b09STao Ma return ret; 41667cf5b09STao Ma } 41767cf5b09STao Ma 41867cf5b09STao Ma static int ext4_destroy_inline_data_nolock(handle_t *handle, 41967cf5b09STao Ma struct inode *inode) 42067cf5b09STao Ma { 42167cf5b09STao Ma struct ext4_inode_info *ei = EXT4_I(inode); 42267cf5b09STao Ma struct ext4_xattr_ibody_find is = { 42367cf5b09STao Ma .s = { .not_found = 0, }, 42467cf5b09STao Ma }; 42567cf5b09STao Ma struct ext4_xattr_info i = { 42667cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 42767cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 42867cf5b09STao Ma .value = NULL, 42967cf5b09STao Ma .value_len = 0, 43067cf5b09STao Ma }; 43167cf5b09STao Ma int error; 43267cf5b09STao Ma 43367cf5b09STao Ma if (!ei->i_inline_off) 43467cf5b09STao Ma return 0; 43567cf5b09STao Ma 43667cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 43767cf5b09STao Ma if (error) 43867cf5b09STao Ma return error; 43967cf5b09STao Ma 44067cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 44167cf5b09STao Ma if (error) 44267cf5b09STao Ma goto out; 44367cf5b09STao Ma 4445d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 445188c299eSJan Kara error = ext4_journal_get_write_access(handle, inode->i_sb, is.iloc.bh, 446188c299eSJan Kara EXT4_JTR_NONE); 44767cf5b09STao Ma if (error) 44867cf5b09STao Ma goto out; 44967cf5b09STao Ma 450310c097cSRitesh Harjani error = ext4_xattr_ibody_set(handle, inode, &i, &is); 45167cf5b09STao Ma if (error) 45267cf5b09STao Ma goto out; 45367cf5b09STao Ma 45467cf5b09STao Ma memset((void *)ext4_raw_inode(&is.iloc)->i_block, 45567cf5b09STao Ma 0, EXT4_MIN_INLINE_DATA_SIZE); 4566e8ab72aSTheodore Ts'o memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); 45767cf5b09STao Ma 458e2b911c5SDarrick J. Wong if (ext4_has_feature_extents(inode->i_sb)) { 45967cf5b09STao Ma if (S_ISDIR(inode->i_mode) || 46067cf5b09STao Ma S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) { 46167cf5b09STao Ma ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); 46267cf5b09STao Ma ext4_ext_tree_init(handle, inode); 46367cf5b09STao Ma } 46467cf5b09STao Ma } 46567cf5b09STao Ma ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA); 46667cf5b09STao Ma 46767cf5b09STao Ma get_bh(is.iloc.bh); 46867cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 46967cf5b09STao Ma 47067cf5b09STao Ma EXT4_I(inode)->i_inline_off = 0; 47167cf5b09STao Ma EXT4_I(inode)->i_inline_size = 0; 47267cf5b09STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 47367cf5b09STao Ma out: 47467cf5b09STao Ma brelse(is.iloc.bh); 47567cf5b09STao Ma if (error == -ENODATA) 47667cf5b09STao Ma error = 0; 47767cf5b09STao Ma return error; 47867cf5b09STao Ma } 47967cf5b09STao Ma 4806b87fbe4SMatthew Wilcox static int ext4_read_inline_folio(struct inode *inode, struct folio *folio) 48146c7f254STao Ma { 48246c7f254STao Ma void *kaddr; 48346c7f254STao Ma int ret = 0; 48446c7f254STao Ma size_t len; 48546c7f254STao Ma struct ext4_iloc iloc; 48646c7f254STao Ma 4876b87fbe4SMatthew Wilcox BUG_ON(!folio_test_locked(folio)); 48846c7f254STao Ma BUG_ON(!ext4_has_inline_data(inode)); 4896b87fbe4SMatthew Wilcox BUG_ON(folio->index); 49046c7f254STao Ma 49146c7f254STao Ma if (!EXT4_I(inode)->i_inline_off) { 49246c7f254STao Ma ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.", 49346c7f254STao Ma inode->i_ino); 49446c7f254STao Ma goto out; 49546c7f254STao Ma } 49646c7f254STao Ma 49746c7f254STao Ma ret = ext4_get_inode_loc(inode, &iloc); 49846c7f254STao Ma if (ret) 49946c7f254STao Ma goto out; 50046c7f254STao Ma 50146c7f254STao Ma len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode)); 5026b87fbe4SMatthew Wilcox BUG_ON(len > PAGE_SIZE); 5036b87fbe4SMatthew Wilcox kaddr = kmap_local_folio(folio, 0); 50446c7f254STao Ma ret = ext4_read_inline_data(inode, kaddr, len, &iloc); 5056b87fbe4SMatthew Wilcox flush_dcache_folio(folio); 5066b87fbe4SMatthew Wilcox kunmap_local(kaddr); 5076b87fbe4SMatthew Wilcox folio_zero_segment(folio, len, folio_size(folio)); 5086b87fbe4SMatthew Wilcox folio_mark_uptodate(folio); 50946c7f254STao Ma brelse(iloc.bh); 51046c7f254STao Ma 51146c7f254STao Ma out: 51246c7f254STao Ma return ret; 51346c7f254STao Ma } 51446c7f254STao Ma 5153edde93eSMatthew Wilcox int ext4_readpage_inline(struct inode *inode, struct folio *folio) 51646c7f254STao Ma { 51746c7f254STao Ma int ret = 0; 51846c7f254STao Ma 51946c7f254STao Ma down_read(&EXT4_I(inode)->xattr_sem); 52046c7f254STao Ma if (!ext4_has_inline_data(inode)) { 52146c7f254STao Ma up_read(&EXT4_I(inode)->xattr_sem); 52246c7f254STao Ma return -EAGAIN; 52346c7f254STao Ma } 52446c7f254STao Ma 52546c7f254STao Ma /* 52646c7f254STao Ma * Current inline data can only exist in the 1st page, 52746c7f254STao Ma * So for all the other pages, just set them uptodate. 52846c7f254STao Ma */ 5293edde93eSMatthew Wilcox if (!folio->index) 5306b87fbe4SMatthew Wilcox ret = ext4_read_inline_folio(inode, folio); 5313edde93eSMatthew Wilcox else if (!folio_test_uptodate(folio)) { 5323edde93eSMatthew Wilcox folio_zero_segment(folio, 0, folio_size(folio)); 5333edde93eSMatthew Wilcox folio_mark_uptodate(folio); 53446c7f254STao Ma } 53546c7f254STao Ma 53646c7f254STao Ma up_read(&EXT4_I(inode)->xattr_sem); 53746c7f254STao Ma 5383edde93eSMatthew Wilcox folio_unlock(folio); 53946c7f254STao Ma return ret >= 0 ? 0 : ret; 54046c7f254STao Ma } 54146c7f254STao Ma 542f19d5870STao Ma static int ext4_convert_inline_data_to_extent(struct address_space *mapping, 543832ee62dSMatthew Wilcox (Oracle) struct inode *inode) 544f19d5870STao Ma { 545c755e251STheodore Ts'o int ret, needed_blocks, no_expand; 546f19d5870STao Ma handle_t *handle = NULL; 547f19d5870STao Ma int retries = 0, sem_held = 0; 54883eba701SMatthew Wilcox struct folio *folio = NULL; 549f19d5870STao Ma unsigned from, to; 550f19d5870STao Ma struct ext4_iloc iloc; 551f19d5870STao Ma 552f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 553f19d5870STao Ma /* 554f19d5870STao Ma * clear the flag so that no new write 555f19d5870STao Ma * will trap here again. 556f19d5870STao Ma */ 557f19d5870STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 558f19d5870STao Ma return 0; 559f19d5870STao Ma } 560f19d5870STao Ma 561f19d5870STao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 562f19d5870STao Ma 563f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 564f19d5870STao Ma if (ret) 565f19d5870STao Ma return ret; 566f19d5870STao Ma 567f19d5870STao Ma retry: 5689924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); 569f19d5870STao Ma if (IS_ERR(handle)) { 570f19d5870STao Ma ret = PTR_ERR(handle); 571f19d5870STao Ma handle = NULL; 572f19d5870STao Ma goto out; 573f19d5870STao Ma } 574f19d5870STao Ma 575f19d5870STao Ma /* We cannot recurse into the filesystem as the transaction is already 576f19d5870STao Ma * started */ 57783eba701SMatthew Wilcox folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS, 57883eba701SMatthew Wilcox mapping_gfp_mask(mapping)); 5797fa8a8eeSLinus Torvalds if (IS_ERR(folio)) { 5807fa8a8eeSLinus Torvalds ret = PTR_ERR(folio); 5817fa8a8eeSLinus Torvalds goto out_nofolio; 582f19d5870STao Ma } 583f19d5870STao Ma 584c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 585f19d5870STao Ma sem_held = 1; 586f19d5870STao Ma /* If some one has already done this for us, just exit. */ 587f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 588f19d5870STao Ma ret = 0; 589f19d5870STao Ma goto out; 590f19d5870STao Ma } 591f19d5870STao Ma 592f19d5870STao Ma from = 0; 593f19d5870STao Ma to = ext4_get_inline_size(inode); 59483eba701SMatthew Wilcox if (!folio_test_uptodate(folio)) { 5956b87fbe4SMatthew Wilcox ret = ext4_read_inline_folio(inode, folio); 596f19d5870STao Ma if (ret < 0) 597f19d5870STao Ma goto out; 598f19d5870STao Ma } 599f19d5870STao Ma 600f19d5870STao Ma ret = ext4_destroy_inline_data_nolock(handle, inode); 601f19d5870STao Ma if (ret) 602f19d5870STao Ma goto out; 603f19d5870STao Ma 604705965bdSJan Kara if (ext4_should_dioread_nolock(inode)) { 60583eba701SMatthew Wilcox ret = __block_write_begin(&folio->page, from, to, 606705965bdSJan Kara ext4_get_block_unwritten); 607705965bdSJan Kara } else 60883eba701SMatthew Wilcox ret = __block_write_begin(&folio->page, from, to, ext4_get_block); 609f19d5870STao Ma 610f19d5870STao Ma if (!ret && ext4_should_journal_data(inode)) { 61183eba701SMatthew Wilcox ret = ext4_walk_page_buffers(handle, inode, 61283eba701SMatthew Wilcox folio_buffers(folio), from, to, 61383eba701SMatthew Wilcox NULL, do_journal_get_write_access); 614f19d5870STao Ma } 615f19d5870STao Ma 616f19d5870STao Ma if (ret) { 61783eba701SMatthew Wilcox folio_unlock(folio); 61883eba701SMatthew Wilcox folio_put(folio); 61983eba701SMatthew Wilcox folio = NULL; 620f19d5870STao Ma ext4_orphan_add(handle, inode); 621c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 622f19d5870STao Ma sem_held = 0; 623f19d5870STao Ma ext4_journal_stop(handle); 624f19d5870STao Ma handle = NULL; 625f19d5870STao Ma ext4_truncate_failed_write(inode); 626f19d5870STao Ma /* 627f19d5870STao Ma * If truncate failed early the inode might 628f19d5870STao Ma * still be on the orphan list; we need to 629f19d5870STao Ma * make sure the inode is removed from the 630f19d5870STao Ma * orphan list in that case. 631f19d5870STao Ma */ 632f19d5870STao Ma if (inode->i_nlink) 633f19d5870STao Ma ext4_orphan_del(NULL, inode); 634f19d5870STao Ma } 635f19d5870STao Ma 636f19d5870STao Ma if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 637f19d5870STao Ma goto retry; 638f19d5870STao Ma 63983eba701SMatthew Wilcox if (folio) 64083eba701SMatthew Wilcox block_commit_write(&folio->page, from, to); 641f19d5870STao Ma out: 64283eba701SMatthew Wilcox if (folio) { 64383eba701SMatthew Wilcox folio_unlock(folio); 64483eba701SMatthew Wilcox folio_put(folio); 645f19d5870STao Ma } 6467fa8a8eeSLinus Torvalds out_nofolio: 647f19d5870STao Ma if (sem_held) 648c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 649f19d5870STao Ma if (handle) 650f19d5870STao Ma ext4_journal_stop(handle); 651f19d5870STao Ma brelse(iloc.bh); 652f19d5870STao Ma return ret; 653f19d5870STao Ma } 654f19d5870STao Ma 655f19d5870STao Ma /* 656f19d5870STao Ma * Try to write data in the inode. 657f19d5870STao Ma * If the inode has inline data, check whether the new write can be 658f19d5870STao Ma * in the inode also. If not, create the page the handle, move the data 659f19d5870STao Ma * to the page make it update and let the later codes create extent for it. 660f19d5870STao Ma */ 661f19d5870STao Ma int ext4_try_to_write_inline_data(struct address_space *mapping, 662f19d5870STao Ma struct inode *inode, 663f19d5870STao Ma loff_t pos, unsigned len, 664f19d5870STao Ma struct page **pagep) 665f19d5870STao Ma { 666f19d5870STao Ma int ret; 667f19d5870STao Ma handle_t *handle; 668f8f8c89fSMatthew Wilcox struct folio *folio; 669f19d5870STao Ma struct ext4_iloc iloc; 670f19d5870STao Ma 671f19d5870STao Ma if (pos + len > ext4_get_max_inline_size(inode)) 672f19d5870STao Ma goto convert; 673f19d5870STao Ma 674f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 675f19d5870STao Ma if (ret) 676f19d5870STao Ma return ret; 677f19d5870STao Ma 678f19d5870STao Ma /* 679f19d5870STao Ma * The possible write could happen in the inode, 680f19d5870STao Ma * so try to reserve the space in inode first. 681f19d5870STao Ma */ 6829924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 683f19d5870STao Ma if (IS_ERR(handle)) { 684f19d5870STao Ma ret = PTR_ERR(handle); 685f19d5870STao Ma handle = NULL; 686f19d5870STao Ma goto out; 687f19d5870STao Ma } 688f19d5870STao Ma 689f19d5870STao Ma ret = ext4_prepare_inline_data(handle, inode, pos + len); 690f19d5870STao Ma if (ret && ret != -ENOSPC) 691f19d5870STao Ma goto out; 692f19d5870STao Ma 693f19d5870STao Ma /* We don't have space in inline inode, so convert it to extent. */ 694f19d5870STao Ma if (ret == -ENOSPC) { 695f19d5870STao Ma ext4_journal_stop(handle); 696f19d5870STao Ma brelse(iloc.bh); 697f19d5870STao Ma goto convert; 698f19d5870STao Ma } 699f19d5870STao Ma 700188c299eSJan Kara ret = ext4_journal_get_write_access(handle, inode->i_sb, iloc.bh, 701188c299eSJan Kara EXT4_JTR_NONE); 702362eca70STheodore Ts'o if (ret) 703362eca70STheodore Ts'o goto out; 704362eca70STheodore Ts'o 705f8f8c89fSMatthew Wilcox folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS, 706f8f8c89fSMatthew Wilcox mapping_gfp_mask(mapping)); 7077fa8a8eeSLinus Torvalds if (IS_ERR(folio)) { 7087fa8a8eeSLinus Torvalds ret = PTR_ERR(folio); 709f19d5870STao Ma goto out; 710f19d5870STao Ma } 711f19d5870STao Ma 712f8f8c89fSMatthew Wilcox *pagep = &folio->page; 713f19d5870STao Ma down_read(&EXT4_I(inode)->xattr_sem); 714f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 715f19d5870STao Ma ret = 0; 716f8f8c89fSMatthew Wilcox folio_unlock(folio); 717f8f8c89fSMatthew Wilcox folio_put(folio); 718f19d5870STao Ma goto out_up_read; 719f19d5870STao Ma } 720f19d5870STao Ma 721f8f8c89fSMatthew Wilcox if (!folio_test_uptodate(folio)) { 7226b87fbe4SMatthew Wilcox ret = ext4_read_inline_folio(inode, folio); 723132d00beSMaurizio Lombardi if (ret < 0) { 724f8f8c89fSMatthew Wilcox folio_unlock(folio); 725f8f8c89fSMatthew Wilcox folio_put(folio); 726f19d5870STao Ma goto out_up_read; 727f19d5870STao Ma } 728132d00beSMaurizio Lombardi } 729f19d5870STao Ma 730f19d5870STao Ma ret = 1; 731f19d5870STao Ma handle = NULL; 732f19d5870STao Ma out_up_read: 733f19d5870STao Ma up_read(&EXT4_I(inode)->xattr_sem); 734f19d5870STao Ma out: 735362eca70STheodore Ts'o if (handle && (ret != 1)) 736f19d5870STao Ma ext4_journal_stop(handle); 737f19d5870STao Ma brelse(iloc.bh); 738f19d5870STao Ma return ret; 739f19d5870STao Ma convert: 740832ee62dSMatthew Wilcox (Oracle) return ext4_convert_inline_data_to_extent(mapping, inode); 741f19d5870STao Ma } 742f19d5870STao Ma 743f19d5870STao Ma int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, 744f19d5870STao Ma unsigned copied, struct page *page) 745f19d5870STao Ma { 7466b90d413SMatthew Wilcox struct folio *folio = page_folio(page); 7476984aef5SZhang Yi handle_t *handle = ext4_journal_current_handle(); 7486984aef5SZhang Yi int no_expand; 749f19d5870STao Ma void *kaddr; 750f19d5870STao Ma struct ext4_iloc iloc; 7516984aef5SZhang Yi int ret = 0, ret2; 752f19d5870STao Ma 7536b90d413SMatthew Wilcox if (unlikely(copied < len) && !folio_test_uptodate(folio)) 754f19d5870STao Ma copied = 0; 755f19d5870STao Ma 7566984aef5SZhang Yi if (likely(copied)) { 757f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 758f19d5870STao Ma if (ret) { 7596b90d413SMatthew Wilcox folio_unlock(folio); 7606b90d413SMatthew Wilcox folio_put(folio); 761f19d5870STao Ma ext4_std_error(inode->i_sb, ret); 762f19d5870STao Ma goto out; 763f19d5870STao Ma } 764c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 765f19d5870STao Ma BUG_ON(!ext4_has_inline_data(inode)); 766f19d5870STao Ma 767a54c4613STheodore Ts'o /* 76811ef08c9STheodore Ts'o * ei->i_inline_off may have changed since 76911ef08c9STheodore Ts'o * ext4_write_begin() called 77011ef08c9STheodore Ts'o * ext4_try_to_write_inline_data() 771a54c4613STheodore Ts'o */ 772a54c4613STheodore Ts'o (void) ext4_find_inline_data_nolock(inode); 773a54c4613STheodore Ts'o 7746b90d413SMatthew Wilcox kaddr = kmap_local_folio(folio, 0); 77555ce2f64SZhang Yi ext4_write_inline_data(inode, &iloc, kaddr, pos, copied); 7766b90d413SMatthew Wilcox kunmap_local(kaddr); 7776b90d413SMatthew Wilcox folio_mark_uptodate(folio); 7786b90d413SMatthew Wilcox /* clear dirty flag so that writepages wouldn't work for us. */ 7796b90d413SMatthew Wilcox folio_clear_dirty(folio); 780f19d5870STao Ma 781c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 782f19d5870STao Ma brelse(iloc.bh); 78355ce2f64SZhang Yi 7846984aef5SZhang Yi /* 7856b90d413SMatthew Wilcox * It's important to update i_size while still holding folio 7866984aef5SZhang Yi * lock: page writeout could otherwise come in and zero 7876984aef5SZhang Yi * beyond i_size. 7886984aef5SZhang Yi */ 7896984aef5SZhang Yi ext4_update_inode_size(inode, pos + copied); 7906984aef5SZhang Yi } 7916b90d413SMatthew Wilcox folio_unlock(folio); 7926b90d413SMatthew Wilcox folio_put(folio); 7936984aef5SZhang Yi 7946984aef5SZhang Yi /* 7956b90d413SMatthew Wilcox * Don't mark the inode dirty under folio lock. First, it unnecessarily 7966b90d413SMatthew Wilcox * makes the holding time of folio lock longer. Second, it forces lock 7976b90d413SMatthew Wilcox * ordering of folio lock and transaction start for journaling 7986984aef5SZhang Yi * filesystems. 7996984aef5SZhang Yi */ 8006984aef5SZhang Yi if (likely(copied)) 801362eca70STheodore Ts'o mark_inode_dirty(inode); 802f19d5870STao Ma out: 8036984aef5SZhang Yi /* 8046984aef5SZhang Yi * If we didn't copy as much data as expected, we need to trim back 8056984aef5SZhang Yi * size of xattr containing inline data. 8066984aef5SZhang Yi */ 8076984aef5SZhang Yi if (pos + len > inode->i_size && ext4_can_truncate(inode)) 8086984aef5SZhang Yi ext4_orphan_add(handle, inode); 8096984aef5SZhang Yi 8106984aef5SZhang Yi ret2 = ext4_journal_stop(handle); 8116984aef5SZhang Yi if (!ret) 8126984aef5SZhang Yi ret = ret2; 8136984aef5SZhang Yi if (pos + len > inode->i_size) { 8146984aef5SZhang Yi ext4_truncate_failed_write(inode); 8156984aef5SZhang Yi /* 8166984aef5SZhang Yi * If truncate failed early the inode might still be 8176984aef5SZhang Yi * on the orphan list; we need to make sure the inode 8186984aef5SZhang Yi * is removed from the orphan list in that case. 8196984aef5SZhang Yi */ 8206984aef5SZhang Yi if (inode->i_nlink) 8216984aef5SZhang Yi ext4_orphan_del(NULL, inode); 8226984aef5SZhang Yi } 8236984aef5SZhang Yi return ret ? ret : copied; 824f19d5870STao Ma } 825f19d5870STao Ma 8263fdcfb66STao Ma struct buffer_head * 8273fdcfb66STao Ma ext4_journalled_write_inline_data(struct inode *inode, 8283fdcfb66STao Ma unsigned len, 8293fdcfb66STao Ma struct page *page) 8303fdcfb66STao Ma { 831c755e251STheodore Ts'o int ret, no_expand; 8323fdcfb66STao Ma void *kaddr; 8333fdcfb66STao Ma struct ext4_iloc iloc; 8343fdcfb66STao Ma 8353fdcfb66STao Ma ret = ext4_get_inode_loc(inode, &iloc); 8363fdcfb66STao Ma if (ret) { 8373fdcfb66STao Ma ext4_std_error(inode->i_sb, ret); 8383fdcfb66STao Ma return NULL; 8393fdcfb66STao Ma } 8403fdcfb66STao Ma 841c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 8423fdcfb66STao Ma kaddr = kmap_atomic(page); 8433fdcfb66STao Ma ext4_write_inline_data(inode, &iloc, kaddr, 0, len); 8443fdcfb66STao Ma kunmap_atomic(kaddr); 845c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 8463fdcfb66STao Ma 8473fdcfb66STao Ma return iloc.bh; 8483fdcfb66STao Ma } 8493fdcfb66STao Ma 8509c3569b5STao Ma /* 8519c3569b5STao Ma * Try to make the page cache and handle ready for the inline data case. 8529c3569b5STao Ma * We can call this function in 2 cases: 8539c3569b5STao Ma * 1. The inode is created and the first write exceeds inline size. We can 8549c3569b5STao Ma * clear the inode state safely. 8559c3569b5STao Ma * 2. The inode has inline data, then we need to read the data, make it 8569c3569b5STao Ma * update and dirty so that ext4_da_writepages can handle it. We don't 8573088e5a5SBhaskar Chowdhury * need to start the journal since the file's metadata isn't changed now. 8589c3569b5STao Ma */ 8599c3569b5STao Ma static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, 8609c3569b5STao Ma struct inode *inode, 8619c3569b5STao Ma void **fsdata) 8629c3569b5STao Ma { 8639c3569b5STao Ma int ret = 0, inline_size; 8644ed9b598SMatthew Wilcox struct folio *folio; 8659c3569b5STao Ma 8664ed9b598SMatthew Wilcox folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN, 8674ed9b598SMatthew Wilcox mapping_gfp_mask(mapping)); 8687fa8a8eeSLinus Torvalds if (IS_ERR(folio)) 8697fa8a8eeSLinus Torvalds return PTR_ERR(folio); 8709c3569b5STao Ma 8719c3569b5STao Ma down_read(&EXT4_I(inode)->xattr_sem); 8729c3569b5STao Ma if (!ext4_has_inline_data(inode)) { 8739c3569b5STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 8749c3569b5STao Ma goto out; 8759c3569b5STao Ma } 8769c3569b5STao Ma 8779c3569b5STao Ma inline_size = ext4_get_inline_size(inode); 8789c3569b5STao Ma 8794ed9b598SMatthew Wilcox if (!folio_test_uptodate(folio)) { 8806b87fbe4SMatthew Wilcox ret = ext4_read_inline_folio(inode, folio); 8819c3569b5STao Ma if (ret < 0) 8829c3569b5STao Ma goto out; 8839c3569b5STao Ma } 8849c3569b5STao Ma 8854ed9b598SMatthew Wilcox ret = __block_write_begin(&folio->page, 0, inline_size, 8869c3569b5STao Ma ext4_da_get_block_prep); 8879c3569b5STao Ma if (ret) { 88850db71abSDmitry Monakhov up_read(&EXT4_I(inode)->xattr_sem); 8894ed9b598SMatthew Wilcox folio_unlock(folio); 8904ed9b598SMatthew Wilcox folio_put(folio); 8919c3569b5STao Ma ext4_truncate_failed_write(inode); 89250db71abSDmitry Monakhov return ret; 8939c3569b5STao Ma } 8949c3569b5STao Ma 8954ed9b598SMatthew Wilcox folio_mark_dirty(folio); 8964ed9b598SMatthew Wilcox folio_mark_uptodate(folio); 8979c3569b5STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 8989c3569b5STao Ma *fsdata = (void *)CONVERT_INLINE_DATA; 8999c3569b5STao Ma 9009c3569b5STao Ma out: 9019c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 9024ed9b598SMatthew Wilcox if (folio) { 9034ed9b598SMatthew Wilcox folio_unlock(folio); 9044ed9b598SMatthew Wilcox folio_put(folio); 9059c3569b5STao Ma } 9069c3569b5STao Ma return ret; 9079c3569b5STao Ma } 9089c3569b5STao Ma 9099c3569b5STao Ma /* 9109c3569b5STao Ma * Prepare the write for the inline data. 9118d6ce136SShijie Luo * If the data can be written into the inode, we just read 9129c3569b5STao Ma * the page and make it uptodate, and start the journal. 9139c3569b5STao Ma * Otherwise read the page, makes it dirty so that it can be 9149c3569b5STao Ma * handle in writepages(the i_disksize update is left to the 9159c3569b5STao Ma * normal ext4_da_write_end). 9169c3569b5STao Ma */ 9179c3569b5STao Ma int ext4_da_write_inline_data_begin(struct address_space *mapping, 9189c3569b5STao Ma struct inode *inode, 9199c3569b5STao Ma loff_t pos, unsigned len, 9209c3569b5STao Ma struct page **pagep, 9219c3569b5STao Ma void **fsdata) 9229c3569b5STao Ma { 92309355d9dSRitesh Harjani int ret; 9249c3569b5STao Ma handle_t *handle; 9259a9d01f0SMatthew Wilcox struct folio *folio; 9269c3569b5STao Ma struct ext4_iloc iloc; 927625ef8a3SLukas Czerner int retries = 0; 9289c3569b5STao Ma 9299c3569b5STao Ma ret = ext4_get_inode_loc(inode, &iloc); 9309c3569b5STao Ma if (ret) 9319c3569b5STao Ma return ret; 9329c3569b5STao Ma 933bc0ca9dfSJan Kara retry_journal: 9349924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 9359c3569b5STao Ma if (IS_ERR(handle)) { 9369c3569b5STao Ma ret = PTR_ERR(handle); 9379c3569b5STao Ma goto out; 9389c3569b5STao Ma } 9399c3569b5STao Ma 9409c3569b5STao Ma ret = ext4_prepare_inline_data(handle, inode, pos + len); 9419c3569b5STao Ma if (ret && ret != -ENOSPC) 94252e44777SJan Kara goto out_journal; 9439c3569b5STao Ma 9449c3569b5STao Ma if (ret == -ENOSPC) { 9458bc1379bSTheodore Ts'o ext4_journal_stop(handle); 9469c3569b5STao Ma ret = ext4_da_convert_inline_data_to_extent(mapping, 9479c3569b5STao Ma inode, 9489c3569b5STao Ma fsdata); 949bc0ca9dfSJan Kara if (ret == -ENOSPC && 950bc0ca9dfSJan Kara ext4_should_retry_alloc(inode->i_sb, &retries)) 951bc0ca9dfSJan Kara goto retry_journal; 9529c3569b5STao Ma goto out; 9539c3569b5STao Ma } 9549c3569b5STao Ma 95536d116e9SMatthew Wilcox (Oracle) /* 95636d116e9SMatthew Wilcox (Oracle) * We cannot recurse into the filesystem as the transaction 95736d116e9SMatthew Wilcox (Oracle) * is already started. 95836d116e9SMatthew Wilcox (Oracle) */ 9599a9d01f0SMatthew Wilcox folio = __filemap_get_folio(mapping, 0, FGP_WRITEBEGIN | FGP_NOFS, 9609a9d01f0SMatthew Wilcox mapping_gfp_mask(mapping)); 9617fa8a8eeSLinus Torvalds if (IS_ERR(folio)) { 9627fa8a8eeSLinus Torvalds ret = PTR_ERR(folio); 96352e44777SJan Kara goto out_journal; 9649c3569b5STao Ma } 9659c3569b5STao Ma 9669c3569b5STao Ma down_read(&EXT4_I(inode)->xattr_sem); 9679c3569b5STao Ma if (!ext4_has_inline_data(inode)) { 9689c3569b5STao Ma ret = 0; 9699c3569b5STao Ma goto out_release_page; 9709c3569b5STao Ma } 9719c3569b5STao Ma 9729a9d01f0SMatthew Wilcox if (!folio_test_uptodate(folio)) { 9736b87fbe4SMatthew Wilcox ret = ext4_read_inline_folio(inode, folio); 9749c3569b5STao Ma if (ret < 0) 9759c3569b5STao Ma goto out_release_page; 9769c3569b5STao Ma } 977188c299eSJan Kara ret = ext4_journal_get_write_access(handle, inode->i_sb, iloc.bh, 978188c299eSJan Kara EXT4_JTR_NONE); 979362eca70STheodore Ts'o if (ret) 980362eca70STheodore Ts'o goto out_release_page; 9819c3569b5STao Ma 9829c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 9839a9d01f0SMatthew Wilcox *pagep = &folio->page; 9849c3569b5STao Ma brelse(iloc.bh); 9859c3569b5STao Ma return 1; 9869c3569b5STao Ma out_release_page: 9879c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 9889a9d01f0SMatthew Wilcox folio_unlock(folio); 9899a9d01f0SMatthew Wilcox folio_put(folio); 99052e44777SJan Kara out_journal: 9919c3569b5STao Ma ext4_journal_stop(handle); 99252e44777SJan Kara out: 9939c3569b5STao Ma brelse(iloc.bh); 9949c3569b5STao Ma return ret; 9959c3569b5STao Ma } 9969c3569b5STao Ma 9973c47d541STao Ma #ifdef INLINE_DIR_DEBUG 9983c47d541STao Ma void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, 9993c47d541STao Ma void *inline_start, int inline_size) 10003c47d541STao Ma { 10013c47d541STao Ma int offset; 10023c47d541STao Ma unsigned short de_len; 10033c47d541STao Ma struct ext4_dir_entry_2 *de = inline_start; 10043c47d541STao Ma void *dlimit = inline_start + inline_size; 10053c47d541STao Ma 10063c47d541STao Ma trace_printk("inode %lu\n", dir->i_ino); 10073c47d541STao Ma offset = 0; 10083c47d541STao Ma while ((void *)de < dlimit) { 10093c47d541STao Ma de_len = ext4_rec_len_from_disk(de->rec_len, inline_size); 101080cfb71eSRasmus Villemoes trace_printk("de: off %u rlen %u name %.*s nlen %u ino %u\n", 10113c47d541STao Ma offset, de_len, de->name_len, de->name, 10123c47d541STao Ma de->name_len, le32_to_cpu(de->inode)); 10133c47d541STao Ma if (ext4_check_dir_entry(dir, NULL, de, bh, 10143c47d541STao Ma inline_start, inline_size, offset)) 10153c47d541STao Ma BUG(); 10163c47d541STao Ma 10173c47d541STao Ma offset += de_len; 10183c47d541STao Ma de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); 10193c47d541STao Ma } 10203c47d541STao Ma } 10213c47d541STao Ma #else 10223c47d541STao Ma #define ext4_show_inline_dir(dir, bh, inline_start, inline_size) 10233c47d541STao Ma #endif 10243c47d541STao Ma 10253c47d541STao Ma /* 10263c47d541STao Ma * Add a new entry into a inline dir. 10273c47d541STao Ma * It will return -ENOSPC if no space is available, and -EIO 10283c47d541STao Ma * and -EEXIST if directory entry already exists. 10293c47d541STao Ma */ 10303c47d541STao Ma static int ext4_add_dirent_to_inline(handle_t *handle, 10315b643f9cSTheodore Ts'o struct ext4_filename *fname, 103256a04915STheodore Ts'o struct inode *dir, 10333c47d541STao Ma struct inode *inode, 10343c47d541STao Ma struct ext4_iloc *iloc, 10353c47d541STao Ma void *inline_start, int inline_size) 10363c47d541STao Ma { 10373c47d541STao Ma int err; 10383c47d541STao Ma struct ext4_dir_entry_2 *de; 10393c47d541STao Ma 10405b643f9cSTheodore Ts'o err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start, 10415b643f9cSTheodore Ts'o inline_size, fname, &de); 10423c47d541STao Ma if (err) 10433c47d541STao Ma return err; 10443c47d541STao Ma 10455d601255Sliang xie BUFFER_TRACE(iloc->bh, "get_write_access"); 1046188c299eSJan Kara err = ext4_journal_get_write_access(handle, dir->i_sb, iloc->bh, 1047188c299eSJan Kara EXT4_JTR_NONE); 10483c47d541STao Ma if (err) 10493c47d541STao Ma return err; 1050471fbbeaSDaniel Rosenberg ext4_insert_dentry(dir, inode, de, inline_size, fname); 10513c47d541STao Ma 10523c47d541STao Ma ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size); 10533c47d541STao Ma 10543c47d541STao Ma /* 10553c47d541STao Ma * XXX shouldn't update any times until successful 10563c47d541STao Ma * completion of syscall, but too many callers depend 10573c47d541STao Ma * on this. 10583c47d541STao Ma * 10593c47d541STao Ma * XXX similarly, too many callers depend on 10603c47d541STao Ma * ext4_new_inode() setting the times, but error 10613c47d541STao Ma * recovery deletes the inode, so the worst that can 10623c47d541STao Ma * happen is that the times are slightly out of date 10633c47d541STao Ma * and/or different from the directory change time. 10643c47d541STao Ma */ 1065eeca7ea1SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 10663c47d541STao Ma ext4_update_dx_flag(dir); 1067ee73f9a5SJeff Layton inode_inc_iversion(dir); 10683c47d541STao Ma return 1; 10693c47d541STao Ma } 10703c47d541STao Ma 10713c47d541STao Ma static void *ext4_get_inline_xattr_pos(struct inode *inode, 10723c47d541STao Ma struct ext4_iloc *iloc) 10733c47d541STao Ma { 10743c47d541STao Ma struct ext4_xattr_entry *entry; 10753c47d541STao Ma struct ext4_xattr_ibody_header *header; 10763c47d541STao Ma 10773c47d541STao Ma BUG_ON(!EXT4_I(inode)->i_inline_off); 10783c47d541STao Ma 10793c47d541STao Ma header = IHDR(inode, ext4_raw_inode(iloc)); 10803c47d541STao Ma entry = (struct ext4_xattr_entry *)((void *)ext4_raw_inode(iloc) + 10813c47d541STao Ma EXT4_I(inode)->i_inline_off); 10823c47d541STao Ma 10833c47d541STao Ma return (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs); 10843c47d541STao Ma } 10853c47d541STao Ma 10863c47d541STao Ma /* Set the final de to cover the whole block. */ 10873c47d541STao Ma static void ext4_update_final_de(void *de_buf, int old_size, int new_size) 10883c47d541STao Ma { 10893c47d541STao Ma struct ext4_dir_entry_2 *de, *prev_de; 10903c47d541STao Ma void *limit; 10913c47d541STao Ma int de_len; 10923c47d541STao Ma 1093c30365b9SYu Zhe de = de_buf; 10943c47d541STao Ma if (old_size) { 10953c47d541STao Ma limit = de_buf + old_size; 10963c47d541STao Ma do { 10973c47d541STao Ma prev_de = de; 10983c47d541STao Ma de_len = ext4_rec_len_from_disk(de->rec_len, old_size); 10993c47d541STao Ma de_buf += de_len; 1100c30365b9SYu Zhe de = de_buf; 11013c47d541STao Ma } while (de_buf < limit); 11023c47d541STao Ma 11033c47d541STao Ma prev_de->rec_len = ext4_rec_len_to_disk(de_len + new_size - 11043c47d541STao Ma old_size, new_size); 11053c47d541STao Ma } else { 11063c47d541STao Ma /* this is just created, so create an empty entry. */ 11073c47d541STao Ma de->inode = 0; 11083c47d541STao Ma de->rec_len = ext4_rec_len_to_disk(new_size, new_size); 11093c47d541STao Ma } 11103c47d541STao Ma } 11113c47d541STao Ma 11123c47d541STao Ma static int ext4_update_inline_dir(handle_t *handle, struct inode *dir, 11133c47d541STao Ma struct ext4_iloc *iloc) 11143c47d541STao Ma { 11153c47d541STao Ma int ret; 11163c47d541STao Ma int old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; 11173c47d541STao Ma int new_size = get_max_inline_xattr_value_size(dir, iloc); 11183c47d541STao Ma 1119471fbbeaSDaniel Rosenberg if (new_size - old_size <= ext4_dir_rec_len(1, NULL)) 11203c47d541STao Ma return -ENOSPC; 11213c47d541STao Ma 11223c47d541STao Ma ret = ext4_update_inline_data(handle, dir, 11233c47d541STao Ma new_size + EXT4_MIN_INLINE_DATA_SIZE); 11243c47d541STao Ma if (ret) 11253c47d541STao Ma return ret; 11263c47d541STao Ma 11273c47d541STao Ma ext4_update_final_de(ext4_get_inline_xattr_pos(dir, iloc), old_size, 11283c47d541STao Ma EXT4_I(dir)->i_inline_size - 11293c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE); 11303c47d541STao Ma dir->i_size = EXT4_I(dir)->i_disksize = EXT4_I(dir)->i_inline_size; 11313c47d541STao Ma return 0; 11323c47d541STao Ma } 11333c47d541STao Ma 11343c47d541STao Ma static void ext4_restore_inline_data(handle_t *handle, struct inode *inode, 11353c47d541STao Ma struct ext4_iloc *iloc, 11363c47d541STao Ma void *buf, int inline_size) 11373c47d541STao Ma { 1138897026aaSRitesh Harjani int ret; 1139897026aaSRitesh Harjani 1140897026aaSRitesh Harjani ret = ext4_create_inline_data(handle, inode, inline_size); 1141897026aaSRitesh Harjani if (ret) { 1142897026aaSRitesh Harjani ext4_msg(inode->i_sb, KERN_EMERG, 1143897026aaSRitesh Harjani "error restoring inline_data for inode -- potential data loss! (inode %lu, error %d)", 1144897026aaSRitesh Harjani inode->i_ino, ret); 1145897026aaSRitesh Harjani return; 1146897026aaSRitesh Harjani } 11473c47d541STao Ma ext4_write_inline_data(inode, iloc, buf, 0, inline_size); 11483c47d541STao Ma ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 11493c47d541STao Ma } 11503c47d541STao Ma 11513c47d541STao Ma static int ext4_finish_convert_inline_dir(handle_t *handle, 11523c47d541STao Ma struct inode *inode, 11533c47d541STao Ma struct buffer_head *dir_block, 11543c47d541STao Ma void *buf, 11553c47d541STao Ma int inline_size) 11563c47d541STao Ma { 11573c47d541STao Ma int err, csum_size = 0, header_size = 0; 11583c47d541STao Ma struct ext4_dir_entry_2 *de; 11593c47d541STao Ma void *target = dir_block->b_data; 11603c47d541STao Ma 11613c47d541STao Ma /* 11623c47d541STao Ma * First create "." and ".." and then copy the dir information 11633c47d541STao Ma * back to the block. 11643c47d541STao Ma */ 1165c30365b9SYu Zhe de = target; 11663c47d541STao Ma de = ext4_init_dot_dotdot(inode, de, 11673c47d541STao Ma inode->i_sb->s_blocksize, csum_size, 11683c47d541STao Ma le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1); 11693c47d541STao Ma header_size = (void *)de - target; 11703c47d541STao Ma 11713c47d541STao Ma memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE, 11723c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE); 11733c47d541STao Ma 11749aa5d32bSDmitry Monakhov if (ext4_has_metadata_csum(inode->i_sb)) 11753c47d541STao Ma csum_size = sizeof(struct ext4_dir_entry_tail); 11763c47d541STao Ma 11773c47d541STao Ma inode->i_size = inode->i_sb->s_blocksize; 11783c47d541STao Ma i_size_write(inode, inode->i_sb->s_blocksize); 11793c47d541STao Ma EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; 11803c47d541STao Ma ext4_update_final_de(dir_block->b_data, 11813c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size, 11823c47d541STao Ma inode->i_sb->s_blocksize - csum_size); 11833c47d541STao Ma 1184ddce3b94STheodore Ts'o if (csum_size) 1185ddce3b94STheodore Ts'o ext4_initialize_dirent_tail(dir_block, 11863c47d541STao Ma inode->i_sb->s_blocksize); 11873c47d541STao Ma set_buffer_uptodate(dir_block); 1188f4ce24f5STheodore Ts'o unlock_buffer(dir_block); 1189f036adb3STheodore Ts'o err = ext4_handle_dirty_dirblock(handle, inode, dir_block); 11903c47d541STao Ma if (err) 11913c47d541STao Ma return err; 1192b9cf625dSEric Biggers set_buffer_verified(dir_block); 1193b9cf625dSEric Biggers return ext4_mark_inode_dirty(handle, inode); 11943c47d541STao Ma } 11953c47d541STao Ma 11963c47d541STao Ma static int ext4_convert_inline_data_nolock(handle_t *handle, 11973c47d541STao Ma struct inode *inode, 11983c47d541STao Ma struct ext4_iloc *iloc) 11993c47d541STao Ma { 12003c47d541STao Ma int error; 12013c47d541STao Ma void *buf = NULL; 12023c47d541STao Ma struct buffer_head *data_bh = NULL; 12033c47d541STao Ma struct ext4_map_blocks map; 12043c47d541STao Ma int inline_size; 12053c47d541STao Ma 12063c47d541STao Ma inline_size = ext4_get_inline_size(inode); 12073c47d541STao Ma buf = kmalloc(inline_size, GFP_NOFS); 12083c47d541STao Ma if (!buf) { 12093c47d541STao Ma error = -ENOMEM; 12103c47d541STao Ma goto out; 12113c47d541STao Ma } 12123c47d541STao Ma 12133c47d541STao Ma error = ext4_read_inline_data(inode, buf, inline_size, iloc); 12143c47d541STao Ma if (error < 0) 12153c47d541STao Ma goto out; 12163c47d541STao Ma 121740b163f1SDarrick J. Wong /* 121840b163f1SDarrick J. Wong * Make sure the inline directory entries pass checks before we try to 121940b163f1SDarrick J. Wong * convert them, so that we avoid touching stuff that needs fsck. 122040b163f1SDarrick J. Wong */ 122140b163f1SDarrick J. Wong if (S_ISDIR(inode->i_mode)) { 122240b163f1SDarrick J. Wong error = ext4_check_all_de(inode, iloc->bh, 122340b163f1SDarrick J. Wong buf + EXT4_INLINE_DOTDOT_SIZE, 122440b163f1SDarrick J. Wong inline_size - EXT4_INLINE_DOTDOT_SIZE); 122540b163f1SDarrick J. Wong if (error) 122640b163f1SDarrick J. Wong goto out; 122740b163f1SDarrick J. Wong } 122840b163f1SDarrick J. Wong 12293c47d541STao Ma error = ext4_destroy_inline_data_nolock(handle, inode); 12303c47d541STao Ma if (error) 12313c47d541STao Ma goto out; 12323c47d541STao Ma 12333c47d541STao Ma map.m_lblk = 0; 12343c47d541STao Ma map.m_len = 1; 12353c47d541STao Ma map.m_flags = 0; 12363c47d541STao Ma error = ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_CREATE); 12373c47d541STao Ma if (error < 0) 12383c47d541STao Ma goto out_restore; 12393c47d541STao Ma if (!(map.m_flags & EXT4_MAP_MAPPED)) { 12403c47d541STao Ma error = -EIO; 12413c47d541STao Ma goto out_restore; 12423c47d541STao Ma } 12433c47d541STao Ma 12443c47d541STao Ma data_bh = sb_getblk(inode->i_sb, map.m_pblk); 12453c47d541STao Ma if (!data_bh) { 1246860d21e2STheodore Ts'o error = -ENOMEM; 12473c47d541STao Ma goto out_restore; 12483c47d541STao Ma } 12493c47d541STao Ma 12503c47d541STao Ma lock_buffer(data_bh); 1251188c299eSJan Kara error = ext4_journal_get_create_access(handle, inode->i_sb, data_bh, 1252188c299eSJan Kara EXT4_JTR_NONE); 12533c47d541STao Ma if (error) { 12543c47d541STao Ma unlock_buffer(data_bh); 12553c47d541STao Ma error = -EIO; 12563c47d541STao Ma goto out_restore; 12573c47d541STao Ma } 12583c47d541STao Ma memset(data_bh->b_data, 0, inode->i_sb->s_blocksize); 12593c47d541STao Ma 12603c47d541STao Ma if (!S_ISDIR(inode->i_mode)) { 12613c47d541STao Ma memcpy(data_bh->b_data, buf, inline_size); 12623c47d541STao Ma set_buffer_uptodate(data_bh); 1263f4ce24f5STheodore Ts'o unlock_buffer(data_bh); 12643c47d541STao Ma error = ext4_handle_dirty_metadata(handle, 12653c47d541STao Ma inode, data_bh); 12663c47d541STao Ma } else { 12673c47d541STao Ma error = ext4_finish_convert_inline_dir(handle, inode, data_bh, 12683c47d541STao Ma buf, inline_size); 12693c47d541STao Ma } 12703c47d541STao Ma 12713c47d541STao Ma out_restore: 12723c47d541STao Ma if (error) 12733c47d541STao Ma ext4_restore_inline_data(handle, inode, iloc, buf, inline_size); 12743c47d541STao Ma 12753c47d541STao Ma out: 12763c47d541STao Ma brelse(data_bh); 12773c47d541STao Ma kfree(buf); 12783c47d541STao Ma return error; 12793c47d541STao Ma } 12803c47d541STao Ma 12813c47d541STao Ma /* 12823c47d541STao Ma * Try to add the new entry to the inline data. 12833c47d541STao Ma * If succeeds, return 0. If not, extended the inline dir and copied data to 12843c47d541STao Ma * the new created block. 12853c47d541STao Ma */ 12865b643f9cSTheodore Ts'o int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, 128756a04915STheodore Ts'o struct inode *dir, struct inode *inode) 12883c47d541STao Ma { 12894209ae12SHarshad Shirwadkar int ret, ret2, inline_size, no_expand; 12903c47d541STao Ma void *inline_start; 12913c47d541STao Ma struct ext4_iloc iloc; 12923c47d541STao Ma 12933c47d541STao Ma ret = ext4_get_inode_loc(dir, &iloc); 12943c47d541STao Ma if (ret) 12953c47d541STao Ma return ret; 12963c47d541STao Ma 1297c755e251STheodore Ts'o ext4_write_lock_xattr(dir, &no_expand); 12983c47d541STao Ma if (!ext4_has_inline_data(dir)) 12993c47d541STao Ma goto out; 13003c47d541STao Ma 13013c47d541STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 13023c47d541STao Ma EXT4_INLINE_DOTDOT_SIZE; 13033c47d541STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; 13043c47d541STao Ma 130556a04915STheodore Ts'o ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, 13063c47d541STao Ma inline_start, inline_size); 13073c47d541STao Ma if (ret != -ENOSPC) 13083c47d541STao Ma goto out; 13093c47d541STao Ma 13103c47d541STao Ma /* check whether it can be inserted to inline xattr space. */ 13113c47d541STao Ma inline_size = EXT4_I(dir)->i_inline_size - 13123c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE; 13133c47d541STao Ma if (!inline_size) { 13143c47d541STao Ma /* Try to use the xattr space.*/ 13153c47d541STao Ma ret = ext4_update_inline_dir(handle, dir, &iloc); 13163c47d541STao Ma if (ret && ret != -ENOSPC) 13173c47d541STao Ma goto out; 13183c47d541STao Ma 13193c47d541STao Ma inline_size = EXT4_I(dir)->i_inline_size - 13203c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE; 13213c47d541STao Ma } 13223c47d541STao Ma 13233c47d541STao Ma if (inline_size) { 13243c47d541STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 13253c47d541STao Ma 132656a04915STheodore Ts'o ret = ext4_add_dirent_to_inline(handle, fname, dir, 13275b643f9cSTheodore Ts'o inode, &iloc, inline_start, 13285b643f9cSTheodore Ts'o inline_size); 13293c47d541STao Ma 13303c47d541STao Ma if (ret != -ENOSPC) 13313c47d541STao Ma goto out; 13323c47d541STao Ma } 13333c47d541STao Ma 13343c47d541STao Ma /* 13353c47d541STao Ma * The inline space is filled up, so create a new block for it. 13363c47d541STao Ma * As the extent tree will be created, we have to save the inline 13373c47d541STao Ma * dir first. 13383c47d541STao Ma */ 13393c47d541STao Ma ret = ext4_convert_inline_data_nolock(handle, dir, &iloc); 13403c47d541STao Ma 13413c47d541STao Ma out: 1342c755e251STheodore Ts'o ext4_write_unlock_xattr(dir, &no_expand); 13434209ae12SHarshad Shirwadkar ret2 = ext4_mark_inode_dirty(handle, dir); 13444209ae12SHarshad Shirwadkar if (unlikely(ret2 && !ret)) 13454209ae12SHarshad Shirwadkar ret = ret2; 13463c47d541STao Ma brelse(iloc.bh); 13473c47d541STao Ma return ret; 13483c47d541STao Ma } 13493c47d541STao Ma 13508af0f082STao Ma /* 13518af0f082STao Ma * This function fills a red-black tree with information from an 13528af0f082STao Ma * inlined dir. It returns the number directory entries loaded 13538af0f082STao Ma * into the tree. If there is an error it is returned in err. 13548af0f082STao Ma */ 13557633b08bSTheodore Ts'o int ext4_inlinedir_to_tree(struct file *dir_file, 13568af0f082STao Ma struct inode *dir, ext4_lblk_t block, 13578af0f082STao Ma struct dx_hash_info *hinfo, 13588af0f082STao Ma __u32 start_hash, __u32 start_minor_hash, 13598af0f082STao Ma int *has_inline_data) 13608af0f082STao Ma { 13618af0f082STao Ma int err = 0, count = 0; 13628af0f082STao Ma unsigned int parent_ino; 13638af0f082STao Ma int pos; 13648af0f082STao Ma struct ext4_dir_entry_2 *de; 13658af0f082STao Ma struct inode *inode = file_inode(dir_file); 13668af0f082STao Ma int ret, inline_size = 0; 13678af0f082STao Ma struct ext4_iloc iloc; 13688af0f082STao Ma void *dir_buf = NULL; 13698af0f082STao Ma struct ext4_dir_entry_2 fake; 1370a7550b30SJaegeuk Kim struct fscrypt_str tmp_str; 13718af0f082STao Ma 13728af0f082STao Ma ret = ext4_get_inode_loc(inode, &iloc); 13738af0f082STao Ma if (ret) 13748af0f082STao Ma return ret; 13758af0f082STao Ma 13768af0f082STao Ma down_read(&EXT4_I(inode)->xattr_sem); 13778af0f082STao Ma if (!ext4_has_inline_data(inode)) { 13788af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13798af0f082STao Ma *has_inline_data = 0; 13808af0f082STao Ma goto out; 13818af0f082STao Ma } 13828af0f082STao Ma 13838af0f082STao Ma inline_size = ext4_get_inline_size(inode); 13848af0f082STao Ma dir_buf = kmalloc(inline_size, GFP_NOFS); 13858af0f082STao Ma if (!dir_buf) { 13868af0f082STao Ma ret = -ENOMEM; 13878af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13888af0f082STao Ma goto out; 13898af0f082STao Ma } 13908af0f082STao Ma 13918af0f082STao Ma ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); 13928af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13938af0f082STao Ma if (ret < 0) 13948af0f082STao Ma goto out; 13958af0f082STao Ma 13968af0f082STao Ma pos = 0; 13978af0f082STao Ma parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 13988af0f082STao Ma while (pos < inline_size) { 13998af0f082STao Ma /* 14008af0f082STao Ma * As inlined dir doesn't store any information about '.' and 14018af0f082STao Ma * only the inode number of '..' is stored, we have to handle 14028af0f082STao Ma * them differently. 14038af0f082STao Ma */ 14048af0f082STao Ma if (pos == 0) { 14058af0f082STao Ma fake.inode = cpu_to_le32(inode->i_ino); 14068af0f082STao Ma fake.name_len = 1; 14078af0f082STao Ma strcpy(fake.name, "."); 14088af0f082STao Ma fake.rec_len = ext4_rec_len_to_disk( 1409471fbbeaSDaniel Rosenberg ext4_dir_rec_len(fake.name_len, NULL), 14108af0f082STao Ma inline_size); 14118af0f082STao Ma ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); 14128af0f082STao Ma de = &fake; 14138af0f082STao Ma pos = EXT4_INLINE_DOTDOT_OFFSET; 14148af0f082STao Ma } else if (pos == EXT4_INLINE_DOTDOT_OFFSET) { 14158af0f082STao Ma fake.inode = cpu_to_le32(parent_ino); 14168af0f082STao Ma fake.name_len = 2; 14178af0f082STao Ma strcpy(fake.name, ".."); 14188af0f082STao Ma fake.rec_len = ext4_rec_len_to_disk( 1419471fbbeaSDaniel Rosenberg ext4_dir_rec_len(fake.name_len, NULL), 14208af0f082STao Ma inline_size); 14218af0f082STao Ma ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); 14228af0f082STao Ma de = &fake; 14238af0f082STao Ma pos = EXT4_INLINE_DOTDOT_SIZE; 14248af0f082STao Ma } else { 14258af0f082STao Ma de = (struct ext4_dir_entry_2 *)(dir_buf + pos); 14268af0f082STao Ma pos += ext4_rec_len_from_disk(de->rec_len, inline_size); 14278af0f082STao Ma if (ext4_check_dir_entry(inode, dir_file, de, 14288af0f082STao Ma iloc.bh, dir_buf, 14298af0f082STao Ma inline_size, pos)) { 14308af0f082STao Ma ret = count; 14318af0f082STao Ma goto out; 14328af0f082STao Ma } 14338af0f082STao Ma } 14348af0f082STao Ma 1435471fbbeaSDaniel Rosenberg if (ext4_hash_in_dirent(dir)) { 1436471fbbeaSDaniel Rosenberg hinfo->hash = EXT4_DIRENT_HASH(de); 1437471fbbeaSDaniel Rosenberg hinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de); 1438471fbbeaSDaniel Rosenberg } else { 1439b886ee3eSGabriel Krisman Bertazi ext4fs_dirhash(dir, de->name, de->name_len, hinfo); 1440471fbbeaSDaniel Rosenberg } 14418af0f082STao Ma if ((hinfo->hash < start_hash) || 14428af0f082STao Ma ((hinfo->hash == start_hash) && 14438af0f082STao Ma (hinfo->minor_hash < start_minor_hash))) 14448af0f082STao Ma continue; 14458af0f082STao Ma if (de->inode == 0) 14468af0f082STao Ma continue; 14472f61830aSTheodore Ts'o tmp_str.name = de->name; 14482f61830aSTheodore Ts'o tmp_str.len = de->name_len; 14492f61830aSTheodore Ts'o err = ext4_htree_store_dirent(dir_file, hinfo->hash, 14502f61830aSTheodore Ts'o hinfo->minor_hash, de, &tmp_str); 14518af0f082STao Ma if (err) { 14527a14826eSColin Ian King ret = err; 14538af0f082STao Ma goto out; 14548af0f082STao Ma } 14558af0f082STao Ma count++; 14568af0f082STao Ma } 14578af0f082STao Ma ret = count; 14588af0f082STao Ma out: 14598af0f082STao Ma kfree(dir_buf); 14608af0f082STao Ma brelse(iloc.bh); 14618af0f082STao Ma return ret; 14628af0f082STao Ma } 14638af0f082STao Ma 1464c4d8b023STao Ma /* 1465c4d8b023STao Ma * So this function is called when the volume is mkfsed with 1466c4d8b023STao Ma * dir_index disabled. In order to keep f_pos persistent 1467c4d8b023STao Ma * after we convert from an inlined dir to a blocked based, 1468c4d8b023STao Ma * we just pretend that we are a normal dir and return the 1469c4d8b023STao Ma * offset as if '.' and '..' really take place. 1470c4d8b023STao Ma * 1471c4d8b023STao Ma */ 1472725bebb2SAl Viro int ext4_read_inline_dir(struct file *file, 1473725bebb2SAl Viro struct dir_context *ctx, 147465d165d9STao Ma int *has_inline_data) 147565d165d9STao Ma { 147665d165d9STao Ma unsigned int offset, parent_ino; 1477725bebb2SAl Viro int i; 147865d165d9STao Ma struct ext4_dir_entry_2 *de; 147965d165d9STao Ma struct super_block *sb; 1480725bebb2SAl Viro struct inode *inode = file_inode(file); 148165d165d9STao Ma int ret, inline_size = 0; 148265d165d9STao Ma struct ext4_iloc iloc; 148365d165d9STao Ma void *dir_buf = NULL; 1484c4d8b023STao Ma int dotdot_offset, dotdot_size, extra_offset, extra_size; 148565d165d9STao Ma 148665d165d9STao Ma ret = ext4_get_inode_loc(inode, &iloc); 148765d165d9STao Ma if (ret) 148865d165d9STao Ma return ret; 148965d165d9STao Ma 149065d165d9STao Ma down_read(&EXT4_I(inode)->xattr_sem); 149165d165d9STao Ma if (!ext4_has_inline_data(inode)) { 149265d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 149365d165d9STao Ma *has_inline_data = 0; 149465d165d9STao Ma goto out; 149565d165d9STao Ma } 149665d165d9STao Ma 149765d165d9STao Ma inline_size = ext4_get_inline_size(inode); 149865d165d9STao Ma dir_buf = kmalloc(inline_size, GFP_NOFS); 149965d165d9STao Ma if (!dir_buf) { 150065d165d9STao Ma ret = -ENOMEM; 150165d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 150265d165d9STao Ma goto out; 150365d165d9STao Ma } 150465d165d9STao Ma 150565d165d9STao Ma ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); 150665d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 150765d165d9STao Ma if (ret < 0) 150865d165d9STao Ma goto out; 150965d165d9STao Ma 151048ffdab1SBoxiLiu ret = 0; 151165d165d9STao Ma sb = inode->i_sb; 151265d165d9STao Ma parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 1513725bebb2SAl Viro offset = ctx->pos; 151465d165d9STao Ma 1515c4d8b023STao Ma /* 1516c4d8b023STao Ma * dotdot_offset and dotdot_size is the real offset and 1517c4d8b023STao Ma * size for ".." and "." if the dir is block based while 1518c4d8b023STao Ma * the real size for them are only EXT4_INLINE_DOTDOT_SIZE. 1519c4d8b023STao Ma * So we will use extra_offset and extra_size to indicate them 1520c4d8b023STao Ma * during the inline dir iteration. 1521c4d8b023STao Ma */ 1522471fbbeaSDaniel Rosenberg dotdot_offset = ext4_dir_rec_len(1, NULL); 1523471fbbeaSDaniel Rosenberg dotdot_size = dotdot_offset + ext4_dir_rec_len(2, NULL); 1524c4d8b023STao Ma extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; 1525c4d8b023STao Ma extra_size = extra_offset + inline_size; 1526c4d8b023STao Ma 152765d165d9STao Ma /* 152865d165d9STao Ma * If the version has changed since the last call to 152965d165d9STao Ma * readdir(2), then we might be pointing to an invalid 153065d165d9STao Ma * dirent right now. Scan from the start of the inline 153165d165d9STao Ma * dir to make sure. 153265d165d9STao Ma */ 1533c472c07bSGoffredo Baroncelli if (!inode_eq_iversion(inode, file->f_version)) { 1534c4d8b023STao Ma for (i = 0; i < extra_size && i < offset;) { 1535c4d8b023STao Ma /* 1536c4d8b023STao Ma * "." is with offset 0 and 1537c4d8b023STao Ma * ".." is dotdot_offset. 1538c4d8b023STao Ma */ 153965d165d9STao Ma if (!i) { 1540c4d8b023STao Ma i = dotdot_offset; 1541c4d8b023STao Ma continue; 1542c4d8b023STao Ma } else if (i == dotdot_offset) { 1543c4d8b023STao Ma i = dotdot_size; 154465d165d9STao Ma continue; 154565d165d9STao Ma } 1546c4d8b023STao Ma /* for other entry, the real offset in 1547c4d8b023STao Ma * the buf has to be tuned accordingly. 1548c4d8b023STao Ma */ 154965d165d9STao Ma de = (struct ext4_dir_entry_2 *) 1550c4d8b023STao Ma (dir_buf + i - extra_offset); 155165d165d9STao Ma /* It's too expensive to do a full 155265d165d9STao Ma * dirent test each time round this 155365d165d9STao Ma * loop, but we do have to test at 155465d165d9STao Ma * least that it is non-zero. A 155565d165d9STao Ma * failure will be detected in the 155665d165d9STao Ma * dirent test below. */ 1557725bebb2SAl Viro if (ext4_rec_len_from_disk(de->rec_len, extra_size) 1558471fbbeaSDaniel Rosenberg < ext4_dir_rec_len(1, NULL)) 155965d165d9STao Ma break; 156065d165d9STao Ma i += ext4_rec_len_from_disk(de->rec_len, 1561c4d8b023STao Ma extra_size); 156265d165d9STao Ma } 156365d165d9STao Ma offset = i; 1564725bebb2SAl Viro ctx->pos = offset; 1565ee73f9a5SJeff Layton file->f_version = inode_query_iversion(inode); 156665d165d9STao Ma } 156765d165d9STao Ma 1568725bebb2SAl Viro while (ctx->pos < extra_size) { 1569725bebb2SAl Viro if (ctx->pos == 0) { 1570725bebb2SAl Viro if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 1571725bebb2SAl Viro goto out; 1572725bebb2SAl Viro ctx->pos = dotdot_offset; 1573c4d8b023STao Ma continue; 1574c4d8b023STao Ma } 157565d165d9STao Ma 1576725bebb2SAl Viro if (ctx->pos == dotdot_offset) { 1577725bebb2SAl Viro if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR)) 1578725bebb2SAl Viro goto out; 1579725bebb2SAl Viro ctx->pos = dotdot_size; 158065d165d9STao Ma continue; 158165d165d9STao Ma } 158265d165d9STao Ma 1583c4d8b023STao Ma de = (struct ext4_dir_entry_2 *) 1584725bebb2SAl Viro (dir_buf + ctx->pos - extra_offset); 1585725bebb2SAl Viro if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf, 1586725bebb2SAl Viro extra_size, ctx->pos)) 1587725bebb2SAl Viro goto out; 1588725bebb2SAl Viro if (le32_to_cpu(de->inode)) { 1589725bebb2SAl Viro if (!dir_emit(ctx, de->name, de->name_len, 1590725bebb2SAl Viro le32_to_cpu(de->inode), 1591725bebb2SAl Viro get_dtype(sb, de->file_type))) 159265d165d9STao Ma goto out; 159365d165d9STao Ma } 1594725bebb2SAl Viro ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size); 159565d165d9STao Ma } 159665d165d9STao Ma out: 159765d165d9STao Ma kfree(dir_buf); 159865d165d9STao Ma brelse(iloc.bh); 159965d165d9STao Ma return ret; 160065d165d9STao Ma } 160165d165d9STao Ma 16025a57bca9SZhang Yi void *ext4_read_inline_link(struct inode *inode) 16035a57bca9SZhang Yi { 16045a57bca9SZhang Yi struct ext4_iloc iloc; 16055a57bca9SZhang Yi int ret, inline_size; 16065a57bca9SZhang Yi void *link; 16075a57bca9SZhang Yi 16085a57bca9SZhang Yi ret = ext4_get_inode_loc(inode, &iloc); 16095a57bca9SZhang Yi if (ret) 16105a57bca9SZhang Yi return ERR_PTR(ret); 16115a57bca9SZhang Yi 16125a57bca9SZhang Yi ret = -ENOMEM; 16135a57bca9SZhang Yi inline_size = ext4_get_inline_size(inode); 16145a57bca9SZhang Yi link = kmalloc(inline_size + 1, GFP_NOFS); 16155a57bca9SZhang Yi if (!link) 16165a57bca9SZhang Yi goto out; 16175a57bca9SZhang Yi 16185a57bca9SZhang Yi ret = ext4_read_inline_data(inode, link, inline_size, &iloc); 16195a57bca9SZhang Yi if (ret < 0) { 16205a57bca9SZhang Yi kfree(link); 16215a57bca9SZhang Yi goto out; 16225a57bca9SZhang Yi } 16235a57bca9SZhang Yi nd_terminate_link(link, inode->i_size, ret); 16245a57bca9SZhang Yi out: 16255a57bca9SZhang Yi if (ret < 0) 16265a57bca9SZhang Yi link = ERR_PTR(ret); 16275a57bca9SZhang Yi brelse(iloc.bh); 16285a57bca9SZhang Yi return link; 16295a57bca9SZhang Yi } 16305a57bca9SZhang Yi 163132f7f22cSTao Ma struct buffer_head *ext4_get_first_inline_block(struct inode *inode, 163232f7f22cSTao Ma struct ext4_dir_entry_2 **parent_de, 163332f7f22cSTao Ma int *retval) 163432f7f22cSTao Ma { 163532f7f22cSTao Ma struct ext4_iloc iloc; 163632f7f22cSTao Ma 163732f7f22cSTao Ma *retval = ext4_get_inode_loc(inode, &iloc); 163832f7f22cSTao Ma if (*retval) 163932f7f22cSTao Ma return NULL; 164032f7f22cSTao Ma 164132f7f22cSTao Ma *parent_de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 164232f7f22cSTao Ma 164332f7f22cSTao Ma return iloc.bh; 164432f7f22cSTao Ma } 164532f7f22cSTao Ma 16463c47d541STao Ma /* 16473c47d541STao Ma * Try to create the inline data for the new dir. 16483c47d541STao Ma * If it succeeds, return 0, otherwise return the error. 16493c47d541STao Ma * In case of ENOSPC, the caller should create the normal disk layout dir. 16503c47d541STao Ma */ 16513c47d541STao Ma int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent, 16523c47d541STao Ma struct inode *inode) 16533c47d541STao Ma { 16543c47d541STao Ma int ret, inline_size = EXT4_MIN_INLINE_DATA_SIZE; 16553c47d541STao Ma struct ext4_iloc iloc; 16563c47d541STao Ma struct ext4_dir_entry_2 *de; 16573c47d541STao Ma 16583c47d541STao Ma ret = ext4_get_inode_loc(inode, &iloc); 16593c47d541STao Ma if (ret) 16603c47d541STao Ma return ret; 16613c47d541STao Ma 16623c47d541STao Ma ret = ext4_prepare_inline_data(handle, inode, inline_size); 16633c47d541STao Ma if (ret) 16643c47d541STao Ma goto out; 16653c47d541STao Ma 16663c47d541STao Ma /* 16673c47d541STao Ma * For inline dir, we only save the inode information for the ".." 16683c47d541STao Ma * and create a fake dentry to cover the left space. 16693c47d541STao Ma */ 16703c47d541STao Ma de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 16713c47d541STao Ma de->inode = cpu_to_le32(parent->i_ino); 16723c47d541STao Ma de = (struct ext4_dir_entry_2 *)((void *)de + EXT4_INLINE_DOTDOT_SIZE); 16733c47d541STao Ma de->inode = 0; 16743c47d541STao Ma de->rec_len = ext4_rec_len_to_disk( 16753c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE, 16763c47d541STao Ma inline_size); 16773c47d541STao Ma set_nlink(inode, 2); 16783c47d541STao Ma inode->i_size = EXT4_I(inode)->i_disksize = inline_size; 16793c47d541STao Ma out: 16803c47d541STao Ma brelse(iloc.bh); 16813c47d541STao Ma return ret; 16823c47d541STao Ma } 16833c47d541STao Ma 1684e8e948e7STao Ma struct buffer_head *ext4_find_inline_entry(struct inode *dir, 16855b643f9cSTheodore Ts'o struct ext4_filename *fname, 1686e8e948e7STao Ma struct ext4_dir_entry_2 **res_dir, 1687e8e948e7STao Ma int *has_inline_data) 1688e8e948e7STao Ma { 1689e8e948e7STao Ma int ret; 1690e8e948e7STao Ma struct ext4_iloc iloc; 1691e8e948e7STao Ma void *inline_start; 1692e8e948e7STao Ma int inline_size; 1693e8e948e7STao Ma 1694e8e948e7STao Ma if (ext4_get_inode_loc(dir, &iloc)) 1695e8e948e7STao Ma return NULL; 1696e8e948e7STao Ma 1697e8e948e7STao Ma down_read(&EXT4_I(dir)->xattr_sem); 1698e8e948e7STao Ma if (!ext4_has_inline_data(dir)) { 1699e8e948e7STao Ma *has_inline_data = 0; 1700e8e948e7STao Ma goto out; 1701e8e948e7STao Ma } 1702e8e948e7STao Ma 1703e8e948e7STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 1704e8e948e7STao Ma EXT4_INLINE_DOTDOT_SIZE; 1705e8e948e7STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; 17065b643f9cSTheodore Ts'o ret = ext4_search_dir(iloc.bh, inline_start, inline_size, 1707d6b97550SEric Biggers dir, fname, 0, res_dir); 1708e8e948e7STao Ma if (ret == 1) 1709e8e948e7STao Ma goto out_find; 1710e8e948e7STao Ma if (ret < 0) 1711e8e948e7STao Ma goto out; 1712e8e948e7STao Ma 1713e8e948e7STao Ma if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE) 1714e8e948e7STao Ma goto out; 1715e8e948e7STao Ma 1716e8e948e7STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 1717e8e948e7STao Ma inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE; 1718e8e948e7STao Ma 17195b643f9cSTheodore Ts'o ret = ext4_search_dir(iloc.bh, inline_start, inline_size, 1720d6b97550SEric Biggers dir, fname, 0, res_dir); 1721e8e948e7STao Ma if (ret == 1) 1722e8e948e7STao Ma goto out_find; 1723e8e948e7STao Ma 1724e8e948e7STao Ma out: 1725e8e948e7STao Ma brelse(iloc.bh); 1726e8e948e7STao Ma iloc.bh = NULL; 1727e8e948e7STao Ma out_find: 1728e8e948e7STao Ma up_read(&EXT4_I(dir)->xattr_sem); 1729e8e948e7STao Ma return iloc.bh; 1730e8e948e7STao Ma } 1731e8e948e7STao Ma 17329f40fe54STao Ma int ext4_delete_inline_entry(handle_t *handle, 17339f40fe54STao Ma struct inode *dir, 17349f40fe54STao Ma struct ext4_dir_entry_2 *de_del, 17359f40fe54STao Ma struct buffer_head *bh, 17369f40fe54STao Ma int *has_inline_data) 17379f40fe54STao Ma { 1738c755e251STheodore Ts'o int err, inline_size, no_expand; 17399f40fe54STao Ma struct ext4_iloc iloc; 17409f40fe54STao Ma void *inline_start; 17419f40fe54STao Ma 17429f40fe54STao Ma err = ext4_get_inode_loc(dir, &iloc); 17439f40fe54STao Ma if (err) 17449f40fe54STao Ma return err; 17459f40fe54STao Ma 1746c755e251STheodore Ts'o ext4_write_lock_xattr(dir, &no_expand); 17479f40fe54STao Ma if (!ext4_has_inline_data(dir)) { 17489f40fe54STao Ma *has_inline_data = 0; 17499f40fe54STao Ma goto out; 17509f40fe54STao Ma } 17519f40fe54STao Ma 17529f40fe54STao Ma if ((void *)de_del - ((void *)ext4_raw_inode(&iloc)->i_block) < 17539f40fe54STao Ma EXT4_MIN_INLINE_DATA_SIZE) { 17549f40fe54STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 17559f40fe54STao Ma EXT4_INLINE_DOTDOT_SIZE; 17569f40fe54STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - 17579f40fe54STao Ma EXT4_INLINE_DOTDOT_SIZE; 17589f40fe54STao Ma } else { 17599f40fe54STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 17609f40fe54STao Ma inline_size = ext4_get_inline_size(dir) - 17619f40fe54STao Ma EXT4_MIN_INLINE_DATA_SIZE; 17629f40fe54STao Ma } 17639f40fe54STao Ma 17645d601255Sliang xie BUFFER_TRACE(bh, "get_write_access"); 1765188c299eSJan Kara err = ext4_journal_get_write_access(handle, dir->i_sb, bh, 1766188c299eSJan Kara EXT4_JTR_NONE); 17679f40fe54STao Ma if (err) 17689f40fe54STao Ma goto out; 17699f40fe54STao Ma 17702fe34d29SKyoungho Koo err = ext4_generic_delete_entry(dir, de_del, bh, 17719f40fe54STao Ma inline_start, inline_size, 0); 17729f40fe54STao Ma if (err) 17739f40fe54STao Ma goto out; 17749f40fe54STao Ma 17759f40fe54STao Ma ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size); 17769f40fe54STao Ma out: 1777c755e251STheodore Ts'o ext4_write_unlock_xattr(dir, &no_expand); 1778b907f2d5STheodore Ts'o if (likely(err == 0)) 1779b907f2d5STheodore Ts'o err = ext4_mark_inode_dirty(handle, dir); 17809f40fe54STao Ma brelse(iloc.bh); 17819f40fe54STao Ma if (err != -ENOENT) 17829f40fe54STao Ma ext4_std_error(dir->i_sb, err); 17839f40fe54STao Ma return err; 17849f40fe54STao Ma } 17859f40fe54STao Ma 178661f86638STao Ma /* 178761f86638STao Ma * Get the inline dentry at offset. 178861f86638STao Ma */ 178961f86638STao Ma static inline struct ext4_dir_entry_2 * 179061f86638STao Ma ext4_get_inline_entry(struct inode *inode, 179161f86638STao Ma struct ext4_iloc *iloc, 179261f86638STao Ma unsigned int offset, 179361f86638STao Ma void **inline_start, 179461f86638STao Ma int *inline_size) 179561f86638STao Ma { 179661f86638STao Ma void *inline_pos; 179761f86638STao Ma 179861f86638STao Ma BUG_ON(offset > ext4_get_inline_size(inode)); 179961f86638STao Ma 180061f86638STao Ma if (offset < EXT4_MIN_INLINE_DATA_SIZE) { 180161f86638STao Ma inline_pos = (void *)ext4_raw_inode(iloc)->i_block; 180261f86638STao Ma *inline_size = EXT4_MIN_INLINE_DATA_SIZE; 180361f86638STao Ma } else { 180461f86638STao Ma inline_pos = ext4_get_inline_xattr_pos(inode, iloc); 180561f86638STao Ma offset -= EXT4_MIN_INLINE_DATA_SIZE; 180661f86638STao Ma *inline_size = ext4_get_inline_size(inode) - 180761f86638STao Ma EXT4_MIN_INLINE_DATA_SIZE; 180861f86638STao Ma } 180961f86638STao Ma 181061f86638STao Ma if (inline_start) 181161f86638STao Ma *inline_start = inline_pos; 181261f86638STao Ma return (struct ext4_dir_entry_2 *)(inline_pos + offset); 181361f86638STao Ma } 181461f86638STao Ma 1815a7550b30SJaegeuk Kim bool empty_inline_dir(struct inode *dir, int *has_inline_data) 181661f86638STao Ma { 181761f86638STao Ma int err, inline_size; 181861f86638STao Ma struct ext4_iloc iloc; 18194d982e25STheodore Ts'o size_t inline_len; 182061f86638STao Ma void *inline_pos; 182161f86638STao Ma unsigned int offset; 182261f86638STao Ma struct ext4_dir_entry_2 *de; 18237aab5c84SYe Bin bool ret = false; 182461f86638STao Ma 182561f86638STao Ma err = ext4_get_inode_loc(dir, &iloc); 182661f86638STao Ma if (err) { 182754d3adbcSTheodore Ts'o EXT4_ERROR_INODE_ERR(dir, -err, 182854d3adbcSTheodore Ts'o "error %d getting inode %lu block", 182961f86638STao Ma err, dir->i_ino); 18307aab5c84SYe Bin return false; 183161f86638STao Ma } 183261f86638STao Ma 183361f86638STao Ma down_read(&EXT4_I(dir)->xattr_sem); 183461f86638STao Ma if (!ext4_has_inline_data(dir)) { 183561f86638STao Ma *has_inline_data = 0; 18367aab5c84SYe Bin ret = true; 183761f86638STao Ma goto out; 183861f86638STao Ma } 183961f86638STao Ma 184061f86638STao Ma de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 184161f86638STao Ma if (!le32_to_cpu(de->inode)) { 184261f86638STao Ma ext4_warning(dir->i_sb, 184361f86638STao Ma "bad inline directory (dir #%lu) - no `..'", 184461f86638STao Ma dir->i_ino); 184561f86638STao Ma goto out; 184661f86638STao Ma } 184761f86638STao Ma 18484d982e25STheodore Ts'o inline_len = ext4_get_inline_size(dir); 184961f86638STao Ma offset = EXT4_INLINE_DOTDOT_SIZE; 18504d982e25STheodore Ts'o while (offset < inline_len) { 185161f86638STao Ma de = ext4_get_inline_entry(dir, &iloc, offset, 185261f86638STao Ma &inline_pos, &inline_size); 185361f86638STao Ma if (ext4_check_dir_entry(dir, NULL, de, 185461f86638STao Ma iloc.bh, inline_pos, 185561f86638STao Ma inline_size, offset)) { 185661f86638STao Ma ext4_warning(dir->i_sb, 185761f86638STao Ma "bad inline directory (dir #%lu) - " 185861f86638STao Ma "inode %u, rec_len %u, name_len %d" 18598d2ae1cbSJakub Wilk "inline size %d", 186061f86638STao Ma dir->i_ino, le32_to_cpu(de->inode), 186161f86638STao Ma le16_to_cpu(de->rec_len), de->name_len, 186261f86638STao Ma inline_size); 186361f86638STao Ma goto out; 186461f86638STao Ma } 186561f86638STao Ma if (le32_to_cpu(de->inode)) { 186661f86638STao Ma goto out; 186761f86638STao Ma } 186861f86638STao Ma offset += ext4_rec_len_from_disk(de->rec_len, inline_size); 186961f86638STao Ma } 187061f86638STao Ma 18717aab5c84SYe Bin ret = true; 187261f86638STao Ma out: 187361f86638STao Ma up_read(&EXT4_I(dir)->xattr_sem); 187461f86638STao Ma brelse(iloc.bh); 187561f86638STao Ma return ret; 187661f86638STao Ma } 187761f86638STao Ma 187867cf5b09STao Ma int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) 187967cf5b09STao Ma { 1880c755e251STheodore Ts'o int ret, no_expand; 188167cf5b09STao Ma 1882c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 188367cf5b09STao Ma ret = ext4_destroy_inline_data_nolock(handle, inode); 1884c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 188567cf5b09STao Ma 188667cf5b09STao Ma return ret; 188767cf5b09STao Ma } 188894191985STao Ma 18897046ae35SAndreas Gruenbacher int ext4_inline_data_iomap(struct inode *inode, struct iomap *iomap) 18907046ae35SAndreas Gruenbacher { 18917046ae35SAndreas Gruenbacher __u64 addr; 18927046ae35SAndreas Gruenbacher int error = -EAGAIN; 18937046ae35SAndreas Gruenbacher struct ext4_iloc iloc; 18947046ae35SAndreas Gruenbacher 18957046ae35SAndreas Gruenbacher down_read(&EXT4_I(inode)->xattr_sem); 18967046ae35SAndreas Gruenbacher if (!ext4_has_inline_data(inode)) 18977046ae35SAndreas Gruenbacher goto out; 18987046ae35SAndreas Gruenbacher 18997046ae35SAndreas Gruenbacher error = ext4_get_inode_loc(inode, &iloc); 19007046ae35SAndreas Gruenbacher if (error) 19017046ae35SAndreas Gruenbacher goto out; 19027046ae35SAndreas Gruenbacher 19037046ae35SAndreas Gruenbacher addr = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; 19047046ae35SAndreas Gruenbacher addr += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; 19057046ae35SAndreas Gruenbacher addr += offsetof(struct ext4_inode, i_block); 19067046ae35SAndreas Gruenbacher 19077046ae35SAndreas Gruenbacher brelse(iloc.bh); 19087046ae35SAndreas Gruenbacher 19097046ae35SAndreas Gruenbacher iomap->addr = addr; 19107046ae35SAndreas Gruenbacher iomap->offset = 0; 19117046ae35SAndreas Gruenbacher iomap->length = min_t(loff_t, ext4_get_inline_size(inode), 19127046ae35SAndreas Gruenbacher i_size_read(inode)); 191319319b53SChristoph Hellwig iomap->type = IOMAP_INLINE; 191419319b53SChristoph Hellwig iomap->flags = 0; 19157046ae35SAndreas Gruenbacher 19167046ae35SAndreas Gruenbacher out: 19177046ae35SAndreas Gruenbacher up_read(&EXT4_I(inode)->xattr_sem); 19187046ae35SAndreas Gruenbacher return error; 19197046ae35SAndreas Gruenbacher } 19207046ae35SAndreas Gruenbacher 192101daf945STheodore Ts'o int ext4_inline_data_truncate(struct inode *inode, int *has_inline) 1922aef1c851STao Ma { 1923aef1c851STao Ma handle_t *handle; 192401daf945STheodore Ts'o int inline_size, value_len, needed_blocks, no_expand, err = 0; 1925aef1c851STao Ma size_t i_size; 1926aef1c851STao Ma void *value = NULL; 1927aef1c851STao Ma struct ext4_xattr_ibody_find is = { 1928aef1c851STao Ma .s = { .not_found = -ENODATA, }, 1929aef1c851STao Ma }; 1930aef1c851STao Ma struct ext4_xattr_info i = { 1931aef1c851STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 1932aef1c851STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 1933aef1c851STao Ma }; 1934aef1c851STao Ma 1935aef1c851STao Ma 1936aef1c851STao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 19379924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, needed_blocks); 1938aef1c851STao Ma if (IS_ERR(handle)) 193901daf945STheodore Ts'o return PTR_ERR(handle); 1940aef1c851STao Ma 1941c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 1942aef1c851STao Ma if (!ext4_has_inline_data(inode)) { 19437067b261SJoseph Qi ext4_write_unlock_xattr(inode, &no_expand); 1944aef1c851STao Ma *has_inline = 0; 1945aef1c851STao Ma ext4_journal_stop(handle); 194601daf945STheodore Ts'o return 0; 1947aef1c851STao Ma } 1948aef1c851STao Ma 194901daf945STheodore Ts'o if ((err = ext4_orphan_add(handle, inode)) != 0) 1950aef1c851STao Ma goto out; 1951aef1c851STao Ma 195201daf945STheodore Ts'o if ((err = ext4_get_inode_loc(inode, &is.iloc)) != 0) 1953aef1c851STao Ma goto out; 1954aef1c851STao Ma 1955aef1c851STao Ma down_write(&EXT4_I(inode)->i_data_sem); 1956aef1c851STao Ma i_size = inode->i_size; 1957aef1c851STao Ma inline_size = ext4_get_inline_size(inode); 1958aef1c851STao Ma EXT4_I(inode)->i_disksize = i_size; 1959aef1c851STao Ma 1960aef1c851STao Ma if (i_size < inline_size) { 19610add491dSEric Whitney /* 19620add491dSEric Whitney * if there's inline data to truncate and this file was 19630add491dSEric Whitney * converted to extents after that inline data was written, 19640add491dSEric Whitney * the extent status cache must be cleared to avoid leaving 19650add491dSEric Whitney * behind stale delayed allocated extent entries 19660add491dSEric Whitney */ 19670add491dSEric Whitney if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { 19680add491dSEric Whitney retry: 19690add491dSEric Whitney err = ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS); 19700add491dSEric Whitney if (err == -ENOMEM) { 19714034247aSNeilBrown memalloc_retry_wait(GFP_ATOMIC); 19720add491dSEric Whitney goto retry; 19730add491dSEric Whitney } 19740add491dSEric Whitney if (err) 19750add491dSEric Whitney goto out_error; 19760add491dSEric Whitney } 19770add491dSEric Whitney 1978aef1c851STao Ma /* Clear the content in the xattr space. */ 1979aef1c851STao Ma if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) { 198001daf945STheodore Ts'o if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0) 1981aef1c851STao Ma goto out_error; 1982aef1c851STao Ma 1983aef1c851STao Ma BUG_ON(is.s.not_found); 1984aef1c851STao Ma 1985aef1c851STao Ma value_len = le32_to_cpu(is.s.here->e_value_size); 1986aef1c851STao Ma value = kmalloc(value_len, GFP_NOFS); 198701daf945STheodore Ts'o if (!value) { 198801daf945STheodore Ts'o err = -ENOMEM; 1989aef1c851STao Ma goto out_error; 199001daf945STheodore Ts'o } 1991aef1c851STao Ma 199201daf945STheodore Ts'o err = ext4_xattr_ibody_get(inode, i.name_index, 199301daf945STheodore Ts'o i.name, value, value_len); 199401daf945STheodore Ts'o if (err <= 0) 1995aef1c851STao Ma goto out_error; 1996aef1c851STao Ma 1997aef1c851STao Ma i.value = value; 1998aef1c851STao Ma i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ? 1999aef1c851STao Ma i_size - EXT4_MIN_INLINE_DATA_SIZE : 0; 2000310c097cSRitesh Harjani err = ext4_xattr_ibody_set(handle, inode, &i, &is); 200101daf945STheodore Ts'o if (err) 2002aef1c851STao Ma goto out_error; 2003aef1c851STao Ma } 2004aef1c851STao Ma 2005aef1c851STao Ma /* Clear the content within i_blocks. */ 200609c455aaSTheodore Ts'o if (i_size < EXT4_MIN_INLINE_DATA_SIZE) { 200709c455aaSTheodore Ts'o void *p = (void *) ext4_raw_inode(&is.iloc)->i_block; 200809c455aaSTheodore Ts'o memset(p + i_size, 0, 2009aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE - i_size); 201009c455aaSTheodore Ts'o } 2011aef1c851STao Ma 2012aef1c851STao Ma EXT4_I(inode)->i_inline_size = i_size < 2013aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE ? 2014aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE : i_size; 2015aef1c851STao Ma } 2016aef1c851STao Ma 2017aef1c851STao Ma out_error: 2018aef1c851STao Ma up_write(&EXT4_I(inode)->i_data_sem); 2019aef1c851STao Ma out: 2020aef1c851STao Ma brelse(is.iloc.bh); 2021c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 2022aef1c851STao Ma kfree(value); 2023aef1c851STao Ma if (inode->i_nlink) 2024aef1c851STao Ma ext4_orphan_del(handle, inode); 2025aef1c851STao Ma 202601daf945STheodore Ts'o if (err == 0) { 2027eeca7ea1SDeepa Dinamani inode->i_mtime = inode->i_ctime = current_time(inode); 202801daf945STheodore Ts'o err = ext4_mark_inode_dirty(handle, inode); 2029aef1c851STao Ma if (IS_SYNC(inode)) 2030aef1c851STao Ma ext4_handle_sync(handle); 203101daf945STheodore Ts'o } 2032aef1c851STao Ma ext4_journal_stop(handle); 203301daf945STheodore Ts'o return err; 2034aef1c851STao Ma } 20350c8d414fSTao Ma 20360c8d414fSTao Ma int ext4_convert_inline_data(struct inode *inode) 20370c8d414fSTao Ma { 2038c755e251STheodore Ts'o int error, needed_blocks, no_expand; 20390c8d414fSTao Ma handle_t *handle; 20400c8d414fSTao Ma struct ext4_iloc iloc; 20410c8d414fSTao Ma 20420c8d414fSTao Ma if (!ext4_has_inline_data(inode)) { 20430c8d414fSTao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 20440c8d414fSTao Ma return 0; 2045ef09ed5dSYe Bin } else if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { 2046ef09ed5dSYe Bin /* 2047ef09ed5dSYe Bin * Inode has inline data but EXT4_STATE_MAY_INLINE_DATA is 2048ef09ed5dSYe Bin * cleared. This means we are in the middle of moving of 2049ef09ed5dSYe Bin * inline data to delay allocated block. Just force writeout 2050ef09ed5dSYe Bin * here to finish conversion. 2051ef09ed5dSYe Bin */ 2052ef09ed5dSYe Bin error = filemap_flush(inode->i_mapping); 2053ef09ed5dSYe Bin if (error) 2054ef09ed5dSYe Bin return error; 2055ef09ed5dSYe Bin if (!ext4_has_inline_data(inode)) 2056ef09ed5dSYe Bin return 0; 20570c8d414fSTao Ma } 20580c8d414fSTao Ma 20590c8d414fSTao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 20600c8d414fSTao Ma 20610c8d414fSTao Ma iloc.bh = NULL; 20620c8d414fSTao Ma error = ext4_get_inode_loc(inode, &iloc); 20630c8d414fSTao Ma if (error) 20640c8d414fSTao Ma return error; 20650c8d414fSTao Ma 20669924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); 20670c8d414fSTao Ma if (IS_ERR(handle)) { 20680c8d414fSTao Ma error = PTR_ERR(handle); 20690c8d414fSTao Ma goto out_free; 20700c8d414fSTao Ma } 20710c8d414fSTao Ma 2072c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 2073c755e251STheodore Ts'o if (ext4_has_inline_data(inode)) 20740c8d414fSTao Ma error = ext4_convert_inline_data_nolock(handle, inode, &iloc); 2075c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 20760c8d414fSTao Ma ext4_journal_stop(handle); 20770c8d414fSTao Ma out_free: 20780c8d414fSTao Ma brelse(iloc.bh); 20790c8d414fSTao Ma return error; 20800c8d414fSTao Ma } 2081