Skip to content

Commit d3c2ae1

Browse files
grwilsonbehlendorf
authored andcommitted
OpenZFS 6950 - ARC should cache compressed data
Authored by: George Wilson <george.wilson@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Dan Kimmel <dan.kimmel@delphix.com> Reviewed by: Matt Ahrens <mahrens@delphix.com> Reviewed by: Paul Dagnelie <pcd@delphix.com> Reviewed by: Tom Caputi <tcaputi@datto.com> Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov> Ported by: David Quigley <david.quigley@intel.com> This review covers the reading and writing of compressed arc headers, sharing data between the arc_hdr_t and the arc_buf_t, and the implementation of a new dbuf cache to keep frequently access data uncompressed. I've added a new member to l1 arc hdr called b_pdata. The b_pdata always hangs off the arc_buf_hdr_t (if an L1 hdr is in use) and points to the physical block for that DVA. The physical block may or may not be compressed. If compressed arc is enabled and the block on-disk is compressed, then the b_pdata will match the block on-disk and remain compressed in memory. If the block on disk is not compressed, then neither will the b_pdata. Lastly, if compressed arc is disabled, then b_pdata will always be an uncompressed version of the on-disk block. Typically the arc will cache only the arc_buf_hdr_t and will aggressively evict any arc_buf_t's that are no longer referenced. This means that the arc will primarily have compressed blocks as the arc_buf_t's are considered overhead and are always uncompressed. When a consumer reads a block we first look to see if the arc_buf_hdr_t is cached. If the hdr is cached then we allocate a new arc_buf_t and decompress the b_pdata contents into the arc_buf_t's b_data. If the hdr already has a arc_buf_t, then we will allocate an additional arc_buf_t and bcopy the uncompressed contents from the first arc_buf_t to the new one. Writing to the compressed arc requires that we first discard the b_pdata since the physical block is about to be rewritten. The new data contents will be passed in via an arc_buf_t (uncompressed) and during the I/O pipeline stages we will copy the physical block contents to a newly allocated b_pdata. When an l2arc is inuse it will also take advantage of the b_pdata. Now the l2arc will always write the contents of b_pdata to the l2arc. This means that when compressed arc is enabled that the l2arc blocks are identical to those stored in the main data pool. This provides a significant advantage since we can leverage the bp's checksum when reading from the l2arc to determine if the contents are valid. If the compressed arc is disabled, then we must first transform the read block to look like the physical block in the main data pool before comparing the checksum and determining it's valid. OpenZFS-issue: https://www.illumos.org/issues/6950 OpenZFS-commit: openzfs/openzfs@7fc10f0 Issue #5078
1 parent b8eb3c4 commit d3c2ae1

27 files changed

+2491
-2018
lines changed

cmd/zdb/zdb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1297,7 +1297,7 @@ visit_indirect(spa_t *spa, const dnode_phys_t *dnp,
12971297
}
12981298
if (!err)
12991299
ASSERT3U(fill, ==, BP_GET_FILL(bp));
1300-
(void) arc_buf_remove_ref(buf, &buf);
1300+
arc_buf_destroy(buf, &buf);
13011301
}
13021302

13031303
return (err);

cmd/ztest/ztest.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ static const ztest_shared_opts_t ztest_opts_defaults = {
192192
extern uint64_t metaslab_gang_bang;
193193
extern uint64_t metaslab_df_alloc_threshold;
194194
extern int metaslab_preload_limit;
195+
extern boolean_t zfs_compressed_arc_enabled;
195196

196197
static ztest_shared_opts_t *ztest_shared_opts;
197198
static ztest_shared_opts_t ztest_opts;
@@ -5880,6 +5881,12 @@ ztest_resume_thread(void *arg)
58805881
if (spa_suspended(spa))
58815882
ztest_resume(spa);
58825883
(void) poll(NULL, 0, 100);
5884+
5885+
/*
5886+
* Periodically change the zfs_compressed_arc_enabled setting.
5887+
*/
5888+
if (ztest_random(10) == 0)
5889+
zfs_compressed_arc_enabled = ztest_random(2);
58835890
}
58845891

