~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/md/persistent-data/dm-space-map-checker.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Red Hat, Inc.
 
3
 *
 
4
 * This file is released under the GPL.
 
5
 */
 
6
 
 
7
#include "dm-space-map-checker.h"
 
8
 
 
9
#include <linux/device-mapper.h>
 
10
#include <linux/export.h>
 
11
 
 
12
#ifdef CONFIG_DM_DEBUG_SPACE_MAPS
 
13
 
 
14
#define DM_MSG_PREFIX "space map checker"
 
15
 
 
16
/*----------------------------------------------------------------*/
 
17
 
 
18
struct count_array {
 
19
        dm_block_t nr;
 
20
        dm_block_t nr_free;
 
21
 
 
22
        uint32_t *counts;
 
23
};
 
24
 
 
25
static int ca_get_count(struct count_array *ca, dm_block_t b, uint32_t *count)
 
26
{
 
27
        if (b >= ca->nr)
 
28
                return -EINVAL;
 
29
 
 
30
        *count = ca->counts[b];
 
31
        return 0;
 
32
}
 
33
 
 
34
static int ca_count_more_than_one(struct count_array *ca, dm_block_t b, int *r)
 
35
{
 
36
        if (b >= ca->nr)
 
37
                return -EINVAL;
 
38
 
 
39
        *r = ca->counts[b] > 1;
 
40
        return 0;
 
41
}
 
42
 
 
43
static int ca_set_count(struct count_array *ca, dm_block_t b, uint32_t count)
 
44
{
 
45
        uint32_t old_count;
 
46
 
 
47
        if (b >= ca->nr)
 
48
                return -EINVAL;
 
49
 
 
50
        old_count = ca->counts[b];
 
51
 
 
52
        if (!count && old_count)
 
53
                ca->nr_free++;
 
54
 
 
55
        else if (count && !old_count)
 
56
                ca->nr_free--;
 
57
 
 
58
        ca->counts[b] = count;
 
59
        return 0;
 
60
}
 
61
 
 
62
static int ca_inc_block(struct count_array *ca, dm_block_t b)
 
63
{
 
64
        if (b >= ca->nr)
 
65
                return -EINVAL;
 
66
 
 
67
        ca_set_count(ca, b, ca->counts[b] + 1);
 
68
        return 0;
 
69
}
 
70
 
 
71
static int ca_dec_block(struct count_array *ca, dm_block_t b)
 
72
{
 
73
        if (b >= ca->nr)
 
74
                return -EINVAL;
 
75
 
 
76
        BUG_ON(ca->counts[b] == 0);
 
77
        ca_set_count(ca, b, ca->counts[b] - 1);
 
78
        return 0;
 
79
}
 
80
 
 
81
static int ca_create(struct count_array *ca, struct dm_space_map *sm)
 
82
{
 
83
        int r;
 
84
        dm_block_t nr_blocks;
 
85
 
 
86
        r = dm_sm_get_nr_blocks(sm, &nr_blocks);
 
87
        if (r)
 
88
                return r;
 
89
 
 
90
        ca->nr = nr_blocks;
 
91
        ca->nr_free = nr_blocks;
 
92
        ca->counts = kzalloc(sizeof(*ca->counts) * nr_blocks, GFP_KERNEL);
 
93
        if (!ca->counts)
 
94
                return -ENOMEM;
 
95
 
 
96
        return 0;
 
97
}
 
98
 
 
99
static int ca_load(struct count_array *ca, struct dm_space_map *sm)
 
100
{
 
101
        int r;
 
102
        uint32_t count;
 
103
        dm_block_t nr_blocks, i;
 
104
 
 
105
        r = dm_sm_get_nr_blocks(sm, &nr_blocks);
 
106
        if (r)
 
107
                return r;
 
108
 
 
109
        BUG_ON(ca->nr != nr_blocks);
 
110
 
 
111
        DMWARN("Loading debug space map from disk.  This may take some time");
 
112
        for (i = 0; i < nr_blocks; i++) {
 
113
                r = dm_sm_get_count(sm, i, &count);
 
114
                if (r) {
 
115
                        DMERR("load failed");
 
116
                        return r;
 
117
                }
 
118
 
 
119
                ca_set_count(ca, i, count);
 
120
        }
 
121
        DMWARN("Load complete");
 
122
 
 
123
        return 0;
 
124
}
 
