0001
0002
0003
0004
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
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
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
0140
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