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