xref: /openbmc/linux/fs/jfs/namei.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *   Copyright (C) International Business Machines Corp., 2000-2004
41da177e4SLinus Torvalds  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <linux/fs.h>
82bc334dcSNick Piggin #include <linux/namei.h>
91da177e4SLinus Torvalds #include <linux/ctype.h>
101da177e4SLinus Torvalds #include <linux/quotaops.h>
11d425de70SChristoph Hellwig #include <linux/exportfs.h>
121da177e4SLinus Torvalds #include "jfs_incore.h"
131da177e4SLinus Torvalds #include "jfs_superblock.h"
141da177e4SLinus Torvalds #include "jfs_inode.h"
151da177e4SLinus Torvalds #include "jfs_dinode.h"
161da177e4SLinus Torvalds #include "jfs_dmap.h"
171da177e4SLinus Torvalds #include "jfs_unicode.h"
181da177e4SLinus Torvalds #include "jfs_metapage.h"
191da177e4SLinus Torvalds #include "jfs_xattr.h"
201da177e4SLinus Torvalds #include "jfs_acl.h"
211da177e4SLinus Torvalds #include "jfs_debug.h"
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds /*
241da177e4SLinus Torvalds  * forward references
251da177e4SLinus Torvalds  */
26ad28b4efSAl Viro const struct dentry_operations jfs_ci_dentry_operations;
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds static s64 commitZeroLink(tid_t, struct inode *);
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
314f4b401bSDave Kleikamp  * NAME:	free_ea_wmap(inode)
324f4b401bSDave Kleikamp  *
334f4b401bSDave Kleikamp  * FUNCTION:	free uncommitted extended attributes from working map
344f4b401bSDave Kleikamp  *
354f4b401bSDave Kleikamp  */
free_ea_wmap(struct inode * inode)364f4b401bSDave Kleikamp static inline void free_ea_wmap(struct inode *inode)
374f4b401bSDave Kleikamp {
384f4b401bSDave Kleikamp 	dxd_t *ea = &JFS_IP(inode)->ea;
394f4b401bSDave Kleikamp 
404f4b401bSDave Kleikamp 	if (ea->flag & DXD_EXTENT) {
414f4b401bSDave Kleikamp 		/* free EA pages from cache */
424f4b401bSDave Kleikamp 		invalidate_dxd_metapages(inode, *ea);
434f4b401bSDave Kleikamp 		dbFree(inode, addressDXD(ea), lengthDXD(ea));
444f4b401bSDave Kleikamp 	}
454f4b401bSDave Kleikamp 	ea->flag = 0;
464f4b401bSDave Kleikamp }
474f4b401bSDave Kleikamp 
484f4b401bSDave Kleikamp /*
491da177e4SLinus Torvalds  * NAME:	jfs_create(dip, dentry, mode)
501da177e4SLinus Torvalds  *
511da177e4SLinus Torvalds  * FUNCTION:	create a regular file in the parent directory <dip>
521da177e4SLinus Torvalds  *		with name = <from dentry> and mode = <mode>
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  * PARAMETER:	dip	- parent directory vnode
551da177e4SLinus Torvalds  *		dentry	- dentry of new file
561da177e4SLinus Torvalds  *		mode	- create mode (rwxrwxrwx).
571da177e4SLinus Torvalds  *		nd- nd struct
581da177e4SLinus Torvalds  *
591da177e4SLinus Torvalds  * RETURN:	Errors from subroutines
601da177e4SLinus Torvalds  *
611da177e4SLinus Torvalds  */
jfs_create(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,umode_t mode,bool excl)626c960e68SChristian Brauner static int jfs_create(struct mnt_idmap *idmap, struct inode *dip,
63549c7297SChristian Brauner 		      struct dentry *dentry, umode_t mode, bool excl)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	int rc = 0;
661da177e4SLinus Torvalds 	tid_t tid;		/* transaction id */
671da177e4SLinus Torvalds 	struct inode *ip = NULL;	/* child directory inode */
681da177e4SLinus Torvalds 	ino_t ino;
691da177e4SLinus Torvalds 	struct component_name dname;	/* child directory name */
701da177e4SLinus Torvalds 	struct btstack btstack;
711da177e4SLinus Torvalds 	struct inode *iplist[2];
721da177e4SLinus Torvalds 	struct tblock *tblk;
731da177e4SLinus Torvalds 
74a455589fSAl Viro 	jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
751da177e4SLinus Torvalds 
76acc84b05SDave Kleikamp 	rc = dquot_initialize(dip);
77acc84b05SDave Kleikamp 	if (rc)
78acc84b05SDave Kleikamp 		goto out1;
79907f4554SChristoph Hellwig 
801da177e4SLinus Torvalds 	/*
811da177e4SLinus Torvalds 	 * search parent directory for entry/freespace
821da177e4SLinus Torvalds 	 * (dtSearch() returns parent directory page pinned)
831da177e4SLinus Torvalds 	 */
841da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
851da177e4SLinus Torvalds 		goto out1;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	/*
881da177e4SLinus Torvalds 	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
891da177e4SLinus Torvalds 	 * block there while holding dtree page, so we allocate the inode &
901da177e4SLinus Torvalds 	 * begin the transaction before we search the directory.
911da177e4SLinus Torvalds 	 */
921da177e4SLinus Torvalds 	ip = ialloc(dip, mode);
93087387f9SAkinobu Mita 	if (IS_ERR(ip)) {
94087387f9SAkinobu Mita 		rc = PTR_ERR(ip);
951da177e4SLinus Torvalds 		goto out2;
961da177e4SLinus Torvalds 	}
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	tid = txBegin(dip->i_sb, 0);
991da177e4SLinus Torvalds 
10082d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
10182d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
1021da177e4SLinus Torvalds 
1034f4b401bSDave Kleikamp 	rc = jfs_init_acl(tid, ip, dip);
1044f4b401bSDave Kleikamp 	if (rc)
1054f4b401bSDave Kleikamp 		goto out3;
1064f4b401bSDave Kleikamp 
1072a7dba39SEric Paris 	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
1081d15b10fSDave Kleikamp 	if (rc) {
1091d15b10fSDave Kleikamp 		txAbort(tid, 0);
1101d15b10fSDave Kleikamp 		goto out3;
1111d15b10fSDave Kleikamp 	}
1121d15b10fSDave Kleikamp 
1131da177e4SLinus Torvalds 	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
1141da177e4SLinus Torvalds 		jfs_err("jfs_create: dtSearch returned %d", rc);
1154f4b401bSDave Kleikamp 		txAbort(tid, 0);
1161da177e4SLinus Torvalds 		goto out3;
1171da177e4SLinus Torvalds 	}
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
1201da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_CREATE;
1211da177e4SLinus Torvalds 	tblk->ino = ip->i_ino;
1221da177e4SLinus Torvalds 	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	iplist[0] = dip;
1251da177e4SLinus Torvalds 	iplist[1] = ip;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds 	/*
1281da177e4SLinus Torvalds 	 * initialize the child XAD tree root in-line in inode
1291da177e4SLinus Torvalds 	 */
1301da177e4SLinus Torvalds 	xtInitRoot(tid, ip);
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	/*
1331da177e4SLinus Torvalds 	 * create entry in parent directory for child directory
1341da177e4SLinus Torvalds 	 * (dtInsert() releases parent directory page)
1351da177e4SLinus Torvalds 	 */
1361da177e4SLinus Torvalds 	ino = ip->i_ino;
1371da177e4SLinus Torvalds 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
1381da177e4SLinus Torvalds 		if (rc == -EIO) {
1391da177e4SLinus Torvalds 			jfs_err("jfs_create: dtInsert returned -EIO");
1401da177e4SLinus Torvalds 			txAbort(tid, 1);	/* Marks Filesystem dirty */
1411da177e4SLinus Torvalds 		} else
1421da177e4SLinus Torvalds 			txAbort(tid, 0);	/* Filesystem full */
1431da177e4SLinus Torvalds 		goto out3;
1441da177e4SLinus Torvalds 	}
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 	ip->i_op = &jfs_file_inode_operations;
1471da177e4SLinus Torvalds 	ip->i_fop = &jfs_file_operations;
1481da177e4SLinus Torvalds 	ip->i_mapping->a_ops = &jfs_aops;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	mark_inode_dirty(ip);
1511da177e4SLinus Torvalds 
152ad9dc5dfSJeff Layton 	dip->i_mtime = inode_set_ctime_current(dip);
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	mark_inode_dirty(dip);
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], 0);
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds       out3:
1591da177e4SLinus Torvalds 	txEnd(tid);
1601de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
16148ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
1621da177e4SLinus Torvalds 	if (rc) {
1634f4b401bSDave Kleikamp 		free_ea_wmap(ip);
1646d6b77f1SMiklos Szeredi 		clear_nlink(ip);
165a6cbedfaSAl Viro 		discard_new_inode(ip);
1661f3403faSDave Kleikamp 	} else {
1671e2e547aSAl Viro 		d_instantiate_new(dentry, ip);
1681f3403faSDave Kleikamp 	}
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds       out2:
1711da177e4SLinus Torvalds 	free_UCSname(&dname);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds       out1:
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	jfs_info("jfs_create: rc:%d", rc);
1761da177e4SLinus Torvalds 	return rc;
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds /*
1811da177e4SLinus Torvalds  * NAME:	jfs_mkdir(dip, dentry, mode)
1821da177e4SLinus Torvalds  *
1831da177e4SLinus Torvalds  * FUNCTION:	create a child directory in the parent directory <dip>
1841da177e4SLinus Torvalds  *		with name = <from dentry> and mode = <mode>
1851da177e4SLinus Torvalds  *
1861da177e4SLinus Torvalds  * PARAMETER:	dip	- parent directory vnode
1871da177e4SLinus Torvalds  *		dentry	- dentry of child directory
1881da177e4SLinus Torvalds  *		mode	- create mode (rwxrwxrwx).
1891da177e4SLinus Torvalds  *
1901da177e4SLinus Torvalds  * RETURN:	Errors from subroutines
1911da177e4SLinus Torvalds  *
1921da177e4SLinus Torvalds  * note:
193a83722f4SColin Ian King  * EACCES: user needs search+write permission on the parent directory
1941da177e4SLinus Torvalds  */
jfs_mkdir(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,umode_t mode)195c54bd91eSChristian Brauner static int jfs_mkdir(struct mnt_idmap *idmap, struct inode *dip,
196549c7297SChristian Brauner 		     struct dentry *dentry, umode_t mode)
1971da177e4SLinus Torvalds {
1981da177e4SLinus Torvalds 	int rc = 0;
1991da177e4SLinus Torvalds 	tid_t tid;		/* transaction id */
2001da177e4SLinus Torvalds 	struct inode *ip = NULL;	/* child directory inode */
2011da177e4SLinus Torvalds 	ino_t ino;
2021da177e4SLinus Torvalds 	struct component_name dname;	/* child directory name */
2031da177e4SLinus Torvalds 	struct btstack btstack;
2041da177e4SLinus Torvalds 	struct inode *iplist[2];
2051da177e4SLinus Torvalds 	struct tblock *tblk;
2061da177e4SLinus Torvalds 
207a455589fSAl Viro 	jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
2081da177e4SLinus Torvalds 
209acc84b05SDave Kleikamp 	rc = dquot_initialize(dip);
210acc84b05SDave Kleikamp 	if (rc)
211acc84b05SDave Kleikamp 		goto out1;
212907f4554SChristoph Hellwig 
2131da177e4SLinus Torvalds 	/*
2141da177e4SLinus Torvalds 	 * search parent directory for entry/freespace
2151da177e4SLinus Torvalds 	 * (dtSearch() returns parent directory page pinned)
2161da177e4SLinus Torvalds 	 */
2171da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
2181da177e4SLinus Torvalds 		goto out1;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 	/*
2211da177e4SLinus Torvalds 	 * Either iAlloc() or txBegin() may block.  Deadlock can occur if we
2221da177e4SLinus Torvalds 	 * block there while holding dtree page, so we allocate the inode &
2231da177e4SLinus Torvalds 	 * begin the transaction before we search the directory.
2241da177e4SLinus Torvalds 	 */
2251da177e4SLinus Torvalds 	ip = ialloc(dip, S_IFDIR | mode);
226087387f9SAkinobu Mita 	if (IS_ERR(ip)) {
227087387f9SAkinobu Mita 		rc = PTR_ERR(ip);
2281da177e4SLinus Torvalds 		goto out2;
2291da177e4SLinus Torvalds 	}
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	tid = txBegin(dip->i_sb, 0);
2321da177e4SLinus Torvalds 
23382d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
23482d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
2351da177e4SLinus Torvalds 
2364f4b401bSDave Kleikamp 	rc = jfs_init_acl(tid, ip, dip);
2374f4b401bSDave Kleikamp 	if (rc)
2384f4b401bSDave Kleikamp 		goto out3;
2394f4b401bSDave Kleikamp 
2402a7dba39SEric Paris 	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
2411d15b10fSDave Kleikamp 	if (rc) {
2421d15b10fSDave Kleikamp 		txAbort(tid, 0);
2431d15b10fSDave Kleikamp 		goto out3;
2441d15b10fSDave Kleikamp 	}
2451d15b10fSDave Kleikamp 
2461da177e4SLinus Torvalds 	if ((rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE))) {
2471da177e4SLinus Torvalds 		jfs_err("jfs_mkdir: dtSearch returned %d", rc);
2484f4b401bSDave Kleikamp 		txAbort(tid, 0);
2491da177e4SLinus Torvalds 		goto out3;
2501da177e4SLinus Torvalds 	}
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
2531da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_CREATE;
2541da177e4SLinus Torvalds 	tblk->ino = ip->i_ino;
2551da177e4SLinus Torvalds 	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 	iplist[0] = dip;
2581da177e4SLinus Torvalds 	iplist[1] = ip;
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	/*
2611da177e4SLinus Torvalds 	 * initialize the child directory in-line in inode
2621da177e4SLinus Torvalds 	 */
2631da177e4SLinus Torvalds 	dtInitRoot(tid, ip, dip->i_ino);
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	/*
2661da177e4SLinus Torvalds 	 * create entry in parent directory for child directory
2671da177e4SLinus Torvalds 	 * (dtInsert() releases parent directory page)
2681da177e4SLinus Torvalds 	 */
2691da177e4SLinus Torvalds 	ino = ip->i_ino;
2701da177e4SLinus Torvalds 	if ((rc = dtInsert(tid, dip, &dname, &ino, &btstack))) {
2711da177e4SLinus Torvalds 		if (rc == -EIO) {
2721da177e4SLinus Torvalds 			jfs_err("jfs_mkdir: dtInsert returned -EIO");
2731da177e4SLinus Torvalds 			txAbort(tid, 1);	/* Marks Filesystem dirty */
2741da177e4SLinus Torvalds 		} else
2751da177e4SLinus Torvalds 			txAbort(tid, 0);	/* Filesystem full */
2761da177e4SLinus Torvalds 		goto out3;
2771da177e4SLinus Torvalds 	}
2781da177e4SLinus Torvalds 
279bfe86848SMiklos Szeredi 	set_nlink(ip, 2);	/* for '.' */
2801da177e4SLinus Torvalds 	ip->i_op = &jfs_dir_inode_operations;
2811da177e4SLinus Torvalds 	ip->i_fop = &jfs_dir_operations;
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds 	mark_inode_dirty(ip);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 	/* update parent directory inode */
286d8c76e6fSDave Hansen 	inc_nlink(dip);		/* for '..' from child directory */
287ad9dc5dfSJeff Layton 	dip->i_mtime = inode_set_ctime_current(dip);
2881da177e4SLinus Torvalds 	mark_inode_dirty(dip);
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], 0);
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds       out3:
2931da177e4SLinus Torvalds 	txEnd(tid);
2941de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
29548ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
2961da177e4SLinus Torvalds 	if (rc) {
2974f4b401bSDave Kleikamp 		free_ea_wmap(ip);
2986d6b77f1SMiklos Szeredi 		clear_nlink(ip);
299a6cbedfaSAl Viro 		discard_new_inode(ip);
3001f3403faSDave Kleikamp 	} else {
3011e2e547aSAl Viro 		d_instantiate_new(dentry, ip);
3021f3403faSDave Kleikamp 	}
3031da177e4SLinus Torvalds 
3041da177e4SLinus Torvalds       out2:
3051da177e4SLinus Torvalds 	free_UCSname(&dname);
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds       out1:
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	jfs_info("jfs_mkdir: rc:%d", rc);
3111da177e4SLinus Torvalds 	return rc;
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds /*
3151da177e4SLinus Torvalds  * NAME:	jfs_rmdir(dip, dentry)
3161da177e4SLinus Torvalds  *
3171da177e4SLinus Torvalds  * FUNCTION:	remove a link to child directory
3181da177e4SLinus Torvalds  *
3191da177e4SLinus Torvalds  * PARAMETER:	dip	- parent inode
3201da177e4SLinus Torvalds  *		dentry	- child directory dentry
3211da177e4SLinus Torvalds  *
3221da177e4SLinus Torvalds  * RETURN:	-EINVAL	- if name is . or ..
3231da177e4SLinus Torvalds  *		-EINVAL - if . or .. exist but are invalid.
3241da177e4SLinus Torvalds  *		errors from subroutines
3251da177e4SLinus Torvalds  *
3261da177e4SLinus Torvalds  * note:
3271da177e4SLinus Torvalds  * if other threads have the directory open when the last link
3281da177e4SLinus Torvalds  * is removed, the "." and ".." entries, if present, are removed before
3291da177e4SLinus Torvalds  * rmdir() returns and no new entries may be created in the directory,
3301da177e4SLinus Torvalds  * but the directory is not removed until the last reference to
3311da177e4SLinus Torvalds  * the directory is released (cf.unlink() of regular file).
3321da177e4SLinus Torvalds  */
jfs_rmdir(struct inode * dip,struct dentry * dentry)3331da177e4SLinus Torvalds static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	int rc;
3361da177e4SLinus Torvalds 	tid_t tid;		/* transaction id */
3372b0143b5SDavid Howells 	struct inode *ip = d_inode(dentry);
3381da177e4SLinus Torvalds 	ino_t ino;
3391da177e4SLinus Torvalds 	struct component_name dname;
3401da177e4SLinus Torvalds 	struct inode *iplist[2];
3411da177e4SLinus Torvalds 	struct tblock *tblk;
3421da177e4SLinus Torvalds 
343a455589fSAl Viro 	jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	/* Init inode for quota operations. */
346acc84b05SDave Kleikamp 	rc = dquot_initialize(dip);
347acc84b05SDave Kleikamp 	if (rc)
348acc84b05SDave Kleikamp 		goto out;
349acc84b05SDave Kleikamp 	rc = dquot_initialize(ip);
350acc84b05SDave Kleikamp 	if (rc)
351acc84b05SDave Kleikamp 		goto out;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	/* directory must be empty to be removed */
3541da177e4SLinus Torvalds 	if (!dtEmpty(ip)) {
3551da177e4SLinus Torvalds 		rc = -ENOTEMPTY;
3561da177e4SLinus Torvalds 		goto out;
3571da177e4SLinus Torvalds 	}
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry))) {
3601da177e4SLinus Torvalds 		goto out;
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	tid = txBegin(dip->i_sb, 0);
3641da177e4SLinus Torvalds 
36582d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
36682d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
3671da177e4SLinus Torvalds 
3681da177e4SLinus Torvalds 	iplist[0] = dip;
3691da177e4SLinus Torvalds 	iplist[1] = ip;
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
3721da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_DELETE;
3731da177e4SLinus Torvalds 	tblk->u.ip = ip;
3741da177e4SLinus Torvalds 
3751da177e4SLinus Torvalds 	/*
3761da177e4SLinus Torvalds 	 * delete the entry of target directory from parent directory
3771da177e4SLinus Torvalds 	 */
3781da177e4SLinus Torvalds 	ino = ip->i_ino;
3791da177e4SLinus Torvalds 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
3801da177e4SLinus Torvalds 		jfs_err("jfs_rmdir: dtDelete returned %d", rc);
3811da177e4SLinus Torvalds 		if (rc == -EIO)
3821da177e4SLinus Torvalds 			txAbort(tid, 1);
3831da177e4SLinus Torvalds 		txEnd(tid);
3841de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
38548ce8b05SEvgeniy Dushistov 		mutex_unlock(&JFS_IP(dip)->commit_mutex);
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 		goto out2;
3881da177e4SLinus Torvalds 	}
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds 	/* update parent directory's link count corresponding
3911da177e4SLinus Torvalds 	 * to ".." entry of the target directory deleted
3921da177e4SLinus Torvalds 	 */
393ad9dc5dfSJeff Layton 	dip->i_mtime = inode_set_ctime_current(dip);
3949a53c3a7SDave Hansen 	inode_dec_link_count(dip);
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 	/*
3971da177e4SLinus Torvalds 	 * OS/2 could have created EA and/or ACL
3981da177e4SLinus Torvalds 	 */
3991da177e4SLinus Torvalds 	/* free EA from both persistent and working map */
4001da177e4SLinus Torvalds 	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
4011da177e4SLinus Torvalds 		/* free EA pages */
4021da177e4SLinus Torvalds 		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
4031da177e4SLinus Torvalds 	}
4041da177e4SLinus Torvalds 	JFS_IP(ip)->ea.flag = 0;
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	/* free ACL from both persistent and working map */
4071da177e4SLinus Torvalds 	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
4081da177e4SLinus Torvalds 		/* free ACL pages */
4091da177e4SLinus Torvalds 		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 	JFS_IP(ip)->acl.flag = 0;
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	/* mark the target directory as deleted */
414ce71ec36SDave Hansen 	clear_nlink(ip);
4151da177e4SLinus Torvalds 	mark_inode_dirty(ip);
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], 0);
4181da177e4SLinus Torvalds 
4191da177e4SLinus Torvalds 	txEnd(tid);
4201da177e4SLinus Torvalds 
4211de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
42248ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	/*
4251da177e4SLinus Torvalds 	 * Truncating the directory index table is not guaranteed.  It
4261da177e4SLinus Torvalds 	 * may need to be done iteratively
4271da177e4SLinus Torvalds 	 */
4281da177e4SLinus Torvalds 	if (test_cflag(COMMIT_Stale, dip)) {
4291da177e4SLinus Torvalds 		if (dip->i_size > 1)
4301da177e4SLinus Torvalds 			jfs_truncate_nolock(dip, 0);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 		clear_cflag(COMMIT_Stale, dip);
4331da177e4SLinus Torvalds 	}
4341da177e4SLinus Torvalds 
4351da177e4SLinus Torvalds       out2:
4361da177e4SLinus Torvalds 	free_UCSname(&dname);
4371da177e4SLinus Torvalds 
4381da177e4SLinus Torvalds       out:
4391da177e4SLinus Torvalds 	jfs_info("jfs_rmdir: rc:%d", rc);
4401da177e4SLinus Torvalds 	return rc;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds 
4431da177e4SLinus Torvalds /*
4441da177e4SLinus Torvalds  * NAME:	jfs_unlink(dip, dentry)
4451da177e4SLinus Torvalds  *
4461da177e4SLinus Torvalds  * FUNCTION:	remove a link to object <vp> named by <name>
4471da177e4SLinus Torvalds  *		from parent directory <dvp>
4481da177e4SLinus Torvalds  *
4491da177e4SLinus Torvalds  * PARAMETER:	dip	- inode of parent directory
4501da177e4SLinus Torvalds  *		dentry	- dentry of object to be removed
4511da177e4SLinus Torvalds  *
4521da177e4SLinus Torvalds  * RETURN:	errors from subroutines
4531da177e4SLinus Torvalds  *
4541da177e4SLinus Torvalds  * note:
4551da177e4SLinus Torvalds  * temporary file: if one or more processes have the file open
4561da177e4SLinus Torvalds  * when the last link is removed, the link will be removed before
4571da177e4SLinus Torvalds  * unlink() returns, but the removal of the file contents will be
4581da177e4SLinus Torvalds  * postponed until all references to the files are closed.
4591da177e4SLinus Torvalds  *
4601da177e4SLinus Torvalds  * JFS does NOT support unlink() on directories.
4611da177e4SLinus Torvalds  *
4621da177e4SLinus Torvalds  */
jfs_unlink(struct inode * dip,struct dentry * dentry)4631da177e4SLinus Torvalds static int jfs_unlink(struct inode *dip, struct dentry *dentry)
4641da177e4SLinus Torvalds {
4651da177e4SLinus Torvalds 	int rc;
4661da177e4SLinus Torvalds 	tid_t tid;		/* transaction id */
4672b0143b5SDavid Howells 	struct inode *ip = d_inode(dentry);
4681da177e4SLinus Torvalds 	ino_t ino;
4691da177e4SLinus Torvalds 	struct component_name dname;	/* object name */
4701da177e4SLinus Torvalds 	struct inode *iplist[2];
4711da177e4SLinus Torvalds 	struct tblock *tblk;
4721da177e4SLinus Torvalds 	s64 new_size = 0;
4731da177e4SLinus Torvalds 	int commit_flag;
4741da177e4SLinus Torvalds 
475a455589fSAl Viro 	jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	/* Init inode for quota operations. */
478acc84b05SDave Kleikamp 	rc = dquot_initialize(dip);
479acc84b05SDave Kleikamp 	if (rc)
480acc84b05SDave Kleikamp 		goto out;
481acc84b05SDave Kleikamp 	rc = dquot_initialize(ip);
482acc84b05SDave Kleikamp 	if (rc)
483acc84b05SDave Kleikamp 		goto out;
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
4861da177e4SLinus Torvalds 		goto out;
4871da177e4SLinus Torvalds 
48882d5b9a7SDave Kleikamp 	IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
4891da177e4SLinus Torvalds 
4901da177e4SLinus Torvalds 	tid = txBegin(dip->i_sb, 0);
4911da177e4SLinus Torvalds 
49282d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
49382d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	iplist[0] = dip;
4961da177e4SLinus Torvalds 	iplist[1] = ip;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 	/*
4991da177e4SLinus Torvalds 	 * delete the entry of target file from parent directory
5001da177e4SLinus Torvalds 	 */
5011da177e4SLinus Torvalds 	ino = ip->i_ino;
5021da177e4SLinus Torvalds 	if ((rc = dtDelete(tid, dip, &dname, &ino, JFS_REMOVE))) {
5031da177e4SLinus Torvalds 		jfs_err("jfs_unlink: dtDelete returned %d", rc);
5041da177e4SLinus Torvalds 		if (rc == -EIO)
5051da177e4SLinus Torvalds 			txAbort(tid, 1);	/* Marks FS Dirty */
5061da177e4SLinus Torvalds 		txEnd(tid);
5071de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
50848ce8b05SEvgeniy Dushistov 		mutex_unlock(&JFS_IP(dip)->commit_mutex);
5091da177e4SLinus Torvalds 		IWRITE_UNLOCK(ip);
5101da177e4SLinus Torvalds 		goto out1;
5111da177e4SLinus Torvalds 	}
5121da177e4SLinus Torvalds 
5131da177e4SLinus Torvalds 	ASSERT(ip->i_nlink);
5141da177e4SLinus Torvalds 
515ad9dc5dfSJeff Layton 	dip->i_mtime = inode_set_ctime_to_ts(dip, inode_set_ctime_current(ip));
5161da177e4SLinus Torvalds 	mark_inode_dirty(dip);
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds 	/* update target's inode */
5199a53c3a7SDave Hansen 	inode_dec_link_count(ip);
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	/*
5221da177e4SLinus Torvalds 	 *	commit zero link count object
5231da177e4SLinus Torvalds 	 */
5241da177e4SLinus Torvalds 	if (ip->i_nlink == 0) {
5251da177e4SLinus Torvalds 		assert(!test_cflag(COMMIT_Nolink, ip));
5261da177e4SLinus Torvalds 		/* free block resources */
5271da177e4SLinus Torvalds 		if ((new_size = commitZeroLink(tid, ip)) < 0) {
5281da177e4SLinus Torvalds 			txAbort(tid, 1);	/* Marks FS Dirty */
5291da177e4SLinus Torvalds 			txEnd(tid);
5301de87444SIngo Molnar 			mutex_unlock(&JFS_IP(ip)->commit_mutex);
53148ce8b05SEvgeniy Dushistov 			mutex_unlock(&JFS_IP(dip)->commit_mutex);
5321da177e4SLinus Torvalds 			IWRITE_UNLOCK(ip);
5331da177e4SLinus Torvalds 			rc = new_size;
5341da177e4SLinus Torvalds 			goto out1;
5351da177e4SLinus Torvalds 		}
5361da177e4SLinus Torvalds 		tblk = tid_to_tblock(tid);
5371da177e4SLinus Torvalds 		tblk->xflag |= COMMIT_DELETE;
5381da177e4SLinus Torvalds 		tblk->u.ip = ip;
5391da177e4SLinus Torvalds 	}
5401da177e4SLinus Torvalds 
5411da177e4SLinus Torvalds 	/*
5421da177e4SLinus Torvalds 	 * Incomplete truncate of file data can
5431da177e4SLinus Torvalds 	 * result in timing problems unless we synchronously commit the
5441da177e4SLinus Torvalds 	 * transaction.
5451da177e4SLinus Torvalds 	 */
5461da177e4SLinus Torvalds 	if (new_size)
5471da177e4SLinus Torvalds 		commit_flag = COMMIT_SYNC;
5481da177e4SLinus Torvalds 	else
5491da177e4SLinus Torvalds 		commit_flag = 0;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 	/*
5521da177e4SLinus Torvalds 	 * If xtTruncate was incomplete, commit synchronously to avoid
5531da177e4SLinus Torvalds 	 * timing complications
5541da177e4SLinus Torvalds 	 */
5551da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], commit_flag);
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds 	txEnd(tid);
5581da177e4SLinus Torvalds 
5591de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
56048ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	while (new_size && (rc == 0)) {
5631da177e4SLinus Torvalds 		tid = txBegin(dip->i_sb, 0);
5641de87444SIngo Molnar 		mutex_lock(&JFS_IP(ip)->commit_mutex);
5651da177e4SLinus Torvalds 		new_size = xtTruncate_pmap(tid, ip, new_size);
5661da177e4SLinus Torvalds 		if (new_size < 0) {
5671da177e4SLinus Torvalds 			txAbort(tid, 1);	/* Marks FS Dirty */
5681da177e4SLinus Torvalds 			rc = new_size;
5691da177e4SLinus Torvalds 		} else
5701da177e4SLinus Torvalds 			rc = txCommit(tid, 2, &iplist[0], COMMIT_SYNC);
5711da177e4SLinus Torvalds 		txEnd(tid);
5721de87444SIngo Molnar 		mutex_unlock(&JFS_IP(ip)->commit_mutex);
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	if (ip->i_nlink == 0)
5761da177e4SLinus Torvalds 		set_cflag(COMMIT_Nolink, ip);
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds 	IWRITE_UNLOCK(ip);
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 	/*
5811da177e4SLinus Torvalds 	 * Truncating the directory index table is not guaranteed.  It
5821da177e4SLinus Torvalds 	 * may need to be done iteratively
5831da177e4SLinus Torvalds 	 */
5841da177e4SLinus Torvalds 	if (test_cflag(COMMIT_Stale, dip)) {
5851da177e4SLinus Torvalds 		if (dip->i_size > 1)
5861da177e4SLinus Torvalds 			jfs_truncate_nolock(dip, 0);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 		clear_cflag(COMMIT_Stale, dip);
5891da177e4SLinus Torvalds 	}
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds       out1:
5921da177e4SLinus Torvalds 	free_UCSname(&dname);
5931da177e4SLinus Torvalds       out:
5941da177e4SLinus Torvalds 	jfs_info("jfs_unlink: rc:%d", rc);
5951da177e4SLinus Torvalds 	return rc;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds /*
5991da177e4SLinus Torvalds  * NAME:	commitZeroLink()
6001da177e4SLinus Torvalds  *
6011da177e4SLinus Torvalds  * FUNCTION:	for non-directory, called by jfs_remove(),
6021da177e4SLinus Torvalds  *		truncate a regular file, directory or symbolic
6031da177e4SLinus Torvalds  *		link to zero length. return 0 if type is not
6041da177e4SLinus Torvalds  *		one of these.
6051da177e4SLinus Torvalds  *
6061da177e4SLinus Torvalds  *		if the file is currently associated with a VM segment
6071da177e4SLinus Torvalds  *		only permanent disk and inode map resources are freed,
6081da177e4SLinus Torvalds  *		and neither the inode nor indirect blocks are modified
6091da177e4SLinus Torvalds  *		so that the resources can be later freed in the work
6101da177e4SLinus Torvalds  *		map by ctrunc1.
6111da177e4SLinus Torvalds  *		if there is no VM segment on entry, the resources are
6121da177e4SLinus Torvalds  *		freed in both work and permanent map.
6131da177e4SLinus Torvalds  *		(? for temporary file - memory object is cached even
6141da177e4SLinus Torvalds  *		after no reference:
6151da177e4SLinus Torvalds  *		reference count > 0 -   )
6161da177e4SLinus Torvalds  *
6171da177e4SLinus Torvalds  * PARAMETERS:	cd	- pointer to commit data structure.
6181da177e4SLinus Torvalds  *			  current inode is the one to truncate.
6191da177e4SLinus Torvalds  *
6201da177e4SLinus Torvalds  * RETURN:	Errors from subroutines
6211da177e4SLinus Torvalds  */
commitZeroLink(tid_t tid,struct inode * ip)6221da177e4SLinus Torvalds static s64 commitZeroLink(tid_t tid, struct inode *ip)
6231da177e4SLinus Torvalds {
6241da177e4SLinus Torvalds 	int filetype;
6251da177e4SLinus Torvalds 	struct tblock *tblk;
6261da177e4SLinus Torvalds 
6271da177e4SLinus Torvalds 	jfs_info("commitZeroLink: tid = %d, ip = 0x%p", tid, ip);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	filetype = ip->i_mode & S_IFMT;
6301da177e4SLinus Torvalds 	switch (filetype) {
6311da177e4SLinus Torvalds 	case S_IFREG:
6321da177e4SLinus Torvalds 		break;
6331da177e4SLinus Torvalds 	case S_IFLNK:
6341da177e4SLinus Torvalds 		/* fast symbolic link */
6351da177e4SLinus Torvalds 		if (ip->i_size < IDATASIZE) {
6361da177e4SLinus Torvalds 			ip->i_size = 0;
6371da177e4SLinus Torvalds 			return 0;
6381da177e4SLinus Torvalds 		}
6391da177e4SLinus Torvalds 		break;
6401da177e4SLinus Torvalds 	default:
6411da177e4SLinus Torvalds 		assert(filetype != S_IFDIR);
6421da177e4SLinus Torvalds 		return 0;
6431da177e4SLinus Torvalds 	}
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	set_cflag(COMMIT_Freewmap, ip);
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds 	/* mark transaction of block map update type */
6481da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
6491da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_PMAP;
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	/*
6521da177e4SLinus Torvalds 	 * free EA
6531da177e4SLinus Torvalds 	 */
6541da177e4SLinus Torvalds 	if (JFS_IP(ip)->ea.flag & DXD_EXTENT)
6551da177e4SLinus Torvalds 		/* acquire maplock on EA to be freed from block map */
6561da177e4SLinus Torvalds 		txEA(tid, ip, &JFS_IP(ip)->ea, NULL);
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	/*
6591da177e4SLinus Torvalds 	 * free ACL
6601da177e4SLinus Torvalds 	 */
6611da177e4SLinus Torvalds 	if (JFS_IP(ip)->acl.flag & DXD_EXTENT)
6621da177e4SLinus Torvalds 		/* acquire maplock on EA to be freed from block map */
6631da177e4SLinus Torvalds 		txEA(tid, ip, &JFS_IP(ip)->acl, NULL);
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 	/*
6661da177e4SLinus Torvalds 	 * free xtree/data (truncate to zero length):
6671da177e4SLinus Torvalds 	 * free xtree/data pages from cache if COMMIT_PWMAP,
6681da177e4SLinus Torvalds 	 * free xtree/data blocks from persistent block map, and
6691da177e4SLinus Torvalds 	 * free xtree/data blocks from working block map if COMMIT_PWMAP;
6701da177e4SLinus Torvalds 	 */
6711da177e4SLinus Torvalds 	if (ip->i_size)
6721da177e4SLinus Torvalds 		return xtTruncate_pmap(tid, ip, 0);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	return 0;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds /*
6791868f4aaSDave Kleikamp  * NAME:	jfs_free_zero_link()
6801da177e4SLinus Torvalds  *
6811da177e4SLinus Torvalds  * FUNCTION:	for non-directory, called by iClose(),
6821da177e4SLinus Torvalds  *		free resources of a file from cache and WORKING map
6831da177e4SLinus Torvalds  *		for a file previously committed with zero link count
6841da177e4SLinus Torvalds  *		while associated with a pager object,
6851da177e4SLinus Torvalds  *
6861da177e4SLinus Torvalds  * PARAMETER:	ip	- pointer to inode of file.
6871da177e4SLinus Torvalds  */
jfs_free_zero_link(struct inode * ip)6881868f4aaSDave Kleikamp void jfs_free_zero_link(struct inode *ip)
6891da177e4SLinus Torvalds {
6901da177e4SLinus Torvalds 	int type;
6911da177e4SLinus Torvalds 
6921868f4aaSDave Kleikamp 	jfs_info("jfs_free_zero_link: ip = 0x%p", ip);
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	/* return if not reg or symbolic link or if size is
6951da177e4SLinus Torvalds 	 * already ok.
6961da177e4SLinus Torvalds 	 */
6971da177e4SLinus Torvalds 	type = ip->i_mode & S_IFMT;
6981da177e4SLinus Torvalds 
6991da177e4SLinus Torvalds 	switch (type) {
7001da177e4SLinus Torvalds 	case S_IFREG:
7011da177e4SLinus Torvalds 		break;
7021da177e4SLinus Torvalds 	case S_IFLNK:
7031da177e4SLinus Torvalds 		/* if its contained in inode nothing to do */
7041da177e4SLinus Torvalds 		if (ip->i_size < IDATASIZE)
7051868f4aaSDave Kleikamp 			return;
7061da177e4SLinus Torvalds 		break;
7071da177e4SLinus Torvalds 	default:
7081868f4aaSDave Kleikamp 		return;
7091da177e4SLinus Torvalds 	}
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	/*
7121da177e4SLinus Torvalds 	 * free EA
7131da177e4SLinus Torvalds 	 */
7141da177e4SLinus Torvalds 	if (JFS_IP(ip)->ea.flag & DXD_EXTENT) {
7151da177e4SLinus Torvalds 		s64 xaddr = addressDXD(&JFS_IP(ip)->ea);
7161da177e4SLinus Torvalds 		int xlen = lengthDXD(&JFS_IP(ip)->ea);
7171da177e4SLinus Torvalds 		struct maplock maplock;	/* maplock for COMMIT_WMAP */
7181da177e4SLinus Torvalds 		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 		/* free EA pages from cache */
7211da177e4SLinus Torvalds 		invalidate_dxd_metapages(ip, JFS_IP(ip)->ea);
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds 		/* free EA extent from working block map */
7241da177e4SLinus Torvalds 		maplock.index = 1;
7251da177e4SLinus Torvalds 		pxdlock = (struct pxd_lock *) & maplock;
7261da177e4SLinus Torvalds 		pxdlock->flag = mlckFREEPXD;
7271da177e4SLinus Torvalds 		PXDaddress(&pxdlock->pxd, xaddr);
7281da177e4SLinus Torvalds 		PXDlength(&pxdlock->pxd, xlen);
7291da177e4SLinus Torvalds 		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
7301da177e4SLinus Torvalds 	}
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	/*
7331da177e4SLinus Torvalds 	 * free ACL
7341da177e4SLinus Torvalds 	 */
7351da177e4SLinus Torvalds 	if (JFS_IP(ip)->acl.flag & DXD_EXTENT) {
7361da177e4SLinus Torvalds 		s64 xaddr = addressDXD(&JFS_IP(ip)->acl);
7371da177e4SLinus Torvalds 		int xlen = lengthDXD(&JFS_IP(ip)->acl);
7381da177e4SLinus Torvalds 		struct maplock maplock;	/* maplock for COMMIT_WMAP */
7391da177e4SLinus Torvalds 		struct pxd_lock *pxdlock;	/* maplock for COMMIT_WMAP */
7401da177e4SLinus Torvalds 
7411da177e4SLinus Torvalds 		invalidate_dxd_metapages(ip, JFS_IP(ip)->acl);
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 		/* free ACL extent from working block map */
7441da177e4SLinus Torvalds 		maplock.index = 1;
7451da177e4SLinus Torvalds 		pxdlock = (struct pxd_lock *) & maplock;
7461da177e4SLinus Torvalds 		pxdlock->flag = mlckFREEPXD;
7471da177e4SLinus Torvalds 		PXDaddress(&pxdlock->pxd, xaddr);
7481da177e4SLinus Torvalds 		PXDlength(&pxdlock->pxd, xlen);
7491da177e4SLinus Torvalds 		txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
7501da177e4SLinus Torvalds 	}
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	/*
7531da177e4SLinus Torvalds 	 * free xtree/data (truncate to zero length):
7541da177e4SLinus Torvalds 	 * free xtree/data pages from cache, and
7551da177e4SLinus Torvalds 	 * free xtree/data blocks from working block map;
7561da177e4SLinus Torvalds 	 */
7571da177e4SLinus Torvalds 	if (ip->i_size)
7581868f4aaSDave Kleikamp 		xtTruncate(0, ip, 0, COMMIT_WMAP);
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds 
7611da177e4SLinus Torvalds /*
7621da177e4SLinus Torvalds  * NAME:	jfs_link(vp, dvp, name, crp)
7631da177e4SLinus Torvalds  *
7641da177e4SLinus Torvalds  * FUNCTION:	create a link to <vp> by the name = <name>
7651da177e4SLinus Torvalds  *		in the parent directory <dvp>
7661da177e4SLinus Torvalds  *
7671da177e4SLinus Torvalds  * PARAMETER:	vp	- target object
7681da177e4SLinus Torvalds  *		dvp	- parent directory of new link
7691da177e4SLinus Torvalds  *		name	- name of new link to target object
7701da177e4SLinus Torvalds  *		crp	- credential
7711da177e4SLinus Torvalds  *
7721da177e4SLinus Torvalds  * RETURN:	Errors from subroutines
7731da177e4SLinus Torvalds  *
7741da177e4SLinus Torvalds  * note:
7751da177e4SLinus Torvalds  * JFS does NOT support link() on directories (to prevent circular
7761da177e4SLinus Torvalds  * path in the directory hierarchy);
7771da177e4SLinus Torvalds  * EPERM: the target object is a directory, and either the caller
7781da177e4SLinus Torvalds  * does not have appropriate privileges or the implementation prohibits
7791da177e4SLinus Torvalds  * using link() on directories [XPG4.2].
7801da177e4SLinus Torvalds  *
7811da177e4SLinus Torvalds  * JFS does NOT support links between file systems:
7821da177e4SLinus Torvalds  * EXDEV: target object and new link are on different file systems and
7831da177e4SLinus Torvalds  * implementation does not support links between file systems [XPG4.2].
7841da177e4SLinus Torvalds  */
jfs_link(struct dentry * old_dentry,struct inode * dir,struct dentry * dentry)7851da177e4SLinus Torvalds static int jfs_link(struct dentry *old_dentry,
7861da177e4SLinus Torvalds 	     struct inode *dir, struct dentry *dentry)
7871da177e4SLinus Torvalds {
7881da177e4SLinus Torvalds 	int rc;
7891da177e4SLinus Torvalds 	tid_t tid;
7902b0143b5SDavid Howells 	struct inode *ip = d_inode(old_dentry);
7911da177e4SLinus Torvalds 	ino_t ino;
7921da177e4SLinus Torvalds 	struct component_name dname;
7931da177e4SLinus Torvalds 	struct btstack btstack;
7941da177e4SLinus Torvalds 	struct inode *iplist[2];
7951da177e4SLinus Torvalds 
796a455589fSAl Viro 	jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
7971da177e4SLinus Torvalds 
798acc84b05SDave Kleikamp 	rc = dquot_initialize(dir);
799acc84b05SDave Kleikamp 	if (rc)
800acc84b05SDave Kleikamp 		goto out;
801907f4554SChristoph Hellwig 
80247cfdc33SImmad Mir 	if (isReadOnly(ip)) {
80347cfdc33SImmad Mir 		jfs_error(ip->i_sb, "read-only filesystem\n");
80447cfdc33SImmad Mir 		return -EROFS;
80547cfdc33SImmad Mir 	}
80647cfdc33SImmad Mir 
8071da177e4SLinus Torvalds 	tid = txBegin(ip->i_sb, 0);
8081da177e4SLinus Torvalds 
80982d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
81082d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
8111da177e4SLinus Torvalds 
8121da177e4SLinus Torvalds 	/*
8131da177e4SLinus Torvalds 	 * scan parent directory for entry/freespace
8141da177e4SLinus Torvalds 	 */
8151da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
816acc84b05SDave Kleikamp 		goto out_tx;
8171da177e4SLinus Torvalds 
8181da177e4SLinus Torvalds 	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
8191da177e4SLinus Torvalds 		goto free_dname;
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	/*
8221da177e4SLinus Torvalds 	 * create entry for new link in parent directory
8231da177e4SLinus Torvalds 	 */
8241da177e4SLinus Torvalds 	ino = ip->i_ino;
8251da177e4SLinus Torvalds 	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack)))
8261da177e4SLinus Torvalds 		goto free_dname;
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds 	/* update object inode */
829d8c76e6fSDave Hansen 	inc_nlink(ip);		/* for new link */
830ad9dc5dfSJeff Layton 	inode_set_ctime_current(ip);
831ad9dc5dfSJeff Layton 	dir->i_mtime = inode_set_ctime_current(dir);
8321da177e4SLinus Torvalds 	mark_inode_dirty(dir);
8337de9c6eeSAl Viro 	ihold(ip);
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	iplist[0] = ip;
8361da177e4SLinus Torvalds 	iplist[1] = dir;
8371da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], 0);
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	if (rc) {
8406d6b77f1SMiklos Szeredi 		drop_nlink(ip); /* never instantiated */
8411da177e4SLinus Torvalds 		iput(ip);
8421da177e4SLinus Torvalds 	} else
8431da177e4SLinus Torvalds 		d_instantiate(dentry, ip);
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds       free_dname:
8461da177e4SLinus Torvalds 	free_UCSname(&dname);
8471da177e4SLinus Torvalds 
848acc84b05SDave Kleikamp       out_tx:
8491da177e4SLinus Torvalds 	txEnd(tid);
8501da177e4SLinus Torvalds 
8511de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
85248ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dir)->commit_mutex);
8531da177e4SLinus Torvalds 
854acc84b05SDave Kleikamp       out:
8551da177e4SLinus Torvalds 	jfs_info("jfs_link: rc:%d", rc);
8561da177e4SLinus Torvalds 	return rc;
8571da177e4SLinus Torvalds }
8581da177e4SLinus Torvalds 
8591da177e4SLinus Torvalds /*
8601da177e4SLinus Torvalds  * NAME:	jfs_symlink(dip, dentry, name)
8611da177e4SLinus Torvalds  *
8621da177e4SLinus Torvalds  * FUNCTION:	creates a symbolic link to <symlink> by name <name>
8631da177e4SLinus Torvalds  *			in directory <dip>
8641da177e4SLinus Torvalds  *
8651da177e4SLinus Torvalds  * PARAMETER:	dip	- parent directory vnode
8661da177e4SLinus Torvalds  *		dentry	- dentry of symbolic link
8671da177e4SLinus Torvalds  *		name	- the path name of the existing object
8681da177e4SLinus Torvalds  *			  that will be the source of the link
8691da177e4SLinus Torvalds  *
8701da177e4SLinus Torvalds  * RETURN:	errors from subroutines
8711da177e4SLinus Torvalds  *
8721da177e4SLinus Torvalds  * note:
8731da177e4SLinus Torvalds  * ENAMETOOLONG: pathname resolution of a symbolic link produced
8741da177e4SLinus Torvalds  * an intermediate result whose length exceeds PATH_MAX [XPG4.2]
8751da177e4SLinus Torvalds */
8761da177e4SLinus Torvalds 
jfs_symlink(struct mnt_idmap * idmap,struct inode * dip,struct dentry * dentry,const char * name)8777a77db95SChristian Brauner static int jfs_symlink(struct mnt_idmap *idmap, struct inode *dip,
878549c7297SChristian Brauner 		       struct dentry *dentry, const char *name)
8791da177e4SLinus Torvalds {
8801da177e4SLinus Torvalds 	int rc;
8811da177e4SLinus Torvalds 	tid_t tid;
8821da177e4SLinus Torvalds 	ino_t ino = 0;
8831da177e4SLinus Torvalds 	struct component_name dname;
884820eb59dSKees Cook 	u32 ssize;		/* source pathname size */
8851da177e4SLinus Torvalds 	struct btstack btstack;
886*87098a0dSColin Ian King 	struct inode *ip;
8871da177e4SLinus Torvalds 	s64 xlen = 0;
8881da177e4SLinus Torvalds 	int bmask = 0, xsize;
8893c2c2262SDave Kleikamp 	s64 xaddr;
8901da177e4SLinus Torvalds 	struct metapage *mp;
8911da177e4SLinus Torvalds 	struct super_block *sb;
8921da177e4SLinus Torvalds 	struct tblock *tblk;
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 	struct inode *iplist[2];
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name);
8971da177e4SLinus Torvalds 
898acc84b05SDave Kleikamp 	rc = dquot_initialize(dip);
899acc84b05SDave Kleikamp 	if (rc)
900acc84b05SDave Kleikamp 		goto out1;
901907f4554SChristoph Hellwig 
9021da177e4SLinus Torvalds 	ssize = strlen(name) + 1;
9031da177e4SLinus Torvalds 
9041da177e4SLinus Torvalds 	/*
9051da177e4SLinus Torvalds 	 * search parent directory for entry/freespace
9061da177e4SLinus Torvalds 	 * (dtSearch() returns parent directory page pinned)
9071da177e4SLinus Torvalds 	 */
9081da177e4SLinus Torvalds 
9091da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
9101da177e4SLinus Torvalds 		goto out1;
9111da177e4SLinus Torvalds 
9121da177e4SLinus Torvalds 	/*
9131da177e4SLinus Torvalds 	 * allocate on-disk/in-memory inode for symbolic link:
9141da177e4SLinus Torvalds 	 * (iAlloc() returns new, locked inode)
9151da177e4SLinus Torvalds 	 */
9161da177e4SLinus Torvalds 	ip = ialloc(dip, S_IFLNK | 0777);
917087387f9SAkinobu Mita 	if (IS_ERR(ip)) {
918087387f9SAkinobu Mita 		rc = PTR_ERR(ip);
9191da177e4SLinus Torvalds 		goto out2;
9201da177e4SLinus Torvalds 	}
9211da177e4SLinus Torvalds 
9221da177e4SLinus Torvalds 	tid = txBegin(dip->i_sb, 0);
9231da177e4SLinus Torvalds 
92482d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
92582d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
9261da177e4SLinus Torvalds 
9272a7dba39SEric Paris 	rc = jfs_init_security(tid, ip, dip, &dentry->d_name);
9281d15b10fSDave Kleikamp 	if (rc)
9291d15b10fSDave Kleikamp 		goto out3;
9301d15b10fSDave Kleikamp 
9311da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
9321da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_CREATE;
9331da177e4SLinus Torvalds 	tblk->ino = ip->i_ino;
9341da177e4SLinus Torvalds 	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	/* fix symlink access permission
9371da177e4SLinus Torvalds 	 * (dir_create() ANDs in the u.u_cmask,
9381da177e4SLinus Torvalds 	 * but symlinks really need to be 777 access)
9391da177e4SLinus Torvalds 	 */
9401da177e4SLinus Torvalds 	ip->i_mode |= 0777;
9411da177e4SLinus Torvalds 
9421da177e4SLinus Torvalds 	/*
9431da177e4SLinus Torvalds 	 * write symbolic link target path name
9441da177e4SLinus Torvalds 	 */
9451da177e4SLinus Torvalds 	xtInitRoot(tid, ip);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	/*
9481da177e4SLinus Torvalds 	 * write source path name inline in on-disk inode (fast symbolic link)
9491da177e4SLinus Torvalds 	 */
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	if (ssize <= IDATASIZE) {
952c7f2e1f0SDmitry Monakhov 		ip->i_op = &jfs_fast_symlink_inode_operations;
9531da177e4SLinus Torvalds 
954ebe06036SDr. David Alan Gilbert 		ip->i_link = JFS_IP(ip)->i_inline_all;
955ad476fedSAl Viro 		memcpy(ip->i_link, name, ssize);
9561da177e4SLinus Torvalds 		ip->i_size = ssize - 1;
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 		/*
9591da177e4SLinus Torvalds 		 * if symlink is > 128 bytes, we don't have the space to
9601da177e4SLinus Torvalds 		 * store inline extended attributes
9611da177e4SLinus Torvalds 		 */
9621da177e4SLinus Torvalds 		if (ssize > sizeof (JFS_IP(ip)->i_inline))
9631da177e4SLinus Torvalds 			JFS_IP(ip)->mode2 &= ~INLINEEA;
9641da177e4SLinus Torvalds 
965820eb59dSKees Cook 		jfs_info("jfs_symlink: fast symlink added  ssize:%u name:%s ",
9661da177e4SLinus Torvalds 			 ssize, name);
9671da177e4SLinus Torvalds 	}
9681da177e4SLinus Torvalds 	/*
9691da177e4SLinus Torvalds 	 * write source path name in a single extent
9701da177e4SLinus Torvalds 	 */
9711da177e4SLinus Torvalds 	else {
9721da177e4SLinus Torvalds 		jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
9731da177e4SLinus Torvalds 
974c7f2e1f0SDmitry Monakhov 		ip->i_op = &jfs_symlink_inode_operations;
97521fc61c7SAl Viro 		inode_nohighmem(ip);
9761da177e4SLinus Torvalds 		ip->i_mapping->a_ops = &jfs_aops;
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 		/*
9791da177e4SLinus Torvalds 		 * even though the data of symlink object (source
9801da177e4SLinus Torvalds 		 * path name) is treated as non-journaled user data,
9811da177e4SLinus Torvalds 		 * it is read/written thru buffer cache for performance.
9821da177e4SLinus Torvalds 		 */
9831da177e4SLinus Torvalds 		sb = ip->i_sb;
9841da177e4SLinus Torvalds 		bmask = JFS_SBI(sb)->bsize - 1;
9851da177e4SLinus Torvalds 		xsize = (ssize + bmask) & ~bmask;
9861da177e4SLinus Torvalds 		xaddr = 0;
9871da177e4SLinus Torvalds 		xlen = xsize >> JFS_SBI(sb)->l2bsize;
9881da177e4SLinus Torvalds 		if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
9891da177e4SLinus Torvalds 			txAbort(tid, 0);
9901da177e4SLinus Torvalds 			goto out3;
9911da177e4SLinus Torvalds 		}
9921da177e4SLinus Torvalds 		ip->i_size = ssize - 1;
9931da177e4SLinus Torvalds 		while (ssize) {
9941da177e4SLinus Torvalds 			/* This is kind of silly since PATH_MAX == 4K */
995820eb59dSKees Cook 			u32 copy_size = min_t(u32, ssize, PSIZE);
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 			mp = get_metapage(ip, xaddr, PSIZE, 1);
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 			if (mp == NULL) {
10001da177e4SLinus Torvalds 				xtTruncate(tid, ip, 0, COMMIT_PWMAP);
10011da177e4SLinus Torvalds 				rc = -EIO;
10021da177e4SLinus Torvalds 				txAbort(tid, 0);
10031da177e4SLinus Torvalds 				goto out3;
10041da177e4SLinus Torvalds 			}
10051da177e4SLinus Torvalds 			memcpy(mp->data, name, copy_size);
10061da177e4SLinus Torvalds 			flush_metapage(mp);
10071da177e4SLinus Torvalds 			ssize -= copy_size;
10081da177e4SLinus Torvalds 			name += copy_size;
10091da177e4SLinus Torvalds 			xaddr += JFS_SBI(sb)->nbperpage;
10101da177e4SLinus Torvalds 		}
10111da177e4SLinus Torvalds 	}
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 	/*
10141da177e4SLinus Torvalds 	 * create entry for symbolic link in parent directory
10151da177e4SLinus Torvalds 	 */
10161da177e4SLinus Torvalds 	rc = dtSearch(dip, &dname, &ino, &btstack, JFS_CREATE);
10171da177e4SLinus Torvalds 	if (rc == 0) {
10181da177e4SLinus Torvalds 		ino = ip->i_ino;
10191da177e4SLinus Torvalds 		rc = dtInsert(tid, dip, &dname, &ino, &btstack);
10201da177e4SLinus Torvalds 	}
10211da177e4SLinus Torvalds 	if (rc) {
10221da177e4SLinus Torvalds 		if (xlen)
10231da177e4SLinus Torvalds 			xtTruncate(tid, ip, 0, COMMIT_PWMAP);
10241da177e4SLinus Torvalds 		txAbort(tid, 0);
10251da177e4SLinus Torvalds 		/* discard new inode */
10261da177e4SLinus Torvalds 		goto out3;
10271da177e4SLinus Torvalds 	}
10281da177e4SLinus Torvalds 
10291da177e4SLinus Torvalds 	mark_inode_dirty(ip);
10301da177e4SLinus Torvalds 
1031ad9dc5dfSJeff Layton 	dip->i_mtime = inode_set_ctime_current(dip);
1032988a6490SDave Kleikamp 	mark_inode_dirty(dip);
10331da177e4SLinus Torvalds 	/*
10341da177e4SLinus Torvalds 	 * commit update of parent directory and link object
10351da177e4SLinus Torvalds 	 */
10361da177e4SLinus Torvalds 
10371da177e4SLinus Torvalds 	iplist[0] = dip;
10381da177e4SLinus Torvalds 	iplist[1] = ip;
10391da177e4SLinus Torvalds 	rc = txCommit(tid, 2, &iplist[0], 0);
10401da177e4SLinus Torvalds 
10411da177e4SLinus Torvalds       out3:
10421da177e4SLinus Torvalds 	txEnd(tid);
10431de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
104448ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(dip)->commit_mutex);
10451da177e4SLinus Torvalds 	if (rc) {
10464f4b401bSDave Kleikamp 		free_ea_wmap(ip);
10476d6b77f1SMiklos Szeredi 		clear_nlink(ip);
1048a6cbedfaSAl Viro 		discard_new_inode(ip);
10491f3403faSDave Kleikamp 	} else {
10501e2e547aSAl Viro 		d_instantiate_new(dentry, ip);
10511f3403faSDave Kleikamp 	}
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds       out2:
10541da177e4SLinus Torvalds 	free_UCSname(&dname);
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds       out1:
10571da177e4SLinus Torvalds 	jfs_info("jfs_symlink: rc:%d", rc);
10581da177e4SLinus Torvalds 	return rc;
10591da177e4SLinus Torvalds }
10601da177e4SLinus Torvalds 
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds /*
10631da177e4SLinus Torvalds  * NAME:	jfs_rename
10641da177e4SLinus Torvalds  *
10651da177e4SLinus Torvalds  * FUNCTION:	rename a file or directory
10661da177e4SLinus Torvalds  */
jfs_rename(struct mnt_idmap * idmap,struct inode * old_dir,struct dentry * old_dentry,struct inode * new_dir,struct dentry * new_dentry,unsigned int flags)1067e18275aeSChristian Brauner static int jfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
1068549c7297SChristian Brauner 		      struct dentry *old_dentry, struct inode *new_dir,
1069549c7297SChristian Brauner 		      struct dentry *new_dentry, unsigned int flags)
10701da177e4SLinus Torvalds {
10711da177e4SLinus Torvalds 	struct btstack btstack;
10721da177e4SLinus Torvalds 	ino_t ino;
10731da177e4SLinus Torvalds 	struct component_name new_dname;
10741da177e4SLinus Torvalds 	struct inode *new_ip;
10751da177e4SLinus Torvalds 	struct component_name old_dname;
10761da177e4SLinus Torvalds 	struct inode *old_ip;
10771da177e4SLinus Torvalds 	int rc;
10781da177e4SLinus Torvalds 	tid_t tid;
10791da177e4SLinus Torvalds 	struct tlock *tlck;
10801da177e4SLinus Torvalds 	struct dt_lock *dtlck;
10811da177e4SLinus Torvalds 	struct lv *lv;
10821da177e4SLinus Torvalds 	int ipcount;
10831da177e4SLinus Torvalds 	struct inode *iplist[4];
10841da177e4SLinus Torvalds 	struct tblock *tblk;
10851da177e4SLinus Torvalds 	s64 new_size = 0;
10861da177e4SLinus Torvalds 	int commit_flag;
10871da177e4SLinus Torvalds 
1088f03b8ad8SMiklos Szeredi 	if (flags & ~RENAME_NOREPLACE)
1089f03b8ad8SMiklos Szeredi 		return -EINVAL;
10901da177e4SLinus Torvalds 
1091a455589fSAl Viro 	jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
10921da177e4SLinus Torvalds 
1093acc84b05SDave Kleikamp 	rc = dquot_initialize(old_dir);
1094acc84b05SDave Kleikamp 	if (rc)
1095acc84b05SDave Kleikamp 		goto out1;
1096acc84b05SDave Kleikamp 	rc = dquot_initialize(new_dir);
1097acc84b05SDave Kleikamp 	if (rc)
1098acc84b05SDave Kleikamp 		goto out1;
1099907f4554SChristoph Hellwig 
11002b0143b5SDavid Howells 	old_ip = d_inode(old_dentry);
11012b0143b5SDavid Howells 	new_ip = d_inode(new_dentry);
11021da177e4SLinus Torvalds 
11031da177e4SLinus Torvalds 	if ((rc = get_UCSname(&old_dname, old_dentry)))
11041da177e4SLinus Torvalds 		goto out1;
11051da177e4SLinus Torvalds 
11061da177e4SLinus Torvalds 	if ((rc = get_UCSname(&new_dname, new_dentry)))
11071da177e4SLinus Torvalds 		goto out2;
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds 	/*
11101da177e4SLinus Torvalds 	 * Make sure source inode number is what we think it is
11111da177e4SLinus Torvalds 	 */
11121da177e4SLinus Torvalds 	rc = dtSearch(old_dir, &old_dname, &ino, &btstack, JFS_LOOKUP);
11131da177e4SLinus Torvalds 	if (rc || (ino != old_ip->i_ino)) {
11141da177e4SLinus Torvalds 		rc = -ENOENT;
11151da177e4SLinus Torvalds 		goto out3;
11161da177e4SLinus Torvalds 	}
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	/*
11191da177e4SLinus Torvalds 	 * Make sure dest inode number (if any) is what we think it is
11201da177e4SLinus Torvalds 	 */
11211da177e4SLinus Torvalds 	rc = dtSearch(new_dir, &new_dname, &ino, &btstack, JFS_LOOKUP);
112209aaa749SJoe Perches 	if (!rc) {
1123da8a41d1SDave Kleikamp 		if ((!new_ip) || (ino != new_ip->i_ino)) {
11241da177e4SLinus Torvalds 			rc = -ESTALE;
11251da177e4SLinus Torvalds 			goto out3;
11261da177e4SLinus Torvalds 		}
11271da177e4SLinus Torvalds 	} else if (rc != -ENOENT)
11281da177e4SLinus Torvalds 		goto out3;
11291da177e4SLinus Torvalds 	else if (new_ip) {
11301da177e4SLinus Torvalds 		/* no entry exists, but one was expected */
11311da177e4SLinus Torvalds 		rc = -ESTALE;
11321da177e4SLinus Torvalds 		goto out3;
11331da177e4SLinus Torvalds 	}
11341da177e4SLinus Torvalds 
11351da177e4SLinus Torvalds 	if (S_ISDIR(old_ip->i_mode)) {
11361da177e4SLinus Torvalds 		if (new_ip) {
11371da177e4SLinus Torvalds 			if (!dtEmpty(new_ip)) {
11381da177e4SLinus Torvalds 				rc = -ENOTEMPTY;
11391da177e4SLinus Torvalds 				goto out3;
11401da177e4SLinus Torvalds 			}
11411da177e4SLinus Torvalds 		}
11421da177e4SLinus Torvalds 	} else if (new_ip) {
114382d5b9a7SDave Kleikamp 		IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
11441da177e4SLinus Torvalds 		/* Init inode for quota operations. */
1145acc84b05SDave Kleikamp 		rc = dquot_initialize(new_ip);
1146acc84b05SDave Kleikamp 		if (rc)
1147acc84b05SDave Kleikamp 			goto out_unlock;
11481da177e4SLinus Torvalds 	}
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 	/*
11511da177e4SLinus Torvalds 	 * The real work starts here
11521da177e4SLinus Torvalds 	 */
11531da177e4SLinus Torvalds 	tid = txBegin(new_dir->i_sb, 0);
11541da177e4SLinus Torvalds 
115582d5b9a7SDave Kleikamp 	/*
115682d5b9a7SDave Kleikamp 	 * How do we know the locking is safe from deadlocks?
115782d5b9a7SDave Kleikamp 	 * The vfs does the hard part for us.  Any time we are taking nested
115882d5b9a7SDave Kleikamp 	 * commit_mutexes, the vfs already has i_mutex held on the parent.
115982d5b9a7SDave Kleikamp 	 * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
116082d5b9a7SDave Kleikamp 	 */
116182d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
116282d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
11631da177e4SLinus Torvalds 	if (old_dir != new_dir)
116482d5b9a7SDave Kleikamp 		mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
116582d5b9a7SDave Kleikamp 				  COMMIT_MUTEX_SECOND_PARENT);
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	if (new_ip) {
116882d5b9a7SDave Kleikamp 		mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
116982d5b9a7SDave Kleikamp 				  COMMIT_MUTEX_VICTIM);
11701da177e4SLinus Torvalds 		/*
11711da177e4SLinus Torvalds 		 * Change existing directory entry to new inode number
11721da177e4SLinus Torvalds 		 */
11731da177e4SLinus Torvalds 		ino = new_ip->i_ino;
11741da177e4SLinus Torvalds 		rc = dtModify(tid, new_dir, &new_dname, &ino,
11751da177e4SLinus Torvalds 			      old_ip->i_ino, JFS_RENAME);
11761da177e4SLinus Torvalds 		if (rc)
117726456955SDave Kleikamp 			goto out_tx;
11789a53c3a7SDave Hansen 		drop_nlink(new_ip);
11791da177e4SLinus Torvalds 		if (S_ISDIR(new_ip->i_mode)) {
11809a53c3a7SDave Hansen 			drop_nlink(new_ip);
11811da177e4SLinus Torvalds 			if (new_ip->i_nlink) {
118248ce8b05SEvgeniy Dushistov 				mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
11831da177e4SLinus Torvalds 				if (old_dir != new_dir)
11841de87444SIngo Molnar 					mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
118548ce8b05SEvgeniy Dushistov 				mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
118648ce8b05SEvgeniy Dushistov 				mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
11871da177e4SLinus Torvalds 				if (!S_ISDIR(old_ip->i_mode) && new_ip)
11881da177e4SLinus Torvalds 					IWRITE_UNLOCK(new_ip);
11891da177e4SLinus Torvalds 				jfs_error(new_ip->i_sb,
1190eb8630d7SJoe Perches 					  "new_ip->i_nlink != 0\n");
11911da177e4SLinus Torvalds 				return -EIO;
11921da177e4SLinus Torvalds 			}
11931da177e4SLinus Torvalds 			tblk = tid_to_tblock(tid);
11941da177e4SLinus Torvalds 			tblk->xflag |= COMMIT_DELETE;
11951da177e4SLinus Torvalds 			tblk->u.ip = new_ip;
11961da177e4SLinus Torvalds 		} else if (new_ip->i_nlink == 0) {
11971da177e4SLinus Torvalds 			assert(!test_cflag(COMMIT_Nolink, new_ip));
11981da177e4SLinus Torvalds 			/* free block resources */
11991da177e4SLinus Torvalds 			if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
12001da177e4SLinus Torvalds 				txAbort(tid, 1);	/* Marks FS Dirty */
12011da177e4SLinus Torvalds 				rc = new_size;
120226456955SDave Kleikamp 				goto out_tx;
12031da177e4SLinus Torvalds 			}
12041da177e4SLinus Torvalds 			tblk = tid_to_tblock(tid);
12051da177e4SLinus Torvalds 			tblk->xflag |= COMMIT_DELETE;
12061da177e4SLinus Torvalds 			tblk->u.ip = new_ip;
12071da177e4SLinus Torvalds 		} else {
1208ad9dc5dfSJeff Layton 			inode_set_ctime_current(new_ip);
12091da177e4SLinus Torvalds 			mark_inode_dirty(new_ip);
12101da177e4SLinus Torvalds 		}
12111da177e4SLinus Torvalds 	} else {
12121da177e4SLinus Torvalds 		/*
12131da177e4SLinus Torvalds 		 * Add new directory entry
12141da177e4SLinus Torvalds 		 */
12151da177e4SLinus Torvalds 		rc = dtSearch(new_dir, &new_dname, &ino, &btstack,
12161da177e4SLinus Torvalds 			      JFS_CREATE);
12171da177e4SLinus Torvalds 		if (rc) {
12186ed71e98SJoe Perches 			jfs_err("jfs_rename didn't expect dtSearch to fail w/rc = %d",
12196ed71e98SJoe Perches 				rc);
122026456955SDave Kleikamp 			goto out_tx;
12211da177e4SLinus Torvalds 		}
12221da177e4SLinus Torvalds 
12231da177e4SLinus Torvalds 		ino = old_ip->i_ino;
12241da177e4SLinus Torvalds 		rc = dtInsert(tid, new_dir, &new_dname, &ino, &btstack);
12251da177e4SLinus Torvalds 		if (rc) {
12261da177e4SLinus Torvalds 			if (rc == -EIO)
12271da177e4SLinus Torvalds 				jfs_err("jfs_rename: dtInsert returned -EIO");
122826456955SDave Kleikamp 			goto out_tx;
12291da177e4SLinus Torvalds 		}
12301da177e4SLinus Torvalds 		if (S_ISDIR(old_ip->i_mode))
1231d8c76e6fSDave Hansen 			inc_nlink(new_dir);
12321da177e4SLinus Torvalds 	}
12331da177e4SLinus Torvalds 	/*
12341da177e4SLinus Torvalds 	 * Remove old directory entry
12351da177e4SLinus Torvalds 	 */
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds 	ino = old_ip->i_ino;
12381da177e4SLinus Torvalds 	rc = dtDelete(tid, old_dir, &old_dname, &ino, JFS_REMOVE);
12391da177e4SLinus Torvalds 	if (rc) {
12401da177e4SLinus Torvalds 		jfs_err("jfs_rename did not expect dtDelete to return rc = %d",
12411da177e4SLinus Torvalds 			rc);
12421da177e4SLinus Torvalds 		txAbort(tid, 1);	/* Marks Filesystem dirty */
124326456955SDave Kleikamp 		goto out_tx;
12441da177e4SLinus Torvalds 	}
12451da177e4SLinus Torvalds 	if (S_ISDIR(old_ip->i_mode)) {
12469a53c3a7SDave Hansen 		drop_nlink(old_dir);
12471da177e4SLinus Torvalds 		if (old_dir != new_dir) {
12481da177e4SLinus Torvalds 			/*
12491da177e4SLinus Torvalds 			 * Change inode number of parent for moved directory
12501da177e4SLinus Torvalds 			 */
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 			JFS_IP(old_ip)->i_dtroot.header.idotdot =
12531da177e4SLinus Torvalds 				cpu_to_le32(new_dir->i_ino);
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 			/* Linelock header of dtree */
12561da177e4SLinus Torvalds 			tlck = txLock(tid, old_ip,
12571da177e4SLinus Torvalds 				    (struct metapage *) &JFS_IP(old_ip)->bxflag,
12581da177e4SLinus Torvalds 				      tlckDTREE | tlckBTROOT | tlckRELINK);
12591da177e4SLinus Torvalds 			dtlck = (struct dt_lock *) & tlck->lock;
12601da177e4SLinus Torvalds 			ASSERT(dtlck->index == 0);
12611da177e4SLinus Torvalds 			lv = & dtlck->lv[0];
12621da177e4SLinus Torvalds 			lv->offset = 0;
12631da177e4SLinus Torvalds 			lv->length = 1;
12641da177e4SLinus Torvalds 			dtlck->index++;
12651da177e4SLinus Torvalds 		}
12661da177e4SLinus Torvalds 	}
12671da177e4SLinus Torvalds 
12681da177e4SLinus Torvalds 	/*
12691da177e4SLinus Torvalds 	 * Update ctime on changed/moved inodes & mark dirty
12701da177e4SLinus Torvalds 	 */
1271ad9dc5dfSJeff Layton 	inode_set_ctime_current(old_ip);
12721da177e4SLinus Torvalds 	mark_inode_dirty(old_ip);
12731da177e4SLinus Torvalds 
1274ad9dc5dfSJeff Layton 	new_dir->i_mtime = inode_set_ctime_current(new_dir);
12751da177e4SLinus Torvalds 	mark_inode_dirty(new_dir);
12761da177e4SLinus Torvalds 
12771da177e4SLinus Torvalds 	/* Build list of inodes modified by this transaction */
12781da177e4SLinus Torvalds 	ipcount = 0;
12791da177e4SLinus Torvalds 	iplist[ipcount++] = old_ip;
12801da177e4SLinus Torvalds 	if (new_ip)
12811da177e4SLinus Torvalds 		iplist[ipcount++] = new_ip;
12821da177e4SLinus Torvalds 	iplist[ipcount++] = old_dir;
12831da177e4SLinus Torvalds 
12841da177e4SLinus Torvalds 	if (old_dir != new_dir) {
12851da177e4SLinus Torvalds 		iplist[ipcount++] = new_dir;
1286ad9dc5dfSJeff Layton 		old_dir->i_mtime = inode_set_ctime_current(old_dir);
12871da177e4SLinus Torvalds 		mark_inode_dirty(old_dir);
12881da177e4SLinus Torvalds 	}
12891da177e4SLinus Torvalds 
12901da177e4SLinus Torvalds 	/*
12911da177e4SLinus Torvalds 	 * Incomplete truncate of file data can
12921da177e4SLinus Torvalds 	 * result in timing problems unless we synchronously commit the
12931da177e4SLinus Torvalds 	 * transaction.
12941da177e4SLinus Torvalds 	 */
12951da177e4SLinus Torvalds 	if (new_size)
12961da177e4SLinus Torvalds 		commit_flag = COMMIT_SYNC;
12971da177e4SLinus Torvalds 	else
12981da177e4SLinus Torvalds 		commit_flag = 0;
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 	rc = txCommit(tid, ipcount, iplist, commit_flag);
13011da177e4SLinus Torvalds 
130226456955SDave Kleikamp       out_tx:
13031da177e4SLinus Torvalds 	txEnd(tid);
13041da177e4SLinus Torvalds 	if (new_ip)
13051de87444SIngo Molnar 		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
130648ce8b05SEvgeniy Dushistov 	if (old_dir != new_dir)
130748ce8b05SEvgeniy Dushistov 		mutex_unlock(&JFS_IP(old_dir)->commit_mutex);
130848ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(old_ip)->commit_mutex);
130948ce8b05SEvgeniy Dushistov 	mutex_unlock(&JFS_IP(new_dir)->commit_mutex);
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds 	while (new_size && (rc == 0)) {
13121da177e4SLinus Torvalds 		tid = txBegin(new_ip->i_sb, 0);
13131de87444SIngo Molnar 		mutex_lock(&JFS_IP(new_ip)->commit_mutex);
13141da177e4SLinus Torvalds 		new_size = xtTruncate_pmap(tid, new_ip, new_size);
13151da177e4SLinus Torvalds 		if (new_size < 0) {
13161da177e4SLinus Torvalds 			txAbort(tid, 1);
13171da177e4SLinus Torvalds 			rc = new_size;
13181da177e4SLinus Torvalds 		} else
13191da177e4SLinus Torvalds 			rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
13201da177e4SLinus Torvalds 		txEnd(tid);
13211de87444SIngo Molnar 		mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
13221da177e4SLinus Torvalds 	}
13231da177e4SLinus Torvalds 	if (new_ip && (new_ip->i_nlink == 0))
13241da177e4SLinus Torvalds 		set_cflag(COMMIT_Nolink, new_ip);
13251da177e4SLinus Torvalds 	/*
13261da177e4SLinus Torvalds 	 * Truncating the directory index table is not guaranteed.  It
13271da177e4SLinus Torvalds 	 * may need to be done iteratively
13281da177e4SLinus Torvalds 	 */
13291da177e4SLinus Torvalds 	if (test_cflag(COMMIT_Stale, old_dir)) {
13301da177e4SLinus Torvalds 		if (old_dir->i_size > 1)
13311da177e4SLinus Torvalds 			jfs_truncate_nolock(old_dir, 0);
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 		clear_cflag(COMMIT_Stale, old_dir);
13341da177e4SLinus Torvalds 	}
1335acc84b05SDave Kleikamp       out_unlock:
133626456955SDave Kleikamp 	if (new_ip && !S_ISDIR(new_ip->i_mode))
133726456955SDave Kleikamp 		IWRITE_UNLOCK(new_ip);
133826456955SDave Kleikamp       out3:
133926456955SDave Kleikamp 	free_UCSname(&new_dname);
134026456955SDave Kleikamp       out2:
134126456955SDave Kleikamp 	free_UCSname(&old_dname);
134226456955SDave Kleikamp       out1:
13431da177e4SLinus Torvalds 	jfs_info("jfs_rename: returning %d", rc);
13441da177e4SLinus Torvalds 	return rc;
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds 
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds /*
13491da177e4SLinus Torvalds  * NAME:	jfs_mknod
13501da177e4SLinus Torvalds  *
13511da177e4SLinus Torvalds  * FUNCTION:	Create a special file (device)
13521da177e4SLinus Torvalds  */
jfs_mknod(struct mnt_idmap * idmap,struct inode * dir,struct dentry * dentry,umode_t mode,dev_t rdev)13535ebb29beSChristian Brauner static int jfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
1354549c7297SChristian Brauner 		     struct dentry *dentry, umode_t mode, dev_t rdev)
13551da177e4SLinus Torvalds {
13561da177e4SLinus Torvalds 	struct jfs_inode_info *jfs_ip;
13571da177e4SLinus Torvalds 	struct btstack btstack;
13581da177e4SLinus Torvalds 	struct component_name dname;
13591da177e4SLinus Torvalds 	ino_t ino;
13601da177e4SLinus Torvalds 	struct inode *ip;
13611da177e4SLinus Torvalds 	struct inode *iplist[2];
13621da177e4SLinus Torvalds 	int rc;
13631da177e4SLinus Torvalds 	tid_t tid;
13641da177e4SLinus Torvalds 	struct tblock *tblk;
13651da177e4SLinus Torvalds 
1366a455589fSAl Viro 	jfs_info("jfs_mknod: %pd", dentry);
13671da177e4SLinus Torvalds 
1368acc84b05SDave Kleikamp 	rc = dquot_initialize(dir);
1369acc84b05SDave Kleikamp 	if (rc)
1370acc84b05SDave Kleikamp 		goto out;
1371907f4554SChristoph Hellwig 
13721da177e4SLinus Torvalds 	if ((rc = get_UCSname(&dname, dentry)))
13731da177e4SLinus Torvalds 		goto out;
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 	ip = ialloc(dir, mode);
1376087387f9SAkinobu Mita 	if (IS_ERR(ip)) {
1377087387f9SAkinobu Mita 		rc = PTR_ERR(ip);
13781da177e4SLinus Torvalds 		goto out1;
13791da177e4SLinus Torvalds 	}
13801da177e4SLinus Torvalds 	jfs_ip = JFS_IP(ip);
13811da177e4SLinus Torvalds 
13821da177e4SLinus Torvalds 	tid = txBegin(dir->i_sb, 0);
13831da177e4SLinus Torvalds 
138482d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
138582d5b9a7SDave Kleikamp 	mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
13861da177e4SLinus Torvalds 
13874f4b401bSDave Kleikamp 	rc = jfs_init_acl(tid, ip, dir);
13884f4b401bSDave Kleikamp 	if (rc)
13891da177e4SLinus Torvalds 		goto out3;
13901da177e4SLinus Torvalds 
13912a7dba39SEric Paris 	rc = jfs_init_security(tid, ip, dir, &dentry->d_name);
13921d15b10fSDave Kleikamp 	if (rc) {
13931d15b10fSDave Kleikamp 		txAbort(tid, 0);
13941d15b10fSDave Kleikamp 		goto out3;
13951d15b10fSDave Kleikamp 	}
13961d15b10fSDave Kleikamp 
13974f4b401bSDave Kleikamp 	if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) {
13984f4b401bSDave Kleikamp 		txAbort(tid, 0);
13994f4b401bSDave Kleikamp 		goto out3;
14004f4b401bSDave Kleikamp 	}
14014f4b401bSDave Kleikamp 
14021da177e4SLinus Torvalds 	tblk = tid_to_tblock(tid);
14031da177e4SLinus Torvalds 	tblk->xflag |= COMMIT_CREATE;
14041da177e4SLinus Torvalds 	tblk->ino = ip->i_ino;
14051da177e4SLinus Torvalds 	tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
14061da177e4SLinus Torvalds 
14071da177e4SLinus Torvalds 	ino = ip->i_ino;
14084f4b401bSDave Kleikamp 	if ((rc = dtInsert(tid, dir, &dname, &ino, &btstack))) {
14094f4b401bSDave Kleikamp 		txAbort(tid, 0);
14101da177e4SLinus Torvalds 		goto out3;
14114f4b401bSDave Kleikamp 	}
14121da177e4SLinus Torvalds 
14131da177e4SLinus Torvalds 	ip->i_op = &jfs_file_inode_operations;
14141da177e4SLinus Torvalds 	jfs_ip->dev = new_encode_dev(rdev);
14151da177e4SLinus Torvalds 	init_special_inode(ip, ip->i_mode, rdev);
14161da177e4SLinus Torvalds 
14171da177e4SLinus Torvalds 	mark_inode_dirty(ip);
14181da177e4SLinus Torvalds 
1419ad9dc5dfSJeff Layton 	dir->i_mtime = inode_set_ctime_current(dir);
14201da177e4SLinus Torvalds 
14211da177e4SLinus Torvalds 	mark_inode_dirty(dir);
14221da177e4SLinus Torvalds 
14231da177e4SLinus Torvalds 	iplist[0] = dir;
14241da177e4SLinus Torvalds 	iplist[1] = ip;
14251da177e4SLinus Torvalds 	rc = txCommit(tid, 2, iplist, 0);
14261da177e4SLinus Torvalds 
14271da177e4SLinus Torvalds       out3:
14281da177e4SLinus Torvalds 	txEnd(tid);
14291de87444SIngo Molnar 	mutex_unlock(&JFS_IP(ip)->commit_mutex);
14301de87444SIngo Molnar 	mutex_unlock(&JFS_IP(dir)->commit_mutex);
14311da177e4SLinus Torvalds 	if (rc) {
14324f4b401bSDave Kleikamp 		free_ea_wmap(ip);
14336d6b77f1SMiklos Szeredi 		clear_nlink(ip);
1434a6cbedfaSAl Viro 		discard_new_inode(ip);
14351f3403faSDave Kleikamp 	} else {
14361e2e547aSAl Viro 		d_instantiate_new(dentry, ip);
14371f3403faSDave Kleikamp 	}
14381da177e4SLinus Torvalds 
14391da177e4SLinus Torvalds       out1:
14401da177e4SLinus Torvalds 	free_UCSname(&dname);
14411da177e4SLinus Torvalds 
14421da177e4SLinus Torvalds       out:
14431da177e4SLinus Torvalds 	jfs_info("jfs_mknod: returning %d", rc);
14441da177e4SLinus Torvalds 	return rc;
14451da177e4SLinus Torvalds }
14461da177e4SLinus Torvalds 
jfs_lookup(struct inode * dip,struct dentry * dentry,unsigned int flags)144700cd8dd3SAl Viro static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags)
14481da177e4SLinus Torvalds {
14491da177e4SLinus Torvalds 	struct btstack btstack;
14501da177e4SLinus Torvalds 	ino_t inum;
14511da177e4SLinus Torvalds 	struct inode *ip;
14521da177e4SLinus Torvalds 	struct component_name key;
14531da177e4SLinus Torvalds 	int rc;
14541da177e4SLinus Torvalds 
1455a455589fSAl Viro 	jfs_info("jfs_lookup: name = %pd", dentry);
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds 	if ((rc = get_UCSname(&key, dentry)))
14581da177e4SLinus Torvalds 		return ERR_PTR(rc);
14591da177e4SLinus Torvalds 	rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
14601da177e4SLinus Torvalds 	free_UCSname(&key);
14611da177e4SLinus Torvalds 	if (rc == -ENOENT) {
146279ac5a46SAl Viro 		ip = NULL;
14631da177e4SLinus Torvalds 	} else if (rc) {
14641da177e4SLinus Torvalds 		jfs_err("jfs_lookup: dtSearch returned %d", rc);
146579ac5a46SAl Viro 		ip = ERR_PTR(rc);
146679ac5a46SAl Viro 	} else {
1467eab1df71SDavid Howells 		ip = jfs_iget(dip->i_sb, inum);
1468a9049376SAl Viro 		if (IS_ERR(ip))
14691da177e4SLinus Torvalds 			jfs_err("jfs_lookup: iget failed on inum %d", (uint)inum);
147079ac5a46SAl Viro 	}
14711da177e4SLinus Torvalds 
147294b77bd8SAl Viro 	return d_splice_alias(ip, dentry);
14731da177e4SLinus Torvalds }
14741da177e4SLinus Torvalds 
jfs_nfs_get_inode(struct super_block * sb,u64 ino,u32 generation)1475d425de70SChristoph Hellwig static struct inode *jfs_nfs_get_inode(struct super_block *sb,
1476d425de70SChristoph Hellwig 		u64 ino, u32 generation)
14775ca29607SChristoph Hellwig {
14785ca29607SChristoph Hellwig 	struct inode *inode;
14795ca29607SChristoph Hellwig 
14805ca29607SChristoph Hellwig 	if (ino == 0)
14815ca29607SChristoph Hellwig 		return ERR_PTR(-ESTALE);
1482eab1df71SDavid Howells 	inode = jfs_iget(sb, ino);
1483eab1df71SDavid Howells 	if (IS_ERR(inode))
1484eab1df71SDavid Howells 		return ERR_CAST(inode);
14855ca29607SChristoph Hellwig 
1486eab1df71SDavid Howells 	if (generation && inode->i_generation != generation) {
14875ca29607SChristoph Hellwig 		iput(inode);
1488d425de70SChristoph Hellwig 		return ERR_PTR(-ESTALE);
1489d425de70SChristoph Hellwig 	}
1490d425de70SChristoph Hellwig 
1491d425de70SChristoph Hellwig 	return inode;
1492d425de70SChristoph Hellwig }
1493d425de70SChristoph Hellwig 
jfs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1494d425de70SChristoph Hellwig struct dentry *jfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
1495d425de70SChristoph Hellwig 		int fh_len, int fh_type)
1496d425de70SChristoph Hellwig {
1497d425de70SChristoph Hellwig 	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1498d425de70SChristoph Hellwig 				    jfs_nfs_get_inode);
1499d425de70SChristoph Hellwig }
1500d425de70SChristoph Hellwig 
jfs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1501d425de70SChristoph Hellwig struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid,
1502d425de70SChristoph Hellwig 		int fh_len, int fh_type)
1503d425de70SChristoph Hellwig {
1504d425de70SChristoph Hellwig 	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1505d425de70SChristoph Hellwig 				    jfs_nfs_get_inode);
15065ca29607SChristoph Hellwig }
15075ca29607SChristoph Hellwig 
jfs_get_parent(struct dentry * dentry)15081da177e4SLinus Torvalds struct dentry *jfs_get_parent(struct dentry *dentry)
15091da177e4SLinus Torvalds {
15101da177e4SLinus Torvalds 	unsigned long parent_ino;
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	parent_ino =
15132b0143b5SDavid Howells 		le32_to_cpu(JFS_IP(d_inode(dentry))->i_dtroot.header.idotdot);
15141da177e4SLinus Torvalds 
1515fc64005cSAl Viro 	return d_obtain_alias(jfs_iget(dentry->d_sb, parent_ino));
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds 
151892e1d5beSArjan van de Ven const struct inode_operations jfs_dir_inode_operations = {
15191da177e4SLinus Torvalds 	.create		= jfs_create,
15201da177e4SLinus Torvalds 	.lookup		= jfs_lookup,
15211da177e4SLinus Torvalds 	.link		= jfs_link,
15221da177e4SLinus Torvalds 	.unlink		= jfs_unlink,
15231da177e4SLinus Torvalds 	.symlink	= jfs_symlink,
15241da177e4SLinus Torvalds 	.mkdir		= jfs_mkdir,
15251da177e4SLinus Torvalds 	.rmdir		= jfs_rmdir,
15261da177e4SLinus Torvalds 	.mknod		= jfs_mknod,
15271da177e4SLinus Torvalds 	.rename		= jfs_rename,
15281da177e4SLinus Torvalds 	.listxattr	= jfs_listxattr,
15291da177e4SLinus Torvalds 	.setattr	= jfs_setattr,
15302ca58e30SMiklos Szeredi 	.fileattr_get	= jfs_fileattr_get,
15312ca58e30SMiklos Szeredi 	.fileattr_set	= jfs_fileattr_set,
1532759bfee6SChristoph Hellwig #ifdef CONFIG_JFS_POSIX_ACL
1533cac2f8b8SChristian Brauner 	.get_inode_acl	= jfs_get_acl,
15342cc6a5a0SChristoph Hellwig 	.set_acl	= jfs_set_acl,
15351da177e4SLinus Torvalds #endif
15361da177e4SLinus Torvalds };
15371da177e4SLinus Torvalds 
15383e327154SLinus Torvalds WRAP_DIR_ITER(jfs_readdir) // FIXME!
15394b6f5d20SArjan van de Ven const struct file_operations jfs_dir_operations = {
15401da177e4SLinus Torvalds 	.read		= generic_read_dir,
15413e327154SLinus Torvalds 	.iterate_shared	= shared_jfs_readdir,
15421da177e4SLinus Torvalds 	.fsync		= jfs_fsync,
1543baab81faSAndi Kleen 	.unlocked_ioctl = jfs_ioctl,
15442ca58e30SMiklos Szeredi 	.compat_ioctl	= compat_ptr_ioctl,
15453222a3e5SChristoph Hellwig 	.llseek		= generic_file_llseek,
15461da177e4SLinus Torvalds };
15471da177e4SLinus Torvalds 
jfs_ci_hash(const struct dentry * dir,struct qstr * this)1548da53be12SLinus Torvalds static int jfs_ci_hash(const struct dentry *dir, struct qstr *this)
15491da177e4SLinus Torvalds {
15501da177e4SLinus Torvalds 	unsigned long hash;
15511da177e4SLinus Torvalds 	int i;
15521da177e4SLinus Torvalds 
15538387ff25SLinus Torvalds 	hash = init_name_hash(dir);
15541da177e4SLinus Torvalds 	for (i=0; i < this->len; i++)
15551da177e4SLinus Torvalds 		hash = partial_name_hash(tolower(this->name[i]), hash);
15561da177e4SLinus Torvalds 	this->hash = end_name_hash(hash);
15571da177e4SLinus Torvalds 
15581da177e4SLinus Torvalds 	return 0;
15591da177e4SLinus Torvalds }
15601da177e4SLinus Torvalds 
jfs_ci_compare(const struct dentry * dentry,unsigned int len,const char * str,const struct qstr * name)15616fa67e70SAl Viro static int jfs_ci_compare(const struct dentry *dentry,
1562621e155aSNick Piggin 		unsigned int len, const char *str, const struct qstr *name)
15631da177e4SLinus Torvalds {
15641da177e4SLinus Torvalds 	int i, result = 1;
15651da177e4SLinus Torvalds 
1566621e155aSNick Piggin 	if (len != name->len)
15671da177e4SLinus Torvalds 		goto out;
1568621e155aSNick Piggin 	for (i=0; i < len; i++) {
1569621e155aSNick Piggin 		if (tolower(str[i]) != tolower(name->name[i]))
15701da177e4SLinus Torvalds 			goto out;
15711da177e4SLinus Torvalds 	}
15721da177e4SLinus Torvalds 	result = 0;
15731da177e4SLinus Torvalds out:
15741da177e4SLinus Torvalds 	return result;
15751da177e4SLinus Torvalds }
15761da177e4SLinus Torvalds 
jfs_ci_revalidate(struct dentry * dentry,unsigned int flags)15770b728e19SAl Viro static int jfs_ci_revalidate(struct dentry *dentry, unsigned int flags)
15782bc334dcSNick Piggin {
15792bc334dcSNick Piggin 	/*
15802bc334dcSNick Piggin 	 * This is not negative dentry. Always valid.
15812bc334dcSNick Piggin 	 *
15822bc334dcSNick Piggin 	 * Note, rename() to existing directory entry will have ->d_inode,
15832bc334dcSNick Piggin 	 * and will use existing name which isn't specified name by user.
15842bc334dcSNick Piggin 	 *
15852bc334dcSNick Piggin 	 * We may be able to drop this positive dentry here. But dropping
15862bc334dcSNick Piggin 	 * positive dentry isn't good idea. So it's unsupported like
15872bc334dcSNick Piggin 	 * rename("filename", "FILENAME") for now.
15882bc334dcSNick Piggin 	 */
15892b0143b5SDavid Howells 	if (d_really_is_positive(dentry))
15902bc334dcSNick Piggin 		return 1;
15912bc334dcSNick Piggin 
15922bc334dcSNick Piggin 	/*
15932bc334dcSNick Piggin 	 * This may be nfsd (or something), anyway, we can't see the
15942bc334dcSNick Piggin 	 * intent of this. So, since this can be for creation, drop it.
15952bc334dcSNick Piggin 	 */
15960b728e19SAl Viro 	if (!flags)
15972bc334dcSNick Piggin 		return 0;
15982bc334dcSNick Piggin 
15992bc334dcSNick Piggin 	/*
16002bc334dcSNick Piggin 	 * Drop the negative dentry, in order to make sure to use the
16012bc334dcSNick Piggin 	 * case sensitive name which is specified by user if this is
16022bc334dcSNick Piggin 	 * for creation.
16032bc334dcSNick Piggin 	 */
16040b728e19SAl Viro 	if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
16052bc334dcSNick Piggin 		return 0;
16062bc334dcSNick Piggin 	return 1;
16072bc334dcSNick Piggin }
16082bc334dcSNick Piggin 
1609ad28b4efSAl Viro const struct dentry_operations jfs_ci_dentry_operations =
16101da177e4SLinus Torvalds {
16111da177e4SLinus Torvalds 	.d_hash = jfs_ci_hash,
16121da177e4SLinus Torvalds 	.d_compare = jfs_ci_compare,
16132bc334dcSNick Piggin 	.d_revalidate = jfs_ci_revalidate,
16141da177e4SLinus Torvalds };
1615