0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #include <linux/kernel.h>
0036 #include <linux/module.h>
0037 #include <linux/slab.h>
0038 #include <linux/export.h>
0039 #include <linux/list.h>
0040 #include <linux/err.h>
0041 #include <linux/parman.h>
0042
0043 struct parman_algo {
0044 int (*item_add)(struct parman *parman, struct parman_prio *prio,
0045 struct parman_item *item);
0046 void (*item_remove)(struct parman *parman, struct parman_prio *prio,
0047 struct parman_item *item);
0048 };
0049
0050 struct parman {
0051 const struct parman_ops *ops;
0052 void *priv;
0053 const struct parman_algo *algo;
0054 unsigned long count;
0055 unsigned long limit_count;
0056 struct list_head prio_list;
0057 };
0058
0059 static int parman_enlarge(struct parman *parman)
0060 {
0061 unsigned long new_count = parman->limit_count +
0062 parman->ops->resize_step;
0063 int err;
0064
0065 err = parman->ops->resize(parman->priv, new_count);
0066 if (err)
0067 return err;
0068 parman->limit_count = new_count;
0069 return 0;
0070 }
0071
0072 static int parman_shrink(struct parman *parman)
0073 {
0074 unsigned long new_count = parman->limit_count -
0075 parman->ops->resize_step;
0076 int err;
0077
0078 if (new_count < parman->ops->base_count)
0079 return 0;
0080 err = parman->ops->resize(parman->priv, new_count);
0081 if (err)
0082 return err;
0083 parman->limit_count = new_count;
0084 return 0;
0085 }
0086
0087 static bool parman_prio_used(struct parman_prio *prio)
0088 {
0089 return !list_empty(&prio->item_list);
0090 }
0091
0092 static struct parman_item *parman_prio_first_item(struct parman_prio *prio)
0093 {
0094 return list_first_entry(&prio->item_list,
0095 typeof(struct parman_item), list);
0096 }
0097
0098 static unsigned long parman_prio_first_index(struct parman_prio *prio)
0099 {
0100 return parman_prio_first_item(prio)->index;
0101 }
0102
0103 static struct parman_item *parman_prio_last_item(struct parman_prio *prio)
0104 {
0105 return list_last_entry(&prio->item_list,
0106 typeof(struct parman_item), list);
0107 }
0108
0109 static unsigned long parman_prio_last_index(struct parman_prio *prio)
0110 {
0111 return parman_prio_last_item(prio)->index;
0112 }
0113
0114 static unsigned long parman_lsort_new_index_find(struct parman *parman,
0115 struct parman_prio *prio)
0116 {
0117 list_for_each_entry_from_reverse(prio, &parman->prio_list, list) {
0118 if (!parman_prio_used(prio))
0119 continue;
0120 return parman_prio_last_index(prio) + 1;
0121 }
0122 return 0;
0123 }
0124
0125 static void __parman_prio_move(struct parman *parman, struct parman_prio *prio,
0126 struct parman_item *item, unsigned long to_index,
0127 unsigned long count)
0128 {
0129 parman->ops->move(parman->priv, item->index, to_index, count);
0130 }
0131
0132 static void parman_prio_shift_down(struct parman *parman,
0133 struct parman_prio *prio)
0134 {
0135 struct parman_item *item;
0136 unsigned long to_index;
0137
0138 if (!parman_prio_used(prio))
0139 return;
0140 item = parman_prio_first_item(prio);
0141 to_index = parman_prio_last_index(prio) + 1;
0142 __parman_prio_move(parman, prio, item, to_index, 1);
0143 list_move_tail(&item->list, &prio->item_list);
0144 item->index = to_index;
0145 }
0146
0147 static void parman_prio_shift_up(struct parman *parman,
0148 struct parman_prio *prio)
0149 {
0150 struct parman_item *item;
0151 unsigned long to_index;
0152
0153 if (!parman_prio_used(prio))
0154 return;
0155 item = parman_prio_last_item(prio);
0156 to_index = parman_prio_first_index(prio) - 1;
0157 __parman_prio_move(parman, prio, item, to_index, 1);
0158 list_move(&item->list, &prio->item_list);
0159 item->index = to_index;
0160 }
0161
0162 static void parman_prio_item_remove(struct parman *parman,
0163 struct parman_prio *prio,
0164 struct parman_item *item)
0165 {
0166 struct parman_item *last_item;
0167 unsigned long to_index;
0168
0169 last_item = parman_prio_last_item(prio);
0170 if (last_item == item) {
0171 list_del(&item->list);
0172 return;
0173 }
0174 to_index = item->index;
0175 __parman_prio_move(parman, prio, last_item, to_index, 1);
0176 list_del(&last_item->list);
0177 list_replace(&item->list, &last_item->list);
0178 last_item->index = to_index;
0179 }
0180
0181 static int parman_lsort_item_add(struct parman *parman,
0182 struct parman_prio *prio,
0183 struct parman_item *item)
0184 {
0185 struct parman_prio *prio2;
0186 unsigned long new_index;
0187 int err;
0188
0189 if (parman->count + 1 > parman->limit_count) {
0190 err = parman_enlarge(parman);
0191 if (err)
0192 return err;
0193 }
0194
0195 new_index = parman_lsort_new_index_find(parman, prio);
0196 list_for_each_entry_reverse(prio2, &parman->prio_list, list) {
0197 if (prio2 == prio)
0198 break;
0199 parman_prio_shift_down(parman, prio2);
0200 }
0201 item->index = new_index;
0202 list_add_tail(&item->list, &prio->item_list);
0203 parman->count++;
0204 return 0;
0205 }
0206
0207 static void parman_lsort_item_remove(struct parman *parman,
0208 struct parman_prio *prio,
0209 struct parman_item *item)
0210 {
0211 parman_prio_item_remove(parman, prio, item);
0212 list_for_each_entry_continue(prio, &parman->prio_list, list)
0213 parman_prio_shift_up(parman, prio);
0214 parman->count--;
0215 if (parman->limit_count - parman->count >= parman->ops->resize_step)
0216 parman_shrink(parman);
0217 }
0218
0219 static const struct parman_algo parman_lsort = {
0220 .item_add = parman_lsort_item_add,
0221 .item_remove = parman_lsort_item_remove,
0222 };
0223
0224 static const struct parman_algo *parman_algos[] = {
0225 &parman_lsort,
0226 };
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 struct parman *parman_create(const struct parman_ops *ops, void *priv)
0268 {
0269 struct parman *parman;
0270
0271 parman = kzalloc(sizeof(*parman), GFP_KERNEL);
0272 if (!parman)
0273 return NULL;
0274 INIT_LIST_HEAD(&parman->prio_list);
0275 parman->ops = ops;
0276 parman->priv = priv;
0277 parman->limit_count = ops->base_count;
0278 parman->algo = parman_algos[ops->algo];
0279 return parman;
0280 }
0281 EXPORT_SYMBOL(parman_create);
0282
0283
0284
0285
0286
0287
0288
0289 void parman_destroy(struct parman *parman)
0290 {
0291 WARN_ON(!list_empty(&parman->prio_list));
0292 kfree(parman);
0293 }
0294 EXPORT_SYMBOL(parman_destroy);
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307 void parman_prio_init(struct parman *parman, struct parman_prio *prio,
0308 unsigned long priority)
0309 {
0310 struct parman_prio *prio2;
0311 struct list_head *pos;
0312
0313 INIT_LIST_HEAD(&prio->item_list);
0314 prio->priority = priority;
0315
0316
0317 list_for_each(pos, &parman->prio_list) {
0318 prio2 = list_entry(pos, typeof(*prio2), list);
0319 if (prio2->priority > prio->priority)
0320 break;
0321 }
0322 list_add_tail(&prio->list, pos);
0323 }
0324 EXPORT_SYMBOL(parman_prio_init);
0325
0326
0327
0328
0329
0330
0331
0332 void parman_prio_fini(struct parman_prio *prio)
0333 {
0334 WARN_ON(parman_prio_used(prio));
0335 list_del(&prio->list);
0336 }
0337 EXPORT_SYMBOL(parman_prio_fini);
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 int parman_item_add(struct parman *parman, struct parman_prio *prio,
0352 struct parman_item *item)
0353 {
0354 return parman->algo->item_add(parman, prio, item);
0355 }
0356 EXPORT_SYMBOL(parman_item_add);
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366 void parman_item_remove(struct parman *parman, struct parman_prio *prio,
0367 struct parman_item *item)
0368 {
0369 parman->algo->item_remove(parman, prio, item);
0370 }
0371 EXPORT_SYMBOL(parman_item_remove);
0372
0373 MODULE_LICENSE("Dual BSD/GPL");
0374 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
0375 MODULE_DESCRIPTION("Priority-based array manager");