Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2011 Red Hat, Inc.
0003  *
0004  * This file is released under the GPL.
0005  */
0006 
0007 #include "dm-space-map-common.h"
0008 #include "dm-space-map-disk.h"
0009 #include "dm-space-map.h"
0010 #include "dm-transaction-manager.h"
0011 
0012 #include <linux/list.h>
0013 #include <linux/slab.h>
0014 #include <linux/export.h>
0015 #include <linux/device-mapper.h>
0016 
0017 #define DM_MSG_PREFIX "space map disk"
0018 
0019 /*----------------------------------------------------------------*/
0020 
0021 /*
0022  * Space map interface.
0023  */
0024 struct sm_disk {
0025     struct dm_space_map sm;
0026 
0027     struct ll_disk ll;
0028     struct ll_disk old_ll;
0029 
0030     dm_block_t begin;
0031     dm_block_t nr_allocated_this_transaction;
0032 };
0033 
0034 static void sm_disk_destroy(struct dm_space_map *sm)
0035 {
0036     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0037 
0038     kfree(smd);
0039 }
0040 
0041 static int sm_disk_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
0042 {
0043     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0044 
0045     return sm_ll_extend(&smd->ll, extra_blocks);
0046 }
0047 
0048 static int sm_disk_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
0049 {
0050     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0051     *count = smd->old_ll.nr_blocks;
0052 
0053     return 0;
0054 }
0055 
0056 static int sm_disk_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
0057 {
0058     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0059     *count = (smd->old_ll.nr_blocks - smd->old_ll.nr_allocated) - smd->nr_allocated_this_transaction;
0060 
0061     return 0;
0062 }
0063 
0064 static int sm_disk_get_count(struct dm_space_map *sm, dm_block_t b,
0065                  uint32_t *result)
0066 {
0067     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0068     return sm_ll_lookup(&smd->ll, b, result);
0069 }
0070 
0071 static int sm_disk_count_is_more_than_one(struct dm_space_map *sm, dm_block_t b,
0072                       int *result)
0073 {
0074     int r;
0075     uint32_t count;
0076 
0077     r = sm_disk_get_count(sm, b, &count);
0078     if (r)
0079         return r;
0080 
0081     *result = count > 1;
0082 
0083     return 0;
0084 }
0085 
0086 static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
0087                  uint32_t count)
0088 {
0089     int r;
0090     int32_t nr_allocations;
0091     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0092 
0093     r = sm_ll_insert(&smd->ll, b, count, &nr_allocations);
0094     if (!r) {
0095         smd->nr_allocated_this_transaction += nr_allocations;
0096     }
0097 
0098     return r;
0099 }
0100 
0101 static int sm_disk_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
0102 {
0103     int r;
0104     int32_t nr_allocations;
0105     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0106 
0107     r = sm_ll_inc(&smd->ll, b, e, &nr_allocations);
0108     if (!r)
0109         smd->nr_allocated_this_transaction += nr_allocations;
0110 
0111     return r;
0112 }
0113 
0114 static int sm_disk_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
0115 {
0116     int r;
0117     int32_t nr_allocations;
0118     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0119 
0120     r = sm_ll_dec(&smd->ll, b, e, &nr_allocations);
0121     if (!r)
0122         smd->nr_allocated_this_transaction += nr_allocations;
0123 
0124     return r;
0125 }
0126 
0127 static int sm_disk_new_block(struct dm_space_map *sm, dm_block_t *b)
0128 {
0129     int r;
0130     int32_t nr_allocations;
0131     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0132 
0133     /*
0134      * Any block we allocate has to be free in both the old and current ll.
0135      */
0136     r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);
0137     if (r == -ENOSPC) {
0138         /*
0139          * There's no free block between smd->begin and the end of the metadata device.
0140          * We search before smd->begin in case something has been freed.
0141          */
0142         r = sm_ll_find_common_free_block(&smd->old_ll, &smd->ll, 0, smd->begin, b);
0143     }
0144 
0145     if (r)
0146         return r;
0147 
0148     smd->begin = *b + 1;
0149     r = sm_ll_inc(&smd->ll, *b, *b + 1, &nr_allocations);
0150     if (!r) {
0151         smd->nr_allocated_this_transaction += nr_allocations;
0152     }
0153 
0154     return r;
0155 }
0156 
0157 static int sm_disk_commit(struct dm_space_map *sm)
0158 {
0159     int r;
0160     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0161 
0162     r = sm_ll_commit(&smd->ll);
0163     if (r)
0164         return r;
0165 
0166     memcpy(&smd->old_ll, &smd->ll, sizeof(smd->old_ll));
0167     smd->nr_allocated_this_transaction = 0;
0168 
0169     return 0;
0170 }
0171 
0172 static int sm_disk_root_size(struct dm_space_map *sm, size_t *result)
0173 {
0174     *result = sizeof(struct disk_sm_root);
0175 
0176     return 0;
0177 }
0178 
0179 static int sm_disk_copy_root(struct dm_space_map *sm, void *where_le, size_t max)
0180 {
0181     struct sm_disk *smd = container_of(sm, struct sm_disk, sm);
0182     struct disk_sm_root root_le;
0183 
0184     root_le.nr_blocks = cpu_to_le64(smd->ll.nr_blocks);
0185     root_le.nr_allocated = cpu_to_le64(smd->ll.nr_allocated);
0186     root_le.bitmap_root = cpu_to_le64(smd->ll.bitmap_root);
0187     root_le.ref_count_root = cpu_to_le64(smd->ll.ref_count_root);
0188 
0189     if (max < sizeof(root_le))
0190         return -ENOSPC;
0191 
0192     memcpy(where_le, &root_le, sizeof(root_le));
0193 
0194     return 0;
0195 }
0196 
0197 /*----------------------------------------------------------------*/
0198 
0199 static struct dm_space_map ops = {
0200     .destroy = sm_disk_destroy,
0201     .extend = sm_disk_extend,
0202     .get_nr_blocks = sm_disk_get_nr_blocks,
0203     .get_nr_free = sm_disk_get_nr_free,
0204     .get_count = sm_disk_get_count,
0205     .count_is_more_than_one = sm_disk_count_is_more_than_one,
0206     .set_count = sm_disk_set_count,
0207     .inc_blocks = sm_disk_inc_blocks,
0208     .dec_blocks = sm_disk_dec_blocks,
0209     .new_block = sm_disk_new_block,
0210     .commit = sm_disk_commit,
0211     .root_size = sm_disk_root_size,
0212     .copy_root = sm_disk_copy_root,
0213     .register_threshold_callback = NULL
0214 };
0215 
0216 struct dm_space_map *dm_sm_disk_create(struct dm_transaction_manager *tm,
0217                        dm_block_t nr_blocks)
0218 {
0219     int r;
0220     struct sm_disk *smd;
0221 
0222     smd = kmalloc(sizeof(*smd), GFP_KERNEL);
0223     if (!smd)
0224         return ERR_PTR(-ENOMEM);
0225 
0226     smd->begin = 0;
0227     smd->nr_allocated_this_transaction = 0;
0228     memcpy(&smd->sm, &ops, sizeof(smd->sm));
0229 
0230     r = sm_ll_new_disk(&smd->ll, tm);
0231     if (r)
0232         goto bad;
0233 
0234     r = sm_ll_extend(&smd->ll, nr_blocks);
0235     if (r)
0236         goto bad;
0237 
0238     r = sm_disk_commit(&smd->sm);
0239     if (r)
0240         goto bad;
0241 
0242     return &smd->sm;
0243 
0244 bad:
0245     kfree(smd);
0246     return ERR_PTR(r);
0247 }
0248 EXPORT_SYMBOL_GPL(dm_sm_disk_create);
0249 
0250 struct dm_space_map *dm_sm_disk_open(struct dm_transaction_manager *tm,
0251                      void *root_le, size_t len)
0252 {
0253     int r;
0254     struct sm_disk *smd;
0255 
0256     smd = kmalloc(sizeof(*smd), GFP_KERNEL);
0257     if (!smd)
0258         return ERR_PTR(-ENOMEM);
0259 
0260     smd->begin = 0;
0261     smd->nr_allocated_this_transaction = 0;
0262     memcpy(&smd->sm, &ops, sizeof(smd->sm));
0263 
0264     r = sm_ll_open_disk(&smd->ll, tm, root_le, len);
0265     if (r)
0266         goto bad;
0267 
0268     r = sm_disk_commit(&smd->sm);
0269     if (r)
0270         goto bad;
0271 
0272     return &smd->sm;
0273 
0274 bad:
0275     kfree(smd);
0276     return ERR_PTR(r);
0277 }
0278 EXPORT_SYMBOL_GPL(dm_sm_disk_open);
0279 
0280 /*----------------------------------------------------------------*/