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> 9ee73f9a5SJeff Layton #include <linux/iversion.h> 104bdfc873SMichael Halcrow 1167cf5b09STao Ma #include "ext4_jbd2.h" 1267cf5b09STao Ma #include "ext4.h" 1367cf5b09STao Ma #include "xattr.h" 14f19d5870STao Ma #include "truncate.h" 1567cf5b09STao Ma 1667cf5b09STao Ma #define EXT4_XATTR_SYSTEM_DATA "data" 1767cf5b09STao Ma #define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS)) 188af0f082STao Ma #define EXT4_INLINE_DOTDOT_OFFSET 2 193c47d541STao Ma #define EXT4_INLINE_DOTDOT_SIZE 4 2067cf5b09STao Ma 21c197855eSStephen Hemminger static int ext4_get_inline_size(struct inode *inode) 2267cf5b09STao Ma { 2367cf5b09STao Ma if (EXT4_I(inode)->i_inline_off) 2467cf5b09STao Ma return EXT4_I(inode)->i_inline_size; 2567cf5b09STao Ma 2667cf5b09STao Ma return 0; 2767cf5b09STao Ma } 2867cf5b09STao Ma 2967cf5b09STao Ma static int get_max_inline_xattr_value_size(struct inode *inode, 3067cf5b09STao Ma struct ext4_iloc *iloc) 3167cf5b09STao Ma { 3267cf5b09STao Ma struct ext4_xattr_ibody_header *header; 3367cf5b09STao Ma struct ext4_xattr_entry *entry; 3467cf5b09STao Ma struct ext4_inode *raw_inode; 3567cf5b09STao Ma int free, min_offs; 3667cf5b09STao Ma 3767cf5b09STao Ma min_offs = EXT4_SB(inode->i_sb)->s_inode_size - 3867cf5b09STao Ma EXT4_GOOD_OLD_INODE_SIZE - 3967cf5b09STao Ma EXT4_I(inode)->i_extra_isize - 4067cf5b09STao Ma sizeof(struct ext4_xattr_ibody_header); 4167cf5b09STao Ma 4267cf5b09STao Ma /* 4367cf5b09STao Ma * We need to subtract another sizeof(__u32) since an in-inode xattr 4467cf5b09STao Ma * needs an empty 4 bytes to indicate the gap between the xattr entry 4567cf5b09STao Ma * and the name/value pair. 4667cf5b09STao Ma */ 4767cf5b09STao Ma if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) 4867cf5b09STao Ma return EXT4_XATTR_SIZE(min_offs - 4967cf5b09STao Ma EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) - 5067cf5b09STao Ma EXT4_XATTR_ROUND - sizeof(__u32)); 5167cf5b09STao Ma 5267cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 5367cf5b09STao Ma header = IHDR(inode, raw_inode); 5467cf5b09STao Ma entry = IFIRST(header); 5567cf5b09STao Ma 5667cf5b09STao Ma /* Compute min_offs. */ 5767cf5b09STao Ma for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { 58e50e5129SAndreas Dilger if (!entry->e_value_inum && entry->e_value_size) { 5967cf5b09STao Ma size_t offs = le16_to_cpu(entry->e_value_offs); 6067cf5b09STao Ma if (offs < min_offs) 6167cf5b09STao Ma min_offs = offs; 6267cf5b09STao Ma } 6367cf5b09STao Ma } 6467cf5b09STao Ma free = min_offs - 6567cf5b09STao Ma ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); 6667cf5b09STao Ma 6767cf5b09STao Ma if (EXT4_I(inode)->i_inline_off) { 6867cf5b09STao Ma entry = (struct ext4_xattr_entry *) 6967cf5b09STao Ma ((void *)raw_inode + EXT4_I(inode)->i_inline_off); 7067cf5b09STao Ma 71c4932dbeSboxi liu free += EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); 7267cf5b09STao Ma goto out; 7367cf5b09STao Ma } 7467cf5b09STao Ma 7567cf5b09STao Ma free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)); 7667cf5b09STao Ma 7767cf5b09STao Ma if (free > EXT4_XATTR_ROUND) 7867cf5b09STao Ma free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND); 7967cf5b09STao Ma else 8067cf5b09STao Ma free = 0; 8167cf5b09STao Ma 8267cf5b09STao Ma out: 8367cf5b09STao Ma return free; 8467cf5b09STao Ma } 8567cf5b09STao Ma 8667cf5b09STao Ma /* 8767cf5b09STao Ma * Get the maximum size we now can store in an inode. 8867cf5b09STao Ma * If we can't find the space for a xattr entry, don't use the space 8967cf5b09STao Ma * of the extents since we have no space to indicate the inline data. 9067cf5b09STao Ma */ 9167cf5b09STao Ma int ext4_get_max_inline_size(struct inode *inode) 9267cf5b09STao Ma { 9367cf5b09STao Ma int error, max_inline_size; 9467cf5b09STao Ma struct ext4_iloc iloc; 9567cf5b09STao Ma 9667cf5b09STao Ma if (EXT4_I(inode)->i_extra_isize == 0) 9767cf5b09STao Ma return 0; 9867cf5b09STao Ma 9967cf5b09STao Ma error = ext4_get_inode_loc(inode, &iloc); 10067cf5b09STao Ma if (error) { 10167cf5b09STao Ma ext4_error_inode(inode, __func__, __LINE__, 0, 10267cf5b09STao Ma "can't get inode location %lu", 10367cf5b09STao Ma inode->i_ino); 10467cf5b09STao Ma return 0; 10567cf5b09STao Ma } 10667cf5b09STao Ma 10767cf5b09STao Ma down_read(&EXT4_I(inode)->xattr_sem); 10867cf5b09STao Ma max_inline_size = get_max_inline_xattr_value_size(inode, &iloc); 10967cf5b09STao Ma up_read(&EXT4_I(inode)->xattr_sem); 11067cf5b09STao Ma 11167cf5b09STao Ma brelse(iloc.bh); 11267cf5b09STao Ma 11367cf5b09STao Ma if (!max_inline_size) 11467cf5b09STao Ma return 0; 11567cf5b09STao Ma 11667cf5b09STao Ma return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE; 11767cf5b09STao Ma } 11867cf5b09STao Ma 11967cf5b09STao Ma /* 12067cf5b09STao Ma * this function does not take xattr_sem, which is OK because it is 12167cf5b09STao Ma * currently only used in a code path coming form ext4_iget, before 12267cf5b09STao Ma * the new inode has been unlocked 12367cf5b09STao Ma */ 12467cf5b09STao Ma int ext4_find_inline_data_nolock(struct inode *inode) 12567cf5b09STao Ma { 12667cf5b09STao Ma struct ext4_xattr_ibody_find is = { 12767cf5b09STao Ma .s = { .not_found = -ENODATA, }, 12867cf5b09STao Ma }; 12967cf5b09STao Ma struct ext4_xattr_info i = { 13067cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 13167cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 13267cf5b09STao Ma }; 13367cf5b09STao Ma int error; 13467cf5b09STao Ma 13567cf5b09STao Ma if (EXT4_I(inode)->i_extra_isize == 0) 13667cf5b09STao Ma return 0; 13767cf5b09STao Ma 13867cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 13967cf5b09STao Ma if (error) 14067cf5b09STao Ma return error; 14167cf5b09STao Ma 14267cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 14367cf5b09STao Ma if (error) 14467cf5b09STao Ma goto out; 14567cf5b09STao Ma 14667cf5b09STao Ma if (!is.s.not_found) { 147117166efSTheodore Ts'o if (is.s.here->e_value_inum) { 148117166efSTheodore Ts'o EXT4_ERROR_INODE(inode, "inline data xattr refers " 149117166efSTheodore Ts'o "to an external xattr inode"); 150117166efSTheodore Ts'o error = -EFSCORRUPTED; 151117166efSTheodore Ts'o goto out; 152117166efSTheodore Ts'o } 15367cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 15467cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 15567cf5b09STao Ma EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + 15667cf5b09STao Ma le32_to_cpu(is.s.here->e_value_size); 15767cf5b09STao Ma ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 15867cf5b09STao Ma } 15967cf5b09STao Ma out: 16067cf5b09STao Ma brelse(is.iloc.bh); 16167cf5b09STao Ma return error; 16267cf5b09STao Ma } 16367cf5b09STao Ma 16467cf5b09STao Ma static int ext4_read_inline_data(struct inode *inode, void *buffer, 16567cf5b09STao Ma unsigned int len, 16667cf5b09STao Ma struct ext4_iloc *iloc) 16767cf5b09STao Ma { 16867cf5b09STao Ma struct ext4_xattr_entry *entry; 16967cf5b09STao Ma struct ext4_xattr_ibody_header *header; 17067cf5b09STao Ma int cp_len = 0; 17167cf5b09STao Ma struct ext4_inode *raw_inode; 17267cf5b09STao Ma 17367cf5b09STao Ma if (!len) 17467cf5b09STao Ma return 0; 17567cf5b09STao Ma 17667cf5b09STao Ma BUG_ON(len > EXT4_I(inode)->i_inline_size); 17767cf5b09STao Ma 17867cf5b09STao Ma cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ? 17967cf5b09STao Ma len : EXT4_MIN_INLINE_DATA_SIZE; 18067cf5b09STao Ma 18167cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 18267cf5b09STao Ma memcpy(buffer, (void *)(raw_inode->i_block), cp_len); 18367cf5b09STao Ma 18467cf5b09STao Ma len -= cp_len; 18567cf5b09STao Ma buffer += cp_len; 18667cf5b09STao Ma 18767cf5b09STao Ma if (!len) 18867cf5b09STao Ma goto out; 18967cf5b09STao Ma 19067cf5b09STao Ma header = IHDR(inode, raw_inode); 19167cf5b09STao Ma entry = (struct ext4_xattr_entry *)((void *)raw_inode + 19267cf5b09STao Ma EXT4_I(inode)->i_inline_off); 19367cf5b09STao Ma len = min_t(unsigned int, len, 19467cf5b09STao Ma (unsigned int)le32_to_cpu(entry->e_value_size)); 19567cf5b09STao Ma 19667cf5b09STao Ma memcpy(buffer, 19767cf5b09STao Ma (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len); 19867cf5b09STao Ma cp_len += len; 19967cf5b09STao Ma 20067cf5b09STao Ma out: 20167cf5b09STao Ma return cp_len; 20267cf5b09STao Ma } 20367cf5b09STao Ma 20467cf5b09STao Ma /* 20567cf5b09STao Ma * write the buffer to the inline inode. 20667cf5b09STao Ma * If 'create' is set, we don't need to do the extra copy in the xattr 2070d812f77STao Ma * value since it is already handled by ext4_xattr_ibody_inline_set. 2080d812f77STao Ma * That saves us one memcpy. 20967cf5b09STao Ma */ 210c197855eSStephen Hemminger static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, 21167cf5b09STao Ma void *buffer, loff_t pos, unsigned int len) 21267cf5b09STao Ma { 21367cf5b09STao Ma struct ext4_xattr_entry *entry; 21467cf5b09STao Ma struct ext4_xattr_ibody_header *header; 21567cf5b09STao Ma struct ext4_inode *raw_inode; 21667cf5b09STao Ma int cp_len = 0; 21767cf5b09STao Ma 2180db1ff22STheodore Ts'o if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb)))) 2190db1ff22STheodore Ts'o return; 2200db1ff22STheodore Ts'o 22167cf5b09STao Ma BUG_ON(!EXT4_I(inode)->i_inline_off); 22267cf5b09STao Ma BUG_ON(pos + len > EXT4_I(inode)->i_inline_size); 22367cf5b09STao Ma 22467cf5b09STao Ma raw_inode = ext4_raw_inode(iloc); 22567cf5b09STao Ma buffer += pos; 22667cf5b09STao Ma 22767cf5b09STao Ma if (pos < EXT4_MIN_INLINE_DATA_SIZE) { 22867cf5b09STao Ma cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ? 22967cf5b09STao Ma EXT4_MIN_INLINE_DATA_SIZE - pos : len; 23067cf5b09STao Ma memcpy((void *)raw_inode->i_block + pos, buffer, cp_len); 23167cf5b09STao Ma 23267cf5b09STao Ma len -= cp_len; 23367cf5b09STao Ma buffer += cp_len; 23467cf5b09STao Ma pos += cp_len; 23567cf5b09STao Ma } 23667cf5b09STao Ma 23767cf5b09STao Ma if (!len) 23867cf5b09STao Ma return; 23967cf5b09STao Ma 24067cf5b09STao Ma pos -= EXT4_MIN_INLINE_DATA_SIZE; 24167cf5b09STao Ma header = IHDR(inode, raw_inode); 24267cf5b09STao Ma entry = (struct ext4_xattr_entry *)((void *)raw_inode + 24367cf5b09STao Ma EXT4_I(inode)->i_inline_off); 24467cf5b09STao Ma 24567cf5b09STao Ma memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos, 24667cf5b09STao Ma buffer, len); 24767cf5b09STao Ma } 24867cf5b09STao Ma 24967cf5b09STao Ma static int ext4_create_inline_data(handle_t *handle, 25067cf5b09STao Ma struct inode *inode, unsigned len) 25167cf5b09STao Ma { 25267cf5b09STao Ma int error; 25367cf5b09STao Ma void *value = NULL; 25467cf5b09STao Ma struct ext4_xattr_ibody_find is = { 25567cf5b09STao Ma .s = { .not_found = -ENODATA, }, 25667cf5b09STao Ma }; 25767cf5b09STao Ma struct ext4_xattr_info i = { 25867cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 25967cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 26067cf5b09STao Ma }; 26167cf5b09STao Ma 26267cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 26367cf5b09STao Ma if (error) 26467cf5b09STao Ma return error; 26567cf5b09STao Ma 2665d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 26767cf5b09STao Ma error = ext4_journal_get_write_access(handle, is.iloc.bh); 26867cf5b09STao Ma if (error) 26967cf5b09STao Ma goto out; 27067cf5b09STao Ma 27167cf5b09STao Ma if (len > EXT4_MIN_INLINE_DATA_SIZE) { 272bd9926e8STheodore Ts'o value = EXT4_ZERO_XATTR_VALUE; 27367cf5b09STao Ma len -= EXT4_MIN_INLINE_DATA_SIZE; 27467cf5b09STao Ma } else { 27567cf5b09STao Ma value = ""; 27667cf5b09STao Ma len = 0; 27767cf5b09STao Ma } 27867cf5b09STao Ma 27967cf5b09STao Ma /* Insert the the xttr entry. */ 28067cf5b09STao Ma i.value = value; 28167cf5b09STao Ma i.value_len = len; 28267cf5b09STao Ma 28367cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 28467cf5b09STao Ma if (error) 28567cf5b09STao Ma goto out; 28667cf5b09STao Ma 28767cf5b09STao Ma BUG_ON(!is.s.not_found); 28867cf5b09STao Ma 2890d812f77STao Ma error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); 29067cf5b09STao Ma if (error) { 29167cf5b09STao Ma if (error == -ENOSPC) 29267cf5b09STao Ma ext4_clear_inode_state(inode, 29367cf5b09STao Ma EXT4_STATE_MAY_INLINE_DATA); 29467cf5b09STao Ma goto out; 29567cf5b09STao Ma } 29667cf5b09STao Ma 29767cf5b09STao Ma memset((void *)ext4_raw_inode(&is.iloc)->i_block, 29867cf5b09STao Ma 0, EXT4_MIN_INLINE_DATA_SIZE); 29967cf5b09STao Ma 30067cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 30167cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 30267cf5b09STao Ma EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE; 30367cf5b09STao Ma ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); 30467cf5b09STao Ma ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA); 30567cf5b09STao Ma get_bh(is.iloc.bh); 30667cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 30767cf5b09STao Ma 30867cf5b09STao Ma out: 30967cf5b09STao Ma brelse(is.iloc.bh); 31067cf5b09STao Ma return error; 31167cf5b09STao Ma } 31267cf5b09STao Ma 31367cf5b09STao Ma static int ext4_update_inline_data(handle_t *handle, struct inode *inode, 31467cf5b09STao Ma unsigned int len) 31567cf5b09STao Ma { 31667cf5b09STao Ma int error; 31767cf5b09STao Ma void *value = NULL; 31867cf5b09STao Ma struct ext4_xattr_ibody_find is = { 31967cf5b09STao Ma .s = { .not_found = -ENODATA, }, 32067cf5b09STao Ma }; 32167cf5b09STao Ma struct ext4_xattr_info i = { 32267cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 32367cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 32467cf5b09STao Ma }; 32567cf5b09STao Ma 32667cf5b09STao Ma /* If the old space is ok, write the data directly. */ 32767cf5b09STao Ma if (len <= EXT4_I(inode)->i_inline_size) 32867cf5b09STao Ma return 0; 32967cf5b09STao Ma 33067cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 33167cf5b09STao Ma if (error) 33267cf5b09STao Ma return error; 33367cf5b09STao Ma 33467cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 33567cf5b09STao Ma if (error) 33667cf5b09STao Ma goto out; 33767cf5b09STao Ma 33867cf5b09STao Ma BUG_ON(is.s.not_found); 33967cf5b09STao Ma 34067cf5b09STao Ma len -= EXT4_MIN_INLINE_DATA_SIZE; 34167cf5b09STao Ma value = kzalloc(len, GFP_NOFS); 342578620f4SDan Carpenter if (!value) { 343578620f4SDan Carpenter error = -ENOMEM; 34467cf5b09STao Ma goto out; 345578620f4SDan Carpenter } 34667cf5b09STao Ma 34767cf5b09STao Ma error = ext4_xattr_ibody_get(inode, i.name_index, i.name, 34867cf5b09STao Ma value, len); 34967cf5b09STao Ma if (error == -ENODATA) 35067cf5b09STao Ma goto out; 35167cf5b09STao Ma 3525d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 35367cf5b09STao Ma error = ext4_journal_get_write_access(handle, is.iloc.bh); 35467cf5b09STao Ma if (error) 35567cf5b09STao Ma goto out; 35667cf5b09STao Ma 35767cf5b09STao Ma /* Update the xttr entry. */ 35867cf5b09STao Ma i.value = value; 35967cf5b09STao Ma i.value_len = len; 36067cf5b09STao Ma 3610d812f77STao Ma error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); 36267cf5b09STao Ma if (error) 36367cf5b09STao Ma goto out; 36467cf5b09STao Ma 36567cf5b09STao Ma EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - 36667cf5b09STao Ma (void *)ext4_raw_inode(&is.iloc)); 36767cf5b09STao Ma EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + 36867cf5b09STao Ma le32_to_cpu(is.s.here->e_value_size); 36967cf5b09STao Ma ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 37067cf5b09STao Ma get_bh(is.iloc.bh); 37167cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 37267cf5b09STao Ma 37367cf5b09STao Ma out: 37467cf5b09STao Ma kfree(value); 37567cf5b09STao Ma brelse(is.iloc.bh); 37667cf5b09STao Ma return error; 37767cf5b09STao Ma } 37867cf5b09STao Ma 379c197855eSStephen Hemminger static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, 38067cf5b09STao Ma unsigned int len) 38167cf5b09STao Ma { 382c755e251STheodore Ts'o int ret, size, no_expand; 38367cf5b09STao Ma struct ext4_inode_info *ei = EXT4_I(inode); 38467cf5b09STao Ma 38567cf5b09STao Ma if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) 38667cf5b09STao Ma return -ENOSPC; 38767cf5b09STao Ma 38867cf5b09STao Ma size = ext4_get_max_inline_size(inode); 38967cf5b09STao Ma if (size < len) 39067cf5b09STao Ma return -ENOSPC; 39167cf5b09STao Ma 392c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 39367cf5b09STao Ma 39467cf5b09STao Ma if (ei->i_inline_off) 39567cf5b09STao Ma ret = ext4_update_inline_data(handle, inode, len); 39667cf5b09STao Ma else 39767cf5b09STao Ma ret = ext4_create_inline_data(handle, inode, len); 39867cf5b09STao Ma 399c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 40067cf5b09STao Ma return ret; 40167cf5b09STao Ma } 40267cf5b09STao Ma 40367cf5b09STao Ma static int ext4_destroy_inline_data_nolock(handle_t *handle, 40467cf5b09STao Ma struct inode *inode) 40567cf5b09STao Ma { 40667cf5b09STao Ma struct ext4_inode_info *ei = EXT4_I(inode); 40767cf5b09STao Ma struct ext4_xattr_ibody_find is = { 40867cf5b09STao Ma .s = { .not_found = 0, }, 40967cf5b09STao Ma }; 41067cf5b09STao Ma struct ext4_xattr_info i = { 41167cf5b09STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 41267cf5b09STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 41367cf5b09STao Ma .value = NULL, 41467cf5b09STao Ma .value_len = 0, 41567cf5b09STao Ma }; 41667cf5b09STao Ma int error; 41767cf5b09STao Ma 41867cf5b09STao Ma if (!ei->i_inline_off) 41967cf5b09STao Ma return 0; 42067cf5b09STao Ma 42167cf5b09STao Ma error = ext4_get_inode_loc(inode, &is.iloc); 42267cf5b09STao Ma if (error) 42367cf5b09STao Ma return error; 42467cf5b09STao Ma 42567cf5b09STao Ma error = ext4_xattr_ibody_find(inode, &i, &is); 42667cf5b09STao Ma if (error) 42767cf5b09STao Ma goto out; 42867cf5b09STao Ma 4295d601255Sliang xie BUFFER_TRACE(is.iloc.bh, "get_write_access"); 43067cf5b09STao Ma error = ext4_journal_get_write_access(handle, is.iloc.bh); 43167cf5b09STao Ma if (error) 43267cf5b09STao Ma goto out; 43367cf5b09STao Ma 4340d812f77STao Ma error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); 43567cf5b09STao Ma if (error) 43667cf5b09STao Ma goto out; 43767cf5b09STao Ma 43867cf5b09STao Ma memset((void *)ext4_raw_inode(&is.iloc)->i_block, 43967cf5b09STao Ma 0, EXT4_MIN_INLINE_DATA_SIZE); 4406e8ab72aSTheodore Ts'o memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); 44167cf5b09STao Ma 442e2b911c5SDarrick J. Wong if (ext4_has_feature_extents(inode->i_sb)) { 44367cf5b09STao Ma if (S_ISDIR(inode->i_mode) || 44467cf5b09STao Ma S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) { 44567cf5b09STao Ma ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); 44667cf5b09STao Ma ext4_ext_tree_init(handle, inode); 44767cf5b09STao Ma } 44867cf5b09STao Ma } 44967cf5b09STao Ma ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA); 45067cf5b09STao Ma 45167cf5b09STao Ma get_bh(is.iloc.bh); 45267cf5b09STao Ma error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); 45367cf5b09STao Ma 45467cf5b09STao Ma EXT4_I(inode)->i_inline_off = 0; 45567cf5b09STao Ma EXT4_I(inode)->i_inline_size = 0; 45667cf5b09STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 45767cf5b09STao Ma out: 45867cf5b09STao Ma brelse(is.iloc.bh); 45967cf5b09STao Ma if (error == -ENODATA) 46067cf5b09STao Ma error = 0; 46167cf5b09STao Ma return error; 46267cf5b09STao Ma } 46367cf5b09STao Ma 46446c7f254STao Ma static int ext4_read_inline_page(struct inode *inode, struct page *page) 46546c7f254STao Ma { 46646c7f254STao Ma void *kaddr; 46746c7f254STao Ma int ret = 0; 46846c7f254STao Ma size_t len; 46946c7f254STao Ma struct ext4_iloc iloc; 47046c7f254STao Ma 47146c7f254STao Ma BUG_ON(!PageLocked(page)); 47246c7f254STao Ma BUG_ON(!ext4_has_inline_data(inode)); 47346c7f254STao Ma BUG_ON(page->index); 47446c7f254STao Ma 47546c7f254STao Ma if (!EXT4_I(inode)->i_inline_off) { 47646c7f254STao Ma ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.", 47746c7f254STao Ma inode->i_ino); 47846c7f254STao Ma goto out; 47946c7f254STao Ma } 48046c7f254STao Ma 48146c7f254STao Ma ret = ext4_get_inode_loc(inode, &iloc); 48246c7f254STao Ma if (ret) 48346c7f254STao Ma goto out; 48446c7f254STao Ma 48546c7f254STao Ma len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode)); 48646c7f254STao Ma kaddr = kmap_atomic(page); 48746c7f254STao Ma ret = ext4_read_inline_data(inode, kaddr, len, &iloc); 48846c7f254STao Ma flush_dcache_page(page); 48946c7f254STao Ma kunmap_atomic(kaddr); 49009cbfeafSKirill A. Shutemov zero_user_segment(page, len, PAGE_SIZE); 49146c7f254STao Ma SetPageUptodate(page); 49246c7f254STao Ma brelse(iloc.bh); 49346c7f254STao Ma 49446c7f254STao Ma out: 49546c7f254STao Ma return ret; 49646c7f254STao Ma } 49746c7f254STao Ma 49846c7f254STao Ma int ext4_readpage_inline(struct inode *inode, struct page *page) 49946c7f254STao Ma { 50046c7f254STao Ma int ret = 0; 50146c7f254STao Ma 50246c7f254STao Ma down_read(&EXT4_I(inode)->xattr_sem); 50346c7f254STao Ma if (!ext4_has_inline_data(inode)) { 50446c7f254STao Ma up_read(&EXT4_I(inode)->xattr_sem); 50546c7f254STao Ma return -EAGAIN; 50646c7f254STao Ma } 50746c7f254STao Ma 50846c7f254STao Ma /* 50946c7f254STao Ma * Current inline data can only exist in the 1st page, 51046c7f254STao Ma * So for all the other pages, just set them uptodate. 51146c7f254STao Ma */ 51246c7f254STao Ma if (!page->index) 51346c7f254STao Ma ret = ext4_read_inline_page(inode, page); 51446c7f254STao Ma else if (!PageUptodate(page)) { 51509cbfeafSKirill A. Shutemov zero_user_segment(page, 0, PAGE_SIZE); 51646c7f254STao Ma SetPageUptodate(page); 51746c7f254STao Ma } 51846c7f254STao Ma 51946c7f254STao Ma up_read(&EXT4_I(inode)->xattr_sem); 52046c7f254STao Ma 52146c7f254STao Ma unlock_page(page); 52246c7f254STao Ma return ret >= 0 ? 0 : ret; 52346c7f254STao Ma } 52446c7f254STao Ma 525f19d5870STao Ma static int ext4_convert_inline_data_to_extent(struct address_space *mapping, 526f19d5870STao Ma struct inode *inode, 527f19d5870STao Ma unsigned flags) 528f19d5870STao Ma { 529c755e251STheodore Ts'o int ret, needed_blocks, no_expand; 530f19d5870STao Ma handle_t *handle = NULL; 531f19d5870STao Ma int retries = 0, sem_held = 0; 532f19d5870STao Ma struct page *page = NULL; 533f19d5870STao Ma unsigned from, to; 534f19d5870STao Ma struct ext4_iloc iloc; 535f19d5870STao Ma 536f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 537f19d5870STao Ma /* 538f19d5870STao Ma * clear the flag so that no new write 539f19d5870STao Ma * will trap here again. 540f19d5870STao Ma */ 541f19d5870STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 542f19d5870STao Ma return 0; 543f19d5870STao Ma } 544f19d5870STao Ma 545f19d5870STao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 546f19d5870STao Ma 547f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 548f19d5870STao Ma if (ret) 549f19d5870STao Ma return ret; 550f19d5870STao Ma 551f19d5870STao Ma retry: 5529924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); 553f19d5870STao Ma if (IS_ERR(handle)) { 554f19d5870STao Ma ret = PTR_ERR(handle); 555f19d5870STao Ma handle = NULL; 556f19d5870STao Ma goto out; 557f19d5870STao Ma } 558f19d5870STao Ma 559f19d5870STao Ma /* We cannot recurse into the filesystem as the transaction is already 560f19d5870STao Ma * started */ 561f19d5870STao Ma flags |= AOP_FLAG_NOFS; 562f19d5870STao Ma 563f19d5870STao Ma page = grab_cache_page_write_begin(mapping, 0, flags); 564f19d5870STao Ma if (!page) { 565f19d5870STao Ma ret = -ENOMEM; 566f19d5870STao Ma goto out; 567f19d5870STao Ma } 568f19d5870STao Ma 569c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 570f19d5870STao Ma sem_held = 1; 571f19d5870STao Ma /* If some one has already done this for us, just exit. */ 572f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 573f19d5870STao Ma ret = 0; 574f19d5870STao Ma goto out; 575f19d5870STao Ma } 576f19d5870STao Ma 577f19d5870STao Ma from = 0; 578f19d5870STao Ma to = ext4_get_inline_size(inode); 579f19d5870STao Ma if (!PageUptodate(page)) { 580f19d5870STao Ma ret = ext4_read_inline_page(inode, page); 581f19d5870STao Ma if (ret < 0) 582f19d5870STao Ma goto out; 583f19d5870STao Ma } 584f19d5870STao Ma 585f19d5870STao Ma ret = ext4_destroy_inline_data_nolock(handle, inode); 586f19d5870STao Ma if (ret) 587f19d5870STao Ma goto out; 588f19d5870STao Ma 589705965bdSJan Kara if (ext4_should_dioread_nolock(inode)) { 590705965bdSJan Kara ret = __block_write_begin(page, from, to, 591705965bdSJan Kara ext4_get_block_unwritten); 592705965bdSJan Kara } else 593f19d5870STao Ma ret = __block_write_begin(page, from, to, ext4_get_block); 594f19d5870STao Ma 595f19d5870STao Ma if (!ret && ext4_should_journal_data(inode)) { 596f19d5870STao Ma ret = ext4_walk_page_buffers(handle, page_buffers(page), 597f19d5870STao Ma from, to, NULL, 598f19d5870STao Ma do_journal_get_write_access); 599f19d5870STao Ma } 600f19d5870STao Ma 601f19d5870STao Ma if (ret) { 602f19d5870STao Ma unlock_page(page); 60309cbfeafSKirill A. Shutemov put_page(page); 604684de574SDarrick J. Wong page = NULL; 605f19d5870STao Ma ext4_orphan_add(handle, inode); 606c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 607f19d5870STao Ma sem_held = 0; 608f19d5870STao Ma ext4_journal_stop(handle); 609f19d5870STao Ma handle = NULL; 610f19d5870STao Ma ext4_truncate_failed_write(inode); 611f19d5870STao Ma /* 612f19d5870STao Ma * If truncate failed early the inode might 613f19d5870STao Ma * still be on the orphan list; we need to 614f19d5870STao Ma * make sure the inode is removed from the 615f19d5870STao Ma * orphan list in that case. 616f19d5870STao Ma */ 617f19d5870STao Ma if (inode->i_nlink) 618f19d5870STao Ma ext4_orphan_del(NULL, inode); 619f19d5870STao Ma } 620f19d5870STao Ma 621f19d5870STao Ma if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 622f19d5870STao Ma goto retry; 623f19d5870STao Ma 624684de574SDarrick J. Wong if (page) 625f19d5870STao Ma block_commit_write(page, from, to); 626f19d5870STao Ma out: 627f19d5870STao Ma if (page) { 628f19d5870STao Ma unlock_page(page); 62909cbfeafSKirill A. Shutemov put_page(page); 630f19d5870STao Ma } 631f19d5870STao Ma if (sem_held) 632c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 633f19d5870STao Ma if (handle) 634f19d5870STao Ma ext4_journal_stop(handle); 635f19d5870STao Ma brelse(iloc.bh); 636f19d5870STao Ma return ret; 637f19d5870STao Ma } 638f19d5870STao Ma 639f19d5870STao Ma /* 640f19d5870STao Ma * Try to write data in the inode. 641f19d5870STao Ma * If the inode has inline data, check whether the new write can be 642f19d5870STao Ma * in the inode also. If not, create the page the handle, move the data 643f19d5870STao Ma * to the page make it update and let the later codes create extent for it. 644f19d5870STao Ma */ 645f19d5870STao Ma int ext4_try_to_write_inline_data(struct address_space *mapping, 646f19d5870STao Ma struct inode *inode, 647f19d5870STao Ma loff_t pos, unsigned len, 648f19d5870STao Ma unsigned flags, 649f19d5870STao Ma struct page **pagep) 650f19d5870STao Ma { 651f19d5870STao Ma int ret; 652f19d5870STao Ma handle_t *handle; 653f19d5870STao Ma struct page *page; 654f19d5870STao Ma struct ext4_iloc iloc; 655f19d5870STao Ma 656f19d5870STao Ma if (pos + len > ext4_get_max_inline_size(inode)) 657f19d5870STao Ma goto convert; 658f19d5870STao Ma 659f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 660f19d5870STao Ma if (ret) 661f19d5870STao Ma return ret; 662f19d5870STao Ma 663f19d5870STao Ma /* 664f19d5870STao Ma * The possible write could happen in the inode, 665f19d5870STao Ma * so try to reserve the space in inode first. 666f19d5870STao Ma */ 6679924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 668f19d5870STao Ma if (IS_ERR(handle)) { 669f19d5870STao Ma ret = PTR_ERR(handle); 670f19d5870STao Ma handle = NULL; 671f19d5870STao Ma goto out; 672f19d5870STao Ma } 673f19d5870STao Ma 674f19d5870STao Ma ret = ext4_prepare_inline_data(handle, inode, pos + len); 675f19d5870STao Ma if (ret && ret != -ENOSPC) 676f19d5870STao Ma goto out; 677f19d5870STao Ma 678f19d5870STao Ma /* We don't have space in inline inode, so convert it to extent. */ 679f19d5870STao Ma if (ret == -ENOSPC) { 680f19d5870STao Ma ext4_journal_stop(handle); 681f19d5870STao Ma brelse(iloc.bh); 682f19d5870STao Ma goto convert; 683f19d5870STao Ma } 684f19d5870STao Ma 685362eca70STheodore Ts'o ret = ext4_journal_get_write_access(handle, iloc.bh); 686362eca70STheodore Ts'o if (ret) 687362eca70STheodore Ts'o goto out; 688362eca70STheodore Ts'o 689f19d5870STao Ma flags |= AOP_FLAG_NOFS; 690f19d5870STao Ma 691f19d5870STao Ma page = grab_cache_page_write_begin(mapping, 0, flags); 692f19d5870STao Ma if (!page) { 693f19d5870STao Ma ret = -ENOMEM; 694f19d5870STao Ma goto out; 695f19d5870STao Ma } 696f19d5870STao Ma 697f19d5870STao Ma *pagep = page; 698f19d5870STao Ma down_read(&EXT4_I(inode)->xattr_sem); 699f19d5870STao Ma if (!ext4_has_inline_data(inode)) { 700f19d5870STao Ma ret = 0; 701f19d5870STao Ma unlock_page(page); 70209cbfeafSKirill A. Shutemov put_page(page); 703f19d5870STao Ma goto out_up_read; 704f19d5870STao Ma } 705f19d5870STao Ma 706f19d5870STao Ma if (!PageUptodate(page)) { 707f19d5870STao Ma ret = ext4_read_inline_page(inode, page); 708f19d5870STao Ma if (ret < 0) 709f19d5870STao Ma goto out_up_read; 710f19d5870STao Ma } 711f19d5870STao Ma 712f19d5870STao Ma ret = 1; 713f19d5870STao Ma handle = NULL; 714f19d5870STao Ma out_up_read: 715f19d5870STao Ma up_read(&EXT4_I(inode)->xattr_sem); 716f19d5870STao Ma out: 717362eca70STheodore Ts'o if (handle && (ret != 1)) 718f19d5870STao Ma ext4_journal_stop(handle); 719f19d5870STao Ma brelse(iloc.bh); 720f19d5870STao Ma return ret; 721f19d5870STao Ma convert: 722f19d5870STao Ma return ext4_convert_inline_data_to_extent(mapping, 723f19d5870STao Ma inode, flags); 724f19d5870STao Ma } 725f19d5870STao Ma 726f19d5870STao Ma int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, 727f19d5870STao Ma unsigned copied, struct page *page) 728f19d5870STao Ma { 729c755e251STheodore Ts'o int ret, no_expand; 730f19d5870STao Ma void *kaddr; 731f19d5870STao Ma struct ext4_iloc iloc; 732f19d5870STao Ma 733f19d5870STao Ma if (unlikely(copied < len)) { 734f19d5870STao Ma if (!PageUptodate(page)) { 735f19d5870STao Ma copied = 0; 736f19d5870STao Ma goto out; 737f19d5870STao Ma } 738f19d5870STao Ma } 739f19d5870STao Ma 740f19d5870STao Ma ret = ext4_get_inode_loc(inode, &iloc); 741f19d5870STao Ma if (ret) { 742f19d5870STao Ma ext4_std_error(inode->i_sb, ret); 743f19d5870STao Ma copied = 0; 744f19d5870STao Ma goto out; 745f19d5870STao Ma } 746f19d5870STao Ma 747c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 748f19d5870STao Ma BUG_ON(!ext4_has_inline_data(inode)); 749f19d5870STao Ma 750f19d5870STao Ma kaddr = kmap_atomic(page); 751f19d5870STao Ma ext4_write_inline_data(inode, &iloc, kaddr, pos, len); 752f19d5870STao Ma kunmap_atomic(kaddr); 753f19d5870STao Ma SetPageUptodate(page); 754f19d5870STao Ma /* clear page dirty so that writepages wouldn't work for us. */ 755f19d5870STao Ma ClearPageDirty(page); 756f19d5870STao Ma 757c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 758f19d5870STao Ma brelse(iloc.bh); 759362eca70STheodore Ts'o mark_inode_dirty(inode); 760f19d5870STao Ma out: 761f19d5870STao Ma return copied; 762f19d5870STao Ma } 763f19d5870STao Ma 7643fdcfb66STao Ma struct buffer_head * 7653fdcfb66STao Ma ext4_journalled_write_inline_data(struct inode *inode, 7663fdcfb66STao Ma unsigned len, 7673fdcfb66STao Ma struct page *page) 7683fdcfb66STao Ma { 769c755e251STheodore Ts'o int ret, no_expand; 7703fdcfb66STao Ma void *kaddr; 7713fdcfb66STao Ma struct ext4_iloc iloc; 7723fdcfb66STao Ma 7733fdcfb66STao Ma ret = ext4_get_inode_loc(inode, &iloc); 7743fdcfb66STao Ma if (ret) { 7753fdcfb66STao Ma ext4_std_error(inode->i_sb, ret); 7763fdcfb66STao Ma return NULL; 7773fdcfb66STao Ma } 7783fdcfb66STao Ma 779c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 7803fdcfb66STao Ma kaddr = kmap_atomic(page); 7813fdcfb66STao Ma ext4_write_inline_data(inode, &iloc, kaddr, 0, len); 7823fdcfb66STao Ma kunmap_atomic(kaddr); 783c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 7843fdcfb66STao Ma 7853fdcfb66STao Ma return iloc.bh; 7863fdcfb66STao Ma } 7873fdcfb66STao Ma 7889c3569b5STao Ma /* 7899c3569b5STao Ma * Try to make the page cache and handle ready for the inline data case. 7909c3569b5STao Ma * We can call this function in 2 cases: 7919c3569b5STao Ma * 1. The inode is created and the first write exceeds inline size. We can 7929c3569b5STao Ma * clear the inode state safely. 7939c3569b5STao Ma * 2. The inode has inline data, then we need to read the data, make it 7949c3569b5STao Ma * update and dirty so that ext4_da_writepages can handle it. We don't 7959c3569b5STao Ma * need to start the journal since the file's metatdata isn't changed now. 7969c3569b5STao Ma */ 7979c3569b5STao Ma static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, 7989c3569b5STao Ma struct inode *inode, 7999c3569b5STao Ma unsigned flags, 8009c3569b5STao Ma void **fsdata) 8019c3569b5STao Ma { 8029c3569b5STao Ma int ret = 0, inline_size; 8039c3569b5STao Ma struct page *page; 8049c3569b5STao Ma 8059c3569b5STao Ma page = grab_cache_page_write_begin(mapping, 0, flags); 8069c3569b5STao Ma if (!page) 8079c3569b5STao Ma return -ENOMEM; 8089c3569b5STao Ma 8099c3569b5STao Ma down_read(&EXT4_I(inode)->xattr_sem); 8109c3569b5STao Ma if (!ext4_has_inline_data(inode)) { 8119c3569b5STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 8129c3569b5STao Ma goto out; 8139c3569b5STao Ma } 8149c3569b5STao Ma 8159c3569b5STao Ma inline_size = ext4_get_inline_size(inode); 8169c3569b5STao Ma 8179c3569b5STao Ma if (!PageUptodate(page)) { 8189c3569b5STao Ma ret = ext4_read_inline_page(inode, page); 8199c3569b5STao Ma if (ret < 0) 8209c3569b5STao Ma goto out; 8219c3569b5STao Ma } 8229c3569b5STao Ma 8239c3569b5STao Ma ret = __block_write_begin(page, 0, inline_size, 8249c3569b5STao Ma ext4_da_get_block_prep); 8259c3569b5STao Ma if (ret) { 82650db71abSDmitry Monakhov up_read(&EXT4_I(inode)->xattr_sem); 82750db71abSDmitry Monakhov unlock_page(page); 82809cbfeafSKirill A. Shutemov put_page(page); 8299c3569b5STao Ma ext4_truncate_failed_write(inode); 83050db71abSDmitry Monakhov return ret; 8319c3569b5STao Ma } 8329c3569b5STao Ma 8339c3569b5STao Ma SetPageDirty(page); 8349c3569b5STao Ma SetPageUptodate(page); 8359c3569b5STao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 8369c3569b5STao Ma *fsdata = (void *)CONVERT_INLINE_DATA; 8379c3569b5STao Ma 8389c3569b5STao Ma out: 8399c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 8409c3569b5STao Ma if (page) { 8419c3569b5STao Ma unlock_page(page); 84209cbfeafSKirill A. Shutemov put_page(page); 8439c3569b5STao Ma } 8449c3569b5STao Ma return ret; 8459c3569b5STao Ma } 8469c3569b5STao Ma 8479c3569b5STao Ma /* 8489c3569b5STao Ma * Prepare the write for the inline data. 8499c3569b5STao Ma * If the the data can be written into the inode, we just read 8509c3569b5STao Ma * the page and make it uptodate, and start the journal. 8519c3569b5STao Ma * Otherwise read the page, makes it dirty so that it can be 8529c3569b5STao Ma * handle in writepages(the i_disksize update is left to the 8539c3569b5STao Ma * normal ext4_da_write_end). 8549c3569b5STao Ma */ 8559c3569b5STao Ma int ext4_da_write_inline_data_begin(struct address_space *mapping, 8569c3569b5STao Ma struct inode *inode, 8579c3569b5STao Ma loff_t pos, unsigned len, 8589c3569b5STao Ma unsigned flags, 8599c3569b5STao Ma struct page **pagep, 8609c3569b5STao Ma void **fsdata) 8619c3569b5STao Ma { 8629c3569b5STao Ma int ret, inline_size; 8639c3569b5STao Ma handle_t *handle; 8649c3569b5STao Ma struct page *page; 8659c3569b5STao Ma struct ext4_iloc iloc; 866bc0ca9dfSJan Kara int retries; 8679c3569b5STao Ma 8689c3569b5STao Ma ret = ext4_get_inode_loc(inode, &iloc); 8699c3569b5STao Ma if (ret) 8709c3569b5STao Ma return ret; 8719c3569b5STao Ma 872bc0ca9dfSJan Kara retry_journal: 8739924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); 8749c3569b5STao Ma if (IS_ERR(handle)) { 8759c3569b5STao Ma ret = PTR_ERR(handle); 8769c3569b5STao Ma goto out; 8779c3569b5STao Ma } 8789c3569b5STao Ma 8799c3569b5STao Ma inline_size = ext4_get_max_inline_size(inode); 8809c3569b5STao Ma 8819c3569b5STao Ma ret = -ENOSPC; 8829c3569b5STao Ma if (inline_size >= pos + len) { 8839c3569b5STao Ma ret = ext4_prepare_inline_data(handle, inode, pos + len); 8849c3569b5STao Ma if (ret && ret != -ENOSPC) 88552e44777SJan Kara goto out_journal; 8869c3569b5STao Ma } 8879c3569b5STao Ma 8885cc28a9eSDmitry Monakhov /* 8895cc28a9eSDmitry Monakhov * We cannot recurse into the filesystem as the transaction 8905cc28a9eSDmitry Monakhov * is already started. 8915cc28a9eSDmitry Monakhov */ 8925cc28a9eSDmitry Monakhov flags |= AOP_FLAG_NOFS; 8935cc28a9eSDmitry Monakhov 8949c3569b5STao Ma if (ret == -ENOSPC) { 8958bc1379bSTheodore Ts'o ext4_journal_stop(handle); 8969c3569b5STao Ma ret = ext4_da_convert_inline_data_to_extent(mapping, 8979c3569b5STao Ma inode, 8989c3569b5STao Ma flags, 8999c3569b5STao Ma fsdata); 900bc0ca9dfSJan Kara if (ret == -ENOSPC && 901bc0ca9dfSJan Kara ext4_should_retry_alloc(inode->i_sb, &retries)) 902bc0ca9dfSJan Kara goto retry_journal; 9039c3569b5STao Ma goto out; 9049c3569b5STao Ma } 9059c3569b5STao Ma 9069c3569b5STao Ma page = grab_cache_page_write_begin(mapping, 0, flags); 9079c3569b5STao Ma if (!page) { 9089c3569b5STao Ma ret = -ENOMEM; 90952e44777SJan Kara goto out_journal; 9109c3569b5STao Ma } 9119c3569b5STao Ma 9129c3569b5STao Ma down_read(&EXT4_I(inode)->xattr_sem); 9139c3569b5STao Ma if (!ext4_has_inline_data(inode)) { 9149c3569b5STao Ma ret = 0; 9159c3569b5STao Ma goto out_release_page; 9169c3569b5STao Ma } 9179c3569b5STao Ma 9189c3569b5STao Ma if (!PageUptodate(page)) { 9199c3569b5STao Ma ret = ext4_read_inline_page(inode, page); 9209c3569b5STao Ma if (ret < 0) 9219c3569b5STao Ma goto out_release_page; 9229c3569b5STao Ma } 923362eca70STheodore Ts'o ret = ext4_journal_get_write_access(handle, iloc.bh); 924362eca70STheodore Ts'o if (ret) 925362eca70STheodore Ts'o goto out_release_page; 9269c3569b5STao Ma 9279c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 9289c3569b5STao Ma *pagep = page; 9299c3569b5STao Ma brelse(iloc.bh); 9309c3569b5STao Ma return 1; 9319c3569b5STao Ma out_release_page: 9329c3569b5STao Ma up_read(&EXT4_I(inode)->xattr_sem); 9339c3569b5STao Ma unlock_page(page); 93409cbfeafSKirill A. Shutemov put_page(page); 93552e44777SJan Kara out_journal: 9369c3569b5STao Ma ext4_journal_stop(handle); 93752e44777SJan Kara out: 9389c3569b5STao Ma brelse(iloc.bh); 9399c3569b5STao Ma return ret; 9409c3569b5STao Ma } 9419c3569b5STao Ma 9429c3569b5STao Ma int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, 9439c3569b5STao Ma unsigned len, unsigned copied, 9449c3569b5STao Ma struct page *page) 9459c3569b5STao Ma { 946eb5efbcbSTheodore Ts'o int ret; 9479c3569b5STao Ma 948eb5efbcbSTheodore Ts'o ret = ext4_write_inline_data_end(inode, pos, len, copied, page); 949eb5efbcbSTheodore Ts'o if (ret < 0) { 950eb5efbcbSTheodore Ts'o unlock_page(page); 951eb5efbcbSTheodore Ts'o put_page(page); 952eb5efbcbSTheodore Ts'o return ret; 953eb5efbcbSTheodore Ts'o } 954eb5efbcbSTheodore Ts'o copied = ret; 9559c3569b5STao Ma 9569c3569b5STao Ma /* 9579c3569b5STao Ma * No need to use i_size_read() here, the i_size 9589c3569b5STao Ma * cannot change under us because we hold i_mutex. 9599c3569b5STao Ma * 9609c3569b5STao Ma * But it's important to update i_size while still holding page lock: 9619c3569b5STao Ma * page writeout could otherwise come in and zero beyond i_size. 9629c3569b5STao Ma */ 963362eca70STheodore Ts'o if (pos+copied > inode->i_size) 9649c3569b5STao Ma i_size_write(inode, pos+copied); 9659c3569b5STao Ma unlock_page(page); 96609cbfeafSKirill A. Shutemov put_page(page); 9679c3569b5STao Ma 9689c3569b5STao Ma /* 9699c3569b5STao Ma * Don't mark the inode dirty under page lock. First, it unnecessarily 9709c3569b5STao Ma * makes the holding time of page lock longer. Second, it forces lock 9719c3569b5STao Ma * ordering of page lock and transaction start for journaling 9729c3569b5STao Ma * filesystems. 9739c3569b5STao Ma */ 9749c3569b5STao Ma mark_inode_dirty(inode); 9759c3569b5STao Ma 9769c3569b5STao Ma return copied; 9779c3569b5STao Ma } 978f19d5870STao Ma 9793c47d541STao Ma #ifdef INLINE_DIR_DEBUG 9803c47d541STao Ma void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, 9813c47d541STao Ma void *inline_start, int inline_size) 9823c47d541STao Ma { 9833c47d541STao Ma int offset; 9843c47d541STao Ma unsigned short de_len; 9853c47d541STao Ma struct ext4_dir_entry_2 *de = inline_start; 9863c47d541STao Ma void *dlimit = inline_start + inline_size; 9873c47d541STao Ma 9883c47d541STao Ma trace_printk("inode %lu\n", dir->i_ino); 9893c47d541STao Ma offset = 0; 9903c47d541STao Ma while ((void *)de < dlimit) { 9913c47d541STao Ma de_len = ext4_rec_len_from_disk(de->rec_len, inline_size); 99280cfb71eSRasmus Villemoes trace_printk("de: off %u rlen %u name %.*s nlen %u ino %u\n", 9933c47d541STao Ma offset, de_len, de->name_len, de->name, 9943c47d541STao Ma de->name_len, le32_to_cpu(de->inode)); 9953c47d541STao Ma if (ext4_check_dir_entry(dir, NULL, de, bh, 9963c47d541STao Ma inline_start, inline_size, offset)) 9973c47d541STao Ma BUG(); 9983c47d541STao Ma 9993c47d541STao Ma offset += de_len; 10003c47d541STao Ma de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); 10013c47d541STao Ma } 10023c47d541STao Ma } 10033c47d541STao Ma #else 10043c47d541STao Ma #define ext4_show_inline_dir(dir, bh, inline_start, inline_size) 10053c47d541STao Ma #endif 10063c47d541STao Ma 10073c47d541STao Ma /* 10083c47d541STao Ma * Add a new entry into a inline dir. 10093c47d541STao Ma * It will return -ENOSPC if no space is available, and -EIO 10103c47d541STao Ma * and -EEXIST if directory entry already exists. 10113c47d541STao Ma */ 10123c47d541STao Ma static int ext4_add_dirent_to_inline(handle_t *handle, 10135b643f9cSTheodore Ts'o struct ext4_filename *fname, 101456a04915STheodore Ts'o struct inode *dir, 10153c47d541STao Ma struct inode *inode, 10163c47d541STao Ma struct ext4_iloc *iloc, 10173c47d541STao Ma void *inline_start, int inline_size) 10183c47d541STao Ma { 10193c47d541STao Ma int err; 10203c47d541STao Ma struct ext4_dir_entry_2 *de; 10213c47d541STao Ma 10225b643f9cSTheodore Ts'o err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start, 10235b643f9cSTheodore Ts'o inline_size, fname, &de); 10243c47d541STao Ma if (err) 10253c47d541STao Ma return err; 10263c47d541STao Ma 10275d601255Sliang xie BUFFER_TRACE(iloc->bh, "get_write_access"); 10283c47d541STao Ma err = ext4_journal_get_write_access(handle, iloc->bh); 10293c47d541STao Ma if (err) 10303c47d541STao Ma return err; 10311bc0af60SEric Biggers ext4_insert_dentry(inode, de, inline_size, fname); 10323c47d541STao Ma 10333c47d541STao Ma ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size); 10343c47d541STao Ma 10353c47d541STao Ma /* 10363c47d541STao Ma * XXX shouldn't update any times until successful 10373c47d541STao Ma * completion of syscall, but too many callers depend 10383c47d541STao Ma * on this. 10393c47d541STao Ma * 10403c47d541STao Ma * XXX similarly, too many callers depend on 10413c47d541STao Ma * ext4_new_inode() setting the times, but error 10423c47d541STao Ma * recovery deletes the inode, so the worst that can 10433c47d541STao Ma * happen is that the times are slightly out of date 10443c47d541STao Ma * and/or different from the directory change time. 10453c47d541STao Ma */ 1046eeca7ea1SDeepa Dinamani dir->i_mtime = dir->i_ctime = current_time(dir); 10473c47d541STao Ma ext4_update_dx_flag(dir); 1048ee73f9a5SJeff Layton inode_inc_iversion(dir); 10493c47d541STao Ma return 1; 10503c47d541STao Ma } 10513c47d541STao Ma 10523c47d541STao Ma static void *ext4_get_inline_xattr_pos(struct inode *inode, 10533c47d541STao Ma struct ext4_iloc *iloc) 10543c47d541STao Ma { 10553c47d541STao Ma struct ext4_xattr_entry *entry; 10563c47d541STao Ma struct ext4_xattr_ibody_header *header; 10573c47d541STao Ma 10583c47d541STao Ma BUG_ON(!EXT4_I(inode)->i_inline_off); 10593c47d541STao Ma 10603c47d541STao Ma header = IHDR(inode, ext4_raw_inode(iloc)); 10613c47d541STao Ma entry = (struct ext4_xattr_entry *)((void *)ext4_raw_inode(iloc) + 10623c47d541STao Ma EXT4_I(inode)->i_inline_off); 10633c47d541STao Ma 10643c47d541STao Ma return (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs); 10653c47d541STao Ma } 10663c47d541STao Ma 10673c47d541STao Ma /* Set the final de to cover the whole block. */ 10683c47d541STao Ma static void ext4_update_final_de(void *de_buf, int old_size, int new_size) 10693c47d541STao Ma { 10703c47d541STao Ma struct ext4_dir_entry_2 *de, *prev_de; 10713c47d541STao Ma void *limit; 10723c47d541STao Ma int de_len; 10733c47d541STao Ma 10743c47d541STao Ma de = (struct ext4_dir_entry_2 *)de_buf; 10753c47d541STao Ma if (old_size) { 10763c47d541STao Ma limit = de_buf + old_size; 10773c47d541STao Ma do { 10783c47d541STao Ma prev_de = de; 10793c47d541STao Ma de_len = ext4_rec_len_from_disk(de->rec_len, old_size); 10803c47d541STao Ma de_buf += de_len; 10813c47d541STao Ma de = (struct ext4_dir_entry_2 *)de_buf; 10823c47d541STao Ma } while (de_buf < limit); 10833c47d541STao Ma 10843c47d541STao Ma prev_de->rec_len = ext4_rec_len_to_disk(de_len + new_size - 10853c47d541STao Ma old_size, new_size); 10863c47d541STao Ma } else { 10873c47d541STao Ma /* this is just created, so create an empty entry. */ 10883c47d541STao Ma de->inode = 0; 10893c47d541STao Ma de->rec_len = ext4_rec_len_to_disk(new_size, new_size); 10903c47d541STao Ma } 10913c47d541STao Ma } 10923c47d541STao Ma 10933c47d541STao Ma static int ext4_update_inline_dir(handle_t *handle, struct inode *dir, 10943c47d541STao Ma struct ext4_iloc *iloc) 10953c47d541STao Ma { 10963c47d541STao Ma int ret; 10973c47d541STao Ma int old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; 10983c47d541STao Ma int new_size = get_max_inline_xattr_value_size(dir, iloc); 10993c47d541STao Ma 11003c47d541STao Ma if (new_size - old_size <= EXT4_DIR_REC_LEN(1)) 11013c47d541STao Ma return -ENOSPC; 11023c47d541STao Ma 11033c47d541STao Ma ret = ext4_update_inline_data(handle, dir, 11043c47d541STao Ma new_size + EXT4_MIN_INLINE_DATA_SIZE); 11053c47d541STao Ma if (ret) 11063c47d541STao Ma return ret; 11073c47d541STao Ma 11083c47d541STao Ma ext4_update_final_de(ext4_get_inline_xattr_pos(dir, iloc), old_size, 11093c47d541STao Ma EXT4_I(dir)->i_inline_size - 11103c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE); 11113c47d541STao Ma dir->i_size = EXT4_I(dir)->i_disksize = EXT4_I(dir)->i_inline_size; 11123c47d541STao Ma return 0; 11133c47d541STao Ma } 11143c47d541STao Ma 11153c47d541STao Ma static void ext4_restore_inline_data(handle_t *handle, struct inode *inode, 11163c47d541STao Ma struct ext4_iloc *iloc, 11173c47d541STao Ma void *buf, int inline_size) 11183c47d541STao Ma { 11193c47d541STao Ma ext4_create_inline_data(handle, inode, inline_size); 11203c47d541STao Ma ext4_write_inline_data(inode, iloc, buf, 0, inline_size); 11213c47d541STao Ma ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 11223c47d541STao Ma } 11233c47d541STao Ma 11243c47d541STao Ma static int ext4_finish_convert_inline_dir(handle_t *handle, 11253c47d541STao Ma struct inode *inode, 11263c47d541STao Ma struct buffer_head *dir_block, 11273c47d541STao Ma void *buf, 11283c47d541STao Ma int inline_size) 11293c47d541STao Ma { 11303c47d541STao Ma int err, csum_size = 0, header_size = 0; 11313c47d541STao Ma struct ext4_dir_entry_2 *de; 11323c47d541STao Ma struct ext4_dir_entry_tail *t; 11333c47d541STao Ma void *target = dir_block->b_data; 11343c47d541STao Ma 11353c47d541STao Ma /* 11363c47d541STao Ma * First create "." and ".." and then copy the dir information 11373c47d541STao Ma * back to the block. 11383c47d541STao Ma */ 11393c47d541STao Ma de = (struct ext4_dir_entry_2 *)target; 11403c47d541STao Ma de = ext4_init_dot_dotdot(inode, de, 11413c47d541STao Ma inode->i_sb->s_blocksize, csum_size, 11423c47d541STao Ma le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1); 11433c47d541STao Ma header_size = (void *)de - target; 11443c47d541STao Ma 11453c47d541STao Ma memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE, 11463c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE); 11473c47d541STao Ma 11489aa5d32bSDmitry Monakhov if (ext4_has_metadata_csum(inode->i_sb)) 11493c47d541STao Ma csum_size = sizeof(struct ext4_dir_entry_tail); 11503c47d541STao Ma 11513c47d541STao Ma inode->i_size = inode->i_sb->s_blocksize; 11523c47d541STao Ma i_size_write(inode, inode->i_sb->s_blocksize); 11533c47d541STao Ma EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; 11543c47d541STao Ma ext4_update_final_de(dir_block->b_data, 11553c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size, 11563c47d541STao Ma inode->i_sb->s_blocksize - csum_size); 11573c47d541STao Ma 11583c47d541STao Ma if (csum_size) { 11593c47d541STao Ma t = EXT4_DIRENT_TAIL(dir_block->b_data, 11603c47d541STao Ma inode->i_sb->s_blocksize); 11613c47d541STao Ma initialize_dirent_tail(t, inode->i_sb->s_blocksize); 11623c47d541STao Ma } 11633c47d541STao Ma set_buffer_uptodate(dir_block); 11643c47d541STao Ma err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); 11653c47d541STao Ma if (err) 11663c47d541STao Ma return err; 1167b9cf625dSEric Biggers set_buffer_verified(dir_block); 1168b9cf625dSEric Biggers return ext4_mark_inode_dirty(handle, inode); 11693c47d541STao Ma } 11703c47d541STao Ma 11713c47d541STao Ma static int ext4_convert_inline_data_nolock(handle_t *handle, 11723c47d541STao Ma struct inode *inode, 11733c47d541STao Ma struct ext4_iloc *iloc) 11743c47d541STao Ma { 11753c47d541STao Ma int error; 11763c47d541STao Ma void *buf = NULL; 11773c47d541STao Ma struct buffer_head *data_bh = NULL; 11783c47d541STao Ma struct ext4_map_blocks map; 11793c47d541STao Ma int inline_size; 11803c47d541STao Ma 11813c47d541STao Ma inline_size = ext4_get_inline_size(inode); 11823c47d541STao Ma buf = kmalloc(inline_size, GFP_NOFS); 11833c47d541STao Ma if (!buf) { 11843c47d541STao Ma error = -ENOMEM; 11853c47d541STao Ma goto out; 11863c47d541STao Ma } 11873c47d541STao Ma 11883c47d541STao Ma error = ext4_read_inline_data(inode, buf, inline_size, iloc); 11893c47d541STao Ma if (error < 0) 11903c47d541STao Ma goto out; 11913c47d541STao Ma 119240b163f1SDarrick J. Wong /* 119340b163f1SDarrick J. Wong * Make sure the inline directory entries pass checks before we try to 119440b163f1SDarrick J. Wong * convert them, so that we avoid touching stuff that needs fsck. 119540b163f1SDarrick J. Wong */ 119640b163f1SDarrick J. Wong if (S_ISDIR(inode->i_mode)) { 119740b163f1SDarrick J. Wong error = ext4_check_all_de(inode, iloc->bh, 119840b163f1SDarrick J. Wong buf + EXT4_INLINE_DOTDOT_SIZE, 119940b163f1SDarrick J. Wong inline_size - EXT4_INLINE_DOTDOT_SIZE); 120040b163f1SDarrick J. Wong if (error) 120140b163f1SDarrick J. Wong goto out; 120240b163f1SDarrick J. Wong } 120340b163f1SDarrick J. Wong 12043c47d541STao Ma error = ext4_destroy_inline_data_nolock(handle, inode); 12053c47d541STao Ma if (error) 12063c47d541STao Ma goto out; 12073c47d541STao Ma 12083c47d541STao Ma map.m_lblk = 0; 12093c47d541STao Ma map.m_len = 1; 12103c47d541STao Ma map.m_flags = 0; 12113c47d541STao Ma error = ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_CREATE); 12123c47d541STao Ma if (error < 0) 12133c47d541STao Ma goto out_restore; 12143c47d541STao Ma if (!(map.m_flags & EXT4_MAP_MAPPED)) { 12153c47d541STao Ma error = -EIO; 12163c47d541STao Ma goto out_restore; 12173c47d541STao Ma } 12183c47d541STao Ma 12193c47d541STao Ma data_bh = sb_getblk(inode->i_sb, map.m_pblk); 12203c47d541STao Ma if (!data_bh) { 1221860d21e2STheodore Ts'o error = -ENOMEM; 12223c47d541STao Ma goto out_restore; 12233c47d541STao Ma } 12243c47d541STao Ma 12253c47d541STao Ma lock_buffer(data_bh); 12263c47d541STao Ma error = ext4_journal_get_create_access(handle, data_bh); 12273c47d541STao Ma if (error) { 12283c47d541STao Ma unlock_buffer(data_bh); 12293c47d541STao Ma error = -EIO; 12303c47d541STao Ma goto out_restore; 12313c47d541STao Ma } 12323c47d541STao Ma memset(data_bh->b_data, 0, inode->i_sb->s_blocksize); 12333c47d541STao Ma 12343c47d541STao Ma if (!S_ISDIR(inode->i_mode)) { 12353c47d541STao Ma memcpy(data_bh->b_data, buf, inline_size); 12363c47d541STao Ma set_buffer_uptodate(data_bh); 12373c47d541STao Ma error = ext4_handle_dirty_metadata(handle, 12383c47d541STao Ma inode, data_bh); 12393c47d541STao Ma } else { 12403c47d541STao Ma error = ext4_finish_convert_inline_dir(handle, inode, data_bh, 12413c47d541STao Ma buf, inline_size); 12423c47d541STao Ma } 12433c47d541STao Ma 12443c47d541STao Ma unlock_buffer(data_bh); 12453c47d541STao Ma out_restore: 12463c47d541STao Ma if (error) 12473c47d541STao Ma ext4_restore_inline_data(handle, inode, iloc, buf, inline_size); 12483c47d541STao Ma 12493c47d541STao Ma out: 12503c47d541STao Ma brelse(data_bh); 12513c47d541STao Ma kfree(buf); 12523c47d541STao Ma return error; 12533c47d541STao Ma } 12543c47d541STao Ma 12553c47d541STao Ma /* 12563c47d541STao Ma * Try to add the new entry to the inline data. 12573c47d541STao Ma * If succeeds, return 0. If not, extended the inline dir and copied data to 12583c47d541STao Ma * the new created block. 12593c47d541STao Ma */ 12605b643f9cSTheodore Ts'o int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, 126156a04915STheodore Ts'o struct inode *dir, struct inode *inode) 12623c47d541STao Ma { 1263c755e251STheodore Ts'o int ret, inline_size, no_expand; 12643c47d541STao Ma void *inline_start; 12653c47d541STao Ma struct ext4_iloc iloc; 12663c47d541STao Ma 12673c47d541STao Ma ret = ext4_get_inode_loc(dir, &iloc); 12683c47d541STao Ma if (ret) 12693c47d541STao Ma return ret; 12703c47d541STao Ma 1271c755e251STheodore Ts'o ext4_write_lock_xattr(dir, &no_expand); 12723c47d541STao Ma if (!ext4_has_inline_data(dir)) 12733c47d541STao Ma goto out; 12743c47d541STao Ma 12753c47d541STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 12763c47d541STao Ma EXT4_INLINE_DOTDOT_SIZE; 12773c47d541STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; 12783c47d541STao Ma 127956a04915STheodore Ts'o ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, 12803c47d541STao Ma inline_start, inline_size); 12813c47d541STao Ma if (ret != -ENOSPC) 12823c47d541STao Ma goto out; 12833c47d541STao Ma 12843c47d541STao Ma /* check whether it can be inserted to inline xattr space. */ 12853c47d541STao Ma inline_size = EXT4_I(dir)->i_inline_size - 12863c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE; 12873c47d541STao Ma if (!inline_size) { 12883c47d541STao Ma /* Try to use the xattr space.*/ 12893c47d541STao Ma ret = ext4_update_inline_dir(handle, dir, &iloc); 12903c47d541STao Ma if (ret && ret != -ENOSPC) 12913c47d541STao Ma goto out; 12923c47d541STao Ma 12933c47d541STao Ma inline_size = EXT4_I(dir)->i_inline_size - 12943c47d541STao Ma EXT4_MIN_INLINE_DATA_SIZE; 12953c47d541STao Ma } 12963c47d541STao Ma 12973c47d541STao Ma if (inline_size) { 12983c47d541STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 12993c47d541STao Ma 130056a04915STheodore Ts'o ret = ext4_add_dirent_to_inline(handle, fname, dir, 13015b643f9cSTheodore Ts'o inode, &iloc, inline_start, 13025b643f9cSTheodore Ts'o inline_size); 13033c47d541STao Ma 13043c47d541STao Ma if (ret != -ENOSPC) 13053c47d541STao Ma goto out; 13063c47d541STao Ma } 13073c47d541STao Ma 13083c47d541STao Ma /* 13093c47d541STao Ma * The inline space is filled up, so create a new block for it. 13103c47d541STao Ma * As the extent tree will be created, we have to save the inline 13113c47d541STao Ma * dir first. 13123c47d541STao Ma */ 13133c47d541STao Ma ret = ext4_convert_inline_data_nolock(handle, dir, &iloc); 13143c47d541STao Ma 13153c47d541STao Ma out: 1316c755e251STheodore Ts'o ext4_write_unlock_xattr(dir, &no_expand); 1317b907f2d5STheodore Ts'o ext4_mark_inode_dirty(handle, dir); 13183c47d541STao Ma brelse(iloc.bh); 13193c47d541STao Ma return ret; 13203c47d541STao Ma } 13213c47d541STao Ma 13228af0f082STao Ma /* 13238af0f082STao Ma * This function fills a red-black tree with information from an 13248af0f082STao Ma * inlined dir. It returns the number directory entries loaded 13258af0f082STao Ma * into the tree. If there is an error it is returned in err. 13268af0f082STao Ma */ 13278af0f082STao Ma int htree_inlinedir_to_tree(struct file *dir_file, 13288af0f082STao Ma struct inode *dir, ext4_lblk_t block, 13298af0f082STao Ma struct dx_hash_info *hinfo, 13308af0f082STao Ma __u32 start_hash, __u32 start_minor_hash, 13318af0f082STao Ma int *has_inline_data) 13328af0f082STao Ma { 13338af0f082STao Ma int err = 0, count = 0; 13348af0f082STao Ma unsigned int parent_ino; 13358af0f082STao Ma int pos; 13368af0f082STao Ma struct ext4_dir_entry_2 *de; 13378af0f082STao Ma struct inode *inode = file_inode(dir_file); 13388af0f082STao Ma int ret, inline_size = 0; 13398af0f082STao Ma struct ext4_iloc iloc; 13408af0f082STao Ma void *dir_buf = NULL; 13418af0f082STao Ma struct ext4_dir_entry_2 fake; 1342a7550b30SJaegeuk Kim struct fscrypt_str tmp_str; 13438af0f082STao Ma 13448af0f082STao Ma ret = ext4_get_inode_loc(inode, &iloc); 13458af0f082STao Ma if (ret) 13468af0f082STao Ma return ret; 13478af0f082STao Ma 13488af0f082STao Ma down_read(&EXT4_I(inode)->xattr_sem); 13498af0f082STao Ma if (!ext4_has_inline_data(inode)) { 13508af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13518af0f082STao Ma *has_inline_data = 0; 13528af0f082STao Ma goto out; 13538af0f082STao Ma } 13548af0f082STao Ma 13558af0f082STao Ma inline_size = ext4_get_inline_size(inode); 13568af0f082STao Ma dir_buf = kmalloc(inline_size, GFP_NOFS); 13578af0f082STao Ma if (!dir_buf) { 13588af0f082STao Ma ret = -ENOMEM; 13598af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13608af0f082STao Ma goto out; 13618af0f082STao Ma } 13628af0f082STao Ma 13638af0f082STao Ma ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); 13648af0f082STao Ma up_read(&EXT4_I(inode)->xattr_sem); 13658af0f082STao Ma if (ret < 0) 13668af0f082STao Ma goto out; 13678af0f082STao Ma 13688af0f082STao Ma pos = 0; 13698af0f082STao Ma parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 13708af0f082STao Ma while (pos < inline_size) { 13718af0f082STao Ma /* 13728af0f082STao Ma * As inlined dir doesn't store any information about '.' and 13738af0f082STao Ma * only the inode number of '..' is stored, we have to handle 13748af0f082STao Ma * them differently. 13758af0f082STao Ma */ 13768af0f082STao Ma if (pos == 0) { 13778af0f082STao Ma fake.inode = cpu_to_le32(inode->i_ino); 13788af0f082STao Ma fake.name_len = 1; 13798af0f082STao Ma strcpy(fake.name, "."); 13808af0f082STao Ma fake.rec_len = ext4_rec_len_to_disk( 13818af0f082STao Ma EXT4_DIR_REC_LEN(fake.name_len), 13828af0f082STao Ma inline_size); 13838af0f082STao Ma ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); 13848af0f082STao Ma de = &fake; 13858af0f082STao Ma pos = EXT4_INLINE_DOTDOT_OFFSET; 13868af0f082STao Ma } else if (pos == EXT4_INLINE_DOTDOT_OFFSET) { 13878af0f082STao Ma fake.inode = cpu_to_le32(parent_ino); 13888af0f082STao Ma fake.name_len = 2; 13898af0f082STao Ma strcpy(fake.name, ".."); 13908af0f082STao Ma fake.rec_len = ext4_rec_len_to_disk( 13918af0f082STao Ma EXT4_DIR_REC_LEN(fake.name_len), 13928af0f082STao Ma inline_size); 13938af0f082STao Ma ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); 13948af0f082STao Ma de = &fake; 13958af0f082STao Ma pos = EXT4_INLINE_DOTDOT_SIZE; 13968af0f082STao Ma } else { 13978af0f082STao Ma de = (struct ext4_dir_entry_2 *)(dir_buf + pos); 13988af0f082STao Ma pos += ext4_rec_len_from_disk(de->rec_len, inline_size); 13998af0f082STao Ma if (ext4_check_dir_entry(inode, dir_file, de, 14008af0f082STao Ma iloc.bh, dir_buf, 14018af0f082STao Ma inline_size, pos)) { 14028af0f082STao Ma ret = count; 14038af0f082STao Ma goto out; 14048af0f082STao Ma } 14058af0f082STao Ma } 14068af0f082STao Ma 14078af0f082STao Ma ext4fs_dirhash(de->name, de->name_len, hinfo); 14088af0f082STao Ma if ((hinfo->hash < start_hash) || 14098af0f082STao Ma ((hinfo->hash == start_hash) && 14108af0f082STao Ma (hinfo->minor_hash < start_minor_hash))) 14118af0f082STao Ma continue; 14128af0f082STao Ma if (de->inode == 0) 14138af0f082STao Ma continue; 14142f61830aSTheodore Ts'o tmp_str.name = de->name; 14152f61830aSTheodore Ts'o tmp_str.len = de->name_len; 14162f61830aSTheodore Ts'o err = ext4_htree_store_dirent(dir_file, hinfo->hash, 14172f61830aSTheodore Ts'o hinfo->minor_hash, de, &tmp_str); 14188af0f082STao Ma if (err) { 14198af0f082STao Ma count = err; 14208af0f082STao Ma goto out; 14218af0f082STao Ma } 14228af0f082STao Ma count++; 14238af0f082STao Ma } 14248af0f082STao Ma ret = count; 14258af0f082STao Ma out: 14268af0f082STao Ma kfree(dir_buf); 14278af0f082STao Ma brelse(iloc.bh); 14288af0f082STao Ma return ret; 14298af0f082STao Ma } 14308af0f082STao Ma 1431c4d8b023STao Ma /* 1432c4d8b023STao Ma * So this function is called when the volume is mkfsed with 1433c4d8b023STao Ma * dir_index disabled. In order to keep f_pos persistent 1434c4d8b023STao Ma * after we convert from an inlined dir to a blocked based, 1435c4d8b023STao Ma * we just pretend that we are a normal dir and return the 1436c4d8b023STao Ma * offset as if '.' and '..' really take place. 1437c4d8b023STao Ma * 1438c4d8b023STao Ma */ 1439725bebb2SAl Viro int ext4_read_inline_dir(struct file *file, 1440725bebb2SAl Viro struct dir_context *ctx, 144165d165d9STao Ma int *has_inline_data) 144265d165d9STao Ma { 144365d165d9STao Ma unsigned int offset, parent_ino; 1444725bebb2SAl Viro int i; 144565d165d9STao Ma struct ext4_dir_entry_2 *de; 144665d165d9STao Ma struct super_block *sb; 1447725bebb2SAl Viro struct inode *inode = file_inode(file); 144865d165d9STao Ma int ret, inline_size = 0; 144965d165d9STao Ma struct ext4_iloc iloc; 145065d165d9STao Ma void *dir_buf = NULL; 1451c4d8b023STao Ma int dotdot_offset, dotdot_size, extra_offset, extra_size; 145265d165d9STao Ma 145365d165d9STao Ma ret = ext4_get_inode_loc(inode, &iloc); 145465d165d9STao Ma if (ret) 145565d165d9STao Ma return ret; 145665d165d9STao Ma 145765d165d9STao Ma down_read(&EXT4_I(inode)->xattr_sem); 145865d165d9STao Ma if (!ext4_has_inline_data(inode)) { 145965d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 146065d165d9STao Ma *has_inline_data = 0; 146165d165d9STao Ma goto out; 146265d165d9STao Ma } 146365d165d9STao Ma 146465d165d9STao Ma inline_size = ext4_get_inline_size(inode); 146565d165d9STao Ma dir_buf = kmalloc(inline_size, GFP_NOFS); 146665d165d9STao Ma if (!dir_buf) { 146765d165d9STao Ma ret = -ENOMEM; 146865d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 146965d165d9STao Ma goto out; 147065d165d9STao Ma } 147165d165d9STao Ma 147265d165d9STao Ma ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); 147365d165d9STao Ma up_read(&EXT4_I(inode)->xattr_sem); 147465d165d9STao Ma if (ret < 0) 147565d165d9STao Ma goto out; 147665d165d9STao Ma 147748ffdab1SBoxiLiu ret = 0; 147865d165d9STao Ma sb = inode->i_sb; 147965d165d9STao Ma parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 1480725bebb2SAl Viro offset = ctx->pos; 148165d165d9STao Ma 1482c4d8b023STao Ma /* 1483c4d8b023STao Ma * dotdot_offset and dotdot_size is the real offset and 1484c4d8b023STao Ma * size for ".." and "." if the dir is block based while 1485c4d8b023STao Ma * the real size for them are only EXT4_INLINE_DOTDOT_SIZE. 1486c4d8b023STao Ma * So we will use extra_offset and extra_size to indicate them 1487c4d8b023STao Ma * during the inline dir iteration. 1488c4d8b023STao Ma */ 1489c4d8b023STao Ma dotdot_offset = EXT4_DIR_REC_LEN(1); 1490c4d8b023STao Ma dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2); 1491c4d8b023STao Ma extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; 1492c4d8b023STao Ma extra_size = extra_offset + inline_size; 1493c4d8b023STao Ma 149465d165d9STao Ma /* 149565d165d9STao Ma * If the version has changed since the last call to 149665d165d9STao Ma * readdir(2), then we might be pointing to an invalid 149765d165d9STao Ma * dirent right now. Scan from the start of the inline 149865d165d9STao Ma * dir to make sure. 149965d165d9STao Ma */ 1500c472c07bSGoffredo Baroncelli if (!inode_eq_iversion(inode, file->f_version)) { 1501c4d8b023STao Ma for (i = 0; i < extra_size && i < offset;) { 1502c4d8b023STao Ma /* 1503c4d8b023STao Ma * "." is with offset 0 and 1504c4d8b023STao Ma * ".." is dotdot_offset. 1505c4d8b023STao Ma */ 150665d165d9STao Ma if (!i) { 1507c4d8b023STao Ma i = dotdot_offset; 1508c4d8b023STao Ma continue; 1509c4d8b023STao Ma } else if (i == dotdot_offset) { 1510c4d8b023STao Ma i = dotdot_size; 151165d165d9STao Ma continue; 151265d165d9STao Ma } 1513c4d8b023STao Ma /* for other entry, the real offset in 1514c4d8b023STao Ma * the buf has to be tuned accordingly. 1515c4d8b023STao Ma */ 151665d165d9STao Ma de = (struct ext4_dir_entry_2 *) 1517c4d8b023STao Ma (dir_buf + i - extra_offset); 151865d165d9STao Ma /* It's too expensive to do a full 151965d165d9STao Ma * dirent test each time round this 152065d165d9STao Ma * loop, but we do have to test at 152165d165d9STao Ma * least that it is non-zero. A 152265d165d9STao Ma * failure will be detected in the 152365d165d9STao Ma * dirent test below. */ 1524725bebb2SAl Viro if (ext4_rec_len_from_disk(de->rec_len, extra_size) 1525725bebb2SAl Viro < EXT4_DIR_REC_LEN(1)) 152665d165d9STao Ma break; 152765d165d9STao Ma i += ext4_rec_len_from_disk(de->rec_len, 1528c4d8b023STao Ma extra_size); 152965d165d9STao Ma } 153065d165d9STao Ma offset = i; 1531725bebb2SAl Viro ctx->pos = offset; 1532ee73f9a5SJeff Layton file->f_version = inode_query_iversion(inode); 153365d165d9STao Ma } 153465d165d9STao Ma 1535725bebb2SAl Viro while (ctx->pos < extra_size) { 1536725bebb2SAl Viro if (ctx->pos == 0) { 1537725bebb2SAl Viro if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) 1538725bebb2SAl Viro goto out; 1539725bebb2SAl Viro ctx->pos = dotdot_offset; 1540c4d8b023STao Ma continue; 1541c4d8b023STao Ma } 154265d165d9STao Ma 1543725bebb2SAl Viro if (ctx->pos == dotdot_offset) { 1544725bebb2SAl Viro if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR)) 1545725bebb2SAl Viro goto out; 1546725bebb2SAl Viro ctx->pos = dotdot_size; 154765d165d9STao Ma continue; 154865d165d9STao Ma } 154965d165d9STao Ma 1550c4d8b023STao Ma de = (struct ext4_dir_entry_2 *) 1551725bebb2SAl Viro (dir_buf + ctx->pos - extra_offset); 1552725bebb2SAl Viro if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf, 1553725bebb2SAl Viro extra_size, ctx->pos)) 1554725bebb2SAl Viro goto out; 1555725bebb2SAl Viro if (le32_to_cpu(de->inode)) { 1556725bebb2SAl Viro if (!dir_emit(ctx, de->name, de->name_len, 1557725bebb2SAl Viro le32_to_cpu(de->inode), 1558725bebb2SAl Viro get_dtype(sb, de->file_type))) 155965d165d9STao Ma goto out; 156065d165d9STao Ma } 1561725bebb2SAl Viro ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size); 156265d165d9STao Ma } 156365d165d9STao Ma out: 156465d165d9STao Ma kfree(dir_buf); 156565d165d9STao Ma brelse(iloc.bh); 156665d165d9STao Ma return ret; 156765d165d9STao Ma } 156865d165d9STao Ma 156932f7f22cSTao Ma struct buffer_head *ext4_get_first_inline_block(struct inode *inode, 157032f7f22cSTao Ma struct ext4_dir_entry_2 **parent_de, 157132f7f22cSTao Ma int *retval) 157232f7f22cSTao Ma { 157332f7f22cSTao Ma struct ext4_iloc iloc; 157432f7f22cSTao Ma 157532f7f22cSTao Ma *retval = ext4_get_inode_loc(inode, &iloc); 157632f7f22cSTao Ma if (*retval) 157732f7f22cSTao Ma return NULL; 157832f7f22cSTao Ma 157932f7f22cSTao Ma *parent_de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 158032f7f22cSTao Ma 158132f7f22cSTao Ma return iloc.bh; 158232f7f22cSTao Ma } 158332f7f22cSTao Ma 15843c47d541STao Ma /* 15853c47d541STao Ma * Try to create the inline data for the new dir. 15863c47d541STao Ma * If it succeeds, return 0, otherwise return the error. 15873c47d541STao Ma * In case of ENOSPC, the caller should create the normal disk layout dir. 15883c47d541STao Ma */ 15893c47d541STao Ma int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent, 15903c47d541STao Ma struct inode *inode) 15913c47d541STao Ma { 15923c47d541STao Ma int ret, inline_size = EXT4_MIN_INLINE_DATA_SIZE; 15933c47d541STao Ma struct ext4_iloc iloc; 15943c47d541STao Ma struct ext4_dir_entry_2 *de; 15953c47d541STao Ma 15963c47d541STao Ma ret = ext4_get_inode_loc(inode, &iloc); 15973c47d541STao Ma if (ret) 15983c47d541STao Ma return ret; 15993c47d541STao Ma 16003c47d541STao Ma ret = ext4_prepare_inline_data(handle, inode, inline_size); 16013c47d541STao Ma if (ret) 16023c47d541STao Ma goto out; 16033c47d541STao Ma 16043c47d541STao Ma /* 16053c47d541STao Ma * For inline dir, we only save the inode information for the ".." 16063c47d541STao Ma * and create a fake dentry to cover the left space. 16073c47d541STao Ma */ 16083c47d541STao Ma de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 16093c47d541STao Ma de->inode = cpu_to_le32(parent->i_ino); 16103c47d541STao Ma de = (struct ext4_dir_entry_2 *)((void *)de + EXT4_INLINE_DOTDOT_SIZE); 16113c47d541STao Ma de->inode = 0; 16123c47d541STao Ma de->rec_len = ext4_rec_len_to_disk( 16133c47d541STao Ma inline_size - EXT4_INLINE_DOTDOT_SIZE, 16143c47d541STao Ma inline_size); 16153c47d541STao Ma set_nlink(inode, 2); 16163c47d541STao Ma inode->i_size = EXT4_I(inode)->i_disksize = inline_size; 16173c47d541STao Ma out: 16183c47d541STao Ma brelse(iloc.bh); 16193c47d541STao Ma return ret; 16203c47d541STao Ma } 16213c47d541STao Ma 1622e8e948e7STao Ma struct buffer_head *ext4_find_inline_entry(struct inode *dir, 16235b643f9cSTheodore Ts'o struct ext4_filename *fname, 1624e8e948e7STao Ma struct ext4_dir_entry_2 **res_dir, 1625e8e948e7STao Ma int *has_inline_data) 1626e8e948e7STao Ma { 1627e8e948e7STao Ma int ret; 1628e8e948e7STao Ma struct ext4_iloc iloc; 1629e8e948e7STao Ma void *inline_start; 1630e8e948e7STao Ma int inline_size; 1631e8e948e7STao Ma 1632e8e948e7STao Ma if (ext4_get_inode_loc(dir, &iloc)) 1633e8e948e7STao Ma return NULL; 1634e8e948e7STao Ma 1635e8e948e7STao Ma down_read(&EXT4_I(dir)->xattr_sem); 1636e8e948e7STao Ma if (!ext4_has_inline_data(dir)) { 1637e8e948e7STao Ma *has_inline_data = 0; 1638e8e948e7STao Ma goto out; 1639e8e948e7STao Ma } 1640e8e948e7STao Ma 1641e8e948e7STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 1642e8e948e7STao Ma EXT4_INLINE_DOTDOT_SIZE; 1643e8e948e7STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; 16445b643f9cSTheodore Ts'o ret = ext4_search_dir(iloc.bh, inline_start, inline_size, 1645d6b97550SEric Biggers dir, fname, 0, res_dir); 1646e8e948e7STao Ma if (ret == 1) 1647e8e948e7STao Ma goto out_find; 1648e8e948e7STao Ma if (ret < 0) 1649e8e948e7STao Ma goto out; 1650e8e948e7STao Ma 1651e8e948e7STao Ma if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE) 1652e8e948e7STao Ma goto out; 1653e8e948e7STao Ma 1654e8e948e7STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 1655e8e948e7STao Ma inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE; 1656e8e948e7STao Ma 16575b643f9cSTheodore Ts'o ret = ext4_search_dir(iloc.bh, inline_start, inline_size, 1658d6b97550SEric Biggers dir, fname, 0, res_dir); 1659e8e948e7STao Ma if (ret == 1) 1660e8e948e7STao Ma goto out_find; 1661e8e948e7STao Ma 1662e8e948e7STao Ma out: 1663e8e948e7STao Ma brelse(iloc.bh); 1664e8e948e7STao Ma iloc.bh = NULL; 1665e8e948e7STao Ma out_find: 1666e8e948e7STao Ma up_read(&EXT4_I(dir)->xattr_sem); 1667e8e948e7STao Ma return iloc.bh; 1668e8e948e7STao Ma } 1669e8e948e7STao Ma 16709f40fe54STao Ma int ext4_delete_inline_entry(handle_t *handle, 16719f40fe54STao Ma struct inode *dir, 16729f40fe54STao Ma struct ext4_dir_entry_2 *de_del, 16739f40fe54STao Ma struct buffer_head *bh, 16749f40fe54STao Ma int *has_inline_data) 16759f40fe54STao Ma { 1676c755e251STheodore Ts'o int err, inline_size, no_expand; 16779f40fe54STao Ma struct ext4_iloc iloc; 16789f40fe54STao Ma void *inline_start; 16799f40fe54STao Ma 16809f40fe54STao Ma err = ext4_get_inode_loc(dir, &iloc); 16819f40fe54STao Ma if (err) 16829f40fe54STao Ma return err; 16839f40fe54STao Ma 1684c755e251STheodore Ts'o ext4_write_lock_xattr(dir, &no_expand); 16859f40fe54STao Ma if (!ext4_has_inline_data(dir)) { 16869f40fe54STao Ma *has_inline_data = 0; 16879f40fe54STao Ma goto out; 16889f40fe54STao Ma } 16899f40fe54STao Ma 16909f40fe54STao Ma if ((void *)de_del - ((void *)ext4_raw_inode(&iloc)->i_block) < 16919f40fe54STao Ma EXT4_MIN_INLINE_DATA_SIZE) { 16929f40fe54STao Ma inline_start = (void *)ext4_raw_inode(&iloc)->i_block + 16939f40fe54STao Ma EXT4_INLINE_DOTDOT_SIZE; 16949f40fe54STao Ma inline_size = EXT4_MIN_INLINE_DATA_SIZE - 16959f40fe54STao Ma EXT4_INLINE_DOTDOT_SIZE; 16969f40fe54STao Ma } else { 16979f40fe54STao Ma inline_start = ext4_get_inline_xattr_pos(dir, &iloc); 16989f40fe54STao Ma inline_size = ext4_get_inline_size(dir) - 16999f40fe54STao Ma EXT4_MIN_INLINE_DATA_SIZE; 17009f40fe54STao Ma } 17019f40fe54STao Ma 17025d601255Sliang xie BUFFER_TRACE(bh, "get_write_access"); 17039f40fe54STao Ma err = ext4_journal_get_write_access(handle, bh); 17049f40fe54STao Ma if (err) 17059f40fe54STao Ma goto out; 17069f40fe54STao Ma 17079f40fe54STao Ma err = ext4_generic_delete_entry(handle, dir, de_del, bh, 17089f40fe54STao Ma inline_start, inline_size, 0); 17099f40fe54STao Ma if (err) 17109f40fe54STao Ma goto out; 17119f40fe54STao Ma 17129f40fe54STao Ma ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size); 17139f40fe54STao Ma out: 1714c755e251STheodore Ts'o ext4_write_unlock_xattr(dir, &no_expand); 1715b907f2d5STheodore Ts'o if (likely(err == 0)) 1716b907f2d5STheodore Ts'o err = ext4_mark_inode_dirty(handle, dir); 17179f40fe54STao Ma brelse(iloc.bh); 17189f40fe54STao Ma if (err != -ENOENT) 17199f40fe54STao Ma ext4_std_error(dir->i_sb, err); 17209f40fe54STao Ma return err; 17219f40fe54STao Ma } 17229f40fe54STao Ma 172361f86638STao Ma /* 172461f86638STao Ma * Get the inline dentry at offset. 172561f86638STao Ma */ 172661f86638STao Ma static inline struct ext4_dir_entry_2 * 172761f86638STao Ma ext4_get_inline_entry(struct inode *inode, 172861f86638STao Ma struct ext4_iloc *iloc, 172961f86638STao Ma unsigned int offset, 173061f86638STao Ma void **inline_start, 173161f86638STao Ma int *inline_size) 173261f86638STao Ma { 173361f86638STao Ma void *inline_pos; 173461f86638STao Ma 173561f86638STao Ma BUG_ON(offset > ext4_get_inline_size(inode)); 173661f86638STao Ma 173761f86638STao Ma if (offset < EXT4_MIN_INLINE_DATA_SIZE) { 173861f86638STao Ma inline_pos = (void *)ext4_raw_inode(iloc)->i_block; 173961f86638STao Ma *inline_size = EXT4_MIN_INLINE_DATA_SIZE; 174061f86638STao Ma } else { 174161f86638STao Ma inline_pos = ext4_get_inline_xattr_pos(inode, iloc); 174261f86638STao Ma offset -= EXT4_MIN_INLINE_DATA_SIZE; 174361f86638STao Ma *inline_size = ext4_get_inline_size(inode) - 174461f86638STao Ma EXT4_MIN_INLINE_DATA_SIZE; 174561f86638STao Ma } 174661f86638STao Ma 174761f86638STao Ma if (inline_start) 174861f86638STao Ma *inline_start = inline_pos; 174961f86638STao Ma return (struct ext4_dir_entry_2 *)(inline_pos + offset); 175061f86638STao Ma } 175161f86638STao Ma 1752a7550b30SJaegeuk Kim bool empty_inline_dir(struct inode *dir, int *has_inline_data) 175361f86638STao Ma { 175461f86638STao Ma int err, inline_size; 175561f86638STao Ma struct ext4_iloc iloc; 1756*4d982e25STheodore Ts'o size_t inline_len; 175761f86638STao Ma void *inline_pos; 175861f86638STao Ma unsigned int offset; 175961f86638STao Ma struct ext4_dir_entry_2 *de; 1760a7550b30SJaegeuk Kim bool ret = true; 176161f86638STao Ma 176261f86638STao Ma err = ext4_get_inode_loc(dir, &iloc); 176361f86638STao Ma if (err) { 176461f86638STao Ma EXT4_ERROR_INODE(dir, "error %d getting inode %lu block", 176561f86638STao Ma err, dir->i_ino); 1766a7550b30SJaegeuk Kim return true; 176761f86638STao Ma } 176861f86638STao Ma 176961f86638STao Ma down_read(&EXT4_I(dir)->xattr_sem); 177061f86638STao Ma if (!ext4_has_inline_data(dir)) { 177161f86638STao Ma *has_inline_data = 0; 177261f86638STao Ma goto out; 177361f86638STao Ma } 177461f86638STao Ma 177561f86638STao Ma de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; 177661f86638STao Ma if (!le32_to_cpu(de->inode)) { 177761f86638STao Ma ext4_warning(dir->i_sb, 177861f86638STao Ma "bad inline directory (dir #%lu) - no `..'", 177961f86638STao Ma dir->i_ino); 1780a7550b30SJaegeuk Kim ret = true; 178161f86638STao Ma goto out; 178261f86638STao Ma } 178361f86638STao Ma 1784*4d982e25STheodore Ts'o inline_len = ext4_get_inline_size(dir); 178561f86638STao Ma offset = EXT4_INLINE_DOTDOT_SIZE; 1786*4d982e25STheodore Ts'o while (offset < inline_len) { 178761f86638STao Ma de = ext4_get_inline_entry(dir, &iloc, offset, 178861f86638STao Ma &inline_pos, &inline_size); 178961f86638STao Ma if (ext4_check_dir_entry(dir, NULL, de, 179061f86638STao Ma iloc.bh, inline_pos, 179161f86638STao Ma inline_size, offset)) { 179261f86638STao Ma ext4_warning(dir->i_sb, 179361f86638STao Ma "bad inline directory (dir #%lu) - " 179461f86638STao Ma "inode %u, rec_len %u, name_len %d" 17958d2ae1cbSJakub Wilk "inline size %d", 179661f86638STao Ma dir->i_ino, le32_to_cpu(de->inode), 179761f86638STao Ma le16_to_cpu(de->rec_len), de->name_len, 179861f86638STao Ma inline_size); 1799a7550b30SJaegeuk Kim ret = true; 180061f86638STao Ma goto out; 180161f86638STao Ma } 180261f86638STao Ma if (le32_to_cpu(de->inode)) { 1803a7550b30SJaegeuk Kim ret = false; 180461f86638STao Ma goto out; 180561f86638STao Ma } 180661f86638STao Ma offset += ext4_rec_len_from_disk(de->rec_len, inline_size); 180761f86638STao Ma } 180861f86638STao Ma 180961f86638STao Ma out: 181061f86638STao Ma up_read(&EXT4_I(dir)->xattr_sem); 181161f86638STao Ma brelse(iloc.bh); 181261f86638STao Ma return ret; 181361f86638STao Ma } 181461f86638STao Ma 181567cf5b09STao Ma int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) 181667cf5b09STao Ma { 1817c755e251STheodore Ts'o int ret, no_expand; 181867cf5b09STao Ma 1819c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 182067cf5b09STao Ma ret = ext4_destroy_inline_data_nolock(handle, inode); 1821c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 182267cf5b09STao Ma 182367cf5b09STao Ma return ret; 182467cf5b09STao Ma } 182594191985STao Ma 18267046ae35SAndreas Gruenbacher int ext4_inline_data_iomap(struct inode *inode, struct iomap *iomap) 18277046ae35SAndreas Gruenbacher { 18287046ae35SAndreas Gruenbacher __u64 addr; 18297046ae35SAndreas Gruenbacher int error = -EAGAIN; 18307046ae35SAndreas Gruenbacher struct ext4_iloc iloc; 18317046ae35SAndreas Gruenbacher 18327046ae35SAndreas Gruenbacher down_read(&EXT4_I(inode)->xattr_sem); 18337046ae35SAndreas Gruenbacher if (!ext4_has_inline_data(inode)) 18347046ae35SAndreas Gruenbacher goto out; 18357046ae35SAndreas Gruenbacher 18367046ae35SAndreas Gruenbacher error = ext4_get_inode_loc(inode, &iloc); 18377046ae35SAndreas Gruenbacher if (error) 18387046ae35SAndreas Gruenbacher goto out; 18397046ae35SAndreas Gruenbacher 18407046ae35SAndreas Gruenbacher addr = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; 18417046ae35SAndreas Gruenbacher addr += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; 18427046ae35SAndreas Gruenbacher addr += offsetof(struct ext4_inode, i_block); 18437046ae35SAndreas Gruenbacher 18447046ae35SAndreas Gruenbacher brelse(iloc.bh); 18457046ae35SAndreas Gruenbacher 18467046ae35SAndreas Gruenbacher iomap->addr = addr; 18477046ae35SAndreas Gruenbacher iomap->offset = 0; 18487046ae35SAndreas Gruenbacher iomap->length = min_t(loff_t, ext4_get_inline_size(inode), 18497046ae35SAndreas Gruenbacher i_size_read(inode)); 185019319b53SChristoph Hellwig iomap->type = IOMAP_INLINE; 185119319b53SChristoph Hellwig iomap->flags = 0; 18527046ae35SAndreas Gruenbacher 18537046ae35SAndreas Gruenbacher out: 18547046ae35SAndreas Gruenbacher up_read(&EXT4_I(inode)->xattr_sem); 18557046ae35SAndreas Gruenbacher return error; 18567046ae35SAndreas Gruenbacher } 18577046ae35SAndreas Gruenbacher 185894191985STao Ma int ext4_inline_data_fiemap(struct inode *inode, 185994191985STao Ma struct fiemap_extent_info *fieinfo, 1860d952d69eSDmitry Monakhov int *has_inline, __u64 start, __u64 len) 186194191985STao Ma { 186294191985STao Ma __u64 physical = 0; 1863d952d69eSDmitry Monakhov __u64 inline_len; 1864d952d69eSDmitry Monakhov __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | 1865d952d69eSDmitry Monakhov FIEMAP_EXTENT_LAST; 186694191985STao Ma int error = 0; 186794191985STao Ma struct ext4_iloc iloc; 186894191985STao Ma 186994191985STao Ma down_read(&EXT4_I(inode)->xattr_sem); 187094191985STao Ma if (!ext4_has_inline_data(inode)) { 187194191985STao Ma *has_inline = 0; 187294191985STao Ma goto out; 187394191985STao Ma } 1874d952d69eSDmitry Monakhov inline_len = min_t(size_t, ext4_get_inline_size(inode), 1875d952d69eSDmitry Monakhov i_size_read(inode)); 1876d952d69eSDmitry Monakhov if (start >= inline_len) 1877d952d69eSDmitry Monakhov goto out; 1878d952d69eSDmitry Monakhov if (start + len < inline_len) 1879d952d69eSDmitry Monakhov inline_len = start + len; 1880d952d69eSDmitry Monakhov inline_len -= start; 188194191985STao Ma 188294191985STao Ma error = ext4_get_inode_loc(inode, &iloc); 188394191985STao Ma if (error) 188494191985STao Ma goto out; 188594191985STao Ma 1886eaf37937SJan Kara physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; 188794191985STao Ma physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; 188894191985STao Ma physical += offsetof(struct ext4_inode, i_block); 188994191985STao Ma 189094191985STao Ma if (physical) 1891d952d69eSDmitry Monakhov error = fiemap_fill_next_extent(fieinfo, start, physical, 1892d952d69eSDmitry Monakhov inline_len, flags); 189394191985STao Ma brelse(iloc.bh); 189494191985STao Ma out: 189594191985STao Ma up_read(&EXT4_I(inode)->xattr_sem); 189694191985STao Ma return (error < 0 ? error : 0); 189794191985STao Ma } 18980d812f77STao Ma 189901daf945STheodore Ts'o int ext4_inline_data_truncate(struct inode *inode, int *has_inline) 1900aef1c851STao Ma { 1901aef1c851STao Ma handle_t *handle; 190201daf945STheodore Ts'o int inline_size, value_len, needed_blocks, no_expand, err = 0; 1903aef1c851STao Ma size_t i_size; 1904aef1c851STao Ma void *value = NULL; 1905aef1c851STao Ma struct ext4_xattr_ibody_find is = { 1906aef1c851STao Ma .s = { .not_found = -ENODATA, }, 1907aef1c851STao Ma }; 1908aef1c851STao Ma struct ext4_xattr_info i = { 1909aef1c851STao Ma .name_index = EXT4_XATTR_INDEX_SYSTEM, 1910aef1c851STao Ma .name = EXT4_XATTR_SYSTEM_DATA, 1911aef1c851STao Ma }; 1912aef1c851STao Ma 1913aef1c851STao Ma 1914aef1c851STao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 19159924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_INODE, needed_blocks); 1916aef1c851STao Ma if (IS_ERR(handle)) 191701daf945STheodore Ts'o return PTR_ERR(handle); 1918aef1c851STao Ma 1919c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 1920aef1c851STao Ma if (!ext4_has_inline_data(inode)) { 1921aef1c851STao Ma *has_inline = 0; 1922aef1c851STao Ma ext4_journal_stop(handle); 192301daf945STheodore Ts'o return 0; 1924aef1c851STao Ma } 1925aef1c851STao Ma 192601daf945STheodore Ts'o if ((err = ext4_orphan_add(handle, inode)) != 0) 1927aef1c851STao Ma goto out; 1928aef1c851STao Ma 192901daf945STheodore Ts'o if ((err = ext4_get_inode_loc(inode, &is.iloc)) != 0) 1930aef1c851STao Ma goto out; 1931aef1c851STao Ma 1932aef1c851STao Ma down_write(&EXT4_I(inode)->i_data_sem); 1933aef1c851STao Ma i_size = inode->i_size; 1934aef1c851STao Ma inline_size = ext4_get_inline_size(inode); 1935aef1c851STao Ma EXT4_I(inode)->i_disksize = i_size; 1936aef1c851STao Ma 1937aef1c851STao Ma if (i_size < inline_size) { 1938aef1c851STao Ma /* Clear the content in the xattr space. */ 1939aef1c851STao Ma if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) { 194001daf945STheodore Ts'o if ((err = ext4_xattr_ibody_find(inode, &i, &is)) != 0) 1941aef1c851STao Ma goto out_error; 1942aef1c851STao Ma 1943aef1c851STao Ma BUG_ON(is.s.not_found); 1944aef1c851STao Ma 1945aef1c851STao Ma value_len = le32_to_cpu(is.s.here->e_value_size); 1946aef1c851STao Ma value = kmalloc(value_len, GFP_NOFS); 194701daf945STheodore Ts'o if (!value) { 194801daf945STheodore Ts'o err = -ENOMEM; 1949aef1c851STao Ma goto out_error; 195001daf945STheodore Ts'o } 1951aef1c851STao Ma 195201daf945STheodore Ts'o err = ext4_xattr_ibody_get(inode, i.name_index, 195301daf945STheodore Ts'o i.name, value, value_len); 195401daf945STheodore Ts'o if (err <= 0) 1955aef1c851STao Ma goto out_error; 1956aef1c851STao Ma 1957aef1c851STao Ma i.value = value; 1958aef1c851STao Ma i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ? 1959aef1c851STao Ma i_size - EXT4_MIN_INLINE_DATA_SIZE : 0; 196001daf945STheodore Ts'o err = ext4_xattr_ibody_inline_set(handle, inode, 196101daf945STheodore Ts'o &i, &is); 196201daf945STheodore Ts'o if (err) 1963aef1c851STao Ma goto out_error; 1964aef1c851STao Ma } 1965aef1c851STao Ma 1966aef1c851STao Ma /* Clear the content within i_blocks. */ 196709c455aaSTheodore Ts'o if (i_size < EXT4_MIN_INLINE_DATA_SIZE) { 196809c455aaSTheodore Ts'o void *p = (void *) ext4_raw_inode(&is.iloc)->i_block; 196909c455aaSTheodore Ts'o memset(p + i_size, 0, 1970aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE - i_size); 197109c455aaSTheodore Ts'o } 1972aef1c851STao Ma 1973aef1c851STao Ma EXT4_I(inode)->i_inline_size = i_size < 1974aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE ? 1975aef1c851STao Ma EXT4_MIN_INLINE_DATA_SIZE : i_size; 1976aef1c851STao Ma } 1977aef1c851STao Ma 1978aef1c851STao Ma out_error: 1979aef1c851STao Ma up_write(&EXT4_I(inode)->i_data_sem); 1980aef1c851STao Ma out: 1981aef1c851STao Ma brelse(is.iloc.bh); 1982c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 1983aef1c851STao Ma kfree(value); 1984aef1c851STao Ma if (inode->i_nlink) 1985aef1c851STao Ma ext4_orphan_del(handle, inode); 1986aef1c851STao Ma 198701daf945STheodore Ts'o if (err == 0) { 1988eeca7ea1SDeepa Dinamani inode->i_mtime = inode->i_ctime = current_time(inode); 198901daf945STheodore Ts'o err = ext4_mark_inode_dirty(handle, inode); 1990aef1c851STao Ma if (IS_SYNC(inode)) 1991aef1c851STao Ma ext4_handle_sync(handle); 199201daf945STheodore Ts'o } 1993aef1c851STao Ma ext4_journal_stop(handle); 199401daf945STheodore Ts'o return err; 1995aef1c851STao Ma } 19960c8d414fSTao Ma 19970c8d414fSTao Ma int ext4_convert_inline_data(struct inode *inode) 19980c8d414fSTao Ma { 1999c755e251STheodore Ts'o int error, needed_blocks, no_expand; 20000c8d414fSTao Ma handle_t *handle; 20010c8d414fSTao Ma struct ext4_iloc iloc; 20020c8d414fSTao Ma 20030c8d414fSTao Ma if (!ext4_has_inline_data(inode)) { 20040c8d414fSTao Ma ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); 20050c8d414fSTao Ma return 0; 20060c8d414fSTao Ma } 20070c8d414fSTao Ma 20080c8d414fSTao Ma needed_blocks = ext4_writepage_trans_blocks(inode); 20090c8d414fSTao Ma 20100c8d414fSTao Ma iloc.bh = NULL; 20110c8d414fSTao Ma error = ext4_get_inode_loc(inode, &iloc); 20120c8d414fSTao Ma if (error) 20130c8d414fSTao Ma return error; 20140c8d414fSTao Ma 20159924a92aSTheodore Ts'o handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); 20160c8d414fSTao Ma if (IS_ERR(handle)) { 20170c8d414fSTao Ma error = PTR_ERR(handle); 20180c8d414fSTao Ma goto out_free; 20190c8d414fSTao Ma } 20200c8d414fSTao Ma 2021c755e251STheodore Ts'o ext4_write_lock_xattr(inode, &no_expand); 2022c755e251STheodore Ts'o if (ext4_has_inline_data(inode)) 20230c8d414fSTao Ma error = ext4_convert_inline_data_nolock(handle, inode, &iloc); 2024c755e251STheodore Ts'o ext4_write_unlock_xattr(inode, &no_expand); 20250c8d414fSTao Ma ext4_journal_stop(handle); 20260c8d414fSTao Ma out_free: 20270c8d414fSTao Ma brelse(iloc.bh); 20280c8d414fSTao Ma return error; 20290c8d414fSTao Ma } 2030