/* * May return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND * FIXME: should add something like IOERROR */ static int reiserfs_find_entry(struct reiserfs_node *dp, const char *name, int namelen, struct path * path_to_entry, struct reiserfs_dir_entry *de) { struct cpu_key key_to_search; int retval; if (namelen > REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize)) return NAME_NOT_FOUND; /* We will search for this key in the tree */ make_cpu_key(&key_to_search, dp, get_third_component(dp->i_reiserfs, name, namelen), TYPE_DIRENTRY, 3); while (1) { reiserfs_log(LOG_DEBUG, "search by entry key\n"); retval = search_by_entry_key(dp->i_reiserfs, &key_to_search, path_to_entry, de); if (retval == IO_ERROR) { reiserfs_log(LOG_DEBUG, "IO error in %s\n", __FUNCTION__); return IO_ERROR; } /* Compare names for all entries having given hash value */ reiserfs_log(LOG_DEBUG, "linear search for `%s'\n", name); retval = linear_search_in_dir_item(&key_to_search, de, name, namelen); if (retval != GOTO_PREVIOUS_ITEM) { /* * There is no need to scan directory anymore. * Given entry found or does not exist */ reiserfs_log(LOG_DEBUG, "linear search returned " "(objectid=%d,dirid=%d)\n", de->de_objectid, de->de_dir_id); path_to_entry->pos_in_item = de->de_entry_num; return retval; } /* * There is left neighboring item of this directory and * given entry can be there */ set_cpu_key_k_offset(&key_to_search, le_ih_k_offset(de->de_ih) - 1); pathrelse(path_to_entry); } /* while (1) */ }
/* * may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND * FIXME: should add something like IOERROR */ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen, struct treepath *path_to_entry, struct reiserfs_dir_entry *de) { struct cpu_key key_to_search; int retval; if (namelen > REISERFS_MAX_NAME(dir->i_sb->s_blocksize)) return NAME_NOT_FOUND; /* we will search for this key in the tree */ make_cpu_key(&key_to_search, dir, get_third_component(dir->i_sb, name, namelen), TYPE_DIRENTRY, 3); while (1) { retval = search_by_entry_key(dir->i_sb, &key_to_search, path_to_entry, de); if (retval == IO_ERROR) { reiserfs_error(dir->i_sb, "zam-7001", "io error"); return IO_ERROR; } /* compare names for all entries having given hash value */ retval = linear_search_in_dir_item(&key_to_search, de, name, namelen); /* * there is no need to scan directory anymore. * Given entry found or does not exist */ if (retval != GOTO_PREVIOUS_ITEM) { path_to_entry->pos_in_item = de->de_entry_num; return retval; } /* * there is left neighboring item of this directory * and given entry can be there */ set_cpu_key_k_offset(&key_to_search, le_ih_k_offset(de->de_ih) - 1); pathrelse(path_to_entry); } /* while (1) */ }
/* The function is NOT SCHEDULE-SAFE! */ int search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi, const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */ struct path *p_s_search_path) /* Filled up by this function. */ { int retval, n_blk_size; off_t item_offset, offset; struct item_head *p_le_ih; /* Pointer to on-disk structure */ struct reiserfs_dir_entry de; /* If searching for directory entry. */ if (is_direntry_cpu_key(p_cpu_key)) return (search_by_entry_key(p_s_sbi, p_cpu_key, p_s_search_path, &de)); /* If not searching for directory entry. */ /* If item is found. */ retval = search_item(p_s_sbi, p_cpu_key, p_s_search_path); if (retval == IO_ERROR) return (retval); if (retval == ITEM_FOUND) { if (ih_item_len(B_N_PITEM_HEAD( PATH_PLAST_BUFFER(p_s_search_path), PATH_LAST_POSITION(p_s_search_path))) == 0) { reiserfs_log(LOG_WARNING, "item length equals zero\n"); } pos_in_item(p_s_search_path) = 0; return (POSITION_FOUND); } if (PATH_LAST_POSITION(p_s_search_path) == 0) { reiserfs_log(LOG_WARNING, "position equals zero\n"); } /* Item is not found. Set path to the previous item. */ p_le_ih = B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path), --PATH_LAST_POSITION(p_s_search_path)); n_blk_size = p_s_sbi->s_blocksize; if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) { return (FILE_NOT_FOUND); } item_offset = le_ih_k_offset(p_le_ih); offset = cpu_key_k_offset(p_cpu_key); /* Needed byte is contained in the item pointed to by the path.*/ if (item_offset <= offset && item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) { pos_in_item(p_s_search_path) = offset - item_offset; if (is_indirect_le_ih(p_le_ih)) { pos_in_item(p_s_search_path) /= n_blk_size; } return (POSITION_FOUND); } /* Needed byte is not contained in the item pointed to by the * path. Set pos_in_item out of the item. */ if (is_indirect_le_ih(p_le_ih)) pos_in_item(p_s_search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE; else pos_in_item(p_s_search_path) = ih_item_len(p_le_ih); return (POSITION_NOT_FOUND); }
static int linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de, const char *name, int namelen) { struct reiserfs_de_head *deh = de->de_deh; int retval; int i; i = de->de_entry_num; if (i == I_ENTRY_COUNT(de->de_ih) || GET_HASH_VALUE(deh_offset(deh + i)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { i--; } RFALSE(de->de_deh != B_I_DEH(de->de_bh, de->de_ih), "vs-7010: array of entry headers not found"); deh += i; for (; i >= 0; i--, deh--) { if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { // hash value does not match, no need to check whole name return NAME_NOT_FOUND; } /* mark, that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), de->de_gen_number_bit_string); // calculate pointer to name and namelen de->de_entry_num = i; set_de_name_and_namelen(de); if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { // de's de_name, de_namelen, de_recordlen are set. Fill the rest: // key of pointed object set_de_object_key(de); store_de_entry_key(de); // retval can be NAME_FOUND or NAME_FOUND_INVISIBLE return retval; } } if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0) /* we have reached left most entry in the node. In common we have to go to the left neighbor, but if generation counter is 0 already, we know for sure, that there is no name with the same hash value */ // FIXME: this work correctly only because hash value can not // be 0. Btw, in case of Yura's hash it is probably possible, // so, this is a bug return NAME_NOT_FOUND; RFALSE(de->de_item_num, "vs-7015: two diritems of the same directory in one node?"); return GOTO_PREVIOUS_ITEM; }
/* this first locks inode (neither reads nor sync are permitted), reads tail through page cache, insert direct item. When direct item inserted successfully inode is left locked. Return value is always what we expect from it (number of cut bytes). But when tail remains in the unformatted node, we set mode to SKIP_BALANCING and unlock inode */ int indirect2direct (struct reiserfs_transaction_handle *th, struct inode * p_s_inode, struct page *page, struct path * p_s_path, /* path to the indirect item. */ const struct cpu_key * p_s_item_key, /* Key to look for unformatted node pointer to be cut. */ loff_t n_new_file_size, /* New file size. */ char * p_c_mode) { struct super_block * p_s_sb = p_s_inode->i_sb; struct item_head s_ih; unsigned long n_block_size = p_s_sb->s_blocksize; char * tail; int tail_len, round_tail_len; loff_t pos, pos1; /* position of first byte of the tail */ struct cpu_key key; p_s_sb->u.reiserfs_sb.s_indirect2direct ++; *p_c_mode = M_SKIP_BALANCING; /* store item head path points to. */ copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path)); tail_len = (n_new_file_size & (n_block_size - 1)); if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2) round_tail_len = ROUND_UP (tail_len); else round_tail_len = tail_len; pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize; pos1 = pos; // we are protected by i_sem. The tail can not disapper, not // append can be done either // we are in truncate or packing tail in file_release tail = (char *)kmap(page) ; /* this can schedule */ if (path_changed (&s_ih, p_s_path)) { /* re-search indirect item */ if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ) reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: " "item to be converted %K does not exist", p_s_item_key); copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path)); #ifdef CONFIG_REISERFS_CHECK pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize; if (pos != pos1) reiserfs_panic (p_s_sb, "vs-5530: indirect2direct: " "tail position changed while we were reading it"); #endif } /* Set direct item header to insert. */ make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/); /* we want a pointer to the first byte of the tail in the page. ** the page was locked and this part of the page was up to date when ** indirect2direct was called, so we know the bytes are still valid */ tail = tail + (pos & (PAGE_CACHE_SIZE - 1)) ; PATH_LAST_POSITION(p_s_path)++; key = *p_s_item_key; set_cpu_key_k_type (&key, TYPE_DIRECT); key.key_length = 4; /* Insert tail as new direct item in the tree */ if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih, tail ? tail : NULL) < 0 ) { /* No disk memory. So we can not convert last unformatted node to the direct item. In this case we used to adjust indirect items's ih_free_space. Now ih_free_space is not used, it would be ideal to write zeros to corresponding unformatted node. For now i_size is considered as guard for going out of file size */ kunmap(page) ; return n_block_size - round_tail_len; } kunmap(page) ; /* this will invalidate all the buffers in the page after ** pos1 */ unmap_buffers(page, pos1) ; // note: we have now the same as in above direct2indirect // conversion: there are two keys which have matching first three // key components. They only differ by the fouhth one. /* We have inserted new direct item and must remove last unformatted node. */ p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512); *p_c_mode = M_CUT; /* we store position of first direct item in the in-core inode */ //mark_file_with_tail (p_s_inode, pos1 + 1); p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1; return n_block_size - round_tail_len; }
/* path points to first direct item of the file regarless of how many of them are there */ int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inode, struct path * path, struct buffer_head * unbh, loff_t tail_offset) { struct super_block * sb = inode->i_sb; struct buffer_head *up_to_date_bh ; struct item_head * p_le_ih = PATH_PITEM_HEAD (path); unsigned long total_tail = 0 ; struct cpu_key end_key; /* Key to search for the last byte of the converted item. */ struct item_head ind_ih; /* new indirect item to be inserted or key of unfm pointer to be pasted */ int n_blk_size, n_retval; /* returned value for reiserfs_insert_item and clones */ struct unfm_nodeinfo unfm_ptr; /* Handle on an unformatted node that will be inserted in the tree. */ sb->u.reiserfs_sb.s_direct2indirect ++; n_blk_size = sb->s_blocksize; /* and key to search for append or insert pointer to the new unformatted node. */ copy_item_head (&ind_ih, p_le_ih); set_le_ih_k_offset (&ind_ih, tail_offset); set_le_ih_k_type (&ind_ih, TYPE_INDIRECT); /* Set the key to search for the place for new unfm pointer */ make_cpu_key (&end_key, inode, tail_offset, TYPE_INDIRECT, 4); // FIXME: we could avoid this if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND ) { reiserfs_warning ("PAP-14030: direct2indirect: " "pasted or inserted byte exists in the tree %K. " "Use fsck to repair.\n", &end_key); pathrelse(path); return -EIO; } p_le_ih = PATH_PITEM_HEAD (path); unfm_ptr.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr); unfm_ptr.unfm_freespace = 0; // ??? if ( is_statdata_le_ih (p_le_ih) ) { /* Insert new indirect item. */ set_ih_free_space (&ind_ih, 0); /* delete at nearest future */ put_ih_item_len( &ind_ih, UNFM_P_SIZE ); PATH_LAST_POSITION (path)++; n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, (char *)&unfm_ptr); } else { /* Paste into last indirect item of an object. */ n_retval = reiserfs_paste_into_item(th, path, &end_key, (char *)&unfm_ptr, UNFM_P_SIZE); } if ( n_retval ) { return n_retval; } // note: from here there are two keys which have matching first // three key components. They only differ by the fourth one. /* Set the key to search for the direct items of the file */ make_cpu_key (&end_key, inode, max_reiserfs_offset (inode), TYPE_DIRECT, 4); /* Move bytes from the direct items to the new unformatted node and delete them. */ while (1) { int tail_size; /* end_key.k_offset is set so, that we will always have found last item of the file */ if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND ) reiserfs_panic (sb, "PAP-14050: direct2indirect: " "direct item (%K) not found", &end_key); p_le_ih = PATH_PITEM_HEAD (path); RFALSE( !is_direct_le_ih (p_le_ih), "vs-14055: direct item expected(%K), found %h", &end_key, p_le_ih); tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1)) + ih_item_len(p_le_ih) - 1; /* we only send the unbh pointer if the buffer is not up to date. ** this avoids overwriting good data from writepage() with old data ** from the disk or buffer cache ** Special case: unbh->b_page will be NULL if we are coming through ** DIRECT_IO handler here. */ if ( !unbh->b_page || buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) { up_to_date_bh = NULL ; } else { up_to_date_bh = unbh ; } n_retval = reiserfs_delete_item (th, path, &end_key, inode, up_to_date_bh) ; total_tail += n_retval ; if (tail_size == n_retval) // done: file does not have direct items anymore break; } /* if we've copied bytes from disk into the page, we need to zero ** out the unused part of the block (it was not up to date before) ** the page is still kmapped (by whoever called reiserfs_get_block) */ if (up_to_date_bh) { unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ; } inode->u.reiserfs_i.i_first_direct_byte = U32_MAX; reiserfs_update_tail_transaction(inode); return 0; }
/* * de's de_bh, de_ih, de_deh, de_item_num, de_entry_num are set already * Used when hash collisions exist */ static int linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de, const char *name, int namelen) { int i; int retval; struct reiserfs_de_head * deh = de->de_deh; i = de->de_entry_num; if (i == I_ENTRY_COUNT(de->de_ih) || GET_HASH_VALUE(deh_offset(deh + i)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { i--; } /*RFALSE( de->de_deh != B_I_DEH (de->de_bh, de->de_ih), "vs-7010: array of entry headers not found");*/ deh += i; for (; i >= 0; i--, deh--) { if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { /* * Hash value does not match, no need to check * whole name */ reiserfs_log(LOG_DEBUG, "name `%s' not found\n", name); return (NAME_NOT_FOUND); } /* Mark that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), (unsigned long *)de->de_gen_number_bit_string); /* Calculate pointer to name and namelen */ de->de_entry_num = i; set_de_name_and_namelen(de); if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { /* * de's de_name, de_namelen, de_recordlen are set. * Fill the rest: */ /* key of pointed object */ set_de_object_key(de); store_de_entry_key(de); /* retval can be NAME_FOUND or NAME_FOUND_INVISIBLE */ reiserfs_log(LOG_DEBUG, "reiserfs_match answered `%d'\n", retval); return (retval); } } if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0) /* * We have reached left most entry in the node. In common * we have to go to the left neighbor, but if generation * counter is 0 already, we know for sure, that there is * no name with the same hash value */ /* FIXME: this work correctly only because hash value can * not be 0. Btw, in case of Yura's hash it is probably * possible, so, this is a bug */ return (NAME_NOT_FOUND); /*RFALSE(de->de_item_num, "vs-7015: two diritems of the same directory in one node?");*/ return (GOTO_PREVIOUS_ITEM); }
int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *inode, struct page *page, struct treepath *path, const struct cpu_key *item_key, loff_t n_new_file_size, char *mode) { struct super_block *sb = inode->i_sb; struct item_head s_ih; unsigned long block_size = sb->s_blocksize; char *tail; int tail_len, round_tail_len; loff_t pos, pos1; struct cpu_key key; BUG_ON(!th->t_trans_id); REISERFS_SB(sb)->s_indirect2direct++; *mode = M_SKIP_BALANCING; copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); tail_len = (n_new_file_size & (block_size - 1)); if (get_inode_sd_version(inode) == STAT_DATA_V2) round_tail_len = ROUND_UP(tail_len); else round_tail_len = tail_len; pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * sb->s_blocksize; pos1 = pos; tail = (char *)kmap(page); if (path_changed(&s_ih, path)) { if (search_for_position_by_key(sb, item_key, path) == POSITION_NOT_FOUND) reiserfs_panic(sb, "PAP-5520", "item to be converted %K does not exist", item_key); copy_item_head(&s_ih, PATH_PITEM_HEAD(path)); #ifdef CONFIG_REISERFS_CHECK pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * sb->s_blocksize; if (pos != pos1) reiserfs_panic(sb, "vs-5530", "tail position " "changed while we were reading it"); #endif } make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff ); tail = tail + (pos & (PAGE_CACHE_SIZE - 1)); PATH_LAST_POSITION(path)++; key = *item_key; set_cpu_key_k_type(&key, TYPE_DIRECT); key.key_length = 4; if (reiserfs_insert_item(th, path, &key, &s_ih, inode, tail ? tail : NULL) < 0) { kunmap(page); return block_size - round_tail_len; } kunmap(page); reiserfs_update_sd(th, inode); *mode = M_CUT; REISERFS_I(inode)->i_first_direct_byte = pos1 + 1; return block_size - round_tail_len; }
int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *path, struct buffer_head *unbh, loff_t tail_offset) { struct super_block *sb = inode->i_sb; struct buffer_head *up_to_date_bh; struct item_head *p_le_ih = PATH_PITEM_HEAD(path); unsigned long total_tail = 0; struct cpu_key end_key; struct item_head ind_ih; int blk_size, retval; unp_t unfm_ptr; BUG_ON(!th->t_trans_id); REISERFS_SB(sb)->s_direct2indirect++; blk_size = sb->s_blocksize; copy_item_head(&ind_ih, p_le_ih); set_le_ih_k_offset(&ind_ih, tail_offset); set_le_ih_k_type(&ind_ih, TYPE_INDIRECT); make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4); if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) { reiserfs_error(sb, "PAP-14030", "pasted or inserted byte exists in " "the tree %K. Use fsck to repair.", &end_key); pathrelse(path); return -EIO; } p_le_ih = PATH_PITEM_HEAD(path); unfm_ptr = cpu_to_le32(unbh->b_blocknr); if (is_statdata_le_ih(p_le_ih)) { set_ih_free_space(&ind_ih, 0); put_ih_item_len(&ind_ih, UNFM_P_SIZE); PATH_LAST_POSITION(path)++; retval = reiserfs_insert_item(th, path, &end_key, &ind_ih, inode, (char *)&unfm_ptr); } else { retval = reiserfs_paste_into_item(th, path, &end_key, inode, (char *)&unfm_ptr, UNFM_P_SIZE); } if (retval) { return retval; } make_cpu_key(&end_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT, 4); while (1) { int tail_size; if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) reiserfs_panic(sb, "PAP-14050", "direct item (%K) not found", &end_key); p_le_ih = PATH_PITEM_HEAD(path); RFALSE(!is_direct_le_ih(p_le_ih), "vs-14055: direct item expected(%K), found %h", &end_key, p_le_ih); tail_size = (le_ih_k_offset(p_le_ih) & (blk_size - 1)) + ih_item_len(p_le_ih) - 1; if (!unbh->b_page || buffer_uptodate(unbh) || PageUptodate(unbh->b_page)) { up_to_date_bh = NULL; } else { up_to_date_bh = unbh; } retval = reiserfs_delete_item(th, path, &end_key, inode, up_to_date_bh); total_tail += retval; if (tail_size == retval) break; } if (up_to_date_bh) { unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1); char *kaddr = kmap_atomic(up_to_date_bh->b_page); memset(kaddr + pgoff, 0, blk_size - total_tail); kunmap_atomic(kaddr); } REISERFS_I(inode)->i_first_direct_byte = U32_MAX; return 0; }
/* * path points to first direct item of the file regardless of how many of * them are there */ int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode, struct treepath *path, struct buffer_head *unbh, loff_t tail_offset) { struct super_block *sb = inode->i_sb; struct buffer_head *up_to_date_bh; struct item_head *p_le_ih = tp_item_head(path); unsigned long total_tail = 0; /* Key to search for the last byte of the converted item. */ struct cpu_key end_key; /* * new indirect item to be inserted or key * of unfm pointer to be pasted */ struct item_head ind_ih; int blk_size; /* returned value for reiserfs_insert_item and clones */ int retval; /* Handle on an unformatted node that will be inserted in the tree. */ unp_t unfm_ptr; BUG_ON(!th->t_trans_id); REISERFS_SB(sb)->s_direct2indirect++; blk_size = sb->s_blocksize; /* * and key to search for append or insert pointer to the new * unformatted node. */ copy_item_head(&ind_ih, p_le_ih); set_le_ih_k_offset(&ind_ih, tail_offset); set_le_ih_k_type(&ind_ih, TYPE_INDIRECT); /* Set the key to search for the place for new unfm pointer */ make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4); /* FIXME: we could avoid this */ if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) { reiserfs_error(sb, "PAP-14030", "pasted or inserted byte exists in " "the tree %K. Use fsck to repair.", &end_key); pathrelse(path); return -EIO; } p_le_ih = tp_item_head(path); unfm_ptr = cpu_to_le32(unbh->b_blocknr); if (is_statdata_le_ih(p_le_ih)) { /* Insert new indirect item. */ set_ih_free_space(&ind_ih, 0); /* delete at nearest future */ put_ih_item_len(&ind_ih, UNFM_P_SIZE); PATH_LAST_POSITION(path)++; retval = reiserfs_insert_item(th, path, &end_key, &ind_ih, inode, (char *)&unfm_ptr); } else { /* Paste into last indirect item of an object. */ retval = reiserfs_paste_into_item(th, path, &end_key, inode, (char *)&unfm_ptr, UNFM_P_SIZE); } if (retval) { return retval; } /* * note: from here there are two keys which have matching first * three key components. They only differ by the fourth one. */ /* Set the key to search for the direct items of the file */ make_cpu_key(&end_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT, 4); /* * Move bytes from the direct items to the new unformatted node * and delete them. */ while (1) { int tail_size; /* * end_key.k_offset is set so, that we will always have found * last item of the file */ if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) reiserfs_panic(sb, "PAP-14050", "direct item (%K) not found", &end_key); p_le_ih = tp_item_head(path); RFALSE(!is_direct_le_ih(p_le_ih), "vs-14055: direct item expected(%K), found %h", &end_key, p_le_ih); tail_size = (le_ih_k_offset(p_le_ih) & (blk_size - 1)) + ih_item_len(p_le_ih) - 1; /* * we only send the unbh pointer if the buffer is not * up to date. this avoids overwriting good data from * writepage() with old data from the disk or buffer cache * Special case: unbh->b_page will be NULL if we are coming * through DIRECT_IO handler here. */ if (!unbh->b_page || buffer_uptodate(unbh) || PageUptodate(unbh->b_page)) { up_to_date_bh = NULL; } else { up_to_date_bh = unbh; } retval = reiserfs_delete_item(th, path, &end_key, inode, up_to_date_bh); total_tail += retval; /* done: file does not have direct items anymore */ if (tail_size == retval) break; } /* * if we've copied bytes from disk into the page, we need to zero * out the unused part of the block (it was not up to date before) */ if (up_to_date_bh) { unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_SIZE - 1); char *kaddr = kmap_atomic(up_to_date_bh->b_page); memset(kaddr + pgoff, 0, blk_size - total_tail); kunmap_atomic(kaddr); } REISERFS_I(inode)->i_first_direct_byte = U32_MAX; return 0; }
/* * this first locks inode (neither reads nor sync are permitted), * reads tail through page cache, insert direct item. When direct item * inserted successfully inode is left locked. Return value is always * what we expect from it (number of cut bytes). But when tail remains * in the unformatted node, we set mode to SKIP_BALANCING and unlock * inode */ int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *inode, struct page *page, struct treepath *path, /* path to the indirect item. */ const struct cpu_key *item_key, /* Key to look for * unformatted node * pointer to be cut. */ loff_t n_new_file_size, /* New file size. */ char *mode) { struct super_block *sb = inode->i_sb; struct item_head s_ih; unsigned long block_size = sb->s_blocksize; char *tail; int tail_len, round_tail_len; loff_t pos, pos1; /* position of first byte of the tail */ struct cpu_key key; BUG_ON(!th->t_trans_id); REISERFS_SB(sb)->s_indirect2direct++; *mode = M_SKIP_BALANCING; /* store item head path points to. */ copy_item_head(&s_ih, tp_item_head(path)); tail_len = (n_new_file_size & (block_size - 1)); if (get_inode_sd_version(inode) == STAT_DATA_V2) round_tail_len = ROUND_UP(tail_len); else round_tail_len = tail_len; pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * sb->s_blocksize; pos1 = pos; /* * we are protected by i_mutex. The tail can not disapper, not * append can be done either * we are in truncate or packing tail in file_release */ tail = (char *)kmap(page); /* this can schedule */ if (path_changed(&s_ih, path)) { /* re-search indirect item */ if (search_for_position_by_key(sb, item_key, path) == POSITION_NOT_FOUND) reiserfs_panic(sb, "PAP-5520", "item to be converted %K does not exist", item_key); copy_item_head(&s_ih, tp_item_head(path)); #ifdef CONFIG_REISERFS_CHECK pos = le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * sb->s_blocksize; if (pos != pos1) reiserfs_panic(sb, "vs-5530", "tail position " "changed while we were reading it"); #endif } /* Set direct item header to insert. */ make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode), pos1 + 1, TYPE_DIRECT, round_tail_len, 0xffff /*ih_free_space */ ); /* * we want a pointer to the first byte of the tail in the page. * the page was locked and this part of the page was up to date when * indirect2direct was called, so we know the bytes are still valid */ tail = tail + (pos & (PAGE_SIZE - 1)); PATH_LAST_POSITION(path)++; key = *item_key; set_cpu_key_k_type(&key, TYPE_DIRECT); key.key_length = 4; /* Insert tail as new direct item in the tree */ if (reiserfs_insert_item(th, path, &key, &s_ih, inode, tail ? tail : NULL) < 0) { /* * No disk memory. So we can not convert last unformatted node * to the direct item. In this case we used to adjust * indirect items's ih_free_space. Now ih_free_space is not * used, it would be ideal to write zeros to corresponding * unformatted node. For now i_size is considered as guard for * going out of file size */ kunmap(page); return block_size - round_tail_len; } kunmap(page); /* make sure to get the i_blocks changes from reiserfs_insert_item */ reiserfs_update_sd(th, inode); /* * note: we have now the same as in above direct2indirect * conversion: there are two keys which have matching first three * key components. They only differ by the fourth one. */ /* * We have inserted new direct item and must remove last * unformatted node. */ *mode = M_CUT; /* we store position of first direct item in the in-core inode */ /* mark_file_with_tail (inode, pos1 + 1); */ REISERFS_I(inode)->i_first_direct_byte = pos1 + 1; return block_size - round_tail_len; }