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