/* * helper function used by traverse tree to start tree traversal not from the * tree root, but from @h->object's vroot, if possible. */ static int prepare_object_lookup(cbk_handle * h) { znode *vroot; int result; vroot = inode_get_vroot(h->object); if (vroot == NULL) { /* * object doesn't have known vroot, start from real tree root. */ return LOOKUP_CONT; } h->level = znode_get_level(vroot); /* take a long-term lock on vroot */ h->result = longterm_lock_znode(h->active_lh, vroot, cbk_lock_mode(h->level, h), ZNODE_LOCK_LOPRI); result = LOOKUP_REST; if (h->result == 0) { int isunique; int inside; isunique = h->flags & CBK_UNIQUE; /* check that key is inside vroot */ read_lock_dk(h->tree); inside = (znode_contains_key_strict(vroot, h->key, isunique) && !ZF_ISSET(vroot, JNODE_HEARD_BANSHEE)); read_unlock_dk(h->tree); if (inside) { h->result = zload(vroot); if (h->result == 0) { /* search for key in vroot. */ result = cbk_node_lookup(h); zrelse(vroot); /*h->active_lh->node); */ if (h->active_lh->node != vroot) { result = LOOKUP_REST; } else if (result == LOOKUP_CONT) { move_lh(h->parent_lh, h->active_lh); h->flags &= ~CBK_DKSET; } } } } zput(vroot); if (IS_CBKERR(h->result) || result == LOOKUP_REST) hput(h); return result; }
/** * find_start * @inode: * @id: * @offset: * * this is used by tail2extent and extent2tail to detect where previous * uncompleted conversion stopped */ static int find_start(struct inode *inode, reiser4_plugin_id id, __u64 *offset) { int result; lock_handle lh; coord_t coord; struct unix_file_info *ufo; int found; reiser4_key key; ufo = unix_file_inode_data(inode); init_lh(&lh); result = 0; found = 0; inode_file_plugin(inode)->key_by_inode(inode, *offset, &key); do { init_lh(&lh); result = find_file_item_nohint(&coord, &lh, &key, ZNODE_READ_LOCK, inode); if (result == CBK_COORD_FOUND) { if (coord.between == AT_UNIT) { /*coord_clear_iplug(&coord); */ result = zload(coord.node); if (result == 0) { if (item_id_by_coord(&coord) == id) found = 1; else item_plugin_by_coord(&coord)->s. file.append_key(&coord, &key); zrelse(coord.node); } } else result = RETERR(-ENOENT); } done_lh(&lh); } while (result == 0 && !found); *offset = get_key_offset(&key); return result; }
/** * tail2extent * @uf_info: * * */ int tail2extent(struct unix_file_info *uf_info) { int result; reiser4_key key; /* key of next byte to be moved to page */ char *p_data; /* data of page */ unsigned page_off = 0, /* offset within the page where to copy data */ count; /* number of bytes of item which can be * copied to page */ struct page *pages[TAIL2EXTENT_PAGE_NUM]; struct page *page; int done; /* set to 1 when all file is read */ char *item; int i; struct inode *inode; int first_iteration; int bytes; __u64 offset; assert("nikita-3362", ea_obtained(uf_info)); inode = unix_file_info_to_inode(uf_info); assert("nikita-3412", !IS_RDONLY(inode)); assert("vs-1649", uf_info->container != UF_CONTAINER_EXTENTS); assert("", !reiser4_inode_get_flag(inode, REISER4_PART_IN_CONV)); offset = 0; first_iteration = 1; result = 0; if (reiser4_inode_get_flag(inode, REISER4_PART_MIXED)) { /* * file is marked on disk as there was a conversion which did * not complete due to either crash or some error. Find which * offset tail conversion stopped at */ result = find_start(inode, FORMATTING_ID, &offset); if (result == -ENOENT) { /* no tail items found, everything is converted */ uf_info->container = UF_CONTAINER_EXTENTS; complete_conversion(inode); return 0; } else if (result != 0) /* some other error */ return result; first_iteration = 0; } reiser4_inode_set_flag(inode, REISER4_PART_IN_CONV); /* get key of first byte of a file */ inode_file_plugin(inode)->key_by_inode(inode, offset, &key); done = 0; while (done == 0) { memset(pages, 0, sizeof(pages)); result = reserve_tail2extent_iteration(inode); if (result != 0) { reiser4_inode_clr_flag(inode, REISER4_PART_IN_CONV); goto out; } if (first_iteration) { reiser4_inode_set_flag(inode, REISER4_PART_MIXED); reiser4_update_sd(inode); first_iteration = 0; } bytes = 0; for (i = 0; i < sizeof_array(pages) && done == 0; i++) { assert("vs-598", (get_key_offset(&key) & ~PAGE_CACHE_MASK) == 0); page = alloc_page(reiser4_ctx_gfp_mask_get()); if (!page) { result = RETERR(-ENOMEM); goto error; } page->index = (unsigned long)(get_key_offset(&key) >> PAGE_CACHE_SHIFT); /* * usually when one is going to longterm lock znode (as * find_file_item does, for instance) he must not hold * locked pages. However, there is an exception for * case tail2extent. Pages appearing here are not * reachable to everyone else, they are clean, they do * not have jnodes attached so keeping them locked do * not risk deadlock appearance */ assert("vs-983", !PagePrivate(page)); reiser4_invalidate_pages(inode->i_mapping, page->index, 1, 0); for (page_off = 0; page_off < PAGE_CACHE_SIZE;) { coord_t coord; lock_handle lh; /* get next item */ /* FIXME: we might want to readahead here */ init_lh(&lh); result = find_file_item_nohint(&coord, &lh, &key, ZNODE_READ_LOCK, inode); if (result != CBK_COORD_FOUND) { /* * error happened of not items of file * were found */ done_lh(&lh); page_cache_release(page); goto error; } if (coord.between == AFTER_UNIT) { /* * end of file is reached. Padd page * with zeros */ done_lh(&lh); done = 1; p_data = kmap_atomic(page, KM_USER0); memset(p_data + page_off, 0, PAGE_CACHE_SIZE - page_off); kunmap_atomic(p_data, KM_USER0); break; } result = zload(coord.node); if (result) { page_cache_release(page); done_lh(&lh); goto error; } assert("vs-856", coord.between == AT_UNIT); item = ((char *)item_body_by_coord(&coord)) + coord.unit_pos; /* how many bytes to copy */ count = item_length_by_coord(&coord) - coord.unit_pos; /* limit length of copy to end of page */ if (count > PAGE_CACHE_SIZE - page_off) count = PAGE_CACHE_SIZE - page_off; /* * copy item (as much as will fit starting from * the beginning of the item) into the page */ p_data = kmap_atomic(page, KM_USER0); memcpy(p_data + page_off, item, count); kunmap_atomic(p_data, KM_USER0); page_off += count; bytes += count; set_key_offset(&key, get_key_offset(&key) + count); zrelse(coord.node); done_lh(&lh); } /* end of loop which fills one page by content of * formatting items */ if (page_off) { /* something was copied into page */ pages[i] = page; } else { page_cache_release(page); assert("vs-1648", done == 1); break; } } /* end of loop through pages of one conversion iteration */ if (i > 0) { result = replace(inode, pages, i, bytes); release_all_pages(pages, sizeof_array(pages)); if (result) goto error; /* * We have to drop exclusive access to avoid deadlock * which may happen because called by reiser4_writepages * capture_unix_file requires to get non-exclusive * access to a file. It is safe to drop EA in the middle * of tail2extent conversion because write_unix_file, * setattr_unix_file(truncate), mmap_unix_file, * release_unix_file(extent2tail) checks if conversion * is not in progress (see comments before * get_exclusive_access_careful(). * Other processes that acquire non-exclusive access * (read_unix_file, reiser4_writepages, etc) should work * on partially converted files. */ drop_exclusive_access(uf_info); /* throttle the conversion FIXME-EDWARD: Pass the precise number of pages that was dirtied */ reiser4_throttle_write(inode, 1); get_exclusive_access(uf_info); /* * nobody is allowed to complete conversion but a * process which started it */ assert("", reiser4_inode_get_flag(inode, REISER4_PART_MIXED)); } } if (result == 0) { /* file is converted to extent items */ reiser4_inode_clr_flag(inode, REISER4_PART_IN_CONV); assert("vs-1697", reiser4_inode_get_flag(inode, REISER4_PART_MIXED)); uf_info->container = UF_CONTAINER_EXTENTS; complete_conversion(inode); } else { /* * conversion is not complete. Inode was already marked as * REISER4_PART_MIXED and stat-data were updated at the first * iteration of the loop above. */ error: release_all_pages(pages, sizeof_array(pages)); reiser4_inode_clr_flag(inode, REISER4_PART_IN_CONV); warning("edward-1548", "Partial conversion of %llu: %i", (unsigned long long)get_inode_oid(inode), result); } out: /* this flag should be cleared, otherwise get_exclusive_access_careful() will fall into infinite loop */ assert("edward-1549", !reiser4_inode_get_flag(inode, REISER4_PART_IN_CONV)); return result; }
/* Execute actor for each item (or unit, depending on @through_units_p), starting from @coord, right-ward, until either: - end of the tree is reached - unformatted node is met - error occurred - @actor returns 0 or less Error code, or last actor return value is returned. This is used by plugin/dir/hashe_dir.c:reiser4_find_entry() to move through sequence of entries with identical keys and alikes. */ int reiser4_iterate_tree(reiser4_tree * tree /* tree to scan */ , coord_t *coord /* coord to start from */ , lock_handle * lh /* lock handle to start with and to * update along the way */ , tree_iterate_actor_t actor /* function to call on each * item/unit */ , void *arg /* argument to pass to @actor */ , znode_lock_mode mode /* lock mode on scanned nodes */ , int through_units_p /* call @actor on each item or on * each unit */ ) { int result; assert("nikita-1143", tree != NULL); assert("nikita-1145", coord != NULL); assert("nikita-1146", lh != NULL); assert("nikita-1147", actor != NULL); result = zload(coord->node); coord_clear_iplug(coord); if (result != 0) return result; if (!coord_is_existing_unit(coord)) { zrelse(coord->node); return -ENOENT; } while ((result = actor(tree, coord, lh, arg)) > 0) { /* move further */ if ((through_units_p && coord_next_unit(coord)) || (!through_units_p && coord_next_item(coord))) { do { lock_handle couple; /* move to the next node */ init_lh(&couple); result = reiser4_get_right_neighbor(&couple, coord->node, (int)mode, GN_CAN_USE_UPPER_LEVELS); zrelse(coord->node); if (result == 0) { result = zload(couple.node); if (result != 0) { done_lh(&couple); return result; } coord_init_first_unit(coord, couple.node); done_lh(lh); move_lh(lh, &couple); } else return result; } while (node_is_empty(coord->node)); } assert("nikita-1149", coord_is_existing_unit(coord)); } zrelse(coord->node); return result; }
/** * reiser4_replace_extent - replace extent and paste 1 or 2 after it * @un_extent: coordinate of extent to be overwritten * @lh: need better comment * @key: need better comment * @exts_to_add: data prepared for insertion into tree * @replace: need better comment * @flags: need better comment * @return_insert_position: need better comment * * Overwrites one extent, pastes 1 or 2 more ones after overwritten one. If * @return_inserted_position is 1 - @un_extent and @lh are returned set to * first of newly inserted units, if it is 0 - @un_extent and @lh are returned * set to extent which was overwritten. */ int reiser4_replace_extent(struct replace_handle *h, int return_inserted_position) { int result; znode *orig_znode; /*ON_DEBUG(reiser4_extent orig_ext);*/ /* this is for debugging */ assert("vs-990", coord_is_existing_unit(h->coord)); assert("vs-1375", znode_is_write_locked(h->coord->node)); assert("vs-1426", extent_get_width(&h->overwrite) != 0); assert("vs-1427", extent_get_width(&h->new_extents[0]) != 0); assert("vs-1427", ergo(h->nr_new_extents == 2, extent_get_width(&h->new_extents[1]) != 0)); /* compose structure for paste */ init_new_extent(&h->item, &h->new_extents[0], h->nr_new_extents); coord_dup(&h->coord_after, h->coord); init_lh(&h->lh_after); copy_lh(&h->lh_after, h->lh); reiser4_tap_init(&h->watch, &h->coord_after, &h->lh_after, ZNODE_WRITE_LOCK); reiser4_tap_monitor(&h->watch); ON_DEBUG(h->orig_ext = *extent_by_coord(h->coord)); orig_znode = h->coord->node; #if REISER4_DEBUG /* make sure that key is set properly */ unit_key_by_coord(h->coord, &h->tmp); set_key_offset(&h->tmp, get_key_offset(&h->tmp) + extent_get_width(&h->overwrite) * current_blocksize); assert("vs-1080", keyeq(&h->tmp, &h->paste_key)); #endif /* set insert point after unit to be replaced */ h->coord->between = AFTER_UNIT; result = insert_into_item(h->coord, return_inserted_position ? h->lh : NULL, &h->paste_key, &h->item, h->flags); if (!result) { /* now we have to replace the unit after which new units were inserted. Its position is tracked by @watch */ reiser4_extent *ext; znode *node; node = h->coord_after.node; if (node != orig_znode) { coord_clear_iplug(&h->coord_after); result = zload(node); } if (likely(!result)) { ext = extent_by_coord(&h->coord_after); assert("vs-987", znode_is_loaded(node)); assert("vs-988", !memcmp(ext, &h->orig_ext, sizeof(*ext))); /* overwrite extent unit */ memcpy(ext, &h->overwrite, sizeof(reiser4_extent)); znode_make_dirty(node); if (node != orig_znode) zrelse(node); if (return_inserted_position == 0) { /* coord and lh are to be set to overwritten extent */ assert("vs-1662", WITH_DATA(node, !memcmp(&h->overwrite, extent_by_coord( &h->coord_after), sizeof(reiser4_extent)))); *h->coord = h->coord_after; done_lh(h->lh); copy_lh(h->lh, &h->lh_after); } else { /* h->coord and h->lh are to be set to first of inserted units */ assert("vs-1663", WITH_DATA(h->coord->node, !memcmp(&h->new_extents[0], extent_by_coord(h->coord), sizeof(reiser4_extent)))); assert("vs-1664", h->lh->node == h->coord->node); } } } reiser4_tap_done(&h->watch); return result; }