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

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sm_disk_destroy
  2. sm_disk_extend
  3. sm_disk_get_nr_blocks
  4. sm_disk_get_nr_free
  5. sm_disk_get_count
  6. sm_disk_count_is_more_than_one
  7. sm_disk_set_count
  8. sm_disk_inc_block
  9. sm_disk_dec_block
  10. sm_disk_new_block
  11. sm_disk_commit
  12. sm_disk_root_size
  13. sm_disk_copy_root
  14. dm_sm_disk_create
  15. dm_sm_disk_open

   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  */
  24 struct 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 
  34 static 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 
  41 static 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 
  48 static 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 
  56 static 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 
  64 static 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 
  71 static 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         *result = count > 1;
  82 
  83         return 0;
  84 }
  85 
  86 static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
  87                              uint32_t count)
  88 {
  89         int r;
  90         uint32_t old_count;
  91         enum allocation_event ev;
  92         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
  93 
  94         r = sm_ll_insert(&smd->ll, b, count, &ev);
  95         if (!r) {
  96                 switch (ev) {
  97                 case SM_NONE:
  98                         break;
  99 
 100                 case SM_ALLOC:
 101                         /*
 102                          * This _must_ be free in the prior transaction
 103                          * otherwise we've lost atomicity.
 104                          */
 105                         smd->nr_allocated_this_transaction++;
 106                         break;
 107 
 108                 case SM_FREE:
 109                         /*
 110                          * It's only free if it's also free in the last
 111                          * transaction.
 112                          */
 113                         r = sm_ll_lookup(&smd->old_ll, b, &old_count);
 114                         if (r)
 115                                 return r;
 116 
 117                         if (!old_count)
 118                                 smd->nr_allocated_this_transaction--;
 119                         break;
 120                 }
 121         }
 122 
 123         return r;
 124 }
 125 
 126 static int sm_disk_inc_block(struct dm_space_map *sm, dm_block_t b)
 127 {
 128         int r;
 129         enum allocation_event ev;
 130         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 131 
 132         r = sm_ll_inc(&smd->ll, b, &ev);
 133         if (!r && (ev == SM_ALLOC))
 134                 /*
 135                  * This _must_ be free in the prior transaction
 136                  * otherwise we've lost atomicity.
 137                  */
 138                 smd->nr_allocated_this_transaction++;
 139 
 140         return r;
 141 }
 142 
 143 static int sm_disk_dec_block(struct dm_space_map *sm, dm_block_t b)
 144 {
 145         int r;
 146         uint32_t old_count;
 147         enum allocation_event ev;
 148         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 149 
 150         r = sm_ll_dec(&smd->ll, b, &ev);
 151         if (!r && (ev == SM_FREE)) {
 152                 /*
 153                  * It's only free if it's also free in the last
 154                  * transaction.
 155                  */
 156                 r = sm_ll_lookup(&smd->old_ll, b, &old_count);
 157                 if (!r && !old_count)
 158                         smd->nr_allocated_this_transaction--;
 159         }
 160 
 161         return r;
 162 }
 163 
 164 static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
 165 {
 166         int r;
 167         enum allocation_event ev;
 168         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 169 
 170         /*
 171          * Any block we allocate has to be free in both the old and current ll.
 172          */
 173         r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);
 174         if (r)
 175                 return r;
 176 
 177         smd->begin = *b + 1;
 178         r = sm_ll_inc(&smd->ll, *b, &ev);
 179         if (!r) {
 180                 BUG_ON(ev != SM_ALLOC);
 181                 smd->nr_allocated_this_transaction++;
 182         }
 183 
 184         return r;
 185 }
 186 
 187 static int sm_disk_commit(struct dm_space_map *sm)
 188 {
 189         int r;
 190         dm_block_t nr_free;
 191         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 192 
 193         r = sm_disk_get_nr_free(sm, &nr_free);
 194         if (r)
 195                 return r;
 196 
 197         r = sm_ll_commit(&smd->ll);
 198         if (r)
 199                 return r;
 200 
 201         memcpy(&smd->old_ll, &smd->ll, sizeof(smd->old_ll));
 202         smd->begin = 0;
 203         smd->nr_allocated_this_transaction = 0;
 204 
 205         r = sm_disk_get_nr_free(sm, &nr_free);
 206         if (r)
 207                 return r;
 208 
 209         return 0;
 210 }
 211 
 212 static int sm_disk_root_size(struct dm_space_map *sm, size_t *result)
 213 {
 214         *result = sizeof(struct disk_sm_root);
 215 
 216         return 0;
 217 }
 218 
 219 static int sm_disk_copy_root(struct dm_space_map *sm, void *where_le, size_t max)
 220 {
 221         struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
 222         struct disk_sm_root root_le;
 223 
 224         root_le.nr_blocks = cpu_to_le64(smd->ll.nr_blocks);
 225         root_le.nr_allocated = cpu_to_le64(smd->ll.nr_allocated);
 226         root_le.bitmap_root = cpu_to_le64(smd->ll.bitmap_root);
 227         root_le.ref_count_root = cpu_to_le64(smd->ll.ref_count_root);
 228 
 229         if (max < sizeof(root_le))
 230                 return -ENOSPC;
 231 
 232         memcpy(where_le, &root_le, sizeof(root_le));
 233 
 234         return 0;
 235 }
 236 
 237 /*----------------------------------------------------------------*/
 238 
 239 static struct dm_space_map ops = {
 240         .destroy = sm_disk_destroy,
 241         .extend = sm_disk_extend,
 242         .get_nr_blocks = sm_disk_get_nr_blocks,
 243         .get_nr_free = sm_disk_get_nr_free,
 244         .get_count = sm_disk_get_count,
 245         .count_is_more_than_one = sm_disk_count_is_more_than_one,
 246         .set_count = sm_disk_set_count,
 247         .inc_block = sm_disk_inc_block,
 248         .dec_block = sm_disk_dec_block,
 249         .new_block = sm_disk_new_block,
 250         .commit = sm_disk_commit,
 251         .root_size = sm_disk_root_size,
 252         .copy_root = sm_disk_copy_root,
 253         .register_threshold_callback = NULL
 254 };
 255 
 256 struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
 257                                        dm_block_t nr_blocks)
 258 {
 259         int r;
 260         struct sm_disk *smd;
 261 
 262         smd = kmalloc(sizeof(*smd), GFP_KERNEL);
 263         if (!smd)
 264                 return ERR_PTR(-ENOMEM);
 265 
 266         smd->begin = 0;
 267         smd->nr_allocated_this_transaction = 0;
 268         memcpy(&smd->sm, &ops, sizeof(smd->sm));
 269 
 270         r = sm_ll_new_disk(&smd->ll, tm);
 271         if (r)
 272                 goto bad;
 273 
 274         r = sm_ll_extend(&smd->ll, nr_blocks);
 275         if (r)
 276                 goto bad;
 277 
 278         r = sm_disk_commit(&smd->sm);
 279         if (r)
 280                 goto bad;
 281 
 282         return &smd->sm;
 283 
 284 bad:
 285         kfree(smd);
 286         return ERR_PTR(r);
 287 }
 288 EXPORT_SYMBOL_GPL(dm_sm_disk_create);
 289 
 290 struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm,
 291                                      void *root_le, size_t len)
 292 {
 293         int r;
 294         struct sm_disk *smd;
 295 
 296         smd = kmalloc(sizeof(*smd), GFP_KERNEL);
 297         if (!smd)
 298                 return ERR_PTR(-ENOMEM);
 299 
 300         smd->begin = 0;
 301         smd->nr_allocated_this_transaction = 0;
 302         memcpy(&smd->sm, &ops, sizeof(smd->sm));
 303 
 304         r = sm_ll_open_disk(&smd->ll, tm, root_le, len);
 305         if (r)
 306                 goto bad;
 307 
 308         r = sm_disk_commit(&smd->sm);
 309         if (r)
 310                 goto bad;
 311 
 312         return &smd->sm;
 313 
 314 bad:
 315         kfree(smd);
 316         return ERR_PTR(r);
 317 }
 318 EXPORT_SYMBOL_GPL(dm_sm_disk_open);
 319 
 320 /*----------------------------------------------------------------*/

/* [<][>][^][v][top][bottom][index][help] */