Beispiel #1
0
/* expand @coord as to accommodate for insertion of @no new entries starting
   from @pos, with total bodies size @size. */
static int expand_item(const coord_t * coord /* coord of item */ ,
		       int pos /* unit position */ , int no	/* number of new
								 * units*/ ,
		       int size /* total size of new units' data */ ,
		       unsigned int data_size	/* free space already reserved
						 * in the item for insertion */ )
{
	int entries;
	cde_unit_header *header;
	char *dent;
	int i;

	assert("nikita-1310", coord != NULL);
	assert("nikita-1311", pos >= 0);
	assert("nikita-1312", no > 0);
	assert("nikita-1313", data_size >= no * sizeof(directory_entry_format));
	assert("nikita-1343",
	       item_length_by_coord(coord) >=
	       (int)(size + data_size + no * sizeof *header));

	entries = units(coord);

	if (pos == entries)
		dent = address(coord, size);
	else
		dent = (char *)entry_at(coord, pos);
	/* place where new header will be in */
	header = header_at(coord, pos);
	/* free space for new entry headers */
	memmove(header + no, header,
		(unsigned)(address(coord, size) - (char *)header));
	/* if adding to the end initialise first new header */
	if (pos == entries) {
		set_offset(coord, pos, (unsigned)size);
	}

	/* adjust entry pointer and size */
	dent = dent + no * sizeof *header;
	size += no * sizeof *header;
	/* free space for new entries */
	memmove(dent + data_size, dent,
		(unsigned)(address(coord, size) - dent));

	/* increase counter */
	entries += no;
	put_unaligned(cpu_to_le16((__u16) entries), &formatted_at(coord)->num_of_entries);

	/* [ 0 ... pos ] entries were shifted by no * ( sizeof *header )
	   bytes.  */
	for (i = 0; i <= pos; ++i)
		adj_offset(coord, i, no * sizeof *header);
	/* [ pos + no ... +\infty ) entries were shifted by ( no *
	   sizeof *header + data_size ) bytes */
	for (i = pos + no; i < entries; ++i)
		adj_offset(coord, i, no * sizeof *header + data_size);
	return 0;
}
Beispiel #2
0
/* return offset of the body of @idx-th entry in @coord */
static unsigned int offset_of(const coord_t * coord /* coord of item */ ,
			      int idx /* index of unit */ )
{
	if (idx < units(coord))
		return le16_to_cpu(get_unaligned(&header_at(coord, idx)->offset));
	else if (idx == units(coord))
		return item_length_by_coord(coord);
	else
		impossible("nikita-1308", "Wrong idx");
	return 0;
}
Beispiel #3
0
/* cde_check ->check() method for compressed directory items

   used for debugging, every item should have here the most complete
   possible check of the consistency of the item that the inventor can
   construct
*/
int reiser4_check_cde(const coord_t * coord /* coord of item to check */,
		      const char **error /* where to store error message */)
{
	int i;
	int result;
	char *item_start;
	char *item_end;
	reiser4_key key;

	coord_t c;

	assert("nikita-1357", coord != NULL);
	assert("nikita-1358", error != NULL);

	if (!ergo(coord->item_pos != 0,
		  is_dot_key(item_key_by_coord(coord, &key)))) {
		*error = "CDE doesn't start with dot";
		return -1;
	}
	item_start = item_body_by_coord(coord);
	item_end = item_start + item_length_by_coord(coord);

	coord_dup(&c, coord);
	result = 0;
	for (i = 0; i < units(coord); ++i) {
		directory_entry_format *entry;

		if ((char *)(header_at(coord, i) + 1) >
		    item_end - units(coord) * sizeof *entry) {
			*error = "CDE header is out of bounds";
			result = -1;
			break;
		}
		entry = entry_at(coord, i);
		if ((char *)entry < item_start + sizeof(cde_item_format)) {
			*error = "CDE header is too low";
			result = -1;
			break;
		}
		if ((char *)(entry + 1) > item_end) {
			*error = "CDE header is too high";
			result = -1;
			break;
		}
	}

	return result;
}
Beispiel #4
0
/* insert new @entry into item */
static int expand(const coord_t * coord /* coord of item */ ,
		  struct cde_entry * entry /* entry to insert */ ,
		  int len /* length of @entry data */ ,
		  int *pos /* position to insert */ ,
		  reiser4_dir_entry_desc * dir_entry	/* parameters for new
							 * entry */ )
{
	cmp_t cmp_res;
	int datasize;

	*pos = find(coord, &dir_entry->key, &cmp_res);
	if (*pos < 0)
		*pos = units(coord);

	datasize = sizeof(directory_entry_format);
	if (is_longname(entry->name->name, entry->name->len))
		datasize += entry->name->len + 1;

	expand_item(coord, *pos, 1, item_length_by_coord(coord) - len,
		    datasize);
	return 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;
}