revert-mm-fix-blkdev-size-calculation-in-generic_write_checks
[linux-2.6/linux-trees-mm.git] / fs / reiser4 / plugin / item / extent_flush_ops.c
blob02dda3ea325c56f6335a75174683492a1a52d6fa
1 /* Copyright 2001, 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
3 #include "item.h"
4 #include "../../tree.h"
5 #include "../../jnode.h"
6 #include "../../super.h"
7 #include "../../flush.h"
8 #include "../../carry.h"
9 #include "../object.h"
11 #include <linux/pagemap.h>
13 static reiser4_block_nr extent_unit_start(const coord_t * item);
15 /* Return either first or last extent (depending on @side) of the item
16 @coord is set to. Set @pos_in_unit either to first or to last block
17 of extent. */
18 static reiser4_extent *extent_utmost_ext(const coord_t * coord, sideof side,
19 reiser4_block_nr * pos_in_unit)
21 reiser4_extent *ext;
23 if (side == LEFT_SIDE) {
24 /* get first extent of item */
25 ext = extent_item(coord);
26 *pos_in_unit = 0;
27 } else {
28 /* get last extent of item and last position within it */
29 assert("vs-363", side == RIGHT_SIDE);
30 ext = extent_item(coord) + coord_last_unit_pos(coord);
31 *pos_in_unit = extent_get_width(ext) - 1;
34 return ext;
37 /* item_plugin->f.utmost_child */
38 /* Return the child. Coord is set to extent item. Find jnode corresponding
39 either to first or to last unformatted node pointed by the item */
40 int utmost_child_extent(const coord_t * coord, sideof side, jnode ** childp)
42 reiser4_extent *ext;
43 reiser4_block_nr pos_in_unit;
45 ext = extent_utmost_ext(coord, side, &pos_in_unit);
47 switch (state_of_extent(ext)) {
48 case HOLE_EXTENT:
49 *childp = NULL;
50 return 0;
51 case ALLOCATED_EXTENT:
52 case UNALLOCATED_EXTENT:
53 break;
54 default:
55 /* this should never happen */
56 assert("vs-1417", 0);
60 reiser4_key key;
61 reiser4_tree *tree;
62 unsigned long index;
64 if (side == LEFT_SIDE) {
65 /* get key of first byte addressed by the extent */
66 item_key_by_coord(coord, &key);
67 } else {
68 /* get key of byte which next after last byte addressed by the extent */
69 append_key_extent(coord, &key);
72 assert("vs-544",
73 (get_key_offset(&key) >> PAGE_CACHE_SHIFT) < ~0ul);
74 /* index of first or last (depending on @side) page addressed
75 by the extent */
76 index =
77 (unsigned long)(get_key_offset(&key) >> PAGE_CACHE_SHIFT);
78 if (side == RIGHT_SIDE)
79 index--;
81 tree = coord->node->zjnode.tree;
82 *childp = jlookup(tree, get_key_objectid(&key), index);
85 return 0;
88 /* item_plugin->f.utmost_child_real_block */
89 /* Return the child's block, if allocated. */
90 int
91 utmost_child_real_block_extent(const coord_t * coord, sideof side,
92 reiser4_block_nr * block)
94 reiser4_extent *ext;
96 ext = extent_by_coord(coord);
98 switch (state_of_extent(ext)) {
99 case ALLOCATED_EXTENT:
100 *block = extent_get_start(ext);
101 if (side == RIGHT_SIDE)
102 *block += extent_get_width(ext) - 1;
103 break;
104 case HOLE_EXTENT:
105 case UNALLOCATED_EXTENT:
106 *block = 0;
107 break;
108 default:
109 /* this should never happen */
110 assert("vs-1418", 0);
113 return 0;
116 /* item_plugin->f.scan */
117 /* Performs leftward scanning starting from an unformatted node and its parent coordinate.
118 This scan continues, advancing the parent coordinate, until either it encounters a
119 formatted child or it finishes scanning this node.
121 If unallocated, the entire extent must be dirty and in the same atom. (Actually, I'm
122 not sure this is last property (same atom) is enforced, but it should be the case since
123 one atom must write the parent and the others must read the parent, thus fusing?). In
124 any case, the code below asserts this case for unallocated extents. Unallocated
125 extents are thus optimized because we can skip to the endpoint when scanning.
127 It returns control to reiser4_scan_extent, handles these terminating conditions,
128 e.g., by loading the next twig.
130 int reiser4_scan_extent(flush_scan * scan)
132 coord_t coord;
133 jnode *neighbor;
134 unsigned long scan_index, unit_index, unit_width, scan_max, scan_dist;
135 reiser4_block_nr unit_start;
136 __u64 oid;
137 reiser4_key key;
138 int ret = 0, allocated, incr;
139 reiser4_tree *tree;
141 if (!JF_ISSET(scan->node, JNODE_DIRTY)) {
142 scan->stop = 1;
143 return 0; /* Race with truncate, this node is already
144 * truncated. */
147 coord_dup(&coord, &scan->parent_coord);
149 assert("jmacd-1404", !reiser4_scan_finished(scan));
150 assert("jmacd-1405", jnode_get_level(scan->node) == LEAF_LEVEL);
151 assert("jmacd-1406", jnode_is_unformatted(scan->node));
153 /* The scan_index variable corresponds to the current page index of the
154 unformatted block scan position. */
155 scan_index = index_jnode(scan->node);
157 assert("jmacd-7889", item_is_extent(&coord));
159 repeat:
160 /* objectid of file */
161 oid = get_key_objectid(item_key_by_coord(&coord, &key));
163 allocated = !extent_is_unallocated(&coord);
164 /* Get the values of this extent unit: */
165 unit_index = extent_unit_index(&coord);
166 unit_width = extent_unit_width(&coord);
167 unit_start = extent_unit_start(&coord);
169 assert("jmacd-7187", unit_width > 0);
170 assert("jmacd-7188", scan_index >= unit_index);
171 assert("jmacd-7189", scan_index <= unit_index + unit_width - 1);
173 /* Depending on the scan direction, we set different maximum values for scan_index
174 (scan_max) and the number of nodes that would be passed if the scan goes the
175 entire way (scan_dist). Incr is an integer reflecting the incremental
176 direction of scan_index. */
177 if (reiser4_scanning_left(scan)) {
178 scan_max = unit_index;
179 scan_dist = scan_index - unit_index;
180 incr = -1;
181 } else {
182 scan_max = unit_index + unit_width - 1;
183 scan_dist = scan_max - unit_index;
184 incr = +1;
187 tree = coord.node->zjnode.tree;
189 /* If the extent is allocated we have to check each of its blocks. If the extent
190 is unallocated we can skip to the scan_max. */
191 if (allocated) {
192 do {
193 neighbor = jlookup(tree, oid, scan_index);
194 if (neighbor == NULL)
195 goto stop_same_parent;
197 if (scan->node != neighbor
198 && !reiser4_scan_goto(scan, neighbor)) {
199 /* @neighbor was jput() by reiser4_scan_goto */
200 goto stop_same_parent;
203 ret = scan_set_current(scan, neighbor, 1, &coord);
204 if (ret != 0) {
205 goto exit;
208 /* reference to @neighbor is stored in @scan, no need
209 to jput(). */
210 scan_index += incr;
212 } while (incr + scan_max != scan_index);
214 } else {
215 /* Optimized case for unallocated extents, skip to the end. */
216 neighbor = jlookup(tree, oid, scan_max /*index */ );
217 if (neighbor == NULL) {
218 /* Race with truncate */
219 scan->stop = 1;
220 ret = 0;
221 goto exit;
224 assert("zam-1043",
225 reiser4_blocknr_is_fake(jnode_get_block(neighbor)));
227 ret = scan_set_current(scan, neighbor, scan_dist, &coord);
228 if (ret != 0) {
229 goto exit;
233 if (coord_sideof_unit(&coord, scan->direction) == 0
234 && item_is_extent(&coord)) {
235 /* Continue as long as there are more extent units. */
237 scan_index =
238 extent_unit_index(&coord) +
239 (reiser4_scanning_left(scan) ?
240 extent_unit_width(&coord) - 1 : 0);
241 goto repeat;
244 if (0) {
245 stop_same_parent:
247 /* If we are scanning left and we stop in the middle of an allocated
248 extent, we know the preceder immediately.. */
249 /* middle of extent is (scan_index - unit_index) != 0. */
250 if (reiser4_scanning_left(scan) &&
251 (scan_index - unit_index) != 0) {
252 /* FIXME(B): Someone should step-through and verify that this preceder
253 calculation is indeed correct. */
254 /* @unit_start is starting block (number) of extent
255 unit. Flush stopped at the @scan_index block from
256 the beginning of the file, which is (scan_index -
257 unit_index) block within extent.
259 if (unit_start) {
260 /* skip preceder update when we are at hole */
261 scan->preceder_blk =
262 unit_start + scan_index - unit_index;
263 check_preceder(scan->preceder_blk);
267 /* In this case, we leave coord set to the parent of scan->node. */
268 scan->stop = 1;
270 } else {
271 /* In this case, we are still scanning, coord is set to the next item which is
272 either off-the-end of the node or not an extent. */
273 assert("jmacd-8912", scan->stop == 0);
274 assert("jmacd-7812",
275 (coord_is_after_sideof_unit(&coord, scan->direction)
276 || !item_is_extent(&coord)));
279 ret = 0;
280 exit:
281 return ret;
284 /* ask block allocator for some blocks */
285 static void extent_allocate_blocks(reiser4_blocknr_hint *preceder,
286 reiser4_block_nr wanted_count,
287 reiser4_block_nr *first_allocated,
288 reiser4_block_nr *allocated,
289 block_stage_t block_stage)
291 *allocated = wanted_count;
292 preceder->max_dist = 0; /* scan whole disk, if needed */
294 /* that number of blocks (wanted_count) is either in UNALLOCATED or in GRABBED */
295 preceder->block_stage = block_stage;
297 /* FIXME: we do not handle errors here now */
298 check_me("vs-420",
299 reiser4_alloc_blocks(preceder, first_allocated, allocated,
300 BA_PERMANENT) == 0);
301 /* update flush_pos's preceder to last allocated block number */
302 preceder->blk = *first_allocated + *allocated - 1;
305 /* when on flush time unallocated extent is to be replaced with allocated one it may happen that one unallocated extent
306 will have to be replaced with set of allocated extents. In this case insert_into_item will be called which may have
307 to add new nodes into tree. Space for that is taken from inviolable reserve (5%). */
308 static reiser4_block_nr reserve_replace(void)
310 reiser4_block_nr grabbed, needed;
312 grabbed = get_current_context()->grabbed_blocks;
313 needed = estimate_one_insert_into_item(current_tree);
314 check_me("vpf-340", !reiser4_grab_space_force(needed, BA_RESERVED));
315 return grabbed;
318 static void free_replace_reserved(reiser4_block_nr grabbed)
320 reiser4_context *ctx;
322 ctx = get_current_context();
323 grabbed2free(ctx, get_super_private(ctx->super),
324 ctx->grabbed_blocks - grabbed);
327 /* Block offset of first block addressed by unit */
328 __u64 extent_unit_index(const coord_t * item)
330 reiser4_key key;
332 assert("vs-648", coord_is_existing_unit(item));
333 unit_key_by_coord(item, &key);
334 return get_key_offset(&key) >> current_blocksize_bits;
337 /* AUDIT shouldn't return value be of reiser4_block_nr type?
338 Josh's answer: who knows? Is a "number of blocks" the same type as "block offset"? */
339 __u64 extent_unit_width(const coord_t * item)
341 assert("vs-649", coord_is_existing_unit(item));
342 return width_by_coord(item);
345 /* Starting block location of this unit */
346 static reiser4_block_nr extent_unit_start(const coord_t * item)
348 return extent_get_start(extent_by_coord(item));
352 * split_allocated_extent -
353 * @coord:
354 * @pos_in_unit:
356 * replace allocated extent with two allocated extents
358 static int split_allocated_extent(coord_t *coord, reiser4_block_nr pos_in_unit)
360 int result;
361 struct replace_handle *h;
362 reiser4_extent *ext;
363 reiser4_block_nr grabbed;
365 ext = extent_by_coord(coord);
366 assert("vs-1410", state_of_extent(ext) == ALLOCATED_EXTENT);
367 assert("vs-1411", extent_get_width(ext) > pos_in_unit);
369 h = kmalloc(sizeof(*h), reiser4_ctx_gfp_mask_get());
370 if (h == NULL)
371 return RETERR(-ENOMEM);
372 h->coord = coord;
373 h->lh = znode_lh(coord->node);
374 h->pkey = &h->key;
375 unit_key_by_coord(coord, h->pkey);
376 set_key_offset(h->pkey,
377 (get_key_offset(h->pkey) +
378 pos_in_unit * current_blocksize));
379 reiser4_set_extent(&h->overwrite, extent_get_start(ext),
380 pos_in_unit);
381 reiser4_set_extent(&h->new_extents[0],
382 extent_get_start(ext) + pos_in_unit,
383 extent_get_width(ext) - pos_in_unit);
384 h->nr_new_extents = 1;
385 h->flags = COPI_DONT_SHIFT_LEFT;
386 h->paste_key = h->key;
388 /* reserve space for extent unit paste, @grabbed is reserved before */
389 grabbed = reserve_replace();
390 result = reiser4_replace_extent(h, 0 /* leave @coord set to overwritten
391 extent */);
392 /* restore reserved */
393 free_replace_reserved(grabbed);
394 kfree(h);
395 return result;
398 /* replace extent @ext by extent @replace. Try to merge @replace with previous extent of the item (if there is
399 one). Return 1 if it succeeded, 0 - otherwise */
400 static int try_to_merge_with_left(coord_t *coord, reiser4_extent *ext,
401 reiser4_extent *replace)
403 assert("vs-1415", extent_by_coord(coord) == ext);
405 if (coord->unit_pos == 0
406 || state_of_extent(ext - 1) != ALLOCATED_EXTENT)
407 /* @ext either does not exist or is not allocated extent */
408 return 0;
409 if (extent_get_start(ext - 1) + extent_get_width(ext - 1) !=
410 extent_get_start(replace))
411 return 0;
413 /* we can glue, widen previous unit */
414 extent_set_width(ext - 1,
415 extent_get_width(ext - 1) + extent_get_width(replace));
417 if (extent_get_width(ext) != extent_get_width(replace)) {
418 /* make current extent narrower */
419 if (state_of_extent(ext) == ALLOCATED_EXTENT)
420 extent_set_start(ext,
421 extent_get_start(ext) +
422 extent_get_width(replace));
423 extent_set_width(ext,
424 extent_get_width(ext) -
425 extent_get_width(replace));
426 } else {
427 /* current extent completely glued with its left neighbor, remove it */
428 coord_t from, to;
430 coord_dup(&from, coord);
431 from.unit_pos = nr_units_extent(coord) - 1;
432 coord_dup(&to, &from);
434 /* currently cut from extent can cut either from the beginning or from the end. Move place which got
435 freed after unit removal to end of item */
436 memmove(ext, ext + 1,
437 (from.unit_pos -
438 coord->unit_pos) * sizeof(reiser4_extent));
439 /* wipe part of item which is going to be cut, so that node_check will not be confused */
440 cut_node_content(&from, &to, NULL, NULL, NULL);
442 znode_make_dirty(coord->node);
443 /* move coord back */
444 coord->unit_pos--;
445 return 1;
449 * conv_extent - replace extent with 2 ones
450 * @coord: coordinate of extent to be replaced
451 * @replace: extent to overwrite the one @coord is set to
453 * Overwrites extent @coord is set to and paste one extent unit after
454 * overwritten one if @replace is shorter than initial extent
456 static int conv_extent(coord_t *coord, reiser4_extent *replace)
458 int result;
459 struct replace_handle *h;
460 reiser4_extent *ext;
461 reiser4_block_nr start, width, new_width;
462 reiser4_block_nr grabbed;
463 extent_state state;
465 ext = extent_by_coord(coord);
466 state = state_of_extent(ext);
467 start = extent_get_start(ext);
468 width = extent_get_width(ext);
469 new_width = extent_get_width(replace);
471 assert("vs-1458", (state == UNALLOCATED_EXTENT ||
472 state == ALLOCATED_EXTENT));
473 assert("vs-1459", width >= new_width);
475 if (try_to_merge_with_left(coord, ext, replace)) {
476 /* merged @replace with left neighbor. Current unit is either
477 removed or narrowed */
478 return 0;
481 if (width == new_width) {
482 /* replace current extent with @replace */
483 *ext = *replace;
484 znode_make_dirty(coord->node);
485 return 0;
488 h = kmalloc(sizeof(*h), reiser4_ctx_gfp_mask_get());
489 if (h == NULL)
490 return RETERR(-ENOMEM);
491 h->coord = coord;
492 h->lh = znode_lh(coord->node);
493 h->pkey = &h->key;
494 unit_key_by_coord(coord, h->pkey);
495 set_key_offset(h->pkey,
496 (get_key_offset(h->pkey) + new_width * current_blocksize));
497 h->overwrite = *replace;
499 /* replace @ext with @replace and padding extent */
500 reiser4_set_extent(&h->new_extents[0],
501 (state == ALLOCATED_EXTENT) ?
502 (start + new_width) :
503 UNALLOCATED_EXTENT_START,
504 width - new_width);
505 h->nr_new_extents = 1;
506 h->flags = COPI_DONT_SHIFT_LEFT;
507 h->paste_key = h->key;
509 /* reserve space for extent unit paste, @grabbed is reserved before */
510 grabbed = reserve_replace();
511 result = reiser4_replace_extent(h, 0 /* leave @coord set to overwritten
512 extent */);
514 /* restore reserved */
515 free_replace_reserved(grabbed);
516 kfree(h);
517 return result;
521 * assign_real_blocknrs
522 * @flush_pos:
523 * @oid: objectid of file jnodes to assign block number to belongs to
524 * @index: first jnode on the range
525 * @count: number of jnodes to assign block numbers to
526 * @first: start of allocated block range
528 * Assigns block numbers to each of @count jnodes. Index of first jnode is
529 * @index. Jnodes get lookuped with jlookup.
531 static void assign_real_blocknrs(flush_pos_t *flush_pos, oid_t oid,
532 unsigned long index, reiser4_block_nr count,
533 reiser4_block_nr first)
535 unsigned long i;
536 reiser4_tree *tree;
537 txn_atom *atom;
538 int nr;
540 atom = atom_locked_by_fq(flush_pos->fq);
541 assert("vs-1468", atom);
542 BUG_ON(atom == NULL);
544 nr = 0;
545 tree = current_tree;
546 for (i = 0; i < count; ++i, ++index) {
547 jnode *node;
549 node = jlookup(tree, oid, index);
550 assert("", node != NULL);
551 BUG_ON(node == NULL);
553 spin_lock_jnode(node);
554 assert("", !jnode_is_flushprepped(node));
555 assert("vs-1475", node->atom == atom);
556 assert("vs-1476", atomic_read(&node->x_count) > 0);
558 JF_CLR(node, JNODE_FLUSH_RESERVED);
559 jnode_set_block(node, &first);
560 unformatted_make_reloc(node, flush_pos->fq);
561 ON_DEBUG(count_jnode(node->atom, node, NODE_LIST(node),
562 FQ_LIST, 0));
563 spin_unlock_jnode(node);
564 first++;
566 atomic_dec(&node->x_count);
567 nr ++;
570 spin_unlock_atom(atom);
571 return;
575 * make_node_ovrwr - assign node to overwrite set
576 * @jnodes: overwrite set list head
577 * @node: jnode to belong to overwrite set
579 * Sets OVRWR jnode state bit and puts @node to the end of list head @jnodes
580 * which is an accumulator for nodes before they get to overwrite set list of
581 * atom.
583 static void make_node_ovrwr(struct list_head *jnodes, jnode *node)
585 spin_lock_jnode(node);
587 assert("zam-917", !JF_ISSET(node, JNODE_RELOC));
588 assert("zam-918", !JF_ISSET(node, JNODE_OVRWR));
590 JF_SET(node, JNODE_OVRWR);
591 list_move_tail(&node->capture_link, jnodes);
592 ON_DEBUG(count_jnode(node->atom, node, DIRTY_LIST, OVRWR_LIST, 0));
594 spin_unlock_jnode(node);
598 * mark_jnodes_overwrite - put bunch of jnodes to overwrite set
599 * @flush_pos: flush position
600 * @oid: objectid of file jnodes belong to
601 * @index: starting index
602 * @width: extent width
604 * Puts nodes of one extent (file objectid @oid, extent width @width) to atom's
605 * overwrite set. Starting from the one with index @index. If end of slum is
606 * detected (node is not found or flushprepped) - stop iterating and set flush
607 * position's state to POS_INVALID.
609 static void mark_jnodes_overwrite(flush_pos_t *flush_pos, oid_t oid,
610 unsigned long index, reiser4_block_nr width)
612 unsigned long i;
613 reiser4_tree *tree;
614 jnode *node;
615 txn_atom *atom;
616 LIST_HEAD(jnodes);
618 tree = current_tree;
620 atom = atom_locked_by_fq(reiser4_pos_fq(flush_pos));
621 assert("vs-1478", atom);
623 for (i = flush_pos->pos_in_unit; i < width; i++, index++) {
624 node = jlookup(tree, oid, index);
625 if (!node) {
626 flush_pos->state = POS_INVALID;
627 break;
629 if (jnode_check_flushprepped(node)) {
630 flush_pos->state = POS_INVALID;
631 atomic_dec(&node->x_count);
632 break;
634 if (node->atom != atom) {
635 flush_pos->state = POS_INVALID;
636 atomic_dec(&node->x_count);
637 break;
639 make_node_ovrwr(&jnodes, node);
640 atomic_dec(&node->x_count);
643 list_splice_init(&jnodes, ATOM_OVRWR_LIST(atom)->prev);
644 spin_unlock_atom(atom);
648 * allocated_extent_slum_size
649 * @flush_pos:
650 * @oid:
651 * @index:
652 * @count:
656 static int allocated_extent_slum_size(flush_pos_t *flush_pos, oid_t oid,
657 unsigned long index, unsigned long count)
659 unsigned long i;
660 reiser4_tree *tree;
661 txn_atom *atom;
662 int nr;
664 atom = atom_locked_by_fq(reiser4_pos_fq(flush_pos));
665 assert("vs-1468", atom);
667 nr = 0;
668 tree = current_tree;
669 for (i = 0; i < count; ++i, ++index) {
670 jnode *node;
672 node = jlookup(tree, oid, index);
673 if (!node)
674 break;
676 if (jnode_check_flushprepped(node)) {
677 atomic_dec(&node->x_count);
678 break;
681 if (node->atom != atom) {
683 * this is possible on overwrite: extent_write may
684 * capture several unformatted nodes without capturing
685 * any formatted nodes.
687 atomic_dec(&node->x_count);
688 break;
691 assert("vs-1476", atomic_read(&node->x_count) > 1);
692 atomic_dec(&node->x_count);
693 nr ++;
696 spin_unlock_atom(atom);
697 return nr;
701 * alloc_extent
702 * @flush_pos:
705 * this is called by handle_pos_on_twig to proceed extent unit flush_pos->coord
706 * is set to. It is to prepare for flushing sequence of not flushprepped nodes
707 * (slum). It supposes that slum starts at flush_pos->pos_in_unit position
708 * within the extent. Slum gets to relocate set if flush_pos->leaf_relocate is
709 * set to 1 and to overwrite set otherwise
711 int reiser4_alloc_extent(flush_pos_t *flush_pos)
713 coord_t *coord;
714 reiser4_extent *ext;
715 reiser4_extent replace_ext;
716 oid_t oid;
717 reiser4_block_nr protected;
718 reiser4_block_nr start;
719 __u64 index;
720 __u64 width;
721 extent_state state;
722 int result;
723 reiser4_block_nr first_allocated;
724 __u64 allocated;
725 reiser4_key key;
726 block_stage_t block_stage;
728 assert("vs-1468", flush_pos->state == POS_ON_EPOINT);
729 assert("vs-1469", coord_is_existing_unit(&flush_pos->coord)
730 && item_is_extent(&flush_pos->coord));
732 coord = &flush_pos->coord;
734 ext = extent_by_coord(coord);
735 state = state_of_extent(ext);
736 if (state == HOLE_EXTENT) {
737 flush_pos->state = POS_INVALID;
738 return 0;
741 item_key_by_coord(coord, &key);
742 oid = get_key_objectid(&key);
743 index = extent_unit_index(coord) + flush_pos->pos_in_unit;
744 start = extent_get_start(ext);
745 width = extent_get_width(ext);
747 assert("vs-1457", width > flush_pos->pos_in_unit);
749 if (flush_pos->leaf_relocate || state == UNALLOCATED_EXTENT) {
750 /* relocate */
751 if (flush_pos->pos_in_unit) {
752 /* split extent unit into two */
753 result =
754 split_allocated_extent(coord,
755 flush_pos->pos_in_unit);
756 flush_pos->pos_in_unit = 0;
757 return result;
760 /* limit number of nodes to allocate */
761 if (flush_pos->nr_to_write < width)
762 width = flush_pos->nr_to_write;
764 if (state == ALLOCATED_EXTENT) {
766 * all protected nodes are not flushprepped, therefore
767 * they are counted as flush_reserved
769 block_stage = BLOCK_FLUSH_RESERVED;
770 protected = allocated_extent_slum_size(flush_pos, oid,
771 index, width);
772 if (protected == 0) {
773 flush_pos->state = POS_INVALID;
774 flush_pos->pos_in_unit = 0;
775 return 0;
777 } else {
778 block_stage = BLOCK_UNALLOCATED;
779 protected = width;
783 * look at previous unit if possible. If it is allocated, make
784 * preceder more precise
786 if (coord->unit_pos &&
787 (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
788 reiser4_pos_hint(flush_pos)->blk =
789 extent_get_start(ext - 1) +
790 extent_get_width(ext - 1);
792 /* allocate new block numbers for protected nodes */
793 extent_allocate_blocks(reiser4_pos_hint(flush_pos),
794 protected,
795 &first_allocated, &allocated,
796 block_stage);
798 if (state == ALLOCATED_EXTENT)
800 * on relocating - free nodes which are going to be
801 * relocated
803 reiser4_dealloc_blocks(&start, &allocated,
804 BLOCK_ALLOCATED, BA_DEFER);
806 /* assign new block numbers to protected nodes */
807 assign_real_blocknrs(flush_pos, oid, index, allocated, first_allocated);
809 /* prepare extent which will replace current one */
810 reiser4_set_extent(&replace_ext, first_allocated, allocated);
812 /* adjust extent item */
813 result = conv_extent(coord, &replace_ext);
814 if (result != 0 && result != -ENOMEM) {
815 warning("vs-1461",
816 "Failed to allocate extent. Should not happen\n");
817 return result;
821 * break flush: we prepared for flushing as many blocks as we
822 * were asked for
824 if (flush_pos->nr_to_write == allocated)
825 flush_pos->state = POS_INVALID;
826 } else {
827 /* overwrite */
828 mark_jnodes_overwrite(flush_pos, oid, index, width);
830 flush_pos->pos_in_unit = 0;
831 return 0;
834 /* if @key is glueable to the item @coord is set to */
835 static int must_insert(const coord_t *coord, const reiser4_key *key)
837 reiser4_key last;
839 if (item_id_by_coord(coord) == EXTENT_POINTER_ID
840 && keyeq(append_key_extent(coord, &last), key))
841 return 0;
842 return 1;
845 /* copy extent @copy to the end of @node. It may have to either insert new item after the last one, or append last item,
846 or modify last unit of last item to have greater width */
847 static int put_unit_to_end(znode *node, const reiser4_key *key,
848 reiser4_extent *copy_ext)
850 int result;
851 coord_t coord;
852 cop_insert_flag flags;
853 reiser4_extent *last_ext;
854 reiser4_item_data data;
856 /* set coord after last unit in an item */
857 coord_init_last_unit(&coord, node);
858 coord.between = AFTER_UNIT;
860 flags =
861 COPI_DONT_SHIFT_LEFT | COPI_DONT_SHIFT_RIGHT | COPI_DONT_ALLOCATE;
862 if (must_insert(&coord, key)) {
863 result =
864 insert_by_coord(&coord, init_new_extent(&data, copy_ext, 1),
865 key, NULL /*lh */ , flags);
867 } else {
868 /* try to glue with last unit */
869 last_ext = extent_by_coord(&coord);
870 if (state_of_extent(last_ext) &&
871 extent_get_start(last_ext) + extent_get_width(last_ext) ==
872 extent_get_start(copy_ext)) {
873 /* widen last unit of node */
874 extent_set_width(last_ext,
875 extent_get_width(last_ext) +
876 extent_get_width(copy_ext));
877 znode_make_dirty(node);
878 return 0;
881 /* FIXME: put an assertion here that we can not merge last unit in @node and new unit */
882 result =
883 insert_into_item(&coord, NULL /*lh */ , key,
884 init_new_extent(&data, copy_ext, 1),
885 flags);
888 assert("vs-438", result == 0 || result == -E_NODE_FULL);
889 return result;
892 /* @coord is set to extent unit */
893 squeeze_result squalloc_extent(znode *left, const coord_t *coord,
894 flush_pos_t *flush_pos,
895 reiser4_key *stop_key)
897 reiser4_extent *ext;
898 __u64 index;
899 __u64 width;
900 reiser4_block_nr start;
901 extent_state state;
902 oid_t oid;
903 reiser4_block_nr first_allocated;
904 __u64 allocated;
905 __u64 protected;
906 reiser4_extent copy_extent;
907 reiser4_key key;
908 int result;
909 block_stage_t block_stage;
911 assert("vs-1457", flush_pos->pos_in_unit == 0);
912 assert("vs-1467", coord_is_leftmost_unit(coord));
913 assert("vs-1467", item_is_extent(coord));
915 ext = extent_by_coord(coord);
916 index = extent_unit_index(coord);
917 start = extent_get_start(ext);
918 width = extent_get_width(ext);
919 state = state_of_extent(ext);
920 unit_key_by_coord(coord, &key);
921 oid = get_key_objectid(&key);
923 if ((flush_pos->leaf_relocate && state == ALLOCATED_EXTENT) ||
924 (state == UNALLOCATED_EXTENT)) {
925 /* relocate */
926 if (state == ALLOCATED_EXTENT) {
927 /* all protected nodes are not flushprepped, therefore
928 * they are counted as flush_reserved */
929 block_stage = BLOCK_FLUSH_RESERVED;
930 protected = allocated_extent_slum_size(flush_pos, oid,
931 index, width);
932 if (protected == 0) {
933 flush_pos->state = POS_INVALID;
934 flush_pos->pos_in_unit = 0;
935 return 0;
937 } else {
938 block_stage = BLOCK_UNALLOCATED;
939 protected = width;
943 * look at previous unit if possible. If it is allocated, make
944 * preceder more precise
946 if (coord->unit_pos &&
947 (state_of_extent(ext - 1) == ALLOCATED_EXTENT))
948 reiser4_pos_hint(flush_pos)->blk =
949 extent_get_start(ext - 1) +
950 extent_get_width(ext - 1);
952 /* allocate new block numbers for protected nodes */
953 extent_allocate_blocks(reiser4_pos_hint(flush_pos),
954 protected,
955 &first_allocated, &allocated,
956 block_stage);
958 /* prepare extent which will be copied to left */
959 reiser4_set_extent(&copy_extent, first_allocated, allocated);
961 result = put_unit_to_end(left, &key, &copy_extent);
962 if (result == -E_NODE_FULL) {
963 int target_block_stage;
965 /* free blocks which were just allocated */
966 target_block_stage =
967 (state ==
968 ALLOCATED_EXTENT) ? BLOCK_FLUSH_RESERVED :
969 BLOCK_UNALLOCATED;
970 reiser4_dealloc_blocks(&first_allocated, &allocated,
971 target_block_stage,
972 BA_PERMANENT);
974 /* rewind the preceder. */
975 flush_pos->preceder.blk = first_allocated;
976 check_preceder(flush_pos->preceder.blk);
978 return SQUEEZE_TARGET_FULL;
981 if (state == ALLOCATED_EXTENT) {
982 /* free nodes which were relocated */
983 reiser4_dealloc_blocks(&start, &allocated,
984 BLOCK_ALLOCATED, BA_DEFER);
987 /* assign new block numbers to protected nodes */
988 assign_real_blocknrs(flush_pos, oid, index, allocated,
989 first_allocated);
991 set_key_offset(&key,
992 get_key_offset(&key) +
993 (allocated << current_blocksize_bits));
994 } else {
996 * overwrite: try to copy unit as it is to left neighbor and
997 * make all first not flushprepped nodes overwrite nodes
999 reiser4_set_extent(&copy_extent, start, width);
1000 result = put_unit_to_end(left, &key, &copy_extent);
1001 if (result == -E_NODE_FULL)
1002 return SQUEEZE_TARGET_FULL;
1004 if (state != HOLE_EXTENT)
1005 mark_jnodes_overwrite(flush_pos, oid, index, width);
1006 set_key_offset(&key,
1007 get_key_offset(&key) +
1008 (width << current_blocksize_bits));
1010 *stop_key = key;
1011 return SQUEEZE_CONTINUE;
1014 int key_by_offset_extent(struct inode *inode, loff_t off, reiser4_key * key)
1016 return key_by_inode_and_offset_common(inode, off, key);
1020 * Local variables:
1021 * c-indentation-style: "K&R"
1022 * mode-name: "LC"
1023 * c-basic-offset: 8
1024 * tab-width: 8
1025 * fill-column: 79
1026 * scroll-step: 1
1027 * End: