162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/namei.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 662306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 762306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 862306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * from 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * linux/fs/minix/namei.c 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Big-endian to little-endian byte-swapping/bitmaps by 1762306a36Sopenharmony_ci * David S. Miller (davem@caip.rutgers.edu), 1995 1862306a36Sopenharmony_ci * Directory entry file type support and forward compatibility hooks 1962306a36Sopenharmony_ci * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 2062306a36Sopenharmony_ci * Hash Tree Directory indexing (c) 2162306a36Sopenharmony_ci * Daniel Phillips, 2001 2262306a36Sopenharmony_ci * Hash Tree Directory indexing porting 2362306a36Sopenharmony_ci * Christopher Li, 2002 2462306a36Sopenharmony_ci * Hash Tree Directory indexing cleanup 2562306a36Sopenharmony_ci * Theodore Ts'o, 2002 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/fs.h> 2962306a36Sopenharmony_ci#include <linux/pagemap.h> 3062306a36Sopenharmony_ci#include <linux/time.h> 3162306a36Sopenharmony_ci#include <linux/fcntl.h> 3262306a36Sopenharmony_ci#include <linux/stat.h> 3362306a36Sopenharmony_ci#include <linux/string.h> 3462306a36Sopenharmony_ci#include <linux/quotaops.h> 3562306a36Sopenharmony_ci#include <linux/buffer_head.h> 3662306a36Sopenharmony_ci#include <linux/bio.h> 3762306a36Sopenharmony_ci#include <linux/iversion.h> 3862306a36Sopenharmony_ci#include <linux/unicode.h> 3962306a36Sopenharmony_ci#include "ext4.h" 4062306a36Sopenharmony_ci#include "ext4_jbd2.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "xattr.h" 4362306a36Sopenharmony_ci#include "acl.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <trace/events/ext4.h> 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * define how far ahead to read directories while searching them. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci#define NAMEI_RA_CHUNKS 2 5062306a36Sopenharmony_ci#define NAMEI_RA_BLOCKS 4 5162306a36Sopenharmony_ci#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct buffer_head *ext4_append(handle_t *handle, 5462306a36Sopenharmony_ci struct inode *inode, 5562306a36Sopenharmony_ci ext4_lblk_t *block) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct ext4_map_blocks map; 5862306a36Sopenharmony_ci struct buffer_head *bh; 5962306a36Sopenharmony_ci int err; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb && 6262306a36Sopenharmony_ci ((inode->i_size >> 10) >= 6362306a36Sopenharmony_ci EXT4_SB(inode->i_sb)->s_max_dir_size_kb))) 6462306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci *block = inode->i_size >> inode->i_sb->s_blocksize_bits; 6762306a36Sopenharmony_ci map.m_lblk = *block; 6862306a36Sopenharmony_ci map.m_len = 1; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * We're appending new directory block. Make sure the block is not 7262306a36Sopenharmony_ci * allocated yet, otherwise we will end up corrupting the 7362306a36Sopenharmony_ci * directory. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci err = ext4_map_blocks(NULL, inode, &map, 0); 7662306a36Sopenharmony_ci if (err < 0) 7762306a36Sopenharmony_ci return ERR_PTR(err); 7862306a36Sopenharmony_ci if (err) { 7962306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "Logical block already allocated"); 8062306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE); 8462306a36Sopenharmony_ci if (IS_ERR(bh)) 8562306a36Sopenharmony_ci return bh; 8662306a36Sopenharmony_ci inode->i_size += inode->i_sb->s_blocksize; 8762306a36Sopenharmony_ci EXT4_I(inode)->i_disksize = inode->i_size; 8862306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 8962306a36Sopenharmony_ci if (err) 9062306a36Sopenharmony_ci goto out; 9162306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 9262306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, inode->i_sb, bh, 9362306a36Sopenharmony_ci EXT4_JTR_NONE); 9462306a36Sopenharmony_ci if (err) 9562306a36Sopenharmony_ci goto out; 9662306a36Sopenharmony_ci return bh; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciout: 9962306a36Sopenharmony_ci brelse(bh); 10062306a36Sopenharmony_ci ext4_std_error(inode->i_sb, err); 10162306a36Sopenharmony_ci return ERR_PTR(err); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int ext4_dx_csum_verify(struct inode *inode, 10562306a36Sopenharmony_ci struct ext4_dir_entry *dirent); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Hints to ext4_read_dirblock regarding whether we expect a directory 10962306a36Sopenharmony_ci * block being read to be an index block, or a block containing 11062306a36Sopenharmony_ci * directory entries (and if the latter, whether it was found via a 11162306a36Sopenharmony_ci * logical block in an htree index block). This is used to control 11262306a36Sopenharmony_ci * what sort of sanity checkinig ext4_read_dirblock() will do on the 11362306a36Sopenharmony_ci * directory block read from the storage device. EITHER will means 11462306a36Sopenharmony_ci * the caller doesn't know what kind of directory block will be read, 11562306a36Sopenharmony_ci * so no specific verification will be done. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_citypedef enum { 11862306a36Sopenharmony_ci EITHER, INDEX, DIRENT, DIRENT_HTREE 11962306a36Sopenharmony_ci} dirblock_type_t; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define ext4_read_dirblock(inode, block, type) \ 12262306a36Sopenharmony_ci __ext4_read_dirblock((inode), (block), (type), __func__, __LINE__) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic struct buffer_head *__ext4_read_dirblock(struct inode *inode, 12562306a36Sopenharmony_ci ext4_lblk_t block, 12662306a36Sopenharmony_ci dirblock_type_t type, 12762306a36Sopenharmony_ci const char *func, 12862306a36Sopenharmony_ci unsigned int line) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct buffer_head *bh; 13162306a36Sopenharmony_ci struct ext4_dir_entry *dirent; 13262306a36Sopenharmony_ci int is_dx_block = 0; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (block >= inode->i_size >> inode->i_blkbits) { 13562306a36Sopenharmony_ci ext4_error_inode(inode, func, line, block, 13662306a36Sopenharmony_ci "Attempting to read directory block (%u) that is past i_size (%llu)", 13762306a36Sopenharmony_ci block, inode->i_size); 13862306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_EIO)) 14262306a36Sopenharmony_ci bh = ERR_PTR(-EIO); 14362306a36Sopenharmony_ci else 14462306a36Sopenharmony_ci bh = ext4_bread(NULL, inode, block, 0); 14562306a36Sopenharmony_ci if (IS_ERR(bh)) { 14662306a36Sopenharmony_ci __ext4_warning(inode->i_sb, func, line, 14762306a36Sopenharmony_ci "inode #%lu: lblock %lu: comm %s: " 14862306a36Sopenharmony_ci "error %ld reading directory block", 14962306a36Sopenharmony_ci inode->i_ino, (unsigned long)block, 15062306a36Sopenharmony_ci current->comm, PTR_ERR(bh)); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return bh; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci if (!bh && (type == INDEX || type == DIRENT_HTREE)) { 15562306a36Sopenharmony_ci ext4_error_inode(inode, func, line, block, 15662306a36Sopenharmony_ci "Directory hole found for htree %s block", 15762306a36Sopenharmony_ci (type == INDEX) ? "index" : "leaf"); 15862306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci if (!bh) 16162306a36Sopenharmony_ci return NULL; 16262306a36Sopenharmony_ci dirent = (struct ext4_dir_entry *) bh->b_data; 16362306a36Sopenharmony_ci /* Determine whether or not we have an index block */ 16462306a36Sopenharmony_ci if (is_dx(inode)) { 16562306a36Sopenharmony_ci if (block == 0) 16662306a36Sopenharmony_ci is_dx_block = 1; 16762306a36Sopenharmony_ci else if (ext4_rec_len_from_disk(dirent->rec_len, 16862306a36Sopenharmony_ci inode->i_sb->s_blocksize) == 16962306a36Sopenharmony_ci inode->i_sb->s_blocksize) 17062306a36Sopenharmony_ci is_dx_block = 1; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci if (!is_dx_block && type == INDEX) { 17362306a36Sopenharmony_ci ext4_error_inode(inode, func, line, block, 17462306a36Sopenharmony_ci "directory leaf block found instead of index block"); 17562306a36Sopenharmony_ci brelse(bh); 17662306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci if (!ext4_has_metadata_csum(inode->i_sb) || 17962306a36Sopenharmony_ci buffer_verified(bh)) 18062306a36Sopenharmony_ci return bh; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * An empty leaf block can get mistaken for a index block; for 18462306a36Sopenharmony_ci * this reason, we can only check the index checksum when the 18562306a36Sopenharmony_ci * caller is sure it should be an index block. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci if (is_dx_block && type == INDEX) { 18862306a36Sopenharmony_ci if (ext4_dx_csum_verify(inode, dirent) && 18962306a36Sopenharmony_ci !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) 19062306a36Sopenharmony_ci set_buffer_verified(bh); 19162306a36Sopenharmony_ci else { 19262306a36Sopenharmony_ci ext4_error_inode_err(inode, func, line, block, 19362306a36Sopenharmony_ci EFSBADCRC, 19462306a36Sopenharmony_ci "Directory index failed checksum"); 19562306a36Sopenharmony_ci brelse(bh); 19662306a36Sopenharmony_ci return ERR_PTR(-EFSBADCRC); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci if (!is_dx_block) { 20062306a36Sopenharmony_ci if (ext4_dirblock_csum_verify(inode, bh) && 20162306a36Sopenharmony_ci !ext4_simulate_fail(inode->i_sb, EXT4_SIM_DIRBLOCK_CRC)) 20262306a36Sopenharmony_ci set_buffer_verified(bh); 20362306a36Sopenharmony_ci else { 20462306a36Sopenharmony_ci ext4_error_inode_err(inode, func, line, block, 20562306a36Sopenharmony_ci EFSBADCRC, 20662306a36Sopenharmony_ci "Directory block failed checksum"); 20762306a36Sopenharmony_ci brelse(bh); 20862306a36Sopenharmony_ci return ERR_PTR(-EFSBADCRC); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci return bh; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci#ifdef DX_DEBUG 21562306a36Sopenharmony_ci#define dxtrace(command) command 21662306a36Sopenharmony_ci#else 21762306a36Sopenharmony_ci#define dxtrace(command) 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistruct fake_dirent 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci __le32 inode; 22362306a36Sopenharmony_ci __le16 rec_len; 22462306a36Sopenharmony_ci u8 name_len; 22562306a36Sopenharmony_ci u8 file_type; 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistruct dx_countlimit 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci __le16 limit; 23162306a36Sopenharmony_ci __le16 count; 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistruct dx_entry 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci __le32 hash; 23762306a36Sopenharmony_ci __le32 block; 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * dx_root_info is laid out so that if it should somehow get overlaid by a 24262306a36Sopenharmony_ci * dirent the two low bits of the hash version will be zero. Therefore, the 24362306a36Sopenharmony_ci * hash version mod 4 should never be 0. Sincerely, the paranoia department. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistruct dx_root 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct fake_dirent dot; 24962306a36Sopenharmony_ci char dot_name[4]; 25062306a36Sopenharmony_ci struct fake_dirent dotdot; 25162306a36Sopenharmony_ci char dotdot_name[4]; 25262306a36Sopenharmony_ci struct dx_root_info 25362306a36Sopenharmony_ci { 25462306a36Sopenharmony_ci __le32 reserved_zero; 25562306a36Sopenharmony_ci u8 hash_version; 25662306a36Sopenharmony_ci u8 info_length; /* 8 */ 25762306a36Sopenharmony_ci u8 indirect_levels; 25862306a36Sopenharmony_ci u8 unused_flags; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci info; 26162306a36Sopenharmony_ci struct dx_entry entries[]; 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistruct dx_node 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct fake_dirent fake; 26762306a36Sopenharmony_ci struct dx_entry entries[]; 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistruct dx_frame 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct buffer_head *bh; 27462306a36Sopenharmony_ci struct dx_entry *entries; 27562306a36Sopenharmony_ci struct dx_entry *at; 27662306a36Sopenharmony_ci}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistruct dx_map_entry 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci u32 hash; 28162306a36Sopenharmony_ci u16 offs; 28262306a36Sopenharmony_ci u16 size; 28362306a36Sopenharmony_ci}; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci/* 28662306a36Sopenharmony_ci * This goes at the end of each htree block. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_cistruct dx_tail { 28962306a36Sopenharmony_ci u32 dt_reserved; 29062306a36Sopenharmony_ci __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */ 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic inline ext4_lblk_t dx_get_block(struct dx_entry *entry); 29462306a36Sopenharmony_cistatic void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); 29562306a36Sopenharmony_cistatic inline unsigned dx_get_hash(struct dx_entry *entry); 29662306a36Sopenharmony_cistatic void dx_set_hash(struct dx_entry *entry, unsigned value); 29762306a36Sopenharmony_cistatic unsigned dx_get_count(struct dx_entry *entries); 29862306a36Sopenharmony_cistatic unsigned dx_get_limit(struct dx_entry *entries); 29962306a36Sopenharmony_cistatic void dx_set_count(struct dx_entry *entries, unsigned value); 30062306a36Sopenharmony_cistatic void dx_set_limit(struct dx_entry *entries, unsigned value); 30162306a36Sopenharmony_cistatic unsigned dx_root_limit(struct inode *dir, unsigned infosize); 30262306a36Sopenharmony_cistatic unsigned dx_node_limit(struct inode *dir); 30362306a36Sopenharmony_cistatic struct dx_frame *dx_probe(struct ext4_filename *fname, 30462306a36Sopenharmony_ci struct inode *dir, 30562306a36Sopenharmony_ci struct dx_hash_info *hinfo, 30662306a36Sopenharmony_ci struct dx_frame *frame); 30762306a36Sopenharmony_cistatic void dx_release(struct dx_frame *frames); 30862306a36Sopenharmony_cistatic int dx_make_map(struct inode *dir, struct buffer_head *bh, 30962306a36Sopenharmony_ci struct dx_hash_info *hinfo, 31062306a36Sopenharmony_ci struct dx_map_entry *map_tail); 31162306a36Sopenharmony_cistatic void dx_sort_map(struct dx_map_entry *map, unsigned count); 31262306a36Sopenharmony_cistatic struct ext4_dir_entry_2 *dx_move_dirents(struct inode *dir, char *from, 31362306a36Sopenharmony_ci char *to, struct dx_map_entry *offsets, 31462306a36Sopenharmony_ci int count, unsigned int blocksize); 31562306a36Sopenharmony_cistatic struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base, 31662306a36Sopenharmony_ci unsigned int blocksize); 31762306a36Sopenharmony_cistatic void dx_insert_block(struct dx_frame *frame, 31862306a36Sopenharmony_ci u32 hash, ext4_lblk_t block); 31962306a36Sopenharmony_cistatic int ext4_htree_next_block(struct inode *dir, __u32 hash, 32062306a36Sopenharmony_ci struct dx_frame *frame, 32162306a36Sopenharmony_ci struct dx_frame *frames, 32262306a36Sopenharmony_ci __u32 *start_hash); 32362306a36Sopenharmony_cistatic struct buffer_head * ext4_dx_find_entry(struct inode *dir, 32462306a36Sopenharmony_ci struct ext4_filename *fname, 32562306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir); 32662306a36Sopenharmony_cistatic int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, 32762306a36Sopenharmony_ci struct inode *dir, struct inode *inode); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* checksumming functions */ 33062306a36Sopenharmony_civoid ext4_initialize_dirent_tail(struct buffer_head *bh, 33162306a36Sopenharmony_ci unsigned int blocksize) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct ext4_dir_entry_tail *t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci memset(t, 0, sizeof(struct ext4_dir_entry_tail)); 33662306a36Sopenharmony_ci t->det_rec_len = ext4_rec_len_to_disk( 33762306a36Sopenharmony_ci sizeof(struct ext4_dir_entry_tail), blocksize); 33862306a36Sopenharmony_ci t->det_reserved_ft = EXT4_FT_DIR_CSUM; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* Walk through a dirent block to find a checksum "dirent" at the tail */ 34262306a36Sopenharmony_cistatic struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode, 34362306a36Sopenharmony_ci struct buffer_head *bh) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct ext4_dir_entry_tail *t; 34662306a36Sopenharmony_ci int blocksize = EXT4_BLOCK_SIZE(inode->i_sb); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci#ifdef PARANOID 34962306a36Sopenharmony_ci struct ext4_dir_entry *d, *top; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci d = (struct ext4_dir_entry *)bh->b_data; 35262306a36Sopenharmony_ci top = (struct ext4_dir_entry *)(bh->b_data + 35362306a36Sopenharmony_ci (blocksize - sizeof(struct ext4_dir_entry_tail))); 35462306a36Sopenharmony_ci while (d < top && ext4_rec_len_from_disk(d->rec_len, blocksize)) 35562306a36Sopenharmony_ci d = (struct ext4_dir_entry *)(((void *)d) + 35662306a36Sopenharmony_ci ext4_rec_len_from_disk(d->rec_len, blocksize)); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (d != top) 35962306a36Sopenharmony_ci return NULL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci t = (struct ext4_dir_entry_tail *)d; 36262306a36Sopenharmony_ci#else 36362306a36Sopenharmony_ci t = EXT4_DIRENT_TAIL(bh->b_data, EXT4_BLOCK_SIZE(inode->i_sb)); 36462306a36Sopenharmony_ci#endif 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (t->det_reserved_zero1 || 36762306a36Sopenharmony_ci (ext4_rec_len_from_disk(t->det_rec_len, blocksize) != 36862306a36Sopenharmony_ci sizeof(struct ext4_dir_entry_tail)) || 36962306a36Sopenharmony_ci t->det_reserved_zero2 || 37062306a36Sopenharmony_ci t->det_reserved_ft != EXT4_FT_DIR_CSUM) 37162306a36Sopenharmony_ci return NULL; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci return t; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic __le32 ext4_dirblock_csum(struct inode *inode, void *dirent, int size) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 37962306a36Sopenharmony_ci struct ext4_inode_info *ei = EXT4_I(inode); 38062306a36Sopenharmony_ci __u32 csum; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); 38362306a36Sopenharmony_ci return cpu_to_le32(csum); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci#define warn_no_space_for_csum(inode) \ 38762306a36Sopenharmony_ci __warn_no_space_for_csum((inode), __func__, __LINE__) 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic void __warn_no_space_for_csum(struct inode *inode, const char *func, 39062306a36Sopenharmony_ci unsigned int line) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci __ext4_warning_inode(inode, func, line, 39362306a36Sopenharmony_ci "No space for directory leaf checksum. Please run e2fsck -D."); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciint ext4_dirblock_csum_verify(struct inode *inode, struct buffer_head *bh) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct ext4_dir_entry_tail *t; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!ext4_has_metadata_csum(inode->i_sb)) 40162306a36Sopenharmony_ci return 1; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci t = get_dirent_tail(inode, bh); 40462306a36Sopenharmony_ci if (!t) { 40562306a36Sopenharmony_ci warn_no_space_for_csum(inode); 40662306a36Sopenharmony_ci return 0; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (t->det_checksum != ext4_dirblock_csum(inode, bh->b_data, 41062306a36Sopenharmony_ci (char *)t - bh->b_data)) 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 1; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void ext4_dirblock_csum_set(struct inode *inode, 41762306a36Sopenharmony_ci struct buffer_head *bh) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct ext4_dir_entry_tail *t; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!ext4_has_metadata_csum(inode->i_sb)) 42262306a36Sopenharmony_ci return; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci t = get_dirent_tail(inode, bh); 42562306a36Sopenharmony_ci if (!t) { 42662306a36Sopenharmony_ci warn_no_space_for_csum(inode); 42762306a36Sopenharmony_ci return; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci t->det_checksum = ext4_dirblock_csum(inode, bh->b_data, 43162306a36Sopenharmony_ci (char *)t - bh->b_data); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ciint ext4_handle_dirty_dirblock(handle_t *handle, 43562306a36Sopenharmony_ci struct inode *inode, 43662306a36Sopenharmony_ci struct buffer_head *bh) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci ext4_dirblock_csum_set(inode, bh); 43962306a36Sopenharmony_ci return ext4_handle_dirty_metadata(handle, inode, bh); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic struct dx_countlimit *get_dx_countlimit(struct inode *inode, 44362306a36Sopenharmony_ci struct ext4_dir_entry *dirent, 44462306a36Sopenharmony_ci int *offset) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct ext4_dir_entry *dp; 44762306a36Sopenharmony_ci struct dx_root_info *root; 44862306a36Sopenharmony_ci int count_offset; 44962306a36Sopenharmony_ci int blocksize = EXT4_BLOCK_SIZE(inode->i_sb); 45062306a36Sopenharmony_ci unsigned int rlen = ext4_rec_len_from_disk(dirent->rec_len, blocksize); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (rlen == blocksize) 45362306a36Sopenharmony_ci count_offset = 8; 45462306a36Sopenharmony_ci else if (rlen == 12) { 45562306a36Sopenharmony_ci dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); 45662306a36Sopenharmony_ci if (ext4_rec_len_from_disk(dp->rec_len, blocksize) != blocksize - 12) 45762306a36Sopenharmony_ci return NULL; 45862306a36Sopenharmony_ci root = (struct dx_root_info *)(((void *)dp + 12)); 45962306a36Sopenharmony_ci if (root->reserved_zero || 46062306a36Sopenharmony_ci root->info_length != sizeof(struct dx_root_info)) 46162306a36Sopenharmony_ci return NULL; 46262306a36Sopenharmony_ci count_offset = 32; 46362306a36Sopenharmony_ci } else 46462306a36Sopenharmony_ci return NULL; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (offset) 46762306a36Sopenharmony_ci *offset = count_offset; 46862306a36Sopenharmony_ci return (struct dx_countlimit *)(((void *)dirent) + count_offset); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent, 47262306a36Sopenharmony_ci int count_offset, int count, struct dx_tail *t) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 47562306a36Sopenharmony_ci struct ext4_inode_info *ei = EXT4_I(inode); 47662306a36Sopenharmony_ci __u32 csum; 47762306a36Sopenharmony_ci int size; 47862306a36Sopenharmony_ci __u32 dummy_csum = 0; 47962306a36Sopenharmony_ci int offset = offsetof(struct dx_tail, dt_checksum); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci size = count_offset + (count * sizeof(struct dx_entry)); 48262306a36Sopenharmony_ci csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); 48362306a36Sopenharmony_ci csum = ext4_chksum(sbi, csum, (__u8 *)t, offset); 48462306a36Sopenharmony_ci csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum)); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return cpu_to_le32(csum); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int ext4_dx_csum_verify(struct inode *inode, 49062306a36Sopenharmony_ci struct ext4_dir_entry *dirent) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct dx_countlimit *c; 49362306a36Sopenharmony_ci struct dx_tail *t; 49462306a36Sopenharmony_ci int count_offset, limit, count; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (!ext4_has_metadata_csum(inode->i_sb)) 49762306a36Sopenharmony_ci return 1; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci c = get_dx_countlimit(inode, dirent, &count_offset); 50062306a36Sopenharmony_ci if (!c) { 50162306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci limit = le16_to_cpu(c->limit); 50562306a36Sopenharmony_ci count = le16_to_cpu(c->count); 50662306a36Sopenharmony_ci if (count_offset + (limit * sizeof(struct dx_entry)) > 50762306a36Sopenharmony_ci EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { 50862306a36Sopenharmony_ci warn_no_space_for_csum(inode); 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci t = (struct dx_tail *)(((struct dx_entry *)c) + limit); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (t->dt_checksum != ext4_dx_csum(inode, dirent, count_offset, 51462306a36Sopenharmony_ci count, t)) 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci return 1; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct dx_countlimit *c; 52262306a36Sopenharmony_ci struct dx_tail *t; 52362306a36Sopenharmony_ci int count_offset, limit, count; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!ext4_has_metadata_csum(inode->i_sb)) 52662306a36Sopenharmony_ci return; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci c = get_dx_countlimit(inode, dirent, &count_offset); 52962306a36Sopenharmony_ci if (!c) { 53062306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); 53162306a36Sopenharmony_ci return; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci limit = le16_to_cpu(c->limit); 53462306a36Sopenharmony_ci count = le16_to_cpu(c->count); 53562306a36Sopenharmony_ci if (count_offset + (limit * sizeof(struct dx_entry)) > 53662306a36Sopenharmony_ci EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { 53762306a36Sopenharmony_ci warn_no_space_for_csum(inode); 53862306a36Sopenharmony_ci return; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci t = (struct dx_tail *)(((struct dx_entry *)c) + limit); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic inline int ext4_handle_dirty_dx_node(handle_t *handle, 54662306a36Sopenharmony_ci struct inode *inode, 54762306a36Sopenharmony_ci struct buffer_head *bh) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci ext4_dx_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); 55062306a36Sopenharmony_ci return ext4_handle_dirty_metadata(handle, inode, bh); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* 55462306a36Sopenharmony_ci * p is at least 6 bytes before the end of page 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_cistatic inline struct ext4_dir_entry_2 * 55762306a36Sopenharmony_ciext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci return (struct ext4_dir_entry_2 *)((char *)p + 56062306a36Sopenharmony_ci ext4_rec_len_from_disk(p->rec_len, blocksize)); 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/* 56462306a36Sopenharmony_ci * Future: use high four bits of block for coalesce-on-delete flags 56562306a36Sopenharmony_ci * Mask them off for now. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cistatic inline ext4_lblk_t dx_get_block(struct dx_entry *entry) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci return le32_to_cpu(entry->block) & 0x0fffffff; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic inline void dx_set_block(struct dx_entry *entry, ext4_lblk_t value) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci entry->block = cpu_to_le32(value); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic inline unsigned dx_get_hash(struct dx_entry *entry) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci return le32_to_cpu(entry->hash); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic inline void dx_set_hash(struct dx_entry *entry, unsigned value) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci entry->hash = cpu_to_le32(value); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic inline unsigned dx_get_count(struct dx_entry *entries) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci return le16_to_cpu(((struct dx_countlimit *) entries)->count); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic inline unsigned dx_get_limit(struct dx_entry *entries) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci return le16_to_cpu(((struct dx_countlimit *) entries)->limit); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic inline void dx_set_count(struct dx_entry *entries, unsigned value) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic inline void dx_set_limit(struct dx_entry *entries, unsigned value) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci unsigned int entry_space = dir->i_sb->s_blocksize - 61162306a36Sopenharmony_ci ext4_dir_rec_len(1, NULL) - 61262306a36Sopenharmony_ci ext4_dir_rec_len(2, NULL) - infosize; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 61562306a36Sopenharmony_ci entry_space -= sizeof(struct dx_tail); 61662306a36Sopenharmony_ci return entry_space / sizeof(struct dx_entry); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic inline unsigned dx_node_limit(struct inode *dir) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci unsigned int entry_space = dir->i_sb->s_blocksize - 62262306a36Sopenharmony_ci ext4_dir_rec_len(0, dir); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 62562306a36Sopenharmony_ci entry_space -= sizeof(struct dx_tail); 62662306a36Sopenharmony_ci return entry_space / sizeof(struct dx_entry); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/* 63062306a36Sopenharmony_ci * Debug 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci#ifdef DX_DEBUG 63362306a36Sopenharmony_cistatic void dx_show_index(char * label, struct dx_entry *entries) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int i, n = dx_get_count (entries); 63662306a36Sopenharmony_ci printk(KERN_DEBUG "%s index", label); 63762306a36Sopenharmony_ci for (i = 0; i < n; i++) { 63862306a36Sopenharmony_ci printk(KERN_CONT " %x->%lu", 63962306a36Sopenharmony_ci i ? dx_get_hash(entries + i) : 0, 64062306a36Sopenharmony_ci (unsigned long)dx_get_block(entries + i)); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci printk(KERN_CONT "\n"); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistruct stats 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci unsigned names; 64862306a36Sopenharmony_ci unsigned space; 64962306a36Sopenharmony_ci unsigned bcount; 65062306a36Sopenharmony_ci}; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic struct stats dx_show_leaf(struct inode *dir, 65362306a36Sopenharmony_ci struct dx_hash_info *hinfo, 65462306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, 65562306a36Sopenharmony_ci int size, int show_names) 65662306a36Sopenharmony_ci{ 65762306a36Sopenharmony_ci unsigned names = 0, space = 0; 65862306a36Sopenharmony_ci char *base = (char *) de; 65962306a36Sopenharmony_ci struct dx_hash_info h = *hinfo; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci printk("names: "); 66262306a36Sopenharmony_ci while ((char *) de < base + size) 66362306a36Sopenharmony_ci { 66462306a36Sopenharmony_ci if (de->inode) 66562306a36Sopenharmony_ci { 66662306a36Sopenharmony_ci if (show_names) 66762306a36Sopenharmony_ci { 66862306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 66962306a36Sopenharmony_ci int len; 67062306a36Sopenharmony_ci char *name; 67162306a36Sopenharmony_ci struct fscrypt_str fname_crypto_str = 67262306a36Sopenharmony_ci FSTR_INIT(NULL, 0); 67362306a36Sopenharmony_ci int res = 0; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci name = de->name; 67662306a36Sopenharmony_ci len = de->name_len; 67762306a36Sopenharmony_ci if (!IS_ENCRYPTED(dir)) { 67862306a36Sopenharmony_ci /* Directory is not encrypted */ 67962306a36Sopenharmony_ci (void) ext4fs_dirhash(dir, de->name, 68062306a36Sopenharmony_ci de->name_len, &h); 68162306a36Sopenharmony_ci printk("%*.s:(U)%x.%u ", len, 68262306a36Sopenharmony_ci name, h.hash, 68362306a36Sopenharmony_ci (unsigned) ((char *) de 68462306a36Sopenharmony_ci - base)); 68562306a36Sopenharmony_ci } else { 68662306a36Sopenharmony_ci struct fscrypt_str de_name = 68762306a36Sopenharmony_ci FSTR_INIT(name, len); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Directory is encrypted */ 69062306a36Sopenharmony_ci res = fscrypt_fname_alloc_buffer( 69162306a36Sopenharmony_ci len, &fname_crypto_str); 69262306a36Sopenharmony_ci if (res) 69362306a36Sopenharmony_ci printk(KERN_WARNING "Error " 69462306a36Sopenharmony_ci "allocating crypto " 69562306a36Sopenharmony_ci "buffer--skipping " 69662306a36Sopenharmony_ci "crypto\n"); 69762306a36Sopenharmony_ci res = fscrypt_fname_disk_to_usr(dir, 69862306a36Sopenharmony_ci 0, 0, &de_name, 69962306a36Sopenharmony_ci &fname_crypto_str); 70062306a36Sopenharmony_ci if (res) { 70162306a36Sopenharmony_ci printk(KERN_WARNING "Error " 70262306a36Sopenharmony_ci "converting filename " 70362306a36Sopenharmony_ci "from disk to usr" 70462306a36Sopenharmony_ci "\n"); 70562306a36Sopenharmony_ci name = "??"; 70662306a36Sopenharmony_ci len = 2; 70762306a36Sopenharmony_ci } else { 70862306a36Sopenharmony_ci name = fname_crypto_str.name; 70962306a36Sopenharmony_ci len = fname_crypto_str.len; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci if (IS_CASEFOLDED(dir)) 71262306a36Sopenharmony_ci h.hash = EXT4_DIRENT_HASH(de); 71362306a36Sopenharmony_ci else 71462306a36Sopenharmony_ci (void) ext4fs_dirhash(dir, 71562306a36Sopenharmony_ci de->name, 71662306a36Sopenharmony_ci de->name_len, &h); 71762306a36Sopenharmony_ci printk("%*.s:(E)%x.%u ", len, name, 71862306a36Sopenharmony_ci h.hash, (unsigned) ((char *) de 71962306a36Sopenharmony_ci - base)); 72062306a36Sopenharmony_ci fscrypt_fname_free_buffer( 72162306a36Sopenharmony_ci &fname_crypto_str); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci#else 72462306a36Sopenharmony_ci int len = de->name_len; 72562306a36Sopenharmony_ci char *name = de->name; 72662306a36Sopenharmony_ci (void) ext4fs_dirhash(dir, de->name, 72762306a36Sopenharmony_ci de->name_len, &h); 72862306a36Sopenharmony_ci printk("%*.s:%x.%u ", len, name, h.hash, 72962306a36Sopenharmony_ci (unsigned) ((char *) de - base)); 73062306a36Sopenharmony_ci#endif 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci space += ext4_dir_rec_len(de->name_len, dir); 73362306a36Sopenharmony_ci names++; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci de = ext4_next_entry(de, size); 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci printk(KERN_CONT "(%i)\n", names); 73862306a36Sopenharmony_ci return (struct stats) { names, space, 1 }; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistruct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, 74262306a36Sopenharmony_ci struct dx_entry *entries, int levels) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci unsigned blocksize = dir->i_sb->s_blocksize; 74562306a36Sopenharmony_ci unsigned count = dx_get_count(entries), names = 0, space = 0, i; 74662306a36Sopenharmony_ci unsigned bcount = 0; 74762306a36Sopenharmony_ci struct buffer_head *bh; 74862306a36Sopenharmony_ci printk("%i indexed blocks...\n", count); 74962306a36Sopenharmony_ci for (i = 0; i < count; i++, entries++) 75062306a36Sopenharmony_ci { 75162306a36Sopenharmony_ci ext4_lblk_t block = dx_get_block(entries); 75262306a36Sopenharmony_ci ext4_lblk_t hash = i ? dx_get_hash(entries): 0; 75362306a36Sopenharmony_ci u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; 75462306a36Sopenharmony_ci struct stats stats; 75562306a36Sopenharmony_ci printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); 75662306a36Sopenharmony_ci bh = ext4_bread(NULL,dir, block, 0); 75762306a36Sopenharmony_ci if (!bh || IS_ERR(bh)) 75862306a36Sopenharmony_ci continue; 75962306a36Sopenharmony_ci stats = levels? 76062306a36Sopenharmony_ci dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): 76162306a36Sopenharmony_ci dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) 76262306a36Sopenharmony_ci bh->b_data, blocksize, 0); 76362306a36Sopenharmony_ci names += stats.names; 76462306a36Sopenharmony_ci space += stats.space; 76562306a36Sopenharmony_ci bcount += stats.bcount; 76662306a36Sopenharmony_ci brelse(bh); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci if (bcount) 76962306a36Sopenharmony_ci printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", 77062306a36Sopenharmony_ci levels ? "" : " ", names, space/bcount, 77162306a36Sopenharmony_ci (space/bcount)*100/blocksize); 77262306a36Sopenharmony_ci return (struct stats) { names, space, bcount}; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/* 77662306a36Sopenharmony_ci * Linear search cross check 77762306a36Sopenharmony_ci */ 77862306a36Sopenharmony_cistatic inline void htree_rep_invariant_check(struct dx_entry *at, 77962306a36Sopenharmony_ci struct dx_entry *target, 78062306a36Sopenharmony_ci u32 hash, unsigned int n) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci while (n--) { 78362306a36Sopenharmony_ci dxtrace(printk(KERN_CONT ",")); 78462306a36Sopenharmony_ci if (dx_get_hash(++at) > hash) { 78562306a36Sopenharmony_ci at--; 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci ASSERT(at == target - 1); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci#else /* DX_DEBUG */ 79262306a36Sopenharmony_cistatic inline void htree_rep_invariant_check(struct dx_entry *at, 79362306a36Sopenharmony_ci struct dx_entry *target, 79462306a36Sopenharmony_ci u32 hash, unsigned int n) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci#endif /* DX_DEBUG */ 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci/* 80062306a36Sopenharmony_ci * Probe for a directory leaf block to search. 80162306a36Sopenharmony_ci * 80262306a36Sopenharmony_ci * dx_probe can return ERR_BAD_DX_DIR, which means there was a format 80362306a36Sopenharmony_ci * error in the directory index, and the caller should fall back to 80462306a36Sopenharmony_ci * searching the directory normally. The callers of dx_probe **MUST** 80562306a36Sopenharmony_ci * check for this error code, and make sure it never gets reflected 80662306a36Sopenharmony_ci * back to userspace. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_cistatic struct dx_frame * 80962306a36Sopenharmony_cidx_probe(struct ext4_filename *fname, struct inode *dir, 81062306a36Sopenharmony_ci struct dx_hash_info *hinfo, struct dx_frame *frame_in) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci unsigned count, indirect, level, i; 81362306a36Sopenharmony_ci struct dx_entry *at, *entries, *p, *q, *m; 81462306a36Sopenharmony_ci struct dx_root *root; 81562306a36Sopenharmony_ci struct dx_frame *frame = frame_in; 81662306a36Sopenharmony_ci struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); 81762306a36Sopenharmony_ci u32 hash; 81862306a36Sopenharmony_ci ext4_lblk_t block; 81962306a36Sopenharmony_ci ext4_lblk_t blocks[EXT4_HTREE_LEVEL]; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci memset(frame_in, 0, EXT4_HTREE_LEVEL * sizeof(frame_in[0])); 82262306a36Sopenharmony_ci frame->bh = ext4_read_dirblock(dir, 0, INDEX); 82362306a36Sopenharmony_ci if (IS_ERR(frame->bh)) 82462306a36Sopenharmony_ci return (struct dx_frame *) frame->bh; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci root = (struct dx_root *) frame->bh->b_data; 82762306a36Sopenharmony_ci if (root->info.hash_version != DX_HASH_TEA && 82862306a36Sopenharmony_ci root->info.hash_version != DX_HASH_HALF_MD4 && 82962306a36Sopenharmony_ci root->info.hash_version != DX_HASH_LEGACY && 83062306a36Sopenharmony_ci root->info.hash_version != DX_HASH_SIPHASH) { 83162306a36Sopenharmony_ci ext4_warning_inode(dir, "Unrecognised inode hash code %u", 83262306a36Sopenharmony_ci root->info.hash_version); 83362306a36Sopenharmony_ci goto fail; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) { 83662306a36Sopenharmony_ci if (root->info.hash_version != DX_HASH_SIPHASH) { 83762306a36Sopenharmony_ci ext4_warning_inode(dir, 83862306a36Sopenharmony_ci "Hash in dirent, but hash is not SIPHASH"); 83962306a36Sopenharmony_ci goto fail; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci } else { 84262306a36Sopenharmony_ci if (root->info.hash_version == DX_HASH_SIPHASH) { 84362306a36Sopenharmony_ci ext4_warning_inode(dir, 84462306a36Sopenharmony_ci "Hash code is SIPHASH, but hash not in dirent"); 84562306a36Sopenharmony_ci goto fail; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci if (fname) 84962306a36Sopenharmony_ci hinfo = &fname->hinfo; 85062306a36Sopenharmony_ci hinfo->hash_version = root->info.hash_version; 85162306a36Sopenharmony_ci if (hinfo->hash_version <= DX_HASH_TEA) 85262306a36Sopenharmony_ci hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; 85362306a36Sopenharmony_ci hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; 85462306a36Sopenharmony_ci /* hash is already computed for encrypted casefolded directory */ 85562306a36Sopenharmony_ci if (fname && fname_name(fname) && 85662306a36Sopenharmony_ci !(IS_ENCRYPTED(dir) && IS_CASEFOLDED(dir))) { 85762306a36Sopenharmony_ci int ret = ext4fs_dirhash(dir, fname_name(fname), 85862306a36Sopenharmony_ci fname_len(fname), hinfo); 85962306a36Sopenharmony_ci if (ret < 0) { 86062306a36Sopenharmony_ci ret_err = ERR_PTR(ret); 86162306a36Sopenharmony_ci goto fail; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci hash = hinfo->hash; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (root->info.unused_flags & 1) { 86762306a36Sopenharmony_ci ext4_warning_inode(dir, "Unimplemented hash flags: %#06x", 86862306a36Sopenharmony_ci root->info.unused_flags); 86962306a36Sopenharmony_ci goto fail; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci indirect = root->info.indirect_levels; 87362306a36Sopenharmony_ci if (indirect >= ext4_dir_htree_level(dir->i_sb)) { 87462306a36Sopenharmony_ci ext4_warning(dir->i_sb, 87562306a36Sopenharmony_ci "Directory (ino: %lu) htree depth %#06x exceed" 87662306a36Sopenharmony_ci "supported value", dir->i_ino, 87762306a36Sopenharmony_ci ext4_dir_htree_level(dir->i_sb)); 87862306a36Sopenharmony_ci if (ext4_dir_htree_level(dir->i_sb) < EXT4_HTREE_LEVEL) { 87962306a36Sopenharmony_ci ext4_warning(dir->i_sb, "Enable large directory " 88062306a36Sopenharmony_ci "feature to access it"); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci goto fail; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci entries = (struct dx_entry *)(((char *)&root->info) + 88662306a36Sopenharmony_ci root->info.info_length); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (dx_get_limit(entries) != dx_root_limit(dir, 88962306a36Sopenharmony_ci root->info.info_length)) { 89062306a36Sopenharmony_ci ext4_warning_inode(dir, "dx entry: limit %u != root limit %u", 89162306a36Sopenharmony_ci dx_get_limit(entries), 89262306a36Sopenharmony_ci dx_root_limit(dir, root->info.info_length)); 89362306a36Sopenharmony_ci goto fail; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci dxtrace(printk("Look up %x", hash)); 89762306a36Sopenharmony_ci level = 0; 89862306a36Sopenharmony_ci blocks[0] = 0; 89962306a36Sopenharmony_ci while (1) { 90062306a36Sopenharmony_ci count = dx_get_count(entries); 90162306a36Sopenharmony_ci if (!count || count > dx_get_limit(entries)) { 90262306a36Sopenharmony_ci ext4_warning_inode(dir, 90362306a36Sopenharmony_ci "dx entry: count %u beyond limit %u", 90462306a36Sopenharmony_ci count, dx_get_limit(entries)); 90562306a36Sopenharmony_ci goto fail; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci p = entries + 1; 90962306a36Sopenharmony_ci q = entries + count - 1; 91062306a36Sopenharmony_ci while (p <= q) { 91162306a36Sopenharmony_ci m = p + (q - p) / 2; 91262306a36Sopenharmony_ci dxtrace(printk(KERN_CONT ".")); 91362306a36Sopenharmony_ci if (dx_get_hash(m) > hash) 91462306a36Sopenharmony_ci q = m - 1; 91562306a36Sopenharmony_ci else 91662306a36Sopenharmony_ci p = m + 1; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci htree_rep_invariant_check(entries, p, hash, count - 1); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci at = p - 1; 92262306a36Sopenharmony_ci dxtrace(printk(KERN_CONT " %x->%u\n", 92362306a36Sopenharmony_ci at == entries ? 0 : dx_get_hash(at), 92462306a36Sopenharmony_ci dx_get_block(at))); 92562306a36Sopenharmony_ci frame->entries = entries; 92662306a36Sopenharmony_ci frame->at = at; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci block = dx_get_block(at); 92962306a36Sopenharmony_ci for (i = 0; i <= level; i++) { 93062306a36Sopenharmony_ci if (blocks[i] == block) { 93162306a36Sopenharmony_ci ext4_warning_inode(dir, 93262306a36Sopenharmony_ci "dx entry: tree cycle block %u points back to block %u", 93362306a36Sopenharmony_ci blocks[level], block); 93462306a36Sopenharmony_ci goto fail; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci if (++level > indirect) 93862306a36Sopenharmony_ci return frame; 93962306a36Sopenharmony_ci blocks[level] = block; 94062306a36Sopenharmony_ci frame++; 94162306a36Sopenharmony_ci frame->bh = ext4_read_dirblock(dir, block, INDEX); 94262306a36Sopenharmony_ci if (IS_ERR(frame->bh)) { 94362306a36Sopenharmony_ci ret_err = (struct dx_frame *) frame->bh; 94462306a36Sopenharmony_ci frame->bh = NULL; 94562306a36Sopenharmony_ci goto fail; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci entries = ((struct dx_node *) frame->bh->b_data)->entries; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (dx_get_limit(entries) != dx_node_limit(dir)) { 95162306a36Sopenharmony_ci ext4_warning_inode(dir, 95262306a36Sopenharmony_ci "dx entry: limit %u != node limit %u", 95362306a36Sopenharmony_ci dx_get_limit(entries), dx_node_limit(dir)); 95462306a36Sopenharmony_ci goto fail; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_cifail: 95862306a36Sopenharmony_ci while (frame >= frame_in) { 95962306a36Sopenharmony_ci brelse(frame->bh); 96062306a36Sopenharmony_ci frame--; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (ret_err == ERR_PTR(ERR_BAD_DX_DIR)) 96462306a36Sopenharmony_ci ext4_warning_inode(dir, 96562306a36Sopenharmony_ci "Corrupt directory, running e2fsck is recommended"); 96662306a36Sopenharmony_ci return ret_err; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic void dx_release(struct dx_frame *frames) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci struct dx_root_info *info; 97262306a36Sopenharmony_ci int i; 97362306a36Sopenharmony_ci unsigned int indirect_levels; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (frames[0].bh == NULL) 97662306a36Sopenharmony_ci return; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci info = &((struct dx_root *)frames[0].bh->b_data)->info; 97962306a36Sopenharmony_ci /* save local copy, "info" may be freed after brelse() */ 98062306a36Sopenharmony_ci indirect_levels = info->indirect_levels; 98162306a36Sopenharmony_ci for (i = 0; i <= indirect_levels; i++) { 98262306a36Sopenharmony_ci if (frames[i].bh == NULL) 98362306a36Sopenharmony_ci break; 98462306a36Sopenharmony_ci brelse(frames[i].bh); 98562306a36Sopenharmony_ci frames[i].bh = NULL; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci/* 99062306a36Sopenharmony_ci * This function increments the frame pointer to search the next leaf 99162306a36Sopenharmony_ci * block, and reads in the necessary intervening nodes if the search 99262306a36Sopenharmony_ci * should be necessary. Whether or not the search is necessary is 99362306a36Sopenharmony_ci * controlled by the hash parameter. If the hash value is even, then 99462306a36Sopenharmony_ci * the search is only continued if the next block starts with that 99562306a36Sopenharmony_ci * hash value. This is used if we are searching for a specific file. 99662306a36Sopenharmony_ci * 99762306a36Sopenharmony_ci * If the hash value is HASH_NB_ALWAYS, then always go to the next block. 99862306a36Sopenharmony_ci * 99962306a36Sopenharmony_ci * This function returns 1 if the caller should continue to search, 100062306a36Sopenharmony_ci * or 0 if it should not. If there is an error reading one of the 100162306a36Sopenharmony_ci * index blocks, it will a negative error code. 100262306a36Sopenharmony_ci * 100362306a36Sopenharmony_ci * If start_hash is non-null, it will be filled in with the starting 100462306a36Sopenharmony_ci * hash of the next page. 100562306a36Sopenharmony_ci */ 100662306a36Sopenharmony_cistatic int ext4_htree_next_block(struct inode *dir, __u32 hash, 100762306a36Sopenharmony_ci struct dx_frame *frame, 100862306a36Sopenharmony_ci struct dx_frame *frames, 100962306a36Sopenharmony_ci __u32 *start_hash) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct dx_frame *p; 101262306a36Sopenharmony_ci struct buffer_head *bh; 101362306a36Sopenharmony_ci int num_frames = 0; 101462306a36Sopenharmony_ci __u32 bhash; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci p = frame; 101762306a36Sopenharmony_ci /* 101862306a36Sopenharmony_ci * Find the next leaf page by incrementing the frame pointer. 101962306a36Sopenharmony_ci * If we run out of entries in the interior node, loop around and 102062306a36Sopenharmony_ci * increment pointer in the parent node. When we break out of 102162306a36Sopenharmony_ci * this loop, num_frames indicates the number of interior 102262306a36Sopenharmony_ci * nodes need to be read. 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci while (1) { 102562306a36Sopenharmony_ci if (++(p->at) < p->entries + dx_get_count(p->entries)) 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci if (p == frames) 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci num_frames++; 103062306a36Sopenharmony_ci p--; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * If the hash is 1, then continue only if the next page has a 103562306a36Sopenharmony_ci * continuation hash of any value. This is used for readdir 103662306a36Sopenharmony_ci * handling. Otherwise, check to see if the hash matches the 103762306a36Sopenharmony_ci * desired continuation hash. If it doesn't, return since 103862306a36Sopenharmony_ci * there's no point to read in the successive index pages. 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ci bhash = dx_get_hash(p->at); 104162306a36Sopenharmony_ci if (start_hash) 104262306a36Sopenharmony_ci *start_hash = bhash; 104362306a36Sopenharmony_ci if ((hash & 1) == 0) { 104462306a36Sopenharmony_ci if ((bhash & ~1) != hash) 104562306a36Sopenharmony_ci return 0; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci /* 104862306a36Sopenharmony_ci * If the hash is HASH_NB_ALWAYS, we always go to the next 104962306a36Sopenharmony_ci * block so no check is necessary 105062306a36Sopenharmony_ci */ 105162306a36Sopenharmony_ci while (num_frames--) { 105262306a36Sopenharmony_ci bh = ext4_read_dirblock(dir, dx_get_block(p->at), INDEX); 105362306a36Sopenharmony_ci if (IS_ERR(bh)) 105462306a36Sopenharmony_ci return PTR_ERR(bh); 105562306a36Sopenharmony_ci p++; 105662306a36Sopenharmony_ci brelse(p->bh); 105762306a36Sopenharmony_ci p->bh = bh; 105862306a36Sopenharmony_ci p->at = p->entries = ((struct dx_node *) bh->b_data)->entries; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci return 1; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci/* 106562306a36Sopenharmony_ci * This function fills a red-black tree with information from a 106662306a36Sopenharmony_ci * directory block. It returns the number directory entries loaded 106762306a36Sopenharmony_ci * into the tree. If there is an error it is returned in err. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_cistatic int htree_dirblock_to_tree(struct file *dir_file, 107062306a36Sopenharmony_ci struct inode *dir, ext4_lblk_t block, 107162306a36Sopenharmony_ci struct dx_hash_info *hinfo, 107262306a36Sopenharmony_ci __u32 start_hash, __u32 start_minor_hash) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct buffer_head *bh; 107562306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, *top; 107662306a36Sopenharmony_ci int err = 0, count = 0; 107762306a36Sopenharmony_ci struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str; 107862306a36Sopenharmony_ci int csum = ext4_has_metadata_csum(dir->i_sb); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", 108162306a36Sopenharmony_ci (unsigned long)block)); 108262306a36Sopenharmony_ci bh = ext4_read_dirblock(dir, block, DIRENT_HTREE); 108362306a36Sopenharmony_ci if (IS_ERR(bh)) 108462306a36Sopenharmony_ci return PTR_ERR(bh); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) bh->b_data; 108762306a36Sopenharmony_ci /* csum entries are not larger in the casefolded encrypted case */ 108862306a36Sopenharmony_ci top = (struct ext4_dir_entry_2 *) ((char *) de + 108962306a36Sopenharmony_ci dir->i_sb->s_blocksize - 109062306a36Sopenharmony_ci ext4_dir_rec_len(0, 109162306a36Sopenharmony_ci csum ? NULL : dir)); 109262306a36Sopenharmony_ci /* Check if the directory is encrypted */ 109362306a36Sopenharmony_ci if (IS_ENCRYPTED(dir)) { 109462306a36Sopenharmony_ci err = fscrypt_prepare_readdir(dir); 109562306a36Sopenharmony_ci if (err < 0) { 109662306a36Sopenharmony_ci brelse(bh); 109762306a36Sopenharmony_ci return err; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci err = fscrypt_fname_alloc_buffer(EXT4_NAME_LEN, 110062306a36Sopenharmony_ci &fname_crypto_str); 110162306a36Sopenharmony_ci if (err < 0) { 110262306a36Sopenharmony_ci brelse(bh); 110362306a36Sopenharmony_ci return err; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { 110862306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh, 110962306a36Sopenharmony_ci bh->b_data, bh->b_size, 111062306a36Sopenharmony_ci (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb)) 111162306a36Sopenharmony_ci + ((char *)de - bh->b_data))) { 111262306a36Sopenharmony_ci /* silently ignore the rest of the block */ 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) { 111662306a36Sopenharmony_ci if (de->name_len && de->inode) { 111762306a36Sopenharmony_ci hinfo->hash = EXT4_DIRENT_HASH(de); 111862306a36Sopenharmony_ci hinfo->minor_hash = EXT4_DIRENT_MINOR_HASH(de); 111962306a36Sopenharmony_ci } else { 112062306a36Sopenharmony_ci hinfo->hash = 0; 112162306a36Sopenharmony_ci hinfo->minor_hash = 0; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci } else { 112462306a36Sopenharmony_ci err = ext4fs_dirhash(dir, de->name, 112562306a36Sopenharmony_ci de->name_len, hinfo); 112662306a36Sopenharmony_ci if (err < 0) { 112762306a36Sopenharmony_ci count = err; 112862306a36Sopenharmony_ci goto errout; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci if ((hinfo->hash < start_hash) || 113262306a36Sopenharmony_ci ((hinfo->hash == start_hash) && 113362306a36Sopenharmony_ci (hinfo->minor_hash < start_minor_hash))) 113462306a36Sopenharmony_ci continue; 113562306a36Sopenharmony_ci if (de->inode == 0) 113662306a36Sopenharmony_ci continue; 113762306a36Sopenharmony_ci if (!IS_ENCRYPTED(dir)) { 113862306a36Sopenharmony_ci tmp_str.name = de->name; 113962306a36Sopenharmony_ci tmp_str.len = de->name_len; 114062306a36Sopenharmony_ci err = ext4_htree_store_dirent(dir_file, 114162306a36Sopenharmony_ci hinfo->hash, hinfo->minor_hash, de, 114262306a36Sopenharmony_ci &tmp_str); 114362306a36Sopenharmony_ci } else { 114462306a36Sopenharmony_ci int save_len = fname_crypto_str.len; 114562306a36Sopenharmony_ci struct fscrypt_str de_name = FSTR_INIT(de->name, 114662306a36Sopenharmony_ci de->name_len); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci /* Directory is encrypted */ 114962306a36Sopenharmony_ci err = fscrypt_fname_disk_to_usr(dir, hinfo->hash, 115062306a36Sopenharmony_ci hinfo->minor_hash, &de_name, 115162306a36Sopenharmony_ci &fname_crypto_str); 115262306a36Sopenharmony_ci if (err) { 115362306a36Sopenharmony_ci count = err; 115462306a36Sopenharmony_ci goto errout; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci err = ext4_htree_store_dirent(dir_file, 115762306a36Sopenharmony_ci hinfo->hash, hinfo->minor_hash, de, 115862306a36Sopenharmony_ci &fname_crypto_str); 115962306a36Sopenharmony_ci fname_crypto_str.len = save_len; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci if (err != 0) { 116262306a36Sopenharmony_ci count = err; 116362306a36Sopenharmony_ci goto errout; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci count++; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_cierrout: 116862306a36Sopenharmony_ci brelse(bh); 116962306a36Sopenharmony_ci fscrypt_fname_free_buffer(&fname_crypto_str); 117062306a36Sopenharmony_ci return count; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci/* 117562306a36Sopenharmony_ci * This function fills a red-black tree with information from a 117662306a36Sopenharmony_ci * directory. We start scanning the directory in hash order, starting 117762306a36Sopenharmony_ci * at start_hash and start_minor_hash. 117862306a36Sopenharmony_ci * 117962306a36Sopenharmony_ci * This function returns the number of entries inserted into the tree, 118062306a36Sopenharmony_ci * or a negative error code. 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ciint ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, 118362306a36Sopenharmony_ci __u32 start_minor_hash, __u32 *next_hash) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci struct dx_hash_info hinfo; 118662306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 118762306a36Sopenharmony_ci struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; 118862306a36Sopenharmony_ci struct inode *dir; 118962306a36Sopenharmony_ci ext4_lblk_t block; 119062306a36Sopenharmony_ci int count = 0; 119162306a36Sopenharmony_ci int ret, err; 119262306a36Sopenharmony_ci __u32 hashval; 119362306a36Sopenharmony_ci struct fscrypt_str tmp_str; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", 119662306a36Sopenharmony_ci start_hash, start_minor_hash)); 119762306a36Sopenharmony_ci dir = file_inode(dir_file); 119862306a36Sopenharmony_ci if (!(ext4_test_inode_flag(dir, EXT4_INODE_INDEX))) { 119962306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) 120062306a36Sopenharmony_ci hinfo.hash_version = DX_HASH_SIPHASH; 120162306a36Sopenharmony_ci else 120262306a36Sopenharmony_ci hinfo.hash_version = 120362306a36Sopenharmony_ci EXT4_SB(dir->i_sb)->s_def_hash_version; 120462306a36Sopenharmony_ci if (hinfo.hash_version <= DX_HASH_TEA) 120562306a36Sopenharmony_ci hinfo.hash_version += 120662306a36Sopenharmony_ci EXT4_SB(dir->i_sb)->s_hash_unsigned; 120762306a36Sopenharmony_ci hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; 120862306a36Sopenharmony_ci if (ext4_has_inline_data(dir)) { 120962306a36Sopenharmony_ci int has_inline_data = 1; 121062306a36Sopenharmony_ci count = ext4_inlinedir_to_tree(dir_file, dir, 0, 121162306a36Sopenharmony_ci &hinfo, start_hash, 121262306a36Sopenharmony_ci start_minor_hash, 121362306a36Sopenharmony_ci &has_inline_data); 121462306a36Sopenharmony_ci if (has_inline_data) { 121562306a36Sopenharmony_ci *next_hash = ~0; 121662306a36Sopenharmony_ci return count; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, 122062306a36Sopenharmony_ci start_hash, start_minor_hash); 122162306a36Sopenharmony_ci *next_hash = ~0; 122262306a36Sopenharmony_ci return count; 122362306a36Sopenharmony_ci } 122462306a36Sopenharmony_ci hinfo.hash = start_hash; 122562306a36Sopenharmony_ci hinfo.minor_hash = 0; 122662306a36Sopenharmony_ci frame = dx_probe(NULL, dir, &hinfo, frames); 122762306a36Sopenharmony_ci if (IS_ERR(frame)) 122862306a36Sopenharmony_ci return PTR_ERR(frame); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* Add '.' and '..' from the htree header */ 123162306a36Sopenharmony_ci if (!start_hash && !start_minor_hash) { 123262306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; 123362306a36Sopenharmony_ci tmp_str.name = de->name; 123462306a36Sopenharmony_ci tmp_str.len = de->name_len; 123562306a36Sopenharmony_ci err = ext4_htree_store_dirent(dir_file, 0, 0, 123662306a36Sopenharmony_ci de, &tmp_str); 123762306a36Sopenharmony_ci if (err != 0) 123862306a36Sopenharmony_ci goto errout; 123962306a36Sopenharmony_ci count++; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) { 124262306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; 124362306a36Sopenharmony_ci de = ext4_next_entry(de, dir->i_sb->s_blocksize); 124462306a36Sopenharmony_ci tmp_str.name = de->name; 124562306a36Sopenharmony_ci tmp_str.len = de->name_len; 124662306a36Sopenharmony_ci err = ext4_htree_store_dirent(dir_file, 2, 0, 124762306a36Sopenharmony_ci de, &tmp_str); 124862306a36Sopenharmony_ci if (err != 0) 124962306a36Sopenharmony_ci goto errout; 125062306a36Sopenharmony_ci count++; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci while (1) { 125462306a36Sopenharmony_ci if (fatal_signal_pending(current)) { 125562306a36Sopenharmony_ci err = -ERESTARTSYS; 125662306a36Sopenharmony_ci goto errout; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci cond_resched(); 125962306a36Sopenharmony_ci block = dx_get_block(frame->at); 126062306a36Sopenharmony_ci ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo, 126162306a36Sopenharmony_ci start_hash, start_minor_hash); 126262306a36Sopenharmony_ci if (ret < 0) { 126362306a36Sopenharmony_ci err = ret; 126462306a36Sopenharmony_ci goto errout; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci count += ret; 126762306a36Sopenharmony_ci hashval = ~0; 126862306a36Sopenharmony_ci ret = ext4_htree_next_block(dir, HASH_NB_ALWAYS, 126962306a36Sopenharmony_ci frame, frames, &hashval); 127062306a36Sopenharmony_ci *next_hash = hashval; 127162306a36Sopenharmony_ci if (ret < 0) { 127262306a36Sopenharmony_ci err = ret; 127362306a36Sopenharmony_ci goto errout; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci /* 127662306a36Sopenharmony_ci * Stop if: (a) there are no more entries, or 127762306a36Sopenharmony_ci * (b) we have inserted at least one entry and the 127862306a36Sopenharmony_ci * next hash value is not a continuation 127962306a36Sopenharmony_ci */ 128062306a36Sopenharmony_ci if ((ret == 0) || 128162306a36Sopenharmony_ci (count && ((hashval & 1) == 0))) 128262306a36Sopenharmony_ci break; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci dx_release(frames); 128562306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "Fill tree: returned %d entries, " 128662306a36Sopenharmony_ci "next hash: %x\n", count, *next_hash)); 128762306a36Sopenharmony_ci return count; 128862306a36Sopenharmony_cierrout: 128962306a36Sopenharmony_ci dx_release(frames); 129062306a36Sopenharmony_ci return (err); 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic inline int search_dirblock(struct buffer_head *bh, 129462306a36Sopenharmony_ci struct inode *dir, 129562306a36Sopenharmony_ci struct ext4_filename *fname, 129662306a36Sopenharmony_ci unsigned int offset, 129762306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci return ext4_search_dir(bh, bh->b_data, dir->i_sb->s_blocksize, dir, 130062306a36Sopenharmony_ci fname, offset, res_dir); 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci/* 130462306a36Sopenharmony_ci * Directory block splitting, compacting 130562306a36Sopenharmony_ci */ 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci/* 130862306a36Sopenharmony_ci * Create map of hash values, offsets, and sizes, stored at end of block. 130962306a36Sopenharmony_ci * Returns number of entries mapped. 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_cistatic int dx_make_map(struct inode *dir, struct buffer_head *bh, 131262306a36Sopenharmony_ci struct dx_hash_info *hinfo, 131362306a36Sopenharmony_ci struct dx_map_entry *map_tail) 131462306a36Sopenharmony_ci{ 131562306a36Sopenharmony_ci int count = 0; 131662306a36Sopenharmony_ci struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *)bh->b_data; 131762306a36Sopenharmony_ci unsigned int buflen = bh->b_size; 131862306a36Sopenharmony_ci char *base = bh->b_data; 131962306a36Sopenharmony_ci struct dx_hash_info h = *hinfo; 132062306a36Sopenharmony_ci int blocksize = EXT4_BLOCK_SIZE(dir->i_sb); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 132362306a36Sopenharmony_ci buflen -= sizeof(struct ext4_dir_entry_tail); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci while ((char *) de < base + buflen) { 132662306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh, base, buflen, 132762306a36Sopenharmony_ci ((char *)de) - base)) 132862306a36Sopenharmony_ci return -EFSCORRUPTED; 132962306a36Sopenharmony_ci if (de->name_len && de->inode) { 133062306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) 133162306a36Sopenharmony_ci h.hash = EXT4_DIRENT_HASH(de); 133262306a36Sopenharmony_ci else { 133362306a36Sopenharmony_ci int err = ext4fs_dirhash(dir, de->name, 133462306a36Sopenharmony_ci de->name_len, &h); 133562306a36Sopenharmony_ci if (err < 0) 133662306a36Sopenharmony_ci return err; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci map_tail--; 133962306a36Sopenharmony_ci map_tail->hash = h.hash; 134062306a36Sopenharmony_ci map_tail->offs = ((char *) de - base)>>2; 134162306a36Sopenharmony_ci map_tail->size = ext4_rec_len_from_disk(de->rec_len, 134262306a36Sopenharmony_ci blocksize); 134362306a36Sopenharmony_ci count++; 134462306a36Sopenharmony_ci cond_resched(); 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci de = ext4_next_entry(de, blocksize); 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci return count; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci/* Sort map by hash value */ 135262306a36Sopenharmony_cistatic void dx_sort_map (struct dx_map_entry *map, unsigned count) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct dx_map_entry *p, *q, *top = map + count - 1; 135562306a36Sopenharmony_ci int more; 135662306a36Sopenharmony_ci /* Combsort until bubble sort doesn't suck */ 135762306a36Sopenharmony_ci while (count > 2) { 135862306a36Sopenharmony_ci count = count*10/13; 135962306a36Sopenharmony_ci if (count - 9 < 2) /* 9, 10 -> 11 */ 136062306a36Sopenharmony_ci count = 11; 136162306a36Sopenharmony_ci for (p = top, q = p - count; q >= map; p--, q--) 136262306a36Sopenharmony_ci if (p->hash < q->hash) 136362306a36Sopenharmony_ci swap(*p, *q); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci /* Garden variety bubble sort */ 136662306a36Sopenharmony_ci do { 136762306a36Sopenharmony_ci more = 0; 136862306a36Sopenharmony_ci q = top; 136962306a36Sopenharmony_ci while (q-- > map) { 137062306a36Sopenharmony_ci if (q[1].hash >= q[0].hash) 137162306a36Sopenharmony_ci continue; 137262306a36Sopenharmony_ci swap(*(q+1), *q); 137362306a36Sopenharmony_ci more = 1; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci } while(more); 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci struct dx_entry *entries = frame->entries; 138162306a36Sopenharmony_ci struct dx_entry *old = frame->at, *new = old + 1; 138262306a36Sopenharmony_ci int count = dx_get_count(entries); 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci ASSERT(count < dx_get_limit(entries)); 138562306a36Sopenharmony_ci ASSERT(old < entries + count); 138662306a36Sopenharmony_ci memmove(new + 1, new, (char *)(entries + count) - (char *)(new)); 138762306a36Sopenharmony_ci dx_set_hash(new, hash); 138862306a36Sopenharmony_ci dx_set_block(new, block); 138962306a36Sopenharmony_ci dx_set_count(entries, count + 1); 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 139362306a36Sopenharmony_ci/* 139462306a36Sopenharmony_ci * Test whether a case-insensitive directory entry matches the filename 139562306a36Sopenharmony_ci * being searched for. If quick is set, assume the name being looked up 139662306a36Sopenharmony_ci * is already in the casefolded form. 139762306a36Sopenharmony_ci * 139862306a36Sopenharmony_ci * Returns: 0 if the directory entry matches, more than 0 if it 139962306a36Sopenharmony_ci * doesn't match or less than zero on error. 140062306a36Sopenharmony_ci */ 140162306a36Sopenharmony_cistatic int ext4_ci_compare(const struct inode *parent, const struct qstr *name, 140262306a36Sopenharmony_ci u8 *de_name, size_t de_name_len, bool quick) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci const struct super_block *sb = parent->i_sb; 140562306a36Sopenharmony_ci const struct unicode_map *um = sb->s_encoding; 140662306a36Sopenharmony_ci struct fscrypt_str decrypted_name = FSTR_INIT(NULL, de_name_len); 140762306a36Sopenharmony_ci struct qstr entry = QSTR_INIT(de_name, de_name_len); 140862306a36Sopenharmony_ci int ret; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (IS_ENCRYPTED(parent)) { 141162306a36Sopenharmony_ci const struct fscrypt_str encrypted_name = 141262306a36Sopenharmony_ci FSTR_INIT(de_name, de_name_len); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci decrypted_name.name = kmalloc(de_name_len, GFP_KERNEL); 141562306a36Sopenharmony_ci if (!decrypted_name.name) 141662306a36Sopenharmony_ci return -ENOMEM; 141762306a36Sopenharmony_ci ret = fscrypt_fname_disk_to_usr(parent, 0, 0, &encrypted_name, 141862306a36Sopenharmony_ci &decrypted_name); 141962306a36Sopenharmony_ci if (ret < 0) 142062306a36Sopenharmony_ci goto out; 142162306a36Sopenharmony_ci entry.name = decrypted_name.name; 142262306a36Sopenharmony_ci entry.len = decrypted_name.len; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (quick) 142662306a36Sopenharmony_ci ret = utf8_strncasecmp_folded(um, name, &entry); 142762306a36Sopenharmony_ci else 142862306a36Sopenharmony_ci ret = utf8_strncasecmp(um, name, &entry); 142962306a36Sopenharmony_ci if (ret < 0) { 143062306a36Sopenharmony_ci /* Handle invalid character sequence as either an error 143162306a36Sopenharmony_ci * or as an opaque byte sequence. 143262306a36Sopenharmony_ci */ 143362306a36Sopenharmony_ci if (sb_has_strict_encoding(sb)) 143462306a36Sopenharmony_ci ret = -EINVAL; 143562306a36Sopenharmony_ci else if (name->len != entry.len) 143662306a36Sopenharmony_ci ret = 1; 143762306a36Sopenharmony_ci else 143862306a36Sopenharmony_ci ret = !!memcmp(name->name, entry.name, entry.len); 143962306a36Sopenharmony_ci } 144062306a36Sopenharmony_ciout: 144162306a36Sopenharmony_ci kfree(decrypted_name.name); 144262306a36Sopenharmony_ci return ret; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ciint ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname, 144662306a36Sopenharmony_ci struct ext4_filename *name) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct fscrypt_str *cf_name = &name->cf_name; 144962306a36Sopenharmony_ci struct dx_hash_info *hinfo = &name->hinfo; 145062306a36Sopenharmony_ci int len; 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci if (!IS_CASEFOLDED(dir) || 145362306a36Sopenharmony_ci (IS_ENCRYPTED(dir) && !fscrypt_has_encryption_key(dir))) { 145462306a36Sopenharmony_ci cf_name->name = NULL; 145562306a36Sopenharmony_ci return 0; 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci cf_name->name = kmalloc(EXT4_NAME_LEN, GFP_NOFS); 145962306a36Sopenharmony_ci if (!cf_name->name) 146062306a36Sopenharmony_ci return -ENOMEM; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci len = utf8_casefold(dir->i_sb->s_encoding, 146362306a36Sopenharmony_ci iname, cf_name->name, 146462306a36Sopenharmony_ci EXT4_NAME_LEN); 146562306a36Sopenharmony_ci if (len <= 0) { 146662306a36Sopenharmony_ci kfree(cf_name->name); 146762306a36Sopenharmony_ci cf_name->name = NULL; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci cf_name->len = (unsigned) len; 147062306a36Sopenharmony_ci if (!IS_ENCRYPTED(dir)) 147162306a36Sopenharmony_ci return 0; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci hinfo->hash_version = DX_HASH_SIPHASH; 147462306a36Sopenharmony_ci hinfo->seed = NULL; 147562306a36Sopenharmony_ci if (cf_name->name) 147662306a36Sopenharmony_ci return ext4fs_dirhash(dir, cf_name->name, cf_name->len, hinfo); 147762306a36Sopenharmony_ci else 147862306a36Sopenharmony_ci return ext4fs_dirhash(dir, iname->name, iname->len, hinfo); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci#endif 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci/* 148362306a36Sopenharmony_ci * Test whether a directory entry matches the filename being searched for. 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * Return: %true if the directory entry matches, otherwise %false. 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_cistatic bool ext4_match(struct inode *parent, 148862306a36Sopenharmony_ci const struct ext4_filename *fname, 148962306a36Sopenharmony_ci struct ext4_dir_entry_2 *de) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct fscrypt_name f; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (!de->inode) 149462306a36Sopenharmony_ci return false; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci f.usr_fname = fname->usr_fname; 149762306a36Sopenharmony_ci f.disk_name = fname->disk_name; 149862306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 149962306a36Sopenharmony_ci f.crypto_buf = fname->crypto_buf; 150062306a36Sopenharmony_ci#endif 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 150362306a36Sopenharmony_ci if (IS_CASEFOLDED(parent) && 150462306a36Sopenharmony_ci (!IS_ENCRYPTED(parent) || fscrypt_has_encryption_key(parent))) { 150562306a36Sopenharmony_ci if (fname->cf_name.name) { 150662306a36Sopenharmony_ci struct qstr cf = {.name = fname->cf_name.name, 150762306a36Sopenharmony_ci .len = fname->cf_name.len}; 150862306a36Sopenharmony_ci if (IS_ENCRYPTED(parent)) { 150962306a36Sopenharmony_ci if (fname->hinfo.hash != EXT4_DIRENT_HASH(de) || 151062306a36Sopenharmony_ci fname->hinfo.minor_hash != 151162306a36Sopenharmony_ci EXT4_DIRENT_MINOR_HASH(de)) { 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci return false; 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci return !ext4_ci_compare(parent, &cf, de->name, 151762306a36Sopenharmony_ci de->name_len, true); 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci return !ext4_ci_compare(parent, fname->usr_fname, de->name, 152062306a36Sopenharmony_ci de->name_len, false); 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci#endif 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return fscrypt_match_name(&f, de->name, de->name_len); 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci/* 152862306a36Sopenharmony_ci * Returns 0 if not found, -1 on failure, and 1 on success 152962306a36Sopenharmony_ci */ 153062306a36Sopenharmony_ciint ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, 153162306a36Sopenharmony_ci struct inode *dir, struct ext4_filename *fname, 153262306a36Sopenharmony_ci unsigned int offset, struct ext4_dir_entry_2 **res_dir) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci struct ext4_dir_entry_2 * de; 153562306a36Sopenharmony_ci char * dlimit; 153662306a36Sopenharmony_ci int de_len; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *)search_buf; 153962306a36Sopenharmony_ci dlimit = search_buf + buf_size; 154062306a36Sopenharmony_ci while ((char *) de < dlimit - EXT4_BASE_DIR_LEN) { 154162306a36Sopenharmony_ci /* this code is executed quadratically often */ 154262306a36Sopenharmony_ci /* do minimal checking `by hand' */ 154362306a36Sopenharmony_ci if (de->name + de->name_len <= dlimit && 154462306a36Sopenharmony_ci ext4_match(dir, fname, de)) { 154562306a36Sopenharmony_ci /* found a match - just to be sure, do 154662306a36Sopenharmony_ci * a full check */ 154762306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf, 154862306a36Sopenharmony_ci buf_size, offset)) 154962306a36Sopenharmony_ci return -1; 155062306a36Sopenharmony_ci *res_dir = de; 155162306a36Sopenharmony_ci return 1; 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci /* prevent looping on a bad block */ 155462306a36Sopenharmony_ci de_len = ext4_rec_len_from_disk(de->rec_len, 155562306a36Sopenharmony_ci dir->i_sb->s_blocksize); 155662306a36Sopenharmony_ci if (de_len <= 0) 155762306a36Sopenharmony_ci return -1; 155862306a36Sopenharmony_ci offset += de_len; 155962306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci return 0; 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, 156562306a36Sopenharmony_ci struct ext4_dir_entry *de) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (!is_dx(dir)) 157062306a36Sopenharmony_ci return 0; 157162306a36Sopenharmony_ci if (block == 0) 157262306a36Sopenharmony_ci return 1; 157362306a36Sopenharmony_ci if (de->inode == 0 && 157462306a36Sopenharmony_ci ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) == 157562306a36Sopenharmony_ci sb->s_blocksize) 157662306a36Sopenharmony_ci return 1; 157762306a36Sopenharmony_ci return 0; 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci/* 158162306a36Sopenharmony_ci * __ext4_find_entry() 158262306a36Sopenharmony_ci * 158362306a36Sopenharmony_ci * finds an entry in the specified directory with the wanted name. It 158462306a36Sopenharmony_ci * returns the cache buffer in which the entry was found, and the entry 158562306a36Sopenharmony_ci * itself (as a parameter - res_dir). It does NOT read the inode of the 158662306a36Sopenharmony_ci * entry - you'll have to do that yourself if you want to. 158762306a36Sopenharmony_ci * 158862306a36Sopenharmony_ci * The returned buffer_head has ->b_count elevated. The caller is expected 158962306a36Sopenharmony_ci * to brelse() it when appropriate. 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_cistatic struct buffer_head *__ext4_find_entry(struct inode *dir, 159262306a36Sopenharmony_ci struct ext4_filename *fname, 159362306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir, 159462306a36Sopenharmony_ci int *inlined) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci struct super_block *sb; 159762306a36Sopenharmony_ci struct buffer_head *bh_use[NAMEI_RA_SIZE]; 159862306a36Sopenharmony_ci struct buffer_head *bh, *ret = NULL; 159962306a36Sopenharmony_ci ext4_lblk_t start, block; 160062306a36Sopenharmony_ci const u8 *name = fname->usr_fname->name; 160162306a36Sopenharmony_ci size_t ra_max = 0; /* Number of bh's in the readahead 160262306a36Sopenharmony_ci buffer, bh_use[] */ 160362306a36Sopenharmony_ci size_t ra_ptr = 0; /* Current index into readahead 160462306a36Sopenharmony_ci buffer */ 160562306a36Sopenharmony_ci ext4_lblk_t nblocks; 160662306a36Sopenharmony_ci int i, namelen, retval; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci *res_dir = NULL; 160962306a36Sopenharmony_ci sb = dir->i_sb; 161062306a36Sopenharmony_ci namelen = fname->usr_fname->len; 161162306a36Sopenharmony_ci if (namelen > EXT4_NAME_LEN) 161262306a36Sopenharmony_ci return NULL; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (ext4_has_inline_data(dir)) { 161562306a36Sopenharmony_ci int has_inline_data = 1; 161662306a36Sopenharmony_ci ret = ext4_find_inline_entry(dir, fname, res_dir, 161762306a36Sopenharmony_ci &has_inline_data); 161862306a36Sopenharmony_ci if (inlined) 161962306a36Sopenharmony_ci *inlined = has_inline_data; 162062306a36Sopenharmony_ci if (has_inline_data) 162162306a36Sopenharmony_ci goto cleanup_and_exit; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci if ((namelen <= 2) && (name[0] == '.') && 162562306a36Sopenharmony_ci (name[1] == '.' || name[1] == '\0')) { 162662306a36Sopenharmony_ci /* 162762306a36Sopenharmony_ci * "." or ".." will only be in the first block 162862306a36Sopenharmony_ci * NFS may look up ".."; "." should be handled by the VFS 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_ci block = start = 0; 163162306a36Sopenharmony_ci nblocks = 1; 163262306a36Sopenharmony_ci goto restart; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci if (is_dx(dir)) { 163562306a36Sopenharmony_ci ret = ext4_dx_find_entry(dir, fname, res_dir); 163662306a36Sopenharmony_ci /* 163762306a36Sopenharmony_ci * On success, or if the error was file not found, 163862306a36Sopenharmony_ci * return. Otherwise, fall back to doing a search the 163962306a36Sopenharmony_ci * old fashioned way. 164062306a36Sopenharmony_ci */ 164162306a36Sopenharmony_ci if (!IS_ERR(ret) || PTR_ERR(ret) != ERR_BAD_DX_DIR) 164262306a36Sopenharmony_ci goto cleanup_and_exit; 164362306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " 164462306a36Sopenharmony_ci "falling back\n")); 164562306a36Sopenharmony_ci ret = NULL; 164662306a36Sopenharmony_ci } 164762306a36Sopenharmony_ci nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); 164862306a36Sopenharmony_ci if (!nblocks) { 164962306a36Sopenharmony_ci ret = NULL; 165062306a36Sopenharmony_ci goto cleanup_and_exit; 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci start = EXT4_I(dir)->i_dir_start_lookup; 165362306a36Sopenharmony_ci if (start >= nblocks) 165462306a36Sopenharmony_ci start = 0; 165562306a36Sopenharmony_ci block = start; 165662306a36Sopenharmony_cirestart: 165762306a36Sopenharmony_ci do { 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * We deal with the read-ahead logic here. 166062306a36Sopenharmony_ci */ 166162306a36Sopenharmony_ci cond_resched(); 166262306a36Sopenharmony_ci if (ra_ptr >= ra_max) { 166362306a36Sopenharmony_ci /* Refill the readahead buffer */ 166462306a36Sopenharmony_ci ra_ptr = 0; 166562306a36Sopenharmony_ci if (block < start) 166662306a36Sopenharmony_ci ra_max = start - block; 166762306a36Sopenharmony_ci else 166862306a36Sopenharmony_ci ra_max = nblocks - block; 166962306a36Sopenharmony_ci ra_max = min(ra_max, ARRAY_SIZE(bh_use)); 167062306a36Sopenharmony_ci retval = ext4_bread_batch(dir, block, ra_max, 167162306a36Sopenharmony_ci false /* wait */, bh_use); 167262306a36Sopenharmony_ci if (retval) { 167362306a36Sopenharmony_ci ret = ERR_PTR(retval); 167462306a36Sopenharmony_ci ra_max = 0; 167562306a36Sopenharmony_ci goto cleanup_and_exit; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci if ((bh = bh_use[ra_ptr++]) == NULL) 167962306a36Sopenharmony_ci goto next; 168062306a36Sopenharmony_ci wait_on_buffer(bh); 168162306a36Sopenharmony_ci if (!buffer_uptodate(bh)) { 168262306a36Sopenharmony_ci EXT4_ERROR_INODE_ERR(dir, EIO, 168362306a36Sopenharmony_ci "reading directory lblock %lu", 168462306a36Sopenharmony_ci (unsigned long) block); 168562306a36Sopenharmony_ci brelse(bh); 168662306a36Sopenharmony_ci ret = ERR_PTR(-EIO); 168762306a36Sopenharmony_ci goto cleanup_and_exit; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci if (!buffer_verified(bh) && 169062306a36Sopenharmony_ci !is_dx_internal_node(dir, block, 169162306a36Sopenharmony_ci (struct ext4_dir_entry *)bh->b_data) && 169262306a36Sopenharmony_ci !ext4_dirblock_csum_verify(dir, bh)) { 169362306a36Sopenharmony_ci EXT4_ERROR_INODE_ERR(dir, EFSBADCRC, 169462306a36Sopenharmony_ci "checksumming directory " 169562306a36Sopenharmony_ci "block %lu", (unsigned long)block); 169662306a36Sopenharmony_ci brelse(bh); 169762306a36Sopenharmony_ci ret = ERR_PTR(-EFSBADCRC); 169862306a36Sopenharmony_ci goto cleanup_and_exit; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci set_buffer_verified(bh); 170162306a36Sopenharmony_ci i = search_dirblock(bh, dir, fname, 170262306a36Sopenharmony_ci block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); 170362306a36Sopenharmony_ci if (i == 1) { 170462306a36Sopenharmony_ci EXT4_I(dir)->i_dir_start_lookup = block; 170562306a36Sopenharmony_ci ret = bh; 170662306a36Sopenharmony_ci goto cleanup_and_exit; 170762306a36Sopenharmony_ci } else { 170862306a36Sopenharmony_ci brelse(bh); 170962306a36Sopenharmony_ci if (i < 0) 171062306a36Sopenharmony_ci goto cleanup_and_exit; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci next: 171362306a36Sopenharmony_ci if (++block >= nblocks) 171462306a36Sopenharmony_ci block = 0; 171562306a36Sopenharmony_ci } while (block != start); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci /* 171862306a36Sopenharmony_ci * If the directory has grown while we were searching, then 171962306a36Sopenharmony_ci * search the last part of the directory before giving up. 172062306a36Sopenharmony_ci */ 172162306a36Sopenharmony_ci block = nblocks; 172262306a36Sopenharmony_ci nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); 172362306a36Sopenharmony_ci if (block < nblocks) { 172462306a36Sopenharmony_ci start = 0; 172562306a36Sopenharmony_ci goto restart; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_cicleanup_and_exit: 172962306a36Sopenharmony_ci /* Clean up the read-ahead blocks */ 173062306a36Sopenharmony_ci for (; ra_ptr < ra_max; ra_ptr++) 173162306a36Sopenharmony_ci brelse(bh_use[ra_ptr]); 173262306a36Sopenharmony_ci return ret; 173362306a36Sopenharmony_ci} 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_cistatic struct buffer_head *ext4_find_entry(struct inode *dir, 173662306a36Sopenharmony_ci const struct qstr *d_name, 173762306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir, 173862306a36Sopenharmony_ci int *inlined) 173962306a36Sopenharmony_ci{ 174062306a36Sopenharmony_ci int err; 174162306a36Sopenharmony_ci struct ext4_filename fname; 174262306a36Sopenharmony_ci struct buffer_head *bh; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci err = ext4_fname_setup_filename(dir, d_name, 1, &fname); 174562306a36Sopenharmony_ci if (err == -ENOENT) 174662306a36Sopenharmony_ci return NULL; 174762306a36Sopenharmony_ci if (err) 174862306a36Sopenharmony_ci return ERR_PTR(err); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci bh = __ext4_find_entry(dir, &fname, res_dir, inlined); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci ext4_fname_free_filename(&fname); 175362306a36Sopenharmony_ci return bh; 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic struct buffer_head *ext4_lookup_entry(struct inode *dir, 175762306a36Sopenharmony_ci struct dentry *dentry, 175862306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci int err; 176162306a36Sopenharmony_ci struct ext4_filename fname; 176262306a36Sopenharmony_ci struct buffer_head *bh; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci err = ext4_fname_prepare_lookup(dir, dentry, &fname); 176562306a36Sopenharmony_ci generic_set_encrypted_ci_d_ops(dentry); 176662306a36Sopenharmony_ci if (err == -ENOENT) 176762306a36Sopenharmony_ci return NULL; 176862306a36Sopenharmony_ci if (err) 176962306a36Sopenharmony_ci return ERR_PTR(err); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci bh = __ext4_find_entry(dir, &fname, res_dir, NULL); 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci ext4_fname_free_filename(&fname); 177462306a36Sopenharmony_ci return bh; 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_cistatic struct buffer_head * ext4_dx_find_entry(struct inode *dir, 177862306a36Sopenharmony_ci struct ext4_filename *fname, 177962306a36Sopenharmony_ci struct ext4_dir_entry_2 **res_dir) 178062306a36Sopenharmony_ci{ 178162306a36Sopenharmony_ci struct super_block * sb = dir->i_sb; 178262306a36Sopenharmony_ci struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; 178362306a36Sopenharmony_ci struct buffer_head *bh; 178462306a36Sopenharmony_ci ext4_lblk_t block; 178562306a36Sopenharmony_ci int retval; 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION 178862306a36Sopenharmony_ci *res_dir = NULL; 178962306a36Sopenharmony_ci#endif 179062306a36Sopenharmony_ci frame = dx_probe(fname, dir, NULL, frames); 179162306a36Sopenharmony_ci if (IS_ERR(frame)) 179262306a36Sopenharmony_ci return (struct buffer_head *) frame; 179362306a36Sopenharmony_ci do { 179462306a36Sopenharmony_ci block = dx_get_block(frame->at); 179562306a36Sopenharmony_ci bh = ext4_read_dirblock(dir, block, DIRENT_HTREE); 179662306a36Sopenharmony_ci if (IS_ERR(bh)) 179762306a36Sopenharmony_ci goto errout; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci retval = search_dirblock(bh, dir, fname, 180062306a36Sopenharmony_ci block << EXT4_BLOCK_SIZE_BITS(sb), 180162306a36Sopenharmony_ci res_dir); 180262306a36Sopenharmony_ci if (retval == 1) 180362306a36Sopenharmony_ci goto success; 180462306a36Sopenharmony_ci brelse(bh); 180562306a36Sopenharmony_ci if (retval == -1) { 180662306a36Sopenharmony_ci bh = ERR_PTR(ERR_BAD_DX_DIR); 180762306a36Sopenharmony_ci goto errout; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci /* Check to see if we should continue to search */ 181162306a36Sopenharmony_ci retval = ext4_htree_next_block(dir, fname->hinfo.hash, frame, 181262306a36Sopenharmony_ci frames, NULL); 181362306a36Sopenharmony_ci if (retval < 0) { 181462306a36Sopenharmony_ci ext4_warning_inode(dir, 181562306a36Sopenharmony_ci "error %d reading directory index block", 181662306a36Sopenharmony_ci retval); 181762306a36Sopenharmony_ci bh = ERR_PTR(retval); 181862306a36Sopenharmony_ci goto errout; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci } while (retval == 1); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci bh = NULL; 182362306a36Sopenharmony_cierrout: 182462306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "%s not found\n", fname->usr_fname->name)); 182562306a36Sopenharmony_cisuccess: 182662306a36Sopenharmony_ci dx_release(frames); 182762306a36Sopenharmony_ci return bh; 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_cistatic struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) 183162306a36Sopenharmony_ci{ 183262306a36Sopenharmony_ci struct inode *inode; 183362306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 183462306a36Sopenharmony_ci struct buffer_head *bh; 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci if (dentry->d_name.len > EXT4_NAME_LEN) 183762306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci bh = ext4_lookup_entry(dir, dentry, &de); 184062306a36Sopenharmony_ci if (IS_ERR(bh)) 184162306a36Sopenharmony_ci return ERR_CAST(bh); 184262306a36Sopenharmony_ci inode = NULL; 184362306a36Sopenharmony_ci if (bh) { 184462306a36Sopenharmony_ci __u32 ino = le32_to_cpu(de->inode); 184562306a36Sopenharmony_ci brelse(bh); 184662306a36Sopenharmony_ci if (!ext4_valid_inum(dir->i_sb, ino)) { 184762306a36Sopenharmony_ci EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); 184862306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci if (unlikely(ino == dir->i_ino)) { 185162306a36Sopenharmony_ci EXT4_ERROR_INODE(dir, "'%pd' linked to parent dir", 185262306a36Sopenharmony_ci dentry); 185362306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci inode = ext4_iget(dir->i_sb, ino, EXT4_IGET_NORMAL); 185662306a36Sopenharmony_ci if (inode == ERR_PTR(-ESTALE)) { 185762306a36Sopenharmony_ci EXT4_ERROR_INODE(dir, 185862306a36Sopenharmony_ci "deleted inode referenced: %u", 185962306a36Sopenharmony_ci ino); 186062306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci if (!IS_ERR(inode) && IS_ENCRYPTED(dir) && 186362306a36Sopenharmony_ci (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && 186462306a36Sopenharmony_ci !fscrypt_has_permitted_context(dir, inode)) { 186562306a36Sopenharmony_ci ext4_warning(inode->i_sb, 186662306a36Sopenharmony_ci "Inconsistent encryption contexts: %lu/%lu", 186762306a36Sopenharmony_ci dir->i_ino, inode->i_ino); 186862306a36Sopenharmony_ci iput(inode); 186962306a36Sopenharmony_ci return ERR_PTR(-EPERM); 187062306a36Sopenharmony_ci } 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 187462306a36Sopenharmony_ci if (!inode && IS_CASEFOLDED(dir)) { 187562306a36Sopenharmony_ci /* Eventually we want to call d_add_ci(dentry, NULL) 187662306a36Sopenharmony_ci * for negative dentries in the encoding case as 187762306a36Sopenharmony_ci * well. For now, prevent the negative dentry 187862306a36Sopenharmony_ci * from being cached. 187962306a36Sopenharmony_ci */ 188062306a36Sopenharmony_ci return NULL; 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci#endif 188362306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_cistruct dentry *ext4_get_parent(struct dentry *child) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci __u32 ino; 189062306a36Sopenharmony_ci struct ext4_dir_entry_2 * de; 189162306a36Sopenharmony_ci struct buffer_head *bh; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci bh = ext4_find_entry(d_inode(child), &dotdot_name, &de, NULL); 189462306a36Sopenharmony_ci if (IS_ERR(bh)) 189562306a36Sopenharmony_ci return ERR_CAST(bh); 189662306a36Sopenharmony_ci if (!bh) 189762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 189862306a36Sopenharmony_ci ino = le32_to_cpu(de->inode); 189962306a36Sopenharmony_ci brelse(bh); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci if (!ext4_valid_inum(child->d_sb, ino)) { 190262306a36Sopenharmony_ci EXT4_ERROR_INODE(d_inode(child), 190362306a36Sopenharmony_ci "bad parent inode number: %u", ino); 190462306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci return d_obtain_alias(ext4_iget(child->d_sb, ino, EXT4_IGET_NORMAL)); 190862306a36Sopenharmony_ci} 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci/* 191162306a36Sopenharmony_ci * Move count entries from end of map between two memory locations. 191262306a36Sopenharmony_ci * Returns pointer to last entry moved. 191362306a36Sopenharmony_ci */ 191462306a36Sopenharmony_cistatic struct ext4_dir_entry_2 * 191562306a36Sopenharmony_cidx_move_dirents(struct inode *dir, char *from, char *to, 191662306a36Sopenharmony_ci struct dx_map_entry *map, int count, 191762306a36Sopenharmony_ci unsigned blocksize) 191862306a36Sopenharmony_ci{ 191962306a36Sopenharmony_ci unsigned rec_len = 0; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci while (count--) { 192262306a36Sopenharmony_ci struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) 192362306a36Sopenharmony_ci (from + (map->offs<<2)); 192462306a36Sopenharmony_ci rec_len = ext4_dir_rec_len(de->name_len, dir); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci memcpy (to, de, rec_len); 192762306a36Sopenharmony_ci ((struct ext4_dir_entry_2 *) to)->rec_len = 192862306a36Sopenharmony_ci ext4_rec_len_to_disk(rec_len, blocksize); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci /* wipe dir_entry excluding the rec_len field */ 193162306a36Sopenharmony_ci de->inode = 0; 193262306a36Sopenharmony_ci memset(&de->name_len, 0, ext4_rec_len_from_disk(de->rec_len, 193362306a36Sopenharmony_ci blocksize) - 193462306a36Sopenharmony_ci offsetof(struct ext4_dir_entry_2, 193562306a36Sopenharmony_ci name_len)); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci map++; 193862306a36Sopenharmony_ci to += rec_len; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci return (struct ext4_dir_entry_2 *) (to - rec_len); 194162306a36Sopenharmony_ci} 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci/* 194462306a36Sopenharmony_ci * Compact each dir entry in the range to the minimal rec_len. 194562306a36Sopenharmony_ci * Returns pointer to last entry in range. 194662306a36Sopenharmony_ci */ 194762306a36Sopenharmony_cistatic struct ext4_dir_entry_2 *dx_pack_dirents(struct inode *dir, char *base, 194862306a36Sopenharmony_ci unsigned int blocksize) 194962306a36Sopenharmony_ci{ 195062306a36Sopenharmony_ci struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base; 195162306a36Sopenharmony_ci unsigned rec_len = 0; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci prev = to = de; 195462306a36Sopenharmony_ci while ((char*)de < base + blocksize) { 195562306a36Sopenharmony_ci next = ext4_next_entry(de, blocksize); 195662306a36Sopenharmony_ci if (de->inode && de->name_len) { 195762306a36Sopenharmony_ci rec_len = ext4_dir_rec_len(de->name_len, dir); 195862306a36Sopenharmony_ci if (de > to) 195962306a36Sopenharmony_ci memmove(to, de, rec_len); 196062306a36Sopenharmony_ci to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize); 196162306a36Sopenharmony_ci prev = to; 196262306a36Sopenharmony_ci to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len); 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci de = next; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci return prev; 196762306a36Sopenharmony_ci} 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci/* 197062306a36Sopenharmony_ci * Split a full leaf block to make room for a new dir entry. 197162306a36Sopenharmony_ci * Allocate a new block, and move entries so that they are approx. equally full. 197262306a36Sopenharmony_ci * Returns pointer to de in block into which the new entry will be inserted. 197362306a36Sopenharmony_ci */ 197462306a36Sopenharmony_cistatic struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, 197562306a36Sopenharmony_ci struct buffer_head **bh,struct dx_frame *frame, 197662306a36Sopenharmony_ci struct dx_hash_info *hinfo) 197762306a36Sopenharmony_ci{ 197862306a36Sopenharmony_ci unsigned blocksize = dir->i_sb->s_blocksize; 197962306a36Sopenharmony_ci unsigned continued; 198062306a36Sopenharmony_ci int count; 198162306a36Sopenharmony_ci struct buffer_head *bh2; 198262306a36Sopenharmony_ci ext4_lblk_t newblock; 198362306a36Sopenharmony_ci u32 hash2; 198462306a36Sopenharmony_ci struct dx_map_entry *map; 198562306a36Sopenharmony_ci char *data1 = (*bh)->b_data, *data2; 198662306a36Sopenharmony_ci unsigned split, move, size; 198762306a36Sopenharmony_ci struct ext4_dir_entry_2 *de = NULL, *de2; 198862306a36Sopenharmony_ci int csum_size = 0; 198962306a36Sopenharmony_ci int err = 0, i; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 199262306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci bh2 = ext4_append(handle, dir, &newblock); 199562306a36Sopenharmony_ci if (IS_ERR(bh2)) { 199662306a36Sopenharmony_ci brelse(*bh); 199762306a36Sopenharmony_ci *bh = NULL; 199862306a36Sopenharmony_ci return (struct ext4_dir_entry_2 *) bh2; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci BUFFER_TRACE(*bh, "get_write_access"); 200262306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, dir->i_sb, *bh, 200362306a36Sopenharmony_ci EXT4_JTR_NONE); 200462306a36Sopenharmony_ci if (err) 200562306a36Sopenharmony_ci goto journal_error; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci BUFFER_TRACE(frame->bh, "get_write_access"); 200862306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, dir->i_sb, frame->bh, 200962306a36Sopenharmony_ci EXT4_JTR_NONE); 201062306a36Sopenharmony_ci if (err) 201162306a36Sopenharmony_ci goto journal_error; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci data2 = bh2->b_data; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* create map in the end of data2 block */ 201662306a36Sopenharmony_ci map = (struct dx_map_entry *) (data2 + blocksize); 201762306a36Sopenharmony_ci count = dx_make_map(dir, *bh, hinfo, map); 201862306a36Sopenharmony_ci if (count < 0) { 201962306a36Sopenharmony_ci err = count; 202062306a36Sopenharmony_ci goto journal_error; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci map -= count; 202362306a36Sopenharmony_ci dx_sort_map(map, count); 202462306a36Sopenharmony_ci /* Ensure that neither split block is over half full */ 202562306a36Sopenharmony_ci size = 0; 202662306a36Sopenharmony_ci move = 0; 202762306a36Sopenharmony_ci for (i = count-1; i >= 0; i--) { 202862306a36Sopenharmony_ci /* is more than half of this entry in 2nd half of the block? */ 202962306a36Sopenharmony_ci if (size + map[i].size/2 > blocksize/2) 203062306a36Sopenharmony_ci break; 203162306a36Sopenharmony_ci size += map[i].size; 203262306a36Sopenharmony_ci move++; 203362306a36Sopenharmony_ci } 203462306a36Sopenharmony_ci /* 203562306a36Sopenharmony_ci * map index at which we will split 203662306a36Sopenharmony_ci * 203762306a36Sopenharmony_ci * If the sum of active entries didn't exceed half the block size, just 203862306a36Sopenharmony_ci * split it in half by count; each resulting block will have at least 203962306a36Sopenharmony_ci * half the space free. 204062306a36Sopenharmony_ci */ 204162306a36Sopenharmony_ci if (i > 0) 204262306a36Sopenharmony_ci split = count - move; 204362306a36Sopenharmony_ci else 204462306a36Sopenharmony_ci split = count/2; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci hash2 = map[split].hash; 204762306a36Sopenharmony_ci continued = hash2 == map[split - 1].hash; 204862306a36Sopenharmony_ci dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n", 204962306a36Sopenharmony_ci (unsigned long)dx_get_block(frame->at), 205062306a36Sopenharmony_ci hash2, split, count-split)); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* Fancy dance to stay within two buffers */ 205362306a36Sopenharmony_ci de2 = dx_move_dirents(dir, data1, data2, map + split, count - split, 205462306a36Sopenharmony_ci blocksize); 205562306a36Sopenharmony_ci de = dx_pack_dirents(dir, data1, blocksize); 205662306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - 205762306a36Sopenharmony_ci (char *) de, 205862306a36Sopenharmony_ci blocksize); 205962306a36Sopenharmony_ci de2->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - 206062306a36Sopenharmony_ci (char *) de2, 206162306a36Sopenharmony_ci blocksize); 206262306a36Sopenharmony_ci if (csum_size) { 206362306a36Sopenharmony_ci ext4_initialize_dirent_tail(*bh, blocksize); 206462306a36Sopenharmony_ci ext4_initialize_dirent_tail(bh2, blocksize); 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data1, 206862306a36Sopenharmony_ci blocksize, 1)); 206962306a36Sopenharmony_ci dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data2, 207062306a36Sopenharmony_ci blocksize, 1)); 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* Which block gets the new entry? */ 207362306a36Sopenharmony_ci if (hinfo->hash >= hash2) { 207462306a36Sopenharmony_ci swap(*bh, bh2); 207562306a36Sopenharmony_ci de = de2; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci dx_insert_block(frame, hash2 + continued, newblock); 207862306a36Sopenharmony_ci err = ext4_handle_dirty_dirblock(handle, dir, bh2); 207962306a36Sopenharmony_ci if (err) 208062306a36Sopenharmony_ci goto journal_error; 208162306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); 208262306a36Sopenharmony_ci if (err) 208362306a36Sopenharmony_ci goto journal_error; 208462306a36Sopenharmony_ci brelse(bh2); 208562306a36Sopenharmony_ci dxtrace(dx_show_index("frame", frame->entries)); 208662306a36Sopenharmony_ci return de; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_cijournal_error: 208962306a36Sopenharmony_ci brelse(*bh); 209062306a36Sopenharmony_ci brelse(bh2); 209162306a36Sopenharmony_ci *bh = NULL; 209262306a36Sopenharmony_ci ext4_std_error(dir->i_sb, err); 209362306a36Sopenharmony_ci return ERR_PTR(err); 209462306a36Sopenharmony_ci} 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ciint ext4_find_dest_de(struct inode *dir, struct inode *inode, 209762306a36Sopenharmony_ci struct buffer_head *bh, 209862306a36Sopenharmony_ci void *buf, int buf_size, 209962306a36Sopenharmony_ci struct ext4_filename *fname, 210062306a36Sopenharmony_ci struct ext4_dir_entry_2 **dest_de) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 210362306a36Sopenharmony_ci unsigned short reclen = ext4_dir_rec_len(fname_len(fname), dir); 210462306a36Sopenharmony_ci int nlen, rlen; 210562306a36Sopenharmony_ci unsigned int offset = 0; 210662306a36Sopenharmony_ci char *top; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci de = buf; 210962306a36Sopenharmony_ci top = buf + buf_size - reclen; 211062306a36Sopenharmony_ci while ((char *) de <= top) { 211162306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh, 211262306a36Sopenharmony_ci buf, buf_size, offset)) 211362306a36Sopenharmony_ci return -EFSCORRUPTED; 211462306a36Sopenharmony_ci if (ext4_match(dir, fname, de)) 211562306a36Sopenharmony_ci return -EEXIST; 211662306a36Sopenharmony_ci nlen = ext4_dir_rec_len(de->name_len, dir); 211762306a36Sopenharmony_ci rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); 211862306a36Sopenharmony_ci if ((de->inode ? rlen - nlen : rlen) >= reclen) 211962306a36Sopenharmony_ci break; 212062306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *)((char *)de + rlen); 212162306a36Sopenharmony_ci offset += rlen; 212262306a36Sopenharmony_ci } 212362306a36Sopenharmony_ci if ((char *) de > top) 212462306a36Sopenharmony_ci return -ENOSPC; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci *dest_de = de; 212762306a36Sopenharmony_ci return 0; 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_civoid ext4_insert_dentry(struct inode *dir, 213162306a36Sopenharmony_ci struct inode *inode, 213262306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, 213362306a36Sopenharmony_ci int buf_size, 213462306a36Sopenharmony_ci struct ext4_filename *fname) 213562306a36Sopenharmony_ci{ 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci int nlen, rlen; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci nlen = ext4_dir_rec_len(de->name_len, dir); 214062306a36Sopenharmony_ci rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); 214162306a36Sopenharmony_ci if (de->inode) { 214262306a36Sopenharmony_ci struct ext4_dir_entry_2 *de1 = 214362306a36Sopenharmony_ci (struct ext4_dir_entry_2 *)((char *)de + nlen); 214462306a36Sopenharmony_ci de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size); 214562306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(nlen, buf_size); 214662306a36Sopenharmony_ci de = de1; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci de->file_type = EXT4_FT_UNKNOWN; 214962306a36Sopenharmony_ci de->inode = cpu_to_le32(inode->i_ino); 215062306a36Sopenharmony_ci ext4_set_de_type(inode->i_sb, de, inode->i_mode); 215162306a36Sopenharmony_ci de->name_len = fname_len(fname); 215262306a36Sopenharmony_ci memcpy(de->name, fname_name(fname), fname_len(fname)); 215362306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) { 215462306a36Sopenharmony_ci struct dx_hash_info *hinfo = &fname->hinfo; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci EXT4_DIRENT_HASHES(de)->hash = cpu_to_le32(hinfo->hash); 215762306a36Sopenharmony_ci EXT4_DIRENT_HASHES(de)->minor_hash = 215862306a36Sopenharmony_ci cpu_to_le32(hinfo->minor_hash); 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci/* 216362306a36Sopenharmony_ci * Add a new entry into a directory (leaf) block. If de is non-NULL, 216462306a36Sopenharmony_ci * it points to a directory entry which is guaranteed to be large 216562306a36Sopenharmony_ci * enough for new directory entry. If de is NULL, then 216662306a36Sopenharmony_ci * add_dirent_to_buf will attempt search the directory block for 216762306a36Sopenharmony_ci * space. It will return -ENOSPC if no space is available, and -EIO 216862306a36Sopenharmony_ci * and -EEXIST if directory entry already exists. 216962306a36Sopenharmony_ci */ 217062306a36Sopenharmony_cistatic int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, 217162306a36Sopenharmony_ci struct inode *dir, 217262306a36Sopenharmony_ci struct inode *inode, struct ext4_dir_entry_2 *de, 217362306a36Sopenharmony_ci struct buffer_head *bh) 217462306a36Sopenharmony_ci{ 217562306a36Sopenharmony_ci unsigned int blocksize = dir->i_sb->s_blocksize; 217662306a36Sopenharmony_ci int csum_size = 0; 217762306a36Sopenharmony_ci int err, err2; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci if (ext4_has_metadata_csum(inode->i_sb)) 218062306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci if (!de) { 218362306a36Sopenharmony_ci err = ext4_find_dest_de(dir, inode, bh, bh->b_data, 218462306a36Sopenharmony_ci blocksize - csum_size, fname, &de); 218562306a36Sopenharmony_ci if (err) 218662306a36Sopenharmony_ci return err; 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 218962306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, dir->i_sb, bh, 219062306a36Sopenharmony_ci EXT4_JTR_NONE); 219162306a36Sopenharmony_ci if (err) { 219262306a36Sopenharmony_ci ext4_std_error(dir->i_sb, err); 219362306a36Sopenharmony_ci return err; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci /* By now the buffer is marked for journaling */ 219762306a36Sopenharmony_ci ext4_insert_dentry(dir, inode, de, blocksize, fname); 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci /* 220062306a36Sopenharmony_ci * XXX shouldn't update any times until successful 220162306a36Sopenharmony_ci * completion of syscall, but too many callers depend 220262306a36Sopenharmony_ci * on this. 220362306a36Sopenharmony_ci * 220462306a36Sopenharmony_ci * XXX similarly, too many callers depend on 220562306a36Sopenharmony_ci * ext4_new_inode() setting the times, but error 220662306a36Sopenharmony_ci * recovery deletes the inode, so the worst that can 220762306a36Sopenharmony_ci * happen is that the times are slightly out of date 220862306a36Sopenharmony_ci * and/or different from the directory change time. 220962306a36Sopenharmony_ci */ 221062306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_current(dir); 221162306a36Sopenharmony_ci ext4_update_dx_flag(dir); 221262306a36Sopenharmony_ci inode_inc_iversion(dir); 221362306a36Sopenharmony_ci err2 = ext4_mark_inode_dirty(handle, dir); 221462306a36Sopenharmony_ci BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 221562306a36Sopenharmony_ci err = ext4_handle_dirty_dirblock(handle, dir, bh); 221662306a36Sopenharmony_ci if (err) 221762306a36Sopenharmony_ci ext4_std_error(dir->i_sb, err); 221862306a36Sopenharmony_ci return err ? err : err2; 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci/* 222262306a36Sopenharmony_ci * This converts a one block unindexed directory to a 3 block indexed 222362306a36Sopenharmony_ci * directory, and adds the dentry to the indexed directory. 222462306a36Sopenharmony_ci */ 222562306a36Sopenharmony_cistatic int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, 222662306a36Sopenharmony_ci struct inode *dir, 222762306a36Sopenharmony_ci struct inode *inode, struct buffer_head *bh) 222862306a36Sopenharmony_ci{ 222962306a36Sopenharmony_ci struct buffer_head *bh2; 223062306a36Sopenharmony_ci struct dx_root *root; 223162306a36Sopenharmony_ci struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; 223262306a36Sopenharmony_ci struct dx_entry *entries; 223362306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, *de2; 223462306a36Sopenharmony_ci char *data2, *top; 223562306a36Sopenharmony_ci unsigned len; 223662306a36Sopenharmony_ci int retval; 223762306a36Sopenharmony_ci unsigned blocksize; 223862306a36Sopenharmony_ci ext4_lblk_t block; 223962306a36Sopenharmony_ci struct fake_dirent *fde; 224062306a36Sopenharmony_ci int csum_size = 0; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (ext4_has_metadata_csum(inode->i_sb)) 224362306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci blocksize = dir->i_sb->s_blocksize; 224662306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); 224762306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 224862306a36Sopenharmony_ci retval = ext4_journal_get_write_access(handle, dir->i_sb, bh, 224962306a36Sopenharmony_ci EXT4_JTR_NONE); 225062306a36Sopenharmony_ci if (retval) { 225162306a36Sopenharmony_ci ext4_std_error(dir->i_sb, retval); 225262306a36Sopenharmony_ci brelse(bh); 225362306a36Sopenharmony_ci return retval; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci root = (struct dx_root *) bh->b_data; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci /* The 0th block becomes the root, move the dirents out */ 225862306a36Sopenharmony_ci fde = &root->dotdot; 225962306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *)((char *)fde + 226062306a36Sopenharmony_ci ext4_rec_len_from_disk(fde->rec_len, blocksize)); 226162306a36Sopenharmony_ci if ((char *) de >= (((char *) root) + blocksize)) { 226262306a36Sopenharmony_ci EXT4_ERROR_INODE(dir, "invalid rec_len for '..'"); 226362306a36Sopenharmony_ci brelse(bh); 226462306a36Sopenharmony_ci return -EFSCORRUPTED; 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci len = ((char *) root) + (blocksize - csum_size) - (char *) de; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci /* Allocate new block for the 0th block's dirents */ 226962306a36Sopenharmony_ci bh2 = ext4_append(handle, dir, &block); 227062306a36Sopenharmony_ci if (IS_ERR(bh2)) { 227162306a36Sopenharmony_ci brelse(bh); 227262306a36Sopenharmony_ci return PTR_ERR(bh2); 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci ext4_set_inode_flag(dir, EXT4_INODE_INDEX); 227562306a36Sopenharmony_ci data2 = bh2->b_data; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci memcpy(data2, de, len); 227862306a36Sopenharmony_ci memset(de, 0, len); /* wipe old data */ 227962306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) data2; 228062306a36Sopenharmony_ci top = data2 + len; 228162306a36Sopenharmony_ci while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) { 228262306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh2, data2, len, 228362306a36Sopenharmony_ci (data2 + (blocksize - csum_size) - 228462306a36Sopenharmony_ci (char *) de))) { 228562306a36Sopenharmony_ci brelse(bh2); 228662306a36Sopenharmony_ci brelse(bh); 228762306a36Sopenharmony_ci return -EFSCORRUPTED; 228862306a36Sopenharmony_ci } 228962306a36Sopenharmony_ci de = de2; 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - 229262306a36Sopenharmony_ci (char *) de, blocksize); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci if (csum_size) 229562306a36Sopenharmony_ci ext4_initialize_dirent_tail(bh2, blocksize); 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci /* Initialize the root; the dot dirents already exist */ 229862306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) (&root->dotdot); 229962306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk( 230062306a36Sopenharmony_ci blocksize - ext4_dir_rec_len(2, NULL), blocksize); 230162306a36Sopenharmony_ci memset (&root->info, 0, sizeof(root->info)); 230262306a36Sopenharmony_ci root->info.info_length = sizeof(root->info); 230362306a36Sopenharmony_ci if (ext4_hash_in_dirent(dir)) 230462306a36Sopenharmony_ci root->info.hash_version = DX_HASH_SIPHASH; 230562306a36Sopenharmony_ci else 230662306a36Sopenharmony_ci root->info.hash_version = 230762306a36Sopenharmony_ci EXT4_SB(dir->i_sb)->s_def_hash_version; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci entries = root->entries; 231062306a36Sopenharmony_ci dx_set_block(entries, 1); 231162306a36Sopenharmony_ci dx_set_count(entries, 1); 231262306a36Sopenharmony_ci dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info))); 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci /* Initialize as for dx_probe */ 231562306a36Sopenharmony_ci fname->hinfo.hash_version = root->info.hash_version; 231662306a36Sopenharmony_ci if (fname->hinfo.hash_version <= DX_HASH_TEA) 231762306a36Sopenharmony_ci fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; 231862306a36Sopenharmony_ci fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci /* casefolded encrypted hashes are computed on fname setup */ 232162306a36Sopenharmony_ci if (!ext4_hash_in_dirent(dir)) { 232262306a36Sopenharmony_ci int err = ext4fs_dirhash(dir, fname_name(fname), 232362306a36Sopenharmony_ci fname_len(fname), &fname->hinfo); 232462306a36Sopenharmony_ci if (err < 0) { 232562306a36Sopenharmony_ci brelse(bh2); 232662306a36Sopenharmony_ci brelse(bh); 232762306a36Sopenharmony_ci return err; 232862306a36Sopenharmony_ci } 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci memset(frames, 0, sizeof(frames)); 233162306a36Sopenharmony_ci frame = frames; 233262306a36Sopenharmony_ci frame->entries = entries; 233362306a36Sopenharmony_ci frame->at = entries; 233462306a36Sopenharmony_ci frame->bh = bh; 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh); 233762306a36Sopenharmony_ci if (retval) 233862306a36Sopenharmony_ci goto out_frames; 233962306a36Sopenharmony_ci retval = ext4_handle_dirty_dirblock(handle, dir, bh2); 234062306a36Sopenharmony_ci if (retval) 234162306a36Sopenharmony_ci goto out_frames; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci de = do_split(handle,dir, &bh2, frame, &fname->hinfo); 234462306a36Sopenharmony_ci if (IS_ERR(de)) { 234562306a36Sopenharmony_ci retval = PTR_ERR(de); 234662306a36Sopenharmony_ci goto out_frames; 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2); 235062306a36Sopenharmony_ciout_frames: 235162306a36Sopenharmony_ci /* 235262306a36Sopenharmony_ci * Even if the block split failed, we have to properly write 235362306a36Sopenharmony_ci * out all the changes we did so far. Otherwise we can end up 235462306a36Sopenharmony_ci * with corrupted filesystem. 235562306a36Sopenharmony_ci */ 235662306a36Sopenharmony_ci if (retval) 235762306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, dir); 235862306a36Sopenharmony_ci dx_release(frames); 235962306a36Sopenharmony_ci brelse(bh2); 236062306a36Sopenharmony_ci return retval; 236162306a36Sopenharmony_ci} 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci/* 236462306a36Sopenharmony_ci * ext4_add_entry() 236562306a36Sopenharmony_ci * 236662306a36Sopenharmony_ci * adds a file entry to the specified directory, using the same 236762306a36Sopenharmony_ci * semantics as ext4_find_entry(). It returns NULL if it failed. 236862306a36Sopenharmony_ci * 236962306a36Sopenharmony_ci * NOTE!! The inode part of 'de' is left at 0 - which means you 237062306a36Sopenharmony_ci * may not sleep between calling this and putting something into 237162306a36Sopenharmony_ci * the entry, as someone else might have used it while you slept. 237262306a36Sopenharmony_ci */ 237362306a36Sopenharmony_cistatic int ext4_add_entry(handle_t *handle, struct dentry *dentry, 237462306a36Sopenharmony_ci struct inode *inode) 237562306a36Sopenharmony_ci{ 237662306a36Sopenharmony_ci struct inode *dir = d_inode(dentry->d_parent); 237762306a36Sopenharmony_ci struct buffer_head *bh = NULL; 237862306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 237962306a36Sopenharmony_ci struct super_block *sb; 238062306a36Sopenharmony_ci struct ext4_filename fname; 238162306a36Sopenharmony_ci int retval; 238262306a36Sopenharmony_ci int dx_fallback=0; 238362306a36Sopenharmony_ci unsigned blocksize; 238462306a36Sopenharmony_ci ext4_lblk_t block, blocks; 238562306a36Sopenharmony_ci int csum_size = 0; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (ext4_has_metadata_csum(inode->i_sb)) 238862306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci sb = dir->i_sb; 239162306a36Sopenharmony_ci blocksize = sb->s_blocksize; 239262306a36Sopenharmony_ci if (!dentry->d_name.len) 239362306a36Sopenharmony_ci return -EINVAL; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci if (fscrypt_is_nokey_name(dentry)) 239662306a36Sopenharmony_ci return -ENOKEY; 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 239962306a36Sopenharmony_ci if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) && 240062306a36Sopenharmony_ci utf8_validate(sb->s_encoding, &dentry->d_name)) 240162306a36Sopenharmony_ci return -EINVAL; 240262306a36Sopenharmony_ci#endif 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci retval = ext4_fname_setup_filename(dir, &dentry->d_name, 0, &fname); 240562306a36Sopenharmony_ci if (retval) 240662306a36Sopenharmony_ci return retval; 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (ext4_has_inline_data(dir)) { 240962306a36Sopenharmony_ci retval = ext4_try_add_inline_entry(handle, &fname, dir, inode); 241062306a36Sopenharmony_ci if (retval < 0) 241162306a36Sopenharmony_ci goto out; 241262306a36Sopenharmony_ci if (retval == 1) { 241362306a36Sopenharmony_ci retval = 0; 241462306a36Sopenharmony_ci goto out; 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci if (is_dx(dir)) { 241962306a36Sopenharmony_ci retval = ext4_dx_add_entry(handle, &fname, dir, inode); 242062306a36Sopenharmony_ci if (!retval || (retval != ERR_BAD_DX_DIR)) 242162306a36Sopenharmony_ci goto out; 242262306a36Sopenharmony_ci /* Can we just ignore htree data? */ 242362306a36Sopenharmony_ci if (ext4_has_metadata_csum(sb)) { 242462306a36Sopenharmony_ci EXT4_ERROR_INODE(dir, 242562306a36Sopenharmony_ci "Directory has corrupted htree index."); 242662306a36Sopenharmony_ci retval = -EFSCORRUPTED; 242762306a36Sopenharmony_ci goto out; 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); 243062306a36Sopenharmony_ci dx_fallback++; 243162306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, dir); 243262306a36Sopenharmony_ci if (unlikely(retval)) 243362306a36Sopenharmony_ci goto out; 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci blocks = dir->i_size >> sb->s_blocksize_bits; 243662306a36Sopenharmony_ci for (block = 0; block < blocks; block++) { 243762306a36Sopenharmony_ci bh = ext4_read_dirblock(dir, block, DIRENT); 243862306a36Sopenharmony_ci if (bh == NULL) { 243962306a36Sopenharmony_ci bh = ext4_bread(handle, dir, block, 244062306a36Sopenharmony_ci EXT4_GET_BLOCKS_CREATE); 244162306a36Sopenharmony_ci goto add_to_new_block; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci if (IS_ERR(bh)) { 244462306a36Sopenharmony_ci retval = PTR_ERR(bh); 244562306a36Sopenharmony_ci bh = NULL; 244662306a36Sopenharmony_ci goto out; 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci retval = add_dirent_to_buf(handle, &fname, dir, inode, 244962306a36Sopenharmony_ci NULL, bh); 245062306a36Sopenharmony_ci if (retval != -ENOSPC) 245162306a36Sopenharmony_ci goto out; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci if (blocks == 1 && !dx_fallback && 245462306a36Sopenharmony_ci ext4_has_feature_dir_index(sb)) { 245562306a36Sopenharmony_ci retval = make_indexed_dir(handle, &fname, dir, 245662306a36Sopenharmony_ci inode, bh); 245762306a36Sopenharmony_ci bh = NULL; /* make_indexed_dir releases bh */ 245862306a36Sopenharmony_ci goto out; 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci brelse(bh); 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci bh = ext4_append(handle, dir, &block); 246362306a36Sopenharmony_ciadd_to_new_block: 246462306a36Sopenharmony_ci if (IS_ERR(bh)) { 246562306a36Sopenharmony_ci retval = PTR_ERR(bh); 246662306a36Sopenharmony_ci bh = NULL; 246762306a36Sopenharmony_ci goto out; 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) bh->b_data; 247062306a36Sopenharmony_ci de->inode = 0; 247162306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci if (csum_size) 247462306a36Sopenharmony_ci ext4_initialize_dirent_tail(bh, blocksize); 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci retval = add_dirent_to_buf(handle, &fname, dir, inode, de, bh); 247762306a36Sopenharmony_ciout: 247862306a36Sopenharmony_ci ext4_fname_free_filename(&fname); 247962306a36Sopenharmony_ci brelse(bh); 248062306a36Sopenharmony_ci if (retval == 0) 248162306a36Sopenharmony_ci ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY); 248262306a36Sopenharmony_ci return retval; 248362306a36Sopenharmony_ci} 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci/* 248662306a36Sopenharmony_ci * Returns 0 for success, or a negative error value 248762306a36Sopenharmony_ci */ 248862306a36Sopenharmony_cistatic int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, 248962306a36Sopenharmony_ci struct inode *dir, struct inode *inode) 249062306a36Sopenharmony_ci{ 249162306a36Sopenharmony_ci struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; 249262306a36Sopenharmony_ci struct dx_entry *entries, *at; 249362306a36Sopenharmony_ci struct buffer_head *bh; 249462306a36Sopenharmony_ci struct super_block *sb = dir->i_sb; 249562306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 249662306a36Sopenharmony_ci int restart; 249762306a36Sopenharmony_ci int err; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ciagain: 250062306a36Sopenharmony_ci restart = 0; 250162306a36Sopenharmony_ci frame = dx_probe(fname, dir, NULL, frames); 250262306a36Sopenharmony_ci if (IS_ERR(frame)) 250362306a36Sopenharmony_ci return PTR_ERR(frame); 250462306a36Sopenharmony_ci entries = frame->entries; 250562306a36Sopenharmony_ci at = frame->at; 250662306a36Sopenharmony_ci bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT_HTREE); 250762306a36Sopenharmony_ci if (IS_ERR(bh)) { 250862306a36Sopenharmony_ci err = PTR_ERR(bh); 250962306a36Sopenharmony_ci bh = NULL; 251062306a36Sopenharmony_ci goto cleanup; 251162306a36Sopenharmony_ci } 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 251462306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, bh, EXT4_JTR_NONE); 251562306a36Sopenharmony_ci if (err) 251662306a36Sopenharmony_ci goto journal_error; 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci err = add_dirent_to_buf(handle, fname, dir, inode, NULL, bh); 251962306a36Sopenharmony_ci if (err != -ENOSPC) 252062306a36Sopenharmony_ci goto cleanup; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci err = 0; 252362306a36Sopenharmony_ci /* Block full, should compress but for now just split */ 252462306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", 252562306a36Sopenharmony_ci dx_get_count(entries), dx_get_limit(entries))); 252662306a36Sopenharmony_ci /* Need to split index? */ 252762306a36Sopenharmony_ci if (dx_get_count(entries) == dx_get_limit(entries)) { 252862306a36Sopenharmony_ci ext4_lblk_t newblock; 252962306a36Sopenharmony_ci int levels = frame - frames + 1; 253062306a36Sopenharmony_ci unsigned int icount; 253162306a36Sopenharmony_ci int add_level = 1; 253262306a36Sopenharmony_ci struct dx_entry *entries2; 253362306a36Sopenharmony_ci struct dx_node *node2; 253462306a36Sopenharmony_ci struct buffer_head *bh2; 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci while (frame > frames) { 253762306a36Sopenharmony_ci if (dx_get_count((frame - 1)->entries) < 253862306a36Sopenharmony_ci dx_get_limit((frame - 1)->entries)) { 253962306a36Sopenharmony_ci add_level = 0; 254062306a36Sopenharmony_ci break; 254162306a36Sopenharmony_ci } 254262306a36Sopenharmony_ci frame--; /* split higher index block */ 254362306a36Sopenharmony_ci at = frame->at; 254462306a36Sopenharmony_ci entries = frame->entries; 254562306a36Sopenharmony_ci restart = 1; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci if (add_level && levels == ext4_dir_htree_level(sb)) { 254862306a36Sopenharmony_ci ext4_warning(sb, "Directory (ino: %lu) index full, " 254962306a36Sopenharmony_ci "reach max htree level :%d", 255062306a36Sopenharmony_ci dir->i_ino, levels); 255162306a36Sopenharmony_ci if (ext4_dir_htree_level(sb) < EXT4_HTREE_LEVEL) { 255262306a36Sopenharmony_ci ext4_warning(sb, "Large directory feature is " 255362306a36Sopenharmony_ci "not enabled on this " 255462306a36Sopenharmony_ci "filesystem"); 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci err = -ENOSPC; 255762306a36Sopenharmony_ci goto cleanup; 255862306a36Sopenharmony_ci } 255962306a36Sopenharmony_ci icount = dx_get_count(entries); 256062306a36Sopenharmony_ci bh2 = ext4_append(handle, dir, &newblock); 256162306a36Sopenharmony_ci if (IS_ERR(bh2)) { 256262306a36Sopenharmony_ci err = PTR_ERR(bh2); 256362306a36Sopenharmony_ci goto cleanup; 256462306a36Sopenharmony_ci } 256562306a36Sopenharmony_ci node2 = (struct dx_node *)(bh2->b_data); 256662306a36Sopenharmony_ci entries2 = node2->entries; 256762306a36Sopenharmony_ci memset(&node2->fake, 0, sizeof(struct fake_dirent)); 256862306a36Sopenharmony_ci node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize, 256962306a36Sopenharmony_ci sb->s_blocksize); 257062306a36Sopenharmony_ci BUFFER_TRACE(frame->bh, "get_write_access"); 257162306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, frame->bh, 257262306a36Sopenharmony_ci EXT4_JTR_NONE); 257362306a36Sopenharmony_ci if (err) 257462306a36Sopenharmony_ci goto journal_error; 257562306a36Sopenharmony_ci if (!add_level) { 257662306a36Sopenharmony_ci unsigned icount1 = icount/2, icount2 = icount - icount1; 257762306a36Sopenharmony_ci unsigned hash2 = dx_get_hash(entries + icount1); 257862306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG "Split index %i/%i\n", 257962306a36Sopenharmony_ci icount1, icount2)); 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ 258262306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, sb, 258362306a36Sopenharmony_ci (frame - 1)->bh, 258462306a36Sopenharmony_ci EXT4_JTR_NONE); 258562306a36Sopenharmony_ci if (err) 258662306a36Sopenharmony_ci goto journal_error; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci memcpy((char *) entries2, (char *) (entries + icount1), 258962306a36Sopenharmony_ci icount2 * sizeof(struct dx_entry)); 259062306a36Sopenharmony_ci dx_set_count(entries, icount1); 259162306a36Sopenharmony_ci dx_set_count(entries2, icount2); 259262306a36Sopenharmony_ci dx_set_limit(entries2, dx_node_limit(dir)); 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci /* Which index block gets the new entry? */ 259562306a36Sopenharmony_ci if (at - entries >= icount1) { 259662306a36Sopenharmony_ci frame->at = at - entries - icount1 + entries2; 259762306a36Sopenharmony_ci frame->entries = entries = entries2; 259862306a36Sopenharmony_ci swap(frame->bh, bh2); 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci dx_insert_block((frame - 1), hash2, newblock); 260162306a36Sopenharmony_ci dxtrace(dx_show_index("node", frame->entries)); 260262306a36Sopenharmony_ci dxtrace(dx_show_index("node", 260362306a36Sopenharmony_ci ((struct dx_node *) bh2->b_data)->entries)); 260462306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, bh2); 260562306a36Sopenharmony_ci if (err) 260662306a36Sopenharmony_ci goto journal_error; 260762306a36Sopenharmony_ci brelse (bh2); 260862306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, 260962306a36Sopenharmony_ci (frame - 1)->bh); 261062306a36Sopenharmony_ci if (err) 261162306a36Sopenharmony_ci goto journal_error; 261262306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, 261362306a36Sopenharmony_ci frame->bh); 261462306a36Sopenharmony_ci if (restart || err) 261562306a36Sopenharmony_ci goto journal_error; 261662306a36Sopenharmony_ci } else { 261762306a36Sopenharmony_ci struct dx_root *dxroot; 261862306a36Sopenharmony_ci memcpy((char *) entries2, (char *) entries, 261962306a36Sopenharmony_ci icount * sizeof(struct dx_entry)); 262062306a36Sopenharmony_ci dx_set_limit(entries2, dx_node_limit(dir)); 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci /* Set up root */ 262362306a36Sopenharmony_ci dx_set_count(entries, 1); 262462306a36Sopenharmony_ci dx_set_block(entries + 0, newblock); 262562306a36Sopenharmony_ci dxroot = (struct dx_root *)frames[0].bh->b_data; 262662306a36Sopenharmony_ci dxroot->info.indirect_levels += 1; 262762306a36Sopenharmony_ci dxtrace(printk(KERN_DEBUG 262862306a36Sopenharmony_ci "Creating %d level index...\n", 262962306a36Sopenharmony_ci dxroot->info.indirect_levels)); 263062306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); 263162306a36Sopenharmony_ci if (err) 263262306a36Sopenharmony_ci goto journal_error; 263362306a36Sopenharmony_ci err = ext4_handle_dirty_dx_node(handle, dir, bh2); 263462306a36Sopenharmony_ci brelse(bh2); 263562306a36Sopenharmony_ci restart = 1; 263662306a36Sopenharmony_ci goto journal_error; 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci de = do_split(handle, dir, &bh, frame, &fname->hinfo); 264062306a36Sopenharmony_ci if (IS_ERR(de)) { 264162306a36Sopenharmony_ci err = PTR_ERR(de); 264262306a36Sopenharmony_ci goto cleanup; 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci err = add_dirent_to_buf(handle, fname, dir, inode, de, bh); 264562306a36Sopenharmony_ci goto cleanup; 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_cijournal_error: 264862306a36Sopenharmony_ci ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ 264962306a36Sopenharmony_cicleanup: 265062306a36Sopenharmony_ci brelse(bh); 265162306a36Sopenharmony_ci dx_release(frames); 265262306a36Sopenharmony_ci /* @restart is true means htree-path has been changed, we need to 265362306a36Sopenharmony_ci * repeat dx_probe() to find out valid htree-path 265462306a36Sopenharmony_ci */ 265562306a36Sopenharmony_ci if (restart && err == 0) 265662306a36Sopenharmony_ci goto again; 265762306a36Sopenharmony_ci return err; 265862306a36Sopenharmony_ci} 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci/* 266162306a36Sopenharmony_ci * ext4_generic_delete_entry deletes a directory entry by merging it 266262306a36Sopenharmony_ci * with the previous entry 266362306a36Sopenharmony_ci */ 266462306a36Sopenharmony_ciint ext4_generic_delete_entry(struct inode *dir, 266562306a36Sopenharmony_ci struct ext4_dir_entry_2 *de_del, 266662306a36Sopenharmony_ci struct buffer_head *bh, 266762306a36Sopenharmony_ci void *entry_buf, 266862306a36Sopenharmony_ci int buf_size, 266962306a36Sopenharmony_ci int csum_size) 267062306a36Sopenharmony_ci{ 267162306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, *pde; 267262306a36Sopenharmony_ci unsigned int blocksize = dir->i_sb->s_blocksize; 267362306a36Sopenharmony_ci int i; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci i = 0; 267662306a36Sopenharmony_ci pde = NULL; 267762306a36Sopenharmony_ci de = entry_buf; 267862306a36Sopenharmony_ci while (i < buf_size - csum_size) { 267962306a36Sopenharmony_ci if (ext4_check_dir_entry(dir, NULL, de, bh, 268062306a36Sopenharmony_ci entry_buf, buf_size, i)) 268162306a36Sopenharmony_ci return -EFSCORRUPTED; 268262306a36Sopenharmony_ci if (de == de_del) { 268362306a36Sopenharmony_ci if (pde) { 268462306a36Sopenharmony_ci pde->rec_len = ext4_rec_len_to_disk( 268562306a36Sopenharmony_ci ext4_rec_len_from_disk(pde->rec_len, 268662306a36Sopenharmony_ci blocksize) + 268762306a36Sopenharmony_ci ext4_rec_len_from_disk(de->rec_len, 268862306a36Sopenharmony_ci blocksize), 268962306a36Sopenharmony_ci blocksize); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci /* wipe entire dir_entry */ 269262306a36Sopenharmony_ci memset(de, 0, ext4_rec_len_from_disk(de->rec_len, 269362306a36Sopenharmony_ci blocksize)); 269462306a36Sopenharmony_ci } else { 269562306a36Sopenharmony_ci /* wipe dir_entry excluding the rec_len field */ 269662306a36Sopenharmony_ci de->inode = 0; 269762306a36Sopenharmony_ci memset(&de->name_len, 0, 269862306a36Sopenharmony_ci ext4_rec_len_from_disk(de->rec_len, 269962306a36Sopenharmony_ci blocksize) - 270062306a36Sopenharmony_ci offsetof(struct ext4_dir_entry_2, 270162306a36Sopenharmony_ci name_len)); 270262306a36Sopenharmony_ci } 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_ci inode_inc_iversion(dir); 270562306a36Sopenharmony_ci return 0; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci i += ext4_rec_len_from_disk(de->rec_len, blocksize); 270862306a36Sopenharmony_ci pde = de; 270962306a36Sopenharmony_ci de = ext4_next_entry(de, blocksize); 271062306a36Sopenharmony_ci } 271162306a36Sopenharmony_ci return -ENOENT; 271262306a36Sopenharmony_ci} 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_cistatic int ext4_delete_entry(handle_t *handle, 271562306a36Sopenharmony_ci struct inode *dir, 271662306a36Sopenharmony_ci struct ext4_dir_entry_2 *de_del, 271762306a36Sopenharmony_ci struct buffer_head *bh) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci int err, csum_size = 0; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (ext4_has_inline_data(dir)) { 272262306a36Sopenharmony_ci int has_inline_data = 1; 272362306a36Sopenharmony_ci err = ext4_delete_inline_entry(handle, dir, de_del, bh, 272462306a36Sopenharmony_ci &has_inline_data); 272562306a36Sopenharmony_ci if (has_inline_data) 272662306a36Sopenharmony_ci return err; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 273062306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 273362306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, dir->i_sb, bh, 273462306a36Sopenharmony_ci EXT4_JTR_NONE); 273562306a36Sopenharmony_ci if (unlikely(err)) 273662306a36Sopenharmony_ci goto out; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci err = ext4_generic_delete_entry(dir, de_del, bh, bh->b_data, 273962306a36Sopenharmony_ci dir->i_sb->s_blocksize, csum_size); 274062306a36Sopenharmony_ci if (err) 274162306a36Sopenharmony_ci goto out; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 274462306a36Sopenharmony_ci err = ext4_handle_dirty_dirblock(handle, dir, bh); 274562306a36Sopenharmony_ci if (unlikely(err)) 274662306a36Sopenharmony_ci goto out; 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci return 0; 274962306a36Sopenharmony_ciout: 275062306a36Sopenharmony_ci if (err != -ENOENT) 275162306a36Sopenharmony_ci ext4_std_error(dir->i_sb, err); 275262306a36Sopenharmony_ci return err; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci/* 275662306a36Sopenharmony_ci * Set directory link count to 1 if nlinks > EXT4_LINK_MAX, or if nlinks == 2 275762306a36Sopenharmony_ci * since this indicates that nlinks count was previously 1 to avoid overflowing 275862306a36Sopenharmony_ci * the 16-bit i_links_count field on disk. Directories with i_nlink == 1 mean 275962306a36Sopenharmony_ci * that subdirectory link counts are not being maintained accurately. 276062306a36Sopenharmony_ci * 276162306a36Sopenharmony_ci * The caller has already checked for i_nlink overflow in case the DIR_LINK 276262306a36Sopenharmony_ci * feature is not enabled and returned -EMLINK. The is_dx() check is a proxy 276362306a36Sopenharmony_ci * for checking S_ISDIR(inode) (since the INODE_INDEX feature will not be set 276462306a36Sopenharmony_ci * on regular files) and to avoid creating huge/slow non-HTREE directories. 276562306a36Sopenharmony_ci */ 276662306a36Sopenharmony_cistatic void ext4_inc_count(struct inode *inode) 276762306a36Sopenharmony_ci{ 276862306a36Sopenharmony_ci inc_nlink(inode); 276962306a36Sopenharmony_ci if (is_dx(inode) && 277062306a36Sopenharmony_ci (inode->i_nlink > EXT4_LINK_MAX || inode->i_nlink == 2)) 277162306a36Sopenharmony_ci set_nlink(inode, 1); 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci/* 277562306a36Sopenharmony_ci * If a directory had nlink == 1, then we should let it be 1. This indicates 277662306a36Sopenharmony_ci * directory has >EXT4_LINK_MAX subdirs. 277762306a36Sopenharmony_ci */ 277862306a36Sopenharmony_cistatic void ext4_dec_count(struct inode *inode) 277962306a36Sopenharmony_ci{ 278062306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) 278162306a36Sopenharmony_ci drop_nlink(inode); 278262306a36Sopenharmony_ci} 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci/* 278662306a36Sopenharmony_ci * Add non-directory inode to a directory. On success, the inode reference is 278762306a36Sopenharmony_ci * consumed by dentry is instantiation. This is also indicated by clearing of 278862306a36Sopenharmony_ci * *inodep pointer. On failure, the caller is responsible for dropping the 278962306a36Sopenharmony_ci * inode reference in the safe context. 279062306a36Sopenharmony_ci */ 279162306a36Sopenharmony_cistatic int ext4_add_nondir(handle_t *handle, 279262306a36Sopenharmony_ci struct dentry *dentry, struct inode **inodep) 279362306a36Sopenharmony_ci{ 279462306a36Sopenharmony_ci struct inode *dir = d_inode(dentry->d_parent); 279562306a36Sopenharmony_ci struct inode *inode = *inodep; 279662306a36Sopenharmony_ci int err = ext4_add_entry(handle, dentry, inode); 279762306a36Sopenharmony_ci if (!err) { 279862306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 279962306a36Sopenharmony_ci if (IS_DIRSYNC(dir)) 280062306a36Sopenharmony_ci ext4_handle_sync(handle); 280162306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 280262306a36Sopenharmony_ci *inodep = NULL; 280362306a36Sopenharmony_ci return err; 280462306a36Sopenharmony_ci } 280562306a36Sopenharmony_ci drop_nlink(inode); 280662306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, inode); 280762306a36Sopenharmony_ci ext4_orphan_add(handle, inode); 280862306a36Sopenharmony_ci unlock_new_inode(inode); 280962306a36Sopenharmony_ci return err; 281062306a36Sopenharmony_ci} 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci/* 281362306a36Sopenharmony_ci * By the time this is called, we already have created 281462306a36Sopenharmony_ci * the directory cache entry for the new file, but it 281562306a36Sopenharmony_ci * is so far negative - it has no inode. 281662306a36Sopenharmony_ci * 281762306a36Sopenharmony_ci * If the create succeeds, we fill in the inode information 281862306a36Sopenharmony_ci * with d_instantiate(). 281962306a36Sopenharmony_ci */ 282062306a36Sopenharmony_cistatic int ext4_create(struct mnt_idmap *idmap, struct inode *dir, 282162306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool excl) 282262306a36Sopenharmony_ci{ 282362306a36Sopenharmony_ci handle_t *handle; 282462306a36Sopenharmony_ci struct inode *inode; 282562306a36Sopenharmony_ci int err, credits, retries = 0; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci err = dquot_initialize(dir); 282862306a36Sopenharmony_ci if (err) 282962306a36Sopenharmony_ci return err; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + 283262306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); 283362306a36Sopenharmony_ciretry: 283462306a36Sopenharmony_ci inode = ext4_new_inode_start_handle(idmap, dir, mode, &dentry->d_name, 283562306a36Sopenharmony_ci 0, NULL, EXT4_HT_DIR, credits); 283662306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 283762306a36Sopenharmony_ci err = PTR_ERR(inode); 283862306a36Sopenharmony_ci if (!IS_ERR(inode)) { 283962306a36Sopenharmony_ci inode->i_op = &ext4_file_inode_operations; 284062306a36Sopenharmony_ci inode->i_fop = &ext4_file_operations; 284162306a36Sopenharmony_ci ext4_set_aops(inode); 284262306a36Sopenharmony_ci err = ext4_add_nondir(handle, dentry, &inode); 284362306a36Sopenharmony_ci if (!err) 284462306a36Sopenharmony_ci ext4_fc_track_create(handle, dentry); 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_ci if (handle) 284762306a36Sopenharmony_ci ext4_journal_stop(handle); 284862306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(inode)) 284962306a36Sopenharmony_ci iput(inode); 285062306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 285162306a36Sopenharmony_ci goto retry; 285262306a36Sopenharmony_ci return err; 285362306a36Sopenharmony_ci} 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_cistatic int ext4_mknod(struct mnt_idmap *idmap, struct inode *dir, 285662306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t rdev) 285762306a36Sopenharmony_ci{ 285862306a36Sopenharmony_ci handle_t *handle; 285962306a36Sopenharmony_ci struct inode *inode; 286062306a36Sopenharmony_ci int err, credits, retries = 0; 286162306a36Sopenharmony_ci 286262306a36Sopenharmony_ci err = dquot_initialize(dir); 286362306a36Sopenharmony_ci if (err) 286462306a36Sopenharmony_ci return err; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_ci credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + 286762306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); 286862306a36Sopenharmony_ciretry: 286962306a36Sopenharmony_ci inode = ext4_new_inode_start_handle(idmap, dir, mode, &dentry->d_name, 287062306a36Sopenharmony_ci 0, NULL, EXT4_HT_DIR, credits); 287162306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 287262306a36Sopenharmony_ci err = PTR_ERR(inode); 287362306a36Sopenharmony_ci if (!IS_ERR(inode)) { 287462306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 287562306a36Sopenharmony_ci inode->i_op = &ext4_special_inode_operations; 287662306a36Sopenharmony_ci err = ext4_add_nondir(handle, dentry, &inode); 287762306a36Sopenharmony_ci if (!err) 287862306a36Sopenharmony_ci ext4_fc_track_create(handle, dentry); 287962306a36Sopenharmony_ci } 288062306a36Sopenharmony_ci if (handle) 288162306a36Sopenharmony_ci ext4_journal_stop(handle); 288262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(inode)) 288362306a36Sopenharmony_ci iput(inode); 288462306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 288562306a36Sopenharmony_ci goto retry; 288662306a36Sopenharmony_ci return err; 288762306a36Sopenharmony_ci} 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_cistatic int ext4_tmpfile(struct mnt_idmap *idmap, struct inode *dir, 289062306a36Sopenharmony_ci struct file *file, umode_t mode) 289162306a36Sopenharmony_ci{ 289262306a36Sopenharmony_ci handle_t *handle; 289362306a36Sopenharmony_ci struct inode *inode; 289462306a36Sopenharmony_ci int err, retries = 0; 289562306a36Sopenharmony_ci 289662306a36Sopenharmony_ci err = dquot_initialize(dir); 289762306a36Sopenharmony_ci if (err) 289862306a36Sopenharmony_ci return err; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ciretry: 290162306a36Sopenharmony_ci inode = ext4_new_inode_start_handle(idmap, dir, mode, 290262306a36Sopenharmony_ci NULL, 0, NULL, 290362306a36Sopenharmony_ci EXT4_HT_DIR, 290462306a36Sopenharmony_ci EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + 290562306a36Sopenharmony_ci 4 + EXT4_XATTR_TRANS_BLOCKS); 290662306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 290762306a36Sopenharmony_ci err = PTR_ERR(inode); 290862306a36Sopenharmony_ci if (!IS_ERR(inode)) { 290962306a36Sopenharmony_ci inode->i_op = &ext4_file_inode_operations; 291062306a36Sopenharmony_ci inode->i_fop = &ext4_file_operations; 291162306a36Sopenharmony_ci ext4_set_aops(inode); 291262306a36Sopenharmony_ci d_tmpfile(file, inode); 291362306a36Sopenharmony_ci err = ext4_orphan_add(handle, inode); 291462306a36Sopenharmony_ci if (err) 291562306a36Sopenharmony_ci goto err_unlock_inode; 291662306a36Sopenharmony_ci mark_inode_dirty(inode); 291762306a36Sopenharmony_ci unlock_new_inode(inode); 291862306a36Sopenharmony_ci } 291962306a36Sopenharmony_ci if (handle) 292062306a36Sopenharmony_ci ext4_journal_stop(handle); 292162306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 292262306a36Sopenharmony_ci goto retry; 292362306a36Sopenharmony_ci return finish_open_simple(file, err); 292462306a36Sopenharmony_cierr_unlock_inode: 292562306a36Sopenharmony_ci ext4_journal_stop(handle); 292662306a36Sopenharmony_ci unlock_new_inode(inode); 292762306a36Sopenharmony_ci return err; 292862306a36Sopenharmony_ci} 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_cistruct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, 293162306a36Sopenharmony_ci struct ext4_dir_entry_2 *de, 293262306a36Sopenharmony_ci int blocksize, int csum_size, 293362306a36Sopenharmony_ci unsigned int parent_ino, int dotdot_real_len) 293462306a36Sopenharmony_ci{ 293562306a36Sopenharmony_ci de->inode = cpu_to_le32(inode->i_ino); 293662306a36Sopenharmony_ci de->name_len = 1; 293762306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(ext4_dir_rec_len(de->name_len, NULL), 293862306a36Sopenharmony_ci blocksize); 293962306a36Sopenharmony_ci strcpy(de->name, "."); 294062306a36Sopenharmony_ci ext4_set_de_type(inode->i_sb, de, S_IFDIR); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci de = ext4_next_entry(de, blocksize); 294362306a36Sopenharmony_ci de->inode = cpu_to_le32(parent_ino); 294462306a36Sopenharmony_ci de->name_len = 2; 294562306a36Sopenharmony_ci if (!dotdot_real_len) 294662306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk(blocksize - 294762306a36Sopenharmony_ci (csum_size + ext4_dir_rec_len(1, NULL)), 294862306a36Sopenharmony_ci blocksize); 294962306a36Sopenharmony_ci else 295062306a36Sopenharmony_ci de->rec_len = ext4_rec_len_to_disk( 295162306a36Sopenharmony_ci ext4_dir_rec_len(de->name_len, NULL), 295262306a36Sopenharmony_ci blocksize); 295362306a36Sopenharmony_ci strcpy(de->name, ".."); 295462306a36Sopenharmony_ci ext4_set_de_type(inode->i_sb, de, S_IFDIR); 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci return ext4_next_entry(de, blocksize); 295762306a36Sopenharmony_ci} 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ciint ext4_init_new_dir(handle_t *handle, struct inode *dir, 296062306a36Sopenharmony_ci struct inode *inode) 296162306a36Sopenharmony_ci{ 296262306a36Sopenharmony_ci struct buffer_head *dir_block = NULL; 296362306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 296462306a36Sopenharmony_ci ext4_lblk_t block = 0; 296562306a36Sopenharmony_ci unsigned int blocksize = dir->i_sb->s_blocksize; 296662306a36Sopenharmony_ci int csum_size = 0; 296762306a36Sopenharmony_ci int err; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci if (ext4_has_metadata_csum(dir->i_sb)) 297062306a36Sopenharmony_ci csum_size = sizeof(struct ext4_dir_entry_tail); 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { 297362306a36Sopenharmony_ci err = ext4_try_create_inline_dir(handle, dir, inode); 297462306a36Sopenharmony_ci if (err < 0 && err != -ENOSPC) 297562306a36Sopenharmony_ci goto out; 297662306a36Sopenharmony_ci if (!err) 297762306a36Sopenharmony_ci goto out; 297862306a36Sopenharmony_ci } 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci inode->i_size = 0; 298162306a36Sopenharmony_ci dir_block = ext4_append(handle, inode, &block); 298262306a36Sopenharmony_ci if (IS_ERR(dir_block)) 298362306a36Sopenharmony_ci return PTR_ERR(dir_block); 298462306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *)dir_block->b_data; 298562306a36Sopenharmony_ci ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); 298662306a36Sopenharmony_ci set_nlink(inode, 2); 298762306a36Sopenharmony_ci if (csum_size) 298862306a36Sopenharmony_ci ext4_initialize_dirent_tail(dir_block, blocksize); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); 299162306a36Sopenharmony_ci err = ext4_handle_dirty_dirblock(handle, inode, dir_block); 299262306a36Sopenharmony_ci if (err) 299362306a36Sopenharmony_ci goto out; 299462306a36Sopenharmony_ci set_buffer_verified(dir_block); 299562306a36Sopenharmony_ciout: 299662306a36Sopenharmony_ci brelse(dir_block); 299762306a36Sopenharmony_ci return err; 299862306a36Sopenharmony_ci} 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_cistatic int ext4_mkdir(struct mnt_idmap *idmap, struct inode *dir, 300162306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 300262306a36Sopenharmony_ci{ 300362306a36Sopenharmony_ci handle_t *handle; 300462306a36Sopenharmony_ci struct inode *inode; 300562306a36Sopenharmony_ci int err, err2 = 0, credits, retries = 0; 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci if (EXT4_DIR_LINK_MAX(dir)) 300862306a36Sopenharmony_ci return -EMLINK; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci err = dquot_initialize(dir); 301162306a36Sopenharmony_ci if (err) 301262306a36Sopenharmony_ci return err; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + 301562306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); 301662306a36Sopenharmony_ciretry: 301762306a36Sopenharmony_ci inode = ext4_new_inode_start_handle(idmap, dir, S_IFDIR | mode, 301862306a36Sopenharmony_ci &dentry->d_name, 301962306a36Sopenharmony_ci 0, NULL, EXT4_HT_DIR, credits); 302062306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 302162306a36Sopenharmony_ci err = PTR_ERR(inode); 302262306a36Sopenharmony_ci if (IS_ERR(inode)) 302362306a36Sopenharmony_ci goto out_stop; 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci inode->i_op = &ext4_dir_inode_operations; 302662306a36Sopenharmony_ci inode->i_fop = &ext4_dir_operations; 302762306a36Sopenharmony_ci err = ext4_init_new_dir(handle, dir, inode); 302862306a36Sopenharmony_ci if (err) 302962306a36Sopenharmony_ci goto out_clear_inode; 303062306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 303162306a36Sopenharmony_ci if (!err) 303262306a36Sopenharmony_ci err = ext4_add_entry(handle, dentry, inode); 303362306a36Sopenharmony_ci if (err) { 303462306a36Sopenharmony_ciout_clear_inode: 303562306a36Sopenharmony_ci clear_nlink(inode); 303662306a36Sopenharmony_ci ext4_orphan_add(handle, inode); 303762306a36Sopenharmony_ci unlock_new_inode(inode); 303862306a36Sopenharmony_ci err2 = ext4_mark_inode_dirty(handle, inode); 303962306a36Sopenharmony_ci if (unlikely(err2)) 304062306a36Sopenharmony_ci err = err2; 304162306a36Sopenharmony_ci ext4_journal_stop(handle); 304262306a36Sopenharmony_ci iput(inode); 304362306a36Sopenharmony_ci goto out_retry; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci ext4_inc_count(dir); 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci ext4_update_dx_flag(dir); 304862306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, dir); 304962306a36Sopenharmony_ci if (err) 305062306a36Sopenharmony_ci goto out_clear_inode; 305162306a36Sopenharmony_ci d_instantiate_new(dentry, inode); 305262306a36Sopenharmony_ci ext4_fc_track_create(handle, dentry); 305362306a36Sopenharmony_ci if (IS_DIRSYNC(dir)) 305462306a36Sopenharmony_ci ext4_handle_sync(handle); 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ciout_stop: 305762306a36Sopenharmony_ci if (handle) 305862306a36Sopenharmony_ci ext4_journal_stop(handle); 305962306a36Sopenharmony_ciout_retry: 306062306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 306162306a36Sopenharmony_ci goto retry; 306262306a36Sopenharmony_ci return err; 306362306a36Sopenharmony_ci} 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci/* 306662306a36Sopenharmony_ci * routine to check that the specified directory is empty (for rmdir) 306762306a36Sopenharmony_ci */ 306862306a36Sopenharmony_cibool ext4_empty_dir(struct inode *inode) 306962306a36Sopenharmony_ci{ 307062306a36Sopenharmony_ci unsigned int offset; 307162306a36Sopenharmony_ci struct buffer_head *bh; 307262306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 307362306a36Sopenharmony_ci struct super_block *sb; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci if (ext4_has_inline_data(inode)) { 307662306a36Sopenharmony_ci int has_inline_data = 1; 307762306a36Sopenharmony_ci int ret; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci ret = empty_inline_dir(inode, &has_inline_data); 308062306a36Sopenharmony_ci if (has_inline_data) 308162306a36Sopenharmony_ci return ret; 308262306a36Sopenharmony_ci } 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci sb = inode->i_sb; 308562306a36Sopenharmony_ci if (inode->i_size < ext4_dir_rec_len(1, NULL) + 308662306a36Sopenharmony_ci ext4_dir_rec_len(2, NULL)) { 308762306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "invalid size"); 308862306a36Sopenharmony_ci return false; 308962306a36Sopenharmony_ci } 309062306a36Sopenharmony_ci /* The first directory block must not be a hole, 309162306a36Sopenharmony_ci * so treat it as DIRENT_HTREE 309262306a36Sopenharmony_ci */ 309362306a36Sopenharmony_ci bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE); 309462306a36Sopenharmony_ci if (IS_ERR(bh)) 309562306a36Sopenharmony_ci return false; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) bh->b_data; 309862306a36Sopenharmony_ci if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, 309962306a36Sopenharmony_ci 0) || 310062306a36Sopenharmony_ci le32_to_cpu(de->inode) != inode->i_ino || strcmp(".", de->name)) { 310162306a36Sopenharmony_ci ext4_warning_inode(inode, "directory missing '.'"); 310262306a36Sopenharmony_ci brelse(bh); 310362306a36Sopenharmony_ci return false; 310462306a36Sopenharmony_ci } 310562306a36Sopenharmony_ci offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); 310662306a36Sopenharmony_ci de = ext4_next_entry(de, sb->s_blocksize); 310762306a36Sopenharmony_ci if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, bh->b_size, 310862306a36Sopenharmony_ci offset) || 310962306a36Sopenharmony_ci le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { 311062306a36Sopenharmony_ci ext4_warning_inode(inode, "directory missing '..'"); 311162306a36Sopenharmony_ci brelse(bh); 311262306a36Sopenharmony_ci return false; 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); 311562306a36Sopenharmony_ci while (offset < inode->i_size) { 311662306a36Sopenharmony_ci if (!(offset & (sb->s_blocksize - 1))) { 311762306a36Sopenharmony_ci unsigned int lblock; 311862306a36Sopenharmony_ci brelse(bh); 311962306a36Sopenharmony_ci lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb); 312062306a36Sopenharmony_ci bh = ext4_read_dirblock(inode, lblock, EITHER); 312162306a36Sopenharmony_ci if (bh == NULL) { 312262306a36Sopenharmony_ci offset += sb->s_blocksize; 312362306a36Sopenharmony_ci continue; 312462306a36Sopenharmony_ci } 312562306a36Sopenharmony_ci if (IS_ERR(bh)) 312662306a36Sopenharmony_ci return false; 312762306a36Sopenharmony_ci } 312862306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) (bh->b_data + 312962306a36Sopenharmony_ci (offset & (sb->s_blocksize - 1))); 313062306a36Sopenharmony_ci if (ext4_check_dir_entry(inode, NULL, de, bh, 313162306a36Sopenharmony_ci bh->b_data, bh->b_size, offset) || 313262306a36Sopenharmony_ci le32_to_cpu(de->inode)) { 313362306a36Sopenharmony_ci brelse(bh); 313462306a36Sopenharmony_ci return false; 313562306a36Sopenharmony_ci } 313662306a36Sopenharmony_ci offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci brelse(bh); 313962306a36Sopenharmony_ci return true; 314062306a36Sopenharmony_ci} 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_cistatic int ext4_rmdir(struct inode *dir, struct dentry *dentry) 314362306a36Sopenharmony_ci{ 314462306a36Sopenharmony_ci int retval; 314562306a36Sopenharmony_ci struct inode *inode; 314662306a36Sopenharmony_ci struct buffer_head *bh; 314762306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 314862306a36Sopenharmony_ci handle_t *handle = NULL; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci if (unlikely(ext4_forced_shutdown(dir->i_sb))) 315162306a36Sopenharmony_ci return -EIO; 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci /* Initialize quotas before so that eventual writes go in 315462306a36Sopenharmony_ci * separate transaction */ 315562306a36Sopenharmony_ci retval = dquot_initialize(dir); 315662306a36Sopenharmony_ci if (retval) 315762306a36Sopenharmony_ci return retval; 315862306a36Sopenharmony_ci retval = dquot_initialize(d_inode(dentry)); 315962306a36Sopenharmony_ci if (retval) 316062306a36Sopenharmony_ci return retval; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci retval = -ENOENT; 316362306a36Sopenharmony_ci bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); 316462306a36Sopenharmony_ci if (IS_ERR(bh)) 316562306a36Sopenharmony_ci return PTR_ERR(bh); 316662306a36Sopenharmony_ci if (!bh) 316762306a36Sopenharmony_ci goto end_rmdir; 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci inode = d_inode(dentry); 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci retval = -EFSCORRUPTED; 317262306a36Sopenharmony_ci if (le32_to_cpu(de->inode) != inode->i_ino) 317362306a36Sopenharmony_ci goto end_rmdir; 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci retval = -ENOTEMPTY; 317662306a36Sopenharmony_ci if (!ext4_empty_dir(inode)) 317762306a36Sopenharmony_ci goto end_rmdir; 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_ci handle = ext4_journal_start(dir, EXT4_HT_DIR, 318062306a36Sopenharmony_ci EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); 318162306a36Sopenharmony_ci if (IS_ERR(handle)) { 318262306a36Sopenharmony_ci retval = PTR_ERR(handle); 318362306a36Sopenharmony_ci handle = NULL; 318462306a36Sopenharmony_ci goto end_rmdir; 318562306a36Sopenharmony_ci } 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci if (IS_DIRSYNC(dir)) 318862306a36Sopenharmony_ci ext4_handle_sync(handle); 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci retval = ext4_delete_entry(handle, dir, de, bh); 319162306a36Sopenharmony_ci if (retval) 319262306a36Sopenharmony_ci goto end_rmdir; 319362306a36Sopenharmony_ci if (!EXT4_DIR_LINK_EMPTY(inode)) 319462306a36Sopenharmony_ci ext4_warning_inode(inode, 319562306a36Sopenharmony_ci "empty directory '%.*s' has too many links (%u)", 319662306a36Sopenharmony_ci dentry->d_name.len, dentry->d_name.name, 319762306a36Sopenharmony_ci inode->i_nlink); 319862306a36Sopenharmony_ci inode_inc_iversion(inode); 319962306a36Sopenharmony_ci clear_nlink(inode); 320062306a36Sopenharmony_ci /* There's no need to set i_disksize: the fact that i_nlink is 320162306a36Sopenharmony_ci * zero will ensure that the right thing happens during any 320262306a36Sopenharmony_ci * recovery. */ 320362306a36Sopenharmony_ci inode->i_size = 0; 320462306a36Sopenharmony_ci ext4_orphan_add(handle, inode); 320562306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_current(dir); 320662306a36Sopenharmony_ci inode_set_ctime_current(inode); 320762306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, inode); 320862306a36Sopenharmony_ci if (retval) 320962306a36Sopenharmony_ci goto end_rmdir; 321062306a36Sopenharmony_ci ext4_dec_count(dir); 321162306a36Sopenharmony_ci ext4_update_dx_flag(dir); 321262306a36Sopenharmony_ci ext4_fc_track_unlink(handle, dentry); 321362306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, dir); 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 321662306a36Sopenharmony_ci /* VFS negative dentries are incompatible with Encoding and 321762306a36Sopenharmony_ci * Case-insensitiveness. Eventually we'll want avoid 321862306a36Sopenharmony_ci * invalidating the dentries here, alongside with returning the 321962306a36Sopenharmony_ci * negative dentries at ext4_lookup(), when it is better 322062306a36Sopenharmony_ci * supported by the VFS for the CI case. 322162306a36Sopenharmony_ci */ 322262306a36Sopenharmony_ci if (IS_CASEFOLDED(dir)) 322362306a36Sopenharmony_ci d_invalidate(dentry); 322462306a36Sopenharmony_ci#endif 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_ciend_rmdir: 322762306a36Sopenharmony_ci brelse(bh); 322862306a36Sopenharmony_ci if (handle) 322962306a36Sopenharmony_ci ext4_journal_stop(handle); 323062306a36Sopenharmony_ci return retval; 323162306a36Sopenharmony_ci} 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ciint __ext4_unlink(struct inode *dir, const struct qstr *d_name, 323462306a36Sopenharmony_ci struct inode *inode, 323562306a36Sopenharmony_ci struct dentry *dentry /* NULL during fast_commit recovery */) 323662306a36Sopenharmony_ci{ 323762306a36Sopenharmony_ci int retval = -ENOENT; 323862306a36Sopenharmony_ci struct buffer_head *bh; 323962306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 324062306a36Sopenharmony_ci handle_t *handle; 324162306a36Sopenharmony_ci int skip_remove_dentry = 0; 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_ci /* 324462306a36Sopenharmony_ci * Keep this outside the transaction; it may have to set up the 324562306a36Sopenharmony_ci * directory's encryption key, which isn't GFP_NOFS-safe. 324662306a36Sopenharmony_ci */ 324762306a36Sopenharmony_ci bh = ext4_find_entry(dir, d_name, &de, NULL); 324862306a36Sopenharmony_ci if (IS_ERR(bh)) 324962306a36Sopenharmony_ci return PTR_ERR(bh); 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci if (!bh) 325262306a36Sopenharmony_ci return -ENOENT; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (le32_to_cpu(de->inode) != inode->i_ino) { 325562306a36Sopenharmony_ci /* 325662306a36Sopenharmony_ci * It's okay if we find dont find dentry which matches 325762306a36Sopenharmony_ci * the inode. That's because it might have gotten 325862306a36Sopenharmony_ci * renamed to a different inode number 325962306a36Sopenharmony_ci */ 326062306a36Sopenharmony_ci if (EXT4_SB(inode->i_sb)->s_mount_state & EXT4_FC_REPLAY) 326162306a36Sopenharmony_ci skip_remove_dentry = 1; 326262306a36Sopenharmony_ci else 326362306a36Sopenharmony_ci goto out_bh; 326462306a36Sopenharmony_ci } 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci handle = ext4_journal_start(dir, EXT4_HT_DIR, 326762306a36Sopenharmony_ci EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); 326862306a36Sopenharmony_ci if (IS_ERR(handle)) { 326962306a36Sopenharmony_ci retval = PTR_ERR(handle); 327062306a36Sopenharmony_ci goto out_bh; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci if (IS_DIRSYNC(dir)) 327462306a36Sopenharmony_ci ext4_handle_sync(handle); 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci if (!skip_remove_dentry) { 327762306a36Sopenharmony_ci retval = ext4_delete_entry(handle, dir, de, bh); 327862306a36Sopenharmony_ci if (retval) 327962306a36Sopenharmony_ci goto out_handle; 328062306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_current(dir); 328162306a36Sopenharmony_ci ext4_update_dx_flag(dir); 328262306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, dir); 328362306a36Sopenharmony_ci if (retval) 328462306a36Sopenharmony_ci goto out_handle; 328562306a36Sopenharmony_ci } else { 328662306a36Sopenharmony_ci retval = 0; 328762306a36Sopenharmony_ci } 328862306a36Sopenharmony_ci if (inode->i_nlink == 0) 328962306a36Sopenharmony_ci ext4_warning_inode(inode, "Deleting file '%.*s' with no links", 329062306a36Sopenharmony_ci d_name->len, d_name->name); 329162306a36Sopenharmony_ci else 329262306a36Sopenharmony_ci drop_nlink(inode); 329362306a36Sopenharmony_ci if (!inode->i_nlink) 329462306a36Sopenharmony_ci ext4_orphan_add(handle, inode); 329562306a36Sopenharmony_ci inode_set_ctime_current(inode); 329662306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, inode); 329762306a36Sopenharmony_ci if (dentry && !retval) 329862306a36Sopenharmony_ci ext4_fc_track_unlink(handle, dentry); 329962306a36Sopenharmony_ciout_handle: 330062306a36Sopenharmony_ci ext4_journal_stop(handle); 330162306a36Sopenharmony_ciout_bh: 330262306a36Sopenharmony_ci brelse(bh); 330362306a36Sopenharmony_ci return retval; 330462306a36Sopenharmony_ci} 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_cistatic int ext4_unlink(struct inode *dir, struct dentry *dentry) 330762306a36Sopenharmony_ci{ 330862306a36Sopenharmony_ci int retval; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci if (unlikely(ext4_forced_shutdown(dir->i_sb))) 331162306a36Sopenharmony_ci return -EIO; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci trace_ext4_unlink_enter(dir, dentry); 331462306a36Sopenharmony_ci /* 331562306a36Sopenharmony_ci * Initialize quotas before so that eventual writes go 331662306a36Sopenharmony_ci * in separate transaction 331762306a36Sopenharmony_ci */ 331862306a36Sopenharmony_ci retval = dquot_initialize(dir); 331962306a36Sopenharmony_ci if (retval) 332062306a36Sopenharmony_ci goto out_trace; 332162306a36Sopenharmony_ci retval = dquot_initialize(d_inode(dentry)); 332262306a36Sopenharmony_ci if (retval) 332362306a36Sopenharmony_ci goto out_trace; 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci retval = __ext4_unlink(dir, &dentry->d_name, d_inode(dentry), dentry); 332662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_UNICODE) 332762306a36Sopenharmony_ci /* VFS negative dentries are incompatible with Encoding and 332862306a36Sopenharmony_ci * Case-insensitiveness. Eventually we'll want avoid 332962306a36Sopenharmony_ci * invalidating the dentries here, alongside with returning the 333062306a36Sopenharmony_ci * negative dentries at ext4_lookup(), when it is better 333162306a36Sopenharmony_ci * supported by the VFS for the CI case. 333262306a36Sopenharmony_ci */ 333362306a36Sopenharmony_ci if (IS_CASEFOLDED(dir)) 333462306a36Sopenharmony_ci d_invalidate(dentry); 333562306a36Sopenharmony_ci#endif 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ciout_trace: 333862306a36Sopenharmony_ci trace_ext4_unlink_exit(dentry, retval); 333962306a36Sopenharmony_ci return retval; 334062306a36Sopenharmony_ci} 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_cistatic int ext4_init_symlink_block(handle_t *handle, struct inode *inode, 334362306a36Sopenharmony_ci struct fscrypt_str *disk_link) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci struct buffer_head *bh; 334662306a36Sopenharmony_ci char *kaddr; 334762306a36Sopenharmony_ci int err = 0; 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci bh = ext4_bread(handle, inode, 0, EXT4_GET_BLOCKS_CREATE); 335062306a36Sopenharmony_ci if (IS_ERR(bh)) 335162306a36Sopenharmony_ci return PTR_ERR(bh); 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci BUFFER_TRACE(bh, "get_write_access"); 335462306a36Sopenharmony_ci err = ext4_journal_get_write_access(handle, inode->i_sb, bh, EXT4_JTR_NONE); 335562306a36Sopenharmony_ci if (err) 335662306a36Sopenharmony_ci goto out; 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci kaddr = (char *)bh->b_data; 335962306a36Sopenharmony_ci memcpy(kaddr, disk_link->name, disk_link->len); 336062306a36Sopenharmony_ci inode->i_size = disk_link->len - 1; 336162306a36Sopenharmony_ci EXT4_I(inode)->i_disksize = inode->i_size; 336262306a36Sopenharmony_ci err = ext4_handle_dirty_metadata(handle, inode, bh); 336362306a36Sopenharmony_ciout: 336462306a36Sopenharmony_ci brelse(bh); 336562306a36Sopenharmony_ci return err; 336662306a36Sopenharmony_ci} 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_cistatic int ext4_symlink(struct mnt_idmap *idmap, struct inode *dir, 336962306a36Sopenharmony_ci struct dentry *dentry, const char *symname) 337062306a36Sopenharmony_ci{ 337162306a36Sopenharmony_ci handle_t *handle; 337262306a36Sopenharmony_ci struct inode *inode; 337362306a36Sopenharmony_ci int err, len = strlen(symname); 337462306a36Sopenharmony_ci int credits; 337562306a36Sopenharmony_ci struct fscrypt_str disk_link; 337662306a36Sopenharmony_ci int retries = 0; 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci if (unlikely(ext4_forced_shutdown(dir->i_sb))) 337962306a36Sopenharmony_ci return -EIO; 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ci err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, 338262306a36Sopenharmony_ci &disk_link); 338362306a36Sopenharmony_ci if (err) 338462306a36Sopenharmony_ci return err; 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci err = dquot_initialize(dir); 338762306a36Sopenharmony_ci if (err) 338862306a36Sopenharmony_ci return err; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci /* 339162306a36Sopenharmony_ci * EXT4_INDEX_EXTRA_TRANS_BLOCKS for addition of entry into the 339262306a36Sopenharmony_ci * directory. +3 for inode, inode bitmap, group descriptor allocation. 339362306a36Sopenharmony_ci * EXT4_DATA_TRANS_BLOCKS for the data block allocation and 339462306a36Sopenharmony_ci * modification. 339562306a36Sopenharmony_ci */ 339662306a36Sopenharmony_ci credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + 339762306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3; 339862306a36Sopenharmony_ciretry: 339962306a36Sopenharmony_ci inode = ext4_new_inode_start_handle(idmap, dir, S_IFLNK|S_IRWXUGO, 340062306a36Sopenharmony_ci &dentry->d_name, 0, NULL, 340162306a36Sopenharmony_ci EXT4_HT_DIR, credits); 340262306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 340362306a36Sopenharmony_ci if (IS_ERR(inode)) { 340462306a36Sopenharmony_ci if (handle) 340562306a36Sopenharmony_ci ext4_journal_stop(handle); 340662306a36Sopenharmony_ci err = PTR_ERR(inode); 340762306a36Sopenharmony_ci goto out_retry; 340862306a36Sopenharmony_ci } 340962306a36Sopenharmony_ci 341062306a36Sopenharmony_ci if (IS_ENCRYPTED(inode)) { 341162306a36Sopenharmony_ci err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); 341262306a36Sopenharmony_ci if (err) 341362306a36Sopenharmony_ci goto err_drop_inode; 341462306a36Sopenharmony_ci inode->i_op = &ext4_encrypted_symlink_inode_operations; 341562306a36Sopenharmony_ci } else { 341662306a36Sopenharmony_ci if ((disk_link.len > EXT4_N_BLOCKS * 4)) { 341762306a36Sopenharmony_ci inode->i_op = &ext4_symlink_inode_operations; 341862306a36Sopenharmony_ci } else { 341962306a36Sopenharmony_ci inode->i_op = &ext4_fast_symlink_inode_operations; 342062306a36Sopenharmony_ci inode->i_link = (char *)&EXT4_I(inode)->i_data; 342162306a36Sopenharmony_ci } 342262306a36Sopenharmony_ci } 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci if ((disk_link.len > EXT4_N_BLOCKS * 4)) { 342562306a36Sopenharmony_ci /* alloc symlink block and fill it */ 342662306a36Sopenharmony_ci err = ext4_init_symlink_block(handle, inode, &disk_link); 342762306a36Sopenharmony_ci if (err) 342862306a36Sopenharmony_ci goto err_drop_inode; 342962306a36Sopenharmony_ci } else { 343062306a36Sopenharmony_ci /* clear the extent format for fast symlink */ 343162306a36Sopenharmony_ci ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); 343262306a36Sopenharmony_ci memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name, 343362306a36Sopenharmony_ci disk_link.len); 343462306a36Sopenharmony_ci inode->i_size = disk_link.len - 1; 343562306a36Sopenharmony_ci EXT4_I(inode)->i_disksize = inode->i_size; 343662306a36Sopenharmony_ci } 343762306a36Sopenharmony_ci err = ext4_add_nondir(handle, dentry, &inode); 343862306a36Sopenharmony_ci if (handle) 343962306a36Sopenharmony_ci ext4_journal_stop(handle); 344062306a36Sopenharmony_ci iput(inode); 344162306a36Sopenharmony_ci goto out_retry; 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_cierr_drop_inode: 344462306a36Sopenharmony_ci clear_nlink(inode); 344562306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, inode); 344662306a36Sopenharmony_ci ext4_orphan_add(handle, inode); 344762306a36Sopenharmony_ci unlock_new_inode(inode); 344862306a36Sopenharmony_ci if (handle) 344962306a36Sopenharmony_ci ext4_journal_stop(handle); 345062306a36Sopenharmony_ci iput(inode); 345162306a36Sopenharmony_ciout_retry: 345262306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 345362306a36Sopenharmony_ci goto retry; 345462306a36Sopenharmony_ci if (disk_link.name != (unsigned char *)symname) 345562306a36Sopenharmony_ci kfree(disk_link.name); 345662306a36Sopenharmony_ci return err; 345762306a36Sopenharmony_ci} 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ciint __ext4_link(struct inode *dir, struct inode *inode, struct dentry *dentry) 346062306a36Sopenharmony_ci{ 346162306a36Sopenharmony_ci handle_t *handle; 346262306a36Sopenharmony_ci int err, retries = 0; 346362306a36Sopenharmony_ciretry: 346462306a36Sopenharmony_ci handle = ext4_journal_start(dir, EXT4_HT_DIR, 346562306a36Sopenharmony_ci (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + 346662306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1); 346762306a36Sopenharmony_ci if (IS_ERR(handle)) 346862306a36Sopenharmony_ci return PTR_ERR(handle); 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci if (IS_DIRSYNC(dir)) 347162306a36Sopenharmony_ci ext4_handle_sync(handle); 347262306a36Sopenharmony_ci 347362306a36Sopenharmony_ci inode_set_ctime_current(inode); 347462306a36Sopenharmony_ci ext4_inc_count(inode); 347562306a36Sopenharmony_ci ihold(inode); 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci err = ext4_add_entry(handle, dentry, inode); 347862306a36Sopenharmony_ci if (!err) { 347962306a36Sopenharmony_ci err = ext4_mark_inode_dirty(handle, inode); 348062306a36Sopenharmony_ci /* this can happen only for tmpfile being 348162306a36Sopenharmony_ci * linked the first time 348262306a36Sopenharmony_ci */ 348362306a36Sopenharmony_ci if (inode->i_nlink == 1) 348462306a36Sopenharmony_ci ext4_orphan_del(handle, inode); 348562306a36Sopenharmony_ci d_instantiate(dentry, inode); 348662306a36Sopenharmony_ci ext4_fc_track_link(handle, dentry); 348762306a36Sopenharmony_ci } else { 348862306a36Sopenharmony_ci drop_nlink(inode); 348962306a36Sopenharmony_ci iput(inode); 349062306a36Sopenharmony_ci } 349162306a36Sopenharmony_ci ext4_journal_stop(handle); 349262306a36Sopenharmony_ci if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) 349362306a36Sopenharmony_ci goto retry; 349462306a36Sopenharmony_ci return err; 349562306a36Sopenharmony_ci} 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_cistatic int ext4_link(struct dentry *old_dentry, 349862306a36Sopenharmony_ci struct inode *dir, struct dentry *dentry) 349962306a36Sopenharmony_ci{ 350062306a36Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 350162306a36Sopenharmony_ci int err; 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci if (inode->i_nlink >= EXT4_LINK_MAX) 350462306a36Sopenharmony_ci return -EMLINK; 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_ci err = fscrypt_prepare_link(old_dentry, dir, dentry); 350762306a36Sopenharmony_ci if (err) 350862306a36Sopenharmony_ci return err; 350962306a36Sopenharmony_ci 351062306a36Sopenharmony_ci if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) && 351162306a36Sopenharmony_ci (!projid_eq(EXT4_I(dir)->i_projid, 351262306a36Sopenharmony_ci EXT4_I(old_dentry->d_inode)->i_projid))) 351362306a36Sopenharmony_ci return -EXDEV; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci err = dquot_initialize(dir); 351662306a36Sopenharmony_ci if (err) 351762306a36Sopenharmony_ci return err; 351862306a36Sopenharmony_ci return __ext4_link(dir, inode, dentry); 351962306a36Sopenharmony_ci} 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci/* 352262306a36Sopenharmony_ci * Try to find buffer head where contains the parent block. 352362306a36Sopenharmony_ci * It should be the inode block if it is inlined or the 1st block 352462306a36Sopenharmony_ci * if it is a normal dir. 352562306a36Sopenharmony_ci */ 352662306a36Sopenharmony_cistatic struct buffer_head *ext4_get_first_dir_block(handle_t *handle, 352762306a36Sopenharmony_ci struct inode *inode, 352862306a36Sopenharmony_ci int *retval, 352962306a36Sopenharmony_ci struct ext4_dir_entry_2 **parent_de, 353062306a36Sopenharmony_ci int *inlined) 353162306a36Sopenharmony_ci{ 353262306a36Sopenharmony_ci struct buffer_head *bh; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci if (!ext4_has_inline_data(inode)) { 353562306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 353662306a36Sopenharmony_ci unsigned int offset; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci /* The first directory block must not be a hole, so 353962306a36Sopenharmony_ci * treat it as DIRENT_HTREE 354062306a36Sopenharmony_ci */ 354162306a36Sopenharmony_ci bh = ext4_read_dirblock(inode, 0, DIRENT_HTREE); 354262306a36Sopenharmony_ci if (IS_ERR(bh)) { 354362306a36Sopenharmony_ci *retval = PTR_ERR(bh); 354462306a36Sopenharmony_ci return NULL; 354562306a36Sopenharmony_ci } 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci de = (struct ext4_dir_entry_2 *) bh->b_data; 354862306a36Sopenharmony_ci if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, 354962306a36Sopenharmony_ci bh->b_size, 0) || 355062306a36Sopenharmony_ci le32_to_cpu(de->inode) != inode->i_ino || 355162306a36Sopenharmony_ci strcmp(".", de->name)) { 355262306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "directory missing '.'"); 355362306a36Sopenharmony_ci brelse(bh); 355462306a36Sopenharmony_ci *retval = -EFSCORRUPTED; 355562306a36Sopenharmony_ci return NULL; 355662306a36Sopenharmony_ci } 355762306a36Sopenharmony_ci offset = ext4_rec_len_from_disk(de->rec_len, 355862306a36Sopenharmony_ci inode->i_sb->s_blocksize); 355962306a36Sopenharmony_ci de = ext4_next_entry(de, inode->i_sb->s_blocksize); 356062306a36Sopenharmony_ci if (ext4_check_dir_entry(inode, NULL, de, bh, bh->b_data, 356162306a36Sopenharmony_ci bh->b_size, offset) || 356262306a36Sopenharmony_ci le32_to_cpu(de->inode) == 0 || strcmp("..", de->name)) { 356362306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "directory missing '..'"); 356462306a36Sopenharmony_ci brelse(bh); 356562306a36Sopenharmony_ci *retval = -EFSCORRUPTED; 356662306a36Sopenharmony_ci return NULL; 356762306a36Sopenharmony_ci } 356862306a36Sopenharmony_ci *parent_de = de; 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci return bh; 357162306a36Sopenharmony_ci } 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci *inlined = 1; 357462306a36Sopenharmony_ci return ext4_get_first_inline_block(inode, parent_de, retval); 357562306a36Sopenharmony_ci} 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_cistruct ext4_renament { 357862306a36Sopenharmony_ci struct inode *dir; 357962306a36Sopenharmony_ci struct dentry *dentry; 358062306a36Sopenharmony_ci struct inode *inode; 358162306a36Sopenharmony_ci bool is_dir; 358262306a36Sopenharmony_ci int dir_nlink_delta; 358362306a36Sopenharmony_ci 358462306a36Sopenharmony_ci /* entry for "dentry" */ 358562306a36Sopenharmony_ci struct buffer_head *bh; 358662306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 358762306a36Sopenharmony_ci int inlined; 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci /* entry for ".." in inode if it's a directory */ 359062306a36Sopenharmony_ci struct buffer_head *dir_bh; 359162306a36Sopenharmony_ci struct ext4_dir_entry_2 *parent_de; 359262306a36Sopenharmony_ci int dir_inlined; 359362306a36Sopenharmony_ci}; 359462306a36Sopenharmony_ci 359562306a36Sopenharmony_cistatic int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent) 359662306a36Sopenharmony_ci{ 359762306a36Sopenharmony_ci int retval; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode, 360062306a36Sopenharmony_ci &retval, &ent->parent_de, 360162306a36Sopenharmony_ci &ent->dir_inlined); 360262306a36Sopenharmony_ci if (!ent->dir_bh) 360362306a36Sopenharmony_ci return retval; 360462306a36Sopenharmony_ci if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino) 360562306a36Sopenharmony_ci return -EFSCORRUPTED; 360662306a36Sopenharmony_ci BUFFER_TRACE(ent->dir_bh, "get_write_access"); 360762306a36Sopenharmony_ci return ext4_journal_get_write_access(handle, ent->dir->i_sb, 360862306a36Sopenharmony_ci ent->dir_bh, EXT4_JTR_NONE); 360962306a36Sopenharmony_ci} 361062306a36Sopenharmony_ci 361162306a36Sopenharmony_cistatic int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent, 361262306a36Sopenharmony_ci unsigned dir_ino) 361362306a36Sopenharmony_ci{ 361462306a36Sopenharmony_ci int retval; 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci ent->parent_de->inode = cpu_to_le32(dir_ino); 361762306a36Sopenharmony_ci BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata"); 361862306a36Sopenharmony_ci if (!ent->dir_inlined) { 361962306a36Sopenharmony_ci if (is_dx(ent->inode)) { 362062306a36Sopenharmony_ci retval = ext4_handle_dirty_dx_node(handle, 362162306a36Sopenharmony_ci ent->inode, 362262306a36Sopenharmony_ci ent->dir_bh); 362362306a36Sopenharmony_ci } else { 362462306a36Sopenharmony_ci retval = ext4_handle_dirty_dirblock(handle, ent->inode, 362562306a36Sopenharmony_ci ent->dir_bh); 362662306a36Sopenharmony_ci } 362762306a36Sopenharmony_ci } else { 362862306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, ent->inode); 362962306a36Sopenharmony_ci } 363062306a36Sopenharmony_ci if (retval) { 363162306a36Sopenharmony_ci ext4_std_error(ent->dir->i_sb, retval); 363262306a36Sopenharmony_ci return retval; 363362306a36Sopenharmony_ci } 363462306a36Sopenharmony_ci return 0; 363562306a36Sopenharmony_ci} 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_cistatic int ext4_setent(handle_t *handle, struct ext4_renament *ent, 363862306a36Sopenharmony_ci unsigned ino, unsigned file_type) 363962306a36Sopenharmony_ci{ 364062306a36Sopenharmony_ci int retval, retval2; 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci BUFFER_TRACE(ent->bh, "get write access"); 364362306a36Sopenharmony_ci retval = ext4_journal_get_write_access(handle, ent->dir->i_sb, ent->bh, 364462306a36Sopenharmony_ci EXT4_JTR_NONE); 364562306a36Sopenharmony_ci if (retval) 364662306a36Sopenharmony_ci return retval; 364762306a36Sopenharmony_ci ent->de->inode = cpu_to_le32(ino); 364862306a36Sopenharmony_ci if (ext4_has_feature_filetype(ent->dir->i_sb)) 364962306a36Sopenharmony_ci ent->de->file_type = file_type; 365062306a36Sopenharmony_ci inode_inc_iversion(ent->dir); 365162306a36Sopenharmony_ci ent->dir->i_mtime = inode_set_ctime_current(ent->dir); 365262306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, ent->dir); 365362306a36Sopenharmony_ci BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata"); 365462306a36Sopenharmony_ci if (!ent->inlined) { 365562306a36Sopenharmony_ci retval2 = ext4_handle_dirty_dirblock(handle, ent->dir, ent->bh); 365662306a36Sopenharmony_ci if (unlikely(retval2)) { 365762306a36Sopenharmony_ci ext4_std_error(ent->dir->i_sb, retval2); 365862306a36Sopenharmony_ci return retval2; 365962306a36Sopenharmony_ci } 366062306a36Sopenharmony_ci } 366162306a36Sopenharmony_ci return retval; 366262306a36Sopenharmony_ci} 366362306a36Sopenharmony_ci 366462306a36Sopenharmony_cistatic void ext4_resetent(handle_t *handle, struct ext4_renament *ent, 366562306a36Sopenharmony_ci unsigned ino, unsigned file_type) 366662306a36Sopenharmony_ci{ 366762306a36Sopenharmony_ci struct ext4_renament old = *ent; 366862306a36Sopenharmony_ci int retval = 0; 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci /* 367162306a36Sopenharmony_ci * old->de could have moved from under us during make indexed dir, 367262306a36Sopenharmony_ci * so the old->de may no longer valid and need to find it again 367362306a36Sopenharmony_ci * before reset old inode info. 367462306a36Sopenharmony_ci */ 367562306a36Sopenharmony_ci old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, 367662306a36Sopenharmony_ci &old.inlined); 367762306a36Sopenharmony_ci if (IS_ERR(old.bh)) 367862306a36Sopenharmony_ci retval = PTR_ERR(old.bh); 367962306a36Sopenharmony_ci if (!old.bh) 368062306a36Sopenharmony_ci retval = -ENOENT; 368162306a36Sopenharmony_ci if (retval) { 368262306a36Sopenharmony_ci ext4_std_error(old.dir->i_sb, retval); 368362306a36Sopenharmony_ci return; 368462306a36Sopenharmony_ci } 368562306a36Sopenharmony_ci 368662306a36Sopenharmony_ci ext4_setent(handle, &old, ino, file_type); 368762306a36Sopenharmony_ci brelse(old.bh); 368862306a36Sopenharmony_ci} 368962306a36Sopenharmony_ci 369062306a36Sopenharmony_cistatic int ext4_find_delete_entry(handle_t *handle, struct inode *dir, 369162306a36Sopenharmony_ci const struct qstr *d_name) 369262306a36Sopenharmony_ci{ 369362306a36Sopenharmony_ci int retval = -ENOENT; 369462306a36Sopenharmony_ci struct buffer_head *bh; 369562306a36Sopenharmony_ci struct ext4_dir_entry_2 *de; 369662306a36Sopenharmony_ci 369762306a36Sopenharmony_ci bh = ext4_find_entry(dir, d_name, &de, NULL); 369862306a36Sopenharmony_ci if (IS_ERR(bh)) 369962306a36Sopenharmony_ci return PTR_ERR(bh); 370062306a36Sopenharmony_ci if (bh) { 370162306a36Sopenharmony_ci retval = ext4_delete_entry(handle, dir, de, bh); 370262306a36Sopenharmony_ci brelse(bh); 370362306a36Sopenharmony_ci } 370462306a36Sopenharmony_ci return retval; 370562306a36Sopenharmony_ci} 370662306a36Sopenharmony_ci 370762306a36Sopenharmony_cistatic void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent, 370862306a36Sopenharmony_ci int force_reread) 370962306a36Sopenharmony_ci{ 371062306a36Sopenharmony_ci int retval; 371162306a36Sopenharmony_ci /* 371262306a36Sopenharmony_ci * ent->de could have moved from under us during htree split, so make 371362306a36Sopenharmony_ci * sure that we are deleting the right entry. We might also be pointing 371462306a36Sopenharmony_ci * to a stale entry in the unused part of ent->bh so just checking inum 371562306a36Sopenharmony_ci * and the name isn't enough. 371662306a36Sopenharmony_ci */ 371762306a36Sopenharmony_ci if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino || 371862306a36Sopenharmony_ci ent->de->name_len != ent->dentry->d_name.len || 371962306a36Sopenharmony_ci strncmp(ent->de->name, ent->dentry->d_name.name, 372062306a36Sopenharmony_ci ent->de->name_len) || 372162306a36Sopenharmony_ci force_reread) { 372262306a36Sopenharmony_ci retval = ext4_find_delete_entry(handle, ent->dir, 372362306a36Sopenharmony_ci &ent->dentry->d_name); 372462306a36Sopenharmony_ci } else { 372562306a36Sopenharmony_ci retval = ext4_delete_entry(handle, ent->dir, ent->de, ent->bh); 372662306a36Sopenharmony_ci if (retval == -ENOENT) { 372762306a36Sopenharmony_ci retval = ext4_find_delete_entry(handle, ent->dir, 372862306a36Sopenharmony_ci &ent->dentry->d_name); 372962306a36Sopenharmony_ci } 373062306a36Sopenharmony_ci } 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci if (retval) { 373362306a36Sopenharmony_ci ext4_warning_inode(ent->dir, 373462306a36Sopenharmony_ci "Deleting old file: nlink %d, error=%d", 373562306a36Sopenharmony_ci ent->dir->i_nlink, retval); 373662306a36Sopenharmony_ci } 373762306a36Sopenharmony_ci} 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_cistatic void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) 374062306a36Sopenharmony_ci{ 374162306a36Sopenharmony_ci if (ent->dir_nlink_delta) { 374262306a36Sopenharmony_ci if (ent->dir_nlink_delta == -1) 374362306a36Sopenharmony_ci ext4_dec_count(ent->dir); 374462306a36Sopenharmony_ci else 374562306a36Sopenharmony_ci ext4_inc_count(ent->dir); 374662306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, ent->dir); 374762306a36Sopenharmony_ci } 374862306a36Sopenharmony_ci} 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_cistatic struct inode *ext4_whiteout_for_rename(struct mnt_idmap *idmap, 375162306a36Sopenharmony_ci struct ext4_renament *ent, 375262306a36Sopenharmony_ci int credits, handle_t **h) 375362306a36Sopenharmony_ci{ 375462306a36Sopenharmony_ci struct inode *wh; 375562306a36Sopenharmony_ci handle_t *handle; 375662306a36Sopenharmony_ci int retries = 0; 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci /* 375962306a36Sopenharmony_ci * for inode block, sb block, group summaries, 376062306a36Sopenharmony_ci * and inode bitmap 376162306a36Sopenharmony_ci */ 376262306a36Sopenharmony_ci credits += (EXT4_MAXQUOTAS_TRANS_BLOCKS(ent->dir->i_sb) + 376362306a36Sopenharmony_ci EXT4_XATTR_TRANS_BLOCKS + 4); 376462306a36Sopenharmony_ciretry: 376562306a36Sopenharmony_ci wh = ext4_new_inode_start_handle(idmap, ent->dir, 376662306a36Sopenharmony_ci S_IFCHR | WHITEOUT_MODE, 376762306a36Sopenharmony_ci &ent->dentry->d_name, 0, NULL, 376862306a36Sopenharmony_ci EXT4_HT_DIR, credits); 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci handle = ext4_journal_current_handle(); 377162306a36Sopenharmony_ci if (IS_ERR(wh)) { 377262306a36Sopenharmony_ci if (handle) 377362306a36Sopenharmony_ci ext4_journal_stop(handle); 377462306a36Sopenharmony_ci if (PTR_ERR(wh) == -ENOSPC && 377562306a36Sopenharmony_ci ext4_should_retry_alloc(ent->dir->i_sb, &retries)) 377662306a36Sopenharmony_ci goto retry; 377762306a36Sopenharmony_ci } else { 377862306a36Sopenharmony_ci *h = handle; 377962306a36Sopenharmony_ci init_special_inode(wh, wh->i_mode, WHITEOUT_DEV); 378062306a36Sopenharmony_ci wh->i_op = &ext4_special_inode_operations; 378162306a36Sopenharmony_ci } 378262306a36Sopenharmony_ci return wh; 378362306a36Sopenharmony_ci} 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_ci/* 378662306a36Sopenharmony_ci * Anybody can rename anything with this: the permission checks are left to the 378762306a36Sopenharmony_ci * higher-level routines. 378862306a36Sopenharmony_ci * 378962306a36Sopenharmony_ci * n.b. old_{dentry,inode) refers to the source dentry/inode 379062306a36Sopenharmony_ci * while new_{dentry,inode) refers to the destination dentry/inode 379162306a36Sopenharmony_ci * This comes from rename(const char *oldpath, const char *newpath) 379262306a36Sopenharmony_ci */ 379362306a36Sopenharmony_cistatic int ext4_rename(struct mnt_idmap *idmap, struct inode *old_dir, 379462306a36Sopenharmony_ci struct dentry *old_dentry, struct inode *new_dir, 379562306a36Sopenharmony_ci struct dentry *new_dentry, unsigned int flags) 379662306a36Sopenharmony_ci{ 379762306a36Sopenharmony_ci handle_t *handle = NULL; 379862306a36Sopenharmony_ci struct ext4_renament old = { 379962306a36Sopenharmony_ci .dir = old_dir, 380062306a36Sopenharmony_ci .dentry = old_dentry, 380162306a36Sopenharmony_ci .inode = d_inode(old_dentry), 380262306a36Sopenharmony_ci }; 380362306a36Sopenharmony_ci struct ext4_renament new = { 380462306a36Sopenharmony_ci .dir = new_dir, 380562306a36Sopenharmony_ci .dentry = new_dentry, 380662306a36Sopenharmony_ci .inode = d_inode(new_dentry), 380762306a36Sopenharmony_ci }; 380862306a36Sopenharmony_ci int force_reread; 380962306a36Sopenharmony_ci int retval; 381062306a36Sopenharmony_ci struct inode *whiteout = NULL; 381162306a36Sopenharmony_ci int credits; 381262306a36Sopenharmony_ci u8 old_file_type; 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci if (new.inode && new.inode->i_nlink == 0) { 381562306a36Sopenharmony_ci EXT4_ERROR_INODE(new.inode, 381662306a36Sopenharmony_ci "target of rename is already freed"); 381762306a36Sopenharmony_ci return -EFSCORRUPTED; 381862306a36Sopenharmony_ci } 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ci if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) && 382162306a36Sopenharmony_ci (!projid_eq(EXT4_I(new_dir)->i_projid, 382262306a36Sopenharmony_ci EXT4_I(old_dentry->d_inode)->i_projid))) 382362306a36Sopenharmony_ci return -EXDEV; 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci retval = dquot_initialize(old.dir); 382662306a36Sopenharmony_ci if (retval) 382762306a36Sopenharmony_ci return retval; 382862306a36Sopenharmony_ci retval = dquot_initialize(old.inode); 382962306a36Sopenharmony_ci if (retval) 383062306a36Sopenharmony_ci return retval; 383162306a36Sopenharmony_ci retval = dquot_initialize(new.dir); 383262306a36Sopenharmony_ci if (retval) 383362306a36Sopenharmony_ci return retval; 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci /* Initialize quotas before so that eventual writes go 383662306a36Sopenharmony_ci * in separate transaction */ 383762306a36Sopenharmony_ci if (new.inode) { 383862306a36Sopenharmony_ci retval = dquot_initialize(new.inode); 383962306a36Sopenharmony_ci if (retval) 384062306a36Sopenharmony_ci return retval; 384162306a36Sopenharmony_ci } 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, 384462306a36Sopenharmony_ci &old.inlined); 384562306a36Sopenharmony_ci if (IS_ERR(old.bh)) 384662306a36Sopenharmony_ci return PTR_ERR(old.bh); 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci /* 384962306a36Sopenharmony_ci * Check for inode number is _not_ due to possible IO errors. 385062306a36Sopenharmony_ci * We might rmdir the source, keep it as pwd of some process 385162306a36Sopenharmony_ci * and merrily kill the link to whatever was created under the 385262306a36Sopenharmony_ci * same name. Goodbye sticky bit ;-< 385362306a36Sopenharmony_ci */ 385462306a36Sopenharmony_ci retval = -ENOENT; 385562306a36Sopenharmony_ci if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) 385662306a36Sopenharmony_ci goto release_bh; 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, 385962306a36Sopenharmony_ci &new.de, &new.inlined); 386062306a36Sopenharmony_ci if (IS_ERR(new.bh)) { 386162306a36Sopenharmony_ci retval = PTR_ERR(new.bh); 386262306a36Sopenharmony_ci new.bh = NULL; 386362306a36Sopenharmony_ci goto release_bh; 386462306a36Sopenharmony_ci } 386562306a36Sopenharmony_ci if (new.bh) { 386662306a36Sopenharmony_ci if (!new.inode) { 386762306a36Sopenharmony_ci brelse(new.bh); 386862306a36Sopenharmony_ci new.bh = NULL; 386962306a36Sopenharmony_ci } 387062306a36Sopenharmony_ci } 387162306a36Sopenharmony_ci if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) 387262306a36Sopenharmony_ci ext4_alloc_da_blocks(old.inode); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + 387562306a36Sopenharmony_ci EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); 387662306a36Sopenharmony_ci if (!(flags & RENAME_WHITEOUT)) { 387762306a36Sopenharmony_ci handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits); 387862306a36Sopenharmony_ci if (IS_ERR(handle)) { 387962306a36Sopenharmony_ci retval = PTR_ERR(handle); 388062306a36Sopenharmony_ci goto release_bh; 388162306a36Sopenharmony_ci } 388262306a36Sopenharmony_ci } else { 388362306a36Sopenharmony_ci whiteout = ext4_whiteout_for_rename(idmap, &old, credits, &handle); 388462306a36Sopenharmony_ci if (IS_ERR(whiteout)) { 388562306a36Sopenharmony_ci retval = PTR_ERR(whiteout); 388662306a36Sopenharmony_ci goto release_bh; 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci } 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_ci old_file_type = old.de->file_type; 389162306a36Sopenharmony_ci if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) 389262306a36Sopenharmony_ci ext4_handle_sync(handle); 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci if (S_ISDIR(old.inode->i_mode)) { 389562306a36Sopenharmony_ci if (new.inode) { 389662306a36Sopenharmony_ci retval = -ENOTEMPTY; 389762306a36Sopenharmony_ci if (!ext4_empty_dir(new.inode)) 389862306a36Sopenharmony_ci goto end_rename; 389962306a36Sopenharmony_ci } else { 390062306a36Sopenharmony_ci retval = -EMLINK; 390162306a36Sopenharmony_ci if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir)) 390262306a36Sopenharmony_ci goto end_rename; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci retval = ext4_rename_dir_prepare(handle, &old); 390562306a36Sopenharmony_ci if (retval) 390662306a36Sopenharmony_ci goto end_rename; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci /* 390962306a36Sopenharmony_ci * If we're renaming a file within an inline_data dir and adding or 391062306a36Sopenharmony_ci * setting the new dirent causes a conversion from inline_data to 391162306a36Sopenharmony_ci * extents/blockmap, we need to force the dirent delete code to 391262306a36Sopenharmony_ci * re-read the directory, or else we end up trying to delete a dirent 391362306a36Sopenharmony_ci * from what is now the extent tree root (or a block map). 391462306a36Sopenharmony_ci */ 391562306a36Sopenharmony_ci force_reread = (new.dir->i_ino == old.dir->i_ino && 391662306a36Sopenharmony_ci ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci if (whiteout) { 391962306a36Sopenharmony_ci /* 392062306a36Sopenharmony_ci * Do this before adding a new entry, so the old entry is sure 392162306a36Sopenharmony_ci * to be still pointing to the valid old entry. 392262306a36Sopenharmony_ci */ 392362306a36Sopenharmony_ci retval = ext4_setent(handle, &old, whiteout->i_ino, 392462306a36Sopenharmony_ci EXT4_FT_CHRDEV); 392562306a36Sopenharmony_ci if (retval) 392662306a36Sopenharmony_ci goto end_rename; 392762306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, whiteout); 392862306a36Sopenharmony_ci if (unlikely(retval)) 392962306a36Sopenharmony_ci goto end_rename; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci } 393262306a36Sopenharmony_ci if (!new.bh) { 393362306a36Sopenharmony_ci retval = ext4_add_entry(handle, new.dentry, old.inode); 393462306a36Sopenharmony_ci if (retval) 393562306a36Sopenharmony_ci goto end_rename; 393662306a36Sopenharmony_ci } else { 393762306a36Sopenharmony_ci retval = ext4_setent(handle, &new, 393862306a36Sopenharmony_ci old.inode->i_ino, old_file_type); 393962306a36Sopenharmony_ci if (retval) 394062306a36Sopenharmony_ci goto end_rename; 394162306a36Sopenharmony_ci } 394262306a36Sopenharmony_ci if (force_reread) 394362306a36Sopenharmony_ci force_reread = !ext4_test_inode_flag(new.dir, 394462306a36Sopenharmony_ci EXT4_INODE_INLINE_DATA); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci /* 394762306a36Sopenharmony_ci * Like most other Unix systems, set the ctime for inodes on a 394862306a36Sopenharmony_ci * rename. 394962306a36Sopenharmony_ci */ 395062306a36Sopenharmony_ci inode_set_ctime_current(old.inode); 395162306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, old.inode); 395262306a36Sopenharmony_ci if (unlikely(retval)) 395362306a36Sopenharmony_ci goto end_rename; 395462306a36Sopenharmony_ci 395562306a36Sopenharmony_ci if (!whiteout) { 395662306a36Sopenharmony_ci /* 395762306a36Sopenharmony_ci * ok, that's it 395862306a36Sopenharmony_ci */ 395962306a36Sopenharmony_ci ext4_rename_delete(handle, &old, force_reread); 396062306a36Sopenharmony_ci } 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci if (new.inode) { 396362306a36Sopenharmony_ci ext4_dec_count(new.inode); 396462306a36Sopenharmony_ci inode_set_ctime_current(new.inode); 396562306a36Sopenharmony_ci } 396662306a36Sopenharmony_ci old.dir->i_mtime = inode_set_ctime_current(old.dir); 396762306a36Sopenharmony_ci ext4_update_dx_flag(old.dir); 396862306a36Sopenharmony_ci if (old.dir_bh) { 396962306a36Sopenharmony_ci retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); 397062306a36Sopenharmony_ci if (retval) 397162306a36Sopenharmony_ci goto end_rename; 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci ext4_dec_count(old.dir); 397462306a36Sopenharmony_ci if (new.inode) { 397562306a36Sopenharmony_ci /* checked ext4_empty_dir above, can't have another 397662306a36Sopenharmony_ci * parent, ext4_dec_count() won't work for many-linked 397762306a36Sopenharmony_ci * dirs */ 397862306a36Sopenharmony_ci clear_nlink(new.inode); 397962306a36Sopenharmony_ci } else { 398062306a36Sopenharmony_ci ext4_inc_count(new.dir); 398162306a36Sopenharmony_ci ext4_update_dx_flag(new.dir); 398262306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, new.dir); 398362306a36Sopenharmony_ci if (unlikely(retval)) 398462306a36Sopenharmony_ci goto end_rename; 398562306a36Sopenharmony_ci } 398662306a36Sopenharmony_ci } 398762306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, old.dir); 398862306a36Sopenharmony_ci if (unlikely(retval)) 398962306a36Sopenharmony_ci goto end_rename; 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci if (S_ISDIR(old.inode->i_mode)) { 399262306a36Sopenharmony_ci /* 399362306a36Sopenharmony_ci * We disable fast commits here that's because the 399462306a36Sopenharmony_ci * replay code is not yet capable of changing dot dot 399562306a36Sopenharmony_ci * dirents in directories. 399662306a36Sopenharmony_ci */ 399762306a36Sopenharmony_ci ext4_fc_mark_ineligible(old.inode->i_sb, 399862306a36Sopenharmony_ci EXT4_FC_REASON_RENAME_DIR, handle); 399962306a36Sopenharmony_ci } else { 400062306a36Sopenharmony_ci struct super_block *sb = old.inode->i_sb; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (new.inode) 400362306a36Sopenharmony_ci ext4_fc_track_unlink(handle, new.dentry); 400462306a36Sopenharmony_ci if (test_opt2(sb, JOURNAL_FAST_COMMIT) && 400562306a36Sopenharmony_ci !(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY) && 400662306a36Sopenharmony_ci !(ext4_test_mount_flag(sb, EXT4_MF_FC_INELIGIBLE))) { 400762306a36Sopenharmony_ci __ext4_fc_track_link(handle, old.inode, new.dentry); 400862306a36Sopenharmony_ci __ext4_fc_track_unlink(handle, old.inode, old.dentry); 400962306a36Sopenharmony_ci if (whiteout) 401062306a36Sopenharmony_ci __ext4_fc_track_create(handle, whiteout, 401162306a36Sopenharmony_ci old.dentry); 401262306a36Sopenharmony_ci } 401362306a36Sopenharmony_ci } 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_ci if (new.inode) { 401662306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, new.inode); 401762306a36Sopenharmony_ci if (unlikely(retval)) 401862306a36Sopenharmony_ci goto end_rename; 401962306a36Sopenharmony_ci if (!new.inode->i_nlink) 402062306a36Sopenharmony_ci ext4_orphan_add(handle, new.inode); 402162306a36Sopenharmony_ci } 402262306a36Sopenharmony_ci retval = 0; 402362306a36Sopenharmony_ci 402462306a36Sopenharmony_ciend_rename: 402562306a36Sopenharmony_ci if (whiteout) { 402662306a36Sopenharmony_ci if (retval) { 402762306a36Sopenharmony_ci ext4_resetent(handle, &old, 402862306a36Sopenharmony_ci old.inode->i_ino, old_file_type); 402962306a36Sopenharmony_ci drop_nlink(whiteout); 403062306a36Sopenharmony_ci ext4_mark_inode_dirty(handle, whiteout); 403162306a36Sopenharmony_ci ext4_orphan_add(handle, whiteout); 403262306a36Sopenharmony_ci } 403362306a36Sopenharmony_ci unlock_new_inode(whiteout); 403462306a36Sopenharmony_ci ext4_journal_stop(handle); 403562306a36Sopenharmony_ci iput(whiteout); 403662306a36Sopenharmony_ci } else { 403762306a36Sopenharmony_ci ext4_journal_stop(handle); 403862306a36Sopenharmony_ci } 403962306a36Sopenharmony_cirelease_bh: 404062306a36Sopenharmony_ci brelse(old.dir_bh); 404162306a36Sopenharmony_ci brelse(old.bh); 404262306a36Sopenharmony_ci brelse(new.bh); 404362306a36Sopenharmony_ci 404462306a36Sopenharmony_ci return retval; 404562306a36Sopenharmony_ci} 404662306a36Sopenharmony_ci 404762306a36Sopenharmony_cistatic int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, 404862306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry) 404962306a36Sopenharmony_ci{ 405062306a36Sopenharmony_ci handle_t *handle = NULL; 405162306a36Sopenharmony_ci struct ext4_renament old = { 405262306a36Sopenharmony_ci .dir = old_dir, 405362306a36Sopenharmony_ci .dentry = old_dentry, 405462306a36Sopenharmony_ci .inode = d_inode(old_dentry), 405562306a36Sopenharmony_ci }; 405662306a36Sopenharmony_ci struct ext4_renament new = { 405762306a36Sopenharmony_ci .dir = new_dir, 405862306a36Sopenharmony_ci .dentry = new_dentry, 405962306a36Sopenharmony_ci .inode = d_inode(new_dentry), 406062306a36Sopenharmony_ci }; 406162306a36Sopenharmony_ci u8 new_file_type; 406262306a36Sopenharmony_ci int retval; 406362306a36Sopenharmony_ci 406462306a36Sopenharmony_ci if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) && 406562306a36Sopenharmony_ci !projid_eq(EXT4_I(new_dir)->i_projid, 406662306a36Sopenharmony_ci EXT4_I(old_dentry->d_inode)->i_projid)) || 406762306a36Sopenharmony_ci (ext4_test_inode_flag(old_dir, EXT4_INODE_PROJINHERIT) && 406862306a36Sopenharmony_ci !projid_eq(EXT4_I(old_dir)->i_projid, 406962306a36Sopenharmony_ci EXT4_I(new_dentry->d_inode)->i_projid))) 407062306a36Sopenharmony_ci return -EXDEV; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci retval = dquot_initialize(old.dir); 407362306a36Sopenharmony_ci if (retval) 407462306a36Sopenharmony_ci return retval; 407562306a36Sopenharmony_ci retval = dquot_initialize(new.dir); 407662306a36Sopenharmony_ci if (retval) 407762306a36Sopenharmony_ci return retval; 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, 408062306a36Sopenharmony_ci &old.de, &old.inlined); 408162306a36Sopenharmony_ci if (IS_ERR(old.bh)) 408262306a36Sopenharmony_ci return PTR_ERR(old.bh); 408362306a36Sopenharmony_ci /* 408462306a36Sopenharmony_ci * Check for inode number is _not_ due to possible IO errors. 408562306a36Sopenharmony_ci * We might rmdir the source, keep it as pwd of some process 408662306a36Sopenharmony_ci * and merrily kill the link to whatever was created under the 408762306a36Sopenharmony_ci * same name. Goodbye sticky bit ;-< 408862306a36Sopenharmony_ci */ 408962306a36Sopenharmony_ci retval = -ENOENT; 409062306a36Sopenharmony_ci if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) 409162306a36Sopenharmony_ci goto end_rename; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_ci new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, 409462306a36Sopenharmony_ci &new.de, &new.inlined); 409562306a36Sopenharmony_ci if (IS_ERR(new.bh)) { 409662306a36Sopenharmony_ci retval = PTR_ERR(new.bh); 409762306a36Sopenharmony_ci new.bh = NULL; 409862306a36Sopenharmony_ci goto end_rename; 409962306a36Sopenharmony_ci } 410062306a36Sopenharmony_ci 410162306a36Sopenharmony_ci /* RENAME_EXCHANGE case: old *and* new must both exist */ 410262306a36Sopenharmony_ci if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino) 410362306a36Sopenharmony_ci goto end_rename; 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci handle = ext4_journal_start(old.dir, EXT4_HT_DIR, 410662306a36Sopenharmony_ci (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + 410762306a36Sopenharmony_ci 2 * EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); 410862306a36Sopenharmony_ci if (IS_ERR(handle)) { 410962306a36Sopenharmony_ci retval = PTR_ERR(handle); 411062306a36Sopenharmony_ci handle = NULL; 411162306a36Sopenharmony_ci goto end_rename; 411262306a36Sopenharmony_ci } 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) 411562306a36Sopenharmony_ci ext4_handle_sync(handle); 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci if (S_ISDIR(old.inode->i_mode)) { 411862306a36Sopenharmony_ci old.is_dir = true; 411962306a36Sopenharmony_ci retval = ext4_rename_dir_prepare(handle, &old); 412062306a36Sopenharmony_ci if (retval) 412162306a36Sopenharmony_ci goto end_rename; 412262306a36Sopenharmony_ci } 412362306a36Sopenharmony_ci if (S_ISDIR(new.inode->i_mode)) { 412462306a36Sopenharmony_ci new.is_dir = true; 412562306a36Sopenharmony_ci retval = ext4_rename_dir_prepare(handle, &new); 412662306a36Sopenharmony_ci if (retval) 412762306a36Sopenharmony_ci goto end_rename; 412862306a36Sopenharmony_ci } 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci /* 413162306a36Sopenharmony_ci * Other than the special case of overwriting a directory, parents' 413262306a36Sopenharmony_ci * nlink only needs to be modified if this is a cross directory rename. 413362306a36Sopenharmony_ci */ 413462306a36Sopenharmony_ci if (old.dir != new.dir && old.is_dir != new.is_dir) { 413562306a36Sopenharmony_ci old.dir_nlink_delta = old.is_dir ? -1 : 1; 413662306a36Sopenharmony_ci new.dir_nlink_delta = -old.dir_nlink_delta; 413762306a36Sopenharmony_ci retval = -EMLINK; 413862306a36Sopenharmony_ci if ((old.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(old.dir)) || 413962306a36Sopenharmony_ci (new.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(new.dir))) 414062306a36Sopenharmony_ci goto end_rename; 414162306a36Sopenharmony_ci } 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci new_file_type = new.de->file_type; 414462306a36Sopenharmony_ci retval = ext4_setent(handle, &new, old.inode->i_ino, old.de->file_type); 414562306a36Sopenharmony_ci if (retval) 414662306a36Sopenharmony_ci goto end_rename; 414762306a36Sopenharmony_ci 414862306a36Sopenharmony_ci retval = ext4_setent(handle, &old, new.inode->i_ino, new_file_type); 414962306a36Sopenharmony_ci if (retval) 415062306a36Sopenharmony_ci goto end_rename; 415162306a36Sopenharmony_ci 415262306a36Sopenharmony_ci /* 415362306a36Sopenharmony_ci * Like most other Unix systems, set the ctime for inodes on a 415462306a36Sopenharmony_ci * rename. 415562306a36Sopenharmony_ci */ 415662306a36Sopenharmony_ci inode_set_ctime_current(old.inode); 415762306a36Sopenharmony_ci inode_set_ctime_current(new.inode); 415862306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, old.inode); 415962306a36Sopenharmony_ci if (unlikely(retval)) 416062306a36Sopenharmony_ci goto end_rename; 416162306a36Sopenharmony_ci retval = ext4_mark_inode_dirty(handle, new.inode); 416262306a36Sopenharmony_ci if (unlikely(retval)) 416362306a36Sopenharmony_ci goto end_rename; 416462306a36Sopenharmony_ci ext4_fc_mark_ineligible(new.inode->i_sb, 416562306a36Sopenharmony_ci EXT4_FC_REASON_CROSS_RENAME, handle); 416662306a36Sopenharmony_ci if (old.dir_bh) { 416762306a36Sopenharmony_ci retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); 416862306a36Sopenharmony_ci if (retval) 416962306a36Sopenharmony_ci goto end_rename; 417062306a36Sopenharmony_ci } 417162306a36Sopenharmony_ci if (new.dir_bh) { 417262306a36Sopenharmony_ci retval = ext4_rename_dir_finish(handle, &new, old.dir->i_ino); 417362306a36Sopenharmony_ci if (retval) 417462306a36Sopenharmony_ci goto end_rename; 417562306a36Sopenharmony_ci } 417662306a36Sopenharmony_ci ext4_update_dir_count(handle, &old); 417762306a36Sopenharmony_ci ext4_update_dir_count(handle, &new); 417862306a36Sopenharmony_ci retval = 0; 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ciend_rename: 418162306a36Sopenharmony_ci brelse(old.dir_bh); 418262306a36Sopenharmony_ci brelse(new.dir_bh); 418362306a36Sopenharmony_ci brelse(old.bh); 418462306a36Sopenharmony_ci brelse(new.bh); 418562306a36Sopenharmony_ci if (handle) 418662306a36Sopenharmony_ci ext4_journal_stop(handle); 418762306a36Sopenharmony_ci return retval; 418862306a36Sopenharmony_ci} 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_cistatic int ext4_rename2(struct mnt_idmap *idmap, 419162306a36Sopenharmony_ci struct inode *old_dir, struct dentry *old_dentry, 419262306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 419362306a36Sopenharmony_ci unsigned int flags) 419462306a36Sopenharmony_ci{ 419562306a36Sopenharmony_ci int err; 419662306a36Sopenharmony_ci 419762306a36Sopenharmony_ci if (unlikely(ext4_forced_shutdown(old_dir->i_sb))) 419862306a36Sopenharmony_ci return -EIO; 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) 420162306a36Sopenharmony_ci return -EINVAL; 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, 420462306a36Sopenharmony_ci flags); 420562306a36Sopenharmony_ci if (err) 420662306a36Sopenharmony_ci return err; 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) { 420962306a36Sopenharmony_ci return ext4_cross_rename(old_dir, old_dentry, 421062306a36Sopenharmony_ci new_dir, new_dentry); 421162306a36Sopenharmony_ci } 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_ci return ext4_rename(idmap, old_dir, old_dentry, new_dir, new_dentry, flags); 421462306a36Sopenharmony_ci} 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci/* 421762306a36Sopenharmony_ci * directories can handle most operations... 421862306a36Sopenharmony_ci */ 421962306a36Sopenharmony_ciconst struct inode_operations ext4_dir_inode_operations = { 422062306a36Sopenharmony_ci .create = ext4_create, 422162306a36Sopenharmony_ci .lookup = ext4_lookup, 422262306a36Sopenharmony_ci .link = ext4_link, 422362306a36Sopenharmony_ci .unlink = ext4_unlink, 422462306a36Sopenharmony_ci .symlink = ext4_symlink, 422562306a36Sopenharmony_ci .mkdir = ext4_mkdir, 422662306a36Sopenharmony_ci .rmdir = ext4_rmdir, 422762306a36Sopenharmony_ci .mknod = ext4_mknod, 422862306a36Sopenharmony_ci .tmpfile = ext4_tmpfile, 422962306a36Sopenharmony_ci .rename = ext4_rename2, 423062306a36Sopenharmony_ci .setattr = ext4_setattr, 423162306a36Sopenharmony_ci .getattr = ext4_getattr, 423262306a36Sopenharmony_ci .listxattr = ext4_listxattr, 423362306a36Sopenharmony_ci .get_inode_acl = ext4_get_acl, 423462306a36Sopenharmony_ci .set_acl = ext4_set_acl, 423562306a36Sopenharmony_ci .fiemap = ext4_fiemap, 423662306a36Sopenharmony_ci .fileattr_get = ext4_fileattr_get, 423762306a36Sopenharmony_ci .fileattr_set = ext4_fileattr_set, 423862306a36Sopenharmony_ci}; 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ciconst struct inode_operations ext4_special_inode_operations = { 424162306a36Sopenharmony_ci .setattr = ext4_setattr, 424262306a36Sopenharmony_ci .getattr = ext4_getattr, 424362306a36Sopenharmony_ci .listxattr = ext4_listxattr, 424462306a36Sopenharmony_ci .get_inode_acl = ext4_get_acl, 424562306a36Sopenharmony_ci .set_acl = ext4_set_acl, 424662306a36Sopenharmony_ci}; 4247