58855892
thread_exit();

include/sys/arc.h

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,24 @@ extern "C" {
4444
*/
4545
#define ARC_EVICT_ALL -1ULL
4646

47+
#define HDR_SET_LSIZE(hdr, x) do { \
48+
ASSERT(IS_P2ALIGNED(x, 1U << SPA_MINBLOCKSHIFT)); \
49+
(hdr)->b_lsize = ((x) >> SPA_MINBLOCKSHIFT); \
50+
_NOTE(CONSTCOND) } while (0)
51+
52+
#define HDR_SET_PSIZE(hdr, x) do { \
53+
ASSERT(IS_P2ALIGNED((x), 1U << SPA_MINBLOCKSHIFT)); \
54+
(hdr)->b_psize = ((x) >> SPA_MINBLOCKSHIFT); \
55+
_NOTE(CONSTCOND) } while (0)
56+
57+
#define HDR_GET_LSIZE(hdr) ((hdr)->b_lsize << SPA_MINBLOCKSHIFT)
58+
#define HDR_GET_PSIZE(hdr) ((hdr)->b_psize << SPA_MINBLOCKSHIFT)
59+
4760
typedef struct arc_buf_hdr arc_buf_hdr_t;
4861
typedef struct arc_buf arc_buf_t;
4962
typedef struct arc_prune arc_prune_t;
5063
typedef void arc_done_func_t(zio_t *zio, arc_buf_t *buf, void *private);
5164
typedef void arc_prune_func_t(int64_t bytes, void *private);
52-
typedef int arc_evict_func_t(void *private);
5365

5466
/* Shared module parameters */
5567
extern int zfs_arc_average_blocksize;
@@ -58,6 +70,8 @@ extern int zfs_arc_average_blocksize;
5870
arc_done_func_t arc_bcopy_func;
5971
arc_done_func_t arc_getbuf_func;
6072

