diff options
Diffstat (limited to 'fs/xfs/xfs_rename.c')
-rw-r--r-- | fs/xfs/xfs_rename.c | 121 |
1 files changed, 40 insertions, 81 deletions
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 7eb157a59f9e..ee371890d85d 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include "xfs_bmap.h" | 36 | #include "xfs_bmap.h" |
37 | #include "xfs_error.h" | 37 | #include "xfs_error.h" |
38 | #include "xfs_quota.h" | 38 | #include "xfs_quota.h" |
39 | #include "xfs_refcache.h" | ||
40 | #include "xfs_utils.h" | 39 | #include "xfs_utils.h" |
41 | #include "xfs_trans_space.h" | 40 | #include "xfs_trans_space.h" |
42 | #include "xfs_vnodeops.h" | 41 | #include "xfs_vnodeops.h" |
@@ -84,25 +83,23 @@ int xfs_rename_skip, xfs_rename_nskip; | |||
84 | */ | 83 | */ |
85 | STATIC int | 84 | STATIC int |
86 | xfs_lock_for_rename( | 85 | xfs_lock_for_rename( |
87 | xfs_inode_t *dp1, /* old (source) directory inode */ | 86 | xfs_inode_t *dp1, /* in: old (source) directory inode */ |
88 | xfs_inode_t *dp2, /* new (target) directory inode */ | 87 | xfs_inode_t *dp2, /* in: new (target) directory inode */ |
89 | bhv_vname_t *vname1,/* old entry name */ | 88 | xfs_inode_t *ip1, /* in: inode of old entry */ |
90 | bhv_vname_t *vname2,/* new entry name */ | 89 | struct xfs_name *name2, /* in: new entry name */ |
91 | xfs_inode_t **ipp1, /* inode of old entry */ | 90 | xfs_inode_t **ipp2, /* out: inode of new entry, if it |
92 | xfs_inode_t **ipp2, /* inode of new entry, if it | ||
93 | already exists, NULL otherwise. */ | 91 | already exists, NULL otherwise. */ |
94 | xfs_inode_t **i_tab,/* array of inode returned, sorted */ | 92 | xfs_inode_t **i_tab,/* out: array of inode returned, sorted */ |
95 | int *num_inodes) /* number of inodes in array */ | 93 | int *num_inodes) /* out: number of inodes in array */ |
96 | { | 94 | { |
97 | xfs_inode_t *ip1, *ip2, *temp; | 95 | xfs_inode_t *ip2 = NULL; |
96 | xfs_inode_t *temp; | ||
98 | xfs_ino_t inum1, inum2; | 97 | xfs_ino_t inum1, inum2; |
99 | int error; | 98 | int error; |
100 | int i, j; | 99 | int i, j; |
101 | uint lock_mode; | 100 | uint lock_mode; |
102 | int diff_dirs = (dp1 != dp2); | 101 | int diff_dirs = (dp1 != dp2); |
103 | 102 | ||
104 | ip2 = NULL; | ||
105 | |||
106 | /* | 103 | /* |
107 | * First, find out the current inums of the entries so that we | 104 | * First, find out the current inums of the entries so that we |
108 | * can determine the initial locking order. We'll have to | 105 | * can determine the initial locking order. We'll have to |
@@ -110,27 +107,20 @@ xfs_lock_for_rename( | |||
110 | * to see if we still have the right inodes, directories, etc. | 107 | * to see if we still have the right inodes, directories, etc. |
111 | */ | 108 | */ |
112 | lock_mode = xfs_ilock_map_shared(dp1); | 109 | lock_mode = xfs_ilock_map_shared(dp1); |
113 | error = xfs_get_dir_entry(vname1, &ip1); | 110 | IHOLD(ip1); |
114 | if (error) { | 111 | xfs_itrace_ref(ip1); |
115 | xfs_iunlock_map_shared(dp1, lock_mode); | ||
116 | return error; | ||
117 | } | ||
118 | 112 | ||
119 | inum1 = ip1->i_ino; | 113 | inum1 = ip1->i_ino; |
120 | 114 | ||
121 | ASSERT(ip1); | ||
122 | xfs_itrace_ref(ip1); | ||
123 | |||
124 | /* | 115 | /* |
125 | * Unlock dp1 and lock dp2 if they are different. | 116 | * Unlock dp1 and lock dp2 if they are different. |
126 | */ | 117 | */ |
127 | |||
128 | if (diff_dirs) { | 118 | if (diff_dirs) { |
129 | xfs_iunlock_map_shared(dp1, lock_mode); | 119 | xfs_iunlock_map_shared(dp1, lock_mode); |
130 | lock_mode = xfs_ilock_map_shared(dp2); | 120 | lock_mode = xfs_ilock_map_shared(dp2); |
131 | } | 121 | } |
132 | 122 | ||
133 | error = xfs_dir_lookup_int(dp2, lock_mode, vname2, &inum2, &ip2); | 123 | error = xfs_dir_lookup_int(dp2, lock_mode, name2, &inum2, &ip2); |
134 | if (error == ENOENT) { /* target does not need to exist. */ | 124 | if (error == ENOENT) { /* target does not need to exist. */ |
135 | inum2 = 0; | 125 | inum2 = 0; |
136 | } else if (error) { | 126 | } else if (error) { |
@@ -162,6 +152,7 @@ xfs_lock_for_rename( | |||
162 | *num_inodes = 4; | 152 | *num_inodes = 4; |
163 | i_tab[3] = ip2; | 153 | i_tab[3] = ip2; |
164 | } | 154 | } |
155 | *ipp2 = i_tab[3]; | ||
165 | 156 | ||
166 | /* | 157 | /* |
167 | * Sort the elements via bubble sort. (Remember, there are at | 158 | * Sort the elements via bubble sort. (Remember, there are at |
@@ -199,21 +190,6 @@ xfs_lock_for_rename( | |||
199 | xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); | 190 | xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); |
200 | } | 191 | } |
201 | 192 | ||
202 | /* | ||
203 | * Set the return value. Null out any unused entries in i_tab. | ||
204 | */ | ||
205 | *ipp1 = *ipp2 = NULL; | ||
206 | for (i=0; i < *num_inodes; i++) { | ||
207 | if (i_tab[i]->i_ino == inum1) { | ||
208 | *ipp1 = i_tab[i]; | ||
209 | } | ||
210 | if (i_tab[i]->i_ino == inum2) { | ||
211 | *ipp2 = i_tab[i]; | ||
212 | } | ||
213 | } | ||
214 | for (;i < 4; i++) { | ||
215 | i_tab[i] = NULL; | ||
216 | } | ||
217 | return 0; | 193 | return 0; |
218 | } | 194 | } |
219 | 195 | ||
@@ -223,13 +199,13 @@ xfs_lock_for_rename( | |||
223 | int | 199 | int |
224 | xfs_rename( | 200 | xfs_rename( |
225 | xfs_inode_t *src_dp, | 201 | xfs_inode_t *src_dp, |
226 | bhv_vname_t *src_vname, | 202 | struct xfs_name *src_name, |
227 | bhv_vnode_t *target_dir_vp, | 203 | xfs_inode_t *src_ip, |
228 | bhv_vname_t *target_vname) | 204 | xfs_inode_t *target_dp, |
205 | struct xfs_name *target_name) | ||
229 | { | 206 | { |
230 | bhv_vnode_t *src_dir_vp = XFS_ITOV(src_dp); | ||
231 | xfs_trans_t *tp; | 207 | xfs_trans_t *tp; |
232 | xfs_inode_t *target_dp, *src_ip, *target_ip; | 208 | xfs_inode_t *target_ip; |
233 | xfs_mount_t *mp = src_dp->i_mount; | 209 | xfs_mount_t *mp = src_dp->i_mount; |
234 | int new_parent; /* moving to a new dir */ | 210 | int new_parent; /* moving to a new dir */ |
235 | int src_is_directory; /* src_name is a directory */ | 211 | int src_is_directory; /* src_name is a directory */ |
@@ -243,29 +219,16 @@ xfs_rename( | |||
243 | int spaceres; | 219 | int spaceres; |
244 | int target_link_zero = 0; | 220 | int target_link_zero = 0; |
245 | int num_inodes; | 221 | int num_inodes; |
246 | char *src_name = VNAME(src_vname); | ||
247 | char *target_name = VNAME(target_vname); | ||
248 | int src_namelen = VNAMELEN(src_vname); | ||
249 | int target_namelen = VNAMELEN(target_vname); | ||
250 | 222 | ||
251 | xfs_itrace_entry(src_dp); | 223 | xfs_itrace_entry(src_dp); |
252 | xfs_itrace_entry(xfs_vtoi(target_dir_vp)); | 224 | xfs_itrace_entry(target_dp); |
253 | |||
254 | /* | ||
255 | * Find the XFS behavior descriptor for the target directory | ||
256 | * vnode since it was not handed to us. | ||
257 | */ | ||
258 | target_dp = xfs_vtoi(target_dir_vp); | ||
259 | if (target_dp == NULL) { | ||
260 | return XFS_ERROR(EXDEV); | ||
261 | } | ||
262 | 225 | ||
263 | if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) || | 226 | if (DM_EVENT_ENABLED(src_dp, DM_EVENT_RENAME) || |
264 | DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) { | 227 | DM_EVENT_ENABLED(target_dp, DM_EVENT_RENAME)) { |
265 | error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME, | 228 | error = XFS_SEND_NAMESP(mp, DM_EVENT_RENAME, |
266 | src_dir_vp, DM_RIGHT_NULL, | 229 | src_dp, DM_RIGHT_NULL, |
267 | target_dir_vp, DM_RIGHT_NULL, | 230 | target_dp, DM_RIGHT_NULL, |
268 | src_name, target_name, | 231 | src_name->name, target_name->name, |
269 | 0, 0, 0); | 232 | 0, 0, 0); |
270 | if (error) { | 233 | if (error) { |
271 | return error; | 234 | return error; |
@@ -282,10 +245,8 @@ xfs_rename( | |||
282 | * does not exist in the source directory. | 245 | * does not exist in the source directory. |
283 | */ | 246 | */ |
284 | tp = NULL; | 247 | tp = NULL; |
285 | error = xfs_lock_for_rename(src_dp, target_dp, src_vname, | 248 | error = xfs_lock_for_rename(src_dp, target_dp, src_ip, target_name, |
286 | target_vname, &src_ip, &target_ip, inodes, | 249 | &target_ip, inodes, &num_inodes); |
287 | &num_inodes); | ||
288 | |||
289 | if (error) { | 250 | if (error) { |
290 | /* | 251 | /* |
291 | * We have nothing locked, no inode references, and | 252 | * We have nothing locked, no inode references, and |
@@ -331,7 +292,7 @@ xfs_rename( | |||
331 | XFS_BMAP_INIT(&free_list, &first_block); | 292 | XFS_BMAP_INIT(&free_list, &first_block); |
332 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); | 293 | tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); |
333 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 294 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
334 | spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen); | 295 | spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); |
335 | error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0, | 296 | error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0, |
336 | XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); | 297 | XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); |
337 | if (error == ENOSPC) { | 298 | if (error == ENOSPC) { |
@@ -365,10 +326,10 @@ xfs_rename( | |||
365 | * them when they unlock the inodes. Also, we need to be careful | 326 | * them when they unlock the inodes. Also, we need to be careful |
366 | * not to add an inode to the transaction more than once. | 327 | * not to add an inode to the transaction more than once. |
367 | */ | 328 | */ |
368 | VN_HOLD(src_dir_vp); | 329 | IHOLD(src_dp); |
369 | xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); | 330 | xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); |
370 | if (new_parent) { | 331 | if (new_parent) { |
371 | VN_HOLD(target_dir_vp); | 332 | IHOLD(target_dp); |
372 | xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); | 333 | xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); |
373 | } | 334 | } |
374 | if ((src_ip != src_dp) && (src_ip != target_dp)) { | 335 | if ((src_ip != src_dp) && (src_ip != target_dp)) { |
@@ -389,9 +350,8 @@ xfs_rename( | |||
389 | * If there's no space reservation, check the entry will | 350 | * If there's no space reservation, check the entry will |
390 | * fit before actually inserting it. | 351 | * fit before actually inserting it. |
391 | */ | 352 | */ |
392 | if (spaceres == 0 && | 353 | error = xfs_dir_canenter(tp, target_dp, target_name, spaceres); |
393 | (error = xfs_dir_canenter(tp, target_dp, target_name, | 354 | if (error) |
394 | target_namelen))) | ||
395 | goto error_return; | 355 | goto error_return; |
396 | /* | 356 | /* |
397 | * If target does not exist and the rename crosses | 357 | * If target does not exist and the rename crosses |
@@ -399,8 +359,8 @@ xfs_rename( | |||
399 | * to account for the ".." reference from the new entry. | 359 | * to account for the ".." reference from the new entry. |
400 | */ | 360 | */ |
401 | error = xfs_dir_createname(tp, target_dp, target_name, | 361 | error = xfs_dir_createname(tp, target_dp, target_name, |
402 | target_namelen, src_ip->i_ino, | 362 | src_ip->i_ino, &first_block, |
403 | &first_block, &free_list, spaceres); | 363 | &free_list, spaceres); |
404 | if (error == ENOSPC) | 364 | if (error == ENOSPC) |
405 | goto error_return; | 365 | goto error_return; |
406 | if (error) | 366 | if (error) |
@@ -439,7 +399,7 @@ xfs_rename( | |||
439 | * name at the destination directory, remove it first. | 399 | * name at the destination directory, remove it first. |
440 | */ | 400 | */ |
441 | error = xfs_dir_replace(tp, target_dp, target_name, | 401 | error = xfs_dir_replace(tp, target_dp, target_name, |
442 | target_namelen, src_ip->i_ino, | 402 | src_ip->i_ino, |
443 | &first_block, &free_list, spaceres); | 403 | &first_block, &free_list, spaceres); |
444 | if (error) | 404 | if (error) |
445 | goto abort_return; | 405 | goto abort_return; |
@@ -476,7 +436,8 @@ xfs_rename( | |||
476 | * Rewrite the ".." entry to point to the new | 436 | * Rewrite the ".." entry to point to the new |
477 | * directory. | 437 | * directory. |
478 | */ | 438 | */ |
479 | error = xfs_dir_replace(tp, src_ip, "..", 2, target_dp->i_ino, | 439 | error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot, |
440 | target_dp->i_ino, | ||
480 | &first_block, &free_list, spaceres); | 441 | &first_block, &free_list, spaceres); |
481 | ASSERT(error != EEXIST); | 442 | ASSERT(error != EEXIST); |
482 | if (error) | 443 | if (error) |
@@ -512,8 +473,8 @@ xfs_rename( | |||
512 | goto abort_return; | 473 | goto abort_return; |
513 | } | 474 | } |
514 | 475 | ||
515 | error = xfs_dir_removename(tp, src_dp, src_name, src_namelen, | 476 | error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, |
516 | src_ip->i_ino, &first_block, &free_list, spaceres); | 477 | &first_block, &free_list, spaceres); |
517 | if (error) | 478 | if (error) |
518 | goto abort_return; | 479 | goto abort_return; |
519 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 480 | xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
@@ -580,10 +541,8 @@ xfs_rename( | |||
580 | * the vnode references. | 541 | * the vnode references. |
581 | */ | 542 | */ |
582 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 543 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
583 | if (target_ip != NULL) { | 544 | if (target_ip != NULL) |
584 | xfs_refcache_purge_ip(target_ip); | ||
585 | IRELE(target_ip); | 545 | IRELE(target_ip); |
586 | } | ||
587 | /* | 546 | /* |
588 | * Let interposed file systems know about removed links. | 547 | * Let interposed file systems know about removed links. |
589 | */ | 548 | */ |
@@ -598,9 +557,9 @@ std_return: | |||
598 | if (DM_EVENT_ENABLED(src_dp, DM_EVENT_POSTRENAME) || | 557 | if (DM_EVENT_ENABLED(src_dp, DM_EVENT_POSTRENAME) || |
599 | DM_EVENT_ENABLED(target_dp, DM_EVENT_POSTRENAME)) { | 558 | DM_EVENT_ENABLED(target_dp, DM_EVENT_POSTRENAME)) { |
600 | (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME, | 559 | (void) XFS_SEND_NAMESP (mp, DM_EVENT_POSTRENAME, |
601 | src_dir_vp, DM_RIGHT_NULL, | 560 | src_dp, DM_RIGHT_NULL, |
602 | target_dir_vp, DM_RIGHT_NULL, | 561 | target_dp, DM_RIGHT_NULL, |
603 | src_name, target_name, | 562 | src_name->name, target_name->name, |
604 | 0, error, 0); | 563 | 0, error, 0); |
605 | } | 564 | } |
606 | return error; | 565 | return error; |