18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/fs/ext2/namei.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Rewrite to pagecache. Almost all code had been changed, so blame me
68c2ecf20Sopenharmony_ci * if the things go wrong. Please, send bug reports to
78c2ecf20Sopenharmony_ci * viro@parcelfarce.linux.theplanet.co.uk
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Stuff here is basically a glue between the VFS and generic UNIXish
108c2ecf20Sopenharmony_ci * filesystem that keeps everything in pagecache. All knowledge of the
118c2ecf20Sopenharmony_ci * directory layout is in fs/ext2/dir.c - it turned out to be easily separatable
128c2ecf20Sopenharmony_ci * and it's easier to debug that way. In principle we might want to
138c2ecf20Sopenharmony_ci * generalize that a bit and turn it into a library. Or not.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * The only non-static object here is ext2_dir_inode_operations.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * TODO: get rid of kmap() use, add readahead.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995
208c2ecf20Sopenharmony_ci * Remy Card (card@masi.ibp.fr)
218c2ecf20Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal
228c2ecf20Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI)
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *  from
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci *  linux/fs/minix/namei.c
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci *  Copyright (C) 1991, 1992  Linus Torvalds
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci *  Big-endian to little-endian byte-swapping/bitmaps by
318c2ecf20Sopenharmony_ci *        David S. Miller (davem@caip.rutgers.edu), 1995
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
358c2ecf20Sopenharmony_ci#include <linux/quotaops.h>
368c2ecf20Sopenharmony_ci#include "ext2.h"
378c2ecf20Sopenharmony_ci#include "xattr.h"
388c2ecf20Sopenharmony_ci#include "acl.h"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	int err = ext2_add_link(dentry, inode);
438c2ecf20Sopenharmony_ci	if (!err) {
448c2ecf20Sopenharmony_ci		d_instantiate_new(dentry, inode);
458c2ecf20Sopenharmony_ci		return 0;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
488c2ecf20Sopenharmony_ci	discard_new_inode(inode);
498c2ecf20Sopenharmony_ci	return err;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci * Methods themselves.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct inode * inode;
598c2ecf20Sopenharmony_ci	ino_t ino;
608c2ecf20Sopenharmony_ci	int res;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (dentry->d_name.len > EXT2_NAME_LEN)
638c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	res = ext2_inode_by_name(dir, &dentry->d_name, &ino);
668c2ecf20Sopenharmony_ci	if (res) {
678c2ecf20Sopenharmony_ci		if (res != -ENOENT)
688c2ecf20Sopenharmony_ci			return ERR_PTR(res);
698c2ecf20Sopenharmony_ci		inode = NULL;
708c2ecf20Sopenharmony_ci	} else {
718c2ecf20Sopenharmony_ci		inode = ext2_iget(dir->i_sb, ino);
728c2ecf20Sopenharmony_ci		if (inode == ERR_PTR(-ESTALE)) {
738c2ecf20Sopenharmony_ci			ext2_error(dir->i_sb, __func__,
748c2ecf20Sopenharmony_ci					"deleted inode referenced: %lu",
758c2ecf20Sopenharmony_ci					(unsigned long) ino);
768c2ecf20Sopenharmony_ci			return ERR_PTR(-EIO);
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	return d_splice_alias(inode, dentry);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistruct dentry *ext2_get_parent(struct dentry *child)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	struct qstr dotdot = QSTR_INIT("..", 2);
858c2ecf20Sopenharmony_ci	ino_t ino;
868c2ecf20Sopenharmony_ci	int res;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	res = ext2_inode_by_name(d_inode(child), &dotdot, &ino);
898c2ecf20Sopenharmony_ci	if (res)
908c2ecf20Sopenharmony_ci		return ERR_PTR(res);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return d_obtain_alias(ext2_iget(child->d_sb, ino));
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/*
968c2ecf20Sopenharmony_ci * By the time this is called, we already have created
978c2ecf20Sopenharmony_ci * the directory cache entry for the new file, but it
988c2ecf20Sopenharmony_ci * is so far negative - it has no inode.
998c2ecf20Sopenharmony_ci *
1008c2ecf20Sopenharmony_ci * If the create succeeds, we fill in the inode information
1018c2ecf20Sopenharmony_ci * with d_instantiate().
1028c2ecf20Sopenharmony_ci */
1038c2ecf20Sopenharmony_cistatic int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	struct inode *inode;
1068c2ecf20Sopenharmony_ci	int err;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
1098c2ecf20Sopenharmony_ci	if (err)
1108c2ecf20Sopenharmony_ci		return err;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	inode = ext2_new_inode(dir, mode, &dentry->d_name);
1138c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
1148c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	ext2_set_file_ops(inode);
1178c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1188c2ecf20Sopenharmony_ci	return ext2_add_nondir(dentry, inode);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int ext2_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct inode *inode = ext2_new_inode(dir, mode, NULL);
1248c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
1258c2ecf20Sopenharmony_ci		return PTR_ERR(inode);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ext2_set_file_ops(inode);
1288c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1298c2ecf20Sopenharmony_ci	d_tmpfile(dentry, inode);
1308c2ecf20Sopenharmony_ci	unlock_new_inode(inode);
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct inode * inode;
1378c2ecf20Sopenharmony_ci	int err;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
1408c2ecf20Sopenharmony_ci	if (err)
1418c2ecf20Sopenharmony_ci		return err;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	inode = ext2_new_inode (dir, mode, &dentry->d_name);
1448c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
1458c2ecf20Sopenharmony_ci	if (!IS_ERR(inode)) {
1468c2ecf20Sopenharmony_ci		init_special_inode(inode, inode->i_mode, rdev);
1478c2ecf20Sopenharmony_ci		inode->i_op = &ext2_special_inode_operations;
1488c2ecf20Sopenharmony_ci		mark_inode_dirty(inode);
1498c2ecf20Sopenharmony_ci		err = ext2_add_nondir(dentry, inode);
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	return err;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic int ext2_symlink (struct inode * dir, struct dentry * dentry,
1558c2ecf20Sopenharmony_ci	const char * symname)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct super_block * sb = dir->i_sb;
1588c2ecf20Sopenharmony_ci	int err = -ENAMETOOLONG;
1598c2ecf20Sopenharmony_ci	unsigned l = strlen(symname)+1;
1608c2ecf20Sopenharmony_ci	struct inode * inode;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (l > sb->s_blocksize)
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
1668c2ecf20Sopenharmony_ci	if (err)
1678c2ecf20Sopenharmony_ci		goto out;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name);
1708c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
1718c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
1728c2ecf20Sopenharmony_ci		goto out;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (l > sizeof (EXT2_I(inode)->i_data)) {
1758c2ecf20Sopenharmony_ci		/* slow symlink */
1768c2ecf20Sopenharmony_ci		inode->i_op = &ext2_symlink_inode_operations;
1778c2ecf20Sopenharmony_ci		inode_nohighmem(inode);
1788c2ecf20Sopenharmony_ci		if (test_opt(inode->i_sb, NOBH))
1798c2ecf20Sopenharmony_ci			inode->i_mapping->a_ops = &ext2_nobh_aops;
1808c2ecf20Sopenharmony_ci		else
1818c2ecf20Sopenharmony_ci			inode->i_mapping->a_ops = &ext2_aops;
1828c2ecf20Sopenharmony_ci		err = page_symlink(inode, symname, l);
1838c2ecf20Sopenharmony_ci		if (err)
1848c2ecf20Sopenharmony_ci			goto out_fail;
1858c2ecf20Sopenharmony_ci	} else {
1868c2ecf20Sopenharmony_ci		/* fast symlink */
1878c2ecf20Sopenharmony_ci		inode->i_op = &ext2_fast_symlink_inode_operations;
1888c2ecf20Sopenharmony_ci		inode->i_link = (char*)EXT2_I(inode)->i_data;
1898c2ecf20Sopenharmony_ci		memcpy(inode->i_link, symname, l);
1908c2ecf20Sopenharmony_ci		inode->i_size = l-1;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci	mark_inode_dirty(inode);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	err = ext2_add_nondir(dentry, inode);
1958c2ecf20Sopenharmony_ciout:
1968c2ecf20Sopenharmony_ci	return err;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciout_fail:
1998c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2008c2ecf20Sopenharmony_ci	discard_new_inode(inode);
2018c2ecf20Sopenharmony_ci	goto out;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int ext2_link (struct dentry * old_dentry, struct inode * dir,
2058c2ecf20Sopenharmony_ci	struct dentry *dentry)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(old_dentry);
2088c2ecf20Sopenharmony_ci	int err;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
2118c2ecf20Sopenharmony_ci	if (err)
2128c2ecf20Sopenharmony_ci		return err;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	inode->i_ctime = current_time(inode);
2158c2ecf20Sopenharmony_ci	inode_inc_link_count(inode);
2168c2ecf20Sopenharmony_ci	ihold(inode);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	err = ext2_add_link(dentry, inode);
2198c2ecf20Sopenharmony_ci	if (!err) {
2208c2ecf20Sopenharmony_ci		d_instantiate(dentry, inode);
2218c2ecf20Sopenharmony_ci		return 0;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2248c2ecf20Sopenharmony_ci	iput(inode);
2258c2ecf20Sopenharmony_ci	return err;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct inode * inode;
2318c2ecf20Sopenharmony_ci	int err;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
2348c2ecf20Sopenharmony_ci	if (err)
2358c2ecf20Sopenharmony_ci		return err;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	inode_inc_link_count(dir);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	inode = ext2_new_inode(dir, S_IFDIR | mode, &dentry->d_name);
2408c2ecf20Sopenharmony_ci	err = PTR_ERR(inode);
2418c2ecf20Sopenharmony_ci	if (IS_ERR(inode))
2428c2ecf20Sopenharmony_ci		goto out_dir;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	inode->i_op = &ext2_dir_inode_operations;
2458c2ecf20Sopenharmony_ci	inode->i_fop = &ext2_dir_operations;
2468c2ecf20Sopenharmony_ci	if (test_opt(inode->i_sb, NOBH))
2478c2ecf20Sopenharmony_ci		inode->i_mapping->a_ops = &ext2_nobh_aops;
2488c2ecf20Sopenharmony_ci	else
2498c2ecf20Sopenharmony_ci		inode->i_mapping->a_ops = &ext2_aops;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	inode_inc_link_count(inode);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	err = ext2_make_empty(inode, dir);
2548c2ecf20Sopenharmony_ci	if (err)
2558c2ecf20Sopenharmony_ci		goto out_fail;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	err = ext2_add_link(dentry, inode);
2588c2ecf20Sopenharmony_ci	if (err)
2598c2ecf20Sopenharmony_ci		goto out_fail;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	d_instantiate_new(dentry, inode);
2628c2ecf20Sopenharmony_ciout:
2638c2ecf20Sopenharmony_ci	return err;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ciout_fail:
2668c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2678c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2688c2ecf20Sopenharmony_ci	discard_new_inode(inode);
2698c2ecf20Sopenharmony_ciout_dir:
2708c2ecf20Sopenharmony_ci	inode_dec_link_count(dir);
2718c2ecf20Sopenharmony_ci	goto out;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int ext2_unlink(struct inode * dir, struct dentry *dentry)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct inode * inode = d_inode(dentry);
2778c2ecf20Sopenharmony_ci	struct ext2_dir_entry_2 * de;
2788c2ecf20Sopenharmony_ci	struct page * page;
2798c2ecf20Sopenharmony_ci	int err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	err = dquot_initialize(dir);
2828c2ecf20Sopenharmony_ci	if (err)
2838c2ecf20Sopenharmony_ci		goto out;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	de = ext2_find_entry(dir, &dentry->d_name, &page);
2868c2ecf20Sopenharmony_ci	if (IS_ERR(de)) {
2878c2ecf20Sopenharmony_ci		err = PTR_ERR(de);
2888c2ecf20Sopenharmony_ci		goto out;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	err = ext2_delete_entry (de, page);
2928c2ecf20Sopenharmony_ci	if (err)
2938c2ecf20Sopenharmony_ci		goto out;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	inode->i_ctime = dir->i_ctime;
2968c2ecf20Sopenharmony_ci	inode_dec_link_count(inode);
2978c2ecf20Sopenharmony_ci	err = 0;
2988c2ecf20Sopenharmony_ciout:
2998c2ecf20Sopenharmony_ci	return err;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int ext2_rmdir (struct inode * dir, struct dentry *dentry)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct inode * inode = d_inode(dentry);
3058c2ecf20Sopenharmony_ci	int err = -ENOTEMPTY;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (ext2_empty_dir(inode)) {
3088c2ecf20Sopenharmony_ci		err = ext2_unlink(dir, dentry);
3098c2ecf20Sopenharmony_ci		if (!err) {
3108c2ecf20Sopenharmony_ci			inode->i_size = 0;
3118c2ecf20Sopenharmony_ci			inode_dec_link_count(inode);
3128c2ecf20Sopenharmony_ci			inode_dec_link_count(dir);
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci	return err;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
3198c2ecf20Sopenharmony_ci			struct inode * new_dir,	struct dentry * new_dentry,
3208c2ecf20Sopenharmony_ci			unsigned int flags)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct inode * old_inode = d_inode(old_dentry);
3238c2ecf20Sopenharmony_ci	struct inode * new_inode = d_inode(new_dentry);
3248c2ecf20Sopenharmony_ci	struct page * dir_page = NULL;
3258c2ecf20Sopenharmony_ci	struct ext2_dir_entry_2 * dir_de = NULL;
3268c2ecf20Sopenharmony_ci	struct page * old_page;
3278c2ecf20Sopenharmony_ci	struct ext2_dir_entry_2 * old_de;
3288c2ecf20Sopenharmony_ci	int err;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if (flags & ~RENAME_NOREPLACE)
3318c2ecf20Sopenharmony_ci		return -EINVAL;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	err = dquot_initialize(old_dir);
3348c2ecf20Sopenharmony_ci	if (err)
3358c2ecf20Sopenharmony_ci		goto out;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	err = dquot_initialize(new_dir);
3388c2ecf20Sopenharmony_ci	if (err)
3398c2ecf20Sopenharmony_ci		goto out;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	old_de = ext2_find_entry(old_dir, &old_dentry->d_name, &old_page);
3428c2ecf20Sopenharmony_ci	if (IS_ERR(old_de)) {
3438c2ecf20Sopenharmony_ci		err = PTR_ERR(old_de);
3448c2ecf20Sopenharmony_ci		goto out;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (S_ISDIR(old_inode->i_mode)) {
3488c2ecf20Sopenharmony_ci		err = -EIO;
3498c2ecf20Sopenharmony_ci		dir_de = ext2_dotdot(old_inode, &dir_page);
3508c2ecf20Sopenharmony_ci		if (!dir_de)
3518c2ecf20Sopenharmony_ci			goto out_old;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (new_inode) {
3558c2ecf20Sopenharmony_ci		struct page *new_page;
3568c2ecf20Sopenharmony_ci		struct ext2_dir_entry_2 *new_de;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci		err = -ENOTEMPTY;
3598c2ecf20Sopenharmony_ci		if (dir_de && !ext2_empty_dir (new_inode))
3608c2ecf20Sopenharmony_ci			goto out_dir;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		new_de = ext2_find_entry(new_dir, &new_dentry->d_name, &new_page);
3638c2ecf20Sopenharmony_ci		if (IS_ERR(new_de)) {
3648c2ecf20Sopenharmony_ci			err = PTR_ERR(new_de);
3658c2ecf20Sopenharmony_ci			goto out_dir;
3668c2ecf20Sopenharmony_ci		}
3678c2ecf20Sopenharmony_ci		ext2_set_link(new_dir, new_de, new_page, old_inode, 1);
3688c2ecf20Sopenharmony_ci		new_inode->i_ctime = current_time(new_inode);
3698c2ecf20Sopenharmony_ci		if (dir_de)
3708c2ecf20Sopenharmony_ci			drop_nlink(new_inode);
3718c2ecf20Sopenharmony_ci		inode_dec_link_count(new_inode);
3728c2ecf20Sopenharmony_ci	} else {
3738c2ecf20Sopenharmony_ci		err = ext2_add_link(new_dentry, old_inode);
3748c2ecf20Sopenharmony_ci		if (err)
3758c2ecf20Sopenharmony_ci			goto out_dir;
3768c2ecf20Sopenharmony_ci		if (dir_de)
3778c2ecf20Sopenharmony_ci			inode_inc_link_count(new_dir);
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/*
3818c2ecf20Sopenharmony_ci	 * Like most other Unix systems, set the ctime for inodes on a
3828c2ecf20Sopenharmony_ci 	 * rename.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	old_inode->i_ctime = current_time(old_inode);
3858c2ecf20Sopenharmony_ci	mark_inode_dirty(old_inode);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	ext2_delete_entry (old_de, old_page);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (dir_de) {
3908c2ecf20Sopenharmony_ci		if (old_dir != new_dir)
3918c2ecf20Sopenharmony_ci			ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
3928c2ecf20Sopenharmony_ci		else {
3938c2ecf20Sopenharmony_ci			kunmap(dir_page);
3948c2ecf20Sopenharmony_ci			put_page(dir_page);
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci		inode_dec_link_count(old_dir);
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci	return 0;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ciout_dir:
4028c2ecf20Sopenharmony_ci	if (dir_de) {
4038c2ecf20Sopenharmony_ci		kunmap(dir_page);
4048c2ecf20Sopenharmony_ci		put_page(dir_page);
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ciout_old:
4078c2ecf20Sopenharmony_ci	kunmap(old_page);
4088c2ecf20Sopenharmony_ci	put_page(old_page);
4098c2ecf20Sopenharmony_ciout:
4108c2ecf20Sopenharmony_ci	return err;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ciconst struct inode_operations ext2_dir_inode_operations = {
4148c2ecf20Sopenharmony_ci	.create		= ext2_create,
4158c2ecf20Sopenharmony_ci	.lookup		= ext2_lookup,
4168c2ecf20Sopenharmony_ci	.link		= ext2_link,
4178c2ecf20Sopenharmony_ci	.unlink		= ext2_unlink,
4188c2ecf20Sopenharmony_ci	.symlink	= ext2_symlink,
4198c2ecf20Sopenharmony_ci	.mkdir		= ext2_mkdir,
4208c2ecf20Sopenharmony_ci	.rmdir		= ext2_rmdir,
4218c2ecf20Sopenharmony_ci	.mknod		= ext2_mknod,
4228c2ecf20Sopenharmony_ci	.rename		= ext2_rename,
4238c2ecf20Sopenharmony_ci	.listxattr	= ext2_listxattr,
4248c2ecf20Sopenharmony_ci	.getattr	= ext2_getattr,
4258c2ecf20Sopenharmony_ci	.setattr	= ext2_setattr,
4268c2ecf20Sopenharmony_ci	.get_acl	= ext2_get_acl,
4278c2ecf20Sopenharmony_ci	.set_acl	= ext2_set_acl,
4288c2ecf20Sopenharmony_ci	.tmpfile	= ext2_tmpfile,
4298c2ecf20Sopenharmony_ci};
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciconst struct inode_operations ext2_special_inode_operations = {
4328c2ecf20Sopenharmony_ci	.listxattr	= ext2_listxattr,
4338c2ecf20Sopenharmony_ci	.getattr	= ext2_getattr,
4348c2ecf20Sopenharmony_ci	.setattr	= ext2_setattr,
4358c2ecf20Sopenharmony_ci	.get_acl	= ext2_get_acl,
4368c2ecf20Sopenharmony_ci	.set_acl	= ext2_set_acl,
4378c2ecf20Sopenharmony_ci};
438