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