125
 
 
126
static int ca_extend(struct count_array *ca, dm_block_t extra_blocks)
 
127
{
 
128
        dm_block_t nr_blocks = ca->nr + extra_blocks;
 
129
        uint32_t *counts = kzalloc(sizeof(*counts) * nr_blocks, GFP_KERNEL);
 
130
        if (!counts)
 
131
                return -ENOMEM;
 
132
 
 
133
        memcpy(counts, ca->counts, sizeof(*counts) * ca->nr);
 
134
        kfree(ca->counts);
 
135
        ca->nr = nr_blocks;
 
136
        ca->nr_free += extra_blocks;
 
137
        ca->counts = counts;
 
138
        return 0;
 
139
}
 
140
 
 
141
static int ca_commit(struct count_array *old, struct count_array *new)
 
142
{
 
143
        if (old->nr != new->nr) {
 
144
                BUG_ON(old->nr > new->nr);
 
145
                ca_extend(old, new->nr - old->nr);
 
146
        }
 
147
 
 
148
        BUG_ON(old->nr != new->nr);
 
149
        old->nr_free = new->nr_free;
 
150
        memcpy(old->counts, new->counts, sizeof(*old->counts) * old->nr);
 
151
        return 0;
 
152
}
 
153
 
 
154
static void ca_destroy(struct count_array *ca)
 
155
{
 
156
        kfree(ca->counts);
 
157
}
 
158
 
 
159
/*----------------------------------------------------------------*/
 
160
 
 
161
struct sm_checker {
 
162
        struct dm_space_map sm;
 
163
 
 
164
        struct count_array old_counts;
 
165
        struct count_array counts;
 
166
 
 
167
        struct dm_space_map *real_sm;
 
168
};
 
169
 
 
170
static void sm_checker_destroy(struct dm_space_map *sm)
 
171
{
 
172
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
173
 
 
174
        dm_sm_destroy(smc->real_sm);
 
175
        ca_destroy(&smc->old_counts);
 
176
        ca_destroy(&smc->counts);
 
177
        kfree(smc);
 
178
}
 
179
 
 
180
static int sm_checker_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
 
181
{
 
182
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
183
        int r = dm_sm_get_nr_blocks(smc->real_sm, count);
 
184
        if (!r)
 
185
                BUG_ON(smc->old_counts.nr != *count);
 
186
        return r;
 
187
}
 
188
 
 
189
static int sm_checker_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
 
190
{
 
191
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
192
        int r = dm_sm_get_nr_free(smc->real_sm, count);
 
193
        if (!r) {
 
194
                /*
 
195
                 * Slow, but we know it's correct.
 
196
                 */
 
197
                dm_block_t b, n = 0;
 
198
                for (b = 0; b < smc->old_counts.nr; b++)
 
199
                        if (smc->old_counts.counts[b] == 0 &&
 
200
                            smc->counts.counts[b] == 0)
 
201
                                n++;
 
202
 
 
203
                if (n != *count)
 
204
                        DMERR("free block counts differ, checker %u, sm-disk:%u",
 
205
                              (unsigned) n, (unsigned) *count);
 
206
        }
 
207
        return r;
 
208
}
 
209
 
 
210
static int sm_checker_new_block(struct dm_space_map *sm, dm_block_t *b)
 
211
{
 
212
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
213
        int r = dm_sm_new_block(smc->real_sm, b);
 
214
 
 
215
        if (!r) {
 
216
                BUG_ON(*b >= smc->old_counts.nr);
 
217
                BUG_ON(smc->old_counts.counts[*b] != 0);
 
218
                BUG_ON(*b >= smc->counts.nr);
 
219
                BUG_ON(smc->counts.counts[*b] != 0);
 
220
                ca_set_count(&smc->counts, *b, 1);
 
221
        }
 
222
 
 
223
        return r;
 
224
}
 
