--- /dev/null
+/*
+ * Copyright (C) 2016 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * 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.
+ */
+#include <libxfs.h>
+#include "btree.h"
+#include "err_protos.h"
+#include "libxlog.h"
+#include "incore.h"
+#include "globals.h"
+#include "dinode.h"
+#include "slab.h"
+#include "rmap.h"
+
+#undef RMAP_DEBUG
+
+#ifdef RMAP_DEBUG
+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
+#else
+# define dbg_printf(f, a...)
+#endif
+
+/* per-AG rmap object anchor */
+struct xfs_ag_rmap {
+ struct xfs_slab *ar_rmaps; /* rmap observations, p4 */
+};
+
+static struct xfs_ag_rmap *ag_rmaps;
+
+/*
+ * Compare rmap observations for array sorting.
+ */
+static int
+rmap_compare(
+ const void *a,
+ const void *b)
+{
+ const struct xfs_rmap_irec *pa;
+ const struct xfs_rmap_irec *pb;
+ __u64 oa;
+ __u64 ob;
+
+ pa = a; pb = b;
+ oa = xfs_rmap_irec_offset_pack(pa);
+ ob = xfs_rmap_irec_offset_pack(pb);
+
+ if (pa->rm_startblock < pb->rm_startblock)
+ return -1;
+ else if (pa->rm_startblock > pb->rm_startblock)
+ return 1;
+ else if (pa->rm_owner < pb->rm_owner)
+ return -1;
+ else if (pa->rm_owner > pb->rm_owner)
+ return 1;
+ else if (oa < ob)
+ return -1;
+ else if (oa > ob)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Returns true if we must reconstruct either the reference count or reverse
+ * mapping trees.
+ */
+bool
+needs_rmap_work(
+ struct xfs_mount *mp)
+{
+ return xfs_sb_version_hasrmapbt(&mp->m_sb);
+}
+
+/*
+ * Initialize per-AG reverse map data.
+ */
+void
+init_rmaps(
+ struct xfs_mount *mp)
+{
+ xfs_agnumber_t i;
+ int error;
+
+ if (!needs_rmap_work(mp))
+ return;
+
+ ag_rmaps = calloc(mp->m_sb.sb_agcount, sizeof(struct xfs_ag_rmap));
+ if (!ag_rmaps)
+ do_error(_("couldn't allocate per-AG reverse map roots\n"));
+
+ for (i = 0; i < mp->m_sb.sb_agcount; i++) {
+ error = init_slab(&ag_rmaps[i].ar_rmaps,
+ sizeof(struct xfs_rmap_irec));
+ if (error)
+ do_error(
+_("Insufficient memory while allocating reverse mapping slabs."));
+ }
+}
+
+/*
+ * Free the per-AG reverse-mapping data.
+ */
+void
+free_rmaps(
+ struct xfs_mount *mp)
+{
+ xfs_agnumber_t i;
+
+ if (!needs_rmap_work(mp))
+ return;
+
+ for (i = 0; i < mp->m_sb.sb_agcount; i++)
+ free_slab(&ag_rmaps[i].ar_rmaps);
+ free(ag_rmaps);
+ ag_rmaps = NULL;
+}
+
+/*
+ * Add an observation about a block mapping in an inode's data or attribute
+ * fork for later btree reconstruction.
+ */
+int
+add_rmap(
+ struct xfs_mount *mp,
+ xfs_ino_t ino,
+ int whichfork,
+ struct xfs_bmbt_irec *irec)
+{
+ struct xfs_slab *rmaps;
+ struct xfs_rmap_irec rmap;
+ xfs_agnumber_t agno;
+ xfs_agblock_t agbno;
+
+ if (!needs_rmap_work(mp))
+ return 0;
+
+ agno = XFS_FSB_TO_AGNO(mp, irec->br_startblock);
+ agbno = XFS_FSB_TO_AGBNO(mp, irec->br_startblock);
+ ASSERT(agno != NULLAGNUMBER);
+ ASSERT(agno < mp->m_sb.sb_agcount);
+ ASSERT(agbno + irec->br_blockcount <= mp->m_sb.sb_agblocks);
+ ASSERT(ino != NULLFSINO);
+ ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
+
+ rmaps = ag_rmaps[agno].ar_rmaps;
+ rmap.rm_owner = ino;
+ rmap.rm_offset = irec->br_startoff;
+ rmap.rm_flags = 0;
+ if (whichfork == XFS_ATTR_FORK)
+ rmap.rm_flags |= XFS_RMAP_ATTR_FORK;
+ rmap.rm_startblock = agbno;
+ rmap.rm_blockcount = irec->br_blockcount;
+ if (irec->br_state == XFS_EXT_UNWRITTEN)
+ rmap.rm_flags |= XFS_RMAP_UNWRITTEN;
+ return slab_add(rmaps, &rmap);
+}
+
+#ifdef RMAP_DEBUG
+static void
+dump_rmap(
+ const char *msg,
+ xfs_agnumber_t agno,
+ struct xfs_rmap_irec *rmap)
+{
+ printf("%s: %p agno=%u pblk=%llu own=%lld lblk=%llu len=%u flags=0x%x\n",
+ msg, rmap,
+ (unsigned int)agno,
+ (unsigned long long)rmap->rm_startblock,
+ (unsigned long long)rmap->rm_owner,
+ (unsigned long long)rmap->rm_offset,
+ (unsigned int)rmap->rm_blockcount,
+ (unsigned int)rmap->rm_flags);
+}
+#else
+# define dump_rmap(m, a, r)
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2016 Oracle. All Rights Reserved.
+ *
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * 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.
+ */
+#ifndef RMAP_H_
+#define RMAP_H_
+
+extern bool collect_rmaps;
+
+extern bool needs_rmap_work(struct xfs_mount *);
+
+extern void init_rmaps(struct xfs_mount *);
+extern void free_rmaps(struct xfs_mount *);
+
+extern int add_rmap(struct xfs_mount *, xfs_ino_t, int, struct xfs_bmbt_irec *);
+
+#endif /* RMAP_H_ */