18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* * This file is part of UBIFS.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
58c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007 University of Szeged, Hungary
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём)
88c2ecf20Sopenharmony_ci *          Adrian Hunter
98c2ecf20Sopenharmony_ci *          Zoltan Sogor
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/*
138c2ecf20Sopenharmony_ci * This file implements directory operations.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * All FS operations in this file allocate budget before writing anything to the
168c2ecf20Sopenharmony_ci * media. If they fail to allocate it, the error is returned. The only
178c2ecf20Sopenharmony_ci * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even
188c2ecf20Sopenharmony_ci * if they unable to allocate the budget, because deletion %-ENOSPC failure is
198c2ecf20Sopenharmony_ci * not what users are usually ready to get. UBIFS budgeting subsystem has some
208c2ecf20Sopenharmony_ci * space reserved for these purposes.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * All operations in this file write all inodes which they change straight
238c2ecf20Sopenharmony_ci * away, instead of marking them dirty. For example, 'ubifs_link()' changes
248c2ecf20Sopenharmony_ci * @i_size of the parent inode and writes the parent inode together with the
258c2ecf20Sopenharmony_ci * target inode. This was done to simplify file-system recovery which would
268c2ecf20Sopenharmony_ci * otherwise be very difficult to do. The only exception is rename which marks
278c2ecf20Sopenharmony_ci * the re-named inode dirty (because its @i_ctime is updated) but does not
288c2ecf20Sopenharmony_ci * write it, but just marks it as dirty.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "ubifs.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/**
348c2ecf20Sopenharmony_ci * inherit_flags - inherit flags of the parent inode.
358c2ecf20Sopenharmony_ci * @dir: parent inode
368c2ecf20Sopenharmony_ci * @mode: new inode mode flags
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * This is a helper function for 'ubifs_new_inode()' which inherits flag of the
398c2ecf20Sopenharmony_ci * parent directory inode @dir. UBIFS inodes inherit the following flags:
408c2ecf20Sopenharmony_ci * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on
418c2ecf20Sopenharmony_ci *   sub-directory basis;
428c2ecf20Sopenharmony_ci * o %UBIFS_SYNC_FL - useful for the same reasons;
438c2ecf20Sopenharmony_ci * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories.
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * This function returns the inherited flags.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_cistatic int inherit_flags(const struct inode *dir, umode_t mode)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int flags;
508c2ecf20Sopenharmony_ci	const struct ubifs_inode *ui = ubifs_inode(dir);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (!S_ISDIR(dir->i_mode))
538c2ecf20Sopenharmony_ci		/*
548c2ecf20Sopenharmony_ci		 * The parent is not a directory, which means that an extended
558c2ecf20Sopenharmony_ci		 * attribute inode is being created. No flags.
568c2ecf20Sopenharmony_ci		 */
578c2ecf20Sopenharmony_ci		return 0;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL);
608c2ecf20Sopenharmony_ci	if (!S_ISDIR(mode))
618c2ecf20Sopenharmony_ci		/* The "DIRSYNC" flag only applies to directories */
628c2ecf20Sopenharmony_ci		flags &= ~UBIFS_DIRSYNC_FL;
638c2ecf20Sopenharmony_ci	return flags;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci * ubifs_new_inode - allocate new UBIFS inode object.
688c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
698c2ecf20Sopenharmony_ci * @dir: parent directory inode
708c2ecf20Sopenharmony_ci * @mode: inode mode flags
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * This function finds an unused inode number, allocates new inode and
738c2ecf20Sopenharmony_ci * initializes it. Returns new inode in case of success and an error code in
748c2ecf20Sopenharmony_ci * case of failure.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistruct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
778c2ecf20Sopenharmony_ci			      umode_t mode)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	int err;
808c2ecf20Sopenharmony_ci	struct inode *inode;
818c2ecf20Sopenharmony_ci	struct ubifs_inode *ui;
828c2ecf20Sopenharmony_ci	bool encrypted = false;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	inode = new_inode(c->vfs_sb);
858c2ecf20Sopenharmony_ci	ui = ubifs_inode(inode);
868c2ecf20Sopenharmony_ci	if (!inode)
878c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/*
908c2ecf20Sopenharmony_ci	 * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and
918c2ecf20Sopenharmony_ci	 * marking them dirty in file write path (see 'file_update_time()').
928c2ecf20Sopenharmony_ci	 * UBIFS has to fully control "clean <-> dirty" transitions of inodes
938c2ecf20Sopenharmony_ci	 * to make budgeting work.
948c2ecf20Sopenharmony_ci	 */
958c2ecf20Sopenharmony_ci	inode->i_flags |= S_NOCMTIME;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	inode_init_owner(inode, dir, mode);
988c2ecf20Sopenharmony_ci	inode->i_mtime = inode->i_atime = inode->i_ctime =
998c2ecf20Sopenharmony_ci			 current_time(inode);
1008c2ecf20Sopenharmony_ci	inode->i_mapping->nrpages = 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	err = fscrypt_prepare_new_inode(dir, inode, &encrypted);
1038c2ecf20Sopenharmony_ci	if (err) {
1048c2ecf20Sopenharmony_ci		ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err);
1058c2ecf20Sopenharmony_ci		goto out_iput;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	switch (mode & S_IFMT) {
1098c2ecf20Sopenharmony_ci	case S_IFREG:
1108c2ecf20Sopenharmony_ci		inode->i_mapping->a_ops = &ubifs_file_address_operations;
1118c2ecf20Sopenharmony_ci		inode->i_op = &ubifs_file_inode_operations;
1128c2ecf20Sopenharmony_ci		inode->i_fop = &ubifs_file_operations;
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci	case S_IFDIR:
1158c2ecf20Sopenharmony_ci		inode->i_op  = &ubifs_dir_inode_operations;
1168c2ecf20Sopenharmony_ci		inode->i_fop = &ubifs_dir_operations;
1178c2ecf20Sopenharmony_ci		inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ;
1188c2ecf20Sopenharmony_ci		break;
1198c2ecf20Sopenharmony_ci	case S_IFLNK:
1208c2ecf20Sopenharmony_ci		inode->i_op = &ubifs_symlink_inode_operations;
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci	case S_IFSOCK:
1238c2ecf20Sopenharmony_ci	case S_IFIFO:
1248c2ecf20Sopenharmony_ci	case S_IFBLK:
1258c2ecf20Sopenharmony_ci	case S_IFCHR:
1268c2ecf20Sopenharmony_ci		inode->i_op  = &ubifs_file_inode_operations;
1278c2ecf20Sopenharmony_ci		break;
1288c2ecf20Sopenharmony_ci	default:
1298c2ecf20Sopenharmony_ci		BUG();
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ui->flags = inherit_flags(dir, mode);
1338c2ecf20Sopenharmony_ci	ubifs_set_inode_flags(inode);
1348c2ecf20Sopenharmony_ci	if (S_ISREG(mode))
1358c2ecf20Sopenharmony_ci		ui->compr_type = c->default_compr;
1368c2ecf20Sopenharmony_ci	else
1378c2ecf20Sopenharmony_ci		ui->compr_type = UBIFS_COMPR_NONE;
1388c2ecf20Sopenharmony_ci	ui->synced_i_size = 0;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	spin_lock(&c->cnt_lock);
1418c2ecf20Sopenharmony_ci	/* Inode number overflow is currently not supported */
1428c2ecf20Sopenharmony_ci	if (c->highest_inum >= INUM_WARN_WATERMARK) {
1438c2ecf20Sopenharmony_ci		if (c->highest_inum >= INUM_WATERMARK) {
1448c2ecf20Sopenharmony_ci			spin_unlock(&c->cnt_lock);
1458c2ecf20Sopenharmony_ci			ubifs_err(c, "out of inode numbers");
1468c2ecf20Sopenharmony_ci			err = -EINVAL;
1478c2ecf20Sopenharmony_ci			goto out_iput;
1488c2ecf20Sopenharmony_ci		}
1498c2ecf20Sopenharmony_ci		ubifs_warn(c, "running out of inode numbers (current %lu, max %u)",
1508c2ecf20Sopenharmony_ci			   (unsigned long)c->highest_inum, INUM_WATERMARK);
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	inode->i_ino = ++c->highest_inum;
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	 * The creation sequence number remains with this inode for its
1568c2ecf20Sopenharmony_ci	 * lifetime. All nodes for this inode have a greater sequence number,
1578c2ecf20Sopenharmony_ci	 * and so it is possible to distinguish obsolete nodes belonging to a
1588c2ecf20Sopenharmony_ci	 * previous incarnation of the same inode number - for example, for the
1598c2ecf20Sopenharmony_ci	 * purpose of rebuilding the index.
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci	ui->creat_sqnum = ++c->max_sqnum;
1628c2ecf20Sopenharmony_ci	spin_unlock(&c->cnt_lock);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	if (encrypted) {
1658c2ecf20Sopenharmony_ci		err = fscrypt_set_context(inode, NULL);
1668c2ecf20Sopenharmony_ci		if (err) {
1678c2ecf20Sopenharmony_ci			ubifs_err(c, "fscrypt_set_context failed: %i", err);
1688c2ecf20Sopenharmony_ci			goto out_iput;
1698c2ecf20Sopenharmony_ci		}
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return inode;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ciout_iput:
1758c2ecf20Sopenharmony_ci	make_bad_inode(inode);
1768c2ecf20Sopenharmony_ci	iput(inode);
1778c2ecf20Sopenharmony_ci	return ERR_PTR(err);
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int dbg_check_name(const struct ubifs_info *c,
1818c2ecf20Sopenharmony_ci			  const struct ubifs_dent_node *dent,
1828c2ecf20Sopenharmony_ci			  const struct fscrypt_name *nm)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	if (!dbg_is_chk_gen(c))
1858c2ecf20Sopenharmony_ci		return 0;
1868c2ecf20Sopenharmony_ci	if (le16_to_cpu(dent->nlen) != fname_len(nm))
1878c2ecf20Sopenharmony_ci		return -EINVAL;
1888c2ecf20Sopenharmony_ci	if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
1898c2ecf20Sopenharmony_ci		return -EINVAL;
1908c2ecf20Sopenharmony_ci	return 0;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
1948c2ecf20Sopenharmony_ci				   unsigned int flags)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	int err;
1978c2ecf20Sopenharmony_ci	union ubifs_key key;
1988c2ecf20Sopenharmony_ci	struct inode *inode = NULL;
1998c2ecf20Sopenharmony_ci	struct ubifs_dent_node *dent = NULL;
2008c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
2018c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	err = fscrypt_prepare_lookup(dir, dentry, &nm);
2068c2ecf20Sopenharmony_ci	if (err == -ENOENT)
2078c2ecf20Sopenharmony_ci		return d_splice_alias(NULL, dentry);
2088c2ecf20Sopenharmony_ci	if (err)
2098c2ecf20Sopenharmony_ci		return ERR_PTR(err);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (fname_len(&nm) > UBIFS_MAX_NLEN) {
2128c2ecf20Sopenharmony_ci		inode = ERR_PTR(-ENAMETOOLONG);
2138c2ecf20Sopenharmony_ci		goto done;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
2178c2ecf20Sopenharmony_ci	if (!dent) {
2188c2ecf20Sopenharmony_ci		inode = ERR_PTR(-ENOMEM);
2198c2ecf20Sopenharmony_ci		goto done;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if (fname_name(&nm) == NULL) {
2238c2ecf20Sopenharmony_ci		if (nm.hash & ~UBIFS_S_KEY_HASH_MASK)
2248c2ecf20Sopenharmony_ci			goto done; /* ENOENT */
2258c2ecf20Sopenharmony_ci		dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
2268c2ecf20Sopenharmony_ci		err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
2278c2ecf20Sopenharmony_ci	} else {
2288c2ecf20Sopenharmony_ci		dent_key_init(c, &key, dir->i_ino, &nm);
2298c2ecf20Sopenharmony_ci		err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (err) {
2338c2ecf20Sopenharmony_ci		if (err == -ENOENT)
2348c2ecf20Sopenharmony_ci			dbg_gen("not found");
2358c2ecf20Sopenharmony_ci		else
2368c2ecf20Sopenharmony_ci			inode = ERR_PTR(err);
2378c2ecf20Sopenharmony_ci		goto done;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (dbg_check_name(c, dent, &nm)) {
2418c2ecf20Sopenharmony_ci		inode = ERR_PTR(-EINVAL);
2428c2ecf20Sopenharmony_ci		goto done;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
2468c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
2478c2ecf20Sopenharmony_ci		/*
2488c2ecf20Sopenharmony_ci		 * This should not happen. Probably the file-system needs
2498c2ecf20Sopenharmony_ci		 * checking.
2508c2ecf20Sopenharmony_ci		 */
2518c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
2528c2ecf20Sopenharmony_ci		ubifs_err(c, "dead directory entry '%pd', error %d",
2538c2ecf20Sopenharmony_ci			  dentry, err);
2548c2ecf20Sopenharmony_ci		ubifs_ro_mode(c, err);
2558c2ecf20Sopenharmony_ci		goto done;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(dir) &&
2598c2ecf20Sopenharmony_ci	    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
2608c2ecf20Sopenharmony_ci	    !fscrypt_has_permitted_context(dir, inode)) {
2618c2ecf20Sopenharmony_ci		ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu",
2628c2ecf20Sopenharmony_ci			   dir->i_ino, inode->i_ino);
2638c2ecf20Sopenharmony_ci		iput(inode);
2648c2ecf20Sopenharmony_ci		inode = ERR_PTR(-EPERM);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cidone:
2688c2ecf20Sopenharmony_ci	kfree(dent);
2698c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
2708c2ecf20Sopenharmony_ci	return d_splice_alias(inode, dentry);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int ubifs_prepare_create(struct inode *dir, struct dentry *dentry,
2748c2ecf20Sopenharmony_ci				struct fscrypt_name *nm)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	if (fscrypt_is_nokey_name(dentry))
2778c2ecf20Sopenharmony_ci		return -ENOKEY;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return fscrypt_setup_filename(dir, &dentry->d_name, 0, nm);
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
2838c2ecf20Sopenharmony_ci			bool excl)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct inode *inode;
2868c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
2878c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
2888c2ecf20Sopenharmony_ci					.dirtied_ino = 1 };
2898c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
2908c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
2918c2ecf20Sopenharmony_ci	int err, sz_change;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	/*
2948c2ecf20Sopenharmony_ci	 * Budget request settings: new inode, new direntry, changing the
2958c2ecf20Sopenharmony_ci	 * parent directory inode.
2968c2ecf20Sopenharmony_ci	 */
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
2998c2ecf20Sopenharmony_ci		dentry, mode, dir->i_ino);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
3028c2ecf20Sopenharmony_ci	if (err)
3038c2ecf20Sopenharmony_ci		return err;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	err = ubifs_prepare_create(dir, dentry, &nm);
3068c2ecf20Sopenharmony_ci	if (err)
3078c2ecf20Sopenharmony_ci		goto out_budg;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, mode);
3128c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
3138c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
3148c2ecf20Sopenharmony_ci		goto out_fname;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
3188c2ecf20Sopenharmony_ci	if (err)
3198c2ecf20Sopenharmony_ci		goto out_inode;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	mutex_lock(&dir_ui->ui_mutex);
3228c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
3238c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
3248c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
3258c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
3268c2ecf20Sopenharmony_ci	if (err)
3278c2ecf20Sopenharmony_ci		goto out_cancel;
3288c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
3318c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
3328c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
3338c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ciout_cancel:
3378c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
3388c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
3398c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
3408c2ecf20Sopenharmony_ciout_inode:
3418c2ecf20Sopenharmony_ci	make_bad_inode(inode);
3428c2ecf20Sopenharmony_ci	iput(inode);
3438c2ecf20Sopenharmony_ciout_fname:
3448c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
3458c2ecf20Sopenharmony_ciout_budg:
3468c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
3478c2ecf20Sopenharmony_ci	ubifs_err(c, "cannot create regular file, error %d", err);
3488c2ecf20Sopenharmony_ci	return err;
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	int err;
3548c2ecf20Sopenharmony_ci	umode_t mode = S_IFCHR | WHITEOUT_MODE;
3558c2ecf20Sopenharmony_ci	struct inode *inode;
3568c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
3578c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/*
3608c2ecf20Sopenharmony_ci	 * Create an inode('nlink = 1') for whiteout without updating journal,
3618c2ecf20Sopenharmony_ci	 * let ubifs_jnl_rename() store it on flash to complete rename whiteout
3628c2ecf20Sopenharmony_ci	 * atomically.
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
3668c2ecf20Sopenharmony_ci		dentry, mode, dir->i_ino);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
3698c2ecf20Sopenharmony_ci	if (err)
3708c2ecf20Sopenharmony_ci		return ERR_PTR(err);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, mode);
3738c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
3748c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
3758c2ecf20Sopenharmony_ci		goto out_free;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
3798c2ecf20Sopenharmony_ci	ubifs_assert(c, inode->i_op == &ubifs_file_inode_operations);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
3828c2ecf20Sopenharmony_ci	if (err)
3838c2ecf20Sopenharmony_ci		goto out_inode;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* The dir size is updated by do_rename. */
3868c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return inode;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciout_inode:
3918c2ecf20Sopenharmony_ci	make_bad_inode(inode);
3928c2ecf20Sopenharmony_ci	iput(inode);
3938c2ecf20Sopenharmony_ciout_free:
3948c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
3958c2ecf20Sopenharmony_ci	ubifs_err(c, "cannot create whiteout file, error %d", err);
3968c2ecf20Sopenharmony_ci	return ERR_PTR(err);
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci/**
4008c2ecf20Sopenharmony_ci * lock_2_inodes - a wrapper for locking two UBIFS inodes.
4018c2ecf20Sopenharmony_ci * @inode1: first inode
4028c2ecf20Sopenharmony_ci * @inode2: second inode
4038c2ecf20Sopenharmony_ci *
4048c2ecf20Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because
4058c2ecf20Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple
4068c2ecf20Sopenharmony_ci * wrapper function.
4078c2ecf20Sopenharmony_ci */
4088c2ecf20Sopenharmony_cistatic void lock_2_inodes(struct inode *inode1, struct inode *inode2)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
4118c2ecf20Sopenharmony_ci	mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/**
4158c2ecf20Sopenharmony_ci * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes.
4168c2ecf20Sopenharmony_ci * @inode1: first inode
4178c2ecf20Sopenharmony_ci * @inode2: second inode
4188c2ecf20Sopenharmony_ci */
4198c2ecf20Sopenharmony_cistatic void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
4228c2ecf20Sopenharmony_ci	mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
4268c2ecf20Sopenharmony_ci			 umode_t mode)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	struct inode *inode;
4298c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
4308c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
4318c2ecf20Sopenharmony_ci					.dirtied_ino = 1};
4328c2ecf20Sopenharmony_ci	struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
4338c2ecf20Sopenharmony_ci	struct ubifs_inode *ui;
4348c2ecf20Sopenharmony_ci	int err, instantiated = 0;
4358c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	/*
4388c2ecf20Sopenharmony_ci	 * Budget request settings: new inode, new direntry, changing the
4398c2ecf20Sopenharmony_ci	 * parent directory inode.
4408c2ecf20Sopenharmony_ci	 * Allocate budget separately for new dirtied inode, the budget will
4418c2ecf20Sopenharmony_ci	 * be released via writeback.
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
4458c2ecf20Sopenharmony_ci		dentry, mode, dir->i_ino);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
4488c2ecf20Sopenharmony_ci	if (err)
4498c2ecf20Sopenharmony_ci		return err;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
4528c2ecf20Sopenharmony_ci	if (err) {
4538c2ecf20Sopenharmony_ci		fscrypt_free_filename(&nm);
4548c2ecf20Sopenharmony_ci		return err;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &ino_req);
4588c2ecf20Sopenharmony_ci	if (err) {
4598c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
4608c2ecf20Sopenharmony_ci		fscrypt_free_filename(&nm);
4618c2ecf20Sopenharmony_ci		return err;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, mode);
4658c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
4668c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
4678c2ecf20Sopenharmony_ci		goto out_budg;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci	ui = ubifs_inode(inode);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
4728c2ecf20Sopenharmony_ci	if (err)
4738c2ecf20Sopenharmony_ci		goto out_inode;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	mutex_lock(&ui->ui_mutex);
4768c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
4778c2ecf20Sopenharmony_ci	d_tmpfile(dentry, inode);
4788c2ecf20Sopenharmony_ci	ubifs_assert(c, ui->dirty);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	instantiated = 1;
4818c2ecf20Sopenharmony_ci	mutex_unlock(&ui->ui_mutex);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	lock_2_inodes(dir, inode);
4848c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
4858c2ecf20Sopenharmony_ci	if (err)
4868c2ecf20Sopenharmony_ci		goto out_cancel;
4878c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
4908c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ciout_cancel:
4958c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
4968c2ecf20Sopenharmony_ciout_inode:
4978c2ecf20Sopenharmony_ci	make_bad_inode(inode);
4988c2ecf20Sopenharmony_ci	if (!instantiated)
4998c2ecf20Sopenharmony_ci		iput(inode);
5008c2ecf20Sopenharmony_ciout_budg:
5018c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
5028c2ecf20Sopenharmony_ci	if (!instantiated)
5038c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &ino_req);
5048c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
5058c2ecf20Sopenharmony_ci	ubifs_err(c, "cannot create temporary file, error %d", err);
5068c2ecf20Sopenharmony_ci	return err;
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci/**
5108c2ecf20Sopenharmony_ci * vfs_dent_type - get VFS directory entry type.
5118c2ecf20Sopenharmony_ci * @type: UBIFS directory entry type
5128c2ecf20Sopenharmony_ci *
5138c2ecf20Sopenharmony_ci * This function converts UBIFS directory entry type into VFS directory entry
5148c2ecf20Sopenharmony_ci * type.
5158c2ecf20Sopenharmony_ci */
5168c2ecf20Sopenharmony_cistatic unsigned int vfs_dent_type(uint8_t type)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	switch (type) {
5198c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_REG:
5208c2ecf20Sopenharmony_ci		return DT_REG;
5218c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_DIR:
5228c2ecf20Sopenharmony_ci		return DT_DIR;
5238c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_LNK:
5248c2ecf20Sopenharmony_ci		return DT_LNK;
5258c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_BLK:
5268c2ecf20Sopenharmony_ci		return DT_BLK;
5278c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_CHR:
5288c2ecf20Sopenharmony_ci		return DT_CHR;
5298c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_FIFO:
5308c2ecf20Sopenharmony_ci		return DT_FIFO;
5318c2ecf20Sopenharmony_ci	case UBIFS_ITYPE_SOCK:
5328c2ecf20Sopenharmony_ci		return DT_SOCK;
5338c2ecf20Sopenharmony_ci	default:
5348c2ecf20Sopenharmony_ci		BUG();
5358c2ecf20Sopenharmony_ci	}
5368c2ecf20Sopenharmony_ci	return 0;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci/*
5408c2ecf20Sopenharmony_ci * The classical Unix view for directory is that it is a linear array of
5418c2ecf20Sopenharmony_ci * (name, inode number) entries. Linux/VFS assumes this model as well.
5428c2ecf20Sopenharmony_ci * Particularly, 'readdir()' call wants us to return a directory entry offset
5438c2ecf20Sopenharmony_ci * which later may be used to continue 'readdir()'ing the directory or to
5448c2ecf20Sopenharmony_ci * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this
5458c2ecf20Sopenharmony_ci * model because directory entries are identified by keys, which may collide.
5468c2ecf20Sopenharmony_ci *
5478c2ecf20Sopenharmony_ci * UBIFS uses directory entry hash value for directory offsets, so
5488c2ecf20Sopenharmony_ci * 'seekdir()'/'telldir()' may not always work because of possible key
5498c2ecf20Sopenharmony_ci * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work
5508c2ecf20Sopenharmony_ci * properly by means of saving full directory entry name in the private field
5518c2ecf20Sopenharmony_ci * of the file description object.
5528c2ecf20Sopenharmony_ci *
5538c2ecf20Sopenharmony_ci * This means that UBIFS cannot support NFS which requires full
5548c2ecf20Sopenharmony_ci * 'seekdir()'/'telldir()' support.
5558c2ecf20Sopenharmony_ci */
5568c2ecf20Sopenharmony_cistatic int ubifs_readdir(struct file *file, struct dir_context *ctx)
5578c2ecf20Sopenharmony_ci{
5588c2ecf20Sopenharmony_ci	int fstr_real_len = 0, err = 0;
5598c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
5608c2ecf20Sopenharmony_ci	struct fscrypt_str fstr = {0};
5618c2ecf20Sopenharmony_ci	union ubifs_key key;
5628c2ecf20Sopenharmony_ci	struct ubifs_dent_node *dent;
5638c2ecf20Sopenharmony_ci	struct inode *dir = file_inode(file);
5648c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
5658c2ecf20Sopenharmony_ci	bool encrypted = IS_ENCRYPTED(dir);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2)
5708c2ecf20Sopenharmony_ci		/*
5718c2ecf20Sopenharmony_ci		 * The directory was seek'ed to a senseless position or there
5728c2ecf20Sopenharmony_ci		 * are no more entries.
5738c2ecf20Sopenharmony_ci		 */
5748c2ecf20Sopenharmony_ci		return 0;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (encrypted) {
5778c2ecf20Sopenharmony_ci		err = fscrypt_get_encryption_info(dir);
5788c2ecf20Sopenharmony_ci		if (err)
5798c2ecf20Sopenharmony_ci			return err;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		err = fscrypt_fname_alloc_buffer(UBIFS_MAX_NLEN, &fstr);
5828c2ecf20Sopenharmony_ci		if (err)
5838c2ecf20Sopenharmony_ci			return err;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		fstr_real_len = fstr.len;
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (file->f_version == 0) {
5898c2ecf20Sopenharmony_ci		/*
5908c2ecf20Sopenharmony_ci		 * The file was seek'ed, which means that @file->private_data
5918c2ecf20Sopenharmony_ci		 * is now invalid. This may also be just the first
5928c2ecf20Sopenharmony_ci		 * 'ubifs_readdir()' invocation, in which case
5938c2ecf20Sopenharmony_ci		 * @file->private_data is NULL, and the below code is
5948c2ecf20Sopenharmony_ci		 * basically a no-op.
5958c2ecf20Sopenharmony_ci		 */
5968c2ecf20Sopenharmony_ci		kfree(file->private_data);
5978c2ecf20Sopenharmony_ci		file->private_data = NULL;
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/*
6018c2ecf20Sopenharmony_ci	 * 'generic_file_llseek()' unconditionally sets @file->f_version to
6028c2ecf20Sopenharmony_ci	 * zero, and we use this for detecting whether the file was seek'ed.
6038c2ecf20Sopenharmony_ci	 */
6048c2ecf20Sopenharmony_ci	file->f_version = 1;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* File positions 0 and 1 correspond to "." and ".." */
6078c2ecf20Sopenharmony_ci	if (ctx->pos < 2) {
6088c2ecf20Sopenharmony_ci		ubifs_assert(c, !file->private_data);
6098c2ecf20Sopenharmony_ci		if (!dir_emit_dots(file, ctx)) {
6108c2ecf20Sopenharmony_ci			if (encrypted)
6118c2ecf20Sopenharmony_ci				fscrypt_fname_free_buffer(&fstr);
6128c2ecf20Sopenharmony_ci			return 0;
6138c2ecf20Sopenharmony_ci		}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		/* Find the first entry in TNC and save it */
6168c2ecf20Sopenharmony_ci		lowest_dent_key(c, &key, dir->i_ino);
6178c2ecf20Sopenharmony_ci		fname_len(&nm) = 0;
6188c2ecf20Sopenharmony_ci		dent = ubifs_tnc_next_ent(c, &key, &nm);
6198c2ecf20Sopenharmony_ci		if (IS_ERR(dent)) {
6208c2ecf20Sopenharmony_ci			err = PTR_ERR(dent);
6218c2ecf20Sopenharmony_ci			goto out;
6228c2ecf20Sopenharmony_ci		}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		ctx->pos = key_hash_flash(c, &dent->key);
6258c2ecf20Sopenharmony_ci		file->private_data = dent;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	dent = file->private_data;
6298c2ecf20Sopenharmony_ci	if (!dent) {
6308c2ecf20Sopenharmony_ci		/*
6318c2ecf20Sopenharmony_ci		 * The directory was seek'ed to and is now readdir'ed.
6328c2ecf20Sopenharmony_ci		 * Find the entry corresponding to @ctx->pos or the closest one.
6338c2ecf20Sopenharmony_ci		 */
6348c2ecf20Sopenharmony_ci		dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
6358c2ecf20Sopenharmony_ci		fname_len(&nm) = 0;
6368c2ecf20Sopenharmony_ci		dent = ubifs_tnc_next_ent(c, &key, &nm);
6378c2ecf20Sopenharmony_ci		if (IS_ERR(dent)) {
6388c2ecf20Sopenharmony_ci			err = PTR_ERR(dent);
6398c2ecf20Sopenharmony_ci			goto out;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci		ctx->pos = key_hash_flash(c, &dent->key);
6428c2ecf20Sopenharmony_ci		file->private_data = dent;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	while (1) {
6468c2ecf20Sopenharmony_ci		dbg_gen("ino %llu, new f_pos %#x",
6478c2ecf20Sopenharmony_ci			(unsigned long long)le64_to_cpu(dent->inum),
6488c2ecf20Sopenharmony_ci			key_hash_flash(c, &dent->key));
6498c2ecf20Sopenharmony_ci		ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) >
6508c2ecf20Sopenharmony_ci			     ubifs_inode(dir)->creat_sqnum);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci		fname_len(&nm) = le16_to_cpu(dent->nlen);
6538c2ecf20Sopenharmony_ci		fname_name(&nm) = dent->name;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		if (encrypted) {
6568c2ecf20Sopenharmony_ci			fstr.len = fstr_real_len;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci			err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
6598c2ecf20Sopenharmony_ci							&dent->key),
6608c2ecf20Sopenharmony_ci							le32_to_cpu(dent->cookie),
6618c2ecf20Sopenharmony_ci							&nm.disk_name, &fstr);
6628c2ecf20Sopenharmony_ci			if (err)
6638c2ecf20Sopenharmony_ci				goto out;
6648c2ecf20Sopenharmony_ci		} else {
6658c2ecf20Sopenharmony_ci			fstr.len = fname_len(&nm);
6668c2ecf20Sopenharmony_ci			fstr.name = fname_name(&nm);
6678c2ecf20Sopenharmony_ci		}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci		if (!dir_emit(ctx, fstr.name, fstr.len,
6708c2ecf20Sopenharmony_ci			       le64_to_cpu(dent->inum),
6718c2ecf20Sopenharmony_ci			       vfs_dent_type(dent->type))) {
6728c2ecf20Sopenharmony_ci			if (encrypted)
6738c2ecf20Sopenharmony_ci				fscrypt_fname_free_buffer(&fstr);
6748c2ecf20Sopenharmony_ci			return 0;
6758c2ecf20Sopenharmony_ci		}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		/* Switch to the next entry */
6788c2ecf20Sopenharmony_ci		key_read(c, &dent->key, &key);
6798c2ecf20Sopenharmony_ci		dent = ubifs_tnc_next_ent(c, &key, &nm);
6808c2ecf20Sopenharmony_ci		if (IS_ERR(dent)) {
6818c2ecf20Sopenharmony_ci			err = PTR_ERR(dent);
6828c2ecf20Sopenharmony_ci			goto out;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		kfree(file->private_data);
6868c2ecf20Sopenharmony_ci		ctx->pos = key_hash_flash(c, &dent->key);
6878c2ecf20Sopenharmony_ci		file->private_data = dent;
6888c2ecf20Sopenharmony_ci		cond_resched();
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ciout:
6928c2ecf20Sopenharmony_ci	kfree(file->private_data);
6938c2ecf20Sopenharmony_ci	file->private_data = NULL;
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	if (encrypted)
6968c2ecf20Sopenharmony_ci		fscrypt_fname_free_buffer(&fstr);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	if (err != -ENOENT)
6998c2ecf20Sopenharmony_ci		ubifs_err(c, "cannot find next direntry, error %d", err);
7008c2ecf20Sopenharmony_ci	else
7018c2ecf20Sopenharmony_ci		/*
7028c2ecf20Sopenharmony_ci		 * -ENOENT is a non-fatal error in this context, the TNC uses
7038c2ecf20Sopenharmony_ci		 * it to indicate that the cursor moved past the current directory
7048c2ecf20Sopenharmony_ci		 * and readdir() has to stop.
7058c2ecf20Sopenharmony_ci		 */
7068c2ecf20Sopenharmony_ci		err = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	/* 2 is a special value indicating that there are no more direntries */
7108c2ecf20Sopenharmony_ci	ctx->pos = 2;
7118c2ecf20Sopenharmony_ci	return err;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/* Free saved readdir() state when the directory is closed */
7158c2ecf20Sopenharmony_cistatic int ubifs_dir_release(struct inode *dir, struct file *file)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	kfree(file->private_data);
7188c2ecf20Sopenharmony_ci	file->private_data = NULL;
7198c2ecf20Sopenharmony_ci	return 0;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic int ubifs_link(struct dentry *old_dentry, struct inode *dir,
7238c2ecf20Sopenharmony_ci		      struct dentry *dentry)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
7268c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(old_dentry);
7278c2ecf20Sopenharmony_ci	struct ubifs_inode *ui = ubifs_inode(inode);
7288c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
7298c2ecf20Sopenharmony_ci	int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len);
7308c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2,
7318c2ecf20Sopenharmony_ci				.dirtied_ino_d = ALIGN(ui->data_len, 8) };
7328c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/*
7358c2ecf20Sopenharmony_ci	 * Budget request settings: new direntry, changing the target inode,
7368c2ecf20Sopenharmony_ci	 * changing the parent inode.
7378c2ecf20Sopenharmony_ci	 */
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu",
7408c2ecf20Sopenharmony_ci		dentry, inode->i_ino,
7418c2ecf20Sopenharmony_ci		inode->i_nlink, dir->i_ino);
7428c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(dir));
7438c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(inode));
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	err = fscrypt_prepare_link(old_dentry, dir, dentry);
7468c2ecf20Sopenharmony_ci	if (err)
7478c2ecf20Sopenharmony_ci		return err;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
7508c2ecf20Sopenharmony_ci	if (err)
7518c2ecf20Sopenharmony_ci		return err;
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	err = dbg_check_synced_i_size(c, inode);
7548c2ecf20Sopenharmony_ci	if (err)
7558c2ecf20Sopenharmony_ci		goto out_fname;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
7588c2ecf20Sopenharmony_ci	if (err)
7598c2ecf20Sopenharmony_ci		goto out_fname;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	lock_2_inodes(dir, inode);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	/* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */
7648c2ecf20Sopenharmony_ci	if (inode->i_nlink == 0)
7658c2ecf20Sopenharmony_ci		ubifs_delete_orphan(c, inode->i_ino);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	inc_nlink(inode);
7688c2ecf20Sopenharmony_ci	ihold(inode);
7698c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
7708c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
7718c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
7728c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
7738c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
7748c2ecf20Sopenharmony_ci	if (err)
7758c2ecf20Sopenharmony_ci		goto out_cancel;
7768c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
7798c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
7808c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
7818c2ecf20Sopenharmony_ci	return 0;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ciout_cancel:
7848c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
7858c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
7868c2ecf20Sopenharmony_ci	drop_nlink(inode);
7878c2ecf20Sopenharmony_ci	if (inode->i_nlink == 0)
7888c2ecf20Sopenharmony_ci		ubifs_add_orphan(c, inode->i_ino);
7898c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
7908c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
7918c2ecf20Sopenharmony_ci	iput(inode);
7928c2ecf20Sopenharmony_ciout_fname:
7938c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
7948c2ecf20Sopenharmony_ci	return err;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic int ubifs_unlink(struct inode *dir, struct dentry *dentry)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
8008c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
8018c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
8028c2ecf20Sopenharmony_ci	int err, sz_change, budgeted = 1;
8038c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
8048c2ecf20Sopenharmony_ci	unsigned int saved_nlink = inode->i_nlink;
8058c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/*
8088c2ecf20Sopenharmony_ci	 * Budget request settings: deletion direntry, deletion inode (+1 for
8098c2ecf20Sopenharmony_ci	 * @dirtied_ino), changing the parent directory inode. If budgeting
8108c2ecf20Sopenharmony_ci	 * fails, go ahead anyway because we have extra space reserved for
8118c2ecf20Sopenharmony_ci	 * deletions.
8128c2ecf20Sopenharmony_ci	 */
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu",
8158c2ecf20Sopenharmony_ci		dentry, inode->i_ino,
8168c2ecf20Sopenharmony_ci		inode->i_nlink, dir->i_ino);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
8198c2ecf20Sopenharmony_ci	if (err)
8208c2ecf20Sopenharmony_ci		return err;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	err = ubifs_purge_xattrs(inode);
8238c2ecf20Sopenharmony_ci	if (err)
8248c2ecf20Sopenharmony_ci		return err;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(dir));
8298c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(inode));
8308c2ecf20Sopenharmony_ci	err = dbg_check_synced_i_size(c, inode);
8318c2ecf20Sopenharmony_ci	if (err)
8328c2ecf20Sopenharmony_ci		goto out_fname;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
8358c2ecf20Sopenharmony_ci	if (err) {
8368c2ecf20Sopenharmony_ci		if (err != -ENOSPC)
8378c2ecf20Sopenharmony_ci			goto out_fname;
8388c2ecf20Sopenharmony_ci		budgeted = 0;
8398c2ecf20Sopenharmony_ci	}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	lock_2_inodes(dir, inode);
8428c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(dir);
8438c2ecf20Sopenharmony_ci	drop_nlink(inode);
8448c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
8458c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
8468c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
8478c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
8488c2ecf20Sopenharmony_ci	if (err)
8498c2ecf20Sopenharmony_ci		goto out_cancel;
8508c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (budgeted)
8538c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
8548c2ecf20Sopenharmony_ci	else {
8558c2ecf20Sopenharmony_ci		/* We've deleted something - clean the "no space" flags */
8568c2ecf20Sopenharmony_ci		c->bi.nospace = c->bi.nospace_rp = 0;
8578c2ecf20Sopenharmony_ci		smp_wmb();
8588c2ecf20Sopenharmony_ci	}
8598c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
8608c2ecf20Sopenharmony_ci	return 0;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ciout_cancel:
8638c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
8648c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
8658c2ecf20Sopenharmony_ci	set_nlink(inode, saved_nlink);
8668c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
8678c2ecf20Sopenharmony_ci	if (budgeted)
8688c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
8698c2ecf20Sopenharmony_ciout_fname:
8708c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
8718c2ecf20Sopenharmony_ci	return err;
8728c2ecf20Sopenharmony_ci}
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci/**
8758c2ecf20Sopenharmony_ci * check_dir_empty - check if a directory is empty or not.
8768c2ecf20Sopenharmony_ci * @dir: VFS inode object of the directory to check
8778c2ecf20Sopenharmony_ci *
8788c2ecf20Sopenharmony_ci * This function checks if directory @dir is empty. Returns zero if the
8798c2ecf20Sopenharmony_ci * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes
8808c2ecf20Sopenharmony_ci * in case of of errors.
8818c2ecf20Sopenharmony_ci */
8828c2ecf20Sopenharmony_ciint ubifs_check_dir_empty(struct inode *dir)
8838c2ecf20Sopenharmony_ci{
8848c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
8858c2ecf20Sopenharmony_ci	struct fscrypt_name nm = { 0 };
8868c2ecf20Sopenharmony_ci	struct ubifs_dent_node *dent;
8878c2ecf20Sopenharmony_ci	union ubifs_key key;
8888c2ecf20Sopenharmony_ci	int err;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	lowest_dent_key(c, &key, dir->i_ino);
8918c2ecf20Sopenharmony_ci	dent = ubifs_tnc_next_ent(c, &key, &nm);
8928c2ecf20Sopenharmony_ci	if (IS_ERR(dent)) {
8938c2ecf20Sopenharmony_ci		err = PTR_ERR(dent);
8948c2ecf20Sopenharmony_ci		if (err == -ENOENT)
8958c2ecf20Sopenharmony_ci			err = 0;
8968c2ecf20Sopenharmony_ci	} else {
8978c2ecf20Sopenharmony_ci		kfree(dent);
8988c2ecf20Sopenharmony_ci		err = -ENOTEMPTY;
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci	return err;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_cistatic int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
9068c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
9078c2ecf20Sopenharmony_ci	int err, sz_change, budgeted = 1;
9088c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
9098c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
9108c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/*
9138c2ecf20Sopenharmony_ci	 * Budget request settings: deletion direntry, deletion inode and
9148c2ecf20Sopenharmony_ci	 * changing the parent inode. If budgeting fails, go ahead anyway
9158c2ecf20Sopenharmony_ci	 * because we have extra space reserved for deletions.
9168c2ecf20Sopenharmony_ci	 */
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	dbg_gen("directory '%pd', ino %lu in dir ino %lu", dentry,
9198c2ecf20Sopenharmony_ci		inode->i_ino, dir->i_ino);
9208c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(dir));
9218c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(inode));
9228c2ecf20Sopenharmony_ci	err = ubifs_check_dir_empty(d_inode(dentry));
9238c2ecf20Sopenharmony_ci	if (err)
9248c2ecf20Sopenharmony_ci		return err;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
9278c2ecf20Sopenharmony_ci	if (err)
9288c2ecf20Sopenharmony_ci		return err;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	err = ubifs_purge_xattrs(inode);
9318c2ecf20Sopenharmony_ci	if (err)
9328c2ecf20Sopenharmony_ci		return err;
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
9378c2ecf20Sopenharmony_ci	if (err) {
9388c2ecf20Sopenharmony_ci		if (err != -ENOSPC)
9398c2ecf20Sopenharmony_ci			goto out_fname;
9408c2ecf20Sopenharmony_ci		budgeted = 0;
9418c2ecf20Sopenharmony_ci	}
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	lock_2_inodes(dir, inode);
9448c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(dir);
9458c2ecf20Sopenharmony_ci	clear_nlink(inode);
9468c2ecf20Sopenharmony_ci	drop_nlink(dir);
9478c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
9488c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
9498c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
9508c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
9518c2ecf20Sopenharmony_ci	if (err)
9528c2ecf20Sopenharmony_ci		goto out_cancel;
9538c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (budgeted)
9568c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
9578c2ecf20Sopenharmony_ci	else {
9588c2ecf20Sopenharmony_ci		/* We've deleted something - clean the "no space" flags */
9598c2ecf20Sopenharmony_ci		c->bi.nospace = c->bi.nospace_rp = 0;
9608c2ecf20Sopenharmony_ci		smp_wmb();
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
9638c2ecf20Sopenharmony_ci	return 0;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ciout_cancel:
9668c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
9678c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
9688c2ecf20Sopenharmony_ci	inc_nlink(dir);
9698c2ecf20Sopenharmony_ci	set_nlink(inode, 2);
9708c2ecf20Sopenharmony_ci	unlock_2_inodes(dir, inode);
9718c2ecf20Sopenharmony_ci	if (budgeted)
9728c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
9738c2ecf20Sopenharmony_ciout_fname:
9748c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
9758c2ecf20Sopenharmony_ci	return err;
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_cistatic int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
9798c2ecf20Sopenharmony_ci{
9808c2ecf20Sopenharmony_ci	struct inode *inode;
9818c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
9828c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
9838c2ecf20Sopenharmony_ci	int err, sz_change;
9848c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
9858c2ecf20Sopenharmony_ci					.dirtied_ino = 1};
9868c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/*
9898c2ecf20Sopenharmony_ci	 * Budget request settings: new inode, new direntry and changing parent
9908c2ecf20Sopenharmony_ci	 * directory inode.
9918c2ecf20Sopenharmony_ci	 */
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
9948c2ecf20Sopenharmony_ci		dentry, mode, dir->i_ino);
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
9978c2ecf20Sopenharmony_ci	if (err)
9988c2ecf20Sopenharmony_ci		return err;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	err = ubifs_prepare_create(dir, dentry, &nm);
10018c2ecf20Sopenharmony_ci	if (err)
10028c2ecf20Sopenharmony_ci		goto out_budg;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, S_IFDIR | mode);
10078c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
10088c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
10098c2ecf20Sopenharmony_ci		goto out_fname;
10108c2ecf20Sopenharmony_ci	}
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
10138c2ecf20Sopenharmony_ci	if (err)
10148c2ecf20Sopenharmony_ci		goto out_inode;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	mutex_lock(&dir_ui->ui_mutex);
10178c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
10188c2ecf20Sopenharmony_ci	inc_nlink(inode);
10198c2ecf20Sopenharmony_ci	inc_nlink(dir);
10208c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
10218c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
10228c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
10238c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
10248c2ecf20Sopenharmony_ci	if (err) {
10258c2ecf20Sopenharmony_ci		ubifs_err(c, "cannot create directory, error %d", err);
10268c2ecf20Sopenharmony_ci		goto out_cancel;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
10318c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
10328c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
10338c2ecf20Sopenharmony_ci	return 0;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ciout_cancel:
10368c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
10378c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
10388c2ecf20Sopenharmony_ci	drop_nlink(dir);
10398c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
10408c2ecf20Sopenharmony_ciout_inode:
10418c2ecf20Sopenharmony_ci	make_bad_inode(inode);
10428c2ecf20Sopenharmony_ci	iput(inode);
10438c2ecf20Sopenharmony_ciout_fname:
10448c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
10458c2ecf20Sopenharmony_ciout_budg:
10468c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
10478c2ecf20Sopenharmony_ci	return err;
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic int ubifs_mknod(struct inode *dir, struct dentry *dentry,
10518c2ecf20Sopenharmony_ci		       umode_t mode, dev_t rdev)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	struct inode *inode;
10548c2ecf20Sopenharmony_ci	struct ubifs_inode *ui;
10558c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
10568c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
10578c2ecf20Sopenharmony_ci	union ubifs_dev_desc *dev = NULL;
10588c2ecf20Sopenharmony_ci	int sz_change;
10598c2ecf20Sopenharmony_ci	int err, devlen = 0;
10608c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
10618c2ecf20Sopenharmony_ci					.dirtied_ino = 1 };
10628c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	/*
10658c2ecf20Sopenharmony_ci	 * Budget request settings: new inode, new direntry and changing parent
10668c2ecf20Sopenharmony_ci	 * directory inode.
10678c2ecf20Sopenharmony_ci	 */
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	if (S_ISBLK(mode) || S_ISCHR(mode)) {
10728c2ecf20Sopenharmony_ci		dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
10738c2ecf20Sopenharmony_ci		if (!dev)
10748c2ecf20Sopenharmony_ci			return -ENOMEM;
10758c2ecf20Sopenharmony_ci		devlen = ubifs_encode_dev(dev, rdev);
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	req.new_ino_d = ALIGN(devlen, 8);
10798c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
10808c2ecf20Sopenharmony_ci	if (err) {
10818c2ecf20Sopenharmony_ci		kfree(dev);
10828c2ecf20Sopenharmony_ci		return err;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	err = ubifs_prepare_create(dir, dentry, &nm);
10868c2ecf20Sopenharmony_ci	if (err) {
10878c2ecf20Sopenharmony_ci		kfree(dev);
10888c2ecf20Sopenharmony_ci		goto out_budg;
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, mode);
10948c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
10958c2ecf20Sopenharmony_ci		kfree(dev);
10968c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
10978c2ecf20Sopenharmony_ci		goto out_fname;
10988c2ecf20Sopenharmony_ci	}
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	init_special_inode(inode, inode->i_mode, rdev);
11018c2ecf20Sopenharmony_ci	inode->i_size = ubifs_inode(inode)->ui_size = devlen;
11028c2ecf20Sopenharmony_ci	ui = ubifs_inode(inode);
11038c2ecf20Sopenharmony_ci	ui->data = dev;
11048c2ecf20Sopenharmony_ci	ui->data_len = devlen;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
11078c2ecf20Sopenharmony_ci	if (err)
11088c2ecf20Sopenharmony_ci		goto out_inode;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	mutex_lock(&dir_ui->ui_mutex);
11118c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
11128c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
11138c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
11148c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
11158c2ecf20Sopenharmony_ci	if (err)
11168c2ecf20Sopenharmony_ci		goto out_cancel;
11178c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
11208c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
11218c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
11228c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
11238c2ecf20Sopenharmony_ci	return 0;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ciout_cancel:
11268c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
11278c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
11288c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
11298c2ecf20Sopenharmony_ciout_inode:
11308c2ecf20Sopenharmony_ci	/* Free inode->i_link before inode is marked as bad. */
11318c2ecf20Sopenharmony_ci	fscrypt_free_inode(inode);
11328c2ecf20Sopenharmony_ci	make_bad_inode(inode);
11338c2ecf20Sopenharmony_ci	iput(inode);
11348c2ecf20Sopenharmony_ciout_fname:
11358c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
11368c2ecf20Sopenharmony_ciout_budg:
11378c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
11388c2ecf20Sopenharmony_ci	return err;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_cistatic int ubifs_symlink(struct inode *dir, struct dentry *dentry,
11428c2ecf20Sopenharmony_ci			 const char *symname)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	struct inode *inode;
11458c2ecf20Sopenharmony_ci	struct ubifs_inode *ui;
11468c2ecf20Sopenharmony_ci	struct ubifs_inode *dir_ui = ubifs_inode(dir);
11478c2ecf20Sopenharmony_ci	struct ubifs_info *c = dir->i_sb->s_fs_info;
11488c2ecf20Sopenharmony_ci	int err, sz_change, len = strlen(symname);
11498c2ecf20Sopenharmony_ci	struct fscrypt_str disk_link;
11508c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
11518c2ecf20Sopenharmony_ci					.dirtied_ino = 1 };
11528c2ecf20Sopenharmony_ci	struct fscrypt_name nm;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
11558c2ecf20Sopenharmony_ci		symname, dir->i_ino);
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA,
11588c2ecf20Sopenharmony_ci				      &disk_link);
11598c2ecf20Sopenharmony_ci	if (err)
11608c2ecf20Sopenharmony_ci		return err;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/*
11638c2ecf20Sopenharmony_ci	 * Budget request settings: new inode, new direntry and changing parent
11648c2ecf20Sopenharmony_ci	 * directory inode.
11658c2ecf20Sopenharmony_ci	 */
11668c2ecf20Sopenharmony_ci	req.new_ino_d = ALIGN(disk_link.len - 1, 8);
11678c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
11688c2ecf20Sopenharmony_ci	if (err)
11698c2ecf20Sopenharmony_ci		return err;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	err = ubifs_prepare_create(dir, dentry, &nm);
11728c2ecf20Sopenharmony_ci	if (err)
11738c2ecf20Sopenharmony_ci		goto out_budg;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	sz_change = CALC_DENT_SIZE(fname_len(&nm));
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO);
11788c2ecf20Sopenharmony_ci	if (IS_ERR(inode)) {
11798c2ecf20Sopenharmony_ci		err = PTR_ERR(inode);
11808c2ecf20Sopenharmony_ci		goto out_fname;
11818c2ecf20Sopenharmony_ci	}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	ui = ubifs_inode(inode);
11848c2ecf20Sopenharmony_ci	ui->data = kmalloc(disk_link.len, GFP_NOFS);
11858c2ecf20Sopenharmony_ci	if (!ui->data) {
11868c2ecf20Sopenharmony_ci		err = -ENOMEM;
11878c2ecf20Sopenharmony_ci		goto out_inode;
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(inode)) {
11918c2ecf20Sopenharmony_ci		disk_link.name = ui->data; /* encrypt directly into ui->data */
11928c2ecf20Sopenharmony_ci		err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
11938c2ecf20Sopenharmony_ci		if (err)
11948c2ecf20Sopenharmony_ci			goto out_inode;
11958c2ecf20Sopenharmony_ci	} else {
11968c2ecf20Sopenharmony_ci		memcpy(ui->data, disk_link.name, disk_link.len);
11978c2ecf20Sopenharmony_ci		inode->i_link = ui->data;
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	/*
12018c2ecf20Sopenharmony_ci	 * The terminating zero byte is not written to the flash media and it
12028c2ecf20Sopenharmony_ci	 * is put just to make later in-memory string processing simpler. Thus,
12038c2ecf20Sopenharmony_ci	 * data length is @disk_link.len - 1, not @disk_link.len.
12048c2ecf20Sopenharmony_ci	 */
12058c2ecf20Sopenharmony_ci	ui->data_len = disk_link.len - 1;
12068c2ecf20Sopenharmony_ci	inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	err = ubifs_init_security(dir, inode, &dentry->d_name);
12098c2ecf20Sopenharmony_ci	if (err)
12108c2ecf20Sopenharmony_ci		goto out_inode;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	mutex_lock(&dir_ui->ui_mutex);
12138c2ecf20Sopenharmony_ci	dir->i_size += sz_change;
12148c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
12158c2ecf20Sopenharmony_ci	dir->i_mtime = dir->i_ctime = inode->i_ctime;
12168c2ecf20Sopenharmony_ci	err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
12178c2ecf20Sopenharmony_ci	if (err)
12188c2ecf20Sopenharmony_ci		goto out_cancel;
12198c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	insert_inode_hash(inode);
12228c2ecf20Sopenharmony_ci	d_instantiate(dentry, inode);
12238c2ecf20Sopenharmony_ci	err = 0;
12248c2ecf20Sopenharmony_ci	goto out_fname;
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ciout_cancel:
12278c2ecf20Sopenharmony_ci	dir->i_size -= sz_change;
12288c2ecf20Sopenharmony_ci	dir_ui->ui_size = dir->i_size;
12298c2ecf20Sopenharmony_ci	mutex_unlock(&dir_ui->ui_mutex);
12308c2ecf20Sopenharmony_ciout_inode:
12318c2ecf20Sopenharmony_ci	/* Free inode->i_link before inode is marked as bad. */
12328c2ecf20Sopenharmony_ci	fscrypt_free_inode(inode);
12338c2ecf20Sopenharmony_ci	make_bad_inode(inode);
12348c2ecf20Sopenharmony_ci	iput(inode);
12358c2ecf20Sopenharmony_ciout_fname:
12368c2ecf20Sopenharmony_ci	fscrypt_free_filename(&nm);
12378c2ecf20Sopenharmony_ciout_budg:
12388c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
12398c2ecf20Sopenharmony_ci	return err;
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci/**
12438c2ecf20Sopenharmony_ci * lock_4_inodes - a wrapper for locking three UBIFS inodes.
12448c2ecf20Sopenharmony_ci * @inode1: first inode
12458c2ecf20Sopenharmony_ci * @inode2: second inode
12468c2ecf20Sopenharmony_ci * @inode3: third inode
12478c2ecf20Sopenharmony_ci * @inode4: fouth inode
12488c2ecf20Sopenharmony_ci *
12498c2ecf20Sopenharmony_ci * This function is used for 'ubifs_rename()' and @inode1 may be the same as
12508c2ecf20Sopenharmony_ci * @inode2 whereas @inode3 and @inode4 may be %NULL.
12518c2ecf20Sopenharmony_ci *
12528c2ecf20Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because
12538c2ecf20Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple
12548c2ecf20Sopenharmony_ci * wrapper function.
12558c2ecf20Sopenharmony_ci */
12568c2ecf20Sopenharmony_cistatic void lock_4_inodes(struct inode *inode1, struct inode *inode2,
12578c2ecf20Sopenharmony_ci			  struct inode *inode3, struct inode *inode4)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
12608c2ecf20Sopenharmony_ci	if (inode2 != inode1)
12618c2ecf20Sopenharmony_ci		mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
12628c2ecf20Sopenharmony_ci	if (inode3)
12638c2ecf20Sopenharmony_ci		mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3);
12648c2ecf20Sopenharmony_ci	if (inode4)
12658c2ecf20Sopenharmony_ci		mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4);
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci/**
12698c2ecf20Sopenharmony_ci * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename.
12708c2ecf20Sopenharmony_ci * @inode1: first inode
12718c2ecf20Sopenharmony_ci * @inode2: second inode
12728c2ecf20Sopenharmony_ci * @inode3: third inode
12738c2ecf20Sopenharmony_ci * @inode4: fouth inode
12748c2ecf20Sopenharmony_ci */
12758c2ecf20Sopenharmony_cistatic void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
12768c2ecf20Sopenharmony_ci			    struct inode *inode3, struct inode *inode4)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	if (inode4)
12798c2ecf20Sopenharmony_ci		mutex_unlock(&ubifs_inode(inode4)->ui_mutex);
12808c2ecf20Sopenharmony_ci	if (inode3)
12818c2ecf20Sopenharmony_ci		mutex_unlock(&ubifs_inode(inode3)->ui_mutex);
12828c2ecf20Sopenharmony_ci	if (inode1 != inode2)
12838c2ecf20Sopenharmony_ci		mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
12848c2ecf20Sopenharmony_ci	mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_cistatic int do_rename(struct inode *old_dir, struct dentry *old_dentry,
12888c2ecf20Sopenharmony_ci		     struct inode *new_dir, struct dentry *new_dentry,
12898c2ecf20Sopenharmony_ci		     unsigned int flags)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
12928c2ecf20Sopenharmony_ci	struct inode *old_inode = d_inode(old_dentry);
12938c2ecf20Sopenharmony_ci	struct inode *new_inode = d_inode(new_dentry);
12948c2ecf20Sopenharmony_ci	struct inode *whiteout = NULL;
12958c2ecf20Sopenharmony_ci	struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode);
12968c2ecf20Sopenharmony_ci	struct ubifs_inode *whiteout_ui = NULL;
12978c2ecf20Sopenharmony_ci	int err, release, sync = 0, move = (new_dir != old_dir);
12988c2ecf20Sopenharmony_ci	int is_dir = S_ISDIR(old_inode->i_mode);
12998c2ecf20Sopenharmony_ci	int unlink = !!new_inode, new_sz, old_sz;
13008c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
13018c2ecf20Sopenharmony_ci					.dirtied_ino = 3 };
13028c2ecf20Sopenharmony_ci	struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
13038c2ecf20Sopenharmony_ci			.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
13048c2ecf20Sopenharmony_ci	struct ubifs_budget_req wht_req;
13058c2ecf20Sopenharmony_ci	struct timespec64 time;
13068c2ecf20Sopenharmony_ci	unsigned int saved_nlink;
13078c2ecf20Sopenharmony_ci	struct fscrypt_name old_nm, new_nm;
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	/*
13108c2ecf20Sopenharmony_ci	 * Budget request settings:
13118c2ecf20Sopenharmony_ci	 *   req: deletion direntry, new direntry, removing the old inode,
13128c2ecf20Sopenharmony_ci	 *   and changing old and new parent directory inodes.
13138c2ecf20Sopenharmony_ci	 *
13148c2ecf20Sopenharmony_ci	 *   wht_req: new whiteout inode for RENAME_WHITEOUT.
13158c2ecf20Sopenharmony_ci	 *
13168c2ecf20Sopenharmony_ci	 *   ino_req: marks the target inode as dirty and does not write it.
13178c2ecf20Sopenharmony_ci	 */
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x",
13208c2ecf20Sopenharmony_ci		old_dentry, old_inode->i_ino, old_dir->i_ino,
13218c2ecf20Sopenharmony_ci		new_dentry, new_dir->i_ino, flags);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	if (unlink) {
13248c2ecf20Sopenharmony_ci		ubifs_assert(c, inode_is_locked(new_inode));
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci		/* Budget for old inode's data when its nlink > 1. */
13278c2ecf20Sopenharmony_ci		req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8);
13288c2ecf20Sopenharmony_ci		err = ubifs_purge_xattrs(new_inode);
13298c2ecf20Sopenharmony_ci		if (err)
13308c2ecf20Sopenharmony_ci			return err;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (unlink && is_dir) {
13348c2ecf20Sopenharmony_ci		err = ubifs_check_dir_empty(new_inode);
13358c2ecf20Sopenharmony_ci		if (err)
13368c2ecf20Sopenharmony_ci			return err;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm);
13408c2ecf20Sopenharmony_ci	if (err)
13418c2ecf20Sopenharmony_ci		return err;
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm);
13448c2ecf20Sopenharmony_ci	if (err) {
13458c2ecf20Sopenharmony_ci		fscrypt_free_filename(&old_nm);
13468c2ecf20Sopenharmony_ci		return err;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	new_sz = CALC_DENT_SIZE(fname_len(&new_nm));
13508c2ecf20Sopenharmony_ci	old_sz = CALC_DENT_SIZE(fname_len(&old_nm));
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
13538c2ecf20Sopenharmony_ci	if (err) {
13548c2ecf20Sopenharmony_ci		fscrypt_free_filename(&old_nm);
13558c2ecf20Sopenharmony_ci		fscrypt_free_filename(&new_nm);
13568c2ecf20Sopenharmony_ci		return err;
13578c2ecf20Sopenharmony_ci	}
13588c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &ino_req);
13598c2ecf20Sopenharmony_ci	if (err) {
13608c2ecf20Sopenharmony_ci		fscrypt_free_filename(&old_nm);
13618c2ecf20Sopenharmony_ci		fscrypt_free_filename(&new_nm);
13628c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &req);
13638c2ecf20Sopenharmony_ci		return err;
13648c2ecf20Sopenharmony_ci	}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	if (flags & RENAME_WHITEOUT) {
13678c2ecf20Sopenharmony_ci		union ubifs_dev_desc *dev = NULL;
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci		dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
13708c2ecf20Sopenharmony_ci		if (!dev) {
13718c2ecf20Sopenharmony_ci			err = -ENOMEM;
13728c2ecf20Sopenharmony_ci			goto out_release;
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci		/*
13768c2ecf20Sopenharmony_ci		 * The whiteout inode without dentry is pinned in memory,
13778c2ecf20Sopenharmony_ci		 * umount won't happen during rename process because we
13788c2ecf20Sopenharmony_ci		 * got parent dentry.
13798c2ecf20Sopenharmony_ci		 */
13808c2ecf20Sopenharmony_ci		whiteout = create_whiteout(old_dir, old_dentry);
13818c2ecf20Sopenharmony_ci		if (IS_ERR(whiteout)) {
13828c2ecf20Sopenharmony_ci			err = PTR_ERR(whiteout);
13838c2ecf20Sopenharmony_ci			kfree(dev);
13848c2ecf20Sopenharmony_ci			goto out_release;
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci		whiteout_ui = ubifs_inode(whiteout);
13888c2ecf20Sopenharmony_ci		whiteout_ui->data = dev;
13898c2ecf20Sopenharmony_ci		whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0));
13908c2ecf20Sopenharmony_ci		ubifs_assert(c, !whiteout_ui->dirty);
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci		memset(&wht_req, 0, sizeof(struct ubifs_budget_req));
13938c2ecf20Sopenharmony_ci		wht_req.new_ino = 1;
13948c2ecf20Sopenharmony_ci		wht_req.new_ino_d = ALIGN(whiteout_ui->data_len, 8);
13958c2ecf20Sopenharmony_ci		/*
13968c2ecf20Sopenharmony_ci		 * To avoid deadlock between space budget (holds ui_mutex and
13978c2ecf20Sopenharmony_ci		 * waits wb work) and writeback work(waits ui_mutex), do space
13988c2ecf20Sopenharmony_ci		 * budget before ubifs inodes locked.
13998c2ecf20Sopenharmony_ci		 */
14008c2ecf20Sopenharmony_ci		err = ubifs_budget_space(c, &wht_req);
14018c2ecf20Sopenharmony_ci		if (err) {
14028c2ecf20Sopenharmony_ci			/*
14038c2ecf20Sopenharmony_ci			 * Whiteout inode can not be written on flash by
14048c2ecf20Sopenharmony_ci			 * ubifs_jnl_write_inode(), because it's neither
14058c2ecf20Sopenharmony_ci			 * dirty nor zero-nlink.
14068c2ecf20Sopenharmony_ci			 */
14078c2ecf20Sopenharmony_ci			iput(whiteout);
14088c2ecf20Sopenharmony_ci			goto out_release;
14098c2ecf20Sopenharmony_ci		}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci		/* Add the old_dentry size to the old_dir size. */
14128c2ecf20Sopenharmony_ci		old_sz -= CALC_DENT_SIZE(fname_len(&old_nm));
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	lock_4_inodes(old_dir, new_dir, new_inode, whiteout);
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	/*
14188c2ecf20Sopenharmony_ci	 * Like most other Unix systems, set the @i_ctime for inodes on a
14198c2ecf20Sopenharmony_ci	 * rename.
14208c2ecf20Sopenharmony_ci	 */
14218c2ecf20Sopenharmony_ci	time = current_time(old_dir);
14228c2ecf20Sopenharmony_ci	old_inode->i_ctime = time;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	/* We must adjust parent link count when renaming directories */
14258c2ecf20Sopenharmony_ci	if (is_dir) {
14268c2ecf20Sopenharmony_ci		if (move) {
14278c2ecf20Sopenharmony_ci			/*
14288c2ecf20Sopenharmony_ci			 * @old_dir loses a link because we are moving
14298c2ecf20Sopenharmony_ci			 * @old_inode to a different directory.
14308c2ecf20Sopenharmony_ci			 */
14318c2ecf20Sopenharmony_ci			drop_nlink(old_dir);
14328c2ecf20Sopenharmony_ci			/*
14338c2ecf20Sopenharmony_ci			 * @new_dir only gains a link if we are not also
14348c2ecf20Sopenharmony_ci			 * overwriting an existing directory.
14358c2ecf20Sopenharmony_ci			 */
14368c2ecf20Sopenharmony_ci			if (!unlink)
14378c2ecf20Sopenharmony_ci				inc_nlink(new_dir);
14388c2ecf20Sopenharmony_ci		} else {
14398c2ecf20Sopenharmony_ci			/*
14408c2ecf20Sopenharmony_ci			 * @old_inode is not moving to a different directory,
14418c2ecf20Sopenharmony_ci			 * but @old_dir still loses a link if we are
14428c2ecf20Sopenharmony_ci			 * overwriting an existing directory.
14438c2ecf20Sopenharmony_ci			 */
14448c2ecf20Sopenharmony_ci			if (unlink)
14458c2ecf20Sopenharmony_ci				drop_nlink(old_dir);
14468c2ecf20Sopenharmony_ci		}
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	old_dir->i_size -= old_sz;
14508c2ecf20Sopenharmony_ci	ubifs_inode(old_dir)->ui_size = old_dir->i_size;
14518c2ecf20Sopenharmony_ci	old_dir->i_mtime = old_dir->i_ctime = time;
14528c2ecf20Sopenharmony_ci	new_dir->i_mtime = new_dir->i_ctime = time;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	/*
14558c2ecf20Sopenharmony_ci	 * And finally, if we unlinked a direntry which happened to have the
14568c2ecf20Sopenharmony_ci	 * same name as the moved direntry, we have to decrement @i_nlink of
14578c2ecf20Sopenharmony_ci	 * the unlinked inode and change its ctime.
14588c2ecf20Sopenharmony_ci	 */
14598c2ecf20Sopenharmony_ci	if (unlink) {
14608c2ecf20Sopenharmony_ci		/*
14618c2ecf20Sopenharmony_ci		 * Directories cannot have hard-links, so if this is a
14628c2ecf20Sopenharmony_ci		 * directory, just clear @i_nlink.
14638c2ecf20Sopenharmony_ci		 */
14648c2ecf20Sopenharmony_ci		saved_nlink = new_inode->i_nlink;
14658c2ecf20Sopenharmony_ci		if (is_dir)
14668c2ecf20Sopenharmony_ci			clear_nlink(new_inode);
14678c2ecf20Sopenharmony_ci		else
14688c2ecf20Sopenharmony_ci			drop_nlink(new_inode);
14698c2ecf20Sopenharmony_ci		new_inode->i_ctime = time;
14708c2ecf20Sopenharmony_ci	} else {
14718c2ecf20Sopenharmony_ci		new_dir->i_size += new_sz;
14728c2ecf20Sopenharmony_ci		ubifs_inode(new_dir)->ui_size = new_dir->i_size;
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	/*
14768c2ecf20Sopenharmony_ci	 * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode
14778c2ecf20Sopenharmony_ci	 * is dirty, because this will be done later on at the end of
14788c2ecf20Sopenharmony_ci	 * 'ubifs_rename()'.
14798c2ecf20Sopenharmony_ci	 */
14808c2ecf20Sopenharmony_ci	if (IS_SYNC(old_inode)) {
14818c2ecf20Sopenharmony_ci		sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
14828c2ecf20Sopenharmony_ci		if (unlink && IS_SYNC(new_inode))
14838c2ecf20Sopenharmony_ci			sync = 1;
14848c2ecf20Sopenharmony_ci		/*
14858c2ecf20Sopenharmony_ci		 * S_SYNC flag of whiteout inherits from the old_dir, and we
14868c2ecf20Sopenharmony_ci		 * have already checked the old dir inode. So there is no need
14878c2ecf20Sopenharmony_ci		 * to check whiteout.
14888c2ecf20Sopenharmony_ci		 */
14898c2ecf20Sopenharmony_ci	}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir,
14928c2ecf20Sopenharmony_ci			       new_inode, &new_nm, whiteout, sync);
14938c2ecf20Sopenharmony_ci	if (err)
14948c2ecf20Sopenharmony_ci		goto out_cancel;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
14978c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	if (whiteout) {
15008c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &wht_req);
15018c2ecf20Sopenharmony_ci		iput(whiteout);
15028c2ecf20Sopenharmony_ci	}
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	mutex_lock(&old_inode_ui->ui_mutex);
15058c2ecf20Sopenharmony_ci	release = old_inode_ui->dirty;
15068c2ecf20Sopenharmony_ci	mark_inode_dirty_sync(old_inode);
15078c2ecf20Sopenharmony_ci	mutex_unlock(&old_inode_ui->ui_mutex);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if (release)
15108c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &ino_req);
15118c2ecf20Sopenharmony_ci	if (IS_SYNC(old_inode))
15128c2ecf20Sopenharmony_ci		/*
15138c2ecf20Sopenharmony_ci		 * Rename finished here. Although old inode cannot be updated
15148c2ecf20Sopenharmony_ci		 * on flash, old ctime is not a big problem, don't return err
15158c2ecf20Sopenharmony_ci		 * code to userspace.
15168c2ecf20Sopenharmony_ci		 */
15178c2ecf20Sopenharmony_ci		old_inode->i_sb->s_op->write_inode(old_inode, NULL);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	fscrypt_free_filename(&old_nm);
15208c2ecf20Sopenharmony_ci	fscrypt_free_filename(&new_nm);
15218c2ecf20Sopenharmony_ci	return 0;
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ciout_cancel:
15248c2ecf20Sopenharmony_ci	if (unlink) {
15258c2ecf20Sopenharmony_ci		set_nlink(new_inode, saved_nlink);
15268c2ecf20Sopenharmony_ci	} else {
15278c2ecf20Sopenharmony_ci		new_dir->i_size -= new_sz;
15288c2ecf20Sopenharmony_ci		ubifs_inode(new_dir)->ui_size = new_dir->i_size;
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci	old_dir->i_size += old_sz;
15318c2ecf20Sopenharmony_ci	ubifs_inode(old_dir)->ui_size = old_dir->i_size;
15328c2ecf20Sopenharmony_ci	if (is_dir) {
15338c2ecf20Sopenharmony_ci		if (move) {
15348c2ecf20Sopenharmony_ci			inc_nlink(old_dir);
15358c2ecf20Sopenharmony_ci			if (!unlink)
15368c2ecf20Sopenharmony_ci				drop_nlink(new_dir);
15378c2ecf20Sopenharmony_ci		} else {
15388c2ecf20Sopenharmony_ci			if (unlink)
15398c2ecf20Sopenharmony_ci				inc_nlink(old_dir);
15408c2ecf20Sopenharmony_ci		}
15418c2ecf20Sopenharmony_ci	}
15428c2ecf20Sopenharmony_ci	unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
15438c2ecf20Sopenharmony_ci	if (whiteout) {
15448c2ecf20Sopenharmony_ci		ubifs_release_budget(c, &wht_req);
15458c2ecf20Sopenharmony_ci		iput(whiteout);
15468c2ecf20Sopenharmony_ci	}
15478c2ecf20Sopenharmony_ciout_release:
15488c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &ino_req);
15498c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
15508c2ecf20Sopenharmony_ci	fscrypt_free_filename(&old_nm);
15518c2ecf20Sopenharmony_ci	fscrypt_free_filename(&new_nm);
15528c2ecf20Sopenharmony_ci	return err;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_cistatic int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
15568c2ecf20Sopenharmony_ci			struct inode *new_dir, struct dentry *new_dentry)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
15598c2ecf20Sopenharmony_ci	struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1,
15608c2ecf20Sopenharmony_ci				.dirtied_ino = 2 };
15618c2ecf20Sopenharmony_ci	int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir);
15628c2ecf20Sopenharmony_ci	struct inode *fst_inode = d_inode(old_dentry);
15638c2ecf20Sopenharmony_ci	struct inode *snd_inode = d_inode(new_dentry);
15648c2ecf20Sopenharmony_ci	struct timespec64 time;
15658c2ecf20Sopenharmony_ci	int err;
15668c2ecf20Sopenharmony_ci	struct fscrypt_name fst_nm, snd_nm;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	ubifs_assert(c, fst_inode && snd_inode);
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm);
15718c2ecf20Sopenharmony_ci	if (err)
15728c2ecf20Sopenharmony_ci		return err;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm);
15758c2ecf20Sopenharmony_ci	if (err) {
15768c2ecf20Sopenharmony_ci		fscrypt_free_filename(&fst_nm);
15778c2ecf20Sopenharmony_ci		return err;
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	err = ubifs_budget_space(c, &req);
15818c2ecf20Sopenharmony_ci	if (err)
15828c2ecf20Sopenharmony_ci		goto out;
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	lock_4_inodes(old_dir, new_dir, NULL, NULL);
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci	time = current_time(old_dir);
15878c2ecf20Sopenharmony_ci	fst_inode->i_ctime = time;
15888c2ecf20Sopenharmony_ci	snd_inode->i_ctime = time;
15898c2ecf20Sopenharmony_ci	old_dir->i_mtime = old_dir->i_ctime = time;
15908c2ecf20Sopenharmony_ci	new_dir->i_mtime = new_dir->i_ctime = time;
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	if (old_dir != new_dir) {
15938c2ecf20Sopenharmony_ci		if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
15948c2ecf20Sopenharmony_ci			inc_nlink(new_dir);
15958c2ecf20Sopenharmony_ci			drop_nlink(old_dir);
15968c2ecf20Sopenharmony_ci		}
15978c2ecf20Sopenharmony_ci		else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
15988c2ecf20Sopenharmony_ci			drop_nlink(new_dir);
15998c2ecf20Sopenharmony_ci			inc_nlink(old_dir);
16008c2ecf20Sopenharmony_ci		}
16018c2ecf20Sopenharmony_ci	}
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir,
16048c2ecf20Sopenharmony_ci				snd_inode, &snd_nm, sync);
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	unlock_4_inodes(old_dir, new_dir, NULL, NULL);
16078c2ecf20Sopenharmony_ci	ubifs_release_budget(c, &req);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ciout:
16108c2ecf20Sopenharmony_ci	fscrypt_free_filename(&fst_nm);
16118c2ecf20Sopenharmony_ci	fscrypt_free_filename(&snd_nm);
16128c2ecf20Sopenharmony_ci	return err;
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
16168c2ecf20Sopenharmony_ci			struct inode *new_dir, struct dentry *new_dentry,
16178c2ecf20Sopenharmony_ci			unsigned int flags)
16188c2ecf20Sopenharmony_ci{
16198c2ecf20Sopenharmony_ci	int err;
16208c2ecf20Sopenharmony_ci	struct ubifs_info *c = old_dir->i_sb->s_fs_info;
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_ci	if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE))
16238c2ecf20Sopenharmony_ci		return -EINVAL;
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(old_dir));
16268c2ecf20Sopenharmony_ci	ubifs_assert(c, inode_is_locked(new_dir));
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry,
16298c2ecf20Sopenharmony_ci				     flags);
16308c2ecf20Sopenharmony_ci	if (err)
16318c2ecf20Sopenharmony_ci		return err;
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	if (flags & RENAME_EXCHANGE)
16348c2ecf20Sopenharmony_ci		return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry);
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_ci	return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags);
16378c2ecf20Sopenharmony_ci}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ciint ubifs_getattr(const struct path *path, struct kstat *stat,
16408c2ecf20Sopenharmony_ci		  u32 request_mask, unsigned int flags)
16418c2ecf20Sopenharmony_ci{
16428c2ecf20Sopenharmony_ci	loff_t size;
16438c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(path->dentry);
16448c2ecf20Sopenharmony_ci	struct ubifs_inode *ui = ubifs_inode(inode);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	mutex_lock(&ui->ui_mutex);
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	if (ui->flags & UBIFS_APPEND_FL)
16498c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_APPEND;
16508c2ecf20Sopenharmony_ci	if (ui->flags & UBIFS_COMPR_FL)
16518c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_COMPRESSED;
16528c2ecf20Sopenharmony_ci	if (ui->flags & UBIFS_CRYPT_FL)
16538c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_ENCRYPTED;
16548c2ecf20Sopenharmony_ci	if (ui->flags & UBIFS_IMMUTABLE_FL)
16558c2ecf20Sopenharmony_ci		stat->attributes |= STATX_ATTR_IMMUTABLE;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	stat->attributes_mask |= (STATX_ATTR_APPEND |
16588c2ecf20Sopenharmony_ci				STATX_ATTR_COMPRESSED |
16598c2ecf20Sopenharmony_ci				STATX_ATTR_ENCRYPTED |
16608c2ecf20Sopenharmony_ci				STATX_ATTR_IMMUTABLE);
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	generic_fillattr(inode, stat);
16638c2ecf20Sopenharmony_ci	stat->blksize = UBIFS_BLOCK_SIZE;
16648c2ecf20Sopenharmony_ci	stat->size = ui->ui_size;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	/*
16678c2ecf20Sopenharmony_ci	 * Unfortunately, the 'stat()' system call was designed for block
16688c2ecf20Sopenharmony_ci	 * device based file systems, and it is not appropriate for UBIFS,
16698c2ecf20Sopenharmony_ci	 * because UBIFS does not have notion of "block". For example, it is
16708c2ecf20Sopenharmony_ci	 * difficult to tell how many block a directory takes - it actually
16718c2ecf20Sopenharmony_ci	 * takes less than 300 bytes, but we have to round it to block size,
16728c2ecf20Sopenharmony_ci	 * which introduces large mistake. This makes utilities like 'du' to
16738c2ecf20Sopenharmony_ci	 * report completely senseless numbers. This is the reason why UBIFS
16748c2ecf20Sopenharmony_ci	 * goes the same way as JFFS2 - it reports zero blocks for everything
16758c2ecf20Sopenharmony_ci	 * but regular files, which makes more sense than reporting completely
16768c2ecf20Sopenharmony_ci	 * wrong sizes.
16778c2ecf20Sopenharmony_ci	 */
16788c2ecf20Sopenharmony_ci	if (S_ISREG(inode->i_mode)) {
16798c2ecf20Sopenharmony_ci		size = ui->xattr_size;
16808c2ecf20Sopenharmony_ci		size += stat->size;
16818c2ecf20Sopenharmony_ci		size = ALIGN(size, UBIFS_BLOCK_SIZE);
16828c2ecf20Sopenharmony_ci		/*
16838c2ecf20Sopenharmony_ci		 * Note, user-space expects 512-byte blocks count irrespectively
16848c2ecf20Sopenharmony_ci		 * of what was reported in @stat->size.
16858c2ecf20Sopenharmony_ci		 */
16868c2ecf20Sopenharmony_ci		stat->blocks = size >> 9;
16878c2ecf20Sopenharmony_ci	} else
16888c2ecf20Sopenharmony_ci		stat->blocks = 0;
16898c2ecf20Sopenharmony_ci	mutex_unlock(&ui->ui_mutex);
16908c2ecf20Sopenharmony_ci	return 0;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_cistatic int ubifs_dir_open(struct inode *dir, struct file *file)
16948c2ecf20Sopenharmony_ci{
16958c2ecf20Sopenharmony_ci	if (IS_ENCRYPTED(dir))
16968c2ecf20Sopenharmony_ci		return fscrypt_get_encryption_info(dir) ? -EACCES : 0;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	return 0;
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ciconst struct inode_operations ubifs_dir_inode_operations = {
17028c2ecf20Sopenharmony_ci	.lookup      = ubifs_lookup,
17038c2ecf20Sopenharmony_ci	.create      = ubifs_create,
17048c2ecf20Sopenharmony_ci	.link        = ubifs_link,
17058c2ecf20Sopenharmony_ci	.symlink     = ubifs_symlink,
17068c2ecf20Sopenharmony_ci	.unlink      = ubifs_unlink,
17078c2ecf20Sopenharmony_ci	.mkdir       = ubifs_mkdir,
17088c2ecf20Sopenharmony_ci	.rmdir       = ubifs_rmdir,
17098c2ecf20Sopenharmony_ci	.mknod       = ubifs_mknod,
17108c2ecf20Sopenharmony_ci	.rename      = ubifs_rename,
17118c2ecf20Sopenharmony_ci	.setattr     = ubifs_setattr,
17128c2ecf20Sopenharmony_ci	.getattr     = ubifs_getattr,
17138c2ecf20Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_XATTR
17148c2ecf20Sopenharmony_ci	.listxattr   = ubifs_listxattr,
17158c2ecf20Sopenharmony_ci#endif
17168c2ecf20Sopenharmony_ci	.update_time = ubifs_update_time,
17178c2ecf20Sopenharmony_ci	.tmpfile     = ubifs_tmpfile,
17188c2ecf20Sopenharmony_ci};
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ciconst struct file_operations ubifs_dir_operations = {
17218c2ecf20Sopenharmony_ci	.llseek         = generic_file_llseek,
17228c2ecf20Sopenharmony_ci	.release        = ubifs_dir_release,
17238c2ecf20Sopenharmony_ci	.read           = generic_read_dir,
17248c2ecf20Sopenharmony_ci	.iterate_shared = ubifs_readdir,
17258c2ecf20Sopenharmony_ci	.fsync          = ubifs_fsync,
17268c2ecf20Sopenharmony_ci	.unlocked_ioctl = ubifs_ioctl,
17278c2ecf20Sopenharmony_ci	.open		= ubifs_dir_open,
17288c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
17298c2ecf20Sopenharmony_ci	.compat_ioctl   = ubifs_compat_ioctl,
17308c2ecf20Sopenharmony_ci#endif
17318c2ecf20Sopenharmony_ci};
1732