1153323Srodrigc/*
2159451Srodrigc * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
3159451Srodrigc * All Rights Reserved.
4153323Srodrigc *
5159451Srodrigc * This program is free software; you can redistribute it and/or
6159451Srodrigc * modify it under the terms of the GNU General Public License as
7153323Srodrigc * published by the Free Software Foundation.
8153323Srodrigc *
9159451Srodrigc * This program is distributed in the hope that it would be useful,
10159451Srodrigc * but WITHOUT ANY WARRANTY; without even the implied warranty of
11159451Srodrigc * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12159451Srodrigc * GNU General Public License for more details.
13153323Srodrigc *
14159451Srodrigc * You should have received a copy of the GNU General Public License
15159451Srodrigc * along with this program; if not, write the Free Software Foundation,
16159451Srodrigc * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17153323Srodrigc */
18153323Srodrigc#include "xfs.h"
19159451Srodrigc#include "xfs_fs.h"
20153323Srodrigc#include "xfs_types.h"
21159451Srodrigc#include "xfs_log.h"
22153323Srodrigc#include "xfs_inum.h"
23153323Srodrigc#include "xfs_trans.h"
24153323Srodrigc#include "xfs_sb.h"
25153323Srodrigc#include "xfs_dir.h"
26153323Srodrigc#include "xfs_dir2.h"
27153323Srodrigc#include "xfs_dmapi.h"
28153323Srodrigc#include "xfs_mount.h"
29159451Srodrigc#include "xfs_da_btree.h"
30153323Srodrigc#include "xfs_bmap_btree.h"
31153323Srodrigc#include "xfs_dir_sf.h"
32153323Srodrigc#include "xfs_dir2_sf.h"
33159451Srodrigc#include "xfs_attr_sf.h"
34153323Srodrigc#include "xfs_dinode.h"
35159451Srodrigc#include "xfs_inode.h"
36153323Srodrigc#include "xfs_inode_item.h"
37153323Srodrigc#include "xfs_bmap.h"
38153323Srodrigc#include "xfs_error.h"
39153323Srodrigc#include "xfs_quota.h"
40153323Srodrigc#include "xfs_refcache.h"
41153323Srodrigc#include "xfs_utils.h"
42153323Srodrigc#include "xfs_trans_space.h"
43153323Srodrigc#include "xfs_dir_leaf.h"
44153323Srodrigc
45153323Srodrigc
46153323Srodrigc/*
47153323Srodrigc * Given an array of up to 4 inode pointers, unlock the pointed to inodes.
48153323Srodrigc * If there are fewer than 4 entries in the array, the empty entries will
49153323Srodrigc * be at the end and will have NULL pointers in them.
50153323Srodrigc */
51153323SrodrigcSTATIC void
52153323Srodrigcxfs_rename_unlock4(
53153323Srodrigc	xfs_inode_t	**i_tab,
54153323Srodrigc	uint		lock_mode)
55153323Srodrigc{
56153323Srodrigc	int	i;
57153323Srodrigc
58153323Srodrigc	xfs_iunlock(i_tab[0], lock_mode);
59153323Srodrigc	for (i = 1; i < 4; i++) {
60153323Srodrigc		if (i_tab[i] == NULL) {
61153323Srodrigc			break;
62153323Srodrigc		}
63153323Srodrigc		/*
64153323Srodrigc		 * Watch out for duplicate entries in the table.
65153323Srodrigc		 */
66153323Srodrigc		if (i_tab[i] != i_tab[i-1]) {
67153323Srodrigc			xfs_iunlock(i_tab[i], lock_mode);
68153323Srodrigc		}
69153323Srodrigc	}
70153323Srodrigc}
71153323Srodrigc
72153323Srodrigc#ifdef DEBUG
73153323Srodrigcint xfs_rename_skip, xfs_rename_nskip;
74153323Srodrigc#endif
75153323Srodrigc
76153323Srodrigc/*
77153323Srodrigc * The following routine will acquire the locks required for a rename
78153323Srodrigc * operation. The code understands the semantics of renames and will
79153323Srodrigc * validate that name1 exists under dp1 & that name2 may or may not
80153323Srodrigc * exist under dp2.
81153323Srodrigc *
82153323Srodrigc * We are renaming dp1/name1 to dp2/name2.
83153323Srodrigc *
84153323Srodrigc * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success.
85153323Srodrigc */
86153323SrodrigcSTATIC int
87153323Srodrigcxfs_lock_for_rename(
88153323Srodrigc	xfs_inode_t	*dp1,	/* old (source) directory inode */
89153323Srodrigc	xfs_inode_t	*dp2,	/* new (target) directory inode */
90153323Srodrigc	vname_t		*vname1,/* old entry name */
91153323Srodrigc	vname_t		*vname2,/* new entry name */
92153323Srodrigc	xfs_inode_t	**ipp1,	/* inode of old entry */
93153323Srodrigc	xfs_inode_t	**ipp2,	/* inode of new entry, if it
94153323Srodrigc				   already exists, NULL otherwise. */
95153323Srodrigc	xfs_inode_t	**i_tab,/* array of inode returned, sorted */
96153323Srodrigc	int		*num_inodes)  /* number of inodes in array */
97153323Srodrigc{
98153323Srodrigc	xfs_inode_t		*ip1, *ip2, *temp;
99153323Srodrigc	xfs_ino_t		inum1, inum2;
100153323Srodrigc	int			error;
101153323Srodrigc	int			i, j;
102153323Srodrigc	uint			lock_mode;
103153323Srodrigc	int			diff_dirs = (dp1 != dp2);
104153323Srodrigc
105153323Srodrigc	ip2 = NULL;
106153323Srodrigc
107153323Srodrigc	/*
108153323Srodrigc	 * First, find out the current inums of the entries so that we
109153323Srodrigc	 * can determine the initial locking order.  We'll have to
110153323Srodrigc	 * sanity check stuff after all the locks have been acquired
111153323Srodrigc	 * to see if we still have the right inodes, directories, etc.
112153323Srodrigc	 */
113153323Srodrigc	lock_mode = xfs_ilock_map_shared(dp1);
114153323Srodrigc	error = xfs_get_dir_entry(vname1, &ip1);
115153323Srodrigc	if (error) {
116153323Srodrigc		xfs_iunlock_map_shared(dp1, lock_mode);
117153323Srodrigc		return error;
118153323Srodrigc	}
119153323Srodrigc
120153323Srodrigc	inum1 = ip1->i_ino;
121153323Srodrigc
122153323Srodrigc	ASSERT(ip1);
123153323Srodrigc	ITRACE(ip1);
124153323Srodrigc
125153323Srodrigc	/*
126153323Srodrigc	 * Unlock dp1 and lock dp2 if they are different.
127153323Srodrigc	 */
128153323Srodrigc
129153323Srodrigc	if (diff_dirs) {
130153323Srodrigc		xfs_iunlock_map_shared(dp1, lock_mode);
131153323Srodrigc		lock_mode = xfs_ilock_map_shared(dp2);
132153323Srodrigc	}
133153323Srodrigc
134153323Srodrigc	error = xfs_dir_lookup_int(XFS_ITOBHV(dp2), lock_mode,
135153323Srodrigc				   vname2, &inum2, &ip2);
136153323Srodrigc	if (error == ENOENT) {		/* target does not need to exist. */
137153323Srodrigc		inum2 = 0;
138153323Srodrigc	} else if (error) {
139153323Srodrigc		/*
140153323Srodrigc		 * If dp2 and dp1 are the same, the next line unlocks dp1.
141153323Srodrigc		 * Got it?
142153323Srodrigc		 */
143153323Srodrigc		xfs_iunlock_map_shared(dp2, lock_mode);
144153323Srodrigc		IRELE (ip1);
145153323Srodrigc		return error;
146153323Srodrigc	} else {
147153323Srodrigc		ITRACE(ip2);
148153323Srodrigc	}
149153323Srodrigc
150153323Srodrigc	/*
151153323Srodrigc	 * i_tab contains a list of pointers to inodes.  We initialize
152153323Srodrigc	 * the table here & we'll sort it.  We will then use it to
153153323Srodrigc	 * order the acquisition of the inode locks.
154153323Srodrigc	 *
155153323Srodrigc	 * Note that the table may contain duplicates.  e.g., dp1 == dp2.
156153323Srodrigc	 */
157153323Srodrigc	i_tab[0] = dp1;
158153323Srodrigc	i_tab[1] = dp2;
159153323Srodrigc	i_tab[2] = ip1;
160153323Srodrigc	if (inum2 == 0) {
161153323Srodrigc		*num_inodes = 3;
162153323Srodrigc		i_tab[3] = NULL;
163153323Srodrigc	} else {
164153323Srodrigc		*num_inodes = 4;
165153323Srodrigc		i_tab[3] = ip2;
166153323Srodrigc	}
167153323Srodrigc
168153323Srodrigc	/*
169153323Srodrigc	 * Sort the elements via bubble sort.  (Remember, there are at
170153323Srodrigc	 * most 4 elements to sort, so this is adequate.)
171153323Srodrigc	 */
172153323Srodrigc	for (i=0; i < *num_inodes; i++) {
173153323Srodrigc		for (j=1; j < *num_inodes; j++) {
174153323Srodrigc			if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) {
175153323Srodrigc				temp = i_tab[j];
176153323Srodrigc				i_tab[j] = i_tab[j-1];
177153323Srodrigc				i_tab[j-1] = temp;
178153323Srodrigc			}
179153323Srodrigc		}
180153323Srodrigc	}
181153323Srodrigc
182153323Srodrigc	/*
183153323Srodrigc	 * We have dp2 locked. If it isn't first, unlock it.
184153323Srodrigc	 * If it is first, tell xfs_lock_inodes so it can skip it
185153323Srodrigc	 * when locking. if dp1 == dp2, xfs_lock_inodes will skip both
186153323Srodrigc	 * since they are equal. xfs_lock_inodes needs all these inodes
187153323Srodrigc	 * so that it can unlock and retry if there might be a dead-lock
188153323Srodrigc	 * potential with the log.
189153323Srodrigc	 */
190153323Srodrigc
191153323Srodrigc	if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) {
192153323Srodrigc#ifdef DEBUG
193153323Srodrigc		xfs_rename_skip++;
194153323Srodrigc#endif
195153323Srodrigc		xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED);
196153323Srodrigc	} else {
197153323Srodrigc#ifdef DEBUG
198153323Srodrigc		xfs_rename_nskip++;
199153323Srodrigc#endif
200153323Srodrigc		xfs_iunlock_map_shared(dp2, lock_mode);
201153323Srodrigc		xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED);
202153323Srodrigc	}
203153323Srodrigc
204153323Srodrigc	/*
205153323Srodrigc	 * Set the return value. Null out any unused entries in i_tab.
206153323Srodrigc	 */
207153323Srodrigc	*ipp1 = *ipp2 = NULL;
208153323Srodrigc	for (i=0; i < *num_inodes; i++) {
209153323Srodrigc		if (i_tab[i]->i_ino == inum1) {
210153323Srodrigc			*ipp1 = i_tab[i];
211153323Srodrigc		}
212153323Srodrigc		if (i_tab[i]->i_ino == inum2) {
213153323Srodrigc			*ipp2 = i_tab[i];
214153323Srodrigc		}
215153323Srodrigc	}
216153323Srodrigc	for (;i < 4; i++) {
217153323Srodrigc		i_tab[i] = NULL;
218153323Srodrigc	}
219153323Srodrigc	return 0;
220153323Srodrigc}
221153323Srodrigc
222153323Srodrigc/*
223153323Srodrigc * xfs_rename
224153323Srodrigc */
225153323Srodrigcint
226153323Srodrigcxfs_rename(
227153323Srodrigc	bhv_desc_t	*src_dir_bdp,
228153323Srodrigc	vname_t		*src_vname,
229153323Srodrigc	xfs_vnode_t	*target_dir_vp,
230153323Srodrigc	vname_t		*target_vname,
231153323Srodrigc	cred_t		*credp)
232153323Srodrigc{
233153323Srodrigc	xfs_trans_t	*tp;
234153323Srodrigc	xfs_inode_t	*src_dp, *target_dp, *src_ip, *target_ip;
235153323Srodrigc	xfs_mount_t	*mp;
236153323Srodrigc	int		new_parent;		/* moving to a new dir */
237153323Srodrigc	int		src_is_directory;	/* src_name is a directory */
238153323Srodrigc	int		error;
239153323Srodrigc	xfs_bmap_free_t free_list;
240153323Srodrigc	xfs_fsblock_t   first_block;
241153323Srodrigc	int		cancel_flags;
242153323Srodrigc	int		committed;
243153323Srodrigc	xfs_inode_t	*inodes[4];
244153323Srodrigc	int		target_ip_dropped = 0;	/* dropped target_ip link? */
245153323Srodrigc	xfs_vnode_t	*src_dir_vp;
246153323Srodrigc	int		spaceres;
247153323Srodrigc	int		target_link_zero = 0;
248153323Srodrigc	int		num_inodes;
249153323Srodrigc	char		*src_name = VNAME(src_vname);
250153323Srodrigc	char		*target_name = VNAME(target_vname);
251153323Srodrigc	int		src_namelen = VNAMELEN(src_vname);
252153323Srodrigc	int		target_namelen = VNAMELEN(target_vname);
253153323Srodrigc
254153323Srodrigc	src_dir_vp = BHV_TO_VNODE(src_dir_bdp);
255153323Srodrigc	vn_trace_entry(src_dir_vp, "xfs_rename", (inst_t *)__return_address);
256153323Srodrigc	vn_trace_entry(target_dir_vp, "xfs_rename", (inst_t *)__return_address);
257153323Srodrigc
258153323Srodrigc	/*
259153323Srodrigc	 * Find the XFS behavior descriptor for the target directory
260153323Srodrigc	 * vnode since it was not handed to us.
261153323Srodrigc	 */
262159451Srodrigc	target_dp = xfs_vtoi(target_dir_vp);
263159451Srodrigc	if (target_dp == NULL) {
264153323Srodrigc		return XFS_ERROR(EXDEV);
265153323Srodrigc	}
266153323Srodrigc
267153323Srodrigc	src_dp = XFS_BHVTOI(src_dir_bdp);
268153323Srodrigc	mp = src_dp->i_mount;
269153323Srodrigc
270153323Srodrigc	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) ||
271153323Srodrigc	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
272153323Srodrigc				target_dp, DM_EVENT_RENAME)) {
273153323Srodrigc		error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME,
274153323Srodrigc					src_dir_vp, DM_RIGHT_NULL,
275153323Srodrigc					target_dir_vp, DM_RIGHT_NULL,
276153323Srodrigc					src_name, target_name,
277153323Srodrigc					0, 0, 0);
278153323Srodrigc		if (error) {
279153323Srodrigc			return error;
280153323Srodrigc		}
281153323Srodrigc	}
282153323Srodrigc	/* Return through std_return after this point. */
283153323Srodrigc
284153323Srodrigc	/*
285153323Srodrigc	 * Lock all the participating inodes. Depending upon whether
286153323Srodrigc	 * the target_name exists in the target directory, and
287153323Srodrigc	 * whether the target directory is the same as the source
288153323Srodrigc	 * directory, we can lock from 2 to 4 inodes.
289153323Srodrigc	 * xfs_lock_for_rename() will return ENOENT if src_name
290153323Srodrigc	 * does not exist in the source directory.
291153323Srodrigc	 */
292153323Srodrigc	tp = NULL;
293153323Srodrigc	error = xfs_lock_for_rename(src_dp, target_dp, src_vname,
294153323Srodrigc			target_vname, &src_ip, &target_ip, inodes,
295153323Srodrigc			&num_inodes);
296153323Srodrigc
297153323Srodrigc	if (error) {
298153323Srodrigc		/*
299153323Srodrigc		 * We have nothing locked, no inode references, and
300153323Srodrigc		 * no transaction, so just get out.
301153323Srodrigc		 */
302153323Srodrigc		goto std_return;
303153323Srodrigc	}
304153323Srodrigc
305153323Srodrigc	ASSERT(src_ip != NULL);
306153323Srodrigc
307153323Srodrigc	if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
308153323Srodrigc		/*
309153323Srodrigc		 * Check for link count overflow on target_dp
310153323Srodrigc		 */
311153323Srodrigc		if (target_ip == NULL && (src_dp != target_dp) &&
312153323Srodrigc		    target_dp->i_d.di_nlink >= XFS_MAXLINK) {
313153323Srodrigc			error = XFS_ERROR(EMLINK);
314153323Srodrigc			xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
315153323Srodrigc			goto rele_return;
316153323Srodrigc		}
317153323Srodrigc	}
318153323Srodrigc
319153323Srodrigc	new_parent = (src_dp != target_dp);
320153323Srodrigc	src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);
321153323Srodrigc
322153323Srodrigc	/*
323153323Srodrigc	 * Drop the locks on our inodes so that we can start the transaction.
324153323Srodrigc	 */
325153323Srodrigc	xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
326153323Srodrigc
327153323Srodrigc	XFS_BMAP_INIT(&free_list, &first_block);
328153323Srodrigc	tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
329153323Srodrigc	cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
330153323Srodrigc	spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen);
331153323Srodrigc	error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0,
332153323Srodrigc			XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
333153323Srodrigc	if (error == ENOSPC) {
334153323Srodrigc		spaceres = 0;
335153323Srodrigc		error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0,
336153323Srodrigc				XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
337153323Srodrigc	}
338153323Srodrigc	if (error) {
339153323Srodrigc		xfs_trans_cancel(tp, 0);
340153323Srodrigc		goto rele_return;
341153323Srodrigc	}
342153323Srodrigc
343153323Srodrigc	/*
344153323Srodrigc	 * Attach the dquots to the inodes
345153323Srodrigc	 */
346153323Srodrigc	if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
347153323Srodrigc		xfs_trans_cancel(tp, cancel_flags);
348153323Srodrigc		goto rele_return;
349153323Srodrigc	}
350153323Srodrigc
351153323Srodrigc	/*
352153323Srodrigc	 * Reacquire the inode locks we dropped above.
353153323Srodrigc	 */
354153323Srodrigc	xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL);
355153323Srodrigc
356153323Srodrigc	/*
357153323Srodrigc	 * Join all the inodes to the transaction. From this point on,
358153323Srodrigc	 * we can rely on either trans_commit or trans_cancel to unlock
359153323Srodrigc	 * them.  Note that we need to add a vnode reference to the
360153323Srodrigc	 * directories since trans_commit & trans_cancel will decrement
361153323Srodrigc	 * them when they unlock the inodes.  Also, we need to be careful
362153323Srodrigc	 * not to add an inode to the transaction more than once.
363153323Srodrigc	 */
364153323Srodrigc	VN_HOLD(src_dir_vp);
365153323Srodrigc	xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
366153323Srodrigc	if (new_parent) {
367153323Srodrigc		VN_HOLD(target_dir_vp);
368153323Srodrigc		xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
369153323Srodrigc	}
370153323Srodrigc	if ((src_ip != src_dp) && (src_ip != target_dp)) {
371153323Srodrigc		xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
372153323Srodrigc	}
373153323Srodrigc	if ((target_ip != NULL) &&
374153323Srodrigc	    (target_ip != src_ip) &&
375153323Srodrigc	    (target_ip != src_dp) &&
376153323Srodrigc	    (target_ip != target_dp)) {
377153323Srodrigc		xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
378153323Srodrigc	}
379153323Srodrigc
380153323Srodrigc	/*
381153323Srodrigc	 * Set up the target.
382153323Srodrigc	 */
383153323Srodrigc	if (target_ip == NULL) {
384153323Srodrigc		/*
385153323Srodrigc		 * If there's no space reservation, check the entry will
386153323Srodrigc		 * fit before actually inserting it.
387153323Srodrigc		 */
388153323Srodrigc		if (spaceres == 0 &&
389153323Srodrigc		    (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name,
390153323Srodrigc				target_namelen))) {
391153323Srodrigc			goto error_return;
392153323Srodrigc		}
393153323Srodrigc		/*
394153323Srodrigc		 * If target does not exist and the rename crosses
395153323Srodrigc		 * directories, adjust the target directory link count
396153323Srodrigc		 * to account for the ".." reference from the new entry.
397153323Srodrigc		 */
398153323Srodrigc		error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name,
399153323Srodrigc					   target_namelen, src_ip->i_ino,
400153323Srodrigc					   &first_block, &free_list, spaceres);
401153323Srodrigc		if (error == ENOSPC) {
402153323Srodrigc			goto error_return;
403153323Srodrigc		}
404153323Srodrigc		if (error) {
405153323Srodrigc			goto abort_return;
406153323Srodrigc		}
407153323Srodrigc		xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
408153323Srodrigc
409153323Srodrigc		if (new_parent && src_is_directory) {
410153323Srodrigc			error = xfs_bumplink(tp, target_dp);
411153323Srodrigc			if (error) {
412153323Srodrigc				goto abort_return;
413153323Srodrigc			}
414153323Srodrigc		}
415153323Srodrigc	} else { /* target_ip != NULL */
416153323Srodrigc
417153323Srodrigc		/*
418153323Srodrigc		 * If target exists and it's a directory, check that both
419153323Srodrigc		 * target and source are directories and that target can be
420153323Srodrigc		 * destroyed, or that neither is a directory.
421153323Srodrigc		 */
422153323Srodrigc		if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
423153323Srodrigc			/*
424153323Srodrigc			 * Make sure target dir is empty.
425153323Srodrigc			 */
426153323Srodrigc			if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) ||
427153323Srodrigc			    (target_ip->i_d.di_nlink > 2)) {
428153323Srodrigc				error = XFS_ERROR(EEXIST);
429153323Srodrigc				goto error_return;
430153323Srodrigc			}
431153323Srodrigc		}
432153323Srodrigc
433153323Srodrigc		/*
434153323Srodrigc		 * Link the source inode under the target name.
435153323Srodrigc		 * If the source inode is a directory and we are moving
436153323Srodrigc		 * it across directories, its ".." entry will be
437153323Srodrigc		 * inconsistent until we replace that down below.
438153323Srodrigc		 *
439153323Srodrigc		 * In case there is already an entry with the same
440153323Srodrigc		 * name at the destination directory, remove it first.
441153323Srodrigc		 */
442153323Srodrigc		error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name,
443153323Srodrigc			target_namelen, src_ip->i_ino, &first_block,
444153323Srodrigc			&free_list, spaceres);
445153323Srodrigc		if (error) {
446153323Srodrigc			goto abort_return;
447153323Srodrigc		}
448153323Srodrigc		xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
449153323Srodrigc
450153323Srodrigc		/*
451153323Srodrigc		 * Decrement the link count on the target since the target
452153323Srodrigc		 * dir no longer points to it.
453153323Srodrigc		 */
454153323Srodrigc		error = xfs_droplink(tp, target_ip);
455153323Srodrigc		if (error) {
456153323Srodrigc			goto abort_return;
457153323Srodrigc		}
458153323Srodrigc		target_ip_dropped = 1;
459153323Srodrigc
460153323Srodrigc		if (src_is_directory) {
461153323Srodrigc			/*
462153323Srodrigc			 * Drop the link from the old "." entry.
463153323Srodrigc			 */
464153323Srodrigc			error = xfs_droplink(tp, target_ip);
465153323Srodrigc			if (error) {
466153323Srodrigc				goto abort_return;
467153323Srodrigc			}
468153323Srodrigc		}
469153323Srodrigc
470153323Srodrigc		/* Do this test while we still hold the locks */
471153323Srodrigc		target_link_zero = (target_ip)->i_d.di_nlink==0;
472153323Srodrigc
473153323Srodrigc	} /* target_ip != NULL */
474153323Srodrigc
475153323Srodrigc	/*
476153323Srodrigc	 * Remove the source.
477153323Srodrigc	 */
478153323Srodrigc	if (new_parent && src_is_directory) {
479153323Srodrigc
480153323Srodrigc		/*
481153323Srodrigc		 * Rewrite the ".." entry to point to the new
482153323Srodrigc		 * directory.
483153323Srodrigc		 */
484153323Srodrigc		error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2,
485153323Srodrigc					target_dp->i_ino, &first_block,
486153323Srodrigc					&free_list, spaceres);
487153323Srodrigc		ASSERT(error != EEXIST);
488153323Srodrigc		if (error) {
489153323Srodrigc			goto abort_return;
490153323Srodrigc		}
491153323Srodrigc		xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
492153323Srodrigc
493153323Srodrigc	} else {
494153323Srodrigc		/*
495153323Srodrigc		 * We always want to hit the ctime on the source inode.
496153323Srodrigc		 * We do it in the if clause above for the 'new_parent &&
497153323Srodrigc		 * src_is_directory' case, and here we get all the other
498153323Srodrigc		 * cases.  This isn't strictly required by the standards
499153323Srodrigc		 * since the source inode isn't really being changed,
500153323Srodrigc		 * but old unix file systems did it and some incremental
501153323Srodrigc		 * backup programs won't work without it.
502153323Srodrigc		 */
503153323Srodrigc		xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG);
504153323Srodrigc	}
505153323Srodrigc
506153323Srodrigc	/*
507153323Srodrigc	 * Adjust the link count on src_dp.  This is necessary when
508153323Srodrigc	 * renaming a directory, either within one parent when
509153323Srodrigc	 * the target existed, or across two parent directories.
510153323Srodrigc	 */
511153323Srodrigc	if (src_is_directory && (new_parent || target_ip != NULL)) {
512153323Srodrigc
513153323Srodrigc		/*
514153323Srodrigc		 * Decrement link count on src_directory since the
515153323Srodrigc		 * entry that's moved no longer points to it.
516153323Srodrigc		 */
517153323Srodrigc		error = xfs_droplink(tp, src_dp);
518153323Srodrigc		if (error) {
519153323Srodrigc			goto abort_return;
520153323Srodrigc		}
521153323Srodrigc	}
522153323Srodrigc
523153323Srodrigc	error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen,
524153323Srodrigc			src_ip->i_ino, &first_block, &free_list, spaceres);
525153323Srodrigc	if (error) {
526153323Srodrigc		goto abort_return;
527153323Srodrigc	}
528153323Srodrigc	xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
529153323Srodrigc
530153323Srodrigc	/*
531153323Srodrigc	 * Update the generation counts on all the directory inodes
532153323Srodrigc	 * that we're modifying.
533153323Srodrigc	 */
534153323Srodrigc	src_dp->i_gen++;
535153323Srodrigc	xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
536153323Srodrigc
537153323Srodrigc	if (new_parent) {
538153323Srodrigc		target_dp->i_gen++;
539153323Srodrigc		xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
540153323Srodrigc	}
541153323Srodrigc
542153323Srodrigc	/*
543153323Srodrigc	 * If there was a target inode, take an extra reference on
544153323Srodrigc	 * it here so that it doesn't go to xfs_inactive() from
545153323Srodrigc	 * within the commit.
546153323Srodrigc	 */
547153323Srodrigc	if (target_ip != NULL) {
548153323Srodrigc		IHOLD(target_ip);
549153323Srodrigc	}
550153323Srodrigc
551153323Srodrigc	/*
552153323Srodrigc	 * If this is a synchronous mount, make sure that the
553153323Srodrigc	 * rename transaction goes to disk before returning to
554153323Srodrigc	 * the user.
555153323Srodrigc	 */
556159451Srodrigc	if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
557153323Srodrigc		xfs_trans_set_sync(tp);
558153323Srodrigc	}
559153323Srodrigc
560153323Srodrigc	/*
561153323Srodrigc	 * Take refs. for vop_link_removed calls below.  No need to worry
562153323Srodrigc	 * about directory refs. because the caller holds them.
563153323Srodrigc	 *
564153323Srodrigc	 * Do holds before the xfs_bmap_finish since it might rele them down
565153323Srodrigc	 * to zero.
566153323Srodrigc	 */
567153323Srodrigc
568153323Srodrigc	if (target_ip_dropped)
569153323Srodrigc		IHOLD(target_ip);
570153323Srodrigc	IHOLD(src_ip);
571153323Srodrigc
572153323Srodrigc	error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
573153323Srodrigc	if (error) {
574153323Srodrigc		xfs_bmap_cancel(&free_list);
575153323Srodrigc		xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
576153323Srodrigc				 XFS_TRANS_ABORT));
577153323Srodrigc		if (target_ip != NULL) {
578153323Srodrigc			IRELE(target_ip);
579153323Srodrigc		}
580153323Srodrigc		if (target_ip_dropped) {
581153323Srodrigc			IRELE(target_ip);
582153323Srodrigc		}
583153323Srodrigc		IRELE(src_ip);
584153323Srodrigc		goto std_return;
585153323Srodrigc	}
586153323Srodrigc
587153323Srodrigc	/*
588153323Srodrigc	 * trans_commit will unlock src_ip, target_ip & decrement
589153323Srodrigc	 * the vnode references.
590153323Srodrigc	 */
591153323Srodrigc	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
592153323Srodrigc	if (target_ip != NULL) {
593153323Srodrigc		xfs_refcache_purge_ip(target_ip);
594153323Srodrigc		IRELE(target_ip);
595153323Srodrigc	}
596153323Srodrigc	/*
597153323Srodrigc	 * Let interposed file systems know about removed links.
598153323Srodrigc	 */
599153323Srodrigc	if (target_ip_dropped) {
600153323Srodrigc		XVOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp,
601153323Srodrigc					target_link_zero);
602153323Srodrigc		IRELE(target_ip);
603153323Srodrigc	}
604153323Srodrigc
605153323Srodrigc	IRELE(src_ip);
606153323Srodrigc
607153323Srodrigc	/* Fall through to std_return with error = 0 or errno from
608153323Srodrigc	 * xfs_trans_commit	 */
609153323Srodrigcstd_return:
610153323Srodrigc	if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) ||
611153323Srodrigc	    DM_EVENT_ENABLED(target_dir_vp->v_vfsp,
612153323Srodrigc				target_dp, DM_EVENT_POSTRENAME)) {
613153323Srodrigc		(void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME,
614153323Srodrigc					src_dir_vp, DM_RIGHT_NULL,
615153323Srodrigc					target_dir_vp, DM_RIGHT_NULL,
616153323Srodrigc					src_name, target_name,
617153323Srodrigc					0, error, 0);
618153323Srodrigc	}
619153323Srodrigc	return error;
620153323Srodrigc
621153323Srodrigc abort_return:
622153323Srodrigc	cancel_flags |= XFS_TRANS_ABORT;
623153323Srodrigc	/* FALLTHROUGH */
624153323Srodrigc error_return:
625153323Srodrigc	xfs_bmap_cancel(&free_list);
626153323Srodrigc	xfs_trans_cancel(tp, cancel_flags);
627153323Srodrigc	goto std_return;
628153323Srodrigc
629153323Srodrigc rele_return:
630153323Srodrigc	IRELE(src_ip);
631153323Srodrigc	if (target_ip != NULL) {
632153323Srodrigc		IRELE(target_ip);
633153323Srodrigc	}
634153323Srodrigc	goto std_return;
635153323Srodrigc}
636153323Srodrigc
637