73+
extern int zfs_arc_num_sublists_per_state;
74+
6175
/* generic arc_prune_func_t wrapper for callbacks */
6276
struct arc_prune {
6377
arc_prune_func_t *p_pfunc;
@@ -77,37 +91,54 @@ typedef enum arc_flags
7791
/*
7892
* Public flags that can be passed into the ARC by external consumers.
7993
*/
80-
ARC_FLAG_NONE = 1 << 0, /* No flags set */
81-
ARC_FLAG_WAIT = 1 << 1, /* perform sync I/O */
82-
ARC_FLAG_NOWAIT = 1 << 2, /* perform async I/O */
83-
ARC_FLAG_PREFETCH = 1 << 3, /* I/O is a prefetch */
84-
ARC_FLAG_CACHED = 1 << 4, /* I/O was in cache */
85-
ARC_FLAG_L2CACHE = 1 << 5, /* cache in L2ARC */
86-
ARC_FLAG_L2COMPRESS = 1 << 6, /* compress in L2ARC */
87-
ARC_FLAG_PREDICTIVE_PREFETCH = 1 << 7, /* I/O from zfetch */
94+
ARC_FLAG_WAIT = 1 << 0, /* perform sync I/O */
95+
ARC_FLAG_NOWAIT = 1 << 1, /* perform async I/O */
96+
ARC_FLAG_PREFETCH = 1 << 2, /* I/O is a prefetch */
97+
ARC_FLAG_CACHED = 1 << 3, /* I/O was in cache */
98+
ARC_FLAG_L2CACHE = 1 << 4, /* cache in L2ARC */
99+
ARC_FLAG_PREDICTIVE_PREFETCH = 1 << 5, /* I/O from zfetch */
88100

89101
/*
90102
* Private ARC flags. These flags are private ARC only flags that
91103
* will show up in b_flags in the arc_hdr_buf_t. These flags should
92104
* only be set by ARC code.
93105
*/
94-
ARC_FLAG_IN_HASH_TABLE = 1 << 8, /* buffer is hashed */
95-
ARC_FLAG_IO_IN_PROGRESS = 1 << 9, /* I/O in progress */
96-
ARC_FLAG_IO_ERROR = 1 << 10, /* I/O failed for buf */
97-
ARC_FLAG_FREED_IN_READ = 1 << 11, /* freed during read */
98-
ARC_FLAG_BUF_AVAILABLE = 1 << 12, /* block not in use */
99-
ARC_FLAG_INDIRECT = 1 << 13, /* indirect block */
106+
ARC_FLAG_IN_HASH_TABLE = 1 << 6, /* buffer is hashed */
107+
ARC_FLAG_IO_IN_PROGRESS = 1 << 7, /* I/O in progress */
108+
ARC_FLAG_IO_ERROR = 1 << 8, /* I/O failed for buf */
109+
ARC_FLAG_INDIRECT = 1 << 9, /* indirect block */
100110
/* Indicates that block was read with ASYNC priority. */
101-
ARC_FLAG_PRIO_ASYNC_READ = 1 << 14,
102-
ARC_FLAG_L2_WRITING = 1 << 15, /* write in progress */
103-
ARC_FLAG_L2_EVICTED = 1 << 16, /* evicted during I/O */
104-
ARC_FLAG_L2_WRITE_HEAD = 1 << 17, /* head of write list */
111+
ARC_FLAG_PRIO_ASYNC_READ = 1 << 10,
112+
ARC_FLAG_L2_WRITING = 1 << 11, /* write in progress */
113+
ARC_FLAG_L2_EVICTED = 1 << 12, /* evicted during I/O */
114+
ARC_FLAG_L2_WRITE_HEAD = 1 << 13, /* head of write list */
105115
/* indicates that the buffer contains metadata (otherwise, data) */
106-
ARC_FLAG_BUFC_METADATA = 1 << 18,
116+
ARC_FLAG_BUFC_METADATA = 1 << 14,
107117

108118
/* Flags specifying whether optional hdr struct fields are defined */
109-
ARC_FLAG_HAS_L1HDR = 1 << 19,
110-
ARC_FLAG_HAS_L2HDR = 1 << 20,
119+
ARC_FLAG_HAS_L1HDR = 1 << 15,
120+
ARC_FLAG_HAS_L2HDR = 1 << 16,
121+
122+
/*
123+
* Indicates the arc_buf_hdr_t's b_pdata matches the on-disk data.
124+
* This allows the l2arc to use the blkptr's checksum to verify
125+
* the data without having to store the checksum in the hdr.
126+
*/
127+
ARC_FLAG_COMPRESSED_ARC = 1 << 17,
128+
ARC_FLAG_SHARED_DATA = 1 << 18,
129+
130+
/*
131+
* The arc buffer's compression mode is stored in the top 7 bits of the
132+
* flags field, so these dummy flags are included so that MDB can
133+
* interpret the enum properly.
134+
*/
135+
ARC_FLAG_COMPRESS_0 = 1 << 24,
136+
ARC_FLAG_COMPRESS_1 = 1 << 25,
137+
ARC_FLAG_COMPRESS_2 = 1 << 26,
138+
ARC_FLAG_COMPRESS_3 = 1 << 27,
139+
ARC_FLAG_COMPRESS_4 = 1 << 28,
140+
ARC_FLAG_COMPRESS_5 = 1 << 29,
141+
ARC_FLAG_COMPRESS_6 = 1 << 30
111142

112143
} arc_flags_t;
113144

@@ -116,11 +147,10 @@ struct arc_buf {
116147
arc_buf_t *b_next;
117148
kmutex_t b_evict_lock;
118149
void *b_data;
119-
arc_evict_func_t *b_efunc;
120-
void *b_private;
121150
};
122151

