Commit | Line | Data |
---|---|---|
86ffa471 DW |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (c) 2000-2006 Silicon Graphics, Inc. | |
4 | * All Rights Reserved. | |
5 | */ | |
6 | #include "xfs.h" | |
7 | #include "xfs_fs.h" | |
8 | #include "xfs_shared.h" | |
9 | #include "xfs_format.h" | |
10 | #include "xfs_log_format.h" | |
11 | #include "xfs_trans_resv.h" | |
12 | #include "xfs_mount.h" | |
13 | #include "xfs_inode.h" | |
14 | #include "xfs_trans.h" | |
15 | #include "xfs_inode_item.h" | |
16 | #include "xfs_trace.h" | |
17 | #include "xfs_trans_priv.h" | |
18 | #include "xfs_buf_item.h" | |
19 | #include "xfs_log.h" | |
20 | #include "xfs_error.h" | |
21 | #include "xfs_log_priv.h" | |
22 | #include "xfs_log_recover.h" | |
658fa68b DW |
23 | #include "xfs_icache.h" |
24 | #include "xfs_bmap_btree.h" | |
86ffa471 | 25 | |
8ea5682d DW |
26 | STATIC void |
27 | xlog_recover_inode_ra_pass2( | |
28 | struct xlog *log, | |
29 | struct xlog_recover_item *item) | |
30 | { | |
31 | if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) { | |
32 | struct xfs_inode_log_format *ilfp = item->ri_buf[0].i_addr; | |
33 | ||
34 | xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len, | |
35 | &xfs_inode_buf_ra_ops); | |
36 | } else { | |
37 | struct xfs_inode_log_format_32 *ilfp = item->ri_buf[0].i_addr; | |
38 | ||
39 | xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len, | |
40 | &xfs_inode_buf_ra_ops); | |
41 | } | |
42 | } | |
43 | ||
658fa68b DW |
44 | /* |
45 | * Inode fork owner changes | |
46 | * | |
47 | * If we have been told that we have to reparent the inode fork, it's because an | |
48 | * extent swap operation on a CRC enabled filesystem has been done and we are | |
49 | * replaying it. We need to walk the BMBT of the appropriate fork and change the | |
50 | * owners of it. | |
51 | * | |
52 | * The complexity here is that we don't have an inode context to work with, so | |
53 | * after we've replayed the inode we need to instantiate one. This is where the | |
54 | * fun begins. | |
55 | * | |
56 | * We are in the middle of log recovery, so we can't run transactions. That | |
57 | * means we cannot use cache coherent inode instantiation via xfs_iget(), as | |
58 | * that will result in the corresponding iput() running the inode through | |
59 | * xfs_inactive(). If we've just replayed an inode core that changes the link | |
60 | * count to zero (i.e. it's been unlinked), then xfs_inactive() will run | |
61 | * transactions (bad!). | |
62 | * | |
63 | * So, to avoid this, we instantiate an inode directly from the inode core we've | |
64 | * just recovered. We have the buffer still locked, and all we really need to | |
65 | * instantiate is the inode core and the forks being modified. We can do this | |
66 | * manually, then run the inode btree owner change, and then tear down the | |
67 | * xfs_inode without having to run any transactions at all. | |
68 | * | |
69 | * Also, because we don't have a transaction context available here but need to | |
70 | * gather all the buffers we modify for writeback so we pass the buffer_list | |
71 | * instead for the operation to use. | |
72 | */ | |
73 | ||
74 | STATIC int | |
75 | xfs_recover_inode_owner_change( | |
76 | struct xfs_mount *mp, | |
77 | struct xfs_dinode *dip, | |
78 | struct xfs_inode_log_format *in_f, | |
79 | struct list_head *buffer_list) | |
80 | { | |
81 | struct xfs_inode *ip; | |
82 | int error; | |
83 | ||
84 | ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)); | |
85 | ||
86 | ip = xfs_inode_alloc(mp, in_f->ilf_ino); | |
87 | if (!ip) | |
88 | return -ENOMEM; | |
89 | ||
90 | /* instantiate the inode */ | |
91 | ASSERT(dip->di_version >= 3); | |
658fa68b | 92 | |
cb7d5859 | 93 | error = xfs_inode_from_disk(ip, dip); |
658fa68b DW |
94 | if (error) |
95 | goto out_free_ip; | |
96 | ||
658fa68b DW |
97 | if (in_f->ilf_fields & XFS_ILOG_DOWNER) { |
98 | ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT); | |
99 | error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK, | |
100 | ip->i_ino, buffer_list); | |
101 | if (error) | |
102 | goto out_free_ip; | |
103 | } | |
104 | ||
105 | if (in_f->ilf_fields & XFS_ILOG_AOWNER) { | |
106 | ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT); | |
107 | error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK, | |
108 | ip->i_ino, buffer_list); | |
109 | if (error) | |
110 | goto out_free_ip; | |
111 | } | |
112 | ||
113 | out_free_ip: | |
114 | xfs_inode_free(ip); | |
115 | return error; | |
116 | } | |
117 | ||
f93e5436 DW |
118 | static inline bool xfs_log_dinode_has_bigtime(const struct xfs_log_dinode *ld) |
119 | { | |
120 | return ld->di_version >= 3 && | |
121 | (ld->di_flags2 & XFS_DIFLAG2_BIGTIME); | |
122 | } | |
123 | ||
5a0bb066 DW |
124 | /* Convert a log timestamp to an ondisk timestamp. */ |
125 | static inline xfs_timestamp_t | |
126 | xfs_log_dinode_to_disk_ts( | |
f93e5436 | 127 | struct xfs_log_dinode *from, |
6fc277c7 | 128 | const xfs_log_timestamp_t its) |
5a0bb066 DW |
129 | { |
130 | struct xfs_legacy_timestamp *lts; | |
732de7db | 131 | struct xfs_log_legacy_timestamp *lits; |
5a0bb066 DW |
132 | xfs_timestamp_t ts; |
133 | ||
f93e5436 DW |
134 | if (xfs_log_dinode_has_bigtime(from)) |
135 | return cpu_to_be64(its); | |
136 | ||
5a0bb066 | 137 | lts = (struct xfs_legacy_timestamp *)&ts; |
732de7db | 138 | lits = (struct xfs_log_legacy_timestamp *)&its; |
30e05599 DW |
139 | lts->t_sec = cpu_to_be32(lits->t_sec); |
140 | lts->t_nsec = cpu_to_be32(lits->t_nsec); | |
5a0bb066 DW |
141 | |
142 | return ts; | |
143 | } | |
144 | ||
9b7d16e3 CB |
145 | static inline bool xfs_log_dinode_has_large_extent_counts( |
146 | const struct xfs_log_dinode *ld) | |
147 | { | |
148 | return ld->di_version >= 3 && | |
149 | (ld->di_flags2 & XFS_DIFLAG2_NREXT64); | |
150 | } | |
151 | ||
52a4a148 CB |
152 | static inline void |
153 | xfs_log_dinode_to_disk_iext_counters( | |
154 | struct xfs_log_dinode *from, | |
155 | struct xfs_dinode *to) | |
156 | { | |
157 | if (xfs_log_dinode_has_large_extent_counts(from)) { | |
158 | to->di_big_nextents = cpu_to_be64(from->di_big_nextents); | |
159 | to->di_big_anextents = cpu_to_be32(from->di_big_anextents); | |
160 | to->di_nrext64_pad = cpu_to_be16(from->di_nrext64_pad); | |
161 | } else { | |
162 | to->di_nextents = cpu_to_be32(from->di_nextents); | |
163 | to->di_anextents = cpu_to_be16(from->di_anextents); | |
164 | } | |
165 | ||
166 | } | |
167 | ||
88947ea0 DW |
168 | STATIC void |
169 | xfs_log_dinode_to_disk( | |
170 | struct xfs_log_dinode *from, | |
32baa63d DC |
171 | struct xfs_dinode *to, |
172 | xfs_lsn_t lsn) | |
88947ea0 DW |
173 | { |
174 | to->di_magic = cpu_to_be16(from->di_magic); | |
175 | to->di_mode = cpu_to_be16(from->di_mode); | |
176 | to->di_version = from->di_version; | |
177 | to->di_format = from->di_format; | |
178 | to->di_onlink = 0; | |
179 | to->di_uid = cpu_to_be32(from->di_uid); | |
180 | to->di_gid = cpu_to_be32(from->di_gid); | |
181 | to->di_nlink = cpu_to_be32(from->di_nlink); | |
182 | to->di_projid_lo = cpu_to_be16(from->di_projid_lo); | |
183 | to->di_projid_hi = cpu_to_be16(from->di_projid_hi); | |
88947ea0 | 184 | |
f93e5436 DW |
185 | to->di_atime = xfs_log_dinode_to_disk_ts(from, from->di_atime); |
186 | to->di_mtime = xfs_log_dinode_to_disk_ts(from, from->di_mtime); | |
187 | to->di_ctime = xfs_log_dinode_to_disk_ts(from, from->di_ctime); | |
88947ea0 DW |
188 | |
189 | to->di_size = cpu_to_be64(from->di_size); | |
190 | to->di_nblocks = cpu_to_be64(from->di_nblocks); | |
191 | to->di_extsize = cpu_to_be32(from->di_extsize); | |
88947ea0 DW |
192 | to->di_forkoff = from->di_forkoff; |
193 | to->di_aformat = from->di_aformat; | |
194 | to->di_dmevmask = cpu_to_be32(from->di_dmevmask); | |
195 | to->di_dmstate = cpu_to_be16(from->di_dmstate); | |
196 | to->di_flags = cpu_to_be16(from->di_flags); | |
197 | to->di_gen = cpu_to_be32(from->di_gen); | |
198 | ||
199 | if (from->di_version == 3) { | |
200 | to->di_changecount = cpu_to_be64(from->di_changecount); | |
f93e5436 DW |
201 | to->di_crtime = xfs_log_dinode_to_disk_ts(from, |
202 | from->di_crtime); | |
88947ea0 DW |
203 | to->di_flags2 = cpu_to_be64(from->di_flags2); |
204 | to->di_cowextsize = cpu_to_be32(from->di_cowextsize); | |
205 | to->di_ino = cpu_to_be64(from->di_ino); | |
32baa63d | 206 | to->di_lsn = cpu_to_be64(lsn); |
52a4a148 | 207 | memset(to->di_pad2, 0, sizeof(to->di_pad2)); |
88947ea0 | 208 | uuid_copy(&to->di_uuid, &from->di_uuid); |
52a4a148 | 209 | to->di_v3_pad = 0; |
88947ea0 DW |
210 | } else { |
211 | to->di_flushiter = cpu_to_be16(from->di_flushiter); | |
52a4a148 CB |
212 | memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad)); |
213 | } | |
214 | ||
215 | xfs_log_dinode_to_disk_iext_counters(from, to); | |
216 | } | |
217 | ||
218 | STATIC int | |
219 | xlog_dinode_verify_extent_counts( | |
220 | struct xfs_mount *mp, | |
221 | struct xfs_log_dinode *ldip) | |
222 | { | |
223 | xfs_extnum_t nextents; | |
224 | xfs_aextnum_t anextents; | |
225 | ||
226 | if (xfs_log_dinode_has_large_extent_counts(ldip)) { | |
227 | if (!xfs_has_large_extent_counts(mp) || | |
228 | (ldip->di_nrext64_pad != 0)) { | |
229 | XFS_CORRUPTION_ERROR( | |
230 | "Bad log dinode large extent count format", | |
231 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
232 | xfs_alert(mp, | |
233 | "Bad inode 0x%llx, large extent counts %d, padding 0x%x", | |
234 | ldip->di_ino, xfs_has_large_extent_counts(mp), | |
235 | ldip->di_nrext64_pad); | |
236 | return -EFSCORRUPTED; | |
237 | } | |
238 | ||
239 | nextents = ldip->di_big_nextents; | |
240 | anextents = ldip->di_big_anextents; | |
241 | } else { | |
242 | if (ldip->di_version == 3 && ldip->di_v3_pad != 0) { | |
243 | XFS_CORRUPTION_ERROR( | |
244 | "Bad log dinode di_v3_pad", | |
245 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
246 | xfs_alert(mp, | |
247 | "Bad inode 0x%llx, di_v3_pad 0x%llx", | |
248 | ldip->di_ino, ldip->di_v3_pad); | |
249 | return -EFSCORRUPTED; | |
250 | } | |
251 | ||
252 | nextents = ldip->di_nextents; | |
253 | anextents = ldip->di_anextents; | |
254 | } | |
255 | ||
256 | if (unlikely(nextents + anextents > ldip->di_nblocks)) { | |
257 | XFS_CORRUPTION_ERROR("Bad log dinode extent counts", | |
258 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
259 | xfs_alert(mp, | |
260 | "Bad inode 0x%llx, large extent counts %d, nextents 0x%llx, anextents 0x%x, nblocks 0x%llx", | |
261 | ldip->di_ino, xfs_has_large_extent_counts(mp), nextents, | |
262 | anextents, ldip->di_nblocks); | |
263 | return -EFSCORRUPTED; | |
88947ea0 | 264 | } |
52a4a148 CB |
265 | |
266 | return 0; | |
88947ea0 DW |
267 | } |
268 | ||
658fa68b DW |
269 | STATIC int |
270 | xlog_recover_inode_commit_pass2( | |
271 | struct xlog *log, | |
272 | struct list_head *buffer_list, | |
273 | struct xlog_recover_item *item, | |
274 | xfs_lsn_t current_lsn) | |
275 | { | |
276 | struct xfs_inode_log_format *in_f; | |
277 | struct xfs_mount *mp = log->l_mp; | |
278 | struct xfs_buf *bp; | |
279 | struct xfs_dinode *dip; | |
280 | int len; | |
281 | char *src; | |
282 | char *dest; | |
283 | int error; | |
284 | int attr_index; | |
285 | uint fields; | |
286 | struct xfs_log_dinode *ldip; | |
287 | uint isize; | |
288 | int need_free = 0; | |
289 | ||
290 | if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) { | |
291 | in_f = item->ri_buf[0].i_addr; | |
292 | } else { | |
293 | in_f = kmem_alloc(sizeof(struct xfs_inode_log_format), 0); | |
294 | need_free = 1; | |
295 | error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f); | |
296 | if (error) | |
297 | goto error; | |
298 | } | |
299 | ||
300 | /* | |
301 | * Inode buffers can be freed, look out for it, | |
302 | * and do not replay the inode. | |
303 | */ | |
304 | if (xlog_is_buffer_cancelled(log, in_f->ilf_blkno, in_f->ilf_len)) { | |
305 | error = 0; | |
306 | trace_xfs_log_recover_inode_cancel(log, in_f); | |
307 | goto error; | |
308 | } | |
309 | trace_xfs_log_recover_inode_recover(log, in_f); | |
310 | ||
311 | error = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, | |
312 | 0, &bp, &xfs_inode_buf_ops); | |
313 | if (error) | |
314 | goto error; | |
315 | ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); | |
316 | dip = xfs_buf_offset(bp, in_f->ilf_boffset); | |
317 | ||
318 | /* | |
319 | * Make sure the place we're flushing out to really looks | |
320 | * like an inode! | |
321 | */ | |
322 | if (XFS_IS_CORRUPT(mp, !xfs_verify_magic16(bp, dip->di_magic))) { | |
323 | xfs_alert(mp, | |
78b0f58b | 324 | "%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %lld", |
658fa68b DW |
325 | __func__, dip, bp, in_f->ilf_ino); |
326 | error = -EFSCORRUPTED; | |
327 | goto out_release; | |
328 | } | |
329 | ldip = item->ri_buf[1].i_addr; | |
330 | if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) { | |
331 | xfs_alert(mp, | |
78b0f58b | 332 | "%s: Bad inode log record, rec ptr "PTR_FMT", ino %lld", |
658fa68b DW |
333 | __func__, item, in_f->ilf_ino); |
334 | error = -EFSCORRUPTED; | |
335 | goto out_release; | |
336 | } | |
337 | ||
338 | /* | |
32baa63d DC |
339 | * If the inode has an LSN in it, recover the inode only if the on-disk |
340 | * inode's LSN is older than the lsn of the transaction we are | |
341 | * replaying. We can have multiple checkpoints with the same start LSN, | |
342 | * so the current LSN being equal to the on-disk LSN doesn't necessarily | |
343 | * mean that the on-disk inode is more recent than the change being | |
344 | * replayed. | |
345 | * | |
346 | * We must check the current_lsn against the on-disk inode | |
347 | * here because the we can't trust the log dinode to contain a valid LSN | |
348 | * (see comment below before replaying the log dinode for details). | |
349 | * | |
350 | * Note: we still need to replay an owner change even though the inode | |
351 | * is more recent than the transaction as there is no guarantee that all | |
352 | * the btree blocks are more recent than this transaction, too. | |
658fa68b DW |
353 | */ |
354 | if (dip->di_version >= 3) { | |
355 | xfs_lsn_t lsn = be64_to_cpu(dip->di_lsn); | |
356 | ||
32baa63d | 357 | if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) > 0) { |
658fa68b DW |
358 | trace_xfs_log_recover_inode_skip(log, in_f); |
359 | error = 0; | |
360 | goto out_owner_change; | |
361 | } | |
362 | } | |
363 | ||
364 | /* | |
365 | * di_flushiter is only valid for v1/2 inodes. All changes for v3 inodes | |
366 | * are transactional and if ordering is necessary we can determine that | |
367 | * more accurately by the LSN field in the V3 inode core. Don't trust | |
368 | * the inode versions we might be changing them here - use the | |
369 | * superblock flag to determine whether we need to look at di_flushiter | |
370 | * to skip replay when the on disk inode is newer than the log one | |
371 | */ | |
38c26bfd | 372 | if (!xfs_has_v3inodes(mp) && |
658fa68b DW |
373 | ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) { |
374 | /* | |
375 | * Deal with the wrap case, DI_MAX_FLUSH is less | |
376 | * than smaller numbers | |
377 | */ | |
378 | if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH && | |
379 | ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) { | |
380 | /* do nothing */ | |
381 | } else { | |
382 | trace_xfs_log_recover_inode_skip(log, in_f); | |
383 | error = 0; | |
384 | goto out_release; | |
385 | } | |
386 | } | |
387 | ||
388 | /* Take the opportunity to reset the flush iteration count */ | |
389 | ldip->di_flushiter = 0; | |
390 | ||
391 | if (unlikely(S_ISREG(ldip->di_mode))) { | |
392 | if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) && | |
393 | (ldip->di_format != XFS_DINODE_FMT_BTREE)) { | |
8314bca0 CB |
394 | XFS_CORRUPTION_ERROR( |
395 | "Bad log dinode data fork format for regular file", | |
396 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
658fa68b | 397 | xfs_alert(mp, |
8314bca0 CB |
398 | "Bad inode 0x%llx, data fork format 0x%x", |
399 | in_f->ilf_ino, ldip->di_format); | |
658fa68b DW |
400 | error = -EFSCORRUPTED; |
401 | goto out_release; | |
402 | } | |
403 | } else if (unlikely(S_ISDIR(ldip->di_mode))) { | |
404 | if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) && | |
405 | (ldip->di_format != XFS_DINODE_FMT_BTREE) && | |
406 | (ldip->di_format != XFS_DINODE_FMT_LOCAL)) { | |
8314bca0 CB |
407 | XFS_CORRUPTION_ERROR( |
408 | "Bad log dinode data fork format for directory", | |
409 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
658fa68b | 410 | xfs_alert(mp, |
8314bca0 CB |
411 | "Bad inode 0x%llx, data fork format 0x%x", |
412 | in_f->ilf_ino, ldip->di_format); | |
658fa68b DW |
413 | error = -EFSCORRUPTED; |
414 | goto out_release; | |
415 | } | |
416 | } | |
52a4a148 CB |
417 | |
418 | error = xlog_dinode_verify_extent_counts(mp, ldip); | |
419 | if (error) | |
658fa68b | 420 | goto out_release; |
52a4a148 | 421 | |
658fa68b | 422 | if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) { |
8314bca0 CB |
423 | XFS_CORRUPTION_ERROR("Bad log dinode fork offset", |
424 | XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip)); | |
658fa68b | 425 | xfs_alert(mp, |
8314bca0 CB |
426 | "Bad inode 0x%llx, di_forkoff 0x%x", |
427 | in_f->ilf_ino, ldip->di_forkoff); | |
658fa68b DW |
428 | error = -EFSCORRUPTED; |
429 | goto out_release; | |
430 | } | |
431 | isize = xfs_log_dinode_size(mp); | |
432 | if (unlikely(item->ri_buf[1].i_len > isize)) { | |
8314bca0 CB |
433 | XFS_CORRUPTION_ERROR("Bad log dinode size", XFS_ERRLEVEL_LOW, |
434 | mp, ldip, sizeof(*ldip)); | |
658fa68b | 435 | xfs_alert(mp, |
8314bca0 CB |
436 | "Bad inode 0x%llx log dinode size 0x%x", |
437 | in_f->ilf_ino, item->ri_buf[1].i_len); | |
658fa68b DW |
438 | error = -EFSCORRUPTED; |
439 | goto out_release; | |
440 | } | |
441 | ||
32baa63d DC |
442 | /* |
443 | * Recover the log dinode inode into the on disk inode. | |
444 | * | |
445 | * The LSN in the log dinode is garbage - it can be zero or reflect | |
446 | * stale in-memory runtime state that isn't coherent with the changes | |
447 | * logged in this transaction or the changes written to the on-disk | |
448 | * inode. Hence we write the current lSN into the inode because that | |
449 | * matches what xfs_iflush() would write inode the inode when flushing | |
450 | * the changes in this transaction. | |
451 | */ | |
452 | xfs_log_dinode_to_disk(ldip, dip, current_lsn); | |
658fa68b DW |
453 | |
454 | fields = in_f->ilf_fields; | |
455 | if (fields & XFS_ILOG_DEV) | |
456 | xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev); | |
457 | ||
458 | if (in_f->ilf_size == 2) | |
459 | goto out_owner_change; | |
460 | len = item->ri_buf[2].i_len; | |
461 | src = item->ri_buf[2].i_addr; | |
462 | ASSERT(in_f->ilf_size <= 4); | |
463 | ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK)); | |
464 | ASSERT(!(fields & XFS_ILOG_DFORK) || | |
b2c28035 | 465 | (len == xlog_calc_iovec_len(in_f->ilf_dsize))); |
658fa68b DW |
466 | |
467 | switch (fields & XFS_ILOG_DFORK) { | |
468 | case XFS_ILOG_DDATA: | |
469 | case XFS_ILOG_DEXT: | |
470 | memcpy(XFS_DFORK_DPTR(dip), src, len); | |
471 | break; | |
472 | ||
473 | case XFS_ILOG_DBROOT: | |
474 | xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, len, | |
475 | (struct xfs_bmdr_block *)XFS_DFORK_DPTR(dip), | |
476 | XFS_DFORK_DSIZE(dip, mp)); | |
477 | break; | |
478 | ||
479 | default: | |
480 | /* | |
481 | * There are no data fork flags set. | |
482 | */ | |
483 | ASSERT((fields & XFS_ILOG_DFORK) == 0); | |
484 | break; | |
485 | } | |
486 | ||
487 | /* | |
488 | * If we logged any attribute data, recover it. There may or | |
489 | * may not have been any other non-core data logged in this | |
490 | * transaction. | |
491 | */ | |
492 | if (in_f->ilf_fields & XFS_ILOG_AFORK) { | |
493 | if (in_f->ilf_fields & XFS_ILOG_DFORK) { | |
494 | attr_index = 3; | |
495 | } else { | |
496 | attr_index = 2; | |
497 | } | |
498 | len = item->ri_buf[attr_index].i_len; | |
499 | src = item->ri_buf[attr_index].i_addr; | |
b2c28035 | 500 | ASSERT(len == xlog_calc_iovec_len(in_f->ilf_asize)); |
658fa68b DW |
501 | |
502 | switch (in_f->ilf_fields & XFS_ILOG_AFORK) { | |
503 | case XFS_ILOG_ADATA: | |
504 | case XFS_ILOG_AEXT: | |
505 | dest = XFS_DFORK_APTR(dip); | |
506 | ASSERT(len <= XFS_DFORK_ASIZE(dip, mp)); | |
507 | memcpy(dest, src, len); | |
508 | break; | |
509 | ||
510 | case XFS_ILOG_ABROOT: | |
511 | dest = XFS_DFORK_APTR(dip); | |
512 | xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, | |
513 | len, (struct xfs_bmdr_block *)dest, | |
514 | XFS_DFORK_ASIZE(dip, mp)); | |
515 | break; | |
516 | ||
517 | default: | |
518 | xfs_warn(log->l_mp, "%s: Invalid flag", __func__); | |
519 | ASSERT(0); | |
520 | error = -EFSCORRUPTED; | |
521 | goto out_release; | |
522 | } | |
523 | } | |
524 | ||
525 | out_owner_change: | |
526 | /* Recover the swapext owner change unless inode has been deleted */ | |
527 | if ((in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) && | |
528 | (dip->di_mode != 0)) | |
529 | error = xfs_recover_inode_owner_change(mp, dip, in_f, | |
530 | buffer_list); | |
531 | /* re-generate the checksum. */ | |
532 | xfs_dinode_calc_crc(log->l_mp, dip); | |
533 | ||
534 | ASSERT(bp->b_mount == mp); | |
9fe5c77c | 535 | bp->b_flags |= _XBF_LOGRECOVERY; |
658fa68b DW |
536 | xfs_buf_delwri_queue(bp, buffer_list); |
537 | ||
538 | out_release: | |
539 | xfs_buf_relse(bp); | |
540 | error: | |
541 | if (need_free) | |
542 | kmem_free(in_f); | |
543 | return error; | |
544 | } | |
545 | ||
86ffa471 DW |
546 | const struct xlog_recover_item_ops xlog_inode_item_ops = { |
547 | .item_type = XFS_LI_INODE, | |
8ea5682d | 548 | .ra_pass2 = xlog_recover_inode_ra_pass2, |
658fa68b | 549 | .commit_pass2 = xlog_recover_inode_commit_pass2, |
86ffa471 | 550 | }; |