1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
44
45STATIC void
46xfs_sort_for_rename(
47 xfs_inode_t *dp1,
48 xfs_inode_t *dp2,
49 xfs_inode_t *ip1,
50 xfs_inode_t *ip2,
51
52 xfs_inode_t **i_tab,
53 int *num_inodes)
54{
55 xfs_inode_t *temp;
56 int i, j;
57
58
59
60
61
62
63
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
78
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
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;
106 int src_is_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 = S_ISDIR(src_ip->i_d.di_mode);
120
121 if (src_is_directory) {
122
123
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
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
162
163
164
165
166 xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
167
168
169
170
171
172
173 xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
174 if (new_parent)
175 xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
176 xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
177 if (target_ip)
178 xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
179
180
181
182
183
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
193
194 if (target_ip == NULL) {
195
196
197
198
199 error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
200 if (error)
201 goto error_return;
202
203
204
205
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 {
224
225
226
227
228
229 if (S_ISDIR(target_ip->i_d.di_mode)) {
230
231
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
242
243
244
245
246
247
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
260
261
262 error = xfs_droplink(tp, target_ip);
263 if (error)
264 goto abort_return;
265
266 if (src_is_directory) {
267
268
269
270 error = xfs_droplink(tp, target_ip);
271 if (error)
272 goto abort_return;
273 }
274 }
275
276
277
278
279 if (new_parent && src_is_directory) {
280
281
282
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
294
295
296
297
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
304
305
306
307 if (src_is_directory && (new_parent || target_ip != NULL)) {
308
309
310
311
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
330
331
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
347
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}
359