📄 stree.c
字号:
if (n_ret_value != REPEAT_SEARCH) break; PROC_INFO_INC(p_s_sb, cut_from_item_restarted); n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path); if (n_ret_value == POSITION_FOUND) continue; reiserfs_warning(p_s_sb, "PAP-5610: reiserfs_cut_from_item: item %K not found", p_s_item_key); unfix_nodes(&s_cut_balance); return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT; } /* while */ // check fix_nodes results (IO_ERROR or NO_DISK_SPACE) if (n_ret_value != CARRY_ON) { if (n_is_inode_locked) { // FIXME: this seems to be not needed: we are always able // to cut item indirect_to_direct_roll_back(th, p_s_inode, p_s_path); } if (n_ret_value == NO_DISK_SPACE) reiserfs_warning(p_s_sb, "NO_DISK_SPACE"); unfix_nodes(&s_cut_balance); return -EIO; } /* go ahead and perform balancing */ RFALSE(c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode"); /* Calculate number of bytes that need to be cut from the item. */ quota_cut_bytes = (c_mode == M_DELETE) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance. insert_size[0]; if (retval2 == -1) n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode); else n_ret_value = retval2; /* For direct items, we only change the quota when deleting the last ** item. */ p_le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path); if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) { if (c_mode == M_DELETE && (le_ih_k_offset(p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1) { // FIXME: this is to keep 3.5 happy REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX; quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE; } else { quota_cut_bytes = 0; } }#ifdef CONFIG_REISERFS_CHECK if (n_is_inode_locked) { struct item_head *le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path); /* we are going to complete indirect2direct conversion. Make sure, that we exactly remove last unformatted node pointer of the item */ if (!is_indirect_le_ih(le_ih)) reiserfs_panic(p_s_sb, "vs-5652: reiserfs_cut_from_item: " "item must be indirect %h", le_ih); if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE) reiserfs_panic(p_s_sb, "vs-5653: reiserfs_cut_from_item: " "completing indirect2direct conversion indirect item %h " "being deleted must be of 4 byte long", le_ih); if (c_mode == M_CUT && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) { reiserfs_panic(p_s_sb, "vs-5654: reiserfs_cut_from_item: " "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)", le_ih, s_cut_balance.insert_size[0]); } /* it would be useful to make sure, that right neighboring item is direct item of this file */ }#endif do_balance(&s_cut_balance, NULL, NULL, c_mode); if (n_is_inode_locked) { /* we've done an indirect->direct conversion. when the data block ** was freed, it was removed from the list of blocks that must ** be flushed before the transaction commits, make sure to ** unmap and invalidate it */ unmap_buffers(page, tail_pos); REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask; }#ifdef REISERQUOTA_DEBUG reiserfs_debug(p_s_inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota cut_from_item(): freeing %u id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, '?');#endif DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); return n_ret_value;}static void truncate_directory(struct reiserfs_transaction_handle *th, struct inode *inode){ BUG_ON(!th->t_trans_id); if (inode->i_nlink) reiserfs_warning(inode->i_sb, "vs-5655: truncate_directory: link count != 0"); set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), DOT_OFFSET); set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_DIRENTRY); reiserfs_delete_solid_item(th, inode, INODE_PKEY(inode)); reiserfs_update_sd(th, inode); set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), SD_OFFSET); set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_STAT_DATA);}/* Truncate file to the new size. Note, this must be called with a transaction already started */int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, /* ->i_size contains new size */ struct page *page, /* up to date for last block */ int update_timestamps /* when it is called by file_release to convert the tail - no timestamps should be updated */ ){ INITIALIZE_PATH(s_search_path); /* Path to the current object item. */ struct item_head *p_le_ih; /* Pointer to an item header. */ struct cpu_key s_item_key; /* Key to search for a previous file item. */ loff_t n_file_size, /* Old file size. */ n_new_file_size; /* New file size. */ int n_deleted; /* Number of deleted or truncated bytes. */ int retval; int err = 0; BUG_ON(!th->t_trans_id); if (! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode))) return 0; if (S_ISDIR(p_s_inode->i_mode)) { // deletion of directory - no need to update timestamps truncate_directory(th, p_s_inode); return 0; } /* Get new file size. */ n_new_file_size = p_s_inode->i_size; // FIXME: note, that key type is unimportant here make_cpu_key(&s_item_key, p_s_inode, max_reiserfs_offset(p_s_inode), TYPE_DIRECT, 3); retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path); if (retval == IO_ERROR) { reiserfs_warning(p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: " "i/o failure occurred trying to truncate %K", &s_item_key); err = -EIO; goto out; } if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) { reiserfs_warning(p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: " "wrong result %d of search for %K", retval, &s_item_key); err = -EIO; goto out; } s_search_path.pos_in_item--; /* Get real file size (total length of all file items) */ p_le_ih = PATH_PITEM_HEAD(&s_search_path); if (is_statdata_le_ih(p_le_ih)) n_file_size = 0; else { loff_t offset = le_ih_k_offset(p_le_ih); int bytes = op_bytes_number(p_le_ih, p_s_inode->i_sb->s_blocksize); /* this may mismatch with real file size: if last direct item had no padding zeros and last unformatted node had no free space, this file would have this file size */ n_file_size = offset + bytes - 1; } /* * are we doing a full truncate or delete, if so * kick in the reada code */ if (n_new_file_size == 0) s_search_path.reada = PATH_READA | PATH_READA_BACK; if (n_file_size == 0 || n_file_size < n_new_file_size) { goto update_and_out; } /* Update key to search for the last file item. */ set_cpu_key_k_offset(&s_item_key, n_file_size); do { /* Cut or delete file item. */ n_deleted = reiserfs_cut_from_item(th, &s_search_path, &s_item_key, p_s_inode, page, n_new_file_size); if (n_deleted < 0) { reiserfs_warning(p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed"); reiserfs_check_path(&s_search_path); return 0; } RFALSE(n_deleted > n_file_size, "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K", n_deleted, n_file_size, &s_item_key); /* Change key to search the last file item. */ n_file_size -= n_deleted; set_cpu_key_k_offset(&s_item_key, n_file_size); /* While there are bytes to truncate and previous file item is presented in the tree. */ /* ** This loop could take a really long time, and could log ** many more blocks than a transaction can hold. So, we do a polite ** journal end here, and if the transaction needs ending, we make ** sure the file is consistent before ending the current trans ** and starting a new one */ if (journal_transaction_should_end(th, 0) || reiserfs_transaction_free_space(th) <= JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD) { int orig_len_alloc = th->t_blocks_allocated; decrement_counters_in_path(&s_search_path); if (update_timestamps) { p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC; } reiserfs_update_sd(th, p_s_inode); err = journal_end(th, p_s_inode->i_sb, orig_len_alloc); if (err) goto out; err = journal_begin(th, p_s_inode->i_sb, JOURNAL_FOR_FREE_BLOCK_AND_UPDATE_SD + JOURNAL_PER_BALANCE_CNT * 4) ; if (err) goto out; reiserfs_update_inode_transaction(p_s_inode); } } while (n_file_size > ROUND_UP(n_new_file_size) && search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND); RFALSE(n_file_size > ROUND_UP(n_new_file_size), "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d", n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid); update_and_out: if (update_timestamps) { // this is truncate, not file closing p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC; } reiserfs_update_sd(th, p_s_inode); out: pathrelse(&s_search_path); return err;}#ifdef CONFIG_REISERFS_CHECK// this makes sure, that we __append__, not overwrite or add holesstatic void check_research_for_paste(struct treepath *path, const struct cpu_key *p_s_key){ struct item_head *found_ih = get_ih(path); if (is_direct_le_ih(found_ih)) { if (le_ih_k_offset(found_ih) + op_bytes_number(found_ih, get_last_bh(path)->b_size) != cpu_key_k_offset(p_s_key) || op_bytes_number(found_ih, get_last_bh(path)->b_size) != pos_in_item(path)) reiserfs_panic(NULL, "PAP-5720: check_research_for_paste: " "found direct item %h or position (%d) does not match to key %K", found_ih, pos_in_item(path), p_s_key); } if (is_indirect_le_ih(found_ih)) { if (le_ih_k_offset(found_ih) + op_bytes_number(found_ih, get_last_bh(path)->b_size) != cpu_key_k_offset(p_s_key) || I_UNFM_NUM(found_ih) != pos_in_item(path) || get_ih_free_space(found_ih) != 0) reiserfs_panic(NULL, "PAP-5730: check_research_for_paste: " "found indirect item (%h) or position (%d) does not match to key (%K)", found_ih, pos_in_item(path), p_s_key); }}#endif /* config reiserfs check *//* Paste bytes to the existing item. Returns bytes number pasted into the item. */int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_search_path, /* Path to the pasted item. */ const struct cpu_key *p_s_key, /* Key to search for the needed item. */ struct inode *inode, /* Inode item belongs to */ const char *p_c_body, /* Pointer to the bytes to paste. */ int n_pasted_size){ /* Size of pasted bytes. */ struct tree_balance s_paste_balance; int retval; int fs_gen; BUG_ON(!th->t_trans_id); fs_gen = get_generation(inode->i_sb);#ifdef REISERQUOTA_DEBUG reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): allocating %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));#endif if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) { pathrelse(p_s_search_path); return -EDQUOT; } init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);#ifdef DISPLACE_NEW_PACKING_LOCALITIES s_paste_balance.key = p_s_key->on_disk_key;#endif /* DQUOT_* can schedule, must check before the fix_nodes */ if (fs_changed(fs_gen, inode->i_sb)) { goto search_again; } while ((retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) == REPEAT_SEARCH) { search_again: /* file system changed while we were in the fix_nodes */ PROC_INFO_INC(th->t_super, paste_into_item_restarted); retval = search_for_position_by_key(th->t_super, p_s_key, p_s_search_path); if (retval == IO_ERROR) { retval = -EIO; goto error_out; } if (retval == POSITION_FOUND) { reiserfs_warning(inode->i_sb, "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key); retval = -EEXIST; goto error_out; }#ifdef CONFIG_REISERFS_CHECK check_research_for_paste(p_s_search_path, p_s_key);#endif } /* Perform balancing after all resources are collected by fix_nodes, and accessing them will not risk triggering schedule. */ if (retval == CARRY_ON) { do_balance(&s_paste_balance, NULL /*ih */ , p_c_body, M_PASTE); return 0; } retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO; error_out: /* this also releases the path */ unfix_nodes(&s_paste_balance);#ifdef REISERQUOTA_DEBUG reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): freeing %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));#endif DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size); return retval;}/* Insert new item into the buffer at the path. */int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct treepath *p_s_path, /* Path to the inserteded item. */ const struct cpu_key *key,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -