summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-08-02 21:36:07 -0400
committerDave Chinner <david@fromorbit.com>2016-08-02 21:36:07 -0400
commit035e00acb5c719bd003639b90716a7e94e023b73 (patch)
treebf4db815b139e959b9ecc06e35f4c1c8ddcb68ca /fs/xfs
parent673930c34a4500c616cf9b2bbe1ae131ead2e155 (diff)
xfs: define the on-disk rmap btree format
Originally-From: Dave Chinner <dchinner@redhat.com> Now we have all the surrounding call infrastructure in place, we can start filling out the rmap btree implementation. Start with the on-disk btree format; add everything needed to read, write and manipulate rmap btree blocks. This prepares the way for adding the btree operations implementation. [darrick: record owner and offset info in rmap btree] [darrick: fork, bmbt and unwritten state in rmap btree] [darrick: flags are a separate field in xfs_rmap_irec] [darrick: calculate maxlevels separately] [darrick: move the 'unwritten' bit into unused parts of rm_offset] Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/libxfs/xfs_btree.c3
-rw-r--r--fs/xfs/libxfs/xfs_btree.h22
-rw-r--r--fs/xfs/libxfs/xfs_format.h73
-rw-r--r--fs/xfs/libxfs/xfs_rmap.h67
-rw-r--r--fs/xfs/libxfs/xfs_rmap_btree.c184
-rw-r--r--fs/xfs/libxfs/xfs_rmap_btree.h55
-rw-r--r--fs/xfs/libxfs/xfs_sb.c6
-rw-r--r--fs/xfs/libxfs/xfs_shared.h2
-rw-r--r--fs/xfs/xfs_mount.c2
-rw-r--r--fs/xfs/xfs_mount.h3
-rw-r--r--fs/xfs/xfs_ondisk.h3
-rw-r--r--fs/xfs/xfs_trace.h2
13 files changed, 415 insertions, 8 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 0498291829c6..b76e937f0729 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -53,6 +53,7 @@ xfs-y += $(addprefix libxfs/, \
53 xfs_inode_buf.o \ 53 xfs_inode_buf.o \
54 xfs_log_rlimit.o \ 54 xfs_log_rlimit.o \
55 xfs_rmap.o \ 55 xfs_rmap.o \
56 xfs_rmap_btree.o \
56 xfs_sb.o \ 57 xfs_sb.o \
57 xfs_symlink_remote.o \ 58 xfs_symlink_remote.o \
58 xfs_trans_resv.o \ 59 xfs_trans_resv.o \
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 4066b01a1807..fe5f27e4cdc5 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -1213,6 +1213,9 @@ xfs_btree_set_refs(
1213 case XFS_BTNUM_BMAP: 1213 case XFS_BTNUM_BMAP:
1214 xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF); 1214 xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF);
1215 break; 1215 break;
1216 case XFS_BTNUM_RMAP:
1217 xfs_buf_set_ref(bp, XFS_RMAP_BTREE_REF);
1218 break;
1216 default: 1219 default:
1217 ASSERT(0); 1220 ASSERT(0);
1218 } 1221 }
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index a480947f094b..573d3a0c5797 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -38,10 +38,11 @@ union xfs_btree_ptr {
38}; 38};
39 39
40union xfs_btree_key { 40union xfs_btree_key {
41 xfs_bmbt_key_t bmbt; 41 struct xfs_bmbt_key bmbt;
42 xfs_bmdr_key_t bmbr; /* bmbt root block */ 42 xfs_bmdr_key_t bmbr; /* bmbt root block */
43 xfs_alloc_key_t alloc; 43 xfs_alloc_key_t alloc;
44 xfs_inobt_key_t inobt; 44 struct xfs_inobt_key inobt;
45 struct xfs_rmap_key rmap;
45}; 46};
46 47
47/* 48/*
@@ -56,13 +57,18 @@ union xfs_btree_bigkey {
56 xfs_bmdr_key_t bmbr; /* bmbt root block */ 57 xfs_bmdr_key_t bmbr; /* bmbt root block */
57 xfs_alloc_key_t alloc; 58 xfs_alloc_key_t alloc;
58 struct xfs_inobt_key inobt; 59 struct xfs_inobt_key inobt;
60 struct {
61 struct xfs_rmap_key rmap;
62 struct xfs_rmap_key rmap_hi;
63 };
59}; 64};
60 65
61union xfs_btree_rec { 66union xfs_btree_rec {
62 xfs_bmbt_rec_t bmbt; 67 struct xfs_bmbt_rec bmbt;
63 xfs_bmdr_rec_t bmbr; /* bmbt root block */ 68 xfs_bmdr_rec_t bmbr; /* bmbt root block */
64 xfs_alloc_rec_t alloc; 69 struct xfs_alloc_rec alloc;
65 xfs_inobt_rec_t inobt; 70 struct xfs_inobt_rec inobt;
71 struct xfs_rmap_rec rmap;
66}; 72};
67 73
68/* 74/*
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index eecfedf19be5..f6a0641e64c8 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1347,6 +1347,79 @@ struct xfs_owner_info {
1347#define XFS_RMAP_OWN_INODES (-7ULL) /* Inode chunk */ 1347#define XFS_RMAP_OWN_INODES (-7ULL) /* Inode chunk */
1348#define XFS_RMAP_OWN_MIN (-8ULL) /* guard */ 1348#define XFS_RMAP_OWN_MIN (-8ULL) /* guard */
1349 1349
1350#define XFS_RMAP_NON_INODE_OWNER(owner) (!!((owner) & (1ULL << 63)))
1351
1352/*
1353 * Data record structure
1354 */
1355struct xfs_rmap_rec {
1356 __be32 rm_startblock; /* extent start block */
1357 __be32 rm_blockcount; /* extent length */
1358 __be64 rm_owner; /* extent owner */
1359 __be64 rm_offset; /* offset within the owner */
1360};
1361
1362/*
1363 * rmap btree record
1364 * rm_offset:63 is the attribute fork flag
1365 * rm_offset:62 is the bmbt block flag
1366 * rm_offset:61 is the unwritten extent flag (same as l0:63 in bmbt)
1367 * rm_offset:54-60 aren't used and should be zero
1368 * rm_offset:0-53 is the block offset within the inode
1369 */
1370#define XFS_RMAP_OFF_ATTR_FORK ((__uint64_t)1ULL << 63)
1371#define XFS_RMAP_OFF_BMBT_BLOCK ((__uint64_t)1ULL << 62)
1372#define XFS_RMAP_OFF_UNWRITTEN ((__uint64_t)1ULL << 61)
1373
1374#define XFS_RMAP_LEN_MAX ((__uint32_t)~0U)
1375#define XFS_RMAP_OFF_FLAGS (XFS_RMAP_OFF_ATTR_FORK | \
1376 XFS_RMAP_OFF_BMBT_BLOCK | \
1377 XFS_RMAP_OFF_UNWRITTEN)
1378#define XFS_RMAP_OFF_MASK ((__uint64_t)0x3FFFFFFFFFFFFFULL)
1379
1380#define XFS_RMAP_OFF(off) ((off) & XFS_RMAP_OFF_MASK)
1381
1382#define XFS_RMAP_IS_BMBT_BLOCK(off) (!!((off) & XFS_RMAP_OFF_BMBT_BLOCK))
1383#define XFS_RMAP_IS_ATTR_FORK(off) (!!((off) & XFS_RMAP_OFF_ATTR_FORK))
1384#define XFS_RMAP_IS_UNWRITTEN(len) (!!((off) & XFS_RMAP_OFF_UNWRITTEN))
1385
1386#define RMAPBT_STARTBLOCK_BITLEN 32
1387#define RMAPBT_BLOCKCOUNT_BITLEN 32
1388#define RMAPBT_OWNER_BITLEN 64
1389#define RMAPBT_ATTRFLAG_BITLEN 1
1390#define RMAPBT_BMBTFLAG_BITLEN 1
1391#define RMAPBT_EXNTFLAG_BITLEN 1
1392#define RMAPBT_UNUSED_OFFSET_BITLEN 7
1393#define RMAPBT_OFFSET_BITLEN 54
1394
1395#define XFS_RMAP_ATTR_FORK (1 << 0)
1396#define XFS_RMAP_BMBT_BLOCK (1 << 1)
1397#define XFS_RMAP_UNWRITTEN (1 << 2)
1398#define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \
1399 XFS_RMAP_BMBT_BLOCK)
1400#define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN)
1401struct xfs_rmap_irec {
1402 xfs_agblock_t rm_startblock; /* extent start block */
1403 xfs_extlen_t rm_blockcount; /* extent length */
1404 __uint64_t rm_owner; /* extent owner */
1405 __uint64_t rm_offset; /* offset within the owner */
1406 unsigned int rm_flags; /* state flags */
1407};
1408
1409/*
1410 * Key structure
1411 *
1412 * We don't use the length for lookups
1413 */
1414struct xfs_rmap_key {
1415 __be32 rm_startblock; /* extent start block */
1416 __be64 rm_owner; /* extent owner */
1417 __be64 rm_offset; /* offset within the owner */
1418} __attribute__((packed));
1419
1420/* btree pointer type */
1421typedef __be32 xfs_rmap_ptr_t;
1422
1350#define XFS_RMAP_BLOCK(mp) \ 1423#define XFS_RMAP_BLOCK(mp) \
1351 (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \ 1424 (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
1352 XFS_FIBT_BLOCK(mp) + 1 : \ 1425 XFS_FIBT_BLOCK(mp) + 1 : \
diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h
index dbf0301e9ae1..e7a670459fea 100644
--- a/fs/xfs/libxfs/xfs_rmap.h
+++ b/fs/xfs/libxfs/xfs_rmap.h
@@ -68,6 +68,73 @@ xfs_rmap_skip_owner_update(
68 68
69struct xfs_buf; 69struct xfs_buf;
70 70
71static inline __u64
72xfs_rmap_irec_offset_pack(
73 const struct xfs_rmap_irec *irec)
74{
75 __u64 x;
76
77 x = XFS_RMAP_OFF(irec->rm_offset);
78 if (irec->rm_flags & XFS_RMAP_ATTR_FORK)
79 x |= XFS_RMAP_OFF_ATTR_FORK;
80 if (irec->rm_flags & XFS_RMAP_BMBT_BLOCK)
81 x |= XFS_RMAP_OFF_BMBT_BLOCK;
82 if (irec->rm_flags & XFS_RMAP_UNWRITTEN)
83 x |= XFS_RMAP_OFF_UNWRITTEN;
84 return x;
85}
86
87static inline int
88xfs_rmap_irec_offset_unpack(
89 __u64 offset,
90 struct xfs_rmap_irec *irec)
91{
92 if (offset & ~(XFS_RMAP_OFF_MASK | XFS_RMAP_OFF_FLAGS))
93 return -EFSCORRUPTED;
94 irec->rm_offset = XFS_RMAP_OFF(offset);
95 if (offset & XFS_RMAP_OFF_ATTR_FORK)
96 irec->rm_flags |= XFS_RMAP_ATTR_FORK;
97 if (offset & XFS_RMAP_OFF_BMBT_BLOCK)
98 irec->rm_flags |= XFS_RMAP_BMBT_BLOCK;
99 if (offset & XFS_RMAP_OFF_UNWRITTEN)
100 irec->rm_flags |= XFS_RMAP_UNWRITTEN;
101 return 0;
102}
103
104static inline void
105xfs_owner_info_unpack(
106 struct xfs_owner_info *oinfo,
107 uint64_t *owner,
108 uint64_t *offset,
109 unsigned int *flags)
110{
111 unsigned int r = 0;
112
113 *owner = oinfo->oi_owner;
114 *offset = oinfo->oi_offset;
115 if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK)
116 r |= XFS_RMAP_ATTR_FORK;
117 if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK)
118 r |= XFS_RMAP_BMBT_BLOCK;
119 *flags = r;
120}
121
122static inline void
123xfs_owner_info_pack(
124 struct xfs_owner_info *oinfo,
125 uint64_t owner,
126 uint64_t offset,
127 unsigned int flags)
128{
129 oinfo->oi_owner = owner;
130 oinfo->oi_offset = XFS_RMAP_OFF(offset);
131 oinfo->oi_flags = 0;
132 if (flags & XFS_RMAP_ATTR_FORK)
133 oinfo->oi_flags |= XFS_OWNER_INFO_ATTR_FORK;
134 if (flags & XFS_RMAP_BMBT_BLOCK)
135 oinfo->oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK;
136}
137
71int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp, 138int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp,
72 xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, 139 xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len,
73 struct xfs_owner_info *oinfo); 140 struct xfs_owner_info *oinfo);
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
new file mode 100644
index 000000000000..a9ddc191aa2d
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -0,0 +1,184 @@
1/*
2 * Copyright (c) 2014 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#include "xfs.h"
19#include "xfs_fs.h"
20#include "xfs_shared.h"
21#include "xfs_format.h"
22#include "xfs_log_format.h"
23#include "xfs_trans_resv.h"
24#include "xfs_bit.h"
25#include "xfs_sb.h"
26#include "xfs_mount.h"
27#include "xfs_defer.h"
28#include "xfs_inode.h"
29#include "xfs_trans.h"
30#include "xfs_alloc.h"
31#include "xfs_btree.h"
32#include "xfs_rmap_btree.h"
33#include "xfs_trace.h"
34#include "xfs_cksum.h"
35#include "xfs_error.h"
36#include "xfs_extent_busy.h"
37
38static struct xfs_btree_cur *
39xfs_rmapbt_dup_cursor(
40 struct xfs_btree_cur *cur)
41{
42 return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp,
43 cur->bc_private.a.agbp, cur->bc_private.a.agno);
44}
45
46static bool
47xfs_rmapbt_verify(
48 struct xfs_buf *bp)
49{
50 struct xfs_mount *mp = bp->b_target->bt_mount;
51 struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
52 struct xfs_perag *pag = bp->b_pag;
53 unsigned int level;
54
55 /*
56 * magic number and level verification
57 *
58 * During growfs operations, we can't verify the exact level or owner as
59 * the perag is not fully initialised and hence not attached to the
60 * buffer. In this case, check against the maximum tree depth.
61 *
62 * Similarly, during log recovery we will have a perag structure
63 * attached, but the agf information will not yet have been initialised
64 * from the on disk AGF. Again, we can only check against maximum limits
65 * in this case.
66 */
67 if (block->bb_magic != cpu_to_be32(XFS_RMAP_CRC_MAGIC))
68 return false;
69
70 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
71 return false;
72 if (!xfs_btree_sblock_v5hdr_verify(bp))
73 return false;
74
75 level = be16_to_cpu(block->bb_level);
76 if (pag && pag->pagf_init) {
77 if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi])
78 return false;
79 } else if (level >= mp->m_rmap_maxlevels)
80 return false;
81
82 return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]);
83}
84
85static void
86xfs_rmapbt_read_verify(
87 struct xfs_buf *bp)
88{
89 if (!xfs_btree_sblock_verify_crc(bp))
90 xfs_buf_ioerror(bp, -EFSBADCRC);
91 else if (!xfs_rmapbt_verify(bp))
92 xfs_buf_ioerror(bp, -EFSCORRUPTED);
93
94 if (bp->b_error) {
95 trace_xfs_btree_corrupt(bp, _RET_IP_);
96 xfs_verifier_error(bp);
97 }
98}
99
100static void
101xfs_rmapbt_write_verify(
102 struct xfs_buf *bp)
103{
104 if (!xfs_rmapbt_verify(bp)) {
105 trace_xfs_btree_corrupt(bp, _RET_IP_);
106 xfs_buf_ioerror(bp, -EFSCORRUPTED);
107 xfs_verifier_error(bp);
108 return;
109 }
110 xfs_btree_sblock_calc_crc(bp);
111
112}
113
114const struct xfs_buf_ops xfs_rmapbt_buf_ops = {
115 .name = "xfs_rmapbt",
116 .verify_read = xfs_rmapbt_read_verify,
117 .verify_write = xfs_rmapbt_write_verify,
118};
119
120static const struct xfs_btree_ops xfs_rmapbt_ops = {
121 .rec_len = sizeof(struct xfs_rmap_rec),
122 .key_len = 2 * sizeof(struct xfs_rmap_key),
123
124 .dup_cursor = xfs_rmapbt_dup_cursor,
125 .buf_ops = &xfs_rmapbt_buf_ops,
126
127 .get_leaf_keys = xfs_btree_get_leaf_keys_overlapped,
128 .get_node_keys = xfs_btree_get_node_keys_overlapped,
129 .update_keys = xfs_btree_update_keys_overlapped,
130};
131
132/*
133 * Allocate a new allocation btree cursor.
134 */
135struct xfs_btree_cur *
136xfs_rmapbt_init_cursor(
137 struct xfs_mount *mp,
138 struct xfs_trans *tp,
139 struct xfs_buf *agbp,
140 xfs_agnumber_t agno)
141{
142 struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp);
143 struct xfs_btree_cur *cur;
144
145 cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS);
146 cur->bc_tp = tp;
147 cur->bc_mp = mp;
148 cur->bc_btnum = XFS_BTNUM_RMAP;
149 cur->bc_flags = XFS_BTREE_CRC_BLOCKS;
150 cur->bc_blocklog = mp->m_sb.sb_blocklog;
151 cur->bc_ops = &xfs_rmapbt_ops;
152 cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]);
153
154 cur->bc_private.a.agbp = agbp;
155 cur->bc_private.a.agno = agno;
156
157 return cur;
158}
159
160/*
161 * Calculate number of records in an rmap btree block.
162 */
163int
164xfs_rmapbt_maxrecs(
165 struct xfs_mount *mp,
166 int blocklen,
167 int leaf)
168{
169 blocklen -= XFS_RMAP_BLOCK_LEN;
170
171 if (leaf)
172 return blocklen / sizeof(struct xfs_rmap_rec);
173 return blocklen /
174 (sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t));
175}
176
177/* Compute the maximum height of an rmap btree. */
178void
179xfs_rmapbt_compute_maxlevels(
180 struct xfs_mount *mp)
181{
182 mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(mp,
183 mp->m_rmap_mnr, mp->m_sb.sb_agblocks);
184}
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
new file mode 100644
index 000000000000..a3a6b7d476c7
--- /dev/null
+++ b/fs/xfs/libxfs/xfs_rmap_btree.h
@@ -0,0 +1,55 @@
1/*
2 * Copyright (c) 2014 Red Hat, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18#ifndef __XFS_RMAP_BTREE_H__
19#define __XFS_RMAP_BTREE_H__
20
21struct xfs_buf;
22struct xfs_btree_cur;
23struct xfs_mount;
24
25/* rmaps only exist on crc enabled filesystems */
26#define XFS_RMAP_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN
27
28/*
29 * Record, key, and pointer address macros for btree blocks.
30 *
31 * (note that some of these may appear unused, but they are used in userspace)
32 */
33#define XFS_RMAP_REC_ADDR(block, index) \
34 ((struct xfs_rmap_rec *) \
35 ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
36 (((index) - 1) * sizeof(struct xfs_rmap_rec))))
37
38#define XFS_RMAP_KEY_ADDR(block, index) \
39 ((struct xfs_rmap_key *) \
40 ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
41 ((index) - 1) * sizeof(struct xfs_rmap_key)))
42
43#define XFS_RMAP_PTR_ADDR(block, index, maxrecs) \
44 ((xfs_rmap_ptr_t *) \
45 ((char *)(block) + XFS_RMAP_BLOCK_LEN + \
46 (maxrecs) * sizeof(struct xfs_rmap_key) + \
47 ((index) - 1) * sizeof(xfs_rmap_ptr_t)))
48
49struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
50 struct xfs_trans *tp, struct xfs_buf *bp,
51 xfs_agnumber_t agno);
52int xfs_rmapbt_maxrecs(struct xfs_mount *mp, int blocklen, int leaf);
53extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp);
54
55#endif /* __XFS_RMAP_BTREE_H__ */
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 2194e5d4eea8..fb33e70e5c9a 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -37,6 +37,7 @@
37#include "xfs_alloc_btree.h" 37#include "xfs_alloc_btree.h"
38#include "xfs_ialloc_btree.h" 38#include "xfs_ialloc_btree.h"
39#include "xfs_log.h" 39#include "xfs_log.h"
40#include "xfs_rmap_btree.h"
40 41
41/* 42/*
42 * Physical superblock buffer manipulations. Shared with libxfs in userspace. 43 * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -730,6 +731,11 @@ xfs_sb_mount_common(
730 mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2; 731 mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
731 mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2; 732 mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
732 733
734 mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 1);
735 mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 0);
736 mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
737 mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
738
733 mp->m_bsize = XFS_FSB_TO_BB(mp, 1); 739 mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
734 mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, 740 mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
735 sbp->sb_inopblock); 741 sbp->sb_inopblock);
diff --git a/fs/xfs/libxfs/xfs_shared.h b/fs/xfs/libxfs/xfs_shared.h
index 16002b5ec4eb..0c5b30bd884c 100644
--- a/fs/xfs/libxfs/xfs_shared.h
+++ b/fs/xfs/libxfs/xfs_shared.h
@@ -38,6 +38,7 @@ extern const struct xfs_buf_ops xfs_agi_buf_ops;
38extern const struct xfs_buf_ops xfs_agf_buf_ops; 38extern const struct xfs_buf_ops xfs_agf_buf_ops;
39extern const struct xfs_buf_ops xfs_agfl_buf_ops; 39extern const struct xfs_buf_ops xfs_agfl_buf_ops;
40extern const struct xfs_buf_ops xfs_allocbt_buf_ops; 40extern const struct xfs_buf_ops xfs_allocbt_buf_ops;
41extern const struct xfs_buf_ops xfs_rmapbt_buf_ops;
41extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops; 42extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops;
42extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; 43extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops;
43extern const struct xfs_buf_ops xfs_bmbt_buf_ops; 44extern const struct xfs_buf_ops xfs_bmbt_buf_ops;
@@ -116,6 +117,7 @@ int xfs_log_calc_minimum_size(struct xfs_mount *);
116#define XFS_INO_BTREE_REF 3 117#define XFS_INO_BTREE_REF 3
117#define XFS_ALLOC_BTREE_REF 2 118#define XFS_ALLOC_BTREE_REF 2
118#define XFS_BMAP_BTREE_REF 2 119#define XFS_BMAP_BTREE_REF 2
120#define XFS_RMAP_BTREE_REF 2
119#define XFS_DIR_BTREE_REF 2 121#define XFS_DIR_BTREE_REF 2
120#define XFS_INO_REF 2 122#define XFS_INO_REF 2
121#define XFS_ATTR_BTREE_REF 1 123#define XFS_ATTR_BTREE_REF 1
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 24ae96b4078f..0041866d51ca 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -42,6 +42,7 @@
42#include "xfs_trace.h" 42#include "xfs_trace.h"
43#include "xfs_icache.h" 43#include "xfs_icache.h"
44#include "xfs_sysfs.h" 44#include "xfs_sysfs.h"
45#include "xfs_rmap_btree.h"
45 46
46 47
47static DEFINE_MUTEX(xfs_uuid_table_mutex); 48static DEFINE_MUTEX(xfs_uuid_table_mutex);
@@ -682,6 +683,7 @@ xfs_mountfs(
682 xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); 683 xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK);
683 xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); 684 xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK);
684 xfs_ialloc_compute_maxlevels(mp); 685 xfs_ialloc_compute_maxlevels(mp);
686 xfs_rmapbt_compute_maxlevels(mp);
685 687
686 xfs_set_maxicount(mp); 688 xfs_set_maxicount(mp);
687 689
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 0537b1f28f90..0ed0f29ddaf5 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -116,9 +116,12 @@ typedef struct xfs_mount {
116 uint m_bmap_dmnr[2]; /* min bmap btree records */ 116 uint m_bmap_dmnr[2]; /* min bmap btree records */
117 uint m_inobt_mxr[2]; /* max inobt btree records */ 117 uint m_inobt_mxr[2]; /* max inobt btree records */
118 uint m_inobt_mnr[2]; /* min inobt btree records */ 118 uint m_inobt_mnr[2]; /* min inobt btree records */
119 uint m_rmap_mxr[2]; /* max rmap btree records */
120 uint m_rmap_mnr[2]; /* min rmap btree records */
119 uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ 121 uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */
120 uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ 122 uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */
121 uint m_in_maxlevels; /* max inobt btree levels. */ 123 uint m_in_maxlevels; /* max inobt btree levels. */
124 uint m_rmap_maxlevels; /* max rmap btree levels */
122 xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */ 125 xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */
123 struct radix_tree_root m_perag_tree; /* per-ag accounting info */ 126 struct radix_tree_root m_perag_tree; /* per-ag accounting info */
124 spinlock_t m_perag_lock; /* lock for m_perag_tree */ 127 spinlock_t m_perag_lock; /* lock for m_perag_tree */
diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h
index 0cc8d8f74356..69e2986a3776 100644
--- a/fs/xfs/xfs_ondisk.h
+++ b/fs/xfs/xfs_ondisk.h
@@ -49,11 +49,14 @@ xfs_check_ondisk_structs(void)
49 XFS_CHECK_STRUCT_SIZE(struct xfs_dsymlink_hdr, 56); 49 XFS_CHECK_STRUCT_SIZE(struct xfs_dsymlink_hdr, 56);
50 XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_key, 4); 50 XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_key, 4);
51 XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_rec, 16); 51 XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_rec, 16);
52 XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_key, 20);
53 XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_rec, 24);
52 XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp, 8); 54 XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp, 8);
53 XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t, 8); 55 XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t, 8);
54 XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t, 4); 56 XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t, 4);
55 XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t, 8); 57 XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t, 8);
56 XFS_CHECK_STRUCT_SIZE(xfs_inobt_ptr_t, 4); 58 XFS_CHECK_STRUCT_SIZE(xfs_inobt_ptr_t, 4);
59 XFS_CHECK_STRUCT_SIZE(xfs_rmap_ptr_t, 4);
57 60
58 /* dir/attr trees */ 61 /* dir/attr trees */
59 XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_leaf_hdr, 80); 62 XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_leaf_hdr, 80);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 79e3812499ba..4c3418b1a244 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2446,6 +2446,8 @@ DECLARE_EVENT_CLASS(xfs_rmap_class,
2446 __entry->owner = oinfo->oi_owner; 2446 __entry->owner = oinfo->oi_owner;
2447 __entry->offset = oinfo->oi_offset; 2447 __entry->offset = oinfo->oi_offset;
2448 __entry->flags = oinfo->oi_flags; 2448 __entry->flags = oinfo->oi_flags;
2449 if (unwritten)
2450 __entry->flags |= XFS_RMAP_UNWRITTEN;
2449 ), 2451 ),
2450 TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%lx", 2452 TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%lx",
2451 MAJOR(__entry->dev), MINOR(__entry->dev), 2453 MAJOR(__entry->dev), MINOR(__entry->dev),