0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_mount.h"
0013 #include "xfs_inode.h"
0014 #include "xfs_trans.h"
0015 #include "xfs_inode_item.h"
0016 #include "xfs_trace.h"
0017 #include "xfs_trans_priv.h"
0018 #include "xfs_buf_item.h"
0019 #include "xfs_log.h"
0020 #include "xfs_error.h"
0021 #include "xfs_log_priv.h"
0022 #include "xfs_log_recover.h"
0023 #include "xfs_icache.h"
0024 #include "xfs_bmap_btree.h"
0025
0026 STATIC void
0027 xlog_recover_inode_ra_pass2(
0028 struct xlog *log,
0029 struct xlog_recover_item *item)
0030 {
0031 if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
0032 struct xfs_inode_log_format *ilfp = item->ri_buf[0].i_addr;
0033
0034 xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
0035 &xfs_inode_buf_ra_ops);
0036 } else {
0037 struct xfs_inode_log_format_32 *ilfp = item->ri_buf[0].i_addr;
0038
0039 xlog_buf_readahead(log, ilfp->ilf_blkno, ilfp->ilf_len,
0040 &xfs_inode_buf_ra_ops);
0041 }
0042 }
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 STATIC int
0075 xfs_recover_inode_owner_change(
0076 struct xfs_mount *mp,
0077 struct xfs_dinode *dip,
0078 struct xfs_inode_log_format *in_f,
0079 struct list_head *buffer_list)
0080 {
0081 struct xfs_inode *ip;
0082 int error;
0083
0084 ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER));
0085
0086 ip = xfs_inode_alloc(mp, in_f->ilf_ino);
0087 if (!ip)
0088 return -ENOMEM;
0089
0090
0091 ASSERT(dip->di_version >= 3);
0092
0093 error = xfs_inode_from_disk(ip, dip);
0094 if (error)
0095 goto out_free_ip;
0096
0097 if (in_f->ilf_fields & XFS_ILOG_DOWNER) {
0098 ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT);
0099 error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK,
0100 ip->i_ino, buffer_list);
0101 if (error)
0102 goto out_free_ip;
0103 }
0104
0105 if (in_f->ilf_fields & XFS_ILOG_AOWNER) {
0106 ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT);
0107 error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK,
0108 ip->i_ino, buffer_list);
0109 if (error)
0110 goto out_free_ip;
0111 }
0112
0113 out_free_ip:
0114 xfs_inode_free(ip);
0115 return error;
0116 }
0117
0118 static inline bool xfs_log_dinode_has_bigtime(const struct xfs_log_dinode *ld)
0119 {
0120 return ld->di_version >= 3 &&
0121 (ld->di_flags2 & XFS_DIFLAG2_BIGTIME);
0122 }
0123
0124
0125 static inline xfs_timestamp_t
0126 xfs_log_dinode_to_disk_ts(
0127 struct xfs_log_dinode *from,
0128 const xfs_log_timestamp_t its)
0129 {
0130 struct xfs_legacy_timestamp *lts;
0131 struct xfs_log_legacy_timestamp *lits;
0132 xfs_timestamp_t ts;
0133
0134 if (xfs_log_dinode_has_bigtime(from))
0135 return cpu_to_be64(its);
0136
0137 lts = (struct xfs_legacy_timestamp *)&ts;
0138 lits = (struct xfs_log_legacy_timestamp *)&its;
0139 lts->t_sec = cpu_to_be32(lits->t_sec);
0140 lts->t_nsec = cpu_to_be32(lits->t_nsec);
0141
0142 return ts;
0143 }
0144
0145 static inline bool xfs_log_dinode_has_large_extent_counts(
0146 const struct xfs_log_dinode *ld)
0147 {
0148 return ld->di_version >= 3 &&
0149 (ld->di_flags2 & XFS_DIFLAG2_NREXT64);
0150 }
0151
0152 static inline void
0153 xfs_log_dinode_to_disk_iext_counters(
0154 struct xfs_log_dinode *from,
0155 struct xfs_dinode *to)
0156 {
0157 if (xfs_log_dinode_has_large_extent_counts(from)) {
0158 to->di_big_nextents = cpu_to_be64(from->di_big_nextents);
0159 to->di_big_anextents = cpu_to_be32(from->di_big_anextents);
0160 to->di_nrext64_pad = cpu_to_be16(from->di_nrext64_pad);
0161 } else {
0162 to->di_nextents = cpu_to_be32(from->di_nextents);
0163 to->di_anextents = cpu_to_be16(from->di_anextents);
0164 }
0165
0166 }
0167
0168 STATIC void
0169 xfs_log_dinode_to_disk(
0170 struct xfs_log_dinode *from,
0171 struct xfs_dinode *to,
0172 xfs_lsn_t lsn)
0173 {
0174 to->di_magic = cpu_to_be16(from->di_magic);
0175 to->di_mode = cpu_to_be16(from->di_mode);
0176 to->di_version = from->di_version;
0177 to->di_format = from->di_format;
0178 to->di_onlink = 0;
0179 to->di_uid = cpu_to_be32(from->di_uid);
0180 to->di_gid = cpu_to_be32(from->di_gid);
0181 to->di_nlink = cpu_to_be32(from->di_nlink);
0182 to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
0183 to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
0184
0185 to->di_atime = xfs_log_dinode_to_disk_ts(from, from->di_atime);
0186 to->di_mtime = xfs_log_dinode_to_disk_ts(from, from->di_mtime);
0187 to->di_ctime = xfs_log_dinode_to_disk_ts(from, from->di_ctime);
0188
0189 to->di_size = cpu_to_be64(from->di_size);
0190 to->di_nblocks = cpu_to_be64(from->di_nblocks);
0191 to->di_extsize = cpu_to_be32(from->di_extsize);
0192 to->di_forkoff = from->di_forkoff;
0193 to->di_aformat = from->di_aformat;
0194 to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
0195 to->di_dmstate = cpu_to_be16(from->di_dmstate);
0196 to->di_flags = cpu_to_be16(from->di_flags);
0197 to->di_gen = cpu_to_be32(from->di_gen);
0198
0199 if (from->di_version == 3) {
0200 to->di_changecount = cpu_to_be64(from->di_changecount);
0201 to->di_crtime = xfs_log_dinode_to_disk_ts(from,
0202 from->di_crtime);
0203 to->di_flags2 = cpu_to_be64(from->di_flags2);
0204 to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
0205 to->di_ino = cpu_to_be64(from->di_ino);
0206 to->di_lsn = cpu_to_be64(lsn);
0207 memset(to->di_pad2, 0, sizeof(to->di_pad2));
0208 uuid_copy(&to->di_uuid, &from->di_uuid);
0209 to->di_v3_pad = 0;
0210 } else {
0211 to->di_flushiter = cpu_to_be16(from->di_flushiter);
0212 memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
0213 }
0214
0215 xfs_log_dinode_to_disk_iext_counters(from, to);
0216 }
0217
0218 STATIC int
0219 xlog_dinode_verify_extent_counts(
0220 struct xfs_mount *mp,
0221 struct xfs_log_dinode *ldip)
0222 {
0223 xfs_extnum_t nextents;
0224 xfs_aextnum_t anextents;
0225
0226 if (xfs_log_dinode_has_large_extent_counts(ldip)) {
0227 if (!xfs_has_large_extent_counts(mp) ||
0228 (ldip->di_nrext64_pad != 0)) {
0229 XFS_CORRUPTION_ERROR(
0230 "Bad log dinode large extent count format",
0231 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0232 xfs_alert(mp,
0233 "Bad inode 0x%llx, large extent counts %d, padding 0x%x",
0234 ldip->di_ino, xfs_has_large_extent_counts(mp),
0235 ldip->di_nrext64_pad);
0236 return -EFSCORRUPTED;
0237 }
0238
0239 nextents = ldip->di_big_nextents;
0240 anextents = ldip->di_big_anextents;
0241 } else {
0242 if (ldip->di_version == 3 && ldip->di_v3_pad != 0) {
0243 XFS_CORRUPTION_ERROR(
0244 "Bad log dinode di_v3_pad",
0245 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0246 xfs_alert(mp,
0247 "Bad inode 0x%llx, di_v3_pad 0x%llx",
0248 ldip->di_ino, ldip->di_v3_pad);
0249 return -EFSCORRUPTED;
0250 }
0251
0252 nextents = ldip->di_nextents;
0253 anextents = ldip->di_anextents;
0254 }
0255
0256 if (unlikely(nextents + anextents > ldip->di_nblocks)) {
0257 XFS_CORRUPTION_ERROR("Bad log dinode extent counts",
0258 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0259 xfs_alert(mp,
0260 "Bad inode 0x%llx, large extent counts %d, nextents 0x%llx, anextents 0x%x, nblocks 0x%llx",
0261 ldip->di_ino, xfs_has_large_extent_counts(mp), nextents,
0262 anextents, ldip->di_nblocks);
0263 return -EFSCORRUPTED;
0264 }
0265
0266 return 0;
0267 }
0268
0269 STATIC int
0270 xlog_recover_inode_commit_pass2(
0271 struct xlog *log,
0272 struct list_head *buffer_list,
0273 struct xlog_recover_item *item,
0274 xfs_lsn_t current_lsn)
0275 {
0276 struct xfs_inode_log_format *in_f;
0277 struct xfs_mount *mp = log->l_mp;
0278 struct xfs_buf *bp;
0279 struct xfs_dinode *dip;
0280 int len;
0281 char *src;
0282 char *dest;
0283 int error;
0284 int attr_index;
0285 uint fields;
0286 struct xfs_log_dinode *ldip;
0287 uint isize;
0288 int need_free = 0;
0289
0290 if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
0291 in_f = item->ri_buf[0].i_addr;
0292 } else {
0293 in_f = kmem_alloc(sizeof(struct xfs_inode_log_format), 0);
0294 need_free = 1;
0295 error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f);
0296 if (error)
0297 goto error;
0298 }
0299
0300
0301
0302
0303
0304 if (xlog_is_buffer_cancelled(log, in_f->ilf_blkno, in_f->ilf_len)) {
0305 error = 0;
0306 trace_xfs_log_recover_inode_cancel(log, in_f);
0307 goto error;
0308 }
0309 trace_xfs_log_recover_inode_recover(log, in_f);
0310
0311 error = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
0312 0, &bp, &xfs_inode_buf_ops);
0313 if (error)
0314 goto error;
0315 ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
0316 dip = xfs_buf_offset(bp, in_f->ilf_boffset);
0317
0318
0319
0320
0321
0322 if (XFS_IS_CORRUPT(mp, !xfs_verify_magic16(bp, dip->di_magic))) {
0323 xfs_alert(mp,
0324 "%s: Bad inode magic number, dip = "PTR_FMT", dino bp = "PTR_FMT", ino = %Ld",
0325 __func__, dip, bp, in_f->ilf_ino);
0326 error = -EFSCORRUPTED;
0327 goto out_release;
0328 }
0329 ldip = item->ri_buf[1].i_addr;
0330 if (XFS_IS_CORRUPT(mp, ldip->di_magic != XFS_DINODE_MAGIC)) {
0331 xfs_alert(mp,
0332 "%s: Bad inode log record, rec ptr "PTR_FMT", ino %Ld",
0333 __func__, item, in_f->ilf_ino);
0334 error = -EFSCORRUPTED;
0335 goto out_release;
0336 }
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354 if (dip->di_version >= 3) {
0355 xfs_lsn_t lsn = be64_to_cpu(dip->di_lsn);
0356
0357 if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) > 0) {
0358 trace_xfs_log_recover_inode_skip(log, in_f);
0359 error = 0;
0360 goto out_owner_change;
0361 }
0362 }
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372 if (!xfs_has_v3inodes(mp) &&
0373 ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) {
0374
0375
0376
0377
0378 if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH &&
0379 ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) {
0380
0381 } else {
0382 trace_xfs_log_recover_inode_skip(log, in_f);
0383 error = 0;
0384 goto out_release;
0385 }
0386 }
0387
0388
0389 ldip->di_flushiter = 0;
0390
0391 if (unlikely(S_ISREG(ldip->di_mode))) {
0392 if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
0393 (ldip->di_format != XFS_DINODE_FMT_BTREE)) {
0394 XFS_CORRUPTION_ERROR(
0395 "Bad log dinode data fork format for regular file",
0396 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0397 xfs_alert(mp,
0398 "Bad inode 0x%llx, data fork format 0x%x",
0399 in_f->ilf_ino, ldip->di_format);
0400 error = -EFSCORRUPTED;
0401 goto out_release;
0402 }
0403 } else if (unlikely(S_ISDIR(ldip->di_mode))) {
0404 if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) &&
0405 (ldip->di_format != XFS_DINODE_FMT_BTREE) &&
0406 (ldip->di_format != XFS_DINODE_FMT_LOCAL)) {
0407 XFS_CORRUPTION_ERROR(
0408 "Bad log dinode data fork format for directory",
0409 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0410 xfs_alert(mp,
0411 "Bad inode 0x%llx, data fork format 0x%x",
0412 in_f->ilf_ino, ldip->di_format);
0413 error = -EFSCORRUPTED;
0414 goto out_release;
0415 }
0416 }
0417
0418 error = xlog_dinode_verify_extent_counts(mp, ldip);
0419 if (error)
0420 goto out_release;
0421
0422 if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) {
0423 XFS_CORRUPTION_ERROR("Bad log dinode fork offset",
0424 XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
0425 xfs_alert(mp,
0426 "Bad inode 0x%llx, di_forkoff 0x%x",
0427 in_f->ilf_ino, ldip->di_forkoff);
0428 error = -EFSCORRUPTED;
0429 goto out_release;
0430 }
0431 isize = xfs_log_dinode_size(mp);
0432 if (unlikely(item->ri_buf[1].i_len > isize)) {
0433 XFS_CORRUPTION_ERROR("Bad log dinode size", XFS_ERRLEVEL_LOW,
0434 mp, ldip, sizeof(*ldip));
0435 xfs_alert(mp,
0436 "Bad inode 0x%llx log dinode size 0x%x",
0437 in_f->ilf_ino, item->ri_buf[1].i_len);
0438 error = -EFSCORRUPTED;
0439 goto out_release;
0440 }
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452 xfs_log_dinode_to_disk(ldip, dip, current_lsn);
0453
0454 fields = in_f->ilf_fields;
0455 if (fields & XFS_ILOG_DEV)
0456 xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev);
0457
0458 if (in_f->ilf_size == 2)
0459 goto out_owner_change;
0460 len = item->ri_buf[2].i_len;
0461 src = item->ri_buf[2].i_addr;
0462 ASSERT(in_f->ilf_size <= 4);
0463 ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK));
0464 ASSERT(!(fields & XFS_ILOG_DFORK) ||
0465 (len == xlog_calc_iovec_len(in_f->ilf_dsize)));
0466
0467 switch (fields & XFS_ILOG_DFORK) {
0468 case XFS_ILOG_DDATA:
0469 case XFS_ILOG_DEXT:
0470 memcpy(XFS_DFORK_DPTR(dip), src, len);
0471 break;
0472
0473 case XFS_ILOG_DBROOT:
0474 xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, len,
0475 (struct xfs_bmdr_block *)XFS_DFORK_DPTR(dip),
0476 XFS_DFORK_DSIZE(dip, mp));
0477 break;
0478
0479 default:
0480
0481
0482
0483 ASSERT((fields & XFS_ILOG_DFORK) == 0);
0484 break;
0485 }
0486
0487
0488
0489
0490
0491
0492 if (in_f->ilf_fields & XFS_ILOG_AFORK) {
0493 if (in_f->ilf_fields & XFS_ILOG_DFORK) {
0494 attr_index = 3;
0495 } else {
0496 attr_index = 2;
0497 }
0498 len = item->ri_buf[attr_index].i_len;
0499 src = item->ri_buf[attr_index].i_addr;
0500 ASSERT(len == xlog_calc_iovec_len(in_f->ilf_asize));
0501
0502 switch (in_f->ilf_fields & XFS_ILOG_AFORK) {
0503 case XFS_ILOG_ADATA:
0504 case XFS_ILOG_AEXT:
0505 dest = XFS_DFORK_APTR(dip);
0506 ASSERT(len <= XFS_DFORK_ASIZE(dip, mp));
0507 memcpy(dest, src, len);
0508 break;
0509
0510 case XFS_ILOG_ABROOT:
0511 dest = XFS_DFORK_APTR(dip);
0512 xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src,
0513 len, (struct xfs_bmdr_block *)dest,
0514 XFS_DFORK_ASIZE(dip, mp));
0515 break;
0516
0517 default:
0518 xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
0519 ASSERT(0);
0520 error = -EFSCORRUPTED;
0521 goto out_release;
0522 }
0523 }
0524
0525 out_owner_change:
0526
0527 if ((in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) &&
0528 (dip->di_mode != 0))
0529 error = xfs_recover_inode_owner_change(mp, dip, in_f,
0530 buffer_list);
0531
0532 xfs_dinode_calc_crc(log->l_mp, dip);
0533
0534 ASSERT(bp->b_mount == mp);
0535 bp->b_flags |= _XBF_LOGRECOVERY;
0536 xfs_buf_delwri_queue(bp, buffer_list);
0537
0538 out_release:
0539 xfs_buf_relse(bp);
0540 error:
0541 if (need_free)
0542 kmem_free(in_f);
0543 return error;
0544 }
0545
0546 const struct xlog_recover_item_ops xlog_inode_item_ops = {
0547 .item_type = XFS_LI_INODE,
0548 .ra_pass2 = xlog_recover_inode_ra_pass2,
0549 .commit_pass2 = xlog_recover_inode_commit_pass2,
0550 };