Exemplo n.º 1
0
/* like coord_by_key(), but starts traversal from vroot of @object rather than
 * from tree root. */
lookup_result reiser4_object_lookup(struct inode *object,
				    const reiser4_key * key,
				    coord_t *coord,
				    lock_handle * lh,
				    znode_lock_mode lock_mode,
				    lookup_bias bias,
				    tree_level lock_level,
				    tree_level stop_level, __u32 flags,
				    ra_info_t *info)
{
	cbk_handle handle;
	lock_handle parent_lh;
	lookup_result result;

	init_lh(lh);
	init_lh(&parent_lh);

	assert("nikita-3023", reiser4_schedulable());

	assert("nikita-354", key != NULL);
	assert("nikita-355", coord != NULL);
	assert("nikita-356", (bias == FIND_EXACT)
	       || (bias == FIND_MAX_NOT_MORE_THAN));
	assert("nikita-357", stop_level >= LEAF_LEVEL);
	/* no locks can be held during tree search by key */
	assert("nikita-2104", lock_stack_isclean(get_current_lock_stack()));

	cbk_pack(&handle,
		 object != NULL ? reiser4_tree_by_inode(object) : current_tree,
		 key,
		 coord,
		 lh,
		 &parent_lh,
		 lock_mode, bias, lock_level, stop_level, flags, info);
	handle.object = object;

	result = coord_by_handle(&handle);
	assert("nikita-3247",
	       ergo(!IS_CBKERR(result), coord->node == lh->node));
	return result;
}
Exemplo n.º 2
0
/**
 * 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;
}
Exemplo n.º 3
0
/**
 * 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;
}
Exemplo n.º 4
0
/* 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;
}
Exemplo n.º 5
0
/* main tree lookup procedure

   Check coord cache. If key we are looking for is not found there, call cbk()
   to do real tree traversal.

   As we have extents on the twig level, @lock_level and @stop_level can
   be different from LEAF_LEVEL and each other.

   Thread cannot keep any reiser4 locks (tree, znode, dk spin-locks, or znode
   long term locks) while calling this.
*/
lookup_result coord_by_key(reiser4_tree * tree	/* tree to perform search
						 * in. Usually this tree is
						 * part of file-system
						 * super-block */ ,
			   const reiser4_key * key /* key to look for */ ,
			   coord_t *coord	/* where to store found
						 * position in a tree. Fields
						 * in "coord" are only valid if
						 * coord_by_key() returned
						 * "CBK_COORD_FOUND" */ ,
			   lock_handle * lh,	/* resulting lock handle */
			   znode_lock_mode lock_mode	/* type of lookup we
							 * want on node. Pass
							 * ZNODE_READ_LOCK here
							 * if you only want to
							 * read item found and
							 * ZNODE_WRITE_LOCK if
							 * you want to modify
							 * it */ ,
			   lookup_bias bias	/* what to return if coord
						 * with exactly the @key is
						 * not in the tree */ ,
			   tree_level lock_level/* tree level where to start
						 * taking @lock type of
						 * locks */ ,
			   tree_level stop_level/* tree level to stop. Pass
						 * LEAF_LEVEL or TWIG_LEVEL
						 * here Item being looked
						 * for has to be between
						 * @lock_level and
						 * @stop_level, inclusive */ ,
			   __u32 flags /* search flags */ ,
			   ra_info_t *
			   info
			   /* information about desired tree traversal
			    * readahead */
			   )
{
	cbk_handle handle;
	lock_handle parent_lh;
	lookup_result result;

	init_lh(lh);
	init_lh(&parent_lh);

	assert("nikita-3023", reiser4_schedulable());

	assert("nikita-353", tree != NULL);
	assert("nikita-354", key != NULL);
	assert("nikita-355", coord != NULL);
	assert("nikita-356", (bias == FIND_EXACT)
	       || (bias == FIND_MAX_NOT_MORE_THAN));
	assert("nikita-357", stop_level >= LEAF_LEVEL);
	/* no locks can be held during tree traversal */
	assert("nikita-2104", lock_stack_isclean(get_current_lock_stack()));

	cbk_pack(&handle,
		 tree,
		 key,
		 coord,
		 lh,
		 &parent_lh,
		 lock_mode, bias, lock_level, stop_level, flags, info);

	result = coord_by_handle(&handle);
	assert("nikita-3247",
	       ergo(!IS_CBKERR(result), coord->node == lh->node));
	return result;
}
Exemplo n.º 6
0
/**
 * 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;
}