123152
typedef enum arc_buf_contents {
153+
ARC_BUFC_INVALID, /* invalid type */
124154
ARC_BUFC_DATA, /* buffer contains data */
125155
ARC_BUFC_METADATA, /* buffer contains metadata */
126156
ARC_BUFC_NUMTYPES
@@ -154,7 +184,7 @@ typedef struct arc_buf_info {
154184
arc_state_type_t abi_state_type;
155185
arc_buf_contents_t abi_state_contents;
156186
uint32_t abi_flags;
157-
uint32_t abi_datacnt;
187+
uint32_t abi_bufcnt;
158188
uint64_t abi_size;
159189
uint64_t abi_spa;
160190
uint64_t abi_access;
@@ -171,21 +201,19 @@ typedef struct arc_buf_info {
171201

172202
void arc_space_consume(uint64_t space, arc_space_type_t type);
173203
void arc_space_return(uint64_t space, arc_space_type_t type);
174-
arc_buf_t *arc_buf_alloc(spa_t *spa, uint64_t size, void *tag,
204+
arc_buf_t *arc_alloc_buf(spa_t *spa, int32_t size, void *tag,
175205
arc_buf_contents_t type);
176206
arc_buf_t *arc_loan_buf(spa_t *spa, uint64_t size);
177207
void arc_return_buf(arc_buf_t *buf, void *tag);
178208
void arc_loan_inuse_buf(arc_buf_t *buf, void *tag);
179-
void arc_buf_add_ref(arc_buf_t *buf, void *tag);
180-
boolean_t arc_buf_remove_ref(arc_buf_t *buf, void *tag);
209+
void arc_buf_destroy(arc_buf_t *buf, void *tag);
181210
void arc_buf_info(arc_buf_t *buf, arc_buf_info_t *abi, int state_index);
182211
uint64_t arc_buf_size(arc_buf_t *buf);
183212
void arc_release(arc_buf_t *buf, void *tag);
184213
int arc_released(arc_buf_t *buf);
185214
void arc_buf_sigsegv(int sig, siginfo_t *si, void *unused);
186215
void arc_buf_freeze(arc_buf_t *buf);
187216
void arc_buf_thaw(arc_buf_t *buf);
188-
boolean_t arc_buf_eviction_needed(arc_buf_t *buf);
189217
#ifdef ZFS_DEBUG
190218
int arc_referenced(arc_buf_t *buf);
191219
#endif
@@ -194,8 +222,7 @@ int arc_read(zio_t *pio, spa_t *spa, const blkptr_t *bp,
194222
arc_done_func_t *done, void *private, zio_priority_t priority, int flags,
195223
arc_flags_t *arc_flags, const zbookmark_phys_t *zb);
196224
zio_t *arc_write(zio_t *pio, spa_t *spa, uint64_t txg,
197-
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, boolean_t l2arc_compress,
198-
const zio_prop_t *zp,
225+
blkptr_t *bp, arc_buf_t *buf, boolean_t l2arc, const zio_prop_t *zp,
199226
arc_done_func_t *ready, arc_done_func_t *child_ready,
200227
arc_done_func_t *physdone, arc_done_func_t *done,
201228
void *private, zio_priority_t priority, int zio_flags,
@@ -205,13 +232,11 @@ arc_prune_t *arc_add_prune_callback(arc_prune_func_t *func, void *private);
205232
void arc_remove_prune_callback(arc_prune_t *p);
206233
void arc_freed(spa_t *spa, const blkptr_t *bp);
207234

208-
void arc_set_callback(arc_buf_t *buf, arc_evict_func_t *func, void *private);
209-
boolean_t arc_clear_callback(arc_buf_t *buf);
210-
211235
void arc_flush(spa_t *spa, boolean_t retry);
212236
void arc_tempreserve_clear(uint64_t reserve);
213237
int arc_tempreserve_space(uint64_t reserve, uint64_t txg);
214238

239+
uint64_t arc_max_bytes(void);
215240
void arc_init(void);
216241
void arc_fini(void);
217242

include/sys/arc_impl.h

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ typedef struct arc_state {
7474
/*
7575
* total amount of evictable data in this state
7676
*/
77-
uint64_t arcs_lsize[ARC_BUFC_NUMTYPES];
77+
refcount_t arcs_esize[ARC_BUFC_NUMTYPES];
7878
/*
7979
* total amount of data in this state; this includes: evictable,
8080
* non-evictable, ARC_BUFC_DATA, and ARC_BUFC_METADATA.
@@ -140,11 +140,13 @@ struct arc_write_callback {
140140
*/
141141
typedef struct l1arc_buf_hdr {
142142
kmutex_t b_freeze_lock;
143+
zio_cksum_t *b_freeze_cksum;
143144

144145
arc_buf_t *b_buf;
145-
uint32_t b_datacnt;
146+
uint32_t b_bufcnt;
146147
/* for waiting on writes to complete */
147148
kcondvar_t b_cv;
149+
uint8_t b_byteswap;
148150

149151

150152
/* protected by arc state mutex */
@@ -163,8 +165,7 @@ typedef struct l1arc_buf_hdr {
163165
refcount_t b_refcnt;
164166

165167
arc_callback_t *b_acb;
166-
/* temporary buffer holder for in-flight compressed data */
167-
void *b_tmp_cdata;
168+
void *b_pdata;
168169
} l1arc_buf_hdr_t;
169170

170171
typedef struct l2arc_dev {
@@ -185,10 +186,7 @@ typedef struct l2arc_buf_hdr {
185186
/* protected by arc_buf_hdr mutex */
186187
l2arc_dev_t *b_dev; /* L2ARC device */
187188
uint64_t b_daddr; /* disk address, offset byte */
188-
/* real alloc'd buffer size depending on b_compress applied */
189189
uint32_t b_hits;
190-
int32_t b_asize;
191-
uint8_t b_compress;
192190

193191
list_node_t b_l2node;
194192
} l2arc_buf_hdr_t;
@@ -202,20 +200,37 @@ struct arc_buf_hdr {
202200
/* protected by hash lock */
203201
dva_t b_dva;
204202
uint64_t b_birth;
205-
/*
206-
* Even though this checksum is only set/verified when a buffer is in
207-
* the L1 cache, it needs to be in the set of common fields because it
208-
* must be preserved from the time before a buffer is written out to
209-
* L2ARC until after it is read back in.
210-
*/
211-
zio_cksum_t *b_freeze_cksum;
212203

204+
arc_buf_contents_t b_type;
213205
arc_buf_hdr_t *b_hash_next;
214206
arc_flags_t b_flags;
215207

216-
/* immutable */
217-
int32_t b_size;
218-
uint64_t b_spa;
208+
/*
209+
* This field stores the size of the data buffer after
210+
* compression, and is set in the arc's zio completion handlers.
211+
* It is in units of SPA_MINBLOCKSIZE (e.g. 1 == 512 bytes).
212+
*
213+
* While the block pointers can store up to 32MB in their psize
214+
* field, we can only store up to 32MB minus 512B. This is due
215+
* to the bp using a bias of 1, whereas we use a bias of 0 (i.e.
216+
* a field of zeros represents 512B in the bp). We can't use a
217+
* bias of 1 since we need to reserve a psize of zero, here, to
218+
* represent holes and embedded blocks.
219+
*
220+
* This isn't a problem in practice, since the maximum size of a
221+
* buffer is limited to 16MB, so we never need to store 32MB in
222+
* this field. Even in the upstream illumos code base, the
223+
* maximum size of a buffer is limited to 16MB.
224+
*/
225+
uint16_t b_psize;
226+
227+
/*
228+
* This field stores the size of the data buffer before
229+
* compression, and cannot change once set. It is in units
230+
* of SPA_MINBLOCKSIZE (e.g. 2 == 1024 bytes)
231+
*/
232+
uint16_t b_lsize; /* immutable */
233+
uint64_t b_spa; /* immutable */
219234

220235
/* L2ARC fields. Undefined when not in L2ARC. */
221236
l2arc_buf_hdr_t b_l2hdr;

include/sys/dbuf.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <sys/zfs_context.h>
3737
#include <sys/refcount.h>
3838
#include <sys/zrlock.h>
39+
#include <sys/multilist.h>
3940

4041
#ifdef __cplusplus
4142
extern "C" {
@@ -228,6 +229,11 @@ typedef struct dmu_buf_impl {
228229
*/
229230
avl_node_t db_link;
230231

232+
/*
233+
* Link in dbuf_cache.
234+
*/
235+
multilist_node_t db_cache_link;
236+
231237
/* Data which is unique to data (leaf) blocks: */
232238

233239
/* User callback information. */
@@ -303,8 +309,7 @@ void dmu_buf_write_embedded(dmu_buf_t *dbuf, void *data,
303309
bp_embedded_type_t etype, enum zio_compress comp,
304310
int uncompressed_size, int compressed_size, int byteorder, dmu_tx_t *tx);
305311

306-
void dbuf_clear(dmu_buf_impl_t *db);
307-
void dbuf_evict(dmu_buf_impl_t *db);
312+
void dbuf_destroy(dmu_buf_impl_t *db);
308313

309314
void dbuf_unoverride(dbuf_dirty_record_t *dr);
310315
void dbuf_sync_list(list_t *list, int level, dmu_tx_t *tx);
@@ -342,10 +347,6 @@ boolean_t dbuf_is_metadata(dmu_buf_impl_t *db);
342347
(dbuf_is_metadata(_db) && \
343348
((_db)->db_objset->os_secondary_cache == ZFS_CACHE_METADATA)))
344349

345-
#define DBUF_IS_L2COMPRESSIBLE(_db) \
346-
((_db)->db_objset->os_compress != ZIO_COMPRESS_OFF || \
347-
(dbuf_is_metadata(_db) && zfs_mdcomp_disable == B_FALSE))
348-
349350
#ifdef ZFS_DEBUG
350351

351352
/*

include/sys/refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ int64_t refcount_remove(refcount_t *rc, void *holder_tag);
7070
int64_t refcount_add_many(refcount_t *rc, uint64_t number, void *holder_tag);
7171
int64_t refcount_remove_many(refcount_t *rc, uint64_t number, void *holder_tag);
7272
void refcount_transfer(refcount_t *dst, refcount_t *src);
73+
void refcount_transfer_ownership(refcount_t *, void *, void *);
7374

7475
void refcount_init(void);
7576
void refcount_fini(void);
@@ -97,6 +98,7 @@ typedef struct refcount {
9798
atomic_add_64(&(src)->rc_count, -__tmp); \
9899
atomic_add_64(&(dst)->rc_count, __tmp); \
99100
}
101+
#define refcount_transfer_ownership(rc, current_holder, new_holder)
100102

101103
#define refcount_init()
102104
#define refcount_fini()

include/sys/spa.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ _NOTE(CONSTCOND) } while (0)
135135
#define SPA_PSIZEBITS 16 /* PSIZE up to 32M (2^16 * 512) */
136136
#define SPA_ASIZEBITS 24 /* ASIZE up to 64 times larger */
137137

138+
#define SPA_COMPRESSBITS 7
139+
138140
/*
139141
* All SPA data is represented by 128-bit data virtual addresses (DVAs).
140142
* The members of the dva_t should be considered opaque outside the SPA.
@@ -363,8 +365,10 @@ _NOTE(CONSTCOND) } while (0)
363365
16, SPA_PSIZEBITS, SPA_MINBLOCKSHIFT, 1, x); \
364366
_NOTE(CONSTCOND) } while (0)
365367

366-
#define BP_GET_COMPRESS(bp) BF64_GET((bp)->blk_prop, 32, 7)
367-
#define BP_SET_COMPRESS(bp, x) BF64_SET((bp)->blk_prop, 32, 7, x)
368+
#define BP_GET_COMPRESS(bp) \
369+
BF64_GET((bp)->blk_prop, 32, SPA_COMPRESSBITS)
370+
#define BP_SET_COMPRESS(bp, x) \
371+
BF64_SET((bp)->blk_prop, 32, SPA_COMPRESSBITS, x)
368372

369373
#define BP_IS_EMBEDDED(bp) BF64_GET((bp)->blk_prop, 39, 1)
370374
#define BP_SET_EMBEDDED(bp, x) BF64_SET((bp)->blk_prop, 39, 1, x)

0 commit comments

Comments
 (0)