|
@@ -66,88 +66,33 @@ void init_buffer ( struct buffer *buffer ) {
|
66
|
66
|
DBG ( "BUFFER [%x,%x) initialised\n", buffer->start, buffer->end );
|
67
|
67
|
}
|
68
|
68
|
|
69
|
|
-/**
|
70
|
|
- * Split a free block.
|
71
|
|
- *
|
72
|
|
- * @v desc A descriptor for the free block
|
73
|
|
- * @v block Start address of the block
|
74
|
|
- * @v split Address at which to split the block
|
75
|
|
- * @ret None -
|
76
|
|
- * @err None -
|
77
|
|
- *
|
78
|
|
- * Split a free block into two separate free blocks. If the split
|
79
|
|
- * point lies outside the block, no action is taken; this is not an
|
80
|
|
- * error.
|
81
|
|
- *
|
82
|
|
- * @b NOTE: It is the reponsibility of the caller to ensure that there
|
83
|
|
- * is enough room in each of the two portions for a free block
|
84
|
|
- * descriptor (a @c struct @c buffer_free_block, except in the case of
|
85
|
|
- * a tail block which requires only a one byte descriptor). If the
|
86
|
|
- * caller fails to do this, data corruption will occur.
|
87
|
|
- *
|
88
|
|
- * In practice, this means that the granularity at which blocks are
|
89
|
|
- * split must be at least @c sizeof(struct @c buffer_free_block).
|
90
|
|
- *
|
91
|
|
- */
|
92
|
|
-static void split_free_block ( struct buffer_free_block *desc,
|
93
|
|
- physaddr_t block, physaddr_t split ) {
|
94
|
|
- /* If split point is before start of block, do nothing */
|
95
|
|
- if ( split <= block )
|
96
|
|
- return;
|
97
|
|
-
|
98
|
|
- /* If split point is after end of block, do nothing */
|
99
|
|
- if ( split >= desc->end )
|
100
|
|
- return;
|
101
|
|
-
|
102
|
|
- DBG ( "BUFFER splitting [%x,%x) -> [%x,%x) [%x,%x)\n",
|
103
|
|
- block, desc->end, block, split, split, desc->end );
|
104
|
|
-
|
105
|
|
- /* Create descriptor for new free block */
|
106
|
|
- copy_to_phys ( split, &desc->tail, sizeof ( desc->tail ) );
|
107
|
|
- if ( ! desc->tail )
|
108
|
|
- copy_to_phys ( split, desc, sizeof ( *desc ) );
|
109
|
|
-
|
110
|
|
- /* Update descriptor for old free block */
|
111
|
|
- desc->tail = 0;
|
112
|
|
- desc->next_free = split;
|
113
|
|
- desc->end = split;
|
114
|
|
- copy_to_phys ( block, desc, sizeof ( *desc ) );
|
115
|
|
-}
|
|
69
|
+static inline int next_free_block ( struct buffer_free_block *block,
|
|
70
|
+ struct buffer *buffer ) {
|
|
71
|
+ /* Move to next block */
|
|
72
|
+ block->start = block->next;
|
116
|
73
|
|
117
|
|
-/**
|
118
|
|
- * Mark a free block as used.
|
119
|
|
- *
|
120
|
|
- * @v buffer The buffer containing the block
|
121
|
|
- * @v desc A descriptor for the free block
|
122
|
|
- * @v prev_block Address of the previous block
|
123
|
|
- * @ret None -
|
124
|
|
- * @err None -
|
125
|
|
- *
|
126
|
|
- * Marks a free block as used, i.e. removes it from the free list.
|
127
|
|
- *
|
128
|
|
- */
|
129
|
|
-static inline void unfree_block ( struct buffer *buffer,
|
130
|
|
- struct buffer_free_block *desc,
|
131
|
|
- physaddr_t prev_block ) {
|
132
|
|
- struct buffer_free_block prev_desc;
|
133
|
|
-
|
134
|
|
- /* If this is the first block, just update buffer->fill */
|
135
|
|
- if ( ! prev_block ) {
|
136
|
|
- DBG ( "BUFFER marking [%x,%x) as used\n",
|
137
|
|
- buffer->start + buffer->fill, desc->end );
|
138
|
|
- buffer->fill = desc->next_free - buffer->start;
|
139
|
|
- return;
|
140
|
|
- }
|
|
74
|
+ /* If at end of buffer, return 0 */
|
|
75
|
+ if ( block->start >= buffer->end )
|
|
76
|
+ return 0;
|
141
|
77
|
|
142
|
|
- /* Get descriptor for previous block (which cannot be a tail block) */
|
143
|
|
- copy_from_phys ( &prev_desc, prev_block, sizeof ( prev_desc ) );
|
|
78
|
+ /* Set up ->next and ->end as for a tail block */
|
|
79
|
+ block->next = block->end = buffer->end;
|
144
|
80
|
|
145
|
|
- DBG ( "BUFFER marking [%x,%x) as used\n",
|
146
|
|
- prev_desc.next_free, desc->end );
|
|
81
|
+ /* Read tail marker from block */
|
|
82
|
+ copy_from_phys ( &block->tail, block->start, sizeof ( block->tail ) );
|
147
|
83
|
|
148
|
|
- /* Modify descriptor for previous block and write it back */
|
149
|
|
- prev_desc.next_free = desc->next_free;
|
150
|
|
- copy_to_phys ( prev_block, &prev_desc, sizeof ( prev_desc ) );
|
|
84
|
+ /* If not a tail block, read whole block descriptor from block */
|
|
85
|
+ if ( ! block->tail ) {
|
|
86
|
+ copy_from_phys ( block, block->start, sizeof ( *block ) );
|
|
87
|
+ }
|
|
88
|
+
|
|
89
|
+ return 1;
|
|
90
|
+}
|
|
91
|
+
|
|
92
|
+static inline void store_free_block ( struct buffer_free_block *block ) {
|
|
93
|
+ copy_to_phys ( block->start, block,
|
|
94
|
+ ( block->tail ?
|
|
95
|
+ sizeof ( block->tail ) : sizeof ( *block ) ) );
|
151
|
96
|
}
|
152
|
97
|
|
153
|
98
|
/**
|
|
@@ -188,8 +133,7 @@ static inline void unfree_block ( struct buffer *buffer,
|
188
|
133
|
*/
|
189
|
134
|
int fill_buffer ( struct buffer *buffer, const void *data,
|
190
|
135
|
off_t offset, size_t len ) {
|
191
|
|
- struct buffer_free_block desc;
|
192
|
|
- physaddr_t block, prev_block;
|
|
136
|
+ struct buffer_free_block block, before, after;
|
193
|
137
|
physaddr_t data_start, data_end;
|
194
|
138
|
|
195
|
139
|
/* Calculate start and end addresses of data */
|
|
@@ -206,38 +150,48 @@ int fill_buffer ( struct buffer *buffer, const void *data,
|
206
|
150
|
return 0;
|
207
|
151
|
}
|
208
|
152
|
|
209
|
|
- /* Iterate through the buffer's free blocks */
|
210
|
|
- prev_block = 0;
|
211
|
|
- block = buffer->start + buffer->fill;
|
212
|
|
- while ( block < buffer->end ) {
|
213
|
|
- /* Read block descriptor */
|
214
|
|
- desc.next_free = buffer->end;
|
215
|
|
- desc.end = buffer->end;
|
216
|
|
- copy_from_phys ( &desc.tail, block, sizeof ( desc.tail ) );
|
217
|
|
- if ( ! desc.tail )
|
218
|
|
- copy_from_phys ( &desc, block, sizeof ( desc ) );
|
219
|
|
-
|
220
|
|
- /* Split block at data start and end markers */
|
221
|
|
- split_free_block ( &desc, block, data_start );
|
222
|
|
- split_free_block ( &desc, block, data_end );
|
223
|
|
-
|
224
|
|
- /* Block is now either completely contained by or
|
225
|
|
- * completely outside the data area
|
226
|
|
- */
|
227
|
|
- if ( ( block >= data_start ) && ( block < data_end ) ) {
|
228
|
|
- /* Block is within the data area */
|
229
|
|
- unfree_block ( buffer, &desc, prev_block );
|
230
|
|
- copy_to_phys ( block, data + ( block - data_start ),
|
231
|
|
- desc.end - block );
|
232
|
|
- } else {
|
233
|
|
- /* Block is outside the data area */
|
234
|
|
- prev_block = block;
|
235
|
|
- }
|
236
|
|
-
|
237
|
|
- /* Move to next free block */
|
238
|
|
- block = desc.next_free;
|
|
153
|
+ /* Find 'before' and 'after' blocks, if any */
|
|
154
|
+ before.start = before.end = 0;
|
|
155
|
+ after.start = after.end = buffer->end;
|
|
156
|
+ block.next = buffer->start + buffer->fill;
|
|
157
|
+ while ( next_free_block ( &block, buffer ) ) {
|
|
158
|
+ if ( ( block.start < data_start ) &&
|
|
159
|
+ ( block.start >= before.start ) )
|
|
160
|
+ memcpy ( &before, &block, sizeof ( before ) );
|
|
161
|
+ if ( ( block.end > data_end ) &&
|
|
162
|
+ ( block.end <= after.end ) )
|
|
163
|
+ memcpy ( &after, &block, sizeof ( after ) );
|
|
164
|
+ }
|
|
165
|
+
|
|
166
|
+ /* Truncate 'before' and 'after' blocks around data. */
|
|
167
|
+ if ( data_start < before.end )
|
|
168
|
+ before.end = data_start;
|
|
169
|
+ if ( data_end > after.start )
|
|
170
|
+ after.start = data_end;
|
|
171
|
+
|
|
172
|
+ /* Link 'after' block to 'before' block */
|
|
173
|
+ before.next = after.start;
|
|
174
|
+
|
|
175
|
+ /* Write back 'before' block, if any */
|
|
176
|
+ if ( before.start ) {
|
|
177
|
+ before.tail = 0;
|
|
178
|
+ store_free_block ( &before );
|
|
179
|
+ } else {
|
|
180
|
+ buffer->fill = before.next - buffer->start;
|
239
|
181
|
}
|
240
|
182
|
|
|
183
|
+ /* Write back 'after' block, if any */
|
|
184
|
+ if ( after.start < buffer->end ) {
|
|
185
|
+ store_free_block ( &after );
|
|
186
|
+ }
|
|
187
|
+
|
|
188
|
+ DBG ( "BUFFER [%x,%x) before [%x,%x) after [%x,%x)\n",
|
|
189
|
+ buffer->start, buffer->end, before.start, before.end,
|
|
190
|
+ after.start, after.end );
|
|
191
|
+
|
|
192
|
+ /* Copy data into buffer */
|
|
193
|
+ copy_to_phys ( data_start, data, len );
|
|
194
|
+
|
241
|
195
|
DBG ( "BUFFER [%x,%x) full up to %x\n",
|
242
|
196
|
buffer->start, buffer->end, buffer->start + buffer->fill );
|
243
|
197
|
|