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