1/* 2 * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. 3 * All Rights Reserved. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18#include "xfs.h" 19#include "xfs_fs.h" 20#include "xfs_types.h" 21#include "xfs_log.h" 22#include "xfs_inum.h" 23#include "xfs_trans.h" 24#include "xfs_sb.h" 25#include "xfs_ag.h" 26#include "xfs_dir2.h" 27#include "xfs_mount.h" 28#include "xfs_da_btree.h" 29#include "xfs_bmap_btree.h" 30#include "xfs_dinode.h" 31#include "xfs_inode.h" 32#include "xfs_inode_item.h" 33#include "xfs_bmap.h" 34#include "xfs_error.h" 35#include "xfs_quota.h" 36#include "xfs_utils.h" 37#include "xfs_trans_space.h" 38#include "xfs_vnodeops.h" 39#include "xfs_trace.h" 40 41 42/* 43 * Enter all inodes for a rename transaction into a sorted array. 44 */ 45STATIC void 46xfs_sort_for_rename( 47 xfs_inode_t *dp1, /* in: old (source) directory inode */ 48 xfs_inode_t *dp2, /* in: new (target) directory inode */ 49 xfs_inode_t *ip1, /* in: inode of old entry */ 50 xfs_inode_t *ip2, /* in: inode of new entry, if it 51 already exists, NULL otherwise. */ 52 xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ 53 int *num_inodes) /* out: number of inodes in array */ 54{ 55 xfs_inode_t *temp; 56 int i, j; 57 58 /* 59 * i_tab contains a list of pointers to inodes. We initialize 60 * the table here & we'll sort it. We will then use it to 61 * order the acquisition of the inode locks. 62 * 63 * Note that the table may contain duplicates. e.g., dp1 == dp2. 64 */ 65 i_tab[0] = dp1; 66 i_tab[1] = dp2; 67 i_tab[2] = ip1; 68 if (ip2) { 69 *num_inodes = 4; 70 i_tab[3] = ip2; 71 } else { 72 *num_inodes = 3; 73 i_tab[3] = NULL; 74 } 75 76 /* 77 * Sort the elements via bubble sort. (Remember, there are at 78 * most 4 elements to sort, so this is adequate.) 79 */ 80 for (i = 0; i < *num_inodes; i++) { 81 for (j = 1; j < *num_inodes; j++) { 82 if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { 83 temp = i_tab[j]; 84 i_tab[j] = i_tab[j-1]; 85 i_tab[j-1] = temp; 86 } 87 } 88 } 89} 90 91/* 92 * xfs_rename 93 */ 94int 95xfs_rename( 96 xfs_inode_t *src_dp, 97 struct xfs_name *src_name, 98 xfs_inode_t *src_ip, 99 xfs_inode_t *target_dp, 100 struct xfs_name *target_name, 101 xfs_inode_t *target_ip) 102{ 103 xfs_trans_t *tp = NULL; 104 xfs_mount_t *mp = src_dp->i_mount; 105 int new_parent; /* moving to a new dir */ 106 int src_is_directory; /* src_name is a directory */ 107 int error; 108 xfs_bmap_free_t free_list; 109 xfs_fsblock_t first_block; 110 int cancel_flags; 111 int committed; 112 xfs_inode_t *inodes[4]; 113 int spaceres; 114 int num_inodes; 115 116 trace_xfs_rename(src_dp, target_dp, src_name, target_name); 117 118 new_parent = (src_dp != target_dp); 119 src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); 120 121 if (src_is_directory) { 122 /* 123 * Check for link count overflow on target_dp 124 */ 125 if (target_ip == NULL && new_parent && 126 target_dp->i_d.di_nlink >= XFS_MAXLINK) { 127 error = XFS_ERROR(EMLINK); 128 goto std_return; 129 } 130 } 131 132 xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, 133 inodes, &num_inodes); 134 135 xfs_bmap_init(&free_list, &first_block); 136 tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); 137 cancel_flags = XFS_TRANS_RELEASE_LOG_RES; 138 spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); 139 error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0, 140 XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); 141 if (error == ENOSPC) { 142 spaceres = 0; 143 error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0, 144 XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); 145 } 146 if (error) { 147 xfs_trans_cancel(tp, 0); 148 goto std_return; 149 } 150 151 /* 152 * Attach the dquots to the inodes 153 */ 154 error = xfs_qm_vop_rename_dqattach(inodes); 155 if (error) { 156 xfs_trans_cancel(tp, cancel_flags); 157 goto std_return; 158 } 159 160 /* 161 * Lock all the participating inodes. Depending upon whether 162 * the target_name exists in the target directory, and 163 * whether the target directory is the same as the source 164 * directory, we can lock from 2 to 4 inodes. 165 */ 166 xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL); 167 168 /* 169 * Join all the inodes to the transaction. From this point on, 170 * we can rely on either trans_commit or trans_cancel to unlock 171 * them. 172 */ 173 xfs_trans_ijoin_ref(tp, src_dp, XFS_ILOCK_EXCL); 174 if (new_parent) 175 xfs_trans_ijoin_ref(tp, target_dp, XFS_ILOCK_EXCL); 176 xfs_trans_ijoin_ref(tp, src_ip, XFS_ILOCK_EXCL); 177 if (target_ip) 178 xfs_trans_ijoin_ref(tp, target_ip, XFS_ILOCK_EXCL); 179 180 /* 181 * If we are using project inheritance, we only allow renames 182 * into our tree when the project IDs are the same; else the 183 * tree quota mechanism would be circumvented. 184 */ 185 if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && 186 (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) { 187 error = XFS_ERROR(EXDEV); 188 goto error_return; 189 } 190 191 /* 192 * Set up the target. 193 */ 194 if (target_ip == NULL) { 195 /* 196 * If there's no space reservation, check the entry will 197 * fit before actually inserting it. 198 */ 199 error = xfs_dir_canenter(tp, target_dp, target_name, spaceres); 200 if (error) 201 goto error_return; 202 /* 203 * If target does not exist and the rename crosses 204 * directories, adjust the target directory link count 205 * to account for the ".." reference from the new entry. 206 */ 207 error = xfs_dir_createname(tp, target_dp, target_name, 208 src_ip->i_ino, &first_block, 209 &free_list, spaceres); 210 if (error == ENOSPC) 211 goto error_return; 212 if (error) 213 goto abort_return; 214 xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 215 216 if (new_parent && src_is_directory) { 217 error = xfs_bumplink(tp, target_dp); 218 if (error) 219 goto abort_return; 220 } 221 } else { /* target_ip != NULL */ 222 /* 223 * If target exists and it's a directory, check that both 224 * target and source are directories and that target can be 225 * destroyed, or that neither is a directory. 226 */ 227 if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { 228 /* 229 * Make sure target dir is empty. 230 */ 231 if (!(xfs_dir_isempty(target_ip)) || 232 (target_ip->i_d.di_nlink > 2)) { 233 error = XFS_ERROR(EEXIST); 234 goto error_return; 235 } 236 } 237 238 /* 239 * Link the source inode under the target name. 240 * If the source inode is a directory and we are moving 241 * it across directories, its ".." entry will be 242 * inconsistent until we replace that down below. 243 * 244 * In case there is already an entry with the same 245 * name at the destination directory, remove it first. 246 */ 247 error = xfs_dir_replace(tp, target_dp, target_name, 248 src_ip->i_ino, 249 &first_block, &free_list, spaceres); 250 if (error) 251 goto abort_return; 252 xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 253 254 /* 255 * Decrement the link count on the target since the target 256 * dir no longer points to it. 257 */ 258 error = xfs_droplink(tp, target_ip); 259 if (error) 260 goto abort_return; 261 262 if (src_is_directory) { 263 /* 264 * Drop the link from the old "." entry. 265 */ 266 error = xfs_droplink(tp, target_ip); 267 if (error) 268 goto abort_return; 269 } 270 } /* target_ip != NULL */ 271 272 /* 273 * Remove the source. 274 */ 275 if (new_parent && src_is_directory) { 276 /* 277 * Rewrite the ".." entry to point to the new 278 * directory. 279 */ 280 error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot, 281 target_dp->i_ino, 282 &first_block, &free_list, spaceres); 283 ASSERT(error != EEXIST); 284 if (error) 285 goto abort_return; 286 } 287 288 /* 289 * We always want to hit the ctime on the source inode. 290 * 291 * This isn't strictly required by the standards since the source 292 * inode isn't really being changed, but old unix file systems did 293 * it and some incremental backup programs won't work without it. 294 */ 295 xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG); 296 297 /* 298 * Adjust the link count on src_dp. This is necessary when 299 * renaming a directory, either within one parent when 300 * the target existed, or across two parent directories. 301 */ 302 if (src_is_directory && (new_parent || target_ip != NULL)) { 303 304 /* 305 * Decrement link count on src_directory since the 306 * entry that's moved no longer points to it. 307 */ 308 error = xfs_droplink(tp, src_dp); 309 if (error) 310 goto abort_return; 311 } 312 313 error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, 314 &first_block, &free_list, spaceres); 315 if (error) 316 goto abort_return; 317 318 xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 319 xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); 320 if (new_parent) 321 xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); 322 323 /* 324 * If this is a synchronous mount, make sure that the 325 * rename transaction goes to disk before returning to 326 * the user. 327 */ 328 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { 329 xfs_trans_set_sync(tp); 330 } 331 332 error = xfs_bmap_finish(&tp, &free_list, &committed); 333 if (error) { 334 xfs_bmap_cancel(&free_list); 335 xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | 336 XFS_TRANS_ABORT)); 337 goto std_return; 338 } 339 340 /* 341 * trans_commit will unlock src_ip, target_ip & decrement 342 * the vnode references. 343 */ 344 return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); 345 346 abort_return: 347 cancel_flags |= XFS_TRANS_ABORT; 348 error_return: 349 xfs_bmap_cancel(&free_list); 350 xfs_trans_cancel(tp, cancel_flags); 351 std_return: 352 return error; 353} 354