source: mainline/uspace/srv/volsrv/empty.c@ 395df52

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 395df52 was 363a504, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Fix empty partition detection to work with ISO 9660.

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * 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.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup volsrv
30 * @{
31 */
32/**
33 * @file Empty partition handling
34 * @brief
35 */
36
37#include <block.h>
38#include <errno.h>
39#include <io/log.h>
40#include <loc.h>
41#include <stdlib.h>
42
43#include "empty.h"
44
45/*
46 * The partition will be considered empty if at least a minimum number of
47 * bytes *and* blocks (whichever is larger) at the beginning and end of
48 * the partition is zero.
49 */
50enum {
51 min_empty_bytes = 16384,
52 /*
53 * First block in ISO 9660 that cannot be empty is the first
54 * volume descriptor at LBA 16
55 */
56 min_empty_blocks = 17
57};
58
59static bool mem_is_zero(void *buf, size_t size)
60{
61 uint8_t *bp;
62 size_t i;
63
64 bp = (uint8_t *)buf;
65 for (i = 0; i < size; i++) {
66 if (bp[i] != 0)
67 return false;
68 }
69
70 return true;
71}
72
73/** Calculate number of blocks to check.
74 *
75 * Will store to @a *ncb the number of blocks that should be checked
76 * at the beginning and end of device each.
77 *
78 * @param nblocks Total number of blocks on block device
79 * @param block_size Block size
80 * @param ncb Place to store number of blocks to check.
81 */
82static void calc_num_check_blocks(aoff64_t nblocks, size_t block_size,
83 aoff64_t *ncb)
84{
85 aoff64_t n;
86
87 /* Check first 16 kiB / 16 blocks, whichever is more */
88 n = (min_empty_bytes + block_size - 1) / block_size;
89 if (n < min_empty_blocks)
90 n = min_empty_blocks;
91 /*
92 * Limit to half of the device so we do not process the same blocks
93 * twice
94 */
95 if (n > (nblocks + 1) / 2)
96 n = (nblocks + 1) / 2;
97
98 *ncb = n;
99}
100
101int volsrv_part_is_empty(service_id_t sid, bool *rempty)
102{
103 int rc;
104 bool block_inited = false;
105 void *buf = NULL;
106 aoff64_t nblocks;
107 aoff64_t n;
108 aoff64_t i;
109 size_t block_size;
110 bool empty;
111
112 rc = block_init(sid, 2048);
113 if (rc != EOK) {
114 log_msg(LOG_DEFAULT, LVL_ERROR, "Error opening "
115 "block device service %zu", sid);
116 rc = EIO;
117 goto error;
118 }
119
120 block_inited = true;
121
122 rc = block_get_bsize(sid, &block_size);
123 if (rc != EOK) {
124 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
125 "block size.");
126 rc = EIO;
127 goto error;
128 }
129
130 rc = block_get_nblocks(sid, &nblocks);
131 if (rc != EOK) {
132 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
133 "number of blocks.");
134 rc = EIO;
135 goto error;
136 }
137
138 calc_num_check_blocks(nblocks, block_size, &n);
139
140 buf = calloc(block_size, 1);
141 if (buf == NULL) {
142 log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
143 rc = ENOMEM;
144 goto error;
145 }
146
147 empty = true;
148
149 for (i = 0; i < n; i++) {
150 rc = block_read_direct(sid, i, 1, buf);
151 if (rc != EOK) {
152 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
153 "reading blocks.");
154 rc = EIO;
155 goto error;
156 }
157
158 if (!mem_is_zero(buf, block_size)) {
159 empty = false;
160 goto done;
161 }
162 }
163
164 for (i = 0; i < n; i++) {
165 rc = block_read_direct(sid, nblocks - n + i, 1, buf);
166 if (rc != EOK) {
167 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
168 "reading blocks.");
169 rc = EIO;
170 goto error;
171 }
172
173 if (!mem_is_zero(buf, block_size)) {
174 empty = false;
175 goto done;
176 }
177 }
178
179done:
180 block_fini(sid);
181 free(buf);
182 *rempty = empty;
183 return EOK;
184error:
185 if (block_inited)
186 block_fini(sid);
187 if (buf != NULL)
188 free(buf);
189 return rc;
190}
191
192int volsrv_part_empty(service_id_t sid)
193{
194 int rc;
195 bool block_inited = false;
196 void *buf = NULL;
197 aoff64_t nblocks;
198 aoff64_t n;
199 aoff64_t i;
200 size_t block_size;
201
202 rc = block_init(sid, 2048);
203 if (rc != EOK) {
204 log_msg(LOG_DEFAULT, LVL_ERROR, "Error opening "
205 "block device service %zu", sid);
206 rc = EIO;
207 goto error;
208 }
209
210 block_inited = true;
211
212 rc = block_get_bsize(sid, &block_size);
213 if (rc != EOK) {
214 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
215 "block size.");
216 rc = EIO;
217 goto error;
218 }
219
220 rc = block_get_nblocks(sid, &nblocks);
221 if (rc != EOK) {
222 log_msg(LOG_DEFAULT, LVL_ERROR, "Error getting "
223 "number of blocks.");
224 rc = EIO;
225 goto error;
226 }
227
228 calc_num_check_blocks(nblocks, block_size, &n);
229
230 buf = calloc(block_size, 1);
231 if (buf == NULL) {
232 log_msg(LOG_DEFAULT, LVL_ERROR, "Error allocating buffer.");
233 rc = ENOMEM;
234 goto error;
235 }
236
237 for (i = 0; i < n; i++) {
238 rc = block_write_direct(sid, i, 1, buf);
239 if (rc != EOK) {
240 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
241 "reading blocks.");
242 rc = EIO;
243 goto error;
244 }
245 }
246
247 for (i = 0; i < n; i++) {
248 rc = block_write_direct(sid, nblocks - n + i, 1, buf);
249 if (rc != EOK) {
250 log_msg(LOG_DEFAULT, LVL_ERROR, "Error "
251 "reading blocks.");
252 rc = EIO;
253 goto error;
254 }
255 }
256
257 block_fini(sid);
258 free(buf);
259 return EOK;
260error:
261 if (block_inited)
262 block_fini(sid);
263 if (buf != NULL)
264 free(buf);
265 return rc;
266}
267
268/** @}
269 */
Note: See TracBrowser for help on using the repository browser.