Root/drivers/md/persistent-data/dm-space-map-disk.c

1/*
2 * Copyright (C) 2011 Red Hat, Inc.
3 *
4 * This file is released under the GPL.
5 */
6
7#include "dm-space-map-common.h"
8#include "dm-space-map-disk.h"
9#include "dm-space-map.h"
10#include "dm-transaction-manager.h"
11
12#include <linux/list.h>
13#include <linux/slab.h>
14#include <linux/export.h>
15#include <linux/device-mapper.h>
16
17#define DM_MSG_PREFIX "space map disk"
18
19/*----------------------------------------------------------------*/
20
21/*
22 * Space map interface.
23 */
24struct sm_disk {
25    struct dm_space_map sm;
26
27    struct ll_disk ll;
28    struct ll_disk old_ll;
29
30    dm_block_t begin;
31    dm_block_t nr_allocated_this_transaction;
32};
33
34static void sm_disk_destroy(struct dm_space_map *sm)
35{
36    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
37
38    kfree(smd);
39}
40
41static int sm_disk_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
42{
43    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
44
45    return sm_ll_extend(&smd->ll, extra_blocks);
46}
47
48static int sm_disk_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
49{
50    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
51    *count = smd->old_ll.nr_blocks;
52
53    return 0;
54}
55
56static int sm_disk_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
57{
58    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
59    *count = (smd->old_ll.nr_blocks - smd->old_ll.nr_allocated) - smd->nr_allocated_this_transaction;
60
61    return 0;
62}
63
64static int sm_disk_get_count(struct dm_space_map *sm, dm_block_t b,
65                 uint32_t *result)
66{
67    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
68    return sm_ll_lookup(&smd->ll, b, result);
69}
70
71static int sm_disk_count_is_more_than_one(struct dm_space_map *sm, dm_block_t b,
72                      int *result)
73{
74    int r;
75    uint32_t count;
76
77    r = sm_disk_get_count(sm, b, &count);
78    if (r)
79        return r;
80
81    return count > 1;
82}
83
84static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
85                 uint32_t count)
86{
87    int r;
88    uint32_t old_count;
89    enum allocation_event ev;
90    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
91
92    r = sm_ll_insert(&smd->ll, b, count, &ev);
93    if (!r) {
94        switch (ev) {
95        case SM_NONE:
96            break;
97
98        case SM_ALLOC:
99            /*
100             * This _must_ be free in the prior transaction
101             * otherwise we've lost atomicity.
102             */
103            smd->nr_allocated_this_transaction++;
104            break;
105
106        case SM_FREE:
107            /*
108             * It's only free if it's also free in the last
109             * transaction.
110             */
111            r = sm_ll_lookup(&smd->old_ll, b, &old_count);
112            if (r)
113                return r;
114
115            if (!old_count)
116                smd->nr_allocated_this_transaction--;
117            break;
118        }
119    }
120
121    return r;
122}
123
124static int sm_disk_inc_block(struct dm_space_map *sm, dm_block_t b)
125{
126    int r;
127    enum allocation_event ev;
128    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
129
130    r = sm_ll_inc(&smd->ll, b, &ev);
131    if (!r && (ev == SM_ALLOC))
132        /*
133         * This _must_ be free in the prior transaction
134         * otherwise we've lost atomicity.
135         */
136        smd->nr_allocated_this_transaction++;
137
138    return r;
139}
140
141static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b)
142{
143    int r;
144    uint32_t old_count;
145    enum allocation_event ev;
146    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
147
148    r = sm_ll_dec(&smd->ll, b, &ev);
149    if (!r && (ev == SM_FREE)) {
150        /*
151         * It's only free if it's also free in the last
152         * transaction.
153         */
154        r = sm_ll_lookup(&smd->old_ll, b, &old_count);
155        if (r)
156            return r;
157
158        if (!old_count)
159            smd->nr_allocated_this_transaction--;
160    }
161
162    return r;
163}
164
165static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
166{
167    int r;
168    enum allocation_event ev;
169    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
170
171    /* FIXME: we should loop round a couple of times */
172    r = sm_ll_find_free_block(&smd->old_ll, smd->begin, smd->old_ll.nr_blocks, b);
173    if (r)
174        return r;
175
176    smd->begin = *b + 1;
177    r = sm_ll_inc(&smd->ll, *b, &ev);
178    if (!r) {
179        BUG_ON(ev != SM_ALLOC);
180        smd->nr_allocated_this_transaction++;
181    }
182
183    return r;
184}
185
186static int sm_disk_commit(struct dm_space_map *sm)
187{
188    int r;
189    dm_block_t nr_free;
190    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
191
192    r = sm_disk_get_nr_free(sm, &nr_free);
193    if (r)
194        return r;
195
196    r = sm_ll_commit(&smd->ll);
197    if (r)
198        return r;
199
200    memcpy(&smd->old_ll, &smd->ll, sizeof(smd->old_ll));
201    smd->begin = 0;
202    smd->nr_allocated_this_transaction = 0;
203
204    r = sm_disk_get_nr_free(sm, &nr_free);
205    if (r)
206        return r;
207
208    return 0;
209}
210
211static int sm_disk_root_size(struct dm_space_map *sm, size_t *result)
212{
213    *result = sizeof(struct disk_sm_root);
214
215    return 0;
216}
217
218static int sm_disk_copy_root(struct dm_space_map *sm, void *where_le, size_t max)
219{
220    struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
221    struct disk_sm_root root_le;
222
223    root_le.nr_blocks = cpu_to_le64(smd->ll.nr_blocks);
224    root_le.nr_allocated = cpu_to_le64(smd->ll.nr_allocated);
225    root_le.bitmap_root = cpu_to_le64(smd->ll.bitmap_root);
226    root_le.ref_count_root = cpu_to_le64(smd->ll.ref_count_root);
227
228    if (max < sizeof(root_le))
229        return -ENOSPC;
230
231    memcpy(where_le, &root_le, sizeof(root_le));
232
233    return 0;
234}
235
236/*----------------------------------------------------------------*/
237
238static struct dm_space_map ops = {
239    .destroy = sm_disk_destroy,
240    .extend = sm_disk_extend,
241    .get_nr_blocks = sm_disk_get_nr_blocks,
242    .get_nr_free = sm_disk_get_nr_free,
243    .get_count = sm_disk_get_count,
244    .count_is_more_than_one = sm_disk_count_is_more_than_one,
245    .set_count = sm_disk_set_count,
246    .inc_block = sm_disk_inc_block,
247    .dec_block = sm_disk_dec_block,
248    .new_block = sm_disk_new_block,
249    .commit = sm_disk_commit,
250    .root_size = sm_disk_root_size,
251    .copy_root = sm_disk_copy_root
252};
253
254struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
255                       dm_block_t nr_blocks)
256{
257    int r;
258    struct sm_disk *smd;
259
260    smd = kmalloc(sizeof(*smd), GFP_KERNEL);
261    if (!smd)
262        return ERR_PTR(-ENOMEM);
263
264    smd->begin = 0;
265    smd->nr_allocated_this_transaction = 0;
266    memcpy(&smd->sm, &ops, sizeof(smd->sm));
267
268    r = sm_ll_new_disk(&smd->ll, tm);
269    if (r)
270        goto bad;
271
272    r = sm_ll_extend(&smd->ll, nr_blocks);
273    if (r)
274        goto bad;
275
276    r = sm_disk_commit(&smd->sm);
277    if (r)
278        goto bad;
279
280    return &smd->sm;
281
282bad:
283    kfree(smd);
284    return ERR_PTR(r);
285}
286EXPORT_SYMBOL_GPL(dm_sm_disk_create);
287
288struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm,
289                     void *root_le, size_t len)
290{
291    int r;
292    struct sm_disk *smd;
293
294    smd = kmalloc(sizeof(*smd), GFP_KERNEL);
295    if (!smd)
296        return ERR_PTR(-ENOMEM);
297
298    smd->begin = 0;
299    smd->nr_allocated_this_transaction = 0;
300    memcpy(&smd->sm, &ops, sizeof(smd->sm));
301
302    r = sm_ll_open_disk(&smd->ll, tm, root_le, len);
303    if (r)
304        goto bad;
305
306    r = sm_disk_commit(&smd->sm);
307    if (r)
308        goto bad;
309
310    return &smd->sm;
311
312bad:
313    kfree(smd);
314    return ERR_PTR(r);
315}
316EXPORT_SYMBOL_GPL(dm_sm_disk_open);
317
318/*----------------------------------------------------------------*/
319

Archive Download this file



interactive