Whamcloud - gitweb
po: update ms.po (from translationproject.org)
[tools/e2fsprogs.git] / e2fsck / ea_refcount.c
1 /*
2  * ea_refcount.c
3  *
4  * Copyright (C) 2001 Theodore Ts'o.  This file may be
5  * redistributed under the terms of the GNU Public License.
6  */
7
8 #include "config.h"
9 #if HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12 #include <string.h>
13 #include <stdio.h>
14
15 #ifdef TEST_PROGRAM
16 #undef ENABLE_NLS
17 #endif
18 #include "e2fsck.h"
19
20 /*
21  * The strategy we use for keeping track of EA refcounts is as
22  * follows.  We keep a sorted array of first EA blocks and its
23  * reference counts.  Once the refcount has dropped to zero, it is
24  * removed from the array to save memory space.  Once the EA block is
25  * checked, its bit is set in the block_ea_map bitmap.
26  */
27 struct ea_refcount_el {
28         /* ea_key could either be an inode number or block number. */
29         ea_key_t        ea_key;
30         ea_value_t      ea_value;
31 };
32
33 struct ea_refcount {
34         size_t          count;
35         size_t          size;
36         size_t          cursor;
37         struct ea_refcount_el   *list;
38 };
39
40 void ea_refcount_free(ext2_refcount_t refcount)
41 {
42         if (!refcount)
43                 return;
44
45         if (refcount->list)
46                 ext2fs_free_mem(&refcount->list);
47         ext2fs_free_mem(&refcount);
48 }
49
50 errcode_t ea_refcount_create(size_t size, ext2_refcount_t *ret)
51 {
52         ext2_refcount_t refcount;
53         errcode_t       retval;
54         size_t          bytes;
55
56         retval = ext2fs_get_memzero(sizeof(struct ea_refcount), &refcount);
57         if (retval)
58                 return retval;
59
60         if (!size)
61                 size = 500;
62         refcount->size = size;
63         bytes = size * sizeof(struct ea_refcount_el);
64 #ifdef DEBUG
65         printf("Refcount allocated %zu entries, %zu bytes.\n",
66                refcount->size, bytes);
67 #endif
68         retval = ext2fs_get_memzero(bytes, &refcount->list);
69         if (retval)
70                 goto errout;
71
72         refcount->count = 0;
73         refcount->cursor = 0;
74
75         *ret = refcount;
76         return 0;
77
78 errout:
79         ea_refcount_free(refcount);
80         return(retval);
81 }
82
83 /*
84  * collapse_refcount() --- go through the refcount array, and get rid
85  * of any count == zero entries
86  */
87 static void refcount_collapse(ext2_refcount_t refcount)
88 {
89         unsigned int    i, j;
90         struct ea_refcount_el   *list;
91
92         list = refcount->list;
93         for (i = 0, j = 0; i < refcount->count; i++) {
94                 if (list[i].ea_value) {
95                         if (i != j)
96                                 list[j] = list[i];
97                         j++;
98                 }
99         }
100 #if defined(DEBUG) || defined(TEST_PROGRAM)
101         printf("Refcount_collapse: size was %zu, now %d\n",
102                refcount->count, j);
103 #endif
104         refcount->count = j;
105 }
106
107
108 /*
109  * insert_refcount_el() --- Insert a new entry into the sorted list at a
110  *      specified position.
111  */
112 static struct ea_refcount_el *insert_refcount_el(ext2_refcount_t refcount,
113                                                  ea_key_t ea_key, int pos)
114 {
115         struct ea_refcount_el   *el;
116         errcode_t               retval;
117         size_t                  new_size = 0;
118         int                     num;
119
120         if (refcount->count >= refcount->size) {
121                 new_size = refcount->size + 100;
122 #ifdef DEBUG
123                 printf("Reallocating refcount %d entries...\n", new_size);
124 #endif
125                 retval = ext2fs_resize_mem((size_t) refcount->size *
126                                            sizeof(struct ea_refcount_el),
127                                            (size_t) new_size *
128                                            sizeof(struct ea_refcount_el),
129                                            &refcount->list);
130                 if (retval)
131                         return 0;
132                 refcount->size = new_size;
133         }
134         num = (int) refcount->count - pos;
135         if (num < 0)
136                 return 0;       /* should never happen */
137         if (num) {
138                 memmove(&refcount->list[pos+1], &refcount->list[pos],
139                         sizeof(struct ea_refcount_el) * num);
140         }
141         refcount->count++;
142         el = &refcount->list[pos];
143         el->ea_key = ea_key;
144         el->ea_value = 0;
145         return el;
146 }
147
148
149 /*
150  * get_refcount_el() --- given an block number, try to find refcount
151  *      information in the sorted list.  If the create flag is set,
152  *      and we can't find an entry, create one in the sorted list.
153  */
154 static struct ea_refcount_el *get_refcount_el(ext2_refcount_t refcount,
155                                               ea_key_t ea_key, int create)
156 {
157         int     low, high, mid;
158
159         if (!refcount || !refcount->list)
160                 return 0;
161 retry:
162         low = 0;
163         high = (int) refcount->count-1;
164         if (create && ((refcount->count == 0) ||
165                        (ea_key > refcount->list[high].ea_key))) {
166                 if (refcount->count >= refcount->size)
167                         refcount_collapse(refcount);
168
169                 return insert_refcount_el(refcount, ea_key,
170                                           (unsigned) refcount->count);
171         }
172         if (refcount->count == 0)
173                 return 0;
174
175         if (refcount->cursor >= refcount->count)
176                 refcount->cursor = 0;
177         if (ea_key == refcount->list[refcount->cursor].ea_key)
178                 return &refcount->list[refcount->cursor++];
179 #ifdef DEBUG
180         printf("Non-cursor get_refcount_el: %u\n", ea_key);
181 #endif
182         while (low <= high) {
183                 mid = (low+high)/2;
184                 if (ea_key == refcount->list[mid].ea_key) {
185                         refcount->cursor = mid+1;
186                         return &refcount->list[mid];
187                 }
188                 if (ea_key < refcount->list[mid].ea_key)
189                         high = mid-1;
190                 else
191                         low = mid+1;
192         }
193         /*
194          * If we need to create a new entry, it should be right at
195          * low (where high will be left at low-1).
196          */
197         if (create) {
198                 if (refcount->count >= refcount->size) {
199                         refcount_collapse(refcount);
200                         if (refcount->count < refcount->size)
201                                 goto retry;
202                 }
203                 return insert_refcount_el(refcount, ea_key, low);
204         }
205         return 0;
206 }
207
208 errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
209                             ea_value_t *ret)
210 {
211         struct ea_refcount_el   *el;
212
213         el = get_refcount_el(refcount, ea_key, 0);
214         if (!el) {
215                 *ret = 0;
216                 return 0;
217         }
218         *ret = el->ea_value;
219         return 0;
220 }
221
222 errcode_t ea_refcount_increment(ext2_refcount_t refcount, ea_key_t ea_key,
223                                 ea_value_t *ret)
224 {
225         struct ea_refcount_el   *el;
226
227         el = get_refcount_el(refcount, ea_key, 1);
228         if (!el)
229                 return EXT2_ET_NO_MEMORY;
230         el->ea_value++;
231
232         if (ret)
233                 *ret = el->ea_value;
234         return 0;
235 }
236
237 errcode_t ea_refcount_decrement(ext2_refcount_t refcount, ea_key_t ea_key,
238                                 ea_value_t *ret)
239 {
240         struct ea_refcount_el   *el;
241
242         el = get_refcount_el(refcount, ea_key, 0);
243         if (!el || el->ea_value == 0)
244                 return EXT2_ET_INVALID_ARGUMENT;
245
246         el->ea_value--;
247
248         if (ret)
249                 *ret = el->ea_value;
250         return 0;
251 }
252
253 errcode_t ea_refcount_store(ext2_refcount_t refcount, ea_key_t ea_key,
254                             ea_value_t ea_value)
255 {
256         struct ea_refcount_el   *el;
257
258         /*
259          * Get the refcount element
260          */
261         el = get_refcount_el(refcount, ea_key, ea_value ? 1 : 0);
262         if (!el)
263                 return ea_value ? EXT2_ET_NO_MEMORY : 0;
264         el->ea_value = ea_value;
265         return 0;
266 }
267
268 size_t ext2fs_get_refcount_size(ext2_refcount_t refcount)
269 {
270         if (!refcount)
271                 return 0;
272
273         return refcount->size;
274 }
275
276 void ea_refcount_intr_begin(ext2_refcount_t refcount)
277 {
278         refcount->cursor = 0;
279 }
280
281 ea_key_t ea_refcount_intr_next(ext2_refcount_t refcount,
282                                 ea_value_t *ret)
283 {
284         struct ea_refcount_el   *list;
285
286         while (1) {
287                 if (refcount->cursor >= refcount->count)
288                         return 0;
289                 list = refcount->list;
290                 if (list[refcount->cursor].ea_value) {
291                         if (ret)
292                                 *ret = list[refcount->cursor].ea_value;
293                         return list[refcount->cursor++].ea_key;
294                 }
295                 refcount->cursor++;
296         }
297 }
298
299
300 #ifdef TEST_PROGRAM
301
302 errcode_t ea_refcount_validate(ext2_refcount_t refcount, FILE *out)
303 {
304         errcode_t       ret = 0;
305         int             i;
306         const char *bad = "bad refcount";
307
308         if (refcount->count > refcount->size) {
309                 fprintf(out, "%s: count > size\n", bad);
310                 return EXT2_ET_INVALID_ARGUMENT;
311         }
312         for (i=1; i < refcount->count; i++) {
313                 if (refcount->list[i-1].ea_key >= refcount->list[i].ea_key) {
314                         fprintf(out,
315                                 "%s: list[%d].ea_key=%llu, list[%d].ea_key=%llu\n",
316                                 bad, i-1,
317                                 (unsigned long long) refcount->list[i-1].ea_key,
318                                 i,
319                                 (unsigned long long) refcount->list[i].ea_key);
320                         ret = EXT2_ET_INVALID_ARGUMENT;
321                 }
322         }
323         return ret;
324 }
325
326 #define BCODE_END       0
327 #define BCODE_CREATE    1
328 #define BCODE_FREE      2
329 #define BCODE_STORE     3
330 #define BCODE_INCR      4
331 #define BCODE_DECR      5
332 #define BCODE_FETCH     6
333 #define BCODE_VALIDATE  7
334 #define BCODE_LIST      8
335 #define BCODE_COLLAPSE 9
336
337 int bcode_program[] = {
338         BCODE_CREATE, 5,
339         BCODE_STORE, 3, 3,
340         BCODE_STORE, 4, 4,
341         BCODE_STORE, 1, 1,
342         BCODE_STORE, 8, 8,
343         BCODE_STORE, 2, 2,
344         BCODE_STORE, 4, 0,
345         BCODE_STORE, 2, 0,
346         BCODE_STORE, 6, 6,
347         BCODE_VALIDATE,
348         BCODE_STORE, 4, 4,
349         BCODE_STORE, 2, 2,
350         BCODE_FETCH, 1,
351         BCODE_FETCH, 2,
352         BCODE_INCR, 3,
353         BCODE_INCR, 3,
354         BCODE_DECR, 4,
355         BCODE_STORE, 4, 4,
356         BCODE_VALIDATE,
357         BCODE_STORE, 20, 20,
358         BCODE_STORE, 40, 40,
359         BCODE_STORE, 30, 30,
360         BCODE_STORE, 10, 10,
361         BCODE_DECR, 30,
362         BCODE_FETCH, 30,
363         BCODE_DECR, 2,
364         BCODE_DECR, 2,
365         BCODE_COLLAPSE,
366         BCODE_LIST,
367         BCODE_VALIDATE,
368         BCODE_FREE,
369         BCODE_END
370 };
371
372 int main(int argc, char **argv)
373 {
374         int     i = 0;
375         ext2_refcount_t refcount;
376         size_t          size;
377         ea_key_t        ea_key;
378         ea_value_t      arg;
379         errcode_t       retval;
380
381         while (1) {
382                 switch (bcode_program[i++]) {
383                 case BCODE_END:
384                         exit(0);
385                 case BCODE_CREATE:
386                         size = bcode_program[i++];
387                         retval = ea_refcount_create(size, &refcount);
388                         if (retval) {
389                                 com_err("ea_refcount_create", retval,
390                                         "while creating size %zu", size);
391                                 exit(1);
392                         } else
393                                 printf("Creating refcount with size %zu\n",
394                                        size);
395                         break;
396                 case BCODE_FREE:
397                         ea_refcount_free(refcount);
398                         refcount = 0;
399                         printf("Freeing refcount\n");
400                         break;
401                 case BCODE_STORE:
402                         ea_key = (size_t) bcode_program[i++];
403                         arg = bcode_program[i++];
404                         printf("Storing ea_key %llu with value %llu\n",
405                                (unsigned long long) ea_key,
406                                (unsigned long long) arg);
407                         retval = ea_refcount_store(refcount, ea_key, arg);
408                         if (retval)
409                                 com_err("ea_refcount_store", retval,
410                                         "while storing ea_key %llu",
411                                         (unsigned long long) ea_key);
412                         break;
413                 case BCODE_FETCH:
414                         ea_key = (size_t) bcode_program[i++];
415                         retval = ea_refcount_fetch(refcount, ea_key, &arg);
416                         if (retval)
417                                 com_err("ea_refcount_fetch", retval,
418                                         "while fetching ea_key %llu",
419                                         (unsigned long long) ea_key);
420                         else
421                                 printf("bcode_fetch(%llu) returns %llu\n",
422                                        (unsigned long long) ea_key,
423                                        (unsigned long long) arg);
424                         break;
425                 case BCODE_INCR:
426                         ea_key = (size_t) bcode_program[i++];
427                         retval = ea_refcount_increment(refcount, ea_key, &arg);
428                         if (retval)
429                                 com_err("ea_refcount_increment", retval,
430                                         "while incrementing ea_key %llu",
431                                         (unsigned long long) ea_key);
432                         else
433                                 printf("bcode_increment(%llu) returns %llu\n",
434                                        (unsigned long long) ea_key,
435                                        (unsigned long long) arg);
436                         break;
437                 case BCODE_DECR:
438                         ea_key = (size_t) bcode_program[i++];
439                         retval = ea_refcount_decrement(refcount, ea_key, &arg);
440                         if (retval)
441                                 com_err("ea_refcount_decrement", retval,
442                                         "while decrementing ea_key %llu",
443                                         (unsigned long long) ea_key);
444                         else
445                                 printf("bcode_decrement(%llu) returns %llu\n",
446                                        (unsigned long long) ea_key,
447                                        (unsigned long long) arg);
448                         break;
449                 case BCODE_VALIDATE:
450                         retval = ea_refcount_validate(refcount, stderr);
451                         if (retval)
452                                 com_err("ea_refcount_validate", retval,
453                                         "while validating");
454                         else
455                                 printf("Refcount validation OK.\n");
456                         break;
457                 case BCODE_LIST:
458                         ea_refcount_intr_begin(refcount);
459                         while (1) {
460                                 ea_key = ea_refcount_intr_next(refcount, &arg);
461                                 if (!ea_key)
462                                         break;
463                                 printf("\tea_key=%llu, count=%llu\n",
464                                        (unsigned long long) ea_key,
465                                        (unsigned long long) arg);
466                         }
467                         break;
468                 case BCODE_COLLAPSE:
469                         refcount_collapse(refcount);
470                         break;
471                 }
472
473         }
474 }
475
476 #endif