/* 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; }
/* 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; }
/* 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; }
/* 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; }