4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 #include <nbdkit-filter.h>
52 static uint64_t maxblock
= 512 * 1024 * 1024;
53 static uint32_t maxdepth
= 8;
56 xz_config (nbdkit_next_config
*next
, nbdkit_backend
*nxdata
,
57 const char *key
, const char *value
)
59 if (strcmp (key
, "xz-max-block") == 0) {
60 int64_t r
= nbdkit_parse_size (value
);
63 maxblock
= (uint64_t) r
;
66 else if (strcmp (key
, "xz-max-depth") == 0) {
67 if (nbdkit_parse_uint32_t ("xz-max-depth", value
, &maxdepth
) == -1)
70 nbdkit_error ("'xz-max-depth' parameter must be >= 1");
76 return next (nxdata
, key
, value
);
79 #define xz_config_help \
80 "xz-max-block=<SIZE> (optional) Maximum block size allowed (default: 512M)\n"\
81 "xz-max-depth=<N> (optional) Maximum blocks in cache (default: 4)\n"
83 /* The per-connection handle. */
91 /* Create the per-connection handle. */
93 xz_open (nbdkit_next_open
*next
, nbdkit_context
*nxdata
,
94 int readonly
, const char *exportname
, int is_tls
)
98 /* Always pass readonly=1 to the underlying plugin. */
99 if (next (nxdata
, 1, exportname
) == -1)
102 h
= malloc (sizeof *h
);
104 nbdkit_error ("malloc: %m");
108 h
->c
= new_blkcache (maxdepth
);
114 /* Initialized in xz_prepare. */
120 /* Free up the per-connection handle. */
122 xz_close (void *handle
)
124 struct xz_handle
*h
= handle
;
125 blkcache_stats stats
;
127 blkcache_get_stats (h
->c
, &stats
);
128 nbdkit_debug ("cache: hits = %zu, misses = %zu", stats
.hits
, stats
.misses
);
130 xzfile_close (h
->xz
);
131 free_blkcache (h
->c
);
136 xz_prepare (nbdkit_next
*next
, void *handle
,
139 struct xz_handle
*h
= handle
;
141 h
->xz
= xzfile_open (next
);
145 if (maxblock
< xzfile_max_uncompressed_block_size (h
->xz
)) {
146 nbdkit_error ("xz file largest block is bigger than maxblock\n"
147 "Either recompress the xz file with smaller blocks "
148 "(see nbdkit-xz-filter(1))\n"
149 "or make maxblock parameter bigger.\n"
150 "maxblock = %" PRIu64
" (bytes)\n"
151 "largest block in xz file = %" PRIu64
" (bytes)",
153 xzfile_max_uncompressed_block_size (h
->xz
));
162 xz_export_description (nbdkit_next
*next
,
165 const char *base
= next
->export_description (next
);
169 return nbdkit_printf_intern ("expansion of xz-compressed image: %s", base
);
172 /* Get the file size. */
174 xz_get_size (nbdkit_next
*next
, void *handle
)
176 struct xz_handle
*h
= handle
;
178 return xzfile_get_size (h
->xz
);
181 /* We need this because otherwise the layer below can_write is called
182 * and that might return true (eg. if the plugin has a pwrite method
183 * at all), resulting in writes being passed through to the layer
184 * below. This is possibly a bug in nbdkit.
187 xz_can_write (nbdkit_next
*next
,
193 /* Whatever the plugin says, this filter is consistent across connections. */
195 xz_can_multi_conn (nbdkit_next
*next
,
201 /* Similar to above. However xz files themselves do support
202 * sparseness so in future we should generate extents information. XXX
205 xz_can_extents (nbdkit_next
*next
,
213 xz_can_cache (nbdkit_next
*next
,
216 /* We are already operating as a cache regardless of the plugin's
217 * underlying .can_cache, but it's easiest to just rely on nbdkit's
218 * behavior of calling .pread for caching.
220 return NBDKIT_CACHE_EMULATE
;
223 /* Read data from the file. */
225 xz_pread (nbdkit_next
*next
,
226 void *handle
, void *buf
, uint32_t count
, uint64_t offset
,
227 uint32_t flags
, int *err
)
229 struct xz_handle
*h
= handle
;
231 uint64_t start
, size
;
234 /* Find the block in the cache. */
235 data
= get_block (h
->c
, offset
, &start
, &size
);
237 /* Not in the cache. We need to read the block from the xz file. */
238 data
= xzfile_read_block (h
->xz
, next
, flags
, err
,
239 offset
, &start
, &size
);
242 put_block (h
->c
, start
, size
, data
);
245 /* It's possible if the blocks are really small or oddly aligned or
246 * if the requests are large that we need to read the following
247 * block to satisfy the request.
250 if (start
+ size
- offset
< n
)
251 n
= start
+ size
- offset
;
253 memcpy (buf
, &data
[offset
-start
], n
);
258 return xz_pread (next
, h
, buf
, count
, offset
, flags
, err
);
263 static int xz_thread_model (void)
265 return NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS
;
268 static struct nbdkit_filter filter
= {
270 .longname
= "nbdkit XZ filter",
272 .config_help
= xz_config_help
,
273 .thread_model
= xz_thread_model
,
276 .prepare
= xz_prepare
,
277 .export_description
= xz_export_description
,
278 .get_size
= xz_get_size
,
279 .can_write
= xz_can_write
,
280 .can_extents
= xz_can_extents
,
281 .can_cache
= xz_can_cache
,
282 .can_multi_conn
= xz_can_multi_conn
,
286 NBDKIT_REGISTER_FILTER (filter
)