225
 
 
226
static int sm_checker_inc_block(struct dm_space_map *sm, dm_block_t b)
 
227
{
 
228
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
229
        int r = dm_sm_inc_block(smc->real_sm, b);
 
230
        int r2 = ca_inc_block(&smc->counts, b);
 
231
        BUG_ON(r != r2);
 
232
        return r;
 
233
}
 
234
 
 
235
static int sm_checker_dec_block(struct dm_space_map *sm, dm_block_t b)
 
236
{
 
237
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
238
        int r = dm_sm_dec_block(smc->real_sm, b);
 
239
        int r2 = ca_dec_block(&smc->counts, b);
 
240
        BUG_ON(r != r2);
 
241
        return r;
 
242
}
 
243
 
 
244
static int sm_checker_get_count(struct dm_space_map *sm, dm_block_t b, uint32_t *result)
 
245
{
 
246
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
247
        uint32_t result2 = 0;
 
248
        int r = dm_sm_get_count(smc->real_sm, b, result);
 
249
        int r2 = ca_get_count(&smc->counts, b, &result2);
 
250
 
 
251
        BUG_ON(r != r2);
 
252
        if (!r)
 
253
                BUG_ON(*result != result2);
 
254
        return r;
 
255
}
 
256
 
 
257
static int sm_checker_count_more_than_one(struct dm_space_map *sm, dm_block_t b, int *result)
 
258
{
 
259
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
260
        int result2 = 0;
 
261
        int r = dm_sm_count_is_more_than_one(smc->real_sm, b, result);
 
262
        int r2 = ca_count_more_than_one(&smc->counts, b, &result2);
 
263
 
 
264
        BUG_ON(r != r2);
 
265
        if (!r)
 
266
                BUG_ON(!(*result) && result2);
 
267
        return r;
 
268
}
 
269
 
 
270
static int sm_checker_set_count(struct dm_space_map *sm, dm_block_t b, uint32_t count)
 
271
{
 
272
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
273
        uint32_t old_rc;
 
274
        int r = dm_sm_set_count(smc->real_sm, b, count);
 
275
        int r2;
 
276
 
 
277
        BUG_ON(b >= smc->counts.nr);
 
278
        old_rc = smc->counts.counts[b];
 
279
        r2 = ca_set_count(&smc->counts, b, count);
 
280
        BUG_ON(r != r2);
 
281
 
 
282
        return r;
 
283
}
 
284
 
 
285
static int sm_checker_commit(struct dm_space_map *sm)
 
286
{
 
287
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
288
        int r;
 
289
 
 
290
        r = dm_sm_commit(smc->real_sm);
 
291
        if (r)
 
292
                return r;
 
293
 
 
294
        r = ca_commit(&smc->old_counts, &smc->counts);
 
295
        if (r)
 
296
                return r;
 
297
 
 
298
        return 0;
 
299
}
 
300
 
 
301
static int sm_checker_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
 
302
{
 
303
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
304
        int r = dm_sm_extend(smc->real_sm, extra_blocks);
 
305
        if (r)
 
306
                return r;
 
307
 
 
308
        return ca_extend(&smc->counts, extra_blocks);
 
309
}
 
310
 
 
311
static int sm_checker_root_size(struct dm_space_map *sm, size_t *result)
 
312
{
 
313
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
314
        return dm_sm_root_size(smc->real_sm, result);
 
315
}
 
316
 
 
317
static int sm_checker_copy_root(struct dm_space_map *sm, void *copy_to_here_le, size_t len)
 
318
{
 
319
        struct sm_checker *smc = container_of(sm, struct sm_checker, sm);
 
320
        return dm_sm_copy_root(smc->real_sm, copy_to_here_le, len);
 
321
}
 
322
 
 
323
/*----------------------------------------------------------------*/
 
