xfs_inode_item_recover.c 16 KB

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