Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.38-rc2 358 lines 9.7 kB view raw
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 (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) { 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 215 xfs_trans_ichgtime(tp, target_dp, 216 XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 217 218 if (new_parent && src_is_directory) { 219 error = xfs_bumplink(tp, target_dp); 220 if (error) 221 goto abort_return; 222 } 223 } else { /* target_ip != NULL */ 224 /* 225 * If target exists and it's a directory, check that both 226 * target and source are directories and that target can be 227 * destroyed, or that neither is a directory. 228 */ 229 if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { 230 /* 231 * Make sure target dir is empty. 232 */ 233 if (!(xfs_dir_isempty(target_ip)) || 234 (target_ip->i_d.di_nlink > 2)) { 235 error = XFS_ERROR(EEXIST); 236 goto error_return; 237 } 238 } 239 240 /* 241 * Link the source inode under the target name. 242 * If the source inode is a directory and we are moving 243 * it across directories, its ".." entry will be 244 * inconsistent until we replace that down below. 245 * 246 * In case there is already an entry with the same 247 * name at the destination directory, remove it first. 248 */ 249 error = xfs_dir_replace(tp, target_dp, target_name, 250 src_ip->i_ino, 251 &first_block, &free_list, spaceres); 252 if (error) 253 goto abort_return; 254 255 xfs_trans_ichgtime(tp, target_dp, 256 XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 257 258 /* 259 * Decrement the link count on the target since the target 260 * dir no longer points to it. 261 */ 262 error = xfs_droplink(tp, target_ip); 263 if (error) 264 goto abort_return; 265 266 if (src_is_directory) { 267 /* 268 * Drop the link from the old "." entry. 269 */ 270 error = xfs_droplink(tp, target_ip); 271 if (error) 272 goto abort_return; 273 } 274 } /* target_ip != NULL */ 275 276 /* 277 * Remove the source. 278 */ 279 if (new_parent && src_is_directory) { 280 /* 281 * Rewrite the ".." entry to point to the new 282 * directory. 283 */ 284 error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot, 285 target_dp->i_ino, 286 &first_block, &free_list, spaceres); 287 ASSERT(error != EEXIST); 288 if (error) 289 goto abort_return; 290 } 291 292 /* 293 * We always want to hit the ctime on the source inode. 294 * 295 * This isn't strictly required by the standards since the source 296 * inode isn't really being changed, but old unix file systems did 297 * it and some incremental backup programs won't work without it. 298 */ 299 xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG); 300 xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE); 301 302 /* 303 * Adjust the link count on src_dp. This is necessary when 304 * renaming a directory, either within one parent when 305 * the target existed, or across two parent directories. 306 */ 307 if (src_is_directory && (new_parent || target_ip != NULL)) { 308 309 /* 310 * Decrement link count on src_directory since the 311 * entry that's moved no longer points to it. 312 */ 313 error = xfs_droplink(tp, src_dp); 314 if (error) 315 goto abort_return; 316 } 317 318 error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, 319 &first_block, &free_list, spaceres); 320 if (error) 321 goto abort_return; 322 323 xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 324 xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); 325 if (new_parent) 326 xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); 327 328 /* 329 * If this is a synchronous mount, make sure that the 330 * rename transaction goes to disk before returning to 331 * the user. 332 */ 333 if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { 334 xfs_trans_set_sync(tp); 335 } 336 337 error = xfs_bmap_finish(&tp, &free_list, &committed); 338 if (error) { 339 xfs_bmap_cancel(&free_list); 340 xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | 341 XFS_TRANS_ABORT)); 342 goto std_return; 343 } 344 345 /* 346 * trans_commit will unlock src_ip, target_ip & decrement 347 * the vnode references. 348 */ 349 return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); 350 351 abort_return: 352 cancel_flags |= XFS_TRANS_ABORT; 353 error_return: 354 xfs_bmap_cancel(&free_list); 355 xfs_trans_cancel(tp, cancel_flags); 356 std_return: 357 return error; 358}