324
 
 
325
static struct dm_space_map ops_ = {
 
326
        .destroy = sm_checker_destroy,
 
327
        .get_nr_blocks = sm_checker_get_nr_blocks,
 
328
        .get_nr_free = sm_checker_get_nr_free,
 
329
        .inc_block = sm_checker_inc_block,
 
330
        .dec_block = sm_checker_dec_block,
 
331
        .new_block = sm_checker_new_block,
 
332
        .get_count = sm_checker_get_count,
 
333
        .count_is_more_than_one = sm_checker_count_more_than_one,
 
334
        .set_count = sm_checker_set_count,
 
335
        .commit = sm_checker_commit,
 
336
        .extend = sm_checker_extend,
 
337
        .root_size = sm_checker_root_size,
 
338
        .copy_root = sm_checker_copy_root
 
339
};
 
340
 
 
341
struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
 
342
{
 
343
        int r;
 
344
        struct sm_checker *smc;
 
345
 
 
346
        if (!sm)
 
347
                return NULL;
 
348
 
 
349
        smc = kmalloc(sizeof(*smc), GFP_KERNEL);
 
350
        if (!smc)
 
351
                return NULL;
 
352
 
 
353
        memcpy(&smc->sm, &ops_, sizeof(smc->sm));
 
354
        r = ca_create(&smc->old_counts, sm);
 
355
        if (r) {
 
356
                kfree(smc);
 
357
                return NULL;
 
358
        }
 
359
 
 
360
        r = ca_create(&smc->counts, sm);
 
361
        if (r) {
 
362
                ca_destroy(&smc->old_counts);
 
363
                kfree(smc);
 
364
                return NULL;
 
365
        }
 
366
 
 
367
        smc->real_sm = sm;
 
368
 
 
369
        r = ca_load(&smc->counts, sm);
 
370
        if (r) {
 
371
                ca_destroy(&smc->counts);
 
372
                ca_destroy(&smc->old_counts);
 
373
                kfree(smc);
 
374
                return NULL;
 
375
        }
 
376
 
 
377
        r = ca_commit(&smc->old_counts, &smc->counts);
 
378
        if (r) {
 
379
                ca_destroy(&smc->counts);
 
380
                ca_destroy(&smc->old_counts);
 
381
                kfree(smc);
 
382
                return NULL;
 
383
        }
 
384
 
 
385
        return &smc->sm;
 
386
}
 
387
EXPORT_SYMBOL_GPL(dm_sm_checker_create);
 
388
 
 
389
struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
 
390
{
 
391
        int r;
 
392
        struct sm_checker *smc;
 
393
 
 
394
        if (!sm)
 
395
                return NULL;
 
396
 
 
397
        smc = kmalloc(sizeof(*smc), GFP_KERNEL);
 
398
        if (!smc)
 
399
                return NULL;
 
400
 
 
401
        memcpy(&smc->sm, &ops_, sizeof(smc->sm));
 
402
        r = ca_create(&smc->old_counts, sm);
 
403
        if (r) {
 
404
                kfree(smc);
 
405
                return NULL;
 
406
        }
 
407
 
 
408
        r = ca_create(&smc->counts, sm);
 
409
        if (r) {
 
410
                ca_destroy(&smc->old_counts);
 
411
                kfree(smc);
 
412
                return NULL;
 
413
        }
 
414
 
 
415
        smc->real_sm = sm;
 
416
        return &smc->sm;
 
417
}
 
418
EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh);
 
419
 
 
420
/*----------------------------------------------------------------*/
 
421
 
 
422
#else
 
423
 
 
424
struct dm_space_map *dm_sm_checker_create(struct dm_space_map *sm)
 
425
{
 
426
        return sm;
 
427
}
 
428
EXPORT_SYMBOL_GPL(dm_sm_checker_create);
 
429
 
 
430
struct dm_space_map *dm_sm_checker_create_fresh(struct dm_space_map *sm)
 
431
{
 
432
        return sm;
 
433
}
 
434
EXPORT_SYMBOL_GPL(dm_sm_checker_create_fresh);
 
435
 
 
436
/*----------------------------------------------------------------*/
 
437
 
 
438
#endif