162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (C) International Business Machines Corp., 2000-2004
462306a36Sopenharmony_ci *   Portions Copyright (C) Christoph Hellwig, 2001-2002
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/fs.h>
862306a36Sopenharmony_ci#include <linux/namei.h>
962306a36Sopenharmony_ci#include <linux/ctype.h>
1062306a36Sopenharmony_ci#include <linux/quotaops.h>
1162306a36Sopenharmony_ci#include <linux/exportfs.h>
1262306a36Sopenharmony_ci#include "jfs_incore.h"
1362306a36Sopenharmony_ci#include "jfs_superblock.h"
1462306a36Sopenharmony_ci#include "jfs_inode.h"
1562306a36Sopenharmony_ci#include "jfs_dinode.h"
1662306a36Sopenharmony_ci#include "jfs_dmap.h"
1762306a36Sopenharmony_ci#include "jfs_unicode.h"
1862306a36Sopenharmony_ci#include "jfs_metapage.h"
1962306a36Sopenharmony_ci#include "jfs_xattr.h"
2062306a36Sopenharmony_ci#include "jfs_acl.h"
2162306a36Sopenharmony_ci#include "jfs_debug.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * forward references
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ciconst struct dentry_operations jfs_ci_dentry_operations;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic s64 commitZeroLink(tid_t, struct inode *);
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/*
3162306a36Sopenharmony_ci * NAME:	free_ea_wmap(inode)
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * FUNCTION:	free uncommitted extended attributes from working map
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistatic inline void free_ea_wmap(struct inode *inode)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	dxd_t *ea = &JFS_IP(inode)->ea;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (ea->flag & DXD_EXTENT) {
4162306a36Sopenharmony_ci		/* free EA pages from cache */
4262306a36Sopenharmony_ci		invalidate_dxd_metapages(inode, *ea);
4362306a36Sopenharmony_ci		dbFree(inode, addressDXD(ea), lengthDXD(ea));
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci	ea->flag = 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * NAME:	jfs_create(dip, dentry, mode)
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * FUNCTION:	create a regular file in the parent directory <dip>
5262306a36Sopenharmony_ci *		with name = <from dentry> and mode = <mode>
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * PARAMETER:	dip	- parent directory vnode
5562306a36Sopenharmony_ci *		dentry	- dentry of new file
5662306a36Sopenharmony_ci *		mode	- create mode (rwxrwxrwx).
5762306a36Sopenharmony_ci *		nd- nd struct
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * RETURN:	Errors from subroutines
6062306a36Sopenharmony_ci *
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistatic int jfs_create(struct mnt_idmap *idmap, struct inode *dip,
6362306a36Sopenharmony_ci		      struct dentry *dentry, umode_t mode, bool excl)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int rc = 0;
6662306a36Sopenharmony_ci	tid_t tid;		/* transaction id */
6762306a36Sopenharmony_ci	struct inode *ip = NULL;	/* child directory inode */
6862306a36Sopenharmony_ci	ino_t ino;
6962306a36Sopenharmony_ci	struct component_name dname;	/* child directory name */
7062306a36Sopenharmony_ci	struct btstack btstack;
7162306a36Sopenharmony_ci	struct inode *iplist[2];
7262306a36Sopenharmony_ci	struct tblock *tblk;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	rc = dquot_initialize(dip);
7762306a36Sopenharmony_ci	if (rc)
7862306a36Sopenharmony_ci		goto out1;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/*
8162306a36Sopenharmony_ci	 * search parent directory for entry/freespace
8262306a36Sopenharmony_ci	 * (dtSearch() returns parent directory page pinned)
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
8562306a36Sopenharmony_ci		goto out1;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	/*
8862306a36Sopenharmony_ci	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
8962306a36Sopenharmony_ci	 * block there while holding dtree page, so we allocate the inode &
9062306a36Sopenharmony_ci	 * begin the transaction before we search the directory.
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	ip = ialloc(dip, mode);
9362306a36Sopenharmony_ci	if (IS_ERR(ip)) {
9462306a36Sopenharmony_ci		rc = PTR_ERR(ip);
9562306a36Sopenharmony_ci		goto out2;
9662306a36Sopenharmony_ci	}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	tid = txBegin(dip->i_sb, 0);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
10162306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	rc = jfs_init_acl(tid, ip, dip);
10462306a36Sopenharmony_ci	if (rc)
10562306a36Sopenharmony_ci		goto out3;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
10862306a36Sopenharmony_ci	if (rc) {
10962306a36Sopenharmony_ci		txAbort(tid, 0);
11062306a36Sopenharmony_ci		goto out3;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
11462306a36Sopenharmony_ci		jfs_err("jfs_create: dtSearch returned %d", rc);
11562306a36Sopenharmony_ci		txAbort(tid, 0);
11662306a36Sopenharmony_ci		goto out3;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
12062306a36Sopenharmony_ci	tblk->xflag |= COMMIT_CREATE;
12162306a36Sopenharmony_ci	tblk->ino = ip->i_ino;
12262306a36Sopenharmony_ci	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	iplist[0] = dip;
12562306a36Sopenharmony_ci	iplist[1] = ip;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	/*
12862306a36Sopenharmony_ci	 * initialize the child XAD tree root in-line in inode
12962306a36Sopenharmony_ci	 */
13062306a36Sopenharmony_ci	xtInitRoot(tid, ip);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/*
13362306a36Sopenharmony_ci	 * create entry in parent directory for child directory
13462306a36Sopenharmony_ci	 * (dtInsert() releases parent directory page)
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	ino = ip->i_ino;
13762306a36Sopenharmony_ci	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
13862306a36Sopenharmony_ci		if (rc == -EIO) {
13962306a36Sopenharmony_ci			jfs_err("jfs_create: dtInsert returned -EIO");
14062306a36Sopenharmony_ci			txAbort(tid, 1);	/* Marks Filesystem dirty */
14162306a36Sopenharmony_ci		} else
14262306a36Sopenharmony_ci			txAbort(tid, 0);	/* Filesystem full */
14362306a36Sopenharmony_ci		goto out3;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	ip->i_op = &jfs_file_inode_operations;
14762306a36Sopenharmony_ci	ip->i_fop = &jfs_file_operations;
14862306a36Sopenharmony_ci	ip->i_mapping->a_ops = &jfs_aops;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	mark_inode_dirty(ip);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	dip->i_mtime = inode_set_ctime_current(dip);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	mark_inode_dirty(dip);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], 0);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci      out3:
15962306a36Sopenharmony_ci	txEnd(tid);
16062306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
16162306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dip)->commit_mutex);
16262306a36Sopenharmony_ci	if (rc) {
16362306a36Sopenharmony_ci		free_ea_wmap(ip);
16462306a36Sopenharmony_ci		clear_nlink(ip);
16562306a36Sopenharmony_ci		discard_new_inode(ip);
16662306a36Sopenharmony_ci	} else {
16762306a36Sopenharmony_ci		d_instantiate_new(dentry, ip);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci      out2:
17162306a36Sopenharmony_ci	free_UCSname(&dname);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci      out1:
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	jfs_info("jfs_create: rc:%d", rc);
17662306a36Sopenharmony_ci	return rc;
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * NAME:	jfs_mkdir(dip, dentry, mode)
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * FUNCTION:	create a child directory in the parent directory <dip>
18462306a36Sopenharmony_ci *		with name = <from dentry> and mode = <mode>
18562306a36Sopenharmony_ci *
18662306a36Sopenharmony_ci * PARAMETER:	dip	- parent directory vnode
18762306a36Sopenharmony_ci *		dentry	- dentry of child directory
18862306a36Sopenharmony_ci *		mode	- create mode (rwxrwxrwx).
18962306a36Sopenharmony_ci *
19062306a36Sopenharmony_ci * RETURN:	Errors from subroutines
19162306a36Sopenharmony_ci *
19262306a36Sopenharmony_ci * note:
19362306a36Sopenharmony_ci * EACCES: user needs search+write permission on the parent directory
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip,
19662306a36Sopenharmony_ci		     struct dentry *dentry, umode_t mode)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int rc = 0;
19962306a36Sopenharmony_ci	tid_t tid;		/* transaction id */
20062306a36Sopenharmony_ci	struct inode *ip = NULL;	/* child directory inode */
20162306a36Sopenharmony_ci	ino_t ino;
20262306a36Sopenharmony_ci	struct component_name dname;	/* child directory name */
20362306a36Sopenharmony_ci	struct btstack btstack;
20462306a36Sopenharmony_ci	struct inode *iplist[2];
20562306a36Sopenharmony_ci	struct tblock *tblk;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	rc = dquot_initialize(dip);
21062306a36Sopenharmony_ci	if (rc)
21162306a36Sopenharmony_ci		goto out1;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/*
21462306a36Sopenharmony_ci	 * search parent directory for entry/freespace
21562306a36Sopenharmony_ci	 * (dtSearch() returns parent directory page pinned)
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
21862306a36Sopenharmony_ci		goto out1;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/*
22162306a36Sopenharmony_ci	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
22262306a36Sopenharmony_ci	 * block there while holding dtree page, so we allocate the inode &
22362306a36Sopenharmony_ci	 * begin the transaction before we search the directory.
22462306a36Sopenharmony_ci	 */
22562306a36Sopenharmony_ci	ip = ialloc(dip, S_IFDIR | mode);
22662306a36Sopenharmony_ci	if (IS_ERR(ip)) {
22762306a36Sopenharmony_ci		rc = PTR_ERR(ip);
22862306a36Sopenharmony_ci		goto out2;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	tid = txBegin(dip->i_sb, 0);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
23462306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	rc = jfs_init_acl(tid, ip, dip);
23762306a36Sopenharmony_ci	if (rc)
23862306a36Sopenharmony_ci		goto out3;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
24162306a36Sopenharmony_ci	if (rc) {
24262306a36Sopenharmony_ci		txAbort(tid, 0);
24362306a36Sopenharmony_ci		goto out3;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
24762306a36Sopenharmony_ci		jfs_err("jfs_mkdir: dtSearch returned %d", rc);
24862306a36Sopenharmony_ci		txAbort(tid, 0);
24962306a36Sopenharmony_ci		goto out3;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
25362306a36Sopenharmony_ci	tblk->xflag |= COMMIT_CREATE;
25462306a36Sopenharmony_ci	tblk->ino = ip->i_ino;
25562306a36Sopenharmony_ci	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	iplist[0] = dip;
25862306a36Sopenharmony_ci	iplist[1] = ip;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	/*
26162306a36Sopenharmony_ci	 * initialize the child directory in-line in inode
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	dtInitRoot(tid, ip, dip->i_ino);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/*
26662306a36Sopenharmony_ci	 * create entry in parent directory for child directory
26762306a36Sopenharmony_ci	 * (dtInsert() releases parent directory page)
26862306a36Sopenharmony_ci	 */
26962306a36Sopenharmony_ci	ino = ip->i_ino;
27062306a36Sopenharmony_ci	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
27162306a36Sopenharmony_ci		if (rc == -EIO) {
27262306a36Sopenharmony_ci			jfs_err("jfs_mkdir: dtInsert returned -EIO");
27362306a36Sopenharmony_ci			txAbort(tid, 1);	/* Marks Filesystem dirty */
27462306a36Sopenharmony_ci		} else
27562306a36Sopenharmony_ci			txAbort(tid, 0);	/* Filesystem full */
27662306a36Sopenharmony_ci		goto out3;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	set_nlink(ip, 2);	/* for '.' */
28062306a36Sopenharmony_ci	ip->i_op = &jfs_dir_inode_operations;
28162306a36Sopenharmony_ci	ip->i_fop = &jfs_dir_operations;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	mark_inode_dirty(ip);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* update parent directory inode */
28662306a36Sopenharmony_ci	inc_nlink(dip);		/* for '..' from child directory */
28762306a36Sopenharmony_ci	dip->i_mtime = inode_set_ctime_current(dip);
28862306a36Sopenharmony_ci	mark_inode_dirty(dip);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], 0);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci      out3:
29362306a36Sopenharmony_ci	txEnd(tid);
29462306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
29562306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dip)->commit_mutex);
29662306a36Sopenharmony_ci	if (rc) {
29762306a36Sopenharmony_ci		free_ea_wmap(ip);
29862306a36Sopenharmony_ci		clear_nlink(ip);
29962306a36Sopenharmony_ci		discard_new_inode(ip);
30062306a36Sopenharmony_ci	} else {
30162306a36Sopenharmony_ci		d_instantiate_new(dentry, ip);
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci      out2:
30562306a36Sopenharmony_ci	free_UCSname(&dname);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci      out1:
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	jfs_info("jfs_mkdir: rc:%d", rc);
31162306a36Sopenharmony_ci	return rc;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * NAME:	jfs_rmdir(dip, dentry)
31662306a36Sopenharmony_ci *
31762306a36Sopenharmony_ci * FUNCTION:	remove a link to child directory
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci * PARAMETER:	dip	- parent inode
32062306a36Sopenharmony_ci *		dentry	- child directory dentry
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * RETURN:	-EINVAL	- if name is . or ..
32362306a36Sopenharmony_ci *		-EINVAL - if . or .. exist but are invalid.
32462306a36Sopenharmony_ci *		errors from subroutines
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * note:
32762306a36Sopenharmony_ci * if other threads have the directory open when the last link
32862306a36Sopenharmony_ci * is removed, the "." and ".." entries, if present, are removed before
32962306a36Sopenharmony_ci * rmdir() returns and no new entries may be created in the directory,
33062306a36Sopenharmony_ci * but the directory is not removed until the last reference to
33162306a36Sopenharmony_ci * the directory is released (cf.unlink() of regular file).
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic int jfs_rmdir(struct inode *dip, struct dentry *dentry)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	int rc;
33662306a36Sopenharmony_ci	tid_t tid;		/* transaction id */
33762306a36Sopenharmony_ci	struct inode *ip = d_inode(dentry);
33862306a36Sopenharmony_ci	ino_t ino;
33962306a36Sopenharmony_ci	struct component_name dname;
34062306a36Sopenharmony_ci	struct inode *iplist[2];
34162306a36Sopenharmony_ci	struct tblock *tblk;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Init inode for quota operations. */
34662306a36Sopenharmony_ci	rc = dquot_initialize(dip);
34762306a36Sopenharmony_ci	if (rc)
34862306a36Sopenharmony_ci		goto out;
34962306a36Sopenharmony_ci	rc = dquot_initialize(ip);
35062306a36Sopenharmony_ci	if (rc)
35162306a36Sopenharmony_ci		goto out;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* directory must be empty to be removed */
35462306a36Sopenharmony_ci	if (!dtEmpty(ip)) {
35562306a36Sopenharmony_ci		rc = -ENOTEMPTY;
35662306a36Sopenharmony_ci		goto out;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry))) {
36062306a36Sopenharmony_ci		goto out;
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	tid = txBegin(dip->i_sb, 0);
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
36662306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	iplist[0] = dip;
36962306a36Sopenharmony_ci	iplist[1] = ip;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
37262306a36Sopenharmony_ci	tblk->xflag |= COMMIT_DELETE;
37362306a36Sopenharmony_ci	tblk->u.ip = ip;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 * delete the entry of target directory from parent directory
37762306a36Sopenharmony_ci	 */
37862306a36Sopenharmony_ci	ino = ip->i_ino;
37962306a36Sopenharmony_ci	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
38062306a36Sopenharmony_ci		jfs_err("jfs_rmdir: dtDelete returned %d", rc);
38162306a36Sopenharmony_ci		if (rc == -EIO)
38262306a36Sopenharmony_ci			txAbort(tid, 1);
38362306a36Sopenharmony_ci		txEnd(tid);
38462306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(ip)->commit_mutex);
38562306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(dip)->commit_mutex);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		goto out2;
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* update parent directory's link count corresponding
39162306a36Sopenharmony_ci	 * to ".." entry of the target directory deleted
39262306a36Sopenharmony_ci	 */
39362306a36Sopenharmony_ci	dip->i_mtime = inode_set_ctime_current(dip);
39462306a36Sopenharmony_ci	inode_dec_link_count(dip);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/*
39762306a36Sopenharmony_ci	 * OS/2 could have created EA and/or ACL
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	/* free EA from both persistent and working map */
40062306a36Sopenharmony_ci	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
40162306a36Sopenharmony_ci		/* free EA pages */
40262306a36Sopenharmony_ci		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	JFS_IP(ip)->ea.flag = 0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* free ACL from both persistent and working map */
40762306a36Sopenharmony_ci	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
40862306a36Sopenharmony_ci		/* free ACL pages */
40962306a36Sopenharmony_ci		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	JFS_IP(ip)->acl.flag = 0;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* mark the target directory as deleted */
41462306a36Sopenharmony_ci	clear_nlink(ip);
41562306a36Sopenharmony_ci	mark_inode_dirty(ip);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], 0);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	txEnd(tid);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
42262306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dip)->commit_mutex);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/*
42562306a36Sopenharmony_ci	 * Truncating the directory index table is not guaranteed.  It
42662306a36Sopenharmony_ci	 * may need to be done iteratively
42762306a36Sopenharmony_ci	 */
42862306a36Sopenharmony_ci	if (test_cflag(COMMIT_Stale, dip)) {
42962306a36Sopenharmony_ci		if (dip->i_size > 1)
43062306a36Sopenharmony_ci			jfs_truncate_nolock(dip, 0);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		clear_cflag(COMMIT_Stale, dip);
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci      out2:
43662306a36Sopenharmony_ci	free_UCSname(&dname);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci      out:
43962306a36Sopenharmony_ci	jfs_info("jfs_rmdir: rc:%d", rc);
44062306a36Sopenharmony_ci	return rc;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/*
44462306a36Sopenharmony_ci * NAME:	jfs_unlink(dip, dentry)
44562306a36Sopenharmony_ci *
44662306a36Sopenharmony_ci * FUNCTION:	remove a link to object <vp> named by <name>
44762306a36Sopenharmony_ci *		from parent directory <dvp>
44862306a36Sopenharmony_ci *
44962306a36Sopenharmony_ci * PARAMETER:	dip	- inode of parent directory
45062306a36Sopenharmony_ci *		dentry	- dentry of object to be removed
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * RETURN:	errors from subroutines
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci * note:
45562306a36Sopenharmony_ci * temporary file: if one or more processes have the file open
45662306a36Sopenharmony_ci * when the last link is removed, the link will be removed before
45762306a36Sopenharmony_ci * unlink() returns, but the removal of the file contents will be
45862306a36Sopenharmony_ci * postponed until all references to the files are closed.
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * JFS does NOT support unlink() on directories.
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci */
46362306a36Sopenharmony_cistatic int jfs_unlink(struct inode *dip, struct dentry *dentry)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	int rc;
46662306a36Sopenharmony_ci	tid_t tid;		/* transaction id */
46762306a36Sopenharmony_ci	struct inode *ip = d_inode(dentry);
46862306a36Sopenharmony_ci	ino_t ino;
46962306a36Sopenharmony_ci	struct component_name dname;	/* object name */
47062306a36Sopenharmony_ci	struct inode *iplist[2];
47162306a36Sopenharmony_ci	struct tblock *tblk;
47262306a36Sopenharmony_ci	s64 new_size = 0;
47362306a36Sopenharmony_ci	int commit_flag;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Init inode for quota operations. */
47862306a36Sopenharmony_ci	rc = dquot_initialize(dip);
47962306a36Sopenharmony_ci	if (rc)
48062306a36Sopenharmony_ci		goto out;
48162306a36Sopenharmony_ci	rc = dquot_initialize(ip);
48262306a36Sopenharmony_ci	if (rc)
48362306a36Sopenharmony_ci		goto out;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
48662306a36Sopenharmony_ci		goto out;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	tid = txBegin(dip->i_sb, 0);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
49362306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	iplist[0] = dip;
49662306a36Sopenharmony_ci	iplist[1] = ip;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/*
49962306a36Sopenharmony_ci	 * delete the entry of target file from parent directory
50062306a36Sopenharmony_ci	 */
50162306a36Sopenharmony_ci	ino = ip->i_ino;
50262306a36Sopenharmony_ci	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
50362306a36Sopenharmony_ci		jfs_err("jfs_unlink: dtDelete returned %d", rc);
50462306a36Sopenharmony_ci		if (rc == -EIO)
50562306a36Sopenharmony_ci			txAbort(tid, 1);	/* Marks FS Dirty */
50662306a36Sopenharmony_ci		txEnd(tid);
50762306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(ip)->commit_mutex);
50862306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(dip)->commit_mutex);
50962306a36Sopenharmony_ci		IWRITE_UNLOCK(ip);
51062306a36Sopenharmony_ci		goto out1;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	ASSERT(ip->i_nlink);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	dip->i_mtime = inode_set_ctime_to_ts(dip, inode_set_ctime_current(ip));
51662306a36Sopenharmony_ci	mark_inode_dirty(dip);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* update target's inode */
51962306a36Sopenharmony_ci	inode_dec_link_count(ip);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 *	commit zero link count object
52362306a36Sopenharmony_ci	 */
52462306a36Sopenharmony_ci	if (ip->i_nlink == 0) {
52562306a36Sopenharmony_ci		assert(!test_cflag(COMMIT_Nolink, ip));
52662306a36Sopenharmony_ci		/* free block resources */
52762306a36Sopenharmony_ci		if ((new_size = commitZeroLink(tid, ip)) < 0) {
52862306a36Sopenharmony_ci			txAbort(tid, 1);	/* Marks FS Dirty */
52962306a36Sopenharmony_ci			txEnd(tid);
53062306a36Sopenharmony_ci			mutex_unlock(&JFS_IP(ip)->commit_mutex);
53162306a36Sopenharmony_ci			mutex_unlock(&JFS_IP(dip)->commit_mutex);
53262306a36Sopenharmony_ci			IWRITE_UNLOCK(ip);
53362306a36Sopenharmony_ci			rc = new_size;
53462306a36Sopenharmony_ci			goto out1;
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci		tblk = tid_to_tblock(tid);
53762306a36Sopenharmony_ci		tblk->xflag |= COMMIT_DELETE;
53862306a36Sopenharmony_ci		tblk->u.ip = ip;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	/*
54262306a36Sopenharmony_ci	 * Incomplete truncate of file data can
54362306a36Sopenharmony_ci	 * result in timing problems unless we synchronously commit the
54462306a36Sopenharmony_ci	 * transaction.
54562306a36Sopenharmony_ci	 */
54662306a36Sopenharmony_ci	if (new_size)
54762306a36Sopenharmony_ci		commit_flag = COMMIT_SYNC;
54862306a36Sopenharmony_ci	else
54962306a36Sopenharmony_ci		commit_flag = 0;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/*
55262306a36Sopenharmony_ci	 * If xtTruncate was incomplete, commit synchronously to avoid
55362306a36Sopenharmony_ci	 * timing complications
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], commit_flag);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	txEnd(tid);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
56062306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dip)->commit_mutex);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	while (new_size && (rc == 0)) {
56362306a36Sopenharmony_ci		tid = txBegin(dip->i_sb, 0);
56462306a36Sopenharmony_ci		mutex_lock(&JFS_IP(ip)->commit_mutex);
56562306a36Sopenharmony_ci		new_size = xtTruncate_pmap(tid, ip, new_size);
56662306a36Sopenharmony_ci		if (new_size < 0) {
56762306a36Sopenharmony_ci			txAbort(tid, 1);	/* Marks FS Dirty */
56862306a36Sopenharmony_ci			rc = new_size;
56962306a36Sopenharmony_ci		} else
57062306a36Sopenharmony_ci			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
57162306a36Sopenharmony_ci		txEnd(tid);
57262306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(ip)->commit_mutex);
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (ip->i_nlink == 0)
57662306a36Sopenharmony_ci		set_cflag(COMMIT_Nolink, ip);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	IWRITE_UNLOCK(ip);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/*
58162306a36Sopenharmony_ci	 * Truncating the directory index table is not guaranteed.  It
58262306a36Sopenharmony_ci	 * may need to be done iteratively
58362306a36Sopenharmony_ci	 */
58462306a36Sopenharmony_ci	if (test_cflag(COMMIT_Stale, dip)) {
58562306a36Sopenharmony_ci		if (dip->i_size > 1)
58662306a36Sopenharmony_ci			jfs_truncate_nolock(dip, 0);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		clear_cflag(COMMIT_Stale, dip);
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci      out1:
59262306a36Sopenharmony_ci	free_UCSname(&dname);
59362306a36Sopenharmony_ci      out:
59462306a36Sopenharmony_ci	jfs_info("jfs_unlink: rc:%d", rc);
59562306a36Sopenharmony_ci	return rc;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/*
59962306a36Sopenharmony_ci * NAME:	commitZeroLink()
60062306a36Sopenharmony_ci *
60162306a36Sopenharmony_ci * FUNCTION:	for non-directory, called by jfs_remove(),
60262306a36Sopenharmony_ci *		truncate a regular file, directory or symbolic
60362306a36Sopenharmony_ci *		link to zero length. return 0 if type is not
60462306a36Sopenharmony_ci *		one of these.
60562306a36Sopenharmony_ci *
60662306a36Sopenharmony_ci *		if the file is currently associated with a VM segment
60762306a36Sopenharmony_ci *		only permanent disk and inode map resources are freed,
60862306a36Sopenharmony_ci *		and neither the inode nor indirect blocks are modified
60962306a36Sopenharmony_ci *		so that the resources can be later freed in the work
61062306a36Sopenharmony_ci *		map by ctrunc1.
61162306a36Sopenharmony_ci *		if there is no VM segment on entry, the resources are
61262306a36Sopenharmony_ci *		freed in both work and permanent map.
61362306a36Sopenharmony_ci *		(? for temporary file - memory object is cached even
61462306a36Sopenharmony_ci *		after no reference:
61562306a36Sopenharmony_ci *		reference count > 0 -   )
61662306a36Sopenharmony_ci *
61762306a36Sopenharmony_ci * PARAMETERS:	cd	- pointer to commit data structure.
61862306a36Sopenharmony_ci *			  current inode is the one to truncate.
61962306a36Sopenharmony_ci *
62062306a36Sopenharmony_ci * RETURN:	Errors from subroutines
62162306a36Sopenharmony_ci */
62262306a36Sopenharmony_cistatic s64 commitZeroLink(tid_t tid, struct inode *ip)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	int filetype;
62562306a36Sopenharmony_ci	struct tblock *tblk;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	filetype = ip->i_mode & S_IFMT;
63062306a36Sopenharmony_ci	switch (filetype) {
63162306a36Sopenharmony_ci	case S_IFREG:
63262306a36Sopenharmony_ci		break;
63362306a36Sopenharmony_ci	case S_IFLNK:
63462306a36Sopenharmony_ci		/* fast symbolic link */
63562306a36Sopenharmony_ci		if (ip->i_size < IDATASIZE) {
63662306a36Sopenharmony_ci			ip->i_size = 0;
63762306a36Sopenharmony_ci			return 0;
63862306a36Sopenharmony_ci		}
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	default:
64162306a36Sopenharmony_ci		assert(filetype != S_IFDIR);
64262306a36Sopenharmony_ci		return 0;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	set_cflag(COMMIT_Freewmap, ip);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* mark transaction of block map update type */
64862306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
64962306a36Sopenharmony_ci	tblk->xflag |= COMMIT_PMAP;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	/*
65262306a36Sopenharmony_ci	 * free EA
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci	if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
65562306a36Sopenharmony_ci		/* acquire maplock on EA to be freed from block map */
65662306a36Sopenharmony_ci		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/*
65962306a36Sopenharmony_ci	 * free ACL
66062306a36Sopenharmony_ci	 */
66162306a36Sopenharmony_ci	if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
66262306a36Sopenharmony_ci		/* acquire maplock on EA to be freed from block map */
66362306a36Sopenharmony_ci		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * free xtree/data (truncate to zero length):
66762306a36Sopenharmony_ci	 * free xtree/data pages from cache if COMMIT_PWMAP,
66862306a36Sopenharmony_ci	 * free xtree/data blocks from persistent block map, and
66962306a36Sopenharmony_ci	 * free xtree/data blocks from working block map if COMMIT_PWMAP;
67062306a36Sopenharmony_ci	 */
67162306a36Sopenharmony_ci	if (ip->i_size)
67262306a36Sopenharmony_ci		return xtTruncate_pmap(tid, ip, 0);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	return 0;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci/*
67962306a36Sopenharmony_ci * NAME:	jfs_free_zero_link()
68062306a36Sopenharmony_ci *
68162306a36Sopenharmony_ci * FUNCTION:	for non-directory, called by iClose(),
68262306a36Sopenharmony_ci *		free resources of a file from cache and WORKING map
68362306a36Sopenharmony_ci *		for a file previously committed with zero link count
68462306a36Sopenharmony_ci *		while associated with a pager object,
68562306a36Sopenharmony_ci *
68662306a36Sopenharmony_ci * PARAMETER:	ip	- pointer to inode of file.
68762306a36Sopenharmony_ci */
68862306a36Sopenharmony_civoid jfs_free_zero_link(struct inode *ip)
68962306a36Sopenharmony_ci{
69062306a36Sopenharmony_ci	int type;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	jfs_info("jfs_free_zero_link: ip = 0x%p", ip);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	/* return if not reg or symbolic link or if size is
69562306a36Sopenharmony_ci	 * already ok.
69662306a36Sopenharmony_ci	 */
69762306a36Sopenharmony_ci	type = ip->i_mode & S_IFMT;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	switch (type) {
70062306a36Sopenharmony_ci	case S_IFREG:
70162306a36Sopenharmony_ci		break;
70262306a36Sopenharmony_ci	case S_IFLNK:
70362306a36Sopenharmony_ci		/* if its contained in inode nothing to do */
70462306a36Sopenharmony_ci		if (ip->i_size < IDATASIZE)
70562306a36Sopenharmony_ci			return;
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	default:
70862306a36Sopenharmony_ci		return;
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	/*
71262306a36Sopenharmony_ci	 * free EA
71362306a36Sopenharmony_ci	 */
71462306a36Sopenharmony_ci	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
71562306a36Sopenharmony_ci		s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
71662306a36Sopenharmony_ci		int xlen = lengthDXD(&JFS_IP(ip)->ea);
71762306a36Sopenharmony_ci		struct maplock maplock;	/* maplock for COMMIT_WMAP */
71862306a36Sopenharmony_ci		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		/* free EA pages from cache */
72162306a36Sopenharmony_ci		invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		/* free EA extent from working block map */
72462306a36Sopenharmony_ci		maplock.index = 1;
72562306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & maplock;
72662306a36Sopenharmony_ci		pxdlock->flag = mlckFREEPXD;
72762306a36Sopenharmony_ci		PXDaddress(&pxdlock->pxd, xaddr);
72862306a36Sopenharmony_ci		PXDlength(&pxdlock->pxd, xlen);
72962306a36Sopenharmony_ci		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/*
73362306a36Sopenharmony_ci	 * free ACL
73462306a36Sopenharmony_ci	 */
73562306a36Sopenharmony_ci	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
73662306a36Sopenharmony_ci		s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
73762306a36Sopenharmony_ci		int xlen = lengthDXD(&JFS_IP(ip)->acl);
73862306a36Sopenharmony_ci		struct maplock maplock;	/* maplock for COMMIT_WMAP */
73962306a36Sopenharmony_ci		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		/* free ACL extent from working block map */
74462306a36Sopenharmony_ci		maplock.index = 1;
74562306a36Sopenharmony_ci		pxdlock = (struct pxd_lock *) & maplock;
74662306a36Sopenharmony_ci		pxdlock->flag = mlckFREEPXD;
74762306a36Sopenharmony_ci		PXDaddress(&pxdlock->pxd, xaddr);
74862306a36Sopenharmony_ci		PXDlength(&pxdlock->pxd, xlen);
74962306a36Sopenharmony_ci		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	/*
75362306a36Sopenharmony_ci	 * free xtree/data (truncate to zero length):
75462306a36Sopenharmony_ci	 * free xtree/data pages from cache, and
75562306a36Sopenharmony_ci	 * free xtree/data blocks from working block map;
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	if (ip->i_size)
75862306a36Sopenharmony_ci		xtTruncate(0, ip, 0, COMMIT_WMAP);
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci/*
76262306a36Sopenharmony_ci * NAME:	jfs_link(vp, dvp, name, crp)
76362306a36Sopenharmony_ci *
76462306a36Sopenharmony_ci * FUNCTION:	create a link to <vp> by the name = <name>
76562306a36Sopenharmony_ci *		in the parent directory <dvp>
76662306a36Sopenharmony_ci *
76762306a36Sopenharmony_ci * PARAMETER:	vp	- target object
76862306a36Sopenharmony_ci *		dvp	- parent directory of new link
76962306a36Sopenharmony_ci *		name	- name of new link to target object
77062306a36Sopenharmony_ci *		crp	- credential
77162306a36Sopenharmony_ci *
77262306a36Sopenharmony_ci * RETURN:	Errors from subroutines
77362306a36Sopenharmony_ci *
77462306a36Sopenharmony_ci * note:
77562306a36Sopenharmony_ci * JFS does NOT support link() on directories (to prevent circular
77662306a36Sopenharmony_ci * path in the directory hierarchy);
77762306a36Sopenharmony_ci * EPERM: the target object is a directory, and either the caller
77862306a36Sopenharmony_ci * does not have appropriate privileges or the implementation prohibits
77962306a36Sopenharmony_ci * using link() on directories [XPG4.2].
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * JFS does NOT support links between file systems:
78262306a36Sopenharmony_ci * EXDEV: target object and new link are on different file systems and
78362306a36Sopenharmony_ci * implementation does not support links between file systems [XPG4.2].
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_cistatic int jfs_link(struct dentry *old_dentry,
78662306a36Sopenharmony_ci	     struct inode *dir, struct dentry *dentry)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	int rc;
78962306a36Sopenharmony_ci	tid_t tid;
79062306a36Sopenharmony_ci	struct inode *ip = d_inode(old_dentry);
79162306a36Sopenharmony_ci	ino_t ino;
79262306a36Sopenharmony_ci	struct component_name dname;
79362306a36Sopenharmony_ci	struct btstack btstack;
79462306a36Sopenharmony_ci	struct inode *iplist[2];
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	rc = dquot_initialize(dir);
79962306a36Sopenharmony_ci	if (rc)
80062306a36Sopenharmony_ci		goto out;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (isReadOnly(ip)) {
80362306a36Sopenharmony_ci		jfs_error(ip->i_sb, "read-only filesystem\n");
80462306a36Sopenharmony_ci		return -EROFS;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	tid = txBegin(ip->i_sb, 0);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
81062306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/*
81362306a36Sopenharmony_ci	 * scan parent directory for entry/freespace
81462306a36Sopenharmony_ci	 */
81562306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
81662306a36Sopenharmony_ci		goto out_tx;
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
81962306a36Sopenharmony_ci		goto free_dname;
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	/*
82262306a36Sopenharmony_ci	 * create entry for new link in parent directory
82362306a36Sopenharmony_ci	 */
82462306a36Sopenharmony_ci	ino = ip->i_ino;
82562306a36Sopenharmony_ci	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
82662306a36Sopenharmony_ci		goto free_dname;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	/* update object inode */
82962306a36Sopenharmony_ci	inc_nlink(ip);		/* for new link */
83062306a36Sopenharmony_ci	inode_set_ctime_current(ip);
83162306a36Sopenharmony_ci	dir->i_mtime = inode_set_ctime_current(dir);
83262306a36Sopenharmony_ci	mark_inode_dirty(dir);
83362306a36Sopenharmony_ci	ihold(ip);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	iplist[0] = ip;
83662306a36Sopenharmony_ci	iplist[1] = dir;
83762306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], 0);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	if (rc) {
84062306a36Sopenharmony_ci		drop_nlink(ip); /* never instantiated */
84162306a36Sopenharmony_ci		iput(ip);
84262306a36Sopenharmony_ci	} else
84362306a36Sopenharmony_ci		d_instantiate(dentry, ip);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci      free_dname:
84662306a36Sopenharmony_ci	free_UCSname(&dname);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci      out_tx:
84962306a36Sopenharmony_ci	txEnd(tid);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
85262306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dir)->commit_mutex);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci      out:
85562306a36Sopenharmony_ci	jfs_info("jfs_link: rc:%d", rc);
85662306a36Sopenharmony_ci	return rc;
85762306a36Sopenharmony_ci}
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci/*
86062306a36Sopenharmony_ci * NAME:	jfs_symlink(dip, dentry, name)
86162306a36Sopenharmony_ci *
86262306a36Sopenharmony_ci * FUNCTION:	creates a symbolic link to <symlink> by name <name>
86362306a36Sopenharmony_ci *			in directory <dip>
86462306a36Sopenharmony_ci *
86562306a36Sopenharmony_ci * PARAMETER:	dip	- parent directory vnode
86662306a36Sopenharmony_ci *		dentry	- dentry of symbolic link
86762306a36Sopenharmony_ci *		name	- the path name of the existing object
86862306a36Sopenharmony_ci *			  that will be the source of the link
86962306a36Sopenharmony_ci *
87062306a36Sopenharmony_ci * RETURN:	errors from subroutines
87162306a36Sopenharmony_ci *
87262306a36Sopenharmony_ci * note:
87362306a36Sopenharmony_ci * ENAMETOOLONG: pathname resolution of a symbolic link produced
87462306a36Sopenharmony_ci * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
87562306a36Sopenharmony_ci*/
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic int jfs_symlink(struct mnt_idmap *idmap, struct inode *dip,
87862306a36Sopenharmony_ci		       struct dentry *dentry, const char *name)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	int rc;
88162306a36Sopenharmony_ci	tid_t tid;
88262306a36Sopenharmony_ci	ino_t ino = 0;
88362306a36Sopenharmony_ci	struct component_name dname;
88462306a36Sopenharmony_ci	u32 ssize;		/* source pathname size */
88562306a36Sopenharmony_ci	struct btstack btstack;
88662306a36Sopenharmony_ci	struct inode *ip;
88762306a36Sopenharmony_ci	s64 xlen = 0;
88862306a36Sopenharmony_ci	int bmask = 0, xsize;
88962306a36Sopenharmony_ci	s64 xaddr;
89062306a36Sopenharmony_ci	struct metapage *mp;
89162306a36Sopenharmony_ci	struct super_block *sb;
89262306a36Sopenharmony_ci	struct tblock *tblk;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	struct inode *iplist[2];
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	rc = dquot_initialize(dip);
89962306a36Sopenharmony_ci	if (rc)
90062306a36Sopenharmony_ci		goto out1;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	ssize = strlen(name) + 1;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/*
90562306a36Sopenharmony_ci	 * search parent directory for entry/freespace
90662306a36Sopenharmony_ci	 * (dtSearch() returns parent directory page pinned)
90762306a36Sopenharmony_ci	 */
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
91062306a36Sopenharmony_ci		goto out1;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/*
91362306a36Sopenharmony_ci	 * allocate on-disk/in-memory inode for symbolic link:
91462306a36Sopenharmony_ci	 * (iAlloc() returns new, locked inode)
91562306a36Sopenharmony_ci	 */
91662306a36Sopenharmony_ci	ip = ialloc(dip, S_IFLNK | 0777);
91762306a36Sopenharmony_ci	if (IS_ERR(ip)) {
91862306a36Sopenharmony_ci		rc = PTR_ERR(ip);
91962306a36Sopenharmony_ci		goto out2;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	tid = txBegin(dip->i_sb, 0);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
92562306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
92862306a36Sopenharmony_ci	if (rc)
92962306a36Sopenharmony_ci		goto out3;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
93262306a36Sopenharmony_ci	tblk->xflag |= COMMIT_CREATE;
93362306a36Sopenharmony_ci	tblk->ino = ip->i_ino;
93462306a36Sopenharmony_ci	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	/* fix symlink access permission
93762306a36Sopenharmony_ci	 * (dir_create() ANDs in the u.u_cmask,
93862306a36Sopenharmony_ci	 * but symlinks really need to be 777 access)
93962306a36Sopenharmony_ci	 */
94062306a36Sopenharmony_ci	ip->i_mode |= 0777;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	/*
94362306a36Sopenharmony_ci	 * write symbolic link target path name
94462306a36Sopenharmony_ci	 */
94562306a36Sopenharmony_ci	xtInitRoot(tid, ip);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	/*
94862306a36Sopenharmony_ci	 * write source path name inline in on-disk inode (fast symbolic link)
94962306a36Sopenharmony_ci	 */
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (ssize <= IDATASIZE) {
95262306a36Sopenharmony_ci		ip->i_op = &jfs_fast_symlink_inode_operations;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci		ip->i_link = JFS_IP(ip)->i_inline_all;
95562306a36Sopenharmony_ci		memcpy(ip->i_link, name, ssize);
95662306a36Sopenharmony_ci		ip->i_size = ssize - 1;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		/*
95962306a36Sopenharmony_ci		 * if symlink is > 128 bytes, we don't have the space to
96062306a36Sopenharmony_ci		 * store inline extended attributes
96162306a36Sopenharmony_ci		 */
96262306a36Sopenharmony_ci		if (ssize > sizeof (JFS_IP(ip)->i_inline))
96362306a36Sopenharmony_ci			JFS_IP(ip)->mode2 &= ~INLINEEA;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		jfs_info("jfs_symlink: fast symlink added  ssize:%u name:%s ",
96662306a36Sopenharmony_ci			 ssize, name);
96762306a36Sopenharmony_ci	}
96862306a36Sopenharmony_ci	/*
96962306a36Sopenharmony_ci	 * write source path name in a single extent
97062306a36Sopenharmony_ci	 */
97162306a36Sopenharmony_ci	else {
97262306a36Sopenharmony_ci		jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci		ip->i_op = &jfs_symlink_inode_operations;
97562306a36Sopenharmony_ci		inode_nohighmem(ip);
97662306a36Sopenharmony_ci		ip->i_mapping->a_ops = &jfs_aops;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		/*
97962306a36Sopenharmony_ci		 * even though the data of symlink object (source
98062306a36Sopenharmony_ci		 * path name) is treated as non-journaled user data,
98162306a36Sopenharmony_ci		 * it is read/written thru buffer cache for performance.
98262306a36Sopenharmony_ci		 */
98362306a36Sopenharmony_ci		sb = ip->i_sb;
98462306a36Sopenharmony_ci		bmask = JFS_SBI(sb)->bsize - 1;
98562306a36Sopenharmony_ci		xsize = (ssize + bmask) & ~bmask;
98662306a36Sopenharmony_ci		xaddr = 0;
98762306a36Sopenharmony_ci		xlen = xsize >> JFS_SBI(sb)->l2bsize;
98862306a36Sopenharmony_ci		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
98962306a36Sopenharmony_ci			txAbort(tid, 0);
99062306a36Sopenharmony_ci			goto out3;
99162306a36Sopenharmony_ci		}
99262306a36Sopenharmony_ci		ip->i_size = ssize - 1;
99362306a36Sopenharmony_ci		while (ssize) {
99462306a36Sopenharmony_ci			/* This is kind of silly since PATH_MAX == 4K */
99562306a36Sopenharmony_ci			u32 copy_size = min_t(u32, ssize, PSIZE);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci			mp = get_metapage(ip, xaddr, PSIZE, 1);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci			if (mp == NULL) {
100062306a36Sopenharmony_ci				xtTruncate(tid, ip, 0, COMMIT_PWMAP);
100162306a36Sopenharmony_ci				rc = -EIO;
100262306a36Sopenharmony_ci				txAbort(tid, 0);
100362306a36Sopenharmony_ci				goto out3;
100462306a36Sopenharmony_ci			}
100562306a36Sopenharmony_ci			memcpy(mp->data, name, copy_size);
100662306a36Sopenharmony_ci			flush_metapage(mp);
100762306a36Sopenharmony_ci			ssize -= copy_size;
100862306a36Sopenharmony_ci			name += copy_size;
100962306a36Sopenharmony_ci			xaddr += JFS_SBI(sb)->nbperpage;
101062306a36Sopenharmony_ci		}
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * create entry for symbolic link in parent directory
101562306a36Sopenharmony_ci	 */
101662306a36Sopenharmony_ci	rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
101762306a36Sopenharmony_ci	if (rc == 0) {
101862306a36Sopenharmony_ci		ino = ip->i_ino;
101962306a36Sopenharmony_ci		rc = dtInsert(tid, dip, &dname, &ino, &btstack);
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci	if (rc) {
102262306a36Sopenharmony_ci		if (xlen)
102362306a36Sopenharmony_ci			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
102462306a36Sopenharmony_ci		txAbort(tid, 0);
102562306a36Sopenharmony_ci		/* discard new inode */
102662306a36Sopenharmony_ci		goto out3;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	mark_inode_dirty(ip);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	dip->i_mtime = inode_set_ctime_current(dip);
103262306a36Sopenharmony_ci	mark_inode_dirty(dip);
103362306a36Sopenharmony_ci	/*
103462306a36Sopenharmony_ci	 * commit update of parent directory and link object
103562306a36Sopenharmony_ci	 */
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	iplist[0] = dip;
103862306a36Sopenharmony_ci	iplist[1] = ip;
103962306a36Sopenharmony_ci	rc = txCommit(tid, 2, &iplist[0], 0);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci      out3:
104262306a36Sopenharmony_ci	txEnd(tid);
104362306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
104462306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dip)->commit_mutex);
104562306a36Sopenharmony_ci	if (rc) {
104662306a36Sopenharmony_ci		free_ea_wmap(ip);
104762306a36Sopenharmony_ci		clear_nlink(ip);
104862306a36Sopenharmony_ci		discard_new_inode(ip);
104962306a36Sopenharmony_ci	} else {
105062306a36Sopenharmony_ci		d_instantiate_new(dentry, ip);
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci      out2:
105462306a36Sopenharmony_ci	free_UCSname(&dname);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci      out1:
105762306a36Sopenharmony_ci	jfs_info("jfs_symlink: rc:%d", rc);
105862306a36Sopenharmony_ci	return rc;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/*
106362306a36Sopenharmony_ci * NAME:	jfs_rename
106462306a36Sopenharmony_ci *
106562306a36Sopenharmony_ci * FUNCTION:	rename a file or directory
106662306a36Sopenharmony_ci */
106762306a36Sopenharmony_cistatic int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
106862306a36Sopenharmony_ci		      struct dentry *old_dentry, struct inode *new_dir,
106962306a36Sopenharmony_ci		      struct dentry *new_dentry, unsigned int flags)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	struct btstack btstack;
107262306a36Sopenharmony_ci	ino_t ino;
107362306a36Sopenharmony_ci	struct component_name new_dname;
107462306a36Sopenharmony_ci	struct inode *new_ip;
107562306a36Sopenharmony_ci	struct component_name old_dname;
107662306a36Sopenharmony_ci	struct inode *old_ip;
107762306a36Sopenharmony_ci	int rc;
107862306a36Sopenharmony_ci	tid_t tid;
107962306a36Sopenharmony_ci	struct tlock *tlck;
108062306a36Sopenharmony_ci	struct dt_lock *dtlck;
108162306a36Sopenharmony_ci	struct lv *lv;
108262306a36Sopenharmony_ci	int ipcount;
108362306a36Sopenharmony_ci	struct inode *iplist[4];
108462306a36Sopenharmony_ci	struct tblock *tblk;
108562306a36Sopenharmony_ci	s64 new_size = 0;
108662306a36Sopenharmony_ci	int commit_flag;
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (flags & ~RENAME_NOREPLACE)
108962306a36Sopenharmony_ci		return -EINVAL;
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	rc = dquot_initialize(old_dir);
109462306a36Sopenharmony_ci	if (rc)
109562306a36Sopenharmony_ci		goto out1;
109662306a36Sopenharmony_ci	rc = dquot_initialize(new_dir);
109762306a36Sopenharmony_ci	if (rc)
109862306a36Sopenharmony_ci		goto out1;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	old_ip = d_inode(old_dentry);
110162306a36Sopenharmony_ci	new_ip = d_inode(new_dentry);
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	if ((rc = get_UCSname(&old_dname, old_dentry)))
110462306a36Sopenharmony_ci		goto out1;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	if ((rc = get_UCSname(&new_dname, new_dentry)))
110762306a36Sopenharmony_ci		goto out2;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	/*
111062306a36Sopenharmony_ci	 * Make sure source inode number is what we think it is
111162306a36Sopenharmony_ci	 */
111262306a36Sopenharmony_ci	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
111362306a36Sopenharmony_ci	if (rc || (ino != old_ip->i_ino)) {
111462306a36Sopenharmony_ci		rc = -ENOENT;
111562306a36Sopenharmony_ci		goto out3;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/*
111962306a36Sopenharmony_ci	 * Make sure dest inode number (if any) is what we think it is
112062306a36Sopenharmony_ci	 */
112162306a36Sopenharmony_ci	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
112262306a36Sopenharmony_ci	if (!rc) {
112362306a36Sopenharmony_ci		if ((!new_ip) || (ino != new_ip->i_ino)) {
112462306a36Sopenharmony_ci			rc = -ESTALE;
112562306a36Sopenharmony_ci			goto out3;
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci	} else if (rc != -ENOENT)
112862306a36Sopenharmony_ci		goto out3;
112962306a36Sopenharmony_ci	else if (new_ip) {
113062306a36Sopenharmony_ci		/* no entry exists, but one was expected */
113162306a36Sopenharmony_ci		rc = -ESTALE;
113262306a36Sopenharmony_ci		goto out3;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	if (S_ISDIR(old_ip->i_mode)) {
113662306a36Sopenharmony_ci		if (new_ip) {
113762306a36Sopenharmony_ci			if (!dtEmpty(new_ip)) {
113862306a36Sopenharmony_ci				rc = -ENOTEMPTY;
113962306a36Sopenharmony_ci				goto out3;
114062306a36Sopenharmony_ci			}
114162306a36Sopenharmony_ci		}
114262306a36Sopenharmony_ci	} else if (new_ip) {
114362306a36Sopenharmony_ci		IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
114462306a36Sopenharmony_ci		/* Init inode for quota operations. */
114562306a36Sopenharmony_ci		rc = dquot_initialize(new_ip);
114662306a36Sopenharmony_ci		if (rc)
114762306a36Sopenharmony_ci			goto out_unlock;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/*
115162306a36Sopenharmony_ci	 * The real work starts here
115262306a36Sopenharmony_ci	 */
115362306a36Sopenharmony_ci	tid = txBegin(new_dir->i_sb, 0);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/*
115662306a36Sopenharmony_ci	 * How do we know the locking is safe from deadlocks?
115762306a36Sopenharmony_ci	 * The vfs does the hard part for us.  Any time we are taking nested
115862306a36Sopenharmony_ci	 * commit_mutexes, the vfs already has i_mutex held on the parent.
115962306a36Sopenharmony_ci	 * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
116062306a36Sopenharmony_ci	 */
116162306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
116262306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
116362306a36Sopenharmony_ci	if (old_dir != new_dir)
116462306a36Sopenharmony_ci		mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
116562306a36Sopenharmony_ci				  COMMIT_MUTEX_SECOND_PARENT);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	if (new_ip) {
116862306a36Sopenharmony_ci		mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
116962306a36Sopenharmony_ci				  COMMIT_MUTEX_VICTIM);
117062306a36Sopenharmony_ci		/*
117162306a36Sopenharmony_ci		 * Change existing directory entry to new inode number
117262306a36Sopenharmony_ci		 */
117362306a36Sopenharmony_ci		ino = new_ip->i_ino;
117462306a36Sopenharmony_ci		rc = dtModify(tid, new_dir, &new_dname, &ino,
117562306a36Sopenharmony_ci			      old_ip->i_ino, JFS_RENAME);
117662306a36Sopenharmony_ci		if (rc)
117762306a36Sopenharmony_ci			goto out_tx;
117862306a36Sopenharmony_ci		drop_nlink(new_ip);
117962306a36Sopenharmony_ci		if (S_ISDIR(new_ip->i_mode)) {
118062306a36Sopenharmony_ci			drop_nlink(new_ip);
118162306a36Sopenharmony_ci			if (new_ip->i_nlink) {
118262306a36Sopenharmony_ci				mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
118362306a36Sopenharmony_ci				if (old_dir != new_dir)
118462306a36Sopenharmony_ci					mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
118562306a36Sopenharmony_ci				mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
118662306a36Sopenharmony_ci				mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
118762306a36Sopenharmony_ci				if (!S_ISDIR(old_ip->i_mode) && new_ip)
118862306a36Sopenharmony_ci					IWRITE_UNLOCK(new_ip);
118962306a36Sopenharmony_ci				jfs_error(new_ip->i_sb,
119062306a36Sopenharmony_ci					  "new_ip->i_nlink != 0\n");
119162306a36Sopenharmony_ci				return -EIO;
119262306a36Sopenharmony_ci			}
119362306a36Sopenharmony_ci			tblk = tid_to_tblock(tid);
119462306a36Sopenharmony_ci			tblk->xflag |= COMMIT_DELETE;
119562306a36Sopenharmony_ci			tblk->u.ip = new_ip;
119662306a36Sopenharmony_ci		} else if (new_ip->i_nlink == 0) {
119762306a36Sopenharmony_ci			assert(!test_cflag(COMMIT_Nolink, new_ip));
119862306a36Sopenharmony_ci			/* free block resources */
119962306a36Sopenharmony_ci			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
120062306a36Sopenharmony_ci				txAbort(tid, 1);	/* Marks FS Dirty */
120162306a36Sopenharmony_ci				rc = new_size;
120262306a36Sopenharmony_ci				goto out_tx;
120362306a36Sopenharmony_ci			}
120462306a36Sopenharmony_ci			tblk = tid_to_tblock(tid);
120562306a36Sopenharmony_ci			tblk->xflag |= COMMIT_DELETE;
120662306a36Sopenharmony_ci			tblk->u.ip = new_ip;
120762306a36Sopenharmony_ci		} else {
120862306a36Sopenharmony_ci			inode_set_ctime_current(new_ip);
120962306a36Sopenharmony_ci			mark_inode_dirty(new_ip);
121062306a36Sopenharmony_ci		}
121162306a36Sopenharmony_ci	} else {
121262306a36Sopenharmony_ci		/*
121362306a36Sopenharmony_ci		 * Add new directory entry
121462306a36Sopenharmony_ci		 */
121562306a36Sopenharmony_ci		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
121662306a36Sopenharmony_ci			      JFS_CREATE);
121762306a36Sopenharmony_ci		if (rc) {
121862306a36Sopenharmony_ci			jfs_err("jfs_rename didn't expect dtSearch to fail w/rc = %d",
121962306a36Sopenharmony_ci				rc);
122062306a36Sopenharmony_ci			goto out_tx;
122162306a36Sopenharmony_ci		}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		ino = old_ip->i_ino;
122462306a36Sopenharmony_ci		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
122562306a36Sopenharmony_ci		if (rc) {
122662306a36Sopenharmony_ci			if (rc == -EIO)
122762306a36Sopenharmony_ci				jfs_err("jfs_rename: dtInsert returned -EIO");
122862306a36Sopenharmony_ci			goto out_tx;
122962306a36Sopenharmony_ci		}
123062306a36Sopenharmony_ci		if (S_ISDIR(old_ip->i_mode))
123162306a36Sopenharmony_ci			inc_nlink(new_dir);
123262306a36Sopenharmony_ci	}
123362306a36Sopenharmony_ci	/*
123462306a36Sopenharmony_ci	 * Remove old directory entry
123562306a36Sopenharmony_ci	 */
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	ino = old_ip->i_ino;
123862306a36Sopenharmony_ci	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
123962306a36Sopenharmony_ci	if (rc) {
124062306a36Sopenharmony_ci		jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
124162306a36Sopenharmony_ci			rc);
124262306a36Sopenharmony_ci		txAbort(tid, 1);	/* Marks Filesystem dirty */
124362306a36Sopenharmony_ci		goto out_tx;
124462306a36Sopenharmony_ci	}
124562306a36Sopenharmony_ci	if (S_ISDIR(old_ip->i_mode)) {
124662306a36Sopenharmony_ci		drop_nlink(old_dir);
124762306a36Sopenharmony_ci		if (old_dir != new_dir) {
124862306a36Sopenharmony_ci			/*
124962306a36Sopenharmony_ci			 * Change inode number of parent for moved directory
125062306a36Sopenharmony_ci			 */
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci			JFS_IP(old_ip)->i_dtroot.header.idotdot =
125362306a36Sopenharmony_ci				cpu_to_le32(new_dir->i_ino);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci			/* Linelock header of dtree */
125662306a36Sopenharmony_ci			tlck = txLock(tid, old_ip,
125762306a36Sopenharmony_ci				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
125862306a36Sopenharmony_ci				      tlckDTREE | tlckBTROOT | tlckRELINK);
125962306a36Sopenharmony_ci			dtlck = (struct dt_lock *) & tlck->lock;
126062306a36Sopenharmony_ci			ASSERT(dtlck->index == 0);
126162306a36Sopenharmony_ci			lv = & dtlck->lv[0];
126262306a36Sopenharmony_ci			lv->offset = 0;
126362306a36Sopenharmony_ci			lv->length = 1;
126462306a36Sopenharmony_ci			dtlck->index++;
126562306a36Sopenharmony_ci		}
126662306a36Sopenharmony_ci	}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	/*
126962306a36Sopenharmony_ci	 * Update ctime on changed/moved inodes & mark dirty
127062306a36Sopenharmony_ci	 */
127162306a36Sopenharmony_ci	inode_set_ctime_current(old_ip);
127262306a36Sopenharmony_ci	mark_inode_dirty(old_ip);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	new_dir->i_mtime = inode_set_ctime_current(new_dir);
127562306a36Sopenharmony_ci	mark_inode_dirty(new_dir);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	/* Build list of inodes modified by this transaction */
127862306a36Sopenharmony_ci	ipcount = 0;
127962306a36Sopenharmony_ci	iplist[ipcount++] = old_ip;
128062306a36Sopenharmony_ci	if (new_ip)
128162306a36Sopenharmony_ci		iplist[ipcount++] = new_ip;
128262306a36Sopenharmony_ci	iplist[ipcount++] = old_dir;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	if (old_dir != new_dir) {
128562306a36Sopenharmony_ci		iplist[ipcount++] = new_dir;
128662306a36Sopenharmony_ci		old_dir->i_mtime = inode_set_ctime_current(old_dir);
128762306a36Sopenharmony_ci		mark_inode_dirty(old_dir);
128862306a36Sopenharmony_ci	}
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/*
129162306a36Sopenharmony_ci	 * Incomplete truncate of file data can
129262306a36Sopenharmony_ci	 * result in timing problems unless we synchronously commit the
129362306a36Sopenharmony_ci	 * transaction.
129462306a36Sopenharmony_ci	 */
129562306a36Sopenharmony_ci	if (new_size)
129662306a36Sopenharmony_ci		commit_flag = COMMIT_SYNC;
129762306a36Sopenharmony_ci	else
129862306a36Sopenharmony_ci		commit_flag = 0;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	rc = txCommit(tid, ipcount, iplist, commit_flag);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci      out_tx:
130362306a36Sopenharmony_ci	txEnd(tid);
130462306a36Sopenharmony_ci	if (new_ip)
130562306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
130662306a36Sopenharmony_ci	if (old_dir != new_dir)
130762306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
130862306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
130962306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	while (new_size && (rc == 0)) {
131262306a36Sopenharmony_ci		tid = txBegin(new_ip->i_sb, 0);
131362306a36Sopenharmony_ci		mutex_lock(&JFS_IP(new_ip)->commit_mutex);
131462306a36Sopenharmony_ci		new_size = xtTruncate_pmap(tid, new_ip, new_size);
131562306a36Sopenharmony_ci		if (new_size < 0) {
131662306a36Sopenharmony_ci			txAbort(tid, 1);
131762306a36Sopenharmony_ci			rc = new_size;
131862306a36Sopenharmony_ci		} else
131962306a36Sopenharmony_ci			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
132062306a36Sopenharmony_ci		txEnd(tid);
132162306a36Sopenharmony_ci		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
132262306a36Sopenharmony_ci	}
132362306a36Sopenharmony_ci	if (new_ip && (new_ip->i_nlink == 0))
132462306a36Sopenharmony_ci		set_cflag(COMMIT_Nolink, new_ip);
132562306a36Sopenharmony_ci	/*
132662306a36Sopenharmony_ci	 * Truncating the directory index table is not guaranteed.  It
132762306a36Sopenharmony_ci	 * may need to be done iteratively
132862306a36Sopenharmony_ci	 */
132962306a36Sopenharmony_ci	if (test_cflag(COMMIT_Stale, old_dir)) {
133062306a36Sopenharmony_ci		if (old_dir->i_size > 1)
133162306a36Sopenharmony_ci			jfs_truncate_nolock(old_dir, 0);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		clear_cflag(COMMIT_Stale, old_dir);
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci      out_unlock:
133662306a36Sopenharmony_ci	if (new_ip && !S_ISDIR(new_ip->i_mode))
133762306a36Sopenharmony_ci		IWRITE_UNLOCK(new_ip);
133862306a36Sopenharmony_ci      out3:
133962306a36Sopenharmony_ci	free_UCSname(&new_dname);
134062306a36Sopenharmony_ci      out2:
134162306a36Sopenharmony_ci	free_UCSname(&old_dname);
134262306a36Sopenharmony_ci      out1:
134362306a36Sopenharmony_ci	jfs_info("jfs_rename: returning %d", rc);
134462306a36Sopenharmony_ci	return rc;
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci/*
134962306a36Sopenharmony_ci * NAME:	jfs_mknod
135062306a36Sopenharmony_ci *
135162306a36Sopenharmony_ci * FUNCTION:	Create a special file (device)
135262306a36Sopenharmony_ci */
135362306a36Sopenharmony_cistatic int jfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
135462306a36Sopenharmony_ci		     struct dentry *dentry, umode_t mode, dev_t rdev)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	struct jfs_inode_info *jfs_ip;
135762306a36Sopenharmony_ci	struct btstack btstack;
135862306a36Sopenharmony_ci	struct component_name dname;
135962306a36Sopenharmony_ci	ino_t ino;
136062306a36Sopenharmony_ci	struct inode *ip;
136162306a36Sopenharmony_ci	struct inode *iplist[2];
136262306a36Sopenharmony_ci	int rc;
136362306a36Sopenharmony_ci	tid_t tid;
136462306a36Sopenharmony_ci	struct tblock *tblk;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	jfs_info("jfs_mknod: %pd", dentry);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	rc = dquot_initialize(dir);
136962306a36Sopenharmony_ci	if (rc)
137062306a36Sopenharmony_ci		goto out;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if ((rc = get_UCSname(&dname, dentry)))
137362306a36Sopenharmony_ci		goto out;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	ip = ialloc(dir, mode);
137662306a36Sopenharmony_ci	if (IS_ERR(ip)) {
137762306a36Sopenharmony_ci		rc = PTR_ERR(ip);
137862306a36Sopenharmony_ci		goto out1;
137962306a36Sopenharmony_ci	}
138062306a36Sopenharmony_ci	jfs_ip = JFS_IP(ip);
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	tid = txBegin(dir->i_sb, 0);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
138562306a36Sopenharmony_ci	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	rc = jfs_init_acl(tid, ip, dir);
138862306a36Sopenharmony_ci	if (rc)
138962306a36Sopenharmony_ci		goto out3;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
139262306a36Sopenharmony_ci	if (rc) {
139362306a36Sopenharmony_ci		txAbort(tid, 0);
139462306a36Sopenharmony_ci		goto out3;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
139862306a36Sopenharmony_ci		txAbort(tid, 0);
139962306a36Sopenharmony_ci		goto out3;
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	tblk = tid_to_tblock(tid);
140362306a36Sopenharmony_ci	tblk->xflag |= COMMIT_CREATE;
140462306a36Sopenharmony_ci	tblk->ino = ip->i_ino;
140562306a36Sopenharmony_ci	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	ino = ip->i_ino;
140862306a36Sopenharmony_ci	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
140962306a36Sopenharmony_ci		txAbort(tid, 0);
141062306a36Sopenharmony_ci		goto out3;
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	ip->i_op = &jfs_file_inode_operations;
141462306a36Sopenharmony_ci	jfs_ip->dev = new_encode_dev(rdev);
141562306a36Sopenharmony_ci	init_special_inode(ip, ip->i_mode, rdev);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	mark_inode_dirty(ip);
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	dir->i_mtime = inode_set_ctime_current(dir);
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	mark_inode_dirty(dir);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	iplist[0] = dir;
142462306a36Sopenharmony_ci	iplist[1] = ip;
142562306a36Sopenharmony_ci	rc = txCommit(tid, 2, iplist, 0);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci      out3:
142862306a36Sopenharmony_ci	txEnd(tid);
142962306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(ip)->commit_mutex);
143062306a36Sopenharmony_ci	mutex_unlock(&JFS_IP(dir)->commit_mutex);
143162306a36Sopenharmony_ci	if (rc) {
143262306a36Sopenharmony_ci		free_ea_wmap(ip);
143362306a36Sopenharmony_ci		clear_nlink(ip);
143462306a36Sopenharmony_ci		discard_new_inode(ip);
143562306a36Sopenharmony_ci	} else {
143662306a36Sopenharmony_ci		d_instantiate_new(dentry, ip);
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci      out1:
144062306a36Sopenharmony_ci	free_UCSname(&dname);
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci      out:
144362306a36Sopenharmony_ci	jfs_info("jfs_mknod: returning %d", rc);
144462306a36Sopenharmony_ci	return rc;
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	struct btstack btstack;
145062306a36Sopenharmony_ci	ino_t inum;
145162306a36Sopenharmony_ci	struct inode *ip;
145262306a36Sopenharmony_ci	struct component_name key;
145362306a36Sopenharmony_ci	int rc;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	jfs_info("jfs_lookup: name = %pd", dentry);
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	if ((rc = get_UCSname(&key, dentry)))
145862306a36Sopenharmony_ci		return ERR_PTR(rc);
145962306a36Sopenharmony_ci	rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
146062306a36Sopenharmony_ci	free_UCSname(&key);
146162306a36Sopenharmony_ci	if (rc == -ENOENT) {
146262306a36Sopenharmony_ci		ip = NULL;
146362306a36Sopenharmony_ci	} else if (rc) {
146462306a36Sopenharmony_ci		jfs_err("jfs_lookup: dtSearch returned %d", rc);
146562306a36Sopenharmony_ci		ip = ERR_PTR(rc);
146662306a36Sopenharmony_ci	} else {
146762306a36Sopenharmony_ci		ip = jfs_iget(dip->i_sb, inum);
146862306a36Sopenharmony_ci		if (IS_ERR(ip))
146962306a36Sopenharmony_ci			jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
147062306a36Sopenharmony_ci	}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	return d_splice_alias(ip, dentry);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic struct inode *jfs_nfs_get_inode(struct super_block *sb,
147662306a36Sopenharmony_ci		u64 ino, u32 generation)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	struct inode *inode;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (ino == 0)
148162306a36Sopenharmony_ci		return ERR_PTR(-ESTALE);
148262306a36Sopenharmony_ci	inode = jfs_iget(sb, ino);
148362306a36Sopenharmony_ci	if (IS_ERR(inode))
148462306a36Sopenharmony_ci		return ERR_CAST(inode);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	if (generation && inode->i_generation != generation) {
148762306a36Sopenharmony_ci		iput(inode);
148862306a36Sopenharmony_ci		return ERR_PTR(-ESTALE);
148962306a36Sopenharmony_ci	}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	return inode;
149262306a36Sopenharmony_ci}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_cistruct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
149562306a36Sopenharmony_ci		int fh_len, int fh_type)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
149862306a36Sopenharmony_ci				    jfs_nfs_get_inode);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistruct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
150262306a36Sopenharmony_ci		int fh_len, int fh_type)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
150562306a36Sopenharmony_ci				    jfs_nfs_get_inode);
150662306a36Sopenharmony_ci}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_cistruct dentry *jfs_get_parent(struct dentry *dentry)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	unsigned long parent_ino;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	parent_ino =
151362306a36Sopenharmony_ci		le32_to_cpu(JFS_IP(d_inode(dentry))->i_dtroot.header.idotdot);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	return d_obtain_alias(jfs_iget(dentry->d_sb, parent_ino));
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ciconst struct inode_operations jfs_dir_inode_operations = {
151962306a36Sopenharmony_ci	.create		= jfs_create,
152062306a36Sopenharmony_ci	.lookup		= jfs_lookup,
152162306a36Sopenharmony_ci	.link		= jfs_link,
152262306a36Sopenharmony_ci	.unlink		= jfs_unlink,
152362306a36Sopenharmony_ci	.symlink	= jfs_symlink,
152462306a36Sopenharmony_ci	.mkdir		= jfs_mkdir,
152562306a36Sopenharmony_ci	.rmdir		= jfs_rmdir,
152662306a36Sopenharmony_ci	.mknod		= jfs_mknod,
152762306a36Sopenharmony_ci	.rename		= jfs_rename,
152862306a36Sopenharmony_ci	.listxattr	= jfs_listxattr,
152962306a36Sopenharmony_ci	.setattr	= jfs_setattr,
153062306a36Sopenharmony_ci	.fileattr_get	= jfs_fileattr_get,
153162306a36Sopenharmony_ci	.fileattr_set	= jfs_fileattr_set,
153262306a36Sopenharmony_ci#ifdef CONFIG_JFS_POSIX_ACL
153362306a36Sopenharmony_ci	.get_inode_acl	= jfs_get_acl,
153462306a36Sopenharmony_ci	.set_acl	= jfs_set_acl,
153562306a36Sopenharmony_ci#endif
153662306a36Sopenharmony_ci};
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ciWRAP_DIR_ITER(jfs_readdir) // FIXME!
153962306a36Sopenharmony_ciconst struct file_operations jfs_dir_operations = {
154062306a36Sopenharmony_ci	.read		= generic_read_dir,
154162306a36Sopenharmony_ci	.iterate_shared	= shared_jfs_readdir,
154262306a36Sopenharmony_ci	.fsync		= jfs_fsync,
154362306a36Sopenharmony_ci	.unlocked_ioctl = jfs_ioctl,
154462306a36Sopenharmony_ci	.compat_ioctl	= compat_ptr_ioctl,
154562306a36Sopenharmony_ci	.llseek		= generic_file_llseek,
154662306a36Sopenharmony_ci};
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	unsigned long hash;
155162306a36Sopenharmony_ci	int i;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	hash = init_name_hash(dir);
155462306a36Sopenharmony_ci	for (i=0; i < this->len; i++)
155562306a36Sopenharmony_ci		hash = partial_name_hash(tolower(this->name[i]), hash);
155662306a36Sopenharmony_ci	this->hash = end_name_hash(hash);
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	return 0;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic int jfs_ci_compare(const struct dentry *dentry,
156262306a36Sopenharmony_ci		unsigned int len, const char *str, const struct qstr *name)
156362306a36Sopenharmony_ci{
156462306a36Sopenharmony_ci	int i, result = 1;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (len != name->len)
156762306a36Sopenharmony_ci		goto out;
156862306a36Sopenharmony_ci	for (i=0; i < len; i++) {
156962306a36Sopenharmony_ci		if (tolower(str[i]) != tolower(name->name[i]))
157062306a36Sopenharmony_ci			goto out;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci	result = 0;
157362306a36Sopenharmony_ciout:
157462306a36Sopenharmony_ci	return result;
157562306a36Sopenharmony_ci}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_cistatic int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	/*
158062306a36Sopenharmony_ci	 * This is not negative dentry. Always valid.
158162306a36Sopenharmony_ci	 *
158262306a36Sopenharmony_ci	 * Note, rename() to existing directory entry will have ->d_inode,
158362306a36Sopenharmony_ci	 * and will use existing name which isn't specified name by user.
158462306a36Sopenharmony_ci	 *
158562306a36Sopenharmony_ci	 * We may be able to drop this positive dentry here. But dropping
158662306a36Sopenharmony_ci	 * positive dentry isn't good idea. So it's unsupported like
158762306a36Sopenharmony_ci	 * rename("filename", "FILENAME") for now.
158862306a36Sopenharmony_ci	 */
158962306a36Sopenharmony_ci	if (d_really_is_positive(dentry))
159062306a36Sopenharmony_ci		return 1;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	/*
159362306a36Sopenharmony_ci	 * This may be nfsd (or something), anyway, we can't see the
159462306a36Sopenharmony_ci	 * intent of this. So, since this can be for creation, drop it.
159562306a36Sopenharmony_ci	 */
159662306a36Sopenharmony_ci	if (!flags)
159762306a36Sopenharmony_ci		return 0;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	/*
160062306a36Sopenharmony_ci	 * Drop the negative dentry, in order to make sure to use the
160162306a36Sopenharmony_ci	 * case sensitive name which is specified by user if this is
160262306a36Sopenharmony_ci	 * for creation.
160362306a36Sopenharmony_ci	 */
160462306a36Sopenharmony_ci	if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
160562306a36Sopenharmony_ci		return 0;
160662306a36Sopenharmony_ci	return 1;
160762306a36Sopenharmony_ci}
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ciconst struct dentry_operations jfs_ci_dentry_operations =
161062306a36Sopenharmony_ci{
161162306a36Sopenharmony_ci	.d_hash = jfs_ci_hash,
161262306a36Sopenharmony_ci	.d_compare = jfs_ci_compare,
161362306a36Sopenharmony_ci	.d_revalidate = jfs_ci_revalidate,
161462306a36Sopenharmony_